diff options
-rw-r--r-- | common/src/api.rs | 15 | ||||
-rw-r--r-- | remuxer/src/import/mod.rs | 51 | ||||
-rw-r--r-- | remuxer/src/lib.rs | 59 | ||||
-rw-r--r-- | server/src/database.rs | 6 | ||||
-rw-r--r-- | server/src/library.rs | 27 | ||||
-rw-r--r-- | server/src/routes/mod.rs | 5 | ||||
-rw-r--r-- | server/src/routes/ui/account/settings.rs | 10 |
7 files changed, 79 insertions, 94 deletions
diff --git a/common/src/api.rs b/common/src/api.rs deleted file mode 100644 index 27541a2..0000000 --- a/common/src/api.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::{DirectoryInfo, ItemInfo}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum ApiNode { - Directory { - identifier: String, - info: DirectoryInfo, - children: Vec<String>, - }, - Item { - identifier: String, - info: ItemInfo, - }, -} diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs index 7971c18..4ccbd1c 100644 --- a/remuxer/src/import/mod.rs +++ b/remuxer/src/import/mod.rs @@ -4,7 +4,7 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use anyhow::{anyhow, bail, Result}; -use jellycommon::{BlockIndex, ItemInfo, SeekIndex, SourceTrack, SourceTrackKind}; +use jellycommon::{BlockIndex, LocalTrack, SeekIndex, SourceTrack, SourceTrackKind}; use jellymatroska::{ block::Block, matroska::MatroskaTag, @@ -14,7 +14,9 @@ use jellymatroska::{ use log::{debug, error, info, trace, warn}; use std::{collections::HashMap, fs::File, path::PathBuf}; -pub fn import_read(path: &PathBuf, input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()> { +pub fn import_read(path: &PathBuf, input: &mut EbmlReader) -> Result<()> { + let mut iteminfo = Vec::new(); + let mut private = Vec::new(); while let Some(item) = input.next() { let item = match item { Ok(item) => item, @@ -43,7 +45,7 @@ pub fn import_read(path: &PathBuf, input: &mut EbmlReader, iteminfo: &mut ItemIn MatroskaTag::Segment(_) => { info!("segment start"); let mut children = Unflatten::new_with_end(input, item); - import_read_segment(path, &mut children, iteminfo)?; + import_read_segment(path, &mut children, &mut iteminfo, &mut private)?; info!("segment end"); } _ => debug!("(r) tag ignored: {item:?}"), @@ -56,8 +58,9 @@ pub fn import_read(path: &PathBuf, input: &mut EbmlReader, iteminfo: &mut ItemIn fn import_read_segment( path: &PathBuf, segment: &mut Unflatten, - iteminfo: &mut ItemInfo, -) -> Result<()> { + iteminfo: &mut Vec<SourceTrack>, + private: &mut Vec<LocalTrack>, +) -> Result<Option<f64>> { let (mut timestamp_scale, mut duration) = (None, None); let mut seek_index = HashMap::new(); @@ -142,8 +145,7 @@ fn import_read_segment( _ => (), } } - let itrack_index = iteminfo.tracks.len(); - let mtrack_index = index.unwrap(); + let track_index = index.unwrap(); let kind = match kind.ok_or(anyhow!("track type required"))? { 1 => SourceTrackKind::Video { fps: fps.unwrap_or(0.0), // TODO @@ -158,19 +160,18 @@ fn import_read_segment( 17 => SourceTrackKind::Subtitles, _ => bail!("invalid track type"), }; - iteminfo.tracks.insert( - itrack_index, - SourceTrack { - track_number: mtrack_index, - path: path.to_owned(), - default_duration, - codec_private, - name: name.unwrap_or_else(|| "unnamed".to_string()), - codec: codec.unwrap(), - language: language.unwrap_or_else(|| "none".to_string()), - kind, - }, - ); + iteminfo.push(SourceTrack { + default_duration, + name: name.unwrap_or_else(|| "unnamed".to_string()), + codec: codec.unwrap(), + language: language.unwrap_or_else(|| "none".to_string()), + kind, + }); + private.push(LocalTrack { + track: track_index as usize, + path: path.to_owned(), + codec_private, + }) } _ => debug!("(rst) tag ignored: {item:?}"), } @@ -253,9 +254,9 @@ fn import_read_segment( bincode::config::standard(), )?; } - if let Some(duration) = duration { - iteminfo.duration = - (duration * timestamp_scale.unwrap_or(1_000_000) as f64) / 1_000_000_000_f64; - } - Ok(()) + Ok(if let Some(duration) = duration { + Some((duration * timestamp_scale.unwrap_or(1_000_000) as f64) / 1_000_000_000_f64) + } else { + None + }) } diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs index e531f06..5fc35f8 100644 --- a/remuxer/src/lib.rs +++ b/remuxer/src/lib.rs @@ -9,7 +9,7 @@ pub mod trim_writer; use crate::{segment_extractor::SegmentExtractIter, trim_writer::TrimWriter}; use anyhow::{anyhow, Context}; -use jellycommon::{BlockIndex, ItemInfo, SeekIndex, SourceTrack, SourceTrackKind}; +use jellycommon::{BlockIndex, ItemPublic, LocalTrack, SeekIndex, SourceTrack, SourceTrackKind}; use jellymatroska::{ block::Block, read::EbmlReader, @@ -39,11 +39,12 @@ impl RemuxerContext { writer: impl Write + 'static, range: Range<usize>, path_base: PathBuf, - iteminfo: ItemInfo, + item: ItemPublic, + track_sources: Vec<LocalTrack>, selection: Vec<usize>, webm: bool, ) -> anyhow::Result<()> { - info!("remuxing {:?} to have tracks {selection:?}", iteminfo.title); + info!("remuxing {:?} to have tracks {selection:?}", item.title); let writer = TrimWriter::new(writer, range.clone()); let mut output = EbmlWriter::new(writer, 0); @@ -52,6 +53,8 @@ impl RemuxerContext { reader: EbmlReader, mapped: u64, index: SeekIndex, + source_track_index: usize, + codec_private: Option<Vec<u8>>, layouting_progress_index: usize, } @@ -61,21 +64,21 @@ impl RemuxerContext { .iter() .enumerate() .map(|(index, sel)| { - let info = iteminfo + let info = item + .media.as_ref() + .unwrap() .tracks - .get(sel) + .get(*sel) .ok_or(anyhow!("track not available"))? .to_owned(); - let source_path = path_base.join(&info.path); + let private = &track_sources[*sel]; + let source_path = path_base.join(&private.path); let mapped = index as u64 + 1; - info!( - "\t- {sel} {source_path:?} ({} => {mapped})", - info.track_number - ); + info!("\t- {sel} {source_path:?} ({} => {mapped})", private.track); info!("\t {}", info); let file = File::open(&source_path).context("opening source file")?; let mut index = - File::open(source_path.with_extension(format!("si.{}", info.track_number))) + File::open(source_path.with_extension(format!("si.{}", private.track))) .context("opening seek index file")?; let index = bincode::decode_from_std_read::<SeekIndex, _, _>( &mut index, @@ -88,6 +91,8 @@ impl RemuxerContext { reader, info, mapped, + source_track_index: private.track, + codec_private: private.codec_private.clone(), layouting_progress_index: 0, }) }) @@ -115,16 +120,16 @@ impl RemuxerContext { output.write_tag(&MatroskaTag::Info(Master::Collected(vec![ MatroskaTag::TimestampScale(1_000_000), - MatroskaTag::Duration(iteminfo.duration * 1000.0), - MatroskaTag::Title(iteminfo.title.clone()), + MatroskaTag::Duration(item.media.unwrap().duration * 1000.0), + MatroskaTag::Title(item.title.clone()), MatroskaTag::MuxingApp("jellyremux".to_string()), MatroskaTag::WritingApp("jellything".to_string()), ])))?; output.write_tag(&MatroskaTag::Tags(Master::Collected(vec![])))?; let tracks_header = inputs - .iter() - .map(|rc| track_to_ebml(rc.mapped, &rc.info)) + .iter_mut() + .map(|rc| track_to_ebml(rc.mapped, &rc.info, rc.codec_private.take())) .collect(); output.write_tag(&MatroskaTag::Tracks(Master::Collected(tracks_header)))?; @@ -197,7 +202,10 @@ impl RemuxerContext { info!("segment layout computed ({} clusters)", clusters.len()); clusters }; - info!("(perf) compute segment layout: {:?}", Instant::now() - timing_cp); + info!( + "(perf) compute segment layout: {:?}", + Instant::now() - timing_cp + ); let timing_cp = Instant::now(); let max_cue_size = 4 // cues id @@ -230,7 +238,9 @@ impl RemuxerContext { let first_cluster_offset_predict = max_cue_size + output.position(); // make the cluster position relative to the segment start as they should - segment_layout.iter_mut().for_each(|e| e.position += first_cluster_offset_predict - segment_offset); + segment_layout + .iter_mut() + .for_each(|e| e.position += first_cluster_offset_predict - segment_offset); output.write_tag(&MatroskaTag::Cues(Master::Collected( segment_layout @@ -265,7 +275,9 @@ impl RemuxerContext { if skip != 0 { info!("skipping {skip} clusters"); - output.seek(SeekFrom::Start((segment_layout[skip].position + segment_offset) as u64))?; + output.seek(SeekFrom::Start( + (segment_layout[skip].position + segment_offset) as u64, + ))?; } struct ReaderD<'a> { @@ -284,7 +296,8 @@ impl RemuxerContext { MatroskaTag::Cluster(Master::Start), ) .context("seeking in input")?; - let mut stream = SegmentExtractIter::new(&mut inp.reader, inp.info.track_number); + let mut stream = + SegmentExtractIter::new(&mut inp.reader, inp.source_track_index as u64); Ok(ReaderD { mapped: inp.mapped, @@ -333,7 +346,11 @@ impl RemuxerContext { } } -pub fn track_to_ebml(number: u64, track: &SourceTrack) -> MatroskaTag { +pub fn track_to_ebml( + number: u64, + track: &SourceTrack, + codec_private: Option<Vec<u8>>, +) -> MatroskaTag { let mut els = vec![ MatroskaTag::TrackNumber(number), MatroskaTag::TrackUID(number), @@ -372,7 +389,7 @@ pub fn track_to_ebml(number: u64, track: &SourceTrack) -> MatroskaTag { els.push(MatroskaTag::TrackType(19)); } } - if let Some(d) = &track.codec_private { + if let Some(d) = &codec_private { els.push(MatroskaTag::CodecPrivate(d.clone())); } MatroskaTag::TrackEntry(Master::Collected(els)) diff --git a/server/src/database.rs b/server/src/database.rs index b6e9ab9..bfb5d47 100644 --- a/server/src/database.rs +++ b/server/src/database.rs @@ -5,6 +5,7 @@ */ use crate::{routes::ui::account::hash_password, CONF}; use anyhow::Context; +use jellycommon::SeekIndex; use log::info; use serde::{Deserialize, Serialize}; use std::path::Path; @@ -12,8 +13,11 @@ use typed_sled::Tree; pub struct Database { pub db: sled::Db, + pub users: Tree<String, User>, pub invites: Tree<String, ()>, + pub items: Tree<String, Item>, + pub seek_index: Tree<(String, usize), SeekIndex>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -32,6 +36,8 @@ impl Database { let r = Ok(Self { users: Tree::open(&db, "users"), invites: Tree::open(&db, "invites"), + items: Tree::open(&db, "items"), + seek_index: Tree::open(&db, "seek_index"), db, }); info!("ready"); diff --git a/server/src/library.rs b/server/src/library.rs index ffd8b4a..8606a6e 100644 --- a/server/src/library.rs +++ b/server/src/library.rs @@ -16,33 +16,6 @@ use std::{ use crate::{routes::ui::node::AssetRole, CONF}; -pub struct Library { - pub root: Arc<Node>, - pub root_path: PathBuf, -} - -#[derive(Debug, Clone)] -pub enum Node { - Directory(Arc<Directory>), - Item(Arc<Item>), -} - -#[derive(Debug, Clone)] -pub struct Directory { - pub lib_path: PathBuf, - pub identifier: String, - pub info: DirectoryInfo, - pub children: Vec<Arc<Node>>, -} - -#[derive(Debug, Clone)] -pub struct Item { - pub fs_path: PathBuf, - pub lib_path: PathBuf, - pub identifier: String, - pub info: ItemInfo, -} - impl Library { pub fn open(path: &Path) -> anyhow::Result<Self> { Ok(Self { diff --git a/server/src/routes/mod.rs b/server/src/routes/mod.rs index 6f8109b..8d50c2e 100644 --- a/server/src/routes/mod.rs +++ b/server/src/routes/mod.rs @@ -4,7 +4,10 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ use crate::{database::Database, library::Library, routes::ui::error::MyResult, CONF}; -use api::{error::r_api_catch, r_api_account_login, r_api_node, r_api_assets_node, r_api_root, r_api_version}; +use api::{ + error::r_api_catch, r_api_account_login, r_api_assets_node, r_api_node, r_api_root, + r_api_version, +}; use jellyremuxer::RemuxerContext; use rocket::{ catchers, config::SecretKey, fairing::AdHoc, fs::FileServer, get, http::Header, routes, Build, diff --git a/server/src/routes/ui/account/settings.rs b/server/src/routes/ui/account/settings.rs index e196b35..59b10b7 100644 --- a/server/src/routes/ui/account/settings.rs +++ b/server/src/routes/ui/account/settings.rs @@ -3,11 +3,6 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2023 metamuffin <metamuffin.org> */ -use std::ops::Range; -use rocket::{ - form::{self, validate::len, Contextual, Form}, - get, post, FromForm, State, -}; use super::{format_form_error, hash_password}; use crate::{ database::Database, @@ -18,6 +13,11 @@ use crate::{ }, uri, }; +use rocket::{ + form::{self, validate::len, Contextual, Form}, + get, post, FromForm, State, +}; +use std::ops::Range; #[derive(FromForm)] pub struct SettingsForm { |