aboutsummaryrefslogtreecommitdiff
path: root/import/src/plugins/media_info.rs
diff options
context:
space:
mode:
Diffstat (limited to 'import/src/plugins/media_info.rs')
-rw-r--r--import/src/plugins/media_info.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/import/src/plugins/media_info.rs b/import/src/plugins/media_info.rs
new file mode 100644
index 0000000..1d4d627
--- /dev/null
+++ b/import/src/plugins/media_info.rs
@@ -0,0 +1,92 @@
+/*
+ This file is part of jellything (https://codeberg.org/metamuffin/jellything)
+ which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
+ Copyright (C) 2025 metamuffin <metamuffin.org>
+*/
+
+use crate::plugins::{ImportContext, ImportPlugin};
+use anyhow::{Result, anyhow};
+use jellycommon::{Chapter, NodeID, SourceTrack, SourceTrackKind, TrackSource};
+use jellyremuxer::matroska::Segment;
+use std::path::Path;
+
+pub struct MediaInfo;
+impl ImportPlugin for MediaInfo {
+ fn media(&self, ct: &ImportContext, node: NodeID, path: &Path, seg: &Segment) -> Result<()> {
+ let tracks = seg
+ .tracks
+ .as_ref()
+ .ok_or(anyhow!("no tracks"))?
+ .entries
+ .iter()
+ .map(|track| SourceTrack {
+ codec: track.codec_id.clone(),
+ language: track.language.clone(),
+ name: track.name.clone().unwrap_or_default(),
+ federated: Vec::new(),
+ kind: if let Some(video) = &track.video {
+ SourceTrackKind::Video {
+ width: video.pixel_width,
+ height: video.pixel_height,
+ fps: video.frame_rate,
+ }
+ } else if let Some(audio) = &track.audio {
+ SourceTrackKind::Audio {
+ channels: audio.channels as usize,
+ sample_rate: audio.sampling_frequency,
+ bit_depth: audio.bit_depth.map(|r| r as usize),
+ }
+ } else {
+ SourceTrackKind::Subtitle
+ },
+ source: TrackSource::Local(path.to_owned(), track.track_number),
+ })
+ .collect::<Vec<_>>();
+
+ let size = path.metadata()?.len();
+
+ ct.db.update_node_init(node, |node| {
+ node.storage_size = size;
+ node.media = Some(jellycommon::MediaInfo {
+ chapters: seg
+ .chapters
+ .clone()
+ .map(|c| {
+ let mut chaps = Vec::new();
+ if let Some(ee) = c.edition_entries.first() {
+ for ca in &ee.chapter_atoms {
+ let mut labels = Vec::new();
+ for cd in &ca.displays {
+ for lang in &cd.languages {
+ labels.push((lang.to_owned(), cd.string.clone()))
+ }
+ }
+ chaps.push(Chapter {
+ labels,
+ time_start: Some(ca.time_start as f64 * 1e-9),
+ time_end: ca.time_end.map(|ts| ts as f64 * 1e-9),
+ })
+ }
+ }
+ chaps
+ })
+ .unwrap_or_default(),
+ duration: fix_invalid_runtime(
+ seg.info.duration.unwrap_or_default() * seg.info.timestamp_scale as f64 * 1e-9,
+ ),
+ tracks,
+ });
+ Ok(())
+ })?;
+
+ Ok(())
+ }
+}
+
+fn fix_invalid_runtime(d: f64) -> f64 {
+ match d {
+ // Broken durations found experimentally
+ 359999.999 | 359999.000 | 86399.999 | 86399.99900000001 => 0.,
+ x => x,
+ }
+}