openfree commited on
Commit
60297b5
·
verified ·
1 Parent(s): 4f89350

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +218 -0
app.py CHANGED
@@ -497,6 +497,106 @@ const content = document.getElementById('content');
497
  let active = "";
498
  let currentPage = 1;
499
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
  // Simple utility functions
501
  function loadHTML(url, callback) {
502
  const xhr = new XMLHttpRequest();
@@ -635,6 +735,14 @@ function loadManage() {
635
 
636
  <h2>Manage Saved URLs</h2>
637
  <div id="url-list" class="url-list">Loading...</div>
 
 
 
 
 
 
 
 
638
  </div>
639
  `;
640
 
@@ -643,14 +751,53 @@ function loadManage() {
643
 
644
  // URL management functions
645
  function loadUrlList() {
 
 
 
646
  makeRequest('/api/favorites?per_page=100', 'GET', null, function(data) {
647
  const urlList = document.getElementById('url-list');
648
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
  if(data.items.length === 0) {
650
  urlList.innerHTML = '<p style="text-align:center;padding:20px">No URLs saved yet.</p>';
651
  return;
652
  }
653
 
 
 
 
654
  let html = '';
655
  data.items.forEach(item => {
656
  // Escape the URL to prevent JavaScript injection when used in onclick handlers
@@ -670,6 +817,7 @@ function loadUrlList() {
670
  urlList.innerHTML = html;
671
  });
672
  }
 
673
 
674
  function addUrl() {
675
  const url = document.getElementById('new-url').value.trim();
@@ -686,6 +834,14 @@ function addUrl() {
686
  showStatus('add-status', data.message, data.success);
687
  if(data.success) {
688
  document.getElementById('new-url').value = '';
 
 
 
 
 
 
 
 
689
  loadUrlList();
690
  // If currently in Favorites tab, reload to see changes immediately
691
  if(active === 'Favorites') {
@@ -708,6 +864,14 @@ function editUrl(url) {
708
 
709
  makeRequest('/api/url/update', 'POST', formData, function(data) {
710
  if(data.success) {
 
 
 
 
 
 
 
 
711
  loadUrlList();
712
  // If currently in Favorites tab, reload to see changes immediately
713
  if(active === 'Favorites') {
@@ -729,6 +893,14 @@ function deleteUrl(url) {
729
 
730
  makeRequest('/api/url/delete', 'POST', formData, function(data) {
731
  if(data.success) {
 
 
 
 
 
 
 
 
732
  loadUrlList();
733
  // If currently in Favorites tab, reload to see changes immediately
734
  if(active === 'Favorites') {
@@ -778,6 +950,52 @@ tabs.appendChild(manageTab);
778
 
779
  // Start with Favorites tab
780
  loadFavorites(1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
781
  </script>
782
  </body>
783
  </html>''')
 
497
  let active = "";
498
  let currentPage = 1;
499
 
500
+ // LocalStorage functionality for URL persistence
501
+ function saveToLocalStorage(urls) {
502
+ try {
503
+ localStorage.setItem('favoriteUrls', JSON.stringify(urls));
504
+ console.log('Saved URLs to localStorage:', urls.length);
505
+ return true;
506
+ } catch (e) {
507
+ console.error('Error saving to localStorage:', e);
508
+ return false;
509
+ }
510
+ }
511
+
512
+ function loadFromLocalStorage() {
513
+ try {
514
+ const data = localStorage.getItem('favoriteUrls');
515
+ if (data) {
516
+ const urls = JSON.parse(data);
517
+ console.log('Loaded URLs from localStorage:', urls.length);
518
+ return urls;
519
+ }
520
+ } catch (e) {
521
+ console.error('Error loading from localStorage:', e);
522
+ }
523
+ return null;
524
+ }
525
+
526
+ // Export/Import functionality
527
+ function exportUrls() {
528
+ makeRequest('/api/favorites?per_page=1000', 'GET', null, function(data) {
529
+ if (data.items && data.items.length > 0) {
530
+ const urls = data.items.map(item => item.url);
531
+
532
+ // Save to localStorage as backup
533
+ saveToLocalStorage(urls);
534
+
535
+ // Create file for download
536
+ const blob = new Blob([JSON.stringify(urls, null, 2)], { type: 'application/json' });
537
+ const a = document.createElement('a');
538
+ a.href = URL.createObjectURL(blob);
539
+ a.download = 'favorite_urls.json';
540
+ document.body.appendChild(a);
541
+ a.click();
542
+ document.body.removeChild(a);
543
+ } else {
544
+ alert('No URLs to export');
545
+ }
546
+ });
547
+ }
548
+
549
+ function importUrls() {
550
+ document.getElementById('import-file').click();
551
+ }
552
+
553
+ function handleImportFile(files) {
554
+ if (files.length === 0) return;
555
+
556
+ const file = files[0];
557
+ const reader = new FileReader();
558
+
559
+ reader.onload = function(e) {
560
+ try {
561
+ const urls = JSON.parse(e.target.result);
562
+ if (Array.isArray(urls)) {
563
+ // Save to localStorage
564
+ saveToLocalStorage(urls);
565
+
566
+ // Add each URL to the server
567
+ let processed = 0;
568
+
569
+ function addNextUrl(index) {
570
+ if (index >= urls.length) {
571
+ alert(`Import complete. Added ${processed} URLs.`);
572
+ loadUrlList();
573
+ if (active === 'Favorites') {
574
+ loadFavorites(currentPage);
575
+ }
576
+ return;
577
+ }
578
+
579
+ const formData = new FormData();
580
+ formData.append('url', urls[index]);
581
+
582
+ makeRequest('/api/url/add', 'POST', formData, function(data) {
583
+ if (data.success) processed++;
584
+ addNextUrl(index + 1);
585
+ });
586
+ }
587
+
588
+ addNextUrl(0);
589
+ } else {
590
+ alert('Invalid format. File must contain a JSON array of URLs.');
591
+ }
592
+ } catch (e) {
593
+ alert('Error parsing file: ' + e.message);
594
+ }
595
+ };
596
+
597
+ reader.readAsText(file);
598
+ }
599
+
600
  // Simple utility functions
601
  function loadHTML(url, callback) {
602
  const xhr = new XMLHttpRequest();
 
735
 
736
  <h2>Manage Saved URLs</h2>
737
  <div id="url-list" class="url-list">Loading...</div>
738
+
739
+ <div style="margin-top: 30px;">
740
+ <h3>Backup & Restore</h3>
741
+ <p>Server storage may not persist across restarts. Use these options to save your data:</p>
742
+ <button onclick="exportUrls()" class="btn btn-success">Export URLs</button>
743
+ <button onclick="importUrls()" class="btn btn-primary">Import URLs</button>
744
+ <input type="file" id="import-file" style="display:none" onchange="handleImportFile(this.files)">
745
+ </div>
746
  </div>
747
  `;
748
 
 
751
 
752
  // URL management functions
753
  function loadUrlList() {
754
+ // First try to load from localStorage as a fallback
755
+ const localUrls = loadFromLocalStorage();
756
+
757
  makeRequest('/api/favorites?per_page=100', 'GET', null, function(data) {
758
  const urlList = document.getElementById('url-list');
759
 
760
+ // If server has no URLs but localStorage does, restore from localStorage
761
+ if (data.items.length === 0 && localUrls && localUrls.length > 0) {
762
+ showStatus('add-status', 'Restoring URLs from local backup...', true);
763
+
764
+ // Add each URL from localStorage to the server
765
+ let restored = 0;
766
+
767
+ function restoreNextUrl(index) {
768
+ if (index >= localUrls.length) {
769
+ showStatus('add-status', `Restored ${restored} URLs from local backup`, true);
770
+ // Reload the list after restoration
771
+ setTimeout(() => {
772
+ loadUrlList();
773
+ if (active === 'Favorites') {
774
+ loadFavorites(currentPage);
775
+ }
776
+ }, 1000);
777
+ return;
778
+ }
779
+
780
+ const formData = new FormData();
781
+ formData.append('url', localUrls[index]);
782
+
783
+ makeRequest('/api/url/add', 'POST', formData, function(data) {
784
+ if (data.success) restored++;
785
+ restoreNextUrl(index + 1);
786
+ });
787
+ }
788
+
789
+ restoreNextUrl(0);
790
+ return;
791
+ }
792
+
793
  if(data.items.length === 0) {
794
  urlList.innerHTML = '<p style="text-align:center;padding:20px">No URLs saved yet.</p>';
795
  return;
796
  }
797
 
798
+ // Update localStorage with server data
799
+ saveToLocalStorage(data.items.map(item => item.url));
800
+
801
  let html = '';
802
  data.items.forEach(item => {
803
  // Escape the URL to prevent JavaScript injection when used in onclick handlers
 
817
  urlList.innerHTML = html;
818
  });
819
  }
820
+ }
821
 
822
  function addUrl() {
823
  const url = document.getElementById('new-url').value.trim();
 
834
  showStatus('add-status', data.message, data.success);
835
  if(data.success) {
836
  document.getElementById('new-url').value = '';
837
+
838
+ // Update localStorage
839
+ const localUrls = loadFromLocalStorage() || [];
840
+ if (!localUrls.includes(url)) {
841
+ localUrls.unshift(url); // Add to beginning
842
+ saveToLocalStorage(localUrls);
843
+ }
844
+
845
  loadUrlList();
846
  // If currently in Favorites tab, reload to see changes immediately
847
  if(active === 'Favorites') {
 
864
 
865
  makeRequest('/api/url/update', 'POST', formData, function(data) {
866
  if(data.success) {
867
+ // Update localStorage
868
+ let localUrls = loadFromLocalStorage() || [];
869
+ const index = localUrls.indexOf(decodedUrl);
870
+ if (index !== -1) {
871
+ localUrls[index] = newUrl;
872
+ saveToLocalStorage(localUrls);
873
+ }
874
+
875
  loadUrlList();
876
  // If currently in Favorites tab, reload to see changes immediately
877
  if(active === 'Favorites') {
 
893
 
894
  makeRequest('/api/url/delete', 'POST', formData, function(data) {
895
  if(data.success) {
896
+ // Update localStorage
897
+ let localUrls = loadFromLocalStorage() || [];
898
+ const index = localUrls.indexOf(decodedUrl);
899
+ if (index !== -1) {
900
+ localUrls.splice(index, 1);
901
+ saveToLocalStorage(localUrls);
902
+ }
903
+
904
  loadUrlList();
905
  // If currently in Favorites tab, reload to see changes immediately
906
  if(active === 'Favorites') {
 
950
 
951
  // Start with Favorites tab
952
  loadFavorites(1);
953
+
954
+ // Check for localStorage on page load
955
+ window.addEventListener('load', function() {
956
+ // Try to load URLs from localStorage
957
+ const localUrls = loadFromLocalStorage();
958
+
959
+ // If we have URLs in localStorage, make sure they're on the server
960
+ if (localUrls && localUrls.length > 0) {
961
+ console.log(`Found ${localUrls.length} URLs in localStorage`);
962
+
963
+ // First get server URLs to compare
964
+ makeRequest('/api/favorites?per_page=1000', 'GET', null, function(data) {
965
+ const serverUrls = data.items.map(item => item.url);
966
+
967
+ // Find URLs that are in localStorage but not on server
968
+ const missingUrls = localUrls.filter(url => !serverUrls.includes(url));
969
+
970
+ if (missingUrls.length > 0) {
971
+ console.log(`Found ${missingUrls.length} URLs missing from server, restoring...`);
972
+
973
+ // Add missing URLs to server
974
+ let restored = 0;
975
+
976
+ function restoreNextUrl(index) {
977
+ if (index >= missingUrls.length) {
978
+ console.log(`Restored ${restored} URLs from localStorage`);
979
+ if (active === 'Favorites') {
980
+ loadFavorites(currentPage);
981
+ }
982
+ return;
983
+ }
984
+
985
+ const formData = new FormData();
986
+ formData.append('url', missingUrls[index]);
987
+
988
+ makeRequest('/api/url/add', 'POST', formData, function(data) {
989
+ if (data.success) restored++;
990
+ restoreNextUrl(index + 1);
991
+ });
992
+ }
993
+
994
+ restoreNextUrl(0);
995
+ }
996
+ });
997
+ }
998
+ });
999
  </script>
1000
  </body>
1001
  </html>''')