mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-26 00:55:16 -07:00
fix(jellyfin): show overlay, inject plugin, and fix stats title on playb
- Show visible overlay automatically during Jellyfin playback so subtitleStyle applies - Inject bundled mpv plugin on auto-launch so keybindings work without overlay focus - Group Jellyfin playback stats under item metadata (jellyfin://host/item/id) instead of stream URLs so episodes merge with matching local titles - Mark ffsubsync unavailable in subsync modal for remote media paths - Drain queued second-instance commands even when onReady throws
This commit is contained in:
+51
@@ -2747,6 +2747,7 @@ const {
|
||||
reportJellyfinRemoteStopped,
|
||||
startJellyfinRemoteSession,
|
||||
stopJellyfinRemoteSession,
|
||||
cleanupJellyfinSubtitleCache,
|
||||
runJellyfinCommand,
|
||||
openJellyfinSetupWindow,
|
||||
getJellyfinClientInfo,
|
||||
@@ -2770,6 +2771,15 @@ const {
|
||||
getLaunchMode: () => getResolvedConfig().mpv.launchMode,
|
||||
platform: process.platform,
|
||||
execPath: process.execPath,
|
||||
getRuntimePluginEntrypoint: () => resolveBundledMpvRuntimePluginEntrypoint(),
|
||||
getInstalledPluginDetection: () =>
|
||||
detectInstalledMpvPlugin({
|
||||
platform: process.platform,
|
||||
homeDir: os.homedir(),
|
||||
xdgConfigHome: process.env.XDG_CONFIG_HOME,
|
||||
appDataDir: app.getPath('appData'),
|
||||
mpvExecutablePath: getResolvedConfig().mpv.executablePath,
|
||||
}),
|
||||
getPluginRuntimeConfig: () => getMpvPluginRuntimeConfig(),
|
||||
defaultMpvLogPath: DEFAULT_MPV_LOG_PATH,
|
||||
defaultMpvArgs: MPV_JELLYFIN_DEFAULT_ARGS,
|
||||
@@ -2805,6 +2815,41 @@ const {
|
||||
sendMpvCommandRuntime(appState.mpvClient, command);
|
||||
},
|
||||
wait: (ms) => new Promise<void>((resolve) => setTimeout(resolve, ms)),
|
||||
cacheSubtitleTrack: async (track) => {
|
||||
if (!track.deliveryUrl) {
|
||||
throw new Error('Jellyfin subtitle track has no delivery URL');
|
||||
}
|
||||
|
||||
const cacheDir = await fs.promises.mkdtemp(
|
||||
path.join(os.tmpdir(), 'subminer-jellyfin-subtitles-'),
|
||||
);
|
||||
const urlPath = (() => {
|
||||
try {
|
||||
return new URL(track.deliveryUrl).pathname;
|
||||
} catch {
|
||||
return track.deliveryUrl;
|
||||
}
|
||||
})();
|
||||
const ext = path.extname(urlPath).slice(0, 16) || '.srt';
|
||||
const subtitlePath = path.join(cacheDir, `track-${track.index}${ext}`);
|
||||
try {
|
||||
const response = await fetch(track.deliveryUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to download Jellyfin subtitle (HTTP ${response.status})`);
|
||||
}
|
||||
const bytes = new Uint8Array(await response.arrayBuffer());
|
||||
await fs.promises.writeFile(subtitlePath, bytes);
|
||||
} catch (error) {
|
||||
fs.rmSync(cacheDir, { recursive: true, force: true });
|
||||
throw error;
|
||||
}
|
||||
return { path: subtitlePath, cleanupDir: cacheDir };
|
||||
},
|
||||
cleanupCachedSubtitles: (dirs) => {
|
||||
for (const dir of dirs) {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
},
|
||||
logDebug: (message, error) => {
|
||||
logger.debug(message, error);
|
||||
},
|
||||
@@ -2823,6 +2868,7 @@ const {
|
||||
},
|
||||
),
|
||||
applyJellyfinMpvDefaults: (mpvClient) => applyJellyfinMpvDefaults(mpvClient),
|
||||
showVisibleOverlay: () => setVisibleOverlayVisible(true),
|
||||
sendMpvCommand: (command) => sendMpvCommandRuntime(appState.mpvClient, command),
|
||||
armQuitOnDisconnect: () => {
|
||||
jellyfinPlayQuitOnDisconnectArmed = false;
|
||||
@@ -2846,6 +2892,10 @@ const {
|
||||
showMpvOsd: (text) => {
|
||||
showMpvOsd(text);
|
||||
},
|
||||
recordJellyfinPlaybackMetadata: (metadata) => {
|
||||
ensureImmersionTrackerStarted();
|
||||
appState.immersionTracker?.recordJellyfinPlaybackMetadata(metadata);
|
||||
},
|
||||
},
|
||||
remoteComposerOptions: {
|
||||
getConfiguredSession: () => getConfiguredJellyfinSession(getResolvedJellyfinConfig()),
|
||||
@@ -3615,6 +3665,7 @@ const {
|
||||
appState.yomitanSettingsWindow = null;
|
||||
},
|
||||
stopJellyfinRemoteSession: () => stopJellyfinRemoteSession(),
|
||||
cleanupJellyfinSubtitleCache: () => cleanupJellyfinSubtitleCache(),
|
||||
stopDiscordPresenceService: () => {
|
||||
void appState.discordPresenceService?.stop();
|
||||
appState.discordPresenceService = null;
|
||||
|
||||
Reference in New Issue
Block a user