local playback v1
This commit is contained in:
@@ -942,3 +942,57 @@ fn aria2_front_status(state: &Arc<Mutex<DownloadState>>) -> Option<String> {
|
|||||||
let res = aria2_rpc_call("aria2.tellStatus", json!([gid, ["status"]])).ok()?;
|
let res = aria2_rpc_call("aria2.tellStatus", json!([gid, ["status"]])).ok()?;
|
||||||
res.get("status").and_then(|v| v.as_str()).map(|s| s.to_string())
|
res.get("status").and_then(|v| v.as_str()).map(|s| s.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// If this item_id has a local download marker, return the local media file path.
|
||||||
|
/// Marker files are written alongside the media file as:
|
||||||
|
/// <media_filename>.<DOWNLOAD_MARKER_EXT>
|
||||||
|
/// where DOWNLOAD_MARKER_EXT == "cj-jftui.json"
|
||||||
|
pub fn local_media_path_for_item_id(item_id: &str) -> Option<PathBuf> {
|
||||||
|
fn walk(dir: &Path, item_id: &str) -> Option<PathBuf> {
|
||||||
|
if !dir.exists() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rd = fs::read_dir(dir).ok()?;
|
||||||
|
for ent in rd {
|
||||||
|
let p = ent.ok()?.path();
|
||||||
|
|
||||||
|
if p.is_dir() {
|
||||||
|
if let Some(found) = walk(&p, item_id) {
|
||||||
|
return Some(found);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("");
|
||||||
|
if !name.ends_with(DOWNLOAD_MARKER_EXT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let raw = fs::read_to_string(&p).ok()?;
|
||||||
|
let v: Value = serde_json::from_str(raw.trim()).ok()?;
|
||||||
|
let id = v.get("item_id").and_then(|x| x.as_str())?;
|
||||||
|
|
||||||
|
if id == item_id {
|
||||||
|
// Marker file is "<media_filename>.<DOWNLOAD_MARKER_EXT>"
|
||||||
|
// So the media file path is the same path with that suffix stripped.
|
||||||
|
let suffix = format!(".{DOWNLOAD_MARKER_EXT}");
|
||||||
|
if !name.ends_with(&suffix) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let media_name = &name[..name.len() - suffix.len()];
|
||||||
|
let media_path = p.with_file_name(media_name);
|
||||||
|
|
||||||
|
if media_path.exists() {
|
||||||
|
return Some(media_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = downloads_root().ok()?;
|
||||||
|
walk(&root, item_id)
|
||||||
|
}
|
||||||
|
|||||||
12
src/main.rs
12
src/main.rs
@@ -694,7 +694,11 @@ fn handle_key(app: &mut App, code: KeyCode) {
|
|||||||
app.mpv_now_playing = Some(item_name);
|
app.mpv_now_playing = Some(item_name);
|
||||||
|
|
||||||
// If mpv running -> replace, else spawn
|
// If mpv running -> replace, else spawn
|
||||||
let url = build_jellyfin_play_url(&cfg, &item_id);
|
let url = if let Some(p) = crate::core::downloads::local_media_path_for_item_id(&item_id) {
|
||||||
|
p.to_string_lossy().to_string()
|
||||||
|
} else {
|
||||||
|
build_jellyfin_play_url(&cfg, &item_id)
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(mpv) = &app.mpv {
|
if let Some(mpv) = &app.mpv {
|
||||||
match mpv_load_url(&cfg, mpv, &url) {
|
match mpv_load_url(&cfg, mpv, &url) {
|
||||||
@@ -733,7 +737,11 @@ fn handle_key(app: &mut App, code: KeyCode) {
|
|||||||
app.autoplay_next_index = if selected + 1 < len { Some(selected + 1) } else { None };
|
app.autoplay_next_index = if selected + 1 < len { Some(selected + 1) } else { None };
|
||||||
|
|
||||||
// load/replace or spawn
|
// load/replace or spawn
|
||||||
let url = build_jellyfin_play_url(&cfg, &item_id);
|
let url = if let Some(p) = crate::core::downloads::local_media_path_for_item_id(&item_id) {
|
||||||
|
p.to_string_lossy().to_string()
|
||||||
|
} else {
|
||||||
|
build_jellyfin_play_url(&cfg, &item_id)
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(mpv) = &app.mpv {
|
if let Some(mpv) = &app.mpv {
|
||||||
match mpv_load_url(&cfg, mpv, &url) {
|
match mpv_load_url(&cfg, mpv, &url) {
|
||||||
|
|||||||
Reference in New Issue
Block a user