danceinterpreter_rs/dataloading/
m3uloader.rs1use std::io;
2use std::io::Result;
3use std::path::{Path, PathBuf};
4
5use crate::dataloading::id3tagreader::read_song_info_from_filepath;
6use crate::dataloading::songinfo::SongInfo;
7use percent_encoding::percent_decode_str;
8use url::Url;
9
10pub fn load_tag_data_from_m3u(path: &Path) -> Result<Vec<SongInfo>> {
11 let files = load_m3u_content_from_path(path)?;
12 let mut songtags: Vec<SongInfo> = Vec::new();
13
14 for file in files {
15 let tag = read_song_info_from_filepath(&file).map_err(|e| {
16 io::Error::new(
17 io::ErrorKind::InvalidData,
18 format!("Error reading tag from file: {}", e),
19 )
20 })?;
21 songtags.push(tag);
22 }
23
24 Ok(songtags)
25}
26
27fn load_m3u_content_from_path(path: &Path) -> Result<Vec<PathBuf>> {
28 let m3u_content = std::fs::read_to_string(path)?;
29 let root = path.parent().unwrap();
30
31 let entries = m3u_content.lines().filter(|x| !x.starts_with('#'));
32
33 let absolute_paths = entries
34 .map(|entry| parse_file_uri(entry).unwrap_or(parse_encoded_file_name(entry)))
35 .map(|entry| root.join(entry));
36
37 let accessible_files = absolute_paths.filter(|entry| entry.exists());
38
39 Ok(accessible_files.collect::<Vec<PathBuf>>())
40}
41
42fn parse_file_uri(uri: &str) -> Option<PathBuf> {
43 let uri = Url::parse(uri).ok()?;
44 uri.to_file_path().ok()
45}
46
47fn parse_encoded_file_name(file: &str) -> PathBuf {
48 PathBuf::from(percent_decode_str(file).decode_utf8_lossy().to_string())
49}
50
51#[cfg(test)]
52#[macro_use]
53mod tests {
54 use std::path::Path;
55
56 use crate::dataloading::m3uloader::{load_m3u_content_from_path, load_tag_data_from_m3u};
57 use crate::test_file;
58
59 #[test]
60 fn m3u_path_parsing() {
61 let result = load_m3u_content_from_path(Path::new(test_file!("m3u_validation_test.m3u")));
62 assert!(result.is_ok());
63 #[cfg(not(windows))]
64 assert_eq!(result.unwrap().len(), 4);
65 #[cfg(windows)]
66 assert_eq!(result.unwrap().len(), 2);
67 }
68
69 #[test]
70 fn m3u_files_id3_tag_loading() {
71 let result = load_tag_data_from_m3u(Path::new(test_file!("id3_read_test.m3u")));
72 assert!(result.is_ok());
73 let res = result.unwrap()[0].clone();
74 assert_eq!(res.title, "Sine Test");
75 assert_eq!(res.artist, "K7");
76 assert_eq!(res.dance, "Test Dance");
77 }
78}