retold-remote 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/html/index.html +2 -0
  2. package/package.json +20 -14
  3. package/source/Pict-Application-RetoldRemote.js +46 -5
  4. package/source/cli/RetoldRemote-CLI-Run.js +0 -0
  5. package/source/cli/RetoldRemote-Server-Setup.js +790 -8
  6. package/source/cli/commands/RetoldRemote-Command-Serve.js +34 -1
  7. package/source/providers/Pict-Provider-GalleryFilterSort.js +61 -9
  8. package/source/providers/Pict-Provider-GalleryNavigation.js +517 -18
  9. package/source/providers/Pict-Provider-RetoldRemote.js +11 -2
  10. package/source/providers/Pict-Provider-RetoldRemoteIcons.js +1 -0
  11. package/source/server/RetoldRemote-ArchiveService.js +830 -0
  12. package/source/server/RetoldRemote-AudioWaveformService.js +673 -0
  13. package/source/server/RetoldRemote-EbookService.js +242 -0
  14. package/source/server/RetoldRemote-MediaService.js +1 -1
  15. package/source/server/RetoldRemote-ToolDetector.js +31 -1
  16. package/source/server/RetoldRemote-VideoFrameService.js +486 -0
  17. package/source/views/PictView-Remote-AudioExplorer.js +1213 -0
  18. package/source/views/PictView-Remote-Gallery.js +141 -2
  19. package/source/views/PictView-Remote-Layout.js +18 -27
  20. package/source/views/PictView-Remote-MediaViewer.js +638 -39
  21. package/source/views/PictView-Remote-SettingsPanel.js +23 -0
  22. package/source/views/PictView-Remote-TopBar.js +121 -0
  23. package/source/views/PictView-Remote-VideoExplorer.js +1229 -0
  24. package/web-application/index.html +2 -0
  25. package/web-application/js/epub.min.js +1 -0
  26. package/web-application/retold-remote.js +7030 -1244
  27. package/web-application/retold-remote.js.map +1 -1
  28. package/web-application/retold-remote.min.js +13 -44
  29. package/web-application/retold-remote.min.js.map +1 -1
  30. package/web-application/retold-remote.compatible.js +0 -5764
  31. package/web-application/retold-remote.compatible.js.map +0 -1
  32. package/web-application/retold-remote.compatible.min.js +0 -120
  33. package/web-application/retold-remote.compatible.min.js.map +0 -1
@@ -113,6 +113,44 @@ const _ViewConfiguration =
113
113
  {
114
114
  color: var(--retold-text-placeholder);
115
115
  }
116
+ .retold-remote-gallery-search-options
117
+ {
118
+ display: flex;
119
+ align-items: center;
120
+ gap: 8px;
121
+ flex-shrink: 0;
122
+ }
123
+ .retold-remote-gallery-search-option
124
+ {
125
+ display: inline-flex;
126
+ align-items: center;
127
+ gap: 3px;
128
+ font-size: 0.68rem;
129
+ color: var(--retold-text-dim);
130
+ cursor: pointer;
131
+ white-space: nowrap;
132
+ user-select: none;
133
+ }
134
+ .retold-remote-gallery-search-option:hover
135
+ {
136
+ color: var(--retold-text-muted);
137
+ }
138
+ .retold-remote-gallery-search-option input[type="checkbox"]
139
+ {
140
+ margin: 0;
141
+ cursor: pointer;
142
+ accent-color: var(--retold-accent);
143
+ }
144
+ .retold-remote-gallery-search-option.active
145
+ {
146
+ color: var(--retold-accent);
147
+ }
148
+ .retold-remote-gallery-search-regex-error
149
+ {
150
+ font-size: 0.68rem;
151
+ color: #e06c75;
152
+ white-space: nowrap;
153
+ }
116
154
  /* Filter chips */
117
155
  .retold-remote-filter-chips
