Nix configurations for my homelab
1From 3c4cef0f2fedd7417333ba0584c86637a66bd7ab Mon Sep 17 00:00:00 2001
2From: "Philipp A." <flying-sheep@web.de>
3Date: Sat, 8 Nov 2025 19:05:43 +0100
4Subject: [PATCH 01/11] add scrub controls
5
6---
7 src/controllers/playback/video/index.js | 12 ++++++++++++
8 1 file changed, 12 insertions(+)
9
10diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js
11index e3f3d3733aa3..cb81b84d9c20 100644
12--- a/src/controllers/playback/video/index.js
13+++ b/src/controllers/playback/video/index.js
14@@ -1310,6 +1310,18 @@ export default function (view) {
15 showOsd(btnFastForward);
16 }
17 break;
18+ case ',':
19+ if (!e.shiftKey) {
20+ e.preventDefault();
21+ playbackManager.seekRelative(currentPlayer, 1);
22+ }
23+ break;
24+ case '.':
25+ if (!e.shiftKey) {
26+ e.preventDefault();
27+ playbackManager.seekRelative(currentPlayer, -1);
28+ }
29+ break;
30 case 'j':
31 case 'J':
32 case 'ArrowLeft':
33
34From b65f95036745ef61707a2726ef1f03df265fed46 Mon Sep 17 00:00:00 2001
35From: "Philipp A." <flying-sheep@web.de>
36Date: Sat, 8 Nov 2025 19:08:02 +0100
37Subject: [PATCH 02/11] fix direction
38
39---
40 src/controllers/playback/video/index.js | 4 ++--
41 1 file changed, 2 insertions(+), 2 deletions(-)
42
43diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js
44index cb81b84d9c20..85d43cb3526e 100644
45--- a/src/controllers/playback/video/index.js
46+++ b/src/controllers/playback/video/index.js
47@@ -1313,13 +1313,13 @@ export default function (view) {
48 case ',':
49 if (!e.shiftKey) {
50 e.preventDefault();
51- playbackManager.seekRelative(currentPlayer, 1);
52+ playbackManager.seekRelative(currentPlayer, -1);
53 }
54 break;
55 case '.':
56 if (!e.shiftKey) {
57 e.preventDefault();
58- playbackManager.seekRelative(currentPlayer, -1);
59+ playbackManager.seekRelative(currentPlayer, 1);
60 }
61 break;
62 case 'j':
63
64From bedceb362c09e4a3677f2abcd75ff221b4511507 Mon Sep 17 00:00:00 2001
65From: "Philipp A." <flying-sheep@web.de>
66Date: Sat, 8 Nov 2025 19:18:24 +0100
67Subject: [PATCH 03/11] fix order
68
69---
70 src/controllers/playback/video/index.js | 4 ++--
71 1 file changed, 2 insertions(+), 2 deletions(-)
72
73diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js
74index 85d43cb3526e..3afb4d8f1c7f 100644
75--- a/src/controllers/playback/video/index.js
76+++ b/src/controllers/playback/video/index.js
77@@ -1313,13 +1313,13 @@ export default function (view) {
78 case ',':
79 if (!e.shiftKey) {
80 e.preventDefault();
81- playbackManager.seekRelative(currentPlayer, -1);
82+ playbackManager.seekRelative(-1, currentPlayer);
83 }
84 break;
85 case '.':
86 if (!e.shiftKey) {
87 e.preventDefault();
88- playbackManager.seekRelative(currentPlayer, 1);
89+ playbackManager.seekRelative(1, currentPlayer);
90 }
91 break;
92 case 'j':
93
94From 6023a198d0317e066a0339c985cf480b8ab5e071 Mon Sep 17 00:00:00 2001
95From: "Philipp A." <flying-sheep@web.de>
96Date: Sat, 8 Nov 2025 20:09:02 +0100
97Subject: [PATCH 04/11] hardcode 25fps for now
98
99---
100 src/controllers/playback/video/index.js | 4 ++--
101 1 file changed, 2 insertions(+), 2 deletions(-)
102
103diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js
104index 3afb4d8f1c7f..4a841d10c1d5 100644
105--- a/src/controllers/playback/video/index.js
106+++ b/src/controllers/playback/video/index.js
107@@ -1313,13 +1313,13 @@ export default function (view) {
108 case ',':
109 if (!e.shiftKey) {
110 e.preventDefault();
111- playbackManager.seekRelative(-1, currentPlayer);
112+ playbackManager.seekRelative(-4e4, currentPlayer);
113 }
114 break;
115 case '.':
116 if (!e.shiftKey) {
117 e.preventDefault();
118- playbackManager.seekRelative(1, currentPlayer);
119+ playbackManager.seekRelative(4e4, currentPlayer);
120 }
121 break;
122 case 'j':
123
124From 373f30d79d9e708802f1e4df7ccb00334965ccba Mon Sep 17 00:00:00 2001
125From: "Philipp A." <flying-sheep@web.de>
126Date: Sun, 9 Nov 2025 14:56:52 +0100
127Subject: [PATCH 05/11] get fps
128
129---
130 src/components/playback/playbackmanager.js | 18 ++++++++++++++++++
131 src/controllers/playback/video/index.js | 4 ++--
132 2 files changed, 20 insertions(+), 2 deletions(-)
133
134diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
135index f9c1f2512f69..9bd4ef1f594e 100644
136--- a/src/components/playback/playbackmanager.js
137+++ b/src/components/playback/playbackmanager.js
138@@ -1345,6 +1345,10 @@ export class PlaybackManager {
139 }
140 };
141
142+ self.getFps = function (player) {
143+ self.currentMediaSource(player).MediaStreams.find(s => s.Type === "Video")?.RealFrameRate
144+ }
145+
146 function getSavedMaxStreamingBitrate(apiClient, mediaType) {
147 if (!apiClient) {
148 // This should hopefully never happen
149@@ -3885,6 +3889,20 @@ export class PlaybackManager {
150 this.seekRelative(offsetTicks, player);
151 }
152
153+ nextFrame(player = this._currentPlayer) {
154+ const fps = this.getFps(player);
155+ if (fps != null) {
156+ this.seekRelative(1e6 / fps, player);
157+ }
158+ }
159+
160+ previousFrame(player = this._currentPlayer) {
161+ const fps = this.getFps(player);
162+ if (fps != null) {
163+ this.seekRelative(-1e6 / fps, player);
164+ }
165+ }
166+
167 seekPercent(percent, player = this._currentPlayer) {
168 let ticks = this.duration(player) || 0;
169
170diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js
171index 4a841d10c1d5..2f52aed1c326 100644
172--- a/src/controllers/playback/video/index.js
173+++ b/src/controllers/playback/video/index.js
174@@ -1313,13 +1313,13 @@ export default function (view) {
175 case ',':
176 if (!e.shiftKey) {
177 e.preventDefault();
178- playbackManager.seekRelative(-4e4, currentPlayer);
179+ playbackManager.previousFrame(currentPlayer);
180 }
181 break;
182 case '.':
183 if (!e.shiftKey) {
184 e.preventDefault();
185- playbackManager.seekRelative(4e4, currentPlayer);
186+ playbackManager.nextFrame(currentPlayer);
187 }
188 break;
189 case 'j':
190
191From 60469d524d9bef458ec7f97b38c5f684a0b9a97b Mon Sep 17 00:00:00 2001
192From: "Philipp A." <flying-sheep@web.de>
193Date: Sun, 9 Nov 2025 15:03:11 +0100
194Subject: [PATCH 06/11] style
195
196---
197 src/components/playback/playbackmanager.js | 4 ++--
198 1 file changed, 2 insertions(+), 2 deletions(-)
199
200diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
201index 9bd4ef1f594e..de425de02079 100644
202--- a/src/components/playback/playbackmanager.js
203+++ b/src/components/playback/playbackmanager.js
204@@ -1346,8 +1346,8 @@ export class PlaybackManager {
205 };
206
207 self.getFps = function (player) {
208- self.currentMediaSource(player).MediaStreams.find(s => s.Type === "Video")?.RealFrameRate
209- }
210+ return self.currentMediaSource(player).MediaStreams.find(s => s.Type === 'Video')?.RealFrameRate;
211+ };
212
213 function getSavedMaxStreamingBitrate(apiClient, mediaType) {
214 if (!apiClient) {
215
216From a4d1bac7a38e19fc4b63e45737b53ff2ab1ac11e Mon Sep 17 00:00:00 2001
217From: "Philipp A." <flying-sheep@web.de>
218Date: Sun, 9 Nov 2025 15:17:22 +0100
219Subject: [PATCH 07/11] fix exponent
220
221---
222 src/components/playback/playbackmanager.js | 4 ++--
223 1 file changed, 2 insertions(+), 2 deletions(-)
224
225diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
226index de425de02079..0dbbf0c2e950 100644
227--- a/src/components/playback/playbackmanager.js
228+++ b/src/components/playback/playbackmanager.js
229@@ -3892,14 +3892,14 @@ export class PlaybackManager {
230 nextFrame(player = this._currentPlayer) {
231 const fps = this.getFps(player);
232 if (fps != null) {
233- this.seekRelative(1e6 / fps, player);
234+ this.seekRelative(1e5 / fps, player);
235 }
236 }
237
238 previousFrame(player = this._currentPlayer) {
239 const fps = this.getFps(player);
240 if (fps != null) {
241- this.seekRelative(-1e6 / fps, player);
242+ this.seekRelative(-1e5 / fps, player);
243 }
244 }
245
246
247From 62e82fc4ecdd13d9af3c798bf0c2a59ebc549636 Mon Sep 17 00:00:00 2001
248From: "Philipp A." <flying-sheep@web.de>
249Date: Sun, 9 Nov 2025 15:29:57 +0100
250Subject: [PATCH 08/11] oops
251
252---
253 src/components/playback/playbackmanager.js | 5 +++--
254 1 file changed, 3 insertions(+), 2 deletions(-)
255
256diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
257index 0dbbf0c2e950..46f49be09fe6 100644
258--- a/src/components/playback/playbackmanager.js
259+++ b/src/components/playback/playbackmanager.js
260@@ -3889,17 +3889,18 @@ export class PlaybackManager {
261 this.seekRelative(offsetTicks, player);
262 }
263
264+ // tick = ⅒ns, so ticks/frame = 1e10 ns / 1e5 *
265 nextFrame(player = this._currentPlayer) {
266 const fps = this.getFps(player);
267 if (fps != null) {
268- this.seekRelative(1e5 / fps, player);
269+ this.seekRelative(1e7 / fps, player);
270 }
271 }
272
273 previousFrame(player = this._currentPlayer) {
274 const fps = this.getFps(player);
275 if (fps != null) {
276- this.seekRelative(-1e5 / fps, player);
277+ this.seekRelative(-1e7 / fps, player);
278 }
279 }
280
281
282From 2198a66007fadb83d6e48410b4f1d65a332e9131 Mon Sep 17 00:00:00 2001
283From: "Philipp A." <flying-sheep@web.de>
284Date: Sun, 9 Nov 2025 15:33:56 +0100
285Subject: [PATCH 09/11] remove comment
286
287---
288 src/components/playback/playbackmanager.js | 1 -
289 1 file changed, 1 deletion(-)
290
291diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
292index 46f49be09fe6..96356d946a67 100644
293--- a/src/components/playback/playbackmanager.js
294+++ b/src/components/playback/playbackmanager.js
295@@ -3889,7 +3889,6 @@ export class PlaybackManager {
296 this.seekRelative(offsetTicks, player);
297 }
298
299- // tick = ⅒ns, so ticks/frame = 1e10 ns / 1e5 *
300 nextFrame(player = this._currentPlayer) {
301 const fps = this.getFps(player);
302 if (fps != null) {
303
304From 1b70b814626ac4c1f497f25c4c6c389e7c7bcd0a Mon Sep 17 00:00:00 2001
305From: "Philipp A." <flying-sheep@web.de>
306Date: Sun, 9 Nov 2025 15:58:03 +0100
307Subject: [PATCH 10/11] use constant
308
309---
310 src/components/playback/playbackmanager.js | 5 +++--
311 1 file changed, 3 insertions(+), 2 deletions(-)
312
313diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
314index 96356d946a67..4f5f6b3450a8 100644
315--- a/src/components/playback/playbackmanager.js
316+++ b/src/components/playback/playbackmanager.js
317@@ -27,6 +27,7 @@ import { PlayerEvent } from 'apps/stable/features/playback/constants/playerEvent
318 import { bindMediaSegmentManager } from 'apps/stable/features/playback/utils/mediaSegmentManager';
319 import { bindMediaSessionSubscriber } from 'apps/stable/features/playback/utils/mediaSessionSubscriber';
320 import { AppFeature } from 'constants/appFeature';
321+import { TICKS_PER_SECOND } from 'constants/time';
322 import { ServerConnections } from 'lib/jellyfin-apiclient';
323 import { MediaError } from 'types/mediaError';
324 import { getMediaError } from 'utils/mediaError';
325@@ -3892,14 +3893,14 @@ export class PlaybackManager {
326 nextFrame(player = this._currentPlayer) {
327 const fps = this.getFps(player);
328 if (fps != null) {
329- this.seekRelative(1e7 / fps, player);
330+ this.seekRelative(TICKS_PER_SECOND / fps, player);
331 }
332 }
333
334 previousFrame(player = this._currentPlayer) {
335 const fps = this.getFps(player);
336 if (fps != null) {
337- this.seekRelative(-1e7 / fps, player);
338+ this.seekRelative(-TICKS_PER_SECOND / fps, player);
339 }
340 }
341
342
343From 148bcd7138fb23f15038e7ac11e53b26c626300b Mon Sep 17 00:00:00 2001
344From: "Philipp A." <flying-sheep@web.de>
345Date: Sat, 6 Dec 2025 14:10:35 +0100
346Subject: [PATCH 11/11] Apply suggestions from code review
347
348Co-authored-by: Bill Thornton <thornbill@users.noreply.github.com>
349---
350 src/components/playback/playbackmanager.js | 6 +++---
351 1 file changed, 3 insertions(+), 3 deletions(-)
352
353diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js
354index 0ac75f2057bf..1cbdf1d3a345 100644
355--- a/src/components/playback/playbackmanager.js
356+++ b/src/components/playback/playbackmanager.js
357@@ -1347,7 +1347,7 @@ export class PlaybackManager {
358 };
359
360 self.getFps = function (player) {
361- return self.currentMediaSource(player).MediaStreams.find(s => s.Type === 'Video')?.RealFrameRate;
362+ return self.currentMediaSource(player).MediaStreams.find(s => s.Type === 'Video')?.ReferenceFrameRate;
363 };
364
365 function getSavedMaxStreamingBitrate(apiClient, mediaType) {
366@@ -3891,14 +3891,14 @@ export class PlaybackManager {
367
368 nextFrame(player = this._currentPlayer) {
369 const fps = this.getFps(player);
370- if (fps != null) {
371+ if (fps) {
372 this.seekRelative(TICKS_PER_SECOND / fps, player);
373 }
374 }
375
376 previousFrame(player = this._currentPlayer) {
377 const fps = this.getFps(player);
378- if (fps != null) {
379+ if (fps) {
380 this.seekRelative(-TICKS_PER_SECOND / fps, player);
381 }
382 }