Sada8888 commited on
Commit
46517fa
·
verified ·
1 Parent(s): cfc4d00

Update templates/video.html

Browse files
Files changed (1) hide show
  1. templates/video.html +315 -5
templates/video.html CHANGED
@@ -234,6 +234,106 @@
234
  .frame-preview-item span { font-size: 0.8rem; font-weight: 600; color: var(--text-secondary); }
235
  #frame-loader { border: 4px solid var(--input-border); border-top: 4px solid var(--accent-primary); border-radius: 50%; width: 40px; height: 40px; animation: ring-rotate 1s linear infinite; margin: 2rem auto; }
236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  @media (max-width: 768px) { main { padding: 3rem 1.5rem; } h1 { font-size: 2.2rem; } .generator-container { height: 250px; } .text-overlay { font-size: 18px; } #previous-results-wrapper { grid-template-columns: 1fr; } }
238
  </style>
239
  </head>
@@ -342,6 +442,23 @@
342
  </div>
343
  </div>
344
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
 
346
  <div id="restart-section" style="display: none; text-align: center; margin-top: 2rem;">
347
  <button id="btnRestart" class="video-button">
@@ -441,10 +558,80 @@
441
  // --- دیتابیس حافظه مرورگر برای ذخیره سوابق ---
442
  const projectDB = {
443
  db: null,
444
- init() { return new Promise((resolve, reject) => { const request = indexedDB.open('AIStudioDB_V2', 1); request.onupgradeneeded = event => { const db = event.target.result; if (!db.objectStoreNames.contains('projectState')) { db.createObjectStore('projectState'); } }; request.onsuccess = event => { this.db = event.target.result; resolve(); }; request.onerror = event => { console.error('IndexedDB error:', event.target.errorCode); reject(event.target.errorCode); }; }); },
 
 
 
 
 
 
 
 
 
 
 
 
 
445
  save(key, value) { return new Promise((resolve, reject) => { if (!this.db) return reject("DB not initialized"); const transaction = this.db.transaction(['projectState'], 'readwrite'); const store = transaction.objectStore('projectState'); const request = store.put(value, key); request.onsuccess = () => resolve(); request.onerror = (event) => reject(event.target.error); }); },
446
  get(key) { return new Promise((resolve, reject) => { if (!this.db) return reject("DB not initialized"); const transaction = this.db.transaction(['projectState'], 'readonly'); const store = transaction.objectStore('projectState'); const request = store.get(key); request.onsuccess = () => resolve(request.result); request.onerror = (event) => reject(event.target.error); }); },
447
- delete(key) { return new Promise((resolve, reject) => { if (!this.db) return reject("DB not initialized"); const transaction = this.db.transaction(['projectState'], 'readwrite'); const store = transaction.objectStore('projectState'); const request = store.delete(key); request.onsuccess = () => resolve(); request.onerror = (event) => reject(event.target.error); }); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  };
449
 
450
  // --- سیستم احراز و اعتبار ---
@@ -599,6 +786,18 @@
599
  statusMessagesDiv.innerHTML = '';
600
  clearInterval(fakeProgressInterval);
601
  tvProgressBar.style.width = '0%';
 
 
 
 
 
 
 
 
 
 
 
 
602
  aiLoader.style.display = 'none';
603
  }
604
 
@@ -910,8 +1109,18 @@
910
 
911
  setTimeout(() => {
912
  gallerySeparator.style.display = 'none';
913
- statusSection.classList.remove('active');
914
- aiLoader.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
915
  restartSection.style.display = 'block';
916
  setUiLock(false);
917
  setGenerateButtonState("ساخت ویدیو جادویی", false);
@@ -1121,10 +1330,111 @@
1121
  } catch(error) { console.error("Could not load project from DB:", error); }
1122
  }
1123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1124
  document.addEventListener('DOMContentLoaded', async () => {
1125
  userFingerprint = await getBrowserFingerprint();
1126
  parent.postMessage({ type: 'REQUEST_USER_DATA' }, '*');
1127
- try { await projectDB.init(); await initializeForm(); await loadStoredProject(); }
 
 
 
 
 
1128
  catch (error) { console.error("Failed to init DB or load project:", error); }
1129
  });
1130
 
 
234
  .frame-preview-item span { font-size: 0.8rem; font-weight: 600; color: var(--text-secondary); }
235
  #frame-loader { border: 4px solid var(--input-border); border-top: 4px solid var(--accent-primary); border-radius: 50%; width: 40px; height: 40px; animation: ring-rotate 1s linear infinite; margin: 2rem auto; }
236
 
237
+ /* استایل‌های سابقه تصاویر */
238
+ .history-item {
239
+ background: var(--panel-bg);
240
+ border: 1px solid var(--panel-border);
241
+ border-radius: var(--radius-input);
242
+ padding: 0.75rem;
243
+ box-shadow: var(--shadow-sm);
244
+ display: flex;
245
+ flex-direction: column;
246
+ gap: 0.75rem;
247
+ transition: var(--transition-smooth);
248
+ }
249
+ .history-item:hover {
250
+ box-shadow: var(--shadow-md);
251
+ border-color: var(--accent-primary);
252
+ }
253
+ .history-item img {
254
+ width: 100%;
255
+ height: 160px;
256
+ object-fit: cover;
257
+ border-radius: 8px;
258
+ cursor: pointer;
259
+ transition: var(--transition-smooth);
260
+ }
261
+ .history-item img:hover {
262
+ filter: brightness(0.9);
263
+ }
264
+ .history-item-details {
265
+ font-size: 0.85rem;
266
+ color: var(--text-secondary);
267
+ display: flex;
268
+ flex-direction: column;
269
+ gap: 0.3rem;
270
+ }
271
+ .history-item-prompt {
272
+ font-weight: 700;
273
+ color: var(--text-primary);
274
+ white-space: nowrap;
275
+ overflow: hidden;
276
+ text-overflow: ellipsis;
277
+ margin-bottom: 0.2rem;
278
+ }
279
+ .history-item-meta {
280
+ display: flex;
281
+ justify-content: space-between;
282
+ background: var(--input-bg);
283
+ padding: 0.2rem 0.5rem;
284
+ border-radius: 4px;
285
+ font-size: 0.8rem;
286
+ }
287
+ .history-item-meta span {
288
+ font-weight: 600;
289
+ color: var(--accent-primary);
290
+ }
291
+ .history-delete-btn {
292
+ position: absolute;
293
+ top: 50%;
294
+ left: 50%;
295
+ transform: translate(-50%, -50%);
296
+ width: 44px;
297
+ height: 44px;
298
+ background-color: rgba(229, 62, 62, 0.9);
299
+ color: white;
300
+ border: none;
301
+ border-radius: 50%;
302
+ display: flex;
303
+ align-items: center;
304
+ justify-content: center;
305
+ cursor: pointer;
306
+ opacity: 0;
307
+ visibility: hidden;
308
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
309
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
310
+ z-index: 10;
311
+ }
312
+ .history-delete-btn:hover {
313
+ background-color: var(--danger-color-hover);
314
+ transform: translate(-50%, -50%) scale(1.15);
315
+ }
316
+ #clear-history-btn {
317
+ display: inline-flex;
318
+ align-items: center;
319
+ justify-content: center;
320
+ padding: 0.5rem 1rem;
321
+ border-radius: var(--radius-btn);
322
+ border: 1px solid var(--danger-color);
323
+ background: transparent;
324
+ color: var(--danger-color);
325
+ font-family: var(--app-font);
326
+ font-weight: 600;
327
+ font-size: 0.9rem;
328
+ cursor: pointer;
329
+ transition: var(--transition-smooth);
330
+ }
331
+ #clear-history-btn:hover {
332
+ background-color: var(--danger-color);
333
+ color: white !important;
334
+ transform: translateY(-2px);
335
+ }
336
+
337
  @media (max-width: 768px) { main { padding: 3rem 1.5rem; } h1 { font-size: 2.2rem; } .generator-container { height: 250px; } .text-overlay { font-size: 18px; } #previous-results-wrapper { grid-template-columns: 1fr; } }
338
  </style>
339
  </head>
 
442
  </div>
443
  </div>
444
  </div>
445
+
446
+ <!-- بخش جدید سابقه تصاویر ساخته شده -->
447
+ <div class="form-group" style="margin-top: 3.5rem;">
448
+ <div class="form-label" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
449
+ <div style="display: flex; align-items: center; gap: 0.75rem;">
450
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
451
+ سابقه تصاویر ساخته شده
452
+ </div>
453
+ <button id="clear-history-btn">
454
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
455
+ حذف همه
456
+ </button>
457
+ </div>
458
+ <div id="image-history-container" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1.5rem; margin-top: 1.5rem;">
459
+ <!-- آیتم‌های سابقه از طریق JS لود می‌شوند -->
460
+ </div>
461
+ </div>
462
 
463
  <div id="restart-section" style="display: none; text-align: center; margin-top: 2rem;">
464
  <button id="btnRestart" class="video-button">
 
558
  // --- دیتابیس حافظه مرورگر برای ذخیره سوابق ---
559
  const projectDB = {
560
  db: null,
561
+ init() { return new Promise((resolve, reject) => {
562
+ const request = indexedDB.open('AIStudioDB_V2', 2);
563
+ request.onupgradeneeded = event => {
564
+ const db = event.target.result;
565
+ if (!db.objectStoreNames.contains('projectState')) {
566
+ db.createObjectStore('projectState');
567
+ }
568
+ if (!db.objectStoreNames.contains('imageHistory')) {
569
+ db.createObjectStore('imageHistory', { keyPath: 'id' });
570
+ }
571
+ };
572
+ request.onsuccess = event => { this.db = event.target.result; resolve(); };
573
+ request.onerror = event => { console.error('IndexedDB error:', event.target.errorCode); reject(event.target.errorCode); };
574
+ }); },
575
  save(key, value) { return new Promise((resolve, reject) => { if (!this.db) return reject("DB not initialized"); const transaction = this.db.transaction(['projectState'], 'readwrite'); const store = transaction.objectStore('projectState'); const request = store.put(value, key); request.onsuccess = () => resolve(); request.onerror = (event) => reject(event.target.error); }); },
576
  get(key) { return new Promise((resolve, reject) => { if (!this.db) return reject("DB not initialized"); const transaction = this.db.transaction(['projectState'], 'readonly'); const store = transaction.objectStore('projectState'); const request = store.get(key); request.onsuccess = () => resolve(request.result); request.onerror = (event) => reject(event.target.error); }); },
577
+ delete(key) { return new Promise((resolve, reject) => { if (!this.db) return reject("DB not initialized"); const transaction = this.db.transaction(['projectState'], 'readwrite'); const store = transaction.objectStore('projectState'); const request = store.delete(key); request.onsuccess = () => resolve(); request.onerror = (event) => reject(event.target.error); }); },
578
+
579
+ // --- بخش توابع سابقه تصاویر ساخته شده ---
580
+ saveHistoryImage(item) {
581
+ return new Promise(async (resolve, reject) => {
582
+ try {
583
+ const allItems = await this.getHistoryImages();
584
+ const transaction = this.db.transaction(['imageHistory'], 'readwrite');
585
+ const store = transaction.objectStore('imageHistory');
586
+
587
+ // نگهداری فقط 50 مورد آخر
588
+ if (allItems.length >= 50) {
589
+ const itemsToDelete = allItems.slice(49);
590
+ for (const oldItem of itemsToDelete) {
591
+ store.delete(oldItem.id);
592
+ }
593
+ }
594
+
595
+ const request = store.put(item);
596
+ request.onsuccess = () => resolve();
597
+ request.onerror = (event) => reject(event.target.error);
598
+ } catch (err) {
599
+ reject(err);
600
+ }
601
+ });
602
+ },
603
+ getHistoryImages() {
604
+ return new Promise((resolve, reject) => {
605
+ if (!this.db) return reject("DB not initialized");
606
+ const transaction = this.db.transaction(['imageHistory'], 'readonly');
607
+ const store = transaction.objectStore('imageHistory');
608
+ const request = store.getAll();
609
+ request.onsuccess = () => {
610
+ let items = request.result;
611
+ items.sort((a, b) => b.timestamp - a.timestamp); // نزولی بر اساس زمان
612
+ resolve(items);
613
+ };
614
+ request.onerror = (event) => reject(event.target.error);
615
+ });
616
+ },
617
+ deleteHistoryImage(id) {
618
+ return new Promise((resolve, reject) => {
619
+ const transaction = this.db.transaction(['imageHistory'], 'readwrite');
620
+ const store = transaction.objectStore('imageHistory');
621
+ const request = store.delete(id);
622
+ request.onsuccess = () => resolve();
623
+ request.onerror = (event) => reject(event.target.error);
624
+ });
625
+ },
626
+ clearAllHistoryImages() {
627
+ return new Promise((resolve, reject) => {
628
+ const transaction = this.db.transaction(['imageHistory'], 'readwrite');
629
+ const store = transaction.objectStore('imageHistory');
630
+ const request = store.clear();
631
+ request.onsuccess = () => resolve();
632
+ request.onerror = (event) => reject(event.target.error);
633
+ });
634
+ }
635
  };
636
 
637
  // --- سیستم احراز و اعتبار ---
 
786
  statusMessagesDiv.innerHTML = '';
787
  clearInterval(fakeProgressInterval);
788
  tvProgressBar.style.width = '0%';
789
+
790
+ // بازگردانی استایل‌های تلویزیون به حالت اولیه
791
+ const generatorContainer = document.querySelector('.generator-container');
792
+ if(generatorContainer) {
793
+ generatorContainer.style.animation = 'pulse-loader 5s infinite cubic-bezier(0.4, 0, 0.6, 1)';
794
+ generatorContainer.style.boxShadow = '0 0 40px rgba(56, 189, 248, 0.3)';
795
+ generatorContainer.style.borderColor = '#38bdf8';
796
+ }
797
+ const particles = document.querySelector('.particles');
798
+ if(particles) particles.style.display = 'block';
799
+ loaderTextOverlay.textContent = "در حال پردازش ویدیو...";
800
+
801
  aiLoader.style.display = 'none';
802
  }
