ChandimaPrabath commited on
Commit
a848cea
1 Parent(s): cd180fe
image_payload_reader.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ import yaml
3
+
4
+ def read_payload_from_image(image_path):
5
+ """
6
+ Reads and extracts the YAML payload embedded in the PNG image metadata.
7
+
8
+ Args:
9
+ image_path (str): Path to the PNG image file.
10
+
11
+ Returns:
12
+ dict or None: Extracted YAML payload as a dictionary if found, None otherwise.
13
+ """
14
+ try:
15
+ # Open the image with Pillow
16
+ img = Image.open(image_path)
17
+
18
+ # Check if the image is a PNG and has metadata
19
+ if img.format == "PNG" and isinstance(img.info, dict) and "YAML" in img.info:
20
+ yaml_data = img.info["YAML"]
21
+
22
+ # Convert YAML string to dictionary
23
+ payload = yaml.safe_load(yaml_data)
24
+ return payload
25
+ else:
26
+ print("No YAML payload found in the PNG image metadata.")
27
+ return None
28
+ except Exception as e:
29
+ print(f"Error reading payload from image: {e}")
30
+ return None
31
+
32
+ # Example usage if executed directly (not necessary in the module version)
33
+ if __name__ == "__main__":
34
+ image_path = "cache/image_20240624111031.png" # Replace with the actual path to your PNG image file
35
+ payload = read_payload_from_image(image_path)
36
+ if payload:
37
+ print("Extracted YAML payload:")
38
+ print(yaml.dump(payload, default_flow_style=False))
39
+ else:
40
+ print("Failed to extract YAML payload.")
imgbb.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ def extract_original_image_urls(url):
5
+ try:
6
+ # Make a GET request to fetch the raw HTML content
7
+ response = requests.get(url)
8
+ response.raise_for_status() # Raise an exception for HTTP errors
9
+
10
+ # Parse the content of the request with BeautifulSoup
11
+ soup = BeautifulSoup(response.content, 'html.parser')
12
+
13
+ # Find all img tags within the specified div structure
14
+ image_tags = soup.find_all('div', class_='list-item-image fixed-size')
15
+
16
+ # Extract original image URLs from img tags
17
+ original_image_urls = []
18
+ for img_tag in image_tags:
19
+ image_url = img_tag.find('img')['src']
20
+ original_image_urls.append(image_url)
21
+
22
+ return original_image_urls
23
+
24
+ except requests.RequestException as e:
25
+ print(f"Error fetching {url}: {e}")
26
+ return []
27
+
28
+ # Example usage:
29
+ if __name__ == "__main__":
30
+ base_url = 'https://unicone-studio.imgbb.com/'
31
+ image_urls = extract_original_image_urls(base_url)
32
+ for url in image_urls:
33
+ print(url)
statics/down-arrow.svg ADDED
statics/logo.png ADDED
statics/sort.svg ADDED
statics/up-arrow.svg ADDED
templates/index.html ADDED
@@ -0,0 +1,427 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Image Files Gallery</title>
7
+ <style>
8
+ body {
9
+ background-color: #1a1a1a; /* Dark background */
10
+ color: #ffffff; /* White text */
11
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
12
+ margin: 0;
13
+ padding: 0;
14
+ display: flex;
15
+ flex-direction: column;
16
+ align-items: center;
17
+ }
18
+ .navbar {
19
+ width: 100%;
20
+ background-color: #1c1c36; /* Darker navbar background */
21
+ padding: 10px;
22
+ display: flex;
23
+ text-align: center;
24
+ justify-content: center;
25
+ align-items: center;
26
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
27
+ position: fixed;
28
+ top: 0;
29
+ left: 0;
30
+ z-index: 1000;
31
+ }
32
+ .navbar h1 {
33
+ margin: 0;
34
+ font-size: 2em; /* Larger font size */
35
+ color: #bd93f9; /* Bright purple */
36
+ }
37
+
38
+ @keyframes colorChange {
39
+ 0% {
40
+ color: rgb(67, 252, 0);
41
+ }
42
+ 50% {
43
+ color: rgb(93, 195, 55);
44
+ }
45
+ 100% {
46
+ color: rgb(67, 252, 0);
47
+ }
48
+ }
49
+
50
+ #version{
51
+ width: 130px;
52
+ position: relative;
53
+ top: -15px;
54
+ right: 21px;
55
+ font-weight: bolder;
56
+ animation: colorChange .5s infinite;
57
+ }
58
+
59
+ .image-container {
60
+ width: 100%;
61
+ max-width: 1200px;
62
+ margin-top: 75px; /* Adjusted margin for fixed navbar and sort button */
63
+ display: flex;
64
+ flex-wrap: wrap;
65
+ justify-content: center;
66
+ gap: 20px;
67
+ padding: 20px;
68
+ scroll-behavior: smooth;
69
+ }
70
+ .image-item {
71
+ background-color: #1f1f2a; /* Darker background */
72
+ border-radius: 8px;
73
+ overflow: hidden;
74
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
75
+ width: calc(33.33% - 20px); /* Three items per row with gap */
76
+ margin-bottom: 20px;
77
+ transition: transform 0.3s ease; /* Smooth transform animation */
78
+ display: flex; /* Make container flex to align image and metadata */
79
+ flex-direction: column; /* Stack image and metadata vertically */
80
+ align-items: center; /* Center items horizontally */
81
+ position: relative; /* Position for absolute time display */
82
+ }
83
+ .image-item:hover {
84
+ transform: scale(1.05); /* Scale up on hover */
85
+ }
86
+ .image-item img {
87
+ max-width: 100%;
88
+ border-radius: 8px;
89
+ cursor: pointer;
90
+ transition: transform 0.3s ease; /* Smooth transform animation */
91
+ }
92
+ .image-item:hover img {
93
+ transform: scale(1.1); /* Scale up image on hover */
94
+ }
95
+ .image-item .created-at {
96
+ background-color: #20203f; /* Dark background for yaml data */
97
+ color: #ffffff;
98
+ text-align: center;
99
+ padding: 8px 16px;
100
+ border-top-left-radius: 8px;
101
+ border-top-right-radius: 8px;
102
+ width: 100%; /* Full width */
103
+ font-size: 0.8em; /* Smaller font size */
104
+ position: absolute; /* Position at the top */
105
+ top: 0; /* Align to the top */
106
+ }
107
+ .pre {
108
+ max-width: 370px;
109
+ overflow: scroll;
110
+ }
111
+ .spinner {
112
+ border: 4px solid rgba(255, 255, 255, 0.3);
113
+ border-radius: 50%;
114
+ border-top: 4px solid #bd93f9; /* Bright purple */
115
+ width: 40px;
116
+ height: 40px;
117
+ animation: spin 1s linear infinite;
118
+ display: none;
119
+ margin-top: 20px;
120
+ }
121
+ .load-more {
122
+ top: -20px;
123
+ padding: 5px;
124
+ margin-bottom: 20px;
125
+ background-color: #a2a2a2; /* Bright purple */
126
+ color: #ffffff;
127
+ border: none;
128
+ padding: 10px;
129
+ border-radius: 100%;
130
+ cursor: pointer;
131
+ transition: background-color 0.3s ease, transform 0.2s ease; /* Smooth background and transform animations */
132
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* Box shadow for depth */
133
+ align-items: center;
134
+ display: flex;
135
+ }
136
+ .load-more:hover {
137
+ background-color: #6272a4; /* Darker hover color */
138
+ transform: translateY(-2px); /* Lift button slightly on hover */
139
+ }
140
+
141
+ .sort-btn {
142
+ margin-top: 85px;
143
+ background-color: #a2a2a2;
144
+ color: #ffffff;
145
+ border: none;
146
+ border-radius: 25px;
147
+ cursor: pointer;
148
+ transition: background-color 0.3s ease, transform 0.2s ease;
149
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
150
+ position: fixed;
151
+ right: 4%;
152
+ z-index: 1;
153
+ }
154
+
155
+ .sort-btn:hover {
156
+ background-color: #6272a4; /* Darker hover color */
157
+ transform: translateY(-2px); /* Lift button slightly on hover */
158
+ }
159
+
160
+ .go-to-top-btn {
161
+ position: fixed;
162
+ bottom: 20px;
163
+ right: 4%;
164
+ background-color: #a2a2a2; /* Bright purple */
165
+ color: #ffffff;
166
+ border: none;
167
+ border-radius: 25px;
168
+ cursor: pointer;
169
+ display: none;
170
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
171
+ transition: background-color 0.3s ease, transform 0.2s ease; /* Smooth background and transform animations */
172
+ }
173
+
174
+
175
+ .go-to-top-btn:hover {
176
+ background-color: #6272a4; /* Darker hover color */
177
+ transform: translateY(-2px); /* Lift button slightly on hover */
178
+ }
179
+
180
+ @keyframes spin {
181
+ 0% { transform: rotate(0deg); }
182
+ 100% { transform: rotate(360deg); }
183
+ }
184
+ @media (max-width: 1200px) {
185
+ .image-item {
186
+ width: calc(50% - 20px); /* Two items per row on smaller screens */
187
+ }
188
+ }
189
+ @media (max-width: 900px) {
190
+ .image-item {
191
+ width: calc(33.33% - 20px); /* Three items per row on smaller screens */
192
+ }
193
+ }
194
+ @media (max-width: 600px) {
195
+ .image-item {
196
+ width: calc(50% - 20px); /* Two items per row on smaller screens */
197
+ }
198
+ .navbar h1 {
199
+ font-size: 1.5em; /* Adjusted font size for smaller screens */
200
+ }
201
+ .image-item .created-at {
202
+ font-size: 0.7em; /* Adjusted font size for smaller screens */
203
+ }
204
+ }
205
+ @media (max-width: 400px) {
206
+ .image-item {
207
+ width: calc(100% - 20px); /* One item per row on very small screens */
208
+ }
209
+ }
210
+ </style>
211
+
212
+ </head>
213
+ <body>
214
+ <div class="navbar">
215
+ <img style="width:60px; border-radius: 20px; margin-right: 10px;" src="/statics/logo.png" alt="logo">
216
+ <h1 style="color: white;">SpaceBullet </h1>
217
+ <h1 style="margin-left: 10px;">Gallery</h1>
218
+ <version id="version"></version>
219
+ </div>
220
+ <button class="sort-btn" id="sort-btn" title="Sort"><img style="color: black;" width="30px" src="/statics/sort.svg" alt="sort"></button>
221
+ <div class="image-container" id="image-container"></div>
222
+ <div class="spinner" id="spinner"></div>
223
+ <button class="load-more" id="load-more-btn" title="Load More"><img width="30px" src="/statics/down-arrow.svg" alt="load-more"></button>
224
+ <button class="go-to-top-btn" id="go-to-top-btn" title="Go to Top"><img width="30px" src="/statics/up-arrow.svg" alt="Go to the Top"></button>
225
+ <script>
226
+ function getInfo() {
227
+ fetch('/info')
228
+ .then(response => {
229
+ if (!response.ok) {
230
+ throw new Error('Network response was not ok');
231
+ }
232
+ return response.json();
233
+ })
234
+ .then(data => {
235
+ // Assuming you want to log the retrieved information
236
+ console.log('Info retrieved:', data);
237
+ const versionElement = document.getElementById('version');
238
+ if (versionElement) {
239
+ // Extract the 'version' property from the data object
240
+ const version = data['version'];
241
+ versionElement.textContent = `${version}`;
242
+ }
243
+ })
244
+ .catch(error => {
245
+ console.error('Error fetching info:', error);
246
+ });
247
+ }
248
+
249
+ // Execute getInfo function when the window loads
250
+ window.onload = getInfo;
251
+ </script>
252
+ <script>
253
+ document.addEventListener('DOMContentLoaded', () => {
254
+ let allImages = [];
255
+ let page = 0;
256
+ const pageSize = 20;
257
+ let loading = false;
258
+ let loadedImageNames = new Set(); // Set to track loaded image names
259
+ let sortClicked = false; // Track if sort button has been clicked
260
+
261
+ async function fetchImages() {
262
+ const response = await fetch('/images');
263
+ return response.json();
264
+ }
265
+
266
+ function createImageItem(image, yaml) {
267
+ const container = document.createElement('div');
268
+ container.className = 'image-item';
269
+
270
+ const img = document.createElement('img');
271
+ img.src = `/cache/${image}`;
272
+ img.alt = image;
273
+ img.onerror = () => {
274
+ container.style.display = 'none';
275
+ };
276
+
277
+ const pre = document.createElement('pre');
278
+ pre.className = 'pre';
279
+ const pre_json = JSON.stringify(yaml, null, 2);
280
+ if (pre_json === '{}') {
281
+ console.log(`YAML data is null for image: ${image}`);
282
+ pre.textContent = "Prompt data unavailable";
283
+
284
+ // Fetch YAML data from /yaml route
285
+ fetch(`/yaml/${image}`)
286
+ .then(response => {
287
+ if (!response.ok) {
288
+ throw new Error(`HTTP error! Status: ${response.status}`);
289
+ }
290
+ return response.json();
291
+ })
292
+ .then(data => {
293
+ if (data) {
294
+ // Update the pre element with fetched YAML data
295
+ pre.textContent = JSON.stringify(data, null, 2);
296
+ } else {
297
+ console.log(`No YAML data found for image: ${image}`);
298
+ }
299
+ })
300
+ .catch(error => {
301
+ console.error('Error fetching YAML data:', error);
302
+ });
303
+ } else {
304
+ pre.textContent = pre_json;
305
+ }
306
+
307
+ const createdAt = document.createElement('div');
308
+ createdAt.className = 'created-at';
309
+ const createdAtDate = getImageCreatedDate(image); // Get formatted date from image name
310
+ createdAt.textContent = `Generated: ${createdAtDate}`;
311
+
312
+ container.appendChild(img);
313
+ container.appendChild(createdAt);
314
+ container.appendChild(pre);
315
+
316
+ return container;
317
+ }
318
+
319
+ function getImageCreatedDate(imageName) {
320
+ // Assuming imageName format: image_YYYYMMDDHHMMSS.jpg
321
+ const year = imageName.substr(6, 4);
322
+ const month = imageName.substr(10, 2);
323
+ const day = imageName.substr(12, 2);
324
+ const hour24 = imageName.substr(14, 2);
325
+ const minute = imageName.substr(16, 2);
326
+ const second = imageName.substr(18, 2);
327
+
328
+ // Convert 24-hour format to 12-hour format
329
+ let hour12 = hour24 % 12;
330
+ hour12 = hour12 ? hour12 : 12; // If hour is 0, set it to 12
331
+
332
+ const period = hour24 >= 12 ? 'PM' : 'AM';
333
+
334
+ return `${day}/${month}/${year} ${hour12}:${minute}:${second} ${period}`;
335
+ }
336
+
337
+ async function loadImages() {
338
+ if (loading) return;
339
+ loading = true;
340
+ const spinner = document.getElementById('spinner');
341
+ spinner.style.display = 'block';
342
+
343
+ const data = await fetchImages();
344
+ allImages = data.image_files.reverse(); // Reverse the order of images
345
+ displayImages(allImages.slice(0, pageSize));
346
+
347
+ spinner.style.display = 'none';
348
+ loading = false;
349
+ }
350
+
351
+ function displayImages(images) {
352
+ const imageContainer = document.getElementById('image-container');
353
+ images.forEach(item => {
354
+ if (!loadedImageNames.has(item.image)) { // Check if image is already loaded
355
+ const imageItem = createImageItem(item.image, item.yaml);
356
+ imageContainer.appendChild(imageItem);
357
+ loadedImageNames.add(item.image); // Add image name to loaded set
358
+ }
359
+ });
360
+ }
361
+
362
+ function sortDisplayImages(images) {
363
+ const imageContainer = document.getElementById('image-container');
364
+ imageContainer.innerHTML = '';
365
+ images.forEach(item => {
366
+ if (!loadedImageNames.has(item.image)) { // Check if image is already loaded
367
+ const imageItem = createImageItem(item.image, item.yaml);
368
+ imageContainer.appendChild(imageItem);
369
+ loadedImageNames.add(item.image); // Add image name to loaded set
370
+ }
371
+ });
372
+ }
373
+
374
+ async function loadMoreImages() {
375
+ if (loading) return;
376
+ loading = true;
377
+ const start = page * pageSize;
378
+ const end = start + pageSize;
379
+ const images = allImages.slice(start, end);
380
+
381
+ if (images.length === 0) {
382
+ const loadMoreBtn = document.getElementById('load-more-btn');
383
+ loadMoreBtn.style.display = 'none';
384
+ } else {
385
+ displayImages(images);
386
+ page++;
387
+ }
388
+
389
+ loading = false;
390
+ }
391
+
392
+ const loadMoreBtn = document.getElementById('load-more-btn');
393
+ loadMoreBtn.addEventListener('click', loadMoreImages);
394
+
395
+ const sortBtn = document.getElementById('sort-btn');
396
+ sortBtn.addEventListener('click', () => {
397
+ console.log('Sort button clicked');
398
+ if (!sortClicked) {
399
+ allImages.reverse();
400
+ sortDisplayImages(allImages.slice(0, pageSize));
401
+ sortClicked = true;
402
+ } else {
403
+ location.reload(); // Reload the webpage if sort button clicked again
404
+ }
405
+ });
406
+
407
+ const goToTopBtn = document.getElementById('go-to-top-btn');
408
+ window.addEventListener('scroll', () => {
409
+ if (window.scrollY > 300) {
410
+ goToTopBtn.style.display = 'block';
411
+ } else {
412
+ goToTopBtn.style.display = 'none';
413
+ }
414
+ });
415
+
416
+ goToTopBtn.addEventListener('click', () => {
417
+ window.scrollTo({
418
+ top: 0,
419
+ behavior: 'smooth'
420
+ });
421
+ });
422
+
423
+ loadImages(); // Initial load of images
424
+ });
425
+ </script>
426
+ </body>
427
+ </html>