jerrycans commited on
Commit
7366e94
·
verified ·
1 Parent(s): 6864d4c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -246
app.py CHANGED
@@ -1,24 +1,17 @@
1
- from flask import Flask, send_from_directory, jsonify
2
  import os
3
  import requests
4
  from pathlib import Path
5
  import threading
6
- import time
7
- import hashlib
8
 
9
  app = Flask(__name__)
10
 
11
  # Configuration
12
  LINKS_FILE = "links.txt"
13
- DOWNLOAD_PATH = "media"
14
 
15
- # Global state - shared across all users
16
  state = {
17
  "status": "idle",
18
- "progress": 0,
19
- "message": "Initializing...",
20
- "total_files": 0,
21
- "processed_files": 0,
22
  "images": []
23
  }
24
  state_lock = threading.Lock()
@@ -31,39 +24,6 @@ def get_state_copy():
31
  with state_lock:
32
  return dict(state)
33
 
34
- def get_images():
35
- extensions = {".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp"}
36
- images = []
37
- if os.path.exists(DOWNLOAD_PATH):
38
- for root, _, files in os.walk(DOWNLOAD_PATH):
39
- for file in files:
40
- if Path(file).suffix.lower() in extensions:
41
- rel_path = os.path.relpath(os.path.join(root, file), DOWNLOAD_PATH)
42
- images.append(rel_path)
43
- return sorted(images)
44
-
45
- def get_file_extension(url, content_type=None):
46
- url_path = url.split('?')[0]
47
- ext = Path(url_path).suffix.lower()
48
- if ext in {'.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'}:
49
- return ext
50
- if content_type:
51
- type_map = {
52
- 'image/jpeg': '.jpg',
53
- 'image/png': '.png',
54
- 'image/gif': '.gif',
55
- 'image/webp': '.webp',
56
- 'image/bmp': '.bmp'
57
- }
58
- for mime, extension in type_map.items():
59
- if mime in content_type:
60
- return extension
61
- return '.jpg'
62
-
63
- def generate_filename(url, index):
64
- url_hash = hashlib.md5(url.encode()).hexdigest()[:8]
65
- return f"image_{index:04d}_{url_hash}"
66
-
67
  def load_links():
68
  links = []
69
  if os.path.exists(LINKS_FILE):
@@ -74,73 +34,12 @@ def load_links():
74
  links.append(line)
75
  return links
76
 
77
- def download_images():
78
- existing_images = get_images()
79
- if existing_images:
80
- update_state(
81
- status="complete",
82
- progress=100,
83
- message=f"Ready! {len(existing_images)} images loaded",
84
- images=existing_images,
85
- total_files=len(existing_images),
86
- processed_files=len(existing_images)
87
- )
88
- return
89
-
90
  links = load_links()
91
- if not links:
92
- update_state(status="error", message="No links found in links.txt")
93
- return
94
-
95
- os.makedirs(DOWNLOAD_PATH, exist_ok=True)
96
- total = len(links)
97
-
98
- update_state(
99
- status="downloading",
100
- progress=0,
101
- message="Connecting...",
102
- total_files=total,
103
- processed_files=0
104
- )
105
-
106
- for i, url in enumerate(links):
107
- try:
108
- update_state(
109
- message=f"Downloading image {i + 1} of {total}",
110
- processed_files=i
111
- )
112
-
113
- response = requests.get(url, timeout=30, headers={
114
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
115
- })
116
- response.raise_for_status()
117
-
118
- content_type = response.headers.get('content-type', '')
119
- ext = get_file_extension(url, content_type)
120
- filename = generate_filename(url, i) + ext
121
- filepath = os.path.join(DOWNLOAD_PATH, filename)
122
-
123
- with open(filepath, 'wb') as f:
124
- f.write(response.content)
125
-
126
- progress = int((i + 1) / total * 100)
127
- update_state(progress=progress, processed_files=i + 1)
128
- time.sleep(0.05)
129
-
130
- except Exception as e:
131
- print(f"Failed to download {url}: {e}")
132
- continue
133
-
134
- images = get_images()
135
- if images:
136
- update_state(
137
- status="complete",
138
- progress=100,
139
- message=f"Complete! {len(images)} images ready",
140
- images=images
141
- )
142
  else:
