maydayjeffk commited on
Commit
e532a92
·
verified ·
1 Parent(s): ce11844

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +214 -64
index.html CHANGED
@@ -117,6 +117,16 @@
117
  z-index: -1;
118
  opacity: 0.1;
119
  }
 
 
 
 
 
 
 
 
 
 
120
  </style>
121
  </head>
122
  <body>
@@ -148,6 +158,10 @@
148
  </div>
149
  <p class="text-sm mt-2 text-gray-400">Works with JPG, PNG, GIF, WEBP, SVG, BMP, TIFF, and more</p>
150
 
 
 
 
 
151
  <div class="mt-6">
152
  <h3 class="text-xl mb-2">OPTIONS</h3>
153
  <div class="flex flex-wrap gap-4">
@@ -314,6 +328,7 @@
314
  const confirmDelete = document.getElementById('confirmDelete');
315
  const recursiveCheck = document.getElementById('recursiveCheck');
316
  const filterCheck = document.getElementById('filterCheck');
 
317
 
318
  // Event listeners
319
  scrapeBtn.addEventListener('click', startScraping);
@@ -359,76 +374,198 @@
359
  progressText.textContent = '0%';
360
  statusText.textContent = 'Starting the digital heist...';
361
 
362
- // Simulate scraping (in a real app, this would be an API call)
363
- simulateScraping(url);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  }
365
 
366
- function simulateScraping(url) {
367
- let progress = 0;
368
- const interval = setInterval(() => {
369
- progress += Math.random() * 10;
370
- if (progress > 100) progress = 100;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
 
372
- progressFill.style.width = `${progress}%`;
373
- progressText.textContent = `${Math.floor(progress)}%`;
 
 
 
 
 
 
374
 
375
- if (progress < 30) {
376
- statusText.textContent = 'Bypassing capitalist security...';
377
- } else if (progress < 60) {
378
- statusText.textContent = 'Stealing from the rich...';
379
- } else if (progress < 90) {
380
- statusText.textContent = 'Sticking it to the man...';
381
- } else {
382
- statusText.textContent = 'Almost there, comrade...';
383
  }
384
 
385
- if (progress >= 100) {
386
- clearInterval(interval);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
  finishScraping();
 
388
  }
389
- }, 300);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  }
391
 
392
  function finishScraping() {
393
- statusText.textContent = 'Done! Images loaded.';
394
-
395
- // Generate mock images (in a real app, these would come from the scraping)
396
- const mockImages = generateMockImages();
397
- scrapedImages = mockImages;
398
 
399
  // Display images
400
- displayImages(mockImages);
401
 
402
  // Show results section
403
  resultsSection.classList.remove('hidden');
404
- }
405
-
406
- function generateMockImages() {
407
- const formats = ['jpg', 'png', 'gif', 'webp', 'svg', 'bmp', 'tiff'];
408
- const images = [];
409
-
410
- const count = Math.floor(Math.random() * 50) + 30; // 30-80 images
411
 
412
- for (let i = 0; i < count; i++) {
413
- const format = formats[Math.floor(Math.random() * formats.length)];
414
- const width = Math.floor(Math.random() * 1000) + 200;
415
- const height = Math.floor(Math.random() * 800) + 200;
416
-
417
- images.push({
418
- url: `https://picsum.photos/${width}/${height}?random=${i}`,
419
- format: format,
420
- width: width,
421
- height: height,
422
- originalUrl: `https://example.com/images/image${i}.${format}`
423
- });
424
- }
425
-
426
- // Filter out tiny images if option is checked
427
- if (filterCheck.checked) {
428
- return images.filter(img => img.width > 100 && img.height > 100);
429
- }
430
-
431
- return images;
432
  }
433
 