118
156
  {
@@ -635,6 +673,12 @@ class RetoldRemoteGalleryView extends libPictView
635
673
  let tmpThumbnailSize = tmpRemote.ThumbnailSize || 'medium';
636
674
  let tmpCursorIndex = tmpRemote.GalleryCursorIndex || 0;
637
675
 
676
+ // Capture search input focus state before re-render so we can restore it
677
+ let tmpSearchEl = document.getElementById('RetoldRemote-Gallery-Search');
678
+ let tmpSearchHadFocus = tmpSearchEl && (document.activeElement === tmpSearchEl);
679
+ let tmpSearchSelStart = tmpSearchHadFocus ? tmpSearchEl.selectionStart : 0;
680
+ let tmpSearchSelEnd = tmpSearchHadFocus ? tmpSearchEl.selectionEnd : 0;
681
+
638
682
  // Build header with type filters, sort, filter toggle, and search
639
683
  let tmpHTML = this._buildHeaderHTML(tmpRemote.FilterState ? tmpRemote.FilterState.MediaType : 'all');
640
684
 
@@ -652,6 +696,17 @@ class RetoldRemoteGalleryView extends libPictView
652
696
  tmpHTML += '<div>Empty folder</div>';
653
697
  tmpHTML += '</div>';
654
698
  tmpContainer.innerHTML = tmpHTML;
699
+
700
+ // Restore search focus even on empty results
701
+ if (tmpSearchHadFocus)
702
+ {
703
+ let tmpNewSearch = document.getElementById('RetoldRemote-Gallery-Search');
704
+ if (tmpNewSearch)
705
+ {
706
+ tmpNewSearch.focus();
707
+ tmpNewSearch.setSelectionRange(tmpSearchSelStart, tmpSearchSelEnd);
708
+ }
709
+ }
655
710
  return;
656
711
  }
657
712
 
@@ -667,6 +722,17 @@ class RetoldRemoteGalleryView extends libPictView
667
722
 
668
723
  tmpContainer.innerHTML = tmpHTML;
669
724
 
725
+ // Restore search input focus and cursor position after re-render
726
+ if (tmpSearchHadFocus)
727
+ {
728
+ let tmpNewSearch = document.getElementById('RetoldRemote-Gallery-Search');
729
+ if (tmpNewSearch)
730
+ {
731
+ tmpNewSearch.focus();
732
+ tmpNewSearch.setSelectionRange(tmpSearchSelStart, tmpSearchSelEnd);
733
+ }
734
+ }
735
+
670
736
  // Set up lazy loading for thumbnail images
671
737
  this._setupLazyLoading();
672
738
 
@@ -676,6 +742,13 @@ class RetoldRemoteGalleryView extends libPictView
676
742
  {
677
743
  tmpNavProvider.recalculateColumns();
678
744
  }
745
+
746
+ // Update the top bar filter icon state
747
+ let tmpTopBarView = this.pict.views['ContentEditor-TopBar'];
748
+ if (tmpTopBarView && tmpTopBarView.updateFilterIcon)
749
+ {
750
+ tmpTopBarView.updateFilterIcon();
751
+ }
679
752
  }
680
753
 
681
754
  // ──────────────────────────────────────────────
@@ -684,10 +757,18 @@ class RetoldRemoteGalleryView extends libPictView
684
757
 
685
758
  /**
686
759
  * Build the gallery header with type filters, sort dropdown, filter toggle, and search.
760
+ * The filter bar is hidden by default; toggled via / key or the top bar filter icon.
687
761
  */
688
762
  _buildHeaderHTML(pActiveFilter)
