mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-15 00:43:08 +01:00
ExoPlayer:
- Pass the resume position into setMediaSource() instead of prepare()-ing
from 0 and then seekTo()-ing, which replayed the first few seconds before
jumping to the resume point.
- Drop the redundant initial seek that mirrors the resume position (fired by
the JS direct-player layer once tracks are ready). ExoPlayer re-buffers on
every seek — even a no-op to the current position — so it stuttered startup.
MPV (Android TV):
- Recover the video pipeline when returning from the screensaver / app
background while paused. TV uses zero-copy hwdec=mediacodec, which binds
MediaCodec directly to the display surface; when the screensaver invalidates
that surface the decoder is left bound to dead buffers and mpv disables the
video track. Register TV-only activity-lifecycle callbacks and reload at the
cached position on resume to recreate the decoder against the live surface
(Android counterpart to iOS's performDecoderReset()).
Video time controls:
- Initialize remainingTime to 0 instead of Infinity and guard non-finite
values, so the first paint shows "0:00" (and "—" for the end time) rather
than "Infinityh NaNm NaNs" and an Invalid Date before the first progress
update
Signed-off-by: Lance Chant <13349722+lancechant@users.noreply.github.com>
120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
/**
|
|
* Converts ticks to a formatted string of hours and minutes.
|
|
* Assumes that ticks are in milliseconds.
|
|
*
|
|
* @param ticks The number of milliseconds.
|
|
* @returns A string formatted as "Xh Ym" where X is hours and Y is minutes.
|
|
*/
|
|
export const runtimeTicksToMinutes = (
|
|
ticks: number | null | undefined,
|
|
): string => {
|
|
if (!ticks) return "0h 0m";
|
|
|
|
const ticksPerMinute = 600000000;
|
|
const ticksPerHour = 36000000000;
|
|
|
|
const hours = Math.floor(ticks / ticksPerHour);
|
|
const minutes = Math.floor((ticks % ticksPerHour) / ticksPerMinute);
|
|
|
|
if (hours > 0) return `${hours}h ${minutes}m`;
|
|
return `${minutes}m`;
|
|
};
|
|
|
|
export const runtimeTicksToSeconds = (
|
|
ticks: number | null | undefined,
|
|
): string => {
|
|
if (!ticks) return "0h 0m";
|
|
|
|
const ticksPerMinute = 600000000;
|
|
const ticksPerHour = 36000000000;
|
|
|
|
const hours = Math.floor(ticks / ticksPerHour);
|
|
const minutes = Math.floor((ticks % ticksPerHour) / ticksPerMinute);
|
|
const seconds = Math.floor((ticks % ticksPerMinute) / 10000000);
|
|
|
|
if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;
|
|
return `${minutes}m ${seconds}s`;
|
|
};
|
|
|
|
// t: ms
|
|
export const formatTimeString = (
|
|
t: number | null | undefined,
|
|
unit: "s" | "ms" | "tick" = "ms",
|
|
): string => {
|
|
if (t === null || t === undefined || !Number.isFinite(t)) return "0:00";
|
|
|
|
let seconds: number;
|
|
switch (unit) {
|
|
case "s":
|
|
seconds = Math.floor(t);
|
|
break;
|
|
case "ms":
|
|
seconds = Math.floor(t / 1000);
|
|
break;
|
|
case "tick":
|
|
seconds = Math.floor(t / 10000000);
|
|
break;
|
|
default:
|
|
seconds = Math.floor(t / 1000); // Default to ms if an invalid type is provided
|
|
}
|
|
|
|
if (seconds < 0) return "0:00";
|
|
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
const remainingSeconds = Math.floor(seconds % 60);
|
|
|
|
if (hours > 0) {
|
|
return `${hours}h ${minutes}m ${remainingSeconds}s`;
|
|
}
|
|
return `${minutes}m ${remainingSeconds}s`;
|
|
};
|
|
|
|
export const secondsToTicks = (seconds?: number | undefined) => {
|
|
if (!seconds) return 0;
|
|
return Math.floor(seconds * 10000000);
|
|
};
|
|
|
|
export const ticksToSeconds = (ticks?: number | undefined) => {
|
|
if (!ticks) return 0;
|
|
return Math.floor(ticks / 10000000);
|
|
};
|
|
|
|
export const msToTicks = (ms?: number | undefined) => {
|
|
if (!ms) return 0;
|
|
return Math.floor(ms * 10000);
|
|
};
|
|
|
|
export const ticksToMs = (ticks?: number | undefined) => {
|
|
if (!ticks) return 0;
|
|
return Math.floor(ticks / 10000);
|
|
};
|
|
|
|
export const secondsToMs = (seconds?: number | undefined) => {
|
|
if (!seconds) return 0;
|
|
return Math.floor(seconds * 1000);
|
|
};
|
|
|
|
export const msToSeconds = (ms?: number | undefined) => {
|
|
if (!ms) return 0;
|
|
return Math.floor(ms / 1000);
|
|
};
|
|
|
|
/**
|
|
* Formats ticks to a compact duration string (MM:SS or HH:MM:SS).
|
|
* Useful for music track durations.
|
|
*/
|
|
export const formatDuration = (ticks: number | null | undefined): string => {
|
|
if (!ticks) return "0:00";
|
|
|
|
const totalSeconds = Math.floor(ticks / 10000000);
|
|
const hours = Math.floor(totalSeconds / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const seconds = totalSeconds % 60;
|
|
|
|
if (hours > 0) {
|
|
return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
}
|
|
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
};
|