803
 
 
1109
 
1110
  setTimeout(() => {
1111
  gallerySeparator.style.display = 'none';
1112
+
1113
+ // جلوگیری از محو شدن تلویزیون و نمایش موفقیت
1114
+ loaderTextOverlay.textContent = "ویدیوی شما آماده است!";
1115
+ const generatorContainer = document.querySelector('.generator-container');
1116
+ if(generatorContainer) {
1117
+ generatorContainer.style.animation = 'none';
1118
+ generatorContainer.style.boxShadow = '0 0 30px rgba(15, 212, 168, 0.4)';
1119
+ generatorContainer.style.borderColor = 'var(--success-color)';
1120
+ }
1121
+ const particles = document.querySelector('.particles');
1122
+ if(particles) particles.style.display = 'none';
1123
+
1124
  restartSection.style.display = 'block';
1125
  setUiLock(false);
1126
  setGenerateButtonState("ساخت ویدیو جادویی", false);
 
1330
  } catch(error) { console.error("Could not load project from DB:", error); }
1331
  }
1332
 
1333
+ // --- توابع رابط کاربری سابقه تصاویر ---
1334
+ async function loadHistoryImages() {
1335
+ try {
1336
+ const images = await projectDB.getHistoryImages();
1337
+ const container = document.getElementById('image-history-container');
1338
+ container.innerHTML = '';
1339
+
1340
+ if (images.length === 0) {
1341
+ container.innerHTML = '<p style="grid-column: 1 / -1; text-align: center; color: var(--text-tertiary); background: var(--input-bg); padding: 2rem; border-radius: var(--radius-card); border: 2px dashed var(--input-border);">سابقه‌ای وجود ندارد</p>';
1342
+ return;
1343
+ }
1344
+
1345
+ images.forEach(item => {
1346
+ const div = document.createElement('div');
1347
+ div.className = 'history-item';
1348
+
1349
+ const objectURL = URL.createObjectURL(item.blob);
1350
+
1351
+ div.innerHTML = `
1352
+ <div style="position: relative;">
1353
+ <img src="${objectURL}" alt="Generated Image" onclick="toggleDeleteBtn(this)">
1354
+ <button class="history-delete-btn" title="حذف تصویر" onclick="deleteHistoryItem(${item.id}, this)">
1355
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width: 20px; height: 20px;"><path d="M3 6h18"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
1356
+ </button>
1357
+ </div>
1358
+ <div class="history-item-details">
1359
+ <div class="history-item-prompt" title="${item.prompt || ''}">${item.prompt || 'بدون متن'}</div>
1360
+ <div class="history-item-meta">مدل: <span>${item.model || 'نامشخص'}</span></div>
1361
+ <div class="history-item-meta">اندازه: <span>${item.size || 'نامشخص'}</span></div>
1362
+ </div>
1363
+ `;
1364
+ container.appendChild(div);
1365
+ });
1366
+ } catch (err) {
1367
+ console.error('Error loading history:', err);
1368
+ }
1369
+ }
1370
+
1371
+ window.toggleDeleteBtn = function(imgElement) {
1372
+ const btn = imgElement.nextElementSibling;
1373
+ const allBtns = document.querySelectorAll('.history-delete-btn');
1374
+
1375
+ allBtns.forEach(b => {
1376
+ if (b !== btn) {
1377
+ b.style.opacity = '0';
1378
+ b.style.visibility = 'hidden';
1379
+ }
1380
+ });
1381
+
1382
+ if (btn.style.opacity === '1') {
1383
+ btn.style.opacity = '0';
1384
+ btn.style.visibility = 'hidden';
1385
+ } else {
1386
+ btn.style.opacity = '1';
1387
+ btn.style.visibility = 'visible';
1388
+ }
1389
+ };
1390
+
1391
+ window.deleteHistoryItem = async function(id, btnElement) {
1392
+ try {
1393
+ await projectDB.deleteHistoryImage(id);
1394
+ await loadHistoryImages();
1395
+ } catch (err) {
1396
+ console.error('Error deleting item:', err);
1397
+ }
1398
+ };
1399
+
1400
+ document.getElementById('clear-history-btn').addEventListener('click', async () => {
1401
+ if (confirm('آیا از حذف تمام تصاویر سابقه اطمینان دارید؟')) {
1402
+ try {
1403
+ await projectDB.clearAllHistoryImages();
1404
+ await loadHistoryImages();
1405
+ } catch (err) {
1406
+ console.error('Error clearing history:', err);
1407
+ }
1408
+ }
1409
+ });
1410
+
1411
+ // این تابع به صورت گلوبال در دسترس است تا از سایر بخش‌ها بتوان تصاویر جدید را به سابقه اضافه کرد
1412
+ window.addGeneratedImageToHistory = async function(blob, prompt, model, size) {
1413
+ const item = {
1414
+ id: Date.now(),
1415
+ timestamp: Date.now(),
1416
+ blob: blob,
1417
+ prompt: prompt || 'بدون متن',
1418
+ model: model || 'نامشخص',
1419
+ size: size || 'نامشخص'
1420
+ };
1421
+ try {
1422
+ await projectDB.saveHistoryImage(item);
1423
+ await loadHistoryImages();
1424
+ } catch (e) {
1425
+ console.error("Error saving image to history:", e);
1426
+ }
1427
+ };
1428
+
1429
  document.addEventListener('DOMContentLoaded', async () => {
1430
  userFingerprint = await getBrowserFingerprint();
1431
  parent.postMessage({ type: 'REQUEST_USER_DATA' }, '*');
1432
+ try {
1433
+ await projectDB.init();
1434
+ await initializeForm();
1435
+ await loadStoredProject();
1436
+ await loadHistoryImages();
1437
+ }
1438
  catch (error) { console.error("Failed to init DB or load project:", error); }
1439
  });
1440