434
  function displayImages(images) {
@@ -441,7 +578,7 @@
441
 
442
  tile.innerHTML = `
443
  <div class="relative pb-full">
444
- <img src="${img.url}" alt="Scraped image" class="absolute h-full w-full object-cover" loading="lazy">
445
  </div>
446
  <div class="absolute bottom-0 left-0 right-0 bg-black bg-opacity-70 p-2 hidden group-hover:block">
447
  <span class="filetype-badge px-2 py-1 text-xs">${img.format.toUpperCase()}</span>
@@ -549,13 +686,20 @@
549
  return;
550
  }
551
 
552
- // In a real app, this would create a zip file of selected images
553
  alert(`Preparing to download ${selectedImages.length} images...\n\n(In a real app, this would create a ZIP file)`);
554
 
555
- // Simulate download
556
- setTimeout(() => {
557
- alert("Download complete! Stick it to the man!");
558
- }, 1500);
 
 
 
 
 
 
 
559
  }
560
 
561
  function showDeleteConfirmation() {
@@ -604,11 +748,17 @@
604
  // In a real app, this would convert images to the selected format
605
  alert(`Converting ${selectedImages.length} images to ${selectedFormat.toUpperCase()}...\n\n(In a real app, this would use a conversion API)`);
606
 
607
- // Simulate conversion
608
- setTimeout(() => {
609
- alert(`Conversion to ${selectedFormat.toUpperCase()} complete! Take that, capitalist image standards!`);
610
- convertModal.classList.add('hidden');
611
- }, 1500);
 
 
 
 
 
 
612
  }
613
 
614
  // Close modals when clicking outside
 
117
  z-index: -1;
118
  opacity: 0.1;
119
  }
120
+
121
+ /* CORS proxy warning */
122
+ .cors-warning {
123
+ background-color: #f00;
124
+ color: #fff;
125
+ padding: 10px;
126
+ margin-top: 10px;
127
+ border: 2px solid #fff;
128
+ font-size: 14px;
129
+ }
130
  </style>
131
  </head>
132
  <body>
 
158
  </div>
159
  <p class="text-sm mt-2 text-gray-400">Works with JPG, PNG, GIF, WEBP, SVG, BMP, TIFF, and more</p>
160
 
161
+ <div class="cors-warning hidden" id="corsWarning">
162
+ WARNING: Due to CORS restrictions, we're using a proxy to scrape this site. Some images may not load properly. For best results, use the browser extension version.
163
+ </div>
164
+
165
  <div class="mt-6">
166
  <h3 class="text-xl mb-2">OPTIONS</h3>
167
  <div class="flex flex-wrap gap-4">
 
328
  const confirmDelete = document.getElementById('confirmDelete');
329
  const recursiveCheck = document.getElementById('recursiveCheck');
330
  const filterCheck = document.getElementById('filterCheck');
331
+ const corsWarning = document.getElementById('corsWarning');
332
 
333
  // Event listeners
334
  scrapeBtn.addEventListener('click', startScraping);
 
374
  progressText.textContent = '0%';
375
  statusText.textContent = 'Starting the digital heist...';
376
 
377
+ // Check if URL is from same origin
378
+ try {
379
+ const urlObj = new URL(url);
380
+ const currentOrigin = new URL(window.location.href).origin;
381
+
382
+ if (urlObj.origin === currentOrigin) {
383
+ // Same origin - we can scrape directly
384
+ corsWarning.classList.add('hidden');
385
+ scrapeSameOrigin(url);
386
+ } else {
387
+ // Different origin - need to use proxy
388
+ corsWarning.classList.remove('hidden');
389
+ scrapeWithProxy(url);
390
+ }
391
+ } catch (e) {
392
+ alert("INVALID URL! TRY AGAIN, COMRADE!");
393
+ progressContainer.classList.add('hidden');
394
+ }
395
  }
396
 
397
+ function scrapeSameOrigin(url) {
398
+ fetch(url)
399
+ .then(response => response.text())
400
+ .then(html => {
401
+ // Parse HTML and extract images
402
+ const parser = new DOMParser();
403
+ const doc = parser.parseFromString(html, 'text/html');
404
+ const images = doc.querySelectorAll('img');
405
+
406
+ // Update progress
407
+ progressFill.style.width = '50%';
408
+ progressText.textContent = '50%';
409
+ statusText.textContent = 'Found ' + images.length + ' images...';
410
+
411
+ // Process images
412
+ processImages(Array.from(images), url);
413
+ })
414
+ .catch(error => {
415
+ console.error('Error:', error);
416
+ statusText.textContent = 'Failed to scrape: ' + error.message;
417
+ setTimeout(() => {
418
+ progressContainer.classList.add('hidden');
419
+ }, 2000);
420
+ });
421
+ }
422
+
423
+ function scrapeWithProxy(url) {
424
+ // Using a CORS proxy - note: in production you'd want your own proxy server
425
+ const proxyUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`;
426
+
427
+ fetch(proxyUrl)
428
+ .then(response => response.json())
429
+ .then(data => {
430
+ if (data.contents) {
431
+ // Parse HTML and extract images
432
+ const parser = new DOMParser();
433
+ const doc = parser.parseFromString(data.contents, 'text/html');
434
+ const images = doc.querySelectorAll('img');
435
+
436
+ // Update progress
437
+ progressFill.style.width = '50%';
438
+ progressText.textContent = '50%';
439
+ statusText.textContent = 'Found ' + images.length + ' images...';
440
+
441
+ // Process images
442
+ processImages(Array.from(images), url);
443
+ } else {
444
+ throw new Error('Failed to get content through proxy');
445
+ }
446
+ })
447
+ .catch(error => {
448
+ console.error('Error:', error);
449
+ statusText.textContent = 'Failed to scrape: ' + error.message;
450
+ setTimeout(() => {
451
+ progressContainer.classList.add('hidden');
452
+ }, 2000);
453
+ });
454
+ }
455
+
456
+ function processImages(images, baseUrl) {
457
+ const baseUrlObj = new URL(baseUrl);
458
+ const filteredImages = [];
459
+
460
+ // Process each image
461
+ images.forEach((img, index) => {
462
+ let src = img.getAttribute('src') || '';
463
+ let width = img.width || 0;
464
+ let height = img.height || 0;
465
 
466
+ // Resolve relative URLs
467
+ if (src.startsWith('//')) {
468
+ src = baseUrlObj.protocol + src;
469
+ } else if (src.startsWith('/')) {
470
+ src = baseUrlObj.origin + src;
471
+ } else if (!src.startsWith('http')) {
472
+ src = new URL(src, baseUrl).href;
473
+ }
474
 
475
+ // Get file extension
476
+ let format = 'unknown';
477
+ const match = src.match(/\.(jpe?g|png|gif|webp|svg|bmp|tiff?|ico)/i);
478
+ if (match) {
479
+ format = match[1].toLowerCase();
 
 
 
480
  }
481
 
482
+ // Check if we should filter small images
483
+ const shouldFilter = filterCheck.checked;
484
+ if (!shouldFilter || (width > 100 && height > 100)) {
485
+ filteredImages.push({
486
+ url: src,
487
+ format: format,
488
+ width: width,
489
+ height: height,
490
+ originalUrl: src
491
+ });
492
+ }
493
+ });
494
+
495
+ // Update progress
496
+ progressFill.style.width = '80%';
497
+ progressText.textContent = '80%';
498
+ statusText.textContent = 'Processing ' + filteredImages.length + ' images...';
499
+
500
+ // Verify which images are accessible
501
+ verifyImageAccess(filteredImages);
502
+ }
503
+
504
+ function verifyImageAccess(images) {
505
+ let verifiedCount = 0;
506
+ const verifiedImages = [];
507
+
508
+ // Function to check image access
509
+ function checkImage(index) {
510
+ if (index >= images.length) {
511
+ // All images checked
512
+ scrapedImages = verifiedImages;
513
  finishScraping();
514
+ return;
515
  }
516
+
517
+ const img = images[index];
518
+ const testImg = new Image();
519
+
520
+ testImg.onload = function() {
521
+ // Image is accessible
522
+ verifiedImages.push(img);
523
+ verifiedCount++;
524
+
525
+ // Update progress
526
+ const progress = 80 + (20 * verifiedCount / images.length);
527
+ progressFill.style.width = progress + '%';
528
+ progressText.textContent = Math.floor(progress) + '%';
529
+ statusText.textContent = `Verified ${verifiedCount}/${images.length} images...`;
530
+
531
+ // Check next image
532
+ checkImage(index + 1);
533
+ };
534
+
535
+ testImg.onerror = function() {
536
+ // Image not accessible, skip it
537
+ verifiedCount++;
538
+
539
+ // Update progress
540
+ const progress = 80 + (20 * verifiedCount / images.length);
541
+ progressFill.style.width = progress + '%';
542
+ progressText.textContent = Math.floor(progress) + '%';
543
+ statusText.textContent = `Verified ${verifiedCount}/${images.length} images...`;
544
+
545
+ // Check next image
546
+ checkImage(index + 1);
547
+ };
548
+
549
+ testImg.src = img.url;
550
+ }
551
+
552
+ // Start checking images
553
+ checkImage(0);
554
  }
