gonk_database/
playlist.rs

1use walkdir::WalkDir;
2
3use crate::{database_path, Index, RawSong, SONG_LEN};
4use std::{
5    fs::{self, File},
6    io::{BufWriter, Write},
7    path::{Path, PathBuf},
8    str::from_utf8_unchecked,
9};
10
11pub fn playlists() -> Vec<RawPlaylist> {
12    let mut path = database_path();
13    path.pop();
14
15    WalkDir::new(path)
16        .into_iter()
17        .flatten()
18        .filter(|path| match path.path().extension() {
19            Some(ex) => {
20                matches!(ex.to_str(), Some("playlist"))
21            }
22            None => false,
23        })
24        .flat_map(|entry| fs::read(entry.path()))
25        .map(|bytes| RawPlaylist::from(bytes.as_slice()))
26        .collect()
27}
28
29pub fn remove_playlist(path: &Path) {
30    fs::remove_file(path).unwrap();
31}
32
33#[derive(Debug)]
34pub struct RawPlaylist {
35    pub name: String,
36    pub path: PathBuf,
37    pub songs: Index<RawSong>,
38}
39
40impl RawPlaylist {
41    pub fn new(name: &str, data: Vec<RawSong>) -> Self {
42        let mut path = database_path();
43        path.pop();
44        path.push(format!("{}.playlist", name));
45
46        Self {
47            path,
48            name: name.to_string(),
49            songs: Index::from(data),
50        }
51    }
52    pub fn save(&self) {
53        //Delete the contents of the file and overwrite with new settings.
54        let file = File::create(&self.path).unwrap();
55        let mut writer = BufWriter::new(file);
56
57        //Convert to bytes.
58        let mut bytes = Vec::new();
59        bytes.extend((self.name.len() as u16).to_le_bytes());
60        bytes.extend(self.name.as_bytes());
61        for song in &self.songs.data {
62            bytes.extend(song.into_bytes());
63        }
64
65        writer.write_all(&bytes).unwrap();
66        writer.flush().unwrap();
67    }
68}
69
70impl From<&[u8]> for RawPlaylist {
71    fn from(bytes: &[u8]) -> Self {
72        unsafe {
73            let name_len = u16::from_le_bytes(bytes[0..2].try_into().unwrap_unchecked()) as usize;
74            let name = from_utf8_unchecked(&bytes[2..name_len + 2]);
75
76            let mut i = name_len + 2;
77            let mut songs = Vec::new();
78
79            while let Some(bytes) = bytes.get(i..i + SONG_LEN) {
80                songs.push(RawSong::from(bytes));
81                i += SONG_LEN;
82            }
83
84            let mut path = database_path();
85            path.pop();
86            path.push(format!("{}.playlist", name));
87
88            Self {
89                name: name.to_string(),
90                path,
91                songs: Index::from(songs),
92            }
93        }
94    }
95}