143
- update_state(status="error", message="No images downloaded")
144
 
145
  HTML_PAGE = '''<!DOCTYPE html>
146
  <html lang="en">
@@ -224,76 +123,19 @@ HTML_PAGE = '''<!DOCTYPE html>
224
  .corner-bracket.bl { bottom: -6px; left: -6px; border-right: none; border-top: none; }
225
  .corner-bracket.br { bottom: -6px; right: -6px; border-left: none; border-top: none; }
226
 
227
- .progress-card {
228
- width: 100%;
229
- max-width: 400px;
230
- background: #000;
231
- border: 3px solid #fff;
232
- padding: 30px;
233
- }
234
-
235
- .progress-status {
236
- font-size: 16px;
237
- font-weight: 700;
238
  letter-spacing: 4px;
239
  color: #fff;
240
- margin-bottom: 20px;
241
- text-transform: uppercase;
242
- text-align: center;
243
  }
244
 
245
- .progress-bar-outer {
246
- width: 100%;
247
- height: 35px;
248
- background: #111;
249
- border: 2px solid #fff;
250
- position: relative;
251
- overflow: hidden;
252
- }
253
-
254
- .progress-bar-inner {
255
- height: 100%;
256
- background: #fff;
257
- width: 0%;
258
- transition: width 0.3s ease-out;
259
- }
260
-
261
- .progress-percent {
262
- position: absolute;
263
- top: 50%;
264
- left: 50%;
265
- transform: translate(-50%, -50%);
266
  font-size: 14px;
267
- font-weight: 800;
268
- color: #fff;
269
- z-index: 2;
270
- mix-blend-mode: difference;
271
- }
272
-
273
- .file-counter {
274
- display: flex;
275
- justify-content: center;
276
- gap: 5px;
277
- margin-top: 20px;
278
- font-size: 20px;
279
- font-weight: 800;
280
- }
281
-
282
- .file-counter .current { color: #fff; }
283
- .file-counter .separator { color: #444; }
284
- .file-counter .total { color: #666; }
285
-
286
- .progress-detail {
287
- margin-top: 15px;
288
- font-size: 11px;
289
- color: #888;
290
  text-align: center;
291
  }
292
 
293
- .error-message {
294
- color: #f44 !important;
295
- }
296
-
297
  /* ===== GALLERY ===== */
298
  #gallery-screen {
299
  display: none;
@@ -520,14 +362,6 @@ HTML_PAGE = '''<!DOCTYPE html>
520
  width: 100px;
521
  height: 100px;
522
  }
523
-
524
- .progress-card {
525
- padding: 25px 20px;
526
- }
527
-
528
- .progress-status {
529
- font-size: 14px;
530
- }
531
  }
532
 
533
  @media (max-width: 380px) {
@@ -550,23 +384,7 @@ HTML_PAGE = '''<!DOCTYPE html>
550
  <div class="corner-bracket br"></div>
551
  <img class="epstein-image" src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Epstein-mugshot.jpg/440px-Epstein-mugshot.jpg" alt="Loading">
552
  </div>
553
-
554
- <div class="progress-card">
555
- <div class="progress-status" id="status-text">LOADING</div>
556
-
557
- <div class="progress-bar-outer">
558
- <div class="progress-bar-inner" id="progress-bar"></div>
559
- <div class="progress-percent" id="progress-pct">0%</div>
560
- </div>
561
-
562
- <div class="file-counter">
563
- <span class="current" id="current-count">0</span>
564
- <span class="separator">/</span>
565
- <span class="total" id="total-count">0</span>
566
- </div>
567
-
568
- <div class="progress-detail" id="detail-text">Connecting...</div>
569
- </div>
570
  </div>
571
 
572
  <!-- Gallery Screen -->
@@ -601,33 +419,7 @@ HTML_PAGE = '''<!DOCTYPE html>
601
 
602
  const loadingScreen = document.getElementById('loading-screen');
603
  const galleryScreen = document.getElementById('gallery-screen');
604
- const progressBar = document.getElementById('progress-bar');
605
- const progressPct = document.getElementById('progress-pct');
606
- const statusText = document.getElementById('status-text');
607
- const detailText = document.getElementById('detail-text');
608
- const currentCount = document.getElementById('current-count');
609
- const totalCount = document.getElementById('total-count');
610
-
611
- function updateUI(data) {
612
- progressBar.style.width = data.progress + '%';
613
- progressPct.textContent = data.progress + '%';
614
- detailText.textContent = data.message;
615
- currentCount.textContent = data.processed_files || 0;
616
- totalCount.textContent = data.total_files || 0;
617
-
618
- if (data.status === 'idle') {
619
- statusText.textContent = 'CONNECTING';
620
- } else if (data.status === 'downloading') {
621
- statusText.textContent = 'DOWNLOADING';
622
- } else if (data.status === 'complete') {
623
- statusText.textContent = 'COMPLETE';
624
- showGallery(data.images);
625
- } else if (data.status === 'error') {
626
- statusText.textContent = 'ERROR';
627
- statusText.classList.add('error-message');
628
- detailText.classList.add('error-message');
629
- }
630
- }
631
 
632
  function showGallery(imageList) {
633
  images = imageList;
@@ -640,14 +432,14 @@ HTML_PAGE = '''<!DOCTYPE html>
640
  const grid = document.getElementById('gallery-grid');
641
  grid.innerHTML = '';
642
 
643
- images.forEach((img, idx) => {
644
  const item = document.createElement('div');
645
  item.className = 'gallery-item';
646
 
647
  const imgEl = document.createElement('img');
648
  imgEl.loading = 'lazy';
649
  imgEl.alt = 'File ' + (idx + 1);
650
- imgEl.src = '/media/' + encodeURIComponent(img);
651
 
652
  const number = document.createElement('div');
653
  number.className = 'item-number';
@@ -660,6 +452,11 @@ HTML_PAGE = '''<!DOCTYPE html>
660
  });
661
  }
662
 
 
 
 
 
 
663
  const lightbox = document.getElementById('lightbox');
664
  const lbImg = document.getElementById('lightbox-img');
665
  const lbCounter = document.getElementById('lb-counter');
@@ -678,7 +475,7 @@ HTML_PAGE = '''<!DOCTYPE html>
678
  }
679
 
680
  function updateLightbox() {
681
- lbImg.src = '/media/' + encodeURIComponent(images[currentIdx]);
682
  lbCounter.textContent = (currentIdx + 1) + ' / ' + images.length;
683
  lbFilename.textContent = 'FILE #' + (currentIdx + 1);
684
  }
@@ -720,19 +517,17 @@ HTML_PAGE = '''<!DOCTYPE html>
720
  }
721
  }, { passive: true });
722
 
723
- function poll() {
724
- fetch('/status')
725
- .then(r => r.json())
726
- .then(data => {
727
- updateUI(data);
728
- if (data.status !== 'complete' && data.status !== 'error') {
729
- setTimeout(poll, 300);
730
- }
731
- })
732
- .catch(() => setTimeout(poll, 1000));
733
- }
734
-
735
- poll();
736
  </script>
737
  </body>
738
  </html>'''
@@ -745,15 +540,8 @@ def index():
745
  def get_status():
746
  return jsonify(get_state_copy())
747
 
748
- @app.route('/media/<path:filename>')
749
- def serve_media(filename):
750
- return send_from_directory(DOWNLOAD_PATH, filename)
751
-
752
- def start_download():
753
- thread = threading.Thread(target=download_images, daemon=True)
754
- thread.start()
755
-
756
- start_download()
757
 
758
  if __name__ == "__main__":
759
  app.run(host="0.0.0.0", port=7860, threaded=True)
 
1
+ from flask import Flask, jsonify, Response
2
  import os
3
  import requests
4
  from pathlib import Path
5
  import threading
 
 
6
 
7
  app = Flask(__name__)
8
 
9
  # Configuration
10
  LINKS_FILE = "links.txt"
 
11
 
12
+ # Global state
13
  state = {
14
  "status": "idle",
 
 
 
 
15
  "images": []
16
  }
17
  state_lock = threading.Lock()
 
24
  with state_lock:
25
  return dict(state)
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  def load_links():
28
  links = []
29
  if os.path.exists(LINKS_FILE):
 
34
  links.append(line)
35
  return links
36
 
37
+ def init_images():
 
 
 
 
 
 
 
 
 
 
 
 
38
  links = load_links()
39
+ if links:
40
+ update_state(status="complete", images=links)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  else:
42
+ update_state(status="error", images=[])
43
 
44
  HTML_PAGE = '''<!DOCTYPE html>
45
  <html lang="en">
 
123
  .corner-bracket.bl { bottom: -6px; left: -6px; border-right: none; border-top: none; }
124
  .corner-bracket.br { bottom: -6px; right: -6px; border-left: none; border-top: none; }
125
 
126
+ .loading-text {
127
+ font-size: 14px;
 
 
 
 
 
 
 
 
 
128
  letter-spacing: 4px;
129
  color: #fff;
 
 
 
130
  }
131
 
132
+ .error-message {
133
+ color: #f44;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  font-size: 14px;
135
+ letter-spacing: 2px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  text-align: center;
137
  }
138
 
 
 
 
 
139
  /* ===== GALLERY ===== */
140
  #gallery-screen {
141
  display: none;
 
362
  width: 100px;
363
  height: 100px;
364
  }
 
 
 
 
 
 
 
 
365
  }
366
 
367
  @media (max-width: 380px) {
 
384
  <div class="corner-bracket br"></div>
385
  <img class="epstein-image" src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Epstein-mugshot.jpg/440px-Epstein-mugshot.jpg" alt="Loading">
386
  </div>
387
+ <div class="loading-text" id="loading-text">LOADING</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  </div>
389
 
390
  <!-- Gallery Screen -->
 
419
 
420
  const loadingScreen = document.getElementById('loading-screen');
421
  const galleryScreen = document.getElementById('gallery-screen');
422
+ const loadingText = document.getElementById('loading-text');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
  function showGallery(imageList) {
425
  images = imageList;
 
432
  const grid = document.getElementById('gallery-grid');
433
  grid.innerHTML = '';
434
 
435
+ images.forEach((url, idx) => {
436
  const item = document.createElement('div');
437
  item.className = 'gallery-item';
438
 
439
  const imgEl = document.createElement('img');
440
  imgEl.loading = 'lazy';
441
  imgEl.alt = 'File ' + (idx + 1);
442
+ imgEl.src = url;
443
 
444
  const number = document.createElement('div');
445
  number.className = 'item-number';
 
452
  });
453
  }
454
 
455
+ function showError(msg) {
456
+ loadingText.textContent = msg;
457
+ loadingText.classList.add('error-message');
458
+ }
459
+
460
  const lightbox = document.getElementById('lightbox');
461
  const lbImg = document.getElementById('lightbox-img');
462
  const lbCounter = document.getElementById('lb-counter');
 
475
  }
476
 
477
  function updateLightbox() {
478
+ lbImg.src = images[currentIdx];
479
  lbCounter.textContent = (currentIdx + 1) + ' / ' + images.length;
480
  lbFilename.textContent = 'FILE #' + (currentIdx + 1);
481
  }
 
517
  }
518
  }, { passive: true });
519
 
520
+ // Load images
521
+ fetch('/status')
522
+ .then(r => r.json())
523
+ .then(data => {
524
+ if (data.status === 'complete' && data.images.length > 0) {
525
+ showGallery(data.images);
526
+ } else {
527
+ showError('NO IMAGES FOUND');
528
+ }
529
+ })
530
+ .catch(() => showError('CONNECTION ERROR'));
 
 
531
  </script>
532
  </body>
533
  </html>'''
 
540
  def get_status():
541
  return jsonify(get_state_copy())
542
 
543
+ # Initialize on startup
544
+ init_images()
 
 
 
 
 
 
 
545
 
546
  if __name__ == "__main__":
547
  app.run(host="0.0.0.0", port=7860, threaded=True)