555
 
556
  function finishScraping() {
557
+ statusText.textContent = 'Done! Found ' + scrapedImages.length + ' accessible images.';
 
 
 
 
558
 
559
  // Display images
560
+ displayImages(scrapedImages);
561
 
562
  // Show results section
563
  resultsSection.classList.remove('hidden');
 
 
 
 
 
 
 
564
 
565
+ // Hide progress after delay
566
+ setTimeout(() => {
567
+ progressContainer.classList.add('hidden');
568
+ }, 2000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  }
570
 
571
  function displayImages(images) {
 
578
 
579
  tile.innerHTML = `
580
  <div class="relative pb-full">
581
+ <img src="${img.url}" alt="Scraped image" class="absolute h-full w-full object-cover" loading="lazy" onerror="this.parentElement.parentElement.remove()">
582
  </div>
583
  <div class="absolute bottom-0 left-0 right-0 bg-black bg-opacity-70 p-2 hidden group-hover:block">
584
  <span class="filetype-badge px-2 py-1 text-xs">${img.format.toUpperCase()}</span>
 
686
  return;
687
  }
688
 
689
+ // Create a zip file of selected images
690
  alert(`Preparing to download ${selectedImages.length} images...\n\n(In a real app, this would create a ZIP file)`);
691
 
692
+ // For demo purposes, we'll download each image individually
693
+ selectedImages.forEach(index => {
694
+ const img = scrapedImages[index];
695
+ const a = document.createElement('a');
696
+ a.href = img.url;
697
+ a.download = `stolen-image-${index}.${img.format}`;
698
+ a.target = '_blank';
699
+ document.body.appendChild(a);
700
+ a.click();
701
+ document.body.removeChild(a);
702
+ });
703
  }
704
 
705
  function showDeleteConfirmation() {
 
748
  // In a real app, this would convert images to the selected format
749
  alert(`Converting ${selectedImages.length} images to ${selectedFormat.toUpperCase()}...\n\n(In a real app, this would use a conversion API)`);
750
 
751
+ // Simulate conversion by changing the format in our data
752
+ selectedImages.forEach(index => {
753
+ scrapedImages[index].format = selectedFormat;
754
+ });
755
+
756
+ // Update the display
757
+ displayImages(scrapedImages);
758
+
759
+ // Show message
760
+ alert(`Conversion to ${selectedFormat.toUpperCase()} complete! Take that, capitalist image standards!`);
761
+ convertModal.classList.add('hidden');
762
  }
763
 
764
  // Close modals when clicking outside