retold-remote 0.0.3 → 0.0.5
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 +2 -2
- package/source/Pict-Application-RetoldRemote.js +43 -1
- package/source/providers/Pict-Provider-GalleryFilterSort.js +13 -2
- package/source/providers/Pict-Provider-GalleryNavigation.js +208 -1
- package/source/server/RetoldRemote-MediaService.js +2 -2
- package/source/server/RetoldRemote-VideoFrameService.js +2 -1
- package/source/views/PictView-Remote-Layout.js +1 -0
- package/source/views/PictView-Remote-MediaViewer.js +231 -20
- package/source/views/PictView-Remote-SettingsPanel.js +154 -18
- package/source/views/PictView-Remote-VLCSetup.js +797 -0
- package/web-application/retold-remote.js +1606 -667
- package/web-application/retold-remote.js.map +1 -1
- package/web-application/retold-remote.min.js +5 -5
- package/web-application/retold-remote.min.js.map +1 -1
|
@@ -232,6 +232,85 @@ const _ViewConfiguration =
|
|
|
232
232
|
background: var(--retold-accent);
|
|
233
233
|
color: var(--retold-bg-primary);
|
|
234
234
|
}
|
|
235
|
+
/* Video action menu */
|
|
236
|
+
.retold-remote-video-action-menu
|
|
237
|
+
{
|
|
238
|
+
display: flex;
|
|
239
|
+
flex-direction: column;
|
|
240
|
+
align-items: center;
|
|
241
|
+
justify-content: center;
|
|
242
|
+
gap: 12px;
|
|
243
|
+
width: 100%;
|
|
244
|
+
height: 100%;
|
|
245
|
+
}
|
|
246
|
+
.retold-remote-video-action-menu-title
|
|
247
|
+
{
|
|
248
|
+
font-size: 0.85rem;
|
|
249
|
+
color: var(--retold-text-secondary);
|
|
250
|
+
margin-bottom: 4px;
|
|
251
|
+
text-align: center;
|
|
252
|
+
overflow: hidden;
|
|
253
|
+
text-overflow: ellipsis;
|
|
254
|
+
max-width: 80%;
|
|
255
|
+
}
|
|
256
|
+
.retold-remote-video-action-thumb-wrap
|
|
257
|
+
{
|
|
258
|
+
margin-bottom: 4px;
|
|
259
|
+
text-align: center;
|
|
260
|
+
}
|
|
261
|
+
.retold-remote-video-action-thumb-wrap img
|
|
262
|
+
{
|
|
263
|
+
max-width: 640px;
|
|
264
|
+
max-height: 360px;
|
|
265
|
+
border-radius: 6px;
|
|
266
|
+
border: 1px solid var(--retold-border);
|
|
267
|
+
object-fit: contain;
|
|
268
|
+
background: var(--retold-bg-primary);
|
|
269
|
+
}
|
|
270
|
+
.retold-remote-video-action-thumb-wrap .retold-remote-video-action-thumb-loading
|
|
271
|
+
{
|
|
272
|
+
color: var(--retold-text-dim);
|
|
273
|
+
font-size: 0.78rem;
|
|
274
|
+
font-style: italic;
|
|
275
|
+
padding: 8px;
|
|
276
|
+
}
|
|
277
|
+
.retold-remote-video-action-btn
|
|
278
|
+
{
|
|
279
|
+
display: flex;
|
|
280
|
+
align-items: center;
|
|
281
|
+
gap: 12px;
|
|
282
|
+
padding: 12px 24px;
|
|
283
|
+
min-width: 280px;
|
|
284
|
+
border: 1px solid var(--retold-border);
|
|
285
|
+
border-radius: 6px;
|
|
286
|
+
background: var(--retold-bg-secondary);
|
|
287
|
+
color: var(--retold-text-secondary);
|
|
288
|
+
font-size: 0.85rem;
|
|
289
|
+
cursor: pointer;
|
|
290
|
+
transition: border-color 0.15s, color 0.15s, background 0.15s;
|
|
291
|
+
font-family: inherit;
|
|
292
|
+
text-align: left;
|
|
293
|
+
}
|
|
294
|
+
.retold-remote-video-action-btn:hover,
|
|
295
|
+
.retold-remote-video-action-btn.selected
|
|
296
|
+
{
|
|
297
|
+
border-color: var(--retold-accent);
|
|
298
|
+
color: var(--retold-text-primary);
|
|
299
|
+
background: var(--retold-bg-tertiary);
|
|
300
|
+
}
|
|
301
|
+
.retold-remote-video-action-key
|
|
302
|
+
{
|
|
303
|
+
display: inline-block;
|
|
304
|
+
padding: 2px 8px;
|
|
305
|
+
border: 1px solid var(--retold-border);
|
|
306
|
+
border-radius: 3px;
|
|
307
|
+
background: var(--retold-bg-primary);
|
|
308
|
+
color: var(--retold-text-dim);
|
|
309
|
+
font-size: 0.72rem;
|
|
310
|
+
font-family: var(--retold-font-mono, monospace);
|
|
311
|
+
min-width: 24px;
|
|
312
|
+
text-align: center;
|
|
313
|
+
}
|
|
235
314
|
/* Ebook reader */
|
|
236
315
|
.retold-remote-ebook-wrap
|
|
237
316
|
{
|
|
@@ -376,6 +455,7 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
376
455
|
tmpRemote.ActiveMode = 'viewer';
|
|
377
456
|
tmpRemote.CurrentViewerFile = pFilePath;
|
|
378
457
|
tmpRemote.CurrentViewerMediaType = pMediaType;
|
|
458
|
+
tmpRemote.VideoMenuActive = (pMediaType === 'video');
|
|
379
459
|
|
|
380
460
|
// Show viewer, hide gallery
|
|
381
461
|
let tmpGalleryContainer = document.getElementById('RetoldRemote-Gallery-Container');
|
|
@@ -477,12 +557,85 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
477
557
|
|
|
478
558
|
_buildVideoHTML(pURL, pFileName)
|
|
479
559
|
{
|
|
560
|
+
let tmpCapabilities = this.pict.AppData.RetoldRemote.ServerCapabilities || {};
|
|
561
|
+
let tmpRemote = this.pict.AppData.RetoldRemote;
|
|
562
|
+
let tmpFilePath = tmpRemote.CurrentViewerFile;
|
|
563
|
+
|
|
564
|
+
// Build the action menu (shown by default instead of the player)
|
|
565
|
+
let tmpHTML = '<div class="retold-remote-video-action-menu" id="RetoldRemote-VideoActionMenu">';
|
|
566
|
+
tmpHTML += '<div class="retold-remote-video-action-menu-title">' + this._escapeHTML(pFileName) + '</div>';
|
|
567
|
+
|
|
568
|
+
// Frame preview container (loaded on demand via t key or automatically)
|
|
569
|
+
if (tmpCapabilities.ffmpeg)
|
|
570
|
+
{
|
|
571
|
+
tmpHTML += '<div id="RetoldRemote-VideoActionThumb" class="retold-remote-video-action-thumb-wrap"></div>';
|
|
572
|
+
// Kick off frame extraction automatically
|
|
573
|
+
setTimeout(() => { this.loadVideoMenuFrame(); }, 0);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Explore option (e)
|
|
577
|
+
if (tmpCapabilities.ffmpeg)
|
|
578
|
+
{
|
|
579
|
+
tmpHTML += '<button class="retold-remote-video-action-btn" '
|
|
580
|
+
+ 'onclick="pict.views[\'RetoldRemote-VideoExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '
|
|
581
|
+
+ 'title="Explore frames from this video">'
|
|
582
|
+
+ '<span class="retold-remote-video-action-key">e</span>'
|
|
583
|
+
+ 'Explore Video Frames'
|
|
584
|
+
+ '</button>';
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Play option (space/enter)
|
|
588
|
+
tmpHTML += '<button class="retold-remote-video-action-btn selected" '
|
|
589
|
+
+ 'onclick="pict.views[\'RetoldRemote-MediaViewer\'].playVideo()" '
|
|
590
|
+
+ 'title="Play video in browser">'
|
|
591
|
+
+ '<span class="retold-remote-video-action-key">Space</span>'
|
|
592
|
+
+ 'Play in Browser'
|
|
593
|
+
+ '</button>';
|
|
594
|
+
|
|
595
|
+
// Thumbnail option (t)
|
|
596
|
+
if (tmpCapabilities.ffmpeg)
|
|
597
|
+
{
|
|
598
|
+
tmpHTML += '<button class="retold-remote-video-action-btn" '
|
|
599
|
+
+ 'onclick="pict.views[\'RetoldRemote-MediaViewer\'].loadVideoMenuFrame()" '
|
|
600
|
+
+ 'title="Extract a frame from the midpoint of this video">'
|
|
601
|
+
+ '<span class="retold-remote-video-action-key">t</span>'
|
|
602
|
+
+ 'Thumbnail'
|
|
603
|
+
+ '</button>';
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// VLC streaming option (v) — always available, streams from server to client VLC
|
|
607
|
+
tmpHTML += '<button class="retold-remote-video-action-btn" '
|
|
608
|
+
+ 'onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._streamWithVLC()" '
|
|
609
|
+
+ 'title="Stream to VLC on this device">'
|
|
610
|
+
+ '<span class="retold-remote-video-action-key">v</span>'
|
|
611
|
+
+ 'Stream with VLC'
|
|
612
|
+
+ '</button>';
|
|
613
|
+
|
|
614
|
+
tmpHTML += '</div>';
|
|
615
|
+
|
|
616
|
+
return tmpHTML;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Launch the in-browser video player (from the video action menu).
|
|
621
|
+
*/
|
|
622
|
+
playVideo()
|
|
623
|
+
{
|
|
624
|
+
let tmpRemote = this.pict.AppData.RetoldRemote;
|
|
625
|
+
let tmpFilePath = tmpRemote.CurrentViewerFile;
|
|
626
|
+
if (!tmpFilePath) return;
|
|
627
|
+
|
|
628
|
+
let tmpFileName = tmpFilePath.replace(/^.*\//, '');
|
|
629
|
+
let tmpProvider = this.pict.providers['RetoldRemote-Provider'];
|
|
630
|
+
let tmpContentURL = tmpProvider ? tmpProvider.getContentURL(tmpFilePath) : ('/content/' + encodeURIComponent(tmpFilePath));
|
|
631
|
+
let tmpCapabilities = tmpRemote.ServerCapabilities || {};
|
|
632
|
+
|
|
480
633
|
let tmpHTML = '<div class="retold-remote-video-wrap">';
|
|
481
634
|
|
|
482
|
-
let tmpAutoplayVideo =
|
|
635
|
+
let tmpAutoplayVideo = tmpRemote.AutoplayVideo ? ' autoplay' : '';
|
|
483
636
|
tmpHTML += '<video controls' + tmpAutoplayVideo + ' preload="metadata" '
|
|
484
637
|
+ 'id="RetoldRemote-VideoPlayer">'
|
|
485
|
-
+ '<source src="' +
|
|
638
|
+
+ '<source src="' + tmpContentURL + '">'
|
|
486
639
|
+ 'Your browser does not support the video tag.'
|
|
487
640
|
+ '</video>';
|
|
488
641
|
|
|
@@ -490,31 +643,79 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
490
643
|
tmpHTML += '<div class="retold-remote-video-stats" id="RetoldRemote-VideoStats">';
|
|
491
644
|
tmpHTML += '<span class="retold-remote-video-stat-label">Loading info...</span>';
|
|
492
645
|
|
|
493
|
-
// Explore Video button (only when ffmpeg is available)
|
|
494
|
-
let tmpCapabilities = this.pict.AppData.RetoldRemote.ServerCapabilities || {};
|
|
495
646
|
if (tmpCapabilities.ffmpeg)
|
|
496
647
|
{
|
|
497
648
|
tmpHTML += '<button class="retold-remote-explore-btn" '
|
|
498
649
|
+ 'onclick="pict.views[\'RetoldRemote-VideoExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '
|
|
499
650
|
+ 'title="Explore frames from this video">'
|
|
500
|
-
+ '
|
|
651
|
+
+ 'Explore Video'
|
|
501
652
|
+ '</button>';
|
|
502
653
|
}
|
|
503
654
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
+ 'title="Open with VLC (Enter)">'
|
|
510
|
-
+ '▶ Open ' + this._escapeHTML(pFileName) + ' with VLC'
|
|
511
|
-
+ '</button>';
|
|
512
|
-
}
|
|
655
|
+
tmpHTML += '<button class="retold-remote-vlc-btn" '
|
|
656
|
+
+ 'onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._streamWithVLC()" '
|
|
657
|
+
+ 'title="Stream to VLC on this device">'
|
|
658
|
+
+ 'Stream with VLC'
|
|
659
|
+
+ '</button>';
|
|
513
660
|
|
|
514
661
|
tmpHTML += '</div>'; // end stats
|
|
515
662
|
tmpHTML += '</div>'; // end wrap
|
|
516
663
|
|
|
517
|
-
|
|
664
|
+
// Replace the action menu with the player
|
|
665
|
+
let tmpMenu = document.getElementById('RetoldRemote-VideoActionMenu');
|
|
666
|
+
if (tmpMenu)
|
|
667
|
+
{
|
|
668
|
+
tmpMenu.outerHTML = tmpHTML;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Mark that we are now in player mode (not menu mode)
|
|
672
|
+
tmpRemote.VideoMenuActive = false;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Extract and display a single full-resolution frame from the midpoint of the current video.
|
|
677
|
+
*/
|
|
678
|
+
loadVideoMenuFrame()
|
|
679
|
+
{
|
|
680
|
+
let tmpRemote = this.pict.AppData.RetoldRemote;
|
|
681
|
+
let tmpFilePath = tmpRemote.CurrentViewerFile;
|
|
682
|
+
if (!tmpFilePath) return;
|
|
683
|
+
|
|
684
|
+
let tmpThumbWrap = document.getElementById('RetoldRemote-VideoActionThumb');
|
|
685
|
+
if (!tmpThumbWrap) return;
|
|
686
|
+
|
|
687
|
+
tmpThumbWrap.innerHTML = '<div class="retold-remote-video-action-thumb-loading">Extracting frame...</div>';
|
|
688
|
+
|
|
689
|
+
let tmpProvider = this.pict.providers['RetoldRemote-Provider'];
|
|
690
|
+
let tmpPathParam = tmpProvider ? tmpProvider._getPathParam(tmpFilePath) : encodeURIComponent(tmpFilePath);
|
|
691
|
+
|
|
692
|
+
fetch('/api/media/video-frames?path=' + tmpPathParam + '&count=1')
|
|
693
|
+
.then((pResponse) => pResponse.json())
|
|
694
|
+
.then((pData) =>
|
|
695
|
+
{
|
|
696
|
+
// Verify we are still on the same file and still in the menu
|
|
697
|
+
if (tmpRemote.CurrentViewerFile !== tmpFilePath) return;
|
|
698
|
+
let tmpWrap = document.getElementById('RetoldRemote-VideoActionThumb');
|
|
699
|
+
if (!tmpWrap) return;
|
|
700
|
+
|
|
701
|
+
if (pData && pData.Frames && pData.Frames.length > 0)
|
|
702
|
+
{
|
|
703
|
+
let tmpFrame = pData.Frames[0];
|
|
704
|
+
let tmpFrameURL = '/api/media/video-frame/' + pData.CacheKey + '/' + tmpFrame.Filename;
|
|
705
|
+
tmpWrap.innerHTML = '<img src="' + tmpFrameURL + '" '
|
|
706
|
+
+ 'alt="' + this._escapeHTML(tmpFilePath.replace(/^.*\//, '')) + '" '
|
|
707
|
+
+ 'onerror="this.parentNode.innerHTML=\'\'">';
|
|
708
|
+
}
|
|
709
|
+
else
|
|
710
|
+
{
|
|
711
|
+
tmpWrap.innerHTML = '';
|
|
712
|
+
}
|
|
713
|
+
})
|
|
714
|
+
.catch(() =>
|
|
715
|
+
{
|
|
716
|
+
let tmpWrap = document.getElementById('RetoldRemote-VideoActionThumb');
|
|
717
|
+
if (tmpWrap) tmpWrap.innerHTML = '';
|
|
718
|
+
});
|
|
518
719
|
}
|
|
519
720
|
|
|
520
721
|
_buildAudioHTML(pURL, pFileName)
|
|
@@ -530,19 +731,29 @@ class RetoldRemoteMediaViewerView extends libPictView
|
|
|
530
731
|
+ 'Your browser does not support the audio tag.'
|
|
531
732
|
+ '</audio>';
|
|
532
733
|
|
|
734
|
+
// Action buttons below the player
|
|
735
|
+
tmpHTML += '<div style="margin-top: 20px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;">';
|
|
736
|
+
|
|
533
737
|
// Explore Audio button (available when ffprobe is present)
|
|
534
738
|
let tmpCapabilities = this.pict.AppData.RetoldRemote.ServerCapabilities || {};
|
|
535
739
|
if (tmpCapabilities.ffprobe || tmpCapabilities.ffmpeg)
|
|
536
740
|
{
|
|
537
|
-
tmpHTML += '<
|
|
538
|
-
+ '<button class="retold-remote-explore-btn" '
|
|
741
|
+
tmpHTML += '<button class="retold-remote-explore-btn" '
|
|
539
742
|
+ 'onclick="pict.views[\'RetoldRemote-AudioExplorer\'].showExplorer(pict.AppData.RetoldRemote.CurrentViewerFile)" '
|
|
540
743
|
+ 'title="Explore waveform and extract segments from this audio">'
|
|
541
|
-
+ '
|
|
542
|
-
+ '</button>'
|
|
543
|
-
+ '</div>';
|
|
744
|
+
+ 'Explore Audio'
|
|
745
|
+
+ '</button>';
|
|
544
746
|
}
|
|
545
747
|
|
|
748
|
+
// Stream with VLC
|
|
749
|
+
tmpHTML += '<button class="retold-remote-vlc-btn" '
|
|
750
|
+
+ 'onclick="pict.providers[\'RetoldRemote-GalleryNavigation\']._streamWithVLC()" '
|
|
751
|
+
+ 'title="Stream to VLC on this device (v)">'
|
|
752
|
+
+ 'Stream with VLC'
|
|
753
|
+
+ '</button>';
|
|
754
|
+
|
|
755
|
+
tmpHTML += '</div>';
|
|
756
|
+
|
|
546
757
|
tmpHTML += '</div>';
|
|
547
758
|
return tmpHTML;
|
|
548
759
|
}
|
|
@@ -77,6 +77,64 @@ const _ViewConfiguration =
|
|
|
77
77
|
{
|
|
78
78
|
color: var(--retold-danger-muted);
|
|
79
79
|
}
|
|
80
|
+
.retold-remote-settings-vlc-btn
|
|
81
|
+
{
|
|
82
|
+
display: block;
|
|
83
|
+
width: 100%;
|
|
84
|
+
padding: 8px 12px;
|
|
85
|
+
border: 1px solid var(--retold-border);
|
|
86
|
+
border-radius: 4px;
|
|
87
|
+
background: var(--retold-bg-secondary);
|
|
88
|
+
color: var(--retold-text-secondary);
|
|
89
|
+
font-size: 0.75rem;
|
|
90
|
+
font-family: inherit;
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
text-align: left;
|
|
93
|
+
transition: background 0.15s, color 0.15s;
|
|
94
|
+
}
|
|
95
|
+
.retold-remote-settings-vlc-btn:hover
|
|
96
|
+
{
|
|
97
|
+
background: var(--retold-bg-hover);
|
|
98
|
+
color: var(--retold-text-primary);
|
|
99
|
+
}
|
|
100
|
+
.retold-remote-settings-shortcut-group
|
|
101
|
+
{
|
|
102
|
+
margin-bottom: 10px;
|
|
103
|
+
}
|
|
104
|
+
.retold-remote-settings-shortcut-group-title
|
|
105
|
+
{
|
|
106
|
+
font-size: 0.68rem;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
color: var(--retold-text-muted);
|
|
109
|
+
margin-bottom: 4px;
|
|
110
|
+
padding-bottom: 2px;
|
|
111
|
+
border-bottom: 1px solid var(--retold-border);
|
|
112
|
+
}
|
|
113
|
+
.retold-remote-settings-shortcut-row
|
|
114
|
+
{
|
|
115
|
+
display: flex;
|
|
116
|
+
justify-content: space-between;
|
|
117
|
+
align-items: center;
|
|
118
|
+
padding: 2px 0;
|
|
119
|
+
}
|
|
120
|
+
.retold-remote-settings-shortcut-desc
|
|
121
|
+
{
|
|
122
|
+
color: var(--retold-text-dim);
|
|
123
|
+
font-size: 0.72rem;
|
|
124
|
+
}
|
|
125
|
+
.retold-remote-settings-shortcut-key
|
|
126
|
+
{
|
|
127
|
+
display: inline-block;
|
|
128
|
+
padding: 1px 6px;
|
|
129
|
+
border: 1px solid var(--retold-border);
|
|
130
|
+
border-radius: 3px;
|
|
131
|
+
background: var(--retold-bg-primary);
|
|
132
|
+
color: var(--retold-accent);
|
|
133
|
+
font-size: 0.68rem;
|
|
134
|
+
font-family: var(--retold-font-mono, monospace);
|
|
135
|
+
min-width: 18px;
|
|
136
|
+
text-align: center;
|
|
137
|
+
}
|
|
80
138
|
`
|
|
81
139
|
};
|
|
82
140
|
|
|
@@ -237,31 +295,92 @@ class RetoldRemoteSettingsPanelView extends libPictView
|
|
|
237
295
|
tmpHTML += '</div>';
|
|
238
296
|
tmpHTML += '</div>'; // end capabilities section
|
|
239
297
|
|
|
298
|
+
// VLC Setup
|
|
299
|
+
tmpHTML += '<div class="retold-remote-settings-section">';
|
|
300
|
+
tmpHTML += '<div class="retold-remote-settings-section-title">VLC Streaming</div>';
|
|
301
|
+
tmpHTML += '<button class="retold-remote-settings-vlc-btn" onclick="pict.views[\'RetoldRemote-VLCSetup\'].openModal()">';
|
|
302
|
+
tmpHTML += 'VLC Protocol Setup';
|
|
303
|
+
tmpHTML += '</button>';
|
|
304
|
+
tmpHTML += '</div>';
|
|
305
|
+
|
|
240
306
|
// Keyboard shortcuts
|
|
241
307
|
tmpHTML += '<div class="retold-remote-settings-section">';
|
|
242
308
|
tmpHTML += '<div class="retold-remote-settings-section-title">Keyboard Shortcuts</div>';
|
|
243
309
|
|
|
244
|
-
|
|
245
|
-
|
|
310
|
+
tmpHTML += this._buildShortcutGroup('Global',
|
|
311
|
+
[
|
|
312
|
+
{ key: 'F1', desc: 'Help panel' },
|
|
313
|
+
{ key: 'F9', desc: 'Focus sidebar' },
|
|
314
|
+
{ key: '/', desc: 'Search / filter bar' },
|
|
315
|
+
{ key: 'Esc', desc: 'Close overlay / back' }
|
|
316
|
+
]);
|
|
317
|
+
|
|
318
|
+
tmpHTML += this._buildShortcutGroup('Gallery',
|
|
319
|
+
[
|
|
320
|
+
{ key: '\u2190 \u2191 \u2192 \u2193', desc: 'Navigate items' },
|
|
246
321
|
{ key: 'Enter', desc: 'Open item' },
|
|
247
|
-
{ key: '
|
|
248
|
-
{ key: '
|
|
249
|
-
{ key: '
|
|
250
|
-
{ key: '
|
|
322
|
+
{ key: '1 2 3 4', desc: 'Open as image / video / audio / text' },
|
|
323
|
+
{ key: 'Esc', desc: 'Go up one folder' },
|
|
324
|
+
{ key: 'Home', desc: 'Jump to first item' },
|
|
325
|
+
{ key: 'End', desc: 'Jump to last item' },
|
|
326
|
+
{ key: 'g', desc: 'Toggle grid / list' },
|
|
327
|
+
{ key: 'f', desc: 'Advanced filter panel' },
|
|
328
|
+
{ key: 's', desc: 'Focus sort dropdown' },
|
|
329
|
+
{ key: 'x', desc: 'Clear all filters' },
|
|
330
|
+
{ key: 'c', desc: 'Settings panel' },
|
|
331
|
+
{ key: 'd', desc: 'Distraction-free mode' }
|
|
332
|
+
]);
|
|
333
|
+
|
|
334
|
+
tmpHTML += this._buildShortcutGroup('Sidebar (F9)',
|
|
335
|
+
[
|
|
336
|
+
{ key: '\u2191 \u2193', desc: 'Navigate file list' },
|
|
337
|
+
{ key: 'Home', desc: 'Jump to first' },
|
|
338
|
+
{ key: 'End', desc: 'Jump to last' },
|
|
339
|
+
{ key: 'Enter', desc: 'Open item' },
|
|
340
|
+
{ key: 'Esc', desc: 'Return to gallery' }
|
|
341
|
+
]);
|
|
342
|
+
|
|
343
|
+
tmpHTML += this._buildShortcutGroup('Media Viewer',
|
|
344
|
+
[
|
|
345
|
+
{ key: 'Esc', desc: 'Back to gallery' },
|
|
346
|
+
{ key: '\u2192 j', desc: 'Next file' },
|
|
347
|
+
{ key: '\u2190 k', desc: 'Previous file' },
|
|
348
|
+
{ key: '1 2 3 4', desc: 'View as image / video / audio / text' },
|
|
251
349
|
{ key: 'Space', desc: 'Play / pause' },
|
|
252
|
-
{ key: '
|
|
350
|
+
{ key: 'f', desc: 'Fullscreen' },
|
|
351
|
+
{ key: 'i', desc: 'File info overlay' },
|
|
352
|
+
{ key: 'v', desc: 'Stream with VLC' },
|
|
353
|
+
{ key: '+ -', desc: 'Zoom in / out' },
|
|
253
354
|
{ key: '0', desc: 'Reset zoom' },
|
|
254
|
-
{ key: '
|
|
255
|
-
{ key: '
|
|
256
|
-
];
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
355
|
+
{ key: 'z', desc: 'Cycle fit mode' },
|
|
356
|
+
{ key: 'd', desc: 'Distraction-free mode' }
|
|
357
|
+
]);
|
|
358
|
+
|
|
359
|
+
tmpHTML += this._buildShortcutGroup('Video Menu',
|
|
360
|
+
[
|
|
361
|
+
{ key: 'Space', desc: 'Play in browser' },
|
|
362
|
+
{ key: 'Enter', desc: 'Play in browser' },
|
|
363
|
+
{ key: 'e', desc: 'Explore video frames' },
|
|
364
|
+
{ key: 't', desc: 'Extract thumbnail' },
|
|
365
|
+
{ key: 'v', desc: 'Stream with VLC' },
|
|
366
|
+
{ key: '\u2192 j', desc: 'Next file' },
|
|
367
|
+
{ key: '\u2190 k', desc: 'Previous file' },
|
|
368
|
+
{ key: 'Esc', desc: 'Back to gallery' }
|
|
369
|
+
]);
|
|
370
|
+
|
|
371
|
+
tmpHTML += this._buildShortcutGroup('Video Explorer',
|
|
372
|
+
[
|
|
373
|
+
{ key: 'Esc', desc: 'Back' }
|
|
374
|
+
]);
|
|
375
|
+
|
|
376
|
+
tmpHTML += this._buildShortcutGroup('Audio Explorer',
|
|
377
|
+
[
|
|
378
|
+
{ key: 'Space', desc: 'Play selection' },
|
|
379
|
+
{ key: '+ -', desc: 'Zoom in / out' },
|
|
380
|
+
{ key: '0', desc: 'Zoom to fit' },
|
|
381
|
+
{ key: 'z', desc: 'Zoom to selection' },
|
|
382
|
+
{ key: 'Esc', desc: 'Clear selection / back' }
|
|
383
|
+
]);
|
|
265
384
|
|
|
266
385
|
tmpHTML += '</div>'; // end shortcuts section
|
|
267
386
|
|
|
@@ -270,6 +389,23 @@ class RetoldRemoteSettingsPanelView extends libPictView
|
|
|
270
389
|
tmpContainer.innerHTML = tmpHTML;
|
|
271
390
|
}
|
|
272
391
|
|
|
392
|
+
_buildShortcutGroup(pTitle, pShortcuts)
|
|
393
|
+
{
|
|
394
|
+
let tmpHTML = '<div class="retold-remote-settings-shortcut-group">';
|
|
395
|
+
tmpHTML += '<div class="retold-remote-settings-shortcut-group-title">' + pTitle + '</div>';
|
|
396
|
+
|
|
397
|
+
for (let i = 0; i < pShortcuts.length; i++)
|
|
398
|
+
{
|
|
399
|
+
tmpHTML += '<div class="retold-remote-settings-shortcut-row">';
|
|
400
|
+
tmpHTML += '<span class="retold-remote-settings-shortcut-desc">' + pShortcuts[i].desc + '</span>';
|
|
401
|
+
tmpHTML += '<span class="retold-remote-settings-shortcut-key">' + pShortcuts[i].key + '</span>';
|
|
402
|
+
tmpHTML += '</div>';
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
tmpHTML += '</div>';
|
|
406
|
+
return tmpHTML;
|
|
407
|
+
}
|
|
408
|
+
|
|
273
409
|
changeTheme(pThemeKey)
|
|
274
410
|
{
|
|
275
411
|
let tmpThemeProvider = this.pict.providers['RetoldRemote-Theme'];
|