danceinterpreter_rs/dataloading/
m3uloader.rs

1use 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}