jellytau_lib/domain/
from_jellyfin.rs1use super::media::{MediaKind, StreamKind};
10
11pub fn stream_kind_from_jellyfin(stream_type: &str) -> StreamKind {
14 match stream_type {
15 "Audio" => StreamKind::Audio,
16 "Video" => StreamKind::Video,
17 "Subtitle" => StreamKind::Subtitle,
18 _ => StreamKind::Other,
19 }
20}
21
22const TICKS_PER_MILLISECOND: i64 = 10_000;
25
26pub fn ticks_to_ms(ticks: i64) -> i64 {
30 ticks / TICKS_PER_MILLISECOND
31}
32
33pub fn kind_from_jellyfin(item_type: &str, is_folder: bool) -> MediaKind {
43 match item_type {
44 "Audio" | "MusicVideo" => MediaKind::Track,
46 "MusicAlbum" => MediaKind::Album,
47 "MusicArtist" | "AlbumArtist" => MediaKind::Artist,
48 "Playlist" => MediaKind::Playlist,
49
50 "Movie" => MediaKind::Movie,
52 "Series" => MediaKind::Series,
53 "Season" => MediaKind::Season,
54 "Episode" => MediaKind::Episode,
55 "Video" => MediaKind::Movie,
57
58 "Person" | "Actor" | "Director" | "Writer" | "Composer" | "GuestStar" | "Producer" => {
61 MediaKind::Person
62 }
63
64 "TvChannel" | "LiveTvChannel" => MediaKind::LiveChannel,
66 "Channel" => MediaKind::Channel,
68
69 "Folder" | "CollectionFolder" | "UserView" | "BoxSet" => MediaKind::Folder,
71 "ChannelFolderItem" => {
74 if is_folder {
75 MediaKind::ChannelFolder
76 } else {
77 MediaKind::ChannelItem
78 }
79 }
80
81 _ => {
83 if is_folder {
84 MediaKind::Folder
85 } else {
86 MediaKind::Other
87 }
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn ticks_convert_to_milliseconds() {
98 assert_eq!(ticks_to_ms(10_000_000), 1000);
100 assert_eq!(ticks_to_ms(905_000_000), 90_500);
102 assert_eq!(ticks_to_ms(0), 0);
103 assert_eq!(ticks_to_ms(9_999), 0);
105 }
106
107 #[test]
108 fn music_types_map() {
109 assert_eq!(kind_from_jellyfin("Audio", false), MediaKind::Track);
110 assert_eq!(kind_from_jellyfin("MusicAlbum", true), MediaKind::Album);
111 assert_eq!(kind_from_jellyfin("MusicArtist", true), MediaKind::Artist);
112 assert_eq!(kind_from_jellyfin("Playlist", true), MediaKind::Playlist);
113 }
114
115 #[test]
116 fn video_types_map() {
117 assert_eq!(kind_from_jellyfin("Movie", false), MediaKind::Movie);
118 assert_eq!(kind_from_jellyfin("Series", true), MediaKind::Series);
119 assert_eq!(kind_from_jellyfin("Season", true), MediaKind::Season);
120 assert_eq!(kind_from_jellyfin("Episode", false), MediaKind::Episode);
121 assert_eq!(kind_from_jellyfin("Video", false), MediaKind::Movie);
122 }
123
124 #[test]
125 fn person_and_role_types_map_to_person() {
126 for t in ["Person", "Actor", "Director", "Writer", "Composer"] {
127 assert_eq!(kind_from_jellyfin(t, false), MediaKind::Person, "{t}");
128 }
129 }
130
131 #[test]
132 fn channel_and_container_types_map() {
133 assert_eq!(
134 kind_from_jellyfin("TvChannel", false),
135 MediaKind::LiveChannel
136 );
137 assert_eq!(kind_from_jellyfin("Channel", false), MediaKind::Channel);
138 assert_eq!(
139 kind_from_jellyfin("CollectionFolder", true),
140 MediaKind::Folder
141 );
142 assert_eq!(kind_from_jellyfin("BoxSet", true), MediaKind::Folder);
143 }
144
145 #[test]
153 fn channel_folder_item_disambiguates_on_is_folder() {
154 assert_eq!(
155 kind_from_jellyfin("ChannelFolderItem", true),
156 MediaKind::ChannelFolder
157 );
158 assert_eq!(
159 kind_from_jellyfin("ChannelFolderItem", false),
160 MediaKind::ChannelItem
161 );
162 }
163
164 #[test]
165 fn stream_kinds_map() {
166 assert_eq!(stream_kind_from_jellyfin("Audio"), StreamKind::Audio);
167 assert_eq!(stream_kind_from_jellyfin("Video"), StreamKind::Video);
168 assert_eq!(stream_kind_from_jellyfin("Subtitle"), StreamKind::Subtitle);
169 assert_eq!(
170 stream_kind_from_jellyfin("EmbeddedImage"),
171 StreamKind::Other
172 );
173 assert_eq!(stream_kind_from_jellyfin(""), StreamKind::Other);
174 }
175
176 #[test]
177 fn unknown_type_never_panics_and_falls_back() {
178 assert_eq!(kind_from_jellyfin("Epis0de", false), MediaKind::Other);
180 assert_eq!(kind_from_jellyfin("", false), MediaKind::Other);
181 assert_eq!(
182 kind_from_jellyfin("SomeFutureType", true),
183 MediaKind::Folder
184 );
185 assert_eq!(kind_from_jellyfin("🎵unicode", false), MediaKind::Other);
186 }
187}