retold-remote 0.0.3 → 0.0.4
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.
- package/package.json +1 -1
- package/source/Pict-Application-RetoldRemote.js +3 -1
- package/source/providers/Pict-Provider-GalleryFilterSort.js +12 -1
- package/source/providers/Pict-Provider-GalleryNavigation.js +68 -0
- package/source/server/RetoldRemote-MediaService.js +1 -1
- package/source/server/RetoldRemote-VideoFrameService.js +2 -1
- package/source/views/PictView-Remote-MediaViewer.js +216 -9
- package/source/views/PictView-Remote-SettingsPanel.js +123 -18
- package/web-application/retold-remote.js +147 -13
- package/web-application/retold-remote.js.map +1 -1
- package/web-application/retold-remote.min.js +4 -4
- package/web-application/retold-remote.min.js.map +1 -1
|
@@ -8562,6 +8562,7 @@ ThumbnailSize:'medium',// 'small', 'medium', 'large'
|
|
|
8562
8562
|
RawFileList:[],// Unfiltered server response
|
|
8563
8563
|
GalleryItems:[],// Filtered+sorted file list (single source of truth)
|
|
8564
8564
|
GalleryCursorIndex:0,// Currently highlighted item
|
|
8565
|
+
FolderCursorHistory:{},// Map of folder path -> last cursor index
|
|
8565
8566
|
GalleryFilter:'all',// 'all', 'images', 'video', 'audio', 'documents'
|
|
8566
8567
|
SearchQuery:'',SearchCaseSensitive:false,SearchRegex:false,ServerCapabilities:{},// From /api/media/capabilities
|
|
8567
8568
|
FolderSummary:null,// From /api/media/folder-summary
|
|
@@ -8619,7 +8620,7 @@ let tmpRemote=tmpSelf.pict.AppData.RetoldRemote;tmpRemote.RawFileList=pFileList|
|
|
|
8619
8620
|
tmpRemote.FilterState={MediaType:tmpRemote.FilterState.MediaType,Extensions:[],SizeMin:null,SizeMax:null,DateModifiedAfter:null,DateModifiedBefore:null,DateCreatedAfter:null,DateCreatedBefore:null};// Show the gallery, hide the viewer
|
|
8620
8621
|
let tmpGalleryContainer=document.getElementById('RetoldRemote-Gallery-Container');let tmpViewerContainer=document.getElementById('RetoldRemote-Viewer-Container');if(tmpGalleryContainer)tmpGalleryContainer.style.display='';if(tmpViewerContainer)tmpViewerContainer.style.display='none';// Run the filter+sort pipeline (sets GalleryItems, resets cursor, renders gallery)
|
|
8621
8622
|
let tmpFilterSort=tmpSelf.pict.providers['RetoldRemote-GalleryFilterSort'];if(tmpFilterSort){tmpFilterSort.applyFilterSort();}else{// Fallback if provider not ready
|
|
8622
|
-
tmpRemote.GalleryItems=pFileList||[];tmpRemote.GalleryCursorIndex=0;let tmpGalleryView=tmpSelf.pict.views['RetoldRemote-Gallery'];if(tmpGalleryView){tmpGalleryView.renderGallery();}}// Update the hash (use hashed identifier when available)
|
|
8623
|
+
tmpRemote.GalleryItems=pFileList||[];let tmpSavedIndex=tmpRemote.FolderCursorHistory&&tmpRemote.FolderCursorHistory[tmpSelf.pict.AppData.PictFileBrowser.CurrentLocation||''];tmpRemote.GalleryCursorIndex=typeof tmpSavedIndex==='number'&&tmpSavedIndex<(pFileList||[]).length?tmpSavedIndex:0;let tmpGalleryView=tmpSelf.pict.views['RetoldRemote-Gallery'];if(tmpGalleryView){tmpGalleryView.renderGallery();}}// Update the hash (use hashed identifier when available)
|
|
8623
8624
|
let tmpCurrentPath=tmpSelf.pict.AppData.PictFileBrowser.CurrentLocation||'';let tmpBrowseFragProvider=tmpSelf.pict.providers['RetoldRemote-Provider'];let tmpBrowseFragId=tmpBrowseFragProvider&&tmpCurrentPath?tmpBrowseFragProvider.getFragmentIdentifier(tmpCurrentPath):tmpCurrentPath;window.location.hash=tmpBrowseFragId?'#/browse/'+tmpBrowseFragId:'#/browse/';// Fetch folder summary for topbar info (skip for archive paths — they are not filesystem directories)
|
|
8624
8625
|
let tmpMediaProvider=tmpSelf.pict.providers['RetoldRemote-Provider'];let tmpIsArchivePath=/\.(zip|7z|rar|tar|tgz|cbz|cbr|tar\.gz|tar\.bz2|tar\.xz)(\/|$)/i.test(tmpCurrentPath);if(tmpMediaProvider&&!tmpIsArchivePath){tmpMediaProvider.fetchFolderSummary(tmpCurrentPath,(pError,pSummary)=>{if(!pError&&pSummary){tmpRemote.FolderSummary=pSummary;let tmpTopBar=tmpSelf.pict.views['ContentEditor-TopBar'];if(tmpTopBar){tmpTopBar.updateLocation();tmpTopBar.updateInfo();}}});}else{let tmpTopBar=tmpSelf.pict.views['ContentEditor-TopBar'];if(tmpTopBar){tmpTopBar.updateLocation();tmpTopBar.updateInfo();}}return tmpCallback();}).catch(pError=>{tmpSelf.log.error(`Failed to load file list: ${pError.message}`);return tmpCallback();});}/**
|
|
8625
8626
|
* Override resolveHash to handle gallery and viewer routes.
|
|
@@ -8649,7 +8650,8 @@ tmpItems=this._applyExtensionFilter(tmpItems,tmpFilterState.Extensions||[]);// 4
|
|
|
8649
8650
|
tmpItems=this._applySizeFilter(tmpItems,tmpFilterState.SizeMin,tmpFilterState.SizeMax);// 5. Date range filter
|
|
8650
8651
|
tmpItems=this._applyDateFilter(tmpItems,tmpFilterState);// 6. Sort
|
|
8651
8652
|
tmpItems=this._sortItems(tmpItems,tmpRemote.SortField||'folder-first',tmpRemote.SortDirection||'asc');// Write result
|
|
8652
|
-
tmpRemote.GalleryItems=tmpItems
|
|
8653
|
+
tmpRemote.GalleryItems=tmpItems;// Restore cursor position if we have a saved one for this folder
|
|
8654
|
+
let tmpCurrentLocation=this.pict.AppData.PictFileBrowser&&this.pict.AppData.PictFileBrowser.CurrentLocation||'';let tmpSavedIndex=tmpRemote.FolderCursorHistory&&tmpRemote.FolderCursorHistory[tmpCurrentLocation];if(typeof tmpSavedIndex==='number'&&tmpSavedIndex<tmpItems.length){tmpRemote.GalleryCursorIndex=tmpSavedIndex;}else{tmpRemote.GalleryCursorIndex=0;}// Re-render gallery
|
|
8653
8655
|
let tmpGalleryView=this.pict.views['RetoldRemote-Gallery'];if(tmpGalleryView){tmpGalleryView.renderGallery();}}// ──────────────────────────────────────────────
|
|
8654
8656
|
// Filter stages
|
|
8655
8657
|
// ──────────────────────────────────────────────
|
|
@@ -8766,7 +8768,8 @@ let tmpRows=document.querySelectorAll('#Pict-FileBrowser-DetailRows .pict-fb-det
|
|
|
8766
8768
|
if(this._sidebarCursorIndex<tmpRows.length){tmpRows[this._sidebarCursorIndex].classList.remove('sidebar-focused');}this._sidebarCursorIndex=pIndex;// Apply new highlight and scroll into view
|
|
8767
8769
|
if(pIndex<tmpRows.length){tmpRows[pIndex].classList.add('sidebar-focused');tmpRows[pIndex].scrollIntoView({block:'nearest',behavior:'smooth'});}}/**
|
|
8768
8770
|
* Handle keyboard events in viewer mode.
|
|
8769
|
-
*/_handleViewerKey(pEvent){
|
|
8771
|
+
*/_handleViewerKey(pEvent){let tmpRemote=this.pict.AppData.RetoldRemote;// Video action menu mode — intercept keys for menu options
|
|
8772
|
+
if(tmpRemote.VideoMenuActive&&tmpRemote.CurrentViewerMediaType==='video'){switch(pEvent.key){case'Escape':pEvent.preventDefault();this.closeViewer();return;case'ArrowRight':case'j':pEvent.preventDefault();this.nextFile();return;case'ArrowLeft':case'k':pEvent.preventDefault();this.prevFile();return;case'e':pEvent.preventDefault();let tmpVEX=this.pict.views['RetoldRemote-VideoExplorer'];if(tmpVEX){tmpVEX.showExplorer(tmpRemote.CurrentViewerFile);}return;case' ':case'Enter':pEvent.preventDefault();let tmpViewer=this.pict.views['RetoldRemote-MediaViewer'];if(tmpViewer){tmpViewer.playVideo();}return;case't':pEvent.preventDefault();let tmpMediaViewer=this.pict.views['RetoldRemote-MediaViewer'];if(tmpMediaViewer){tmpMediaViewer.loadVideoMenuFrame();}return;case'v':pEvent.preventDefault();this._openWithVLC();return;}return;}switch(pEvent.key){case'Escape':pEvent.preventDefault();this.closeViewer();break;case'ArrowRight':case'j':pEvent.preventDefault();this.nextFile();break;case'ArrowLeft':case'k':pEvent.preventDefault();this.prevFile();break;case'f':pEvent.preventDefault();this._toggleFullscreen();break;case'i':pEvent.preventDefault();this._toggleFileInfo();break;case' ':pEvent.preventDefault();this._togglePlayPause();break;case'+':case'=':pEvent.preventDefault();this._zoomIn();break;case'-':pEvent.preventDefault();this._zoomOut();break;case'0':pEvent.preventDefault();this._zoomReset();break;case'z':pEvent.preventDefault();this._cycleFitMode();break;case'Enter':pEvent.preventDefault();this._openWithVLC();break;case'd':pEvent.preventDefault();this._toggleDistractionFree();break;}}/**
|
|
8770
8773
|
* Handle keyboard events in video explorer mode.
|
|
8771
8774
|
*/_handleVideoExplorerKey(pEvent){switch(pEvent.key){case'Escape':pEvent.preventDefault();let tmpVEX=this.pict.views['RetoldRemote-VideoExplorer'];if(tmpVEX){tmpVEX.goBack();}break;}}/**
|
|
8772
8775
|
* Handle keyboard events in audio explorer mode.
|
|
@@ -8778,11 +8781,13 @@ if(pIndex<tmpRows.length){tmpRows[pIndex].classList.add('sidebar-focused');tmpRo
|
|
|
8778
8781
|
let tmpOldTile=document.querySelector(`.retold-remote-tile[data-index="${tmpOldIndex}"], .retold-remote-list-row[data-index="${tmpOldIndex}"]`);let tmpNewTile=document.querySelector(`.retold-remote-tile[data-index="${pNewIndex}"], .retold-remote-list-row[data-index="${pNewIndex}"]`);if(tmpOldTile){tmpOldTile.classList.remove('selected');}if(tmpNewTile){tmpNewTile.classList.add('selected');// Scroll the tile into view if needed
|
|
8779
8782
|
tmpNewTile.scrollIntoView({block:'nearest',behavior:'smooth'});}}/**
|
|
8780
8783
|
* Open the currently selected gallery item.
|
|
8781
|
-
*/openCurrent(){let tmpRemote=this.pict.AppData.RetoldRemote;let tmpItems=tmpRemote.GalleryItems||[];let tmpIndex=tmpRemote.GalleryCursorIndex||0;if(tmpIndex>=tmpItems.length){return;}let tmpItem=tmpItems[tmpIndex];if(tmpItem.Type==='folder'||tmpItem.Type==='archive'){//
|
|
8784
|
+
*/openCurrent(){let tmpRemote=this.pict.AppData.RetoldRemote;let tmpItems=tmpRemote.GalleryItems||[];let tmpIndex=tmpRemote.GalleryCursorIndex||0;if(tmpIndex>=tmpItems.length){return;}let tmpItem=tmpItems[tmpIndex];if(tmpItem.Type==='folder'||tmpItem.Type==='archive'){// Remember cursor position in the current folder before navigating away
|
|
8785
|
+
let tmpCurrentLocation=this.pict.AppData.PictFileBrowser&&this.pict.AppData.PictFileBrowser.CurrentLocation||'';tmpRemote.FolderCursorHistory[tmpCurrentLocation]=tmpIndex;// Navigate into the folder or archive
|
|
8782
8786
|
let tmpApp=this.pict.PictApplication;if(tmpApp&&tmpApp.loadFileList){tmpApp.loadFileList(tmpItem.Path);}}else{// Open the file in the viewer
|
|
8783
8787
|
let tmpApp=this.pict.PictApplication;if(tmpApp&&tmpApp.navigateToFile){tmpApp.navigateToFile(tmpItem.Path);}}}/**
|
|
8784
8788
|
* Navigate up one directory level.
|
|
8785
|
-
*/navigateUp(){let tmpCurrentLocation=this.pict.AppData.PictFileBrowser&&this.pict.AppData.PictFileBrowser.CurrentLocation||'';if(!tmpCurrentLocation){return;}
|
|
8789
|
+
*/navigateUp(){let tmpCurrentLocation=this.pict.AppData.PictFileBrowser&&this.pict.AppData.PictFileBrowser.CurrentLocation||'';if(!tmpCurrentLocation){return;}// Remember cursor position in the current folder before navigating away
|
|
8790
|
+
let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.FolderCursorHistory[tmpCurrentLocation]=tmpRemote.GalleryCursorIndex||0;let tmpParent=tmpCurrentLocation.indexOf('/')>=0?tmpCurrentLocation.replace(/\/[^/]+\/?$/,''):'';let tmpApp=this.pict.PictApplication;if(tmpApp&&tmpApp.loadFileList){tmpApp.loadFileList(tmpParent);}}/**
|
|
8786
8791
|
* Close the viewer and return to gallery mode.
|
|
8787
8792
|
*/closeViewer(){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.ActiveMode='gallery';let tmpGalleryContainer=document.getElementById('RetoldRemote-Gallery-Container');let tmpViewerContainer=document.getElementById('RetoldRemote-Viewer-Container');if(tmpGalleryContainer)tmpGalleryContainer.style.display='';if(tmpViewerContainer)tmpViewerContainer.style.display='none';// Restore the hash to the browse route (use hashed identifier when available)
|
|
8788
8793
|
let tmpCurrentLocation=this.pict.AppData.PictFileBrowser&&this.pict.AppData.PictFileBrowser.CurrentLocation||'';let tmpFragProvider=this.pict.providers['RetoldRemote-Provider'];let tmpFragId=tmpFragProvider&&tmpCurrentLocation?tmpFragProvider.getFragmentIdentifier(tmpCurrentLocation):tmpCurrentLocation;window.location.hash=tmpFragId?'#/browse/'+tmpFragId:'#/browse/';// Re-render gallery to ensure cursor is visible
|
|
@@ -10740,6 +10745,85 @@ tmpHandle.addEventListener('dblclick',function(pEvent){pEvent.preventDefault();t
|
|
|
10740
10745
|
background: var(--retold-accent);
|
|
10741
10746
|
color: var(--retold-bg-primary);
|
|
10742
10747
|
}
|
|
10748
|
+
/* Video action menu */
|
|
10749
|
+
.retold-remote-video-action-menu
|
|
10750
|
+
{
|
|
10751
|
+
display: flex;
|
|
10752
|
+
flex-direction: column;
|
|
10753
|
+
align-items: center;
|
|
10754
|
+
justify-content: center;
|
|
10755
|
+
gap: 12px;
|
|
10756
|
+
width: 100%;
|
|
10757
|
+
height: 100%;
|
|
10758
|
+
}
|
|
10759
|
+
.retold-remote-video-action-menu-title
|
|
10760
|
+
{
|
|
10761
|
+
font-size: 0.85rem;
|
|
10762
|
+
color: var(--retold-text-secondary);
|
|
10763
|
+
margin-bottom: 4px;
|
|
10764
|
+
text-align: center;
|
|
10765
|
+
overflow: hidden;
|
|
10766
|
+
text-overflow: ellipsis;
|
|
10767
|
+
max-width: 80%;
|
|
10768
|
+
}
|
|
10769
|
+
.retold-remote-video-action-thumb-wrap
|
|
10770
|
+
{
|
|
10771
|
+
margin-bottom: 4px;
|
|
10772
|
+
text-align: center;
|
|
10773
|
+
}
|
|
10774
|
+
.retold-remote-video-action-thumb-wrap img
|
|
10775
|
+
{
|
|
10776
|
+
max-width: 640px;
|
|
10777
|
+
max-height: 360px;
|
|
10778
|
+
border-radius: 6px;
|
|
10779
|
+
border: 1px solid var(--retold-border);
|
|
10780
|
+
object-fit: contain;
|
|
10781
|
+
background: var(--retold-bg-primary);
|
|
10782
|
+
}
|
|
10783
|
+
.retold-remote-video-action-thumb-wrap .retold-remote-video-action-thumb-loading
|
|
10784
|
+
{
|
|
10785
|
+
color: var(--retold-text-dim);
|
|
10786
|
+
font-size: 0.78rem;
|
|
10787
|
+
font-style: italic;
|
|
10788
|
+
padding: 8px;
|
|
10789
|
+
}
|
|
10790
|
+
.retold-remote-video-action-btn
|
|
10791
|
+
{
|
|
10792
|
+
display: flex;
|
|
10793
|
+
align-items: center;
|
|
10794
|
+
gap: 12px;
|
|
10795
|
+
padding: 12px 24px;
|
|
10796
|
+
min-width: 280px;
|
|
10797
|
+
border: 1px solid var(--retold-border);
|
|
10798
|
+
border-radius: 6px;
|
|
10799
|
+
background: var(--retold-bg-secondary);
|
|
10800
|
+
color: var(--retold-text-secondary);
|
|
10801
|
+
font-size: 0.85rem;
|
|
10802
|
+
cursor: pointer;
|
|
10803
|
+
transition: border-color 0.15s, color 0.15s, background 0.15s;
|
|
10804
|
+
font-family: inherit;
|
|
10805
|
+
text-align: left;
|
|
10806
|
+
}
|
|
10807
|
+
.retold-remote-video-action-btn:hover,
|
|
10808
|
+
.retold-remote-video-action-btn.selected
|
|
10809
|
+
{
|
|
10810
|
+
border-color: var(--retold-accent);
|
|
10811
|
+
color: var(--retold-text-primary);
|
|
10812
|
+
background: var(--retold-bg-tertiary);
|
|
10813
|
+
}
|
|
10814
|
+
.retold-remote-video-action-key
|
|
10815
|
+
{
|
|
10816
|
+
display: inline-block;
|
|
10817
|
+
padding: 2px 8px;
|
|
10818
|
+
border: 1px solid var(--retold-border);
|
|
10819
|
+
border-radius: 3px;
|
|
10820
|
+
background: var(--retold-bg-primary);
|
|
10821
|
+
color: var(--retold-text-dim);
|
|
10822
|
+
font-size: 0.72rem;
|
|
10823
|
+
font-family: var(--retold-font-mono, monospace);
|
|
10824
|
+
min-width: 24px;
|
|
10825
|
+
text-align: center;
|
|
10826
|
+
}
|
|
10743
10827
|
/* Ebook reader */
|
|
10744
10828
|
.retold-remote-ebook-wrap
|
|
10745
10829
|
{
|
|
@@ -10867,7 +10951,7 @@ tmpHandle.addEventListener('dblclick',function(pEvent){pEvent.preventDefault();t
|
|
|
10867
10951
|
*
|
|
10868
10952
|
* @param {string} pFilePath - Relative file path
|
|
10869
10953
|
* @param {string} pMediaType - 'image', 'video', 'audio', 'document', or 'other'
|
|
10870
|
-
*/showMedia(pFilePath,pMediaType){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.ActiveMode='viewer';tmpRemote.CurrentViewerFile=pFilePath;tmpRemote.CurrentViewerMediaType=pMediaType;// Show viewer, hide gallery
|
|
10954
|
+
*/showMedia(pFilePath,pMediaType){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.ActiveMode='viewer';tmpRemote.CurrentViewerFile=pFilePath;tmpRemote.CurrentViewerMediaType=pMediaType;tmpRemote.VideoMenuActive=pMediaType==='video';// Show viewer, hide gallery
|
|
10871
10955
|
let tmpGalleryContainer=document.getElementById('RetoldRemote-Gallery-Container');let tmpViewerContainer=document.getElementById('RetoldRemote-Viewer-Container');if(tmpGalleryContainer)tmpGalleryContainer.style.display='none';if(tmpViewerContainer)tmpViewerContainer.style.display='block';let tmpFileName=pFilePath.replace(/^.*\//,'');let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpContentURL=tmpProvider?tmpProvider.getContentURL(pFilePath):'/content/'+encodeURIComponent(pFilePath);// Build the viewer HTML
|
|
10872
10956
|
let tmpHTML='<div class="retold-remote-viewer">';// Header with nav
|
|
10873
10957
|
tmpHTML+='<div class="retold-remote-viewer-header">';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].closeViewer()" title="Back (Esc)">← Back</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].prevFile()" title="Previous (k)">‹ Prev</button>';tmpHTML+='<div class="retold-remote-viewer-title">'+this._escapeHTML(tmpFileName)+'</div>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\'].nextFile()" title="Next (j)">Next ›</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._toggleFileInfo()" title="Info (i)">ⓘ</button>';tmpHTML+='<button class="retold-remote-viewer-nav-btn" onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._toggleFullscreen()" title="Fullscreen (f)">▢</button>';tmpHTML+='</div>';// Body with media content
|
|
@@ -10878,12 +10962,24 @@ if(tmpViewerContainer){tmpViewerContainer.innerHTML=tmpHTML;}// Fetch and popula
|
|
|
10878
10962
|
this._loadFileInfo(pFilePath);// Fetch text content and initialize code viewer
|
|
10879
10963
|
if(pMediaType==='text'){this._loadCodeViewer(tmpContentURL,pFilePath);}// Load ebook viewer for epub/mobi
|
|
10880
10964
|
if(pMediaType==='document'){let tmpExt=pFilePath.replace(/^.*\./,'').toLowerCase();if(tmpExt==='epub'||tmpExt==='mobi'){this._loadEbookViewer(tmpContentURL,pFilePath);}}// Update topbar
|
|
10881
|
-
let tmpTopBar=this.pict.views['ContentEditor-TopBar'];if(tmpTopBar){tmpTopBar.updateInfo();}}_buildImageHTML(pURL,pFileName){return'<img src="'+pURL+'" alt="'+this._escapeHTML(pFileName)+'" '+'style="max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in;" '+'id="RetoldRemote-ImageViewer-Img" '+'onload="pict.views[\'RetoldRemote-ImageViewer\'].initImage()" '+'onclick="pict.views[\'RetoldRemote-ImageViewer\'].toggleZoom()">';}_buildVideoHTML(pURL,pFileName){let
|
|
10882
|
-
tmpHTML
|
|
10883
|
-
|
|
10884
|
-
|
|
10965
|
+
let tmpTopBar=this.pict.views['ContentEditor-TopBar'];if(tmpTopBar){tmpTopBar.updateInfo();}}_buildImageHTML(pURL,pFileName){return'<img src="'+pURL+'" alt="'+this._escapeHTML(pFileName)+'" '+'style="max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in;" '+'id="RetoldRemote-ImageViewer-Img" '+'onload="pict.views[\'RetoldRemote-ImageViewer\'].initImage()" '+'onclick="pict.views[\'RetoldRemote-ImageViewer\'].toggleZoom()">';}_buildVideoHTML(pURL,pFileName){let tmpCapabilities=this.pict.AppData.RetoldRemote.ServerCapabilities||{};let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilePath=tmpRemote.CurrentViewerFile;// Build the action menu (shown by default instead of the player)
|
|
10966
|
+
let tmpHTML='<div class="retold-remote-video-action-menu" id="RetoldRemote-VideoActionMenu">';tmpHTML+='<div class="retold-remote-video-action-menu-title">'+this._escapeHTML(pFileName)+'</div>';// Frame preview container (loaded on demand via t key or automatically)
|
|
10967
|
+
if(tmpCapabilities.ffmpeg){tmpHTML+='<div id="RetoldRemote-VideoActionThumb" class="retold-remote-video-action-thumb-wrap"></div>';// Kick off frame extraction automatically
|
|
10968
|
+
setTimeout(()=>{this.loadVideoMenuFrame();},0);}// Explore option (e)
|
|
10969
|
+
if(tmpCapabilities.ffmpeg){tmpHTML+='<button class="retold-remote-video-action-btn" '+'onclick="pict.views[\'RetoldRemote-VideoExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '+'title="Explore frames from this video">'+'<span class="retold-remote-video-action-key">e</span>'+'Explore Video Frames'+'</button>';}// Play option (space/enter)
|
|
10970
|
+
tmpHTML+='<button class="retold-remote-video-action-btn selected" '+'onclick="pict.views[\'RetoldRemote-MediaViewer\'].playVideo()" '+'title="Play video in browser">'+'<span class="retold-remote-video-action-key">Space</span>'+'Play in Browser'+'</button>';// Thumbnail option (t)
|
|
10971
|
+
if(tmpCapabilities.ffmpeg){tmpHTML+='<button class="retold-remote-video-action-btn" '+'onclick="pict.views[\'RetoldRemote-MediaViewer\'].loadVideoMenuFrame()" '+'title="Extract a frame from the midpoint of this video">'+'<span class="retold-remote-video-action-key">t</span>'+'Thumbnail'+'</button>';}// VLC option (v)
|
|
10972
|
+
if(tmpCapabilities.vlc){tmpHTML+='<button class="retold-remote-video-action-btn" '+'onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._openWithVLC()" '+'title="Open with VLC media player">'+'<span class="retold-remote-video-action-key">v</span>'+'Open with VLC'+'</button>';}tmpHTML+='</div>';return tmpHTML;}/**
|
|
10973
|
+
* Launch the in-browser video player (from the video action menu).
|
|
10974
|
+
*/playVideo(){let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilePath=tmpRemote.CurrentViewerFile;if(!tmpFilePath)return;let tmpFileName=tmpFilePath.replace(/^.*\//,'');let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpContentURL=tmpProvider?tmpProvider.getContentURL(tmpFilePath):'/content/'+encodeURIComponent(tmpFilePath);let tmpCapabilities=tmpRemote.ServerCapabilities||{};let tmpHTML='<div class="retold-remote-video-wrap">';let tmpAutoplayVideo=tmpRemote.AutoplayVideo?' autoplay':'';tmpHTML+='<video controls'+tmpAutoplayVideo+' preload="metadata" '+'id="RetoldRemote-VideoPlayer">'+'<source src="'+tmpContentURL+'">'+'Your browser does not support the video tag.'+'</video>';// Stats bar below the video
|
|
10975
|
+
tmpHTML+='<div class="retold-remote-video-stats" id="RetoldRemote-VideoStats">';tmpHTML+='<span class="retold-remote-video-stat-label">Loading info...</span>';if(tmpCapabilities.ffmpeg){tmpHTML+='<button class="retold-remote-explore-btn" '+'onclick="pict.views[\'RetoldRemote-VideoExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '+'title="Explore frames from this video">'+'Explore Video'+'</button>';}if(tmpCapabilities.vlc){tmpHTML+='<button class="retold-remote-vlc-btn" '+'onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._openWithVLC()" '+'title="Open with VLC">'+'Open with VLC'+'</button>';}tmpHTML+='</div>';// end stats
|
|
10885
10976
|
tmpHTML+='</div>';// end wrap
|
|
10886
|
-
|
|
10977
|
+
// Replace the action menu with the player
|
|
10978
|
+
let tmpMenu=document.getElementById('RetoldRemote-VideoActionMenu');if(tmpMenu){tmpMenu.outerHTML=tmpHTML;}// Mark that we are now in player mode (not menu mode)
|
|
10979
|
+
tmpRemote.VideoMenuActive=false;}/**
|
|
10980
|
+
* Extract and display a single full-resolution frame from the midpoint of the current video.
|
|
10981
|
+
*/loadVideoMenuFrame(){let tmpRemote=this.pict.AppData.RetoldRemote;let tmpFilePath=tmpRemote.CurrentViewerFile;if(!tmpFilePath)return;let tmpThumbWrap=document.getElementById('RetoldRemote-VideoActionThumb');if(!tmpThumbWrap)return;tmpThumbWrap.innerHTML='<div class="retold-remote-video-action-thumb-loading">Extracting frame...</div>';let tmpProvider=this.pict.providers['RetoldRemote-Provider'];let tmpPathParam=tmpProvider?tmpProvider._getPathParam(tmpFilePath):encodeURIComponent(tmpFilePath);fetch('/api/media/video-frames?path='+tmpPathParam+'&count=1').then(pResponse=>pResponse.json()).then(pData=>{// Verify we are still on the same file and still in the menu
|
|
10982
|
+
if(tmpRemote.CurrentViewerFile!==tmpFilePath)return;let tmpWrap=document.getElementById('RetoldRemote-VideoActionThumb');if(!tmpWrap)return;if(pData&&pData.Frames&&pData.Frames.length>0){let tmpFrame=pData.Frames[0];let tmpFrameURL='/api/media/video-frame/'+pData.CacheKey+'/'+tmpFrame.Filename;tmpWrap.innerHTML='<img src="'+tmpFrameURL+'" '+'alt="'+this._escapeHTML(tmpFilePath.replace(/^.*\//,''))+'" '+'onerror="this.parentNode.innerHTML=\'\'">';}else{tmpWrap.innerHTML='';}}).catch(()=>{let tmpWrap=document.getElementById('RetoldRemote-VideoActionThumb');if(tmpWrap)tmpWrap.innerHTML='';});}_buildAudioHTML(pURL,pFileName){let tmpIconProvider=this.pict.providers['RetoldRemote-Icons'];let tmpIconHTML=tmpIconProvider?'<span class="retold-remote-icon retold-remote-icon-lg">'+tmpIconProvider.getIcon('music-note',64)+'</span>':'🎵';let tmpHTML='<div style="text-align: center; padding: 40px;">'+'<div style="margin-bottom: 24px;">'+tmpIconHTML+'</div>'+'<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">'+this._escapeHTML(pFileName)+'</div>'+'<audio controls'+(this.pict.AppData.RetoldRemote.AutoplayAudio?' autoplay':'')+' preload="metadata" id="RetoldRemote-AudioPlayer" style="width: 100%; max-width: 500px;">'+'<source src="'+pURL+'">'+'Your browser does not support the audio tag.'+'</audio>';// Explore Audio button (available when ffprobe is present)
|
|
10887
10983
|
let tmpCapabilities=this.pict.AppData.RetoldRemote.ServerCapabilities||{};if(tmpCapabilities.ffprobe||tmpCapabilities.ffmpeg){tmpHTML+='<div style="margin-top: 20px;">'+'<button class="retold-remote-explore-btn" '+'onclick="pict.views[\'RetoldRemote-AudioExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '+'title="Explore waveform and extract segments from this audio">'+'📊 Explore Audio'+'</button>'+'</div>';}tmpHTML+='</div>';return tmpHTML;}_buildDocumentHTML(pURL,pFileName,pFilePath){let tmpExtension=pFilePath.replace(/^.*\./,'').toLowerCase();if(tmpExtension==='pdf'){return'<iframe src="'+pURL+'" '+'style="width: 100%; height: 100%; border: none;">'+'</iframe>';}if(tmpExtension==='epub'||tmpExtension==='mobi'){return this._buildEbookHTML(pURL,pFileName,pFilePath);}// For other document types, show a download link
|
|
10888
10984
|
let tmpIconProvider=this.pict.providers['RetoldRemote-Icons'];let tmpDocIconHTML=tmpIconProvider?'<span class="retold-remote-icon retold-remote-icon-lg">'+tmpIconProvider.getIcon('document-large',64)+'</span>':'📄';return'<div style="text-align: center; padding: 40px;">'+'<div style="margin-bottom: 24px;">'+tmpDocIconHTML+'</div>'+'<div style="font-size: 1.1rem; color: var(--retold-text-secondary); margin-bottom: 24px;">'+this._escapeHTML(pFileName)+'</div>'+'<a href="'+pURL+'" target="_blank" style="color: var(--retold-accent); font-size: 0.9rem;">Open in new tab</a>'+'</div>';}_buildTextHTML(pURL,pFileName,pFilePath){return'<div class="retold-remote-code-viewer-container" id="RetoldRemote-CodeViewer-Container">'+'<div class="retold-remote-code-viewer-loading">Loading...</div>'+'</div>';}/**
|
|
10889
10985
|
* Map a file extension to a pict-section-code highlight language.
|
|
@@ -11016,6 +11112,44 @@ let tmpExploreBtn=tmpStatsBar.querySelector('.retold-remote-explore-btn');let tm
|
|
|
11016
11112
|
{
|
|
11017
11113
|
color: var(--retold-danger-muted);
|
|
11018
11114
|
}
|
|
11115
|
+
.retold-remote-settings-shortcut-group
|
|
11116
|
+
{
|
|
11117
|
+
margin-bottom: 10px;
|
|
11118
|
+
}
|
|
11119
|
+
.retold-remote-settings-shortcut-group-title
|
|
11120
|
+
{
|
|
11121
|
+
font-size: 0.68rem;
|
|
11122
|
+
font-weight: 600;
|
|
11123
|
+
color: var(--retold-text-muted);
|
|
11124
|
+
margin-bottom: 4px;
|
|
11125
|
+
padding-bottom: 2px;
|
|
11126
|
+
border-bottom: 1px solid var(--retold-border);
|
|
11127
|
+
}
|
|
11128
|
+
.retold-remote-settings-shortcut-row
|
|
11129
|
+
{
|
|
11130
|
+
display: flex;
|
|
11131
|
+
justify-content: space-between;
|
|
11132
|
+
align-items: center;
|
|
11133
|
+
padding: 2px 0;
|
|
11134
|
+
}
|
|
11135
|
+
.retold-remote-settings-shortcut-desc
|
|
11136
|
+
{
|
|
11137
|
+
color: var(--retold-text-dim);
|
|
11138
|
+
font-size: 0.72rem;
|
|
11139
|
+
}
|
|
11140
|
+
.retold-remote-settings-shortcut-key
|
|
11141
|
+
{
|
|
11142
|
+
display: inline-block;
|
|
11143
|
+
padding: 1px 6px;
|
|
11144
|
+
border: 1px solid var(--retold-border);
|
|
11145
|
+
border-radius: 3px;
|
|
11146
|
+
background: var(--retold-bg-primary);
|
|
11147
|
+
color: var(--retold-accent);
|
|
11148
|
+
font-size: 0.68rem;
|
|
11149
|
+
font-family: var(--retold-font-mono, monospace);
|
|
11150
|
+
min-width: 18px;
|
|
11151
|
+
text-align: center;
|
|
11152
|
+
}
|
|
11019
11153
|
`};class RetoldRemoteSettingsPanelView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}onAfterRender(){super.onAfterRender();this._renderSettingsContent();}_renderSettingsContent(){let tmpContainer=document.getElementById('RetoldRemote-Settings-Container');if(!tmpContainer){return;}let tmpRemote=this.pict.AppData.RetoldRemote;let tmpCapabilities=tmpRemote.ServerCapabilities||{};let tmpHTML='<div class="retold-remote-settings">';// Appearance section (theme dropdown)
|
|
11020
11154
|
tmpHTML+='<div class="retold-remote-settings-section">';tmpHTML+='<div class="retold-remote-settings-section-title">Appearance</div>';tmpHTML+='<div class="retold-remote-settings-row">';tmpHTML+='<span class="retold-remote-settings-label">Theme</span>';tmpHTML+='<select class="retold-remote-settings-select" onchange="pict.views[\'RetoldRemote-SettingsPanel\'].changeTheme(this.value)">';let tmpThemeProvider=this.pict.providers['RetoldRemote-Theme'];if(tmpThemeProvider){let tmpThemes=tmpThemeProvider.getThemeList();let tmpCurrentTheme=tmpThemeProvider.getCurrentTheme();let tmpCurrentCategory='';for(let i=0;i<tmpThemes.length;i++){let tmpTheme=tmpThemes[i];if(tmpTheme.category!==tmpCurrentCategory){if(tmpCurrentCategory){tmpHTML+='</optgroup>';}tmpHTML+='<optgroup label="'+tmpTheme.category+'">';tmpCurrentCategory=tmpTheme.category;}tmpHTML+='<option value="'+tmpTheme.key+'"'+(tmpTheme.key===tmpCurrentTheme?' selected':'')+'>'+tmpTheme.name+'</option>';}if(tmpCurrentCategory){tmpHTML+='</optgroup>';}}tmpHTML+='</select>';tmpHTML+='</div>';tmpHTML+='</div>';// end appearance section
|
|
11021
11155
|
// Gallery section
|
|
@@ -11030,9 +11164,9 @@ tmpHTML+='<div class="retold-remote-settings-row">';tmpHTML+='<span class="retol
|
|
|
11030
11164
|
tmpHTML+='<div class="retold-remote-settings-section">';tmpHTML+='<div class="retold-remote-settings-section-title">Server Capabilities</div>';tmpHTML+='<div class="retold-remote-settings-capabilities">';let tmpTools=[{key:'sharp',label:'Sharp (image thumbnails)'},{key:'imagemagick',label:'ImageMagick (image fallback)'},{key:'ffmpeg',label:'ffmpeg (video thumbnails)'},{key:'ffprobe',label:'ffprobe (media metadata)'}];for(let i=0;i<tmpTools.length;i++){let tmpTool=tmpTools[i];let tmpAvailable=tmpCapabilities[tmpTool.key];tmpHTML+='<div class="retold-remote-settings-cap-row">';tmpHTML+='<span class="retold-remote-settings-cap-label">'+tmpTool.label+'</span>';tmpHTML+='<span class="'+(tmpAvailable?'retold-remote-settings-cap-yes':'retold-remote-settings-cap-no')+'">'+(tmpAvailable?'Available':'Not found')+'</span>';tmpHTML+='</div>';}// Hashed filenames status
|
|
11031
11165
|
tmpHTML+='<div class="retold-remote-settings-cap-row" style="margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--retold-border);">';tmpHTML+='<span class="retold-remote-settings-cap-label">Hashed filenames</span>';tmpHTML+='<span class="'+(tmpRemote.HashedFilenames?'retold-remote-settings-cap-yes':'retold-remote-settings-cap-no')+'">'+(tmpRemote.HashedFilenames?'Enabled':'Disabled')+'</span>';tmpHTML+='</div>';tmpHTML+='</div>';tmpHTML+='</div>';// end capabilities section
|
|
11032
11166
|
// Keyboard shortcuts
|
|
11033
|
-
tmpHTML+='<div class="retold-remote-settings-section">';tmpHTML+='<div class="retold-remote-settings-section-title">Keyboard Shortcuts</div>';
|
|
11167
|
+
tmpHTML+='<div class="retold-remote-settings-section">';tmpHTML+='<div class="retold-remote-settings-section-title">Keyboard Shortcuts</div>';tmpHTML+=this._buildShortcutGroup('Global',[{key:'F1',desc:'Help panel'},{key:'F9',desc:'Focus sidebar'},{key:'/',desc:'Search / filter bar'},{key:'Esc',desc:'Close overlay / back'}]);tmpHTML+=this._buildShortcutGroup('Gallery',[{key:'\u2190 \u2191 \u2192 \u2193',desc:'Navigate items'},{key:'Enter',desc:'Open item'},{key:'Esc',desc:'Go up one folder'},{key:'Home',desc:'Jump to first item'},{key:'End',desc:'Jump to last item'},{key:'g',desc:'Toggle grid / list'},{key:'f',desc:'Advanced filter panel'},{key:'s',desc:'Focus sort dropdown'},{key:'x',desc:'Clear all filters'},{key:'c',desc:'Settings panel'},{key:'d',desc:'Distraction-free mode'}]);tmpHTML+=this._buildShortcutGroup('Sidebar (F9)',[{key:'\u2191 \u2193',desc:'Navigate file list'},{key:'Home',desc:'Jump to first'},{key:'End',desc:'Jump to last'},{key:'Enter',desc:'Open item'},{key:'Esc',desc:'Return to gallery'}]);tmpHTML+=this._buildShortcutGroup('Media Viewer',[{key:'Esc',desc:'Back to gallery'},{key:'\u2192 j',desc:'Next file'},{key:'\u2190 k',desc:'Previous file'},{key:'Space',desc:'Play / pause'},{key:'f',desc:'Fullscreen'},{key:'i',desc:'File info overlay'},{key:'+ -',desc:'Zoom in / out'},{key:'0',desc:'Reset zoom'},{key:'z',desc:'Cycle fit mode'},{key:'d',desc:'Distraction-free mode'}]);tmpHTML+=this._buildShortcutGroup('Video Menu',[{key:'Space',desc:'Play in browser'},{key:'Enter',desc:'Play in browser'},{key:'e',desc:'Explore video frames'},{key:'t',desc:'Extract thumbnail'},{key:'v',desc:'Open with VLC'},{key:'\u2192 j',desc:'Next file'},{key:'\u2190 k',desc:'Previous file'},{key:'Esc',desc:'Back to gallery'}]);tmpHTML+=this._buildShortcutGroup('Video Explorer',[{key:'Esc',desc:'Back'}]);tmpHTML+=this._buildShortcutGroup('Audio Explorer',[{key:'Space',desc:'Play selection'},{key:'+ -',desc:'Zoom in / out'},{key:'0',desc:'Zoom to fit'},{key:'z',desc:'Zoom to selection'},{key:'Esc',desc:'Clear selection / back'}]);tmpHTML+='</div>';// end shortcuts section
|
|
11034
11168
|
tmpHTML+='</div>';// end settings
|
|
11035
|
-
tmpContainer.innerHTML=tmpHTML;}changeTheme(pThemeKey){let tmpThemeProvider=this.pict.providers['RetoldRemote-Theme'];if(tmpThemeProvider){tmpThemeProvider.applyTheme(pThemeKey);this.pict.PictApplication.saveSettings();// Re-render settings to update dropdown selection
|
|
11169
|
+
tmpContainer.innerHTML=tmpHTML;}_buildShortcutGroup(pTitle,pShortcuts){let tmpHTML='<div class="retold-remote-settings-shortcut-group">';tmpHTML+='<div class="retold-remote-settings-shortcut-group-title">'+pTitle+'</div>';for(let i=0;i<pShortcuts.length;i++){tmpHTML+='<div class="retold-remote-settings-shortcut-row">';tmpHTML+='<span class="retold-remote-settings-shortcut-desc">'+pShortcuts[i].desc+'</span>';tmpHTML+='<span class="retold-remote-settings-shortcut-key">'+pShortcuts[i].key+'</span>';tmpHTML+='</div>';}tmpHTML+='</div>';return tmpHTML;}changeTheme(pThemeKey){let tmpThemeProvider=this.pict.providers['RetoldRemote-Theme'];if(tmpThemeProvider){tmpThemeProvider.applyTheme(pThemeKey);this.pict.PictApplication.saveSettings();// Re-render settings to update dropdown selection
|
|
11036
11170
|
this._renderSettingsContent();}}changeSetting(pKey,pValue){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote[pKey]=pValue;this.pict.PictApplication.saveSettings();// Re-render gallery if visible
|
|
11037
11171
|
if(tmpRemote.ActiveMode==='gallery'){let tmpGalleryView=this.pict.views['RetoldRemote-Gallery'];if(tmpGalleryView){tmpGalleryView.renderGallery();}}}toggleHiddenFiles(pChecked){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.ShowHiddenFiles=pChecked;this.pict.PictApplication.saveSettings();this.pict.PictApplication.syncHiddenFilesSetting(()=>{this.pict.PictApplication.loadFileList();});}toggleAutoplay(pKey,pChecked){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote[pKey]=pChecked;this.pict.PictApplication.saveSettings();}toggleDistractionFreeNav(pChecked){let tmpRemote=this.pict.AppData.RetoldRemote;tmpRemote.DistractionFreeShowNav=pChecked;this.pict.PictApplication.saveSettings();// If currently in distraction-free mode, apply immediately
|
|
11038
11172
|
if(tmpRemote._distractionFreeMode){let tmpViewerHeader=document.querySelector('.retold-remote-viewer-header');if(tmpViewerHeader){tmpViewerHeader.style.display=pChecked?'':'none';}}}}RetoldRemoteSettingsPanelView.default_configuration=_ViewConfiguration;module.exports=RetoldRemoteSettingsPanelView;},{"pict-view":76}],128:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"ContentEditor-TopBar",DefaultRenderable:"RetoldRemote-TopBar",DefaultDestinationAddress:"#ContentEditor-TopBar-Container",AutoRender:false,CSS:/*css*/`
|