offline mode almost there
This commit is contained in:
@@ -71,6 +71,98 @@ pub struct DownloadManager {
|
||||
pub state: Arc<Mutex<DownloadState>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LocalEntry {
|
||||
pub item_id: String,
|
||||
pub title: String,
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
/// Scan downloads root for marker files and return local playable entries.
|
||||
/// Title is taken from marker JSON if present, else from the media filename stem.
|
||||
pub fn scan_local_entries() -> Vec<LocalEntry> {
|
||||
fn walk(dir: &Path, out: &mut Vec<LocalEntry>) {
|
||||
let rd = match std::fs::read_dir(dir) {
|
||||
Ok(r) => r,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
for ent in rd.flatten() {
|
||||
let p = ent.path();
|
||||
|
||||
if p.is_dir() {
|
||||
walk(&p, out);
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = match p.file_name().and_then(|s| s.to_str()) {
|
||||
Some(s) => s,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if !name.ends_with(DOWNLOAD_MARKER_EXT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let raw = match std::fs::read_to_string(&p) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let v: serde_json::Value = match serde_json::from_str(raw.trim()) {
|
||||
Ok(v) => v,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let item_id = match v.get("item_id").and_then(|x| x.as_str()) {
|
||||
Some(s) if !s.is_empty() => s.to_string(),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
// derive media path: "<media>.<DOWNLOAD_MARKER_EXT>" -> "<media>"
|
||||
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() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// title: prefer json field if you ever add it, else from filename
|
||||
let title = v
|
||||
.get("title")
|
||||
.and_then(|x| x.as_str())
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or_else(|| {
|
||||
media_path
|
||||
.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or(media_name)
|
||||
.to_string()
|
||||
});
|
||||
|
||||
out.push(LocalEntry {
|
||||
item_id,
|
||||
title,
|
||||
path: media_path,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let mut out = Vec::new();
|
||||
if let Ok(root) = downloads_root() {
|
||||
walk(&root, &mut out);
|
||||
}
|
||||
|
||||
// Stable sort: title
|
||||
out.sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase()));
|
||||
out
|
||||
}
|
||||
|
||||
|
||||
impl DownloadManager {
|
||||
pub fn start(cfg: Config) -> Self {
|
||||
let state = Arc::new(Mutex::new(DownloadState::default()));
|
||||
|
||||
Reference in New Issue
Block a user