aboutsummaryrefslogtreecommitdiff
path: root/import/src/plugins/media_info.rs
blob: d2aa5af72af7de7e4d844202cc088a6bcd3c49b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
    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) 2026 metamuffin <metamuffin.org>
*/

use crate::plugins::{ImportContext, ImportPlugin, PluginInfo};
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 info(&self) -> PluginInfo {
        PluginInfo {
            name: "media-info",
            handle_media: true,
            ..Default::default()
        }
    }
    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(())
    }
}

fn fix_invalid_runtime(d: f64) -> f64 {
    match d {
        // Broken durations found experimentally
        359999.999 | 359999.000 | 86399.999 | 86399.99900000001 => 0.,
        x => x,
    }
}