Skip to content

Commit d0f0ed6

Browse files
committed
Map libation cats
1 parent 400d005 commit d0f0ed6

5 files changed

Lines changed: 836 additions & 4 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use std::{
2+
collections::BTreeMap,
3+
env, fs,
4+
path::{Path, PathBuf},
5+
};
6+
7+
use anyhow::{Context, Result, bail};
8+
use mlm::linker::{
9+
folder::Libation,
10+
libation_cats::{MappingDepth, three_plus_override_candidates},
11+
};
12+
13+
#[derive(Debug, Clone)]
14+
struct CandidateStat {
15+
count: usize,
16+
depth: MappingDepth,
17+
}
18+
19+
fn main() -> Result<()> {
20+
let root = env::args_os().nth(1).map(PathBuf::from).unwrap_or_default();
21+
if root.as_os_str().is_empty() {
22+
bail!(
23+
"usage: cargo run -p mlm --bin libation_unmapped_categories -- <libation-export-dir>"
24+
);
25+
}
26+
27+
let mut stats: BTreeMap<Vec<String>, CandidateStat> = BTreeMap::new();
28+
let mut json_files = Vec::new();
29+
collect_json_files(&root, &mut json_files)?;
30+
31+
for path in json_files {
32+
let raw = fs::read_to_string(&path)
33+
.with_context(|| format!("failed to read {}", path.display()))?;
34+
let Ok(meta) = serde_json::from_str::<Libation>(&raw) else {
35+
continue;
36+
};
37+
38+
for candidate in three_plus_override_candidates(&meta.category_ladders) {
39+
let stat = stats
40+
.entry(candidate.original_path.clone())
41+
.or_insert(CandidateStat {
42+
count: 0,
43+
depth: candidate.depth,
44+
});
45+
stat.count += 1;
46+
}
47+
}
48+
49+
let mut rows: Vec<_> = stats.into_iter().collect();
50+
rows.sort_by(|(left_path, left), (right_path, right)| {
51+
right
52+
.count
53+
.cmp(&left.count)
54+
.then_with(|| left.depth.cmp(&right.depth))
55+
.then_with(|| left_path.cmp(right_path))
56+
});
57+
58+
for (path, stat) in rows {
59+
println!(
60+
"{:>6} {:<16} {}",
61+
stat.count,
62+
format!("{:?}", stat.depth),
63+
path.join(" > ")
64+
);
65+
}
66+
67+
Ok(())
68+
}
69+
70+
fn collect_json_files(dir: &Path, out: &mut Vec<PathBuf>) -> Result<()> {
71+
for entry in fs::read_dir(dir).with_context(|| format!("failed to read {}", dir.display()))? {
72+
let entry = entry?;
73+
let path = entry.path();
74+
if path.is_dir() {
75+
collect_json_files(&path, out)?;
76+
} else if path.extension().is_some_and(|ext| ext == "json") {
77+
out.push(path);
78+
}
79+
}
80+
81+
Ok(())
82+
}

server/src/linker/folder.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ use tracing::{Level, instrument, span, trace, warn};
2222
use crate::audiobookshelf as abs;
2323
use crate::config::{Config, Library, LibraryLinkMethod};
2424
use crate::linker::{
25-
copy, file_size, find_matches, hard_link, library_dir, rank_torrents, select_format, symlink,
25+
copy, file_size, find_matches, hard_link, libation_cats, library_dir, rank_torrents,
26+
select_format, symlink,
2627
};
2728
use crate::logging::{update_errored_torrent, write_event};
2829

@@ -204,6 +205,7 @@ async fn build_libation_torrent(
204205
if libation_meta.format_type.starts_with("abridged") {
205206
flags.abridged = Some(true);
206207
}
208+
let mapped_categories = libation_cats::map_category_ladders(&libation_meta.category_ladders);
207209
let (size, filetypes) = folder_file_stats(audio_files, ebook_files).await?;
208210

209211
let meta = TorrentMeta {
@@ -212,8 +214,8 @@ async fn build_libation_torrent(
212214
cat: None,
213215
media_type: MediaType::Audiobook,
214216
main_cat: None,
215-
categories: vec![],
216-
tags: vec![],
217+
categories: mapped_categories.categories,
218+
tags: mapped_categories.freeform_tags,
217219
language: Language::from_str(&libation_meta.language).ok(),
218220
flags: Some(FlagBits::new(flags.as_bitfield())),
219221
filetypes,

0 commit comments

Comments
 (0)