689
763
  {
690
764
  let tmpRemote = this.pict.AppData.RetoldRemote;
765
+
766
+ // If the filter bar is not visible, don't render the header
767
+ if (!tmpRemote.FilterBarVisible)
768
+ {
769
+ return '';
770
+ }
771
+
691
772
  let tmpFilters = [
692
773
  { key: 'all', label: 'All' },
693
774
  { key: 'images', label: 'Images' },
@@ -754,6 +835,24 @@ class RetoldRemoteGalleryView extends libPictView
754
835
  + 'placeholder="Search files... (/)" '
755
836
  + 'value="' + this._escapeHTML(tmpSearchValue) + '" '
756
837
  + 'oninput="pict.views[\'RetoldRemote-Gallery\'].onSearchInput(this.value)">';
838
+
839
+ // Case sensitivity and regex checkboxes
840
+ let tmpCaseSensitive = tmpRemote.SearchCaseSensitive || false;
841
+ let tmpRegex = tmpRemote.SearchRegex || false;
842
+ tmpHTML += '<div class="retold-remote-gallery-search-options">';
843
+ tmpHTML += '<label class="retold-remote-gallery-search-option' + (tmpCaseSensitive ? ' active' : '') + '">'
844
+ + '<input type="checkbox" ' + (tmpCaseSensitive ? 'checked ' : '')
845
+ + 'onchange="pict.views[\'RetoldRemote-Gallery\'].onSearchCaseSensitiveChange(this.checked)">'
846
+ + 'Aa</label>';
847
+ tmpHTML += '<label class="retold-remote-gallery-search-option' + (tmpRegex ? ' active' : '') + '">'
848
+ + '<input type="checkbox" ' + (tmpRegex ? 'checked ' : '')
849
+ + 'onchange="pict.views[\'RetoldRemote-Gallery\'].onSearchRegexChange(this.checked)">'
850
+ + '.*</label>';
851
+ if (tmpRemote._searchRegexError)
852
+ {
853
+ tmpHTML += '<span class="retold-remote-gallery-search-regex-error" title="' + this._escapeHTML(tmpRemote._searchRegexError) + '">invalid regex</span>';
854
+ }
855
+ tmpHTML += '</div>';
757
856
  tmpHTML += '</div>';
758
857
 
759
858
  return tmpHTML;
@@ -950,6 +1049,11 @@ class RetoldRemoteGalleryView extends libPictView
950
1049
  tmpHTML += '<div class="retold-remote-tile-thumb-icon"><span class="retold-remote-icon retold-remote-icon-md">' + (tmpIconProvider ? tmpIconProvider.getIcon('folder', 48) : '') + '</span></div>';
951
1050
  tmpHTML += '<span class="retold-remote-tile-badge retold-remote-tile-badge-folder">Folder</span>';
952
1051
  }
1052
+ else if (tmpItem.Type === 'archive')
1053
+ {
1054
+ tmpHTML += '<div class="retold-remote-tile-thumb-icon"><span class="retold-remote-icon retold-remote-icon-md">' + (tmpIconProvider ? tmpIconProvider.getIcon('file-archive', 48) : '') + '</span></div>';
1055
+ tmpHTML += '<span class="retold-remote-tile-badge retold-remote-tile-badge-folder">Archive</span>';
1056
+ }
953
1057
  else if (tmpCategory === 'image' && tmpProvider)
954
1058
  {
955
1059
  let tmpThumbURL = tmpProvider.getThumbnailURL(tmpItem.Path, 400, 300);
@@ -1012,6 +1116,10 @@ class RetoldRemoteGalleryView extends libPictView
1012
1116
  {
1013
1117
  tmpHTML += '<div class="retold-remote-tile-meta">Folder</div>';
1014
1118
  }
1119
+ else if (tmpItem.Type === 'archive')
1120
+ {
1121
+ tmpHTML += '<div class="retold-remote-tile-meta">Archive' + (tmpItem.Size ? ' · ' + this._formatFileSize(tmpItem.Size) : '') + '</div>';
1122
+ }
1015
1123
 
1016
1124
  tmpHTML += '</div>'; // end tile
1017
1125
  }
@@ -1047,7 +1155,7 @@ class RetoldRemoteGalleryView extends libPictView
1047
1155
  tmpHTML += '<div class="retold-remote-list-icon">' + tmpIcon + '</div>';
1048
1156
  tmpHTML += '<div class="retold-remote-list-name">' + this._escapeHTML(tmpItem.Name) + '</div>';
1049
1157
 
1050
- if (tmpItem.Type === 'file' && tmpItem.Size !== undefined)
1158
+ if ((tmpItem.Type === 'file' || tmpItem.Type === 'archive') && tmpItem.Size !== undefined)
1051
1159
  {
1052
1160
  tmpHTML += '<div class="retold-remote-list-size">' + this._formatFileSize(tmpItem.Size) + '</div>';
1053
1161
  }
@@ -1169,7 +1277,37 @@ class RetoldRemoteGalleryView extends libPictView
1169
1277
  onSearchInput(pValue)
1170
1278
  {
1171
1279
  let tmpRemote = this.pict.AppData.RetoldRemote;
1172
- tmpRemote.SearchQuery = (pValue || '').toLowerCase();
1280
+ tmpRemote.SearchQuery = pValue || '';
1281
+
1282
+ let tmpFilterSort = this.pict.providers['RetoldRemote-GalleryFilterSort'];
1283
+ if (tmpFilterSort)
1284
+ {
1285
+ tmpFilterSort.applyFilterSort();
1286
+ }
1287
+ }
1288
+
1289
+ /**
1290
+ * Handle case-sensitive checkbox change.
1291
+ */
1292
+ onSearchCaseSensitiveChange(pChecked)
1293
+ {
1294
+ let tmpRemote = this.pict.AppData.RetoldRemote;
1295
+ tmpRemote.SearchCaseSensitive = pChecked;
1296
+
1297
+ let tmpFilterSort = this.pict.providers['RetoldRemote-GalleryFilterSort'];
1298
+ if (tmpFilterSort)
1299
+ {
1300
+ tmpFilterSort.applyFilterSort();
1301
+ }
1302
+ }
1303
+
1304
+ /**
1305
+ * Handle regex checkbox change.
1306
+ */
1307
+ onSearchRegexChange(pChecked)
1308
+ {
1309
+ let tmpRemote = this.pict.AppData.RetoldRemote;
1310
+ tmpRemote.SearchRegex = pChecked;
1173
1311
 
1174
1312
  let tmpFilterSort = this.pict.providers['RetoldRemote-GalleryFilterSort'];
1175
1313
  if (tmpFilterSort)
@@ -1400,6 +1538,7 @@ class RetoldRemoteGalleryView extends libPictView
1400
1538
  _getCategory(pExtension, pType)
1401
1539
  {
1402
1540
  if (pType === 'folder') return 'folder';
1541
+ if (pType === 'archive') return 'archive';
1403
1542
  // Delegate to the filter/sort provider if available
1404
1543
  let tmpFilterSort = this.pict.providers['RetoldRemote-GalleryFilterSort'];
1405
1544
  if (tmpFilterSort)
@@ -102,32 +102,6 @@ const _ViewConfiguration =
102
102
  {
103
103
  display: none;
104
104
  }
105
- /* Collapse toggle */
106
- .content-editor-sidebar-toggle
107
- {
108
- position: absolute;
109
- top: 8px;
110
- right: -20px;
111
- width: 20px;
112
- height: 28px;
113
- display: flex;
114
- align-items: center;
115
- justify-content: center;
116
- background: var(--retold-bg-tertiary);
117
- border: 1px solid var(--retold-border);
118
- border-left: none;
119
- border-radius: 0 4px 4px 0;
120
- cursor: pointer;
121
- z-index: 10;
122
- color: var(--retold-text-muted);
123
- font-size: 11px;
124
- line-height: 1;
125
- transition: color 0.15s;
126
- }
127
- .content-editor-sidebar-toggle:hover
128
- {
129
- color: var(--retold-text-primary);
130
- }
131
105
  /* Resize handle */
132
106
  .content-editor-resize-handle
133
107
  {
@@ -186,6 +160,17 @@ const _ViewConfiguration =
186
160
  background: var(--retold-bg-selected);
187
161
  color: var(--retold-accent);
188
162
  }
163
+ #ContentEditor-Sidebar-Container .pict-fb-detail-row.sidebar-focused
164
+ {
165
+ outline: 2px solid var(--retold-accent);
166
+ outline-offset: -2px;
167
+ background: var(--retold-bg-hover);
168
+ color: var(--retold-text-primary);
169
+ }
170
+ .content-editor-sidebar-inner.keyboard-focused
171
+ {
172
+ box-shadow: inset 0 0 0 1px var(--retold-accent);
173
+ }
189
174
  #ContentEditor-Sidebar-Container .pict-fb-breadcrumbs
190
175
  {
191
176
  color: var(--retold-text-muted);
@@ -233,7 +218,6 @@ const _ViewConfiguration =
233
218
  <div id="ContentEditor-TopBar-Container"></div>
234
219
  <div class="content-editor-body">
235
220
  <div class="content-editor-sidebar-wrap" style="width: 250px;">
236
- <div class="content-editor-sidebar-toggle" onclick="pict.views['ContentEditor-Layout'].toggleSidebar()">&#9664;</div>
237
221
  <div class="content-editor-sidebar-inner">
238
222
  <div class="content-editor-sidebar-tabs">
239
223
  <button class="content-editor-sidebar-tab active" data-tab="files" onclick="pict.views['ContentEditor-Layout'].switchSidebarTab('files')">Files</button>
@@ -412,6 +396,13 @@ class RetoldRemoteLayoutView extends libPictView
412
396
  }
413
397
 
414
398
  tmpHandle.addEventListener('mousedown', onMouseDown);
399
+
400
+ // Double-click on resize handle collapses the sidebar
401
+ tmpHandle.addEventListener('dblclick', function (pEvent)
402
+ {
403
+ pEvent.preventDefault();
404
+ tmpSelf.toggleSidebar();
405
+ });
415
406
  }
416
407
  }
417
408