Skip to content

Commit 6c3256a

Browse files
committed
refactor: Create a download manager crate, create a common structs crate.
1 parent 1517d31 commit 6c3256a

File tree

23 files changed

+448
-341
lines changed

23 files changed

+448
-341
lines changed

Cargo.lock

Lines changed: 22 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
[workspace]
22
resolver = "3"
3-
members = ["crates/database","crates/player", "crates/ytermusic", "crates/ytpapi2"]
3+
members = ["crates/common-structs","crates/database", "crates/download-manager","crates/player", "crates/ytermusic", "crates/ytpapi2"]
44

55
[workspace.dependencies]
66
player = { path = "crates/player" }
77
ytpapi2 = { path = "crates/ytpapi2" }
88
database = { path = "crates/database" }
9+
download-manager = { path = "crates/download-manager" }
10+
common-structs = { path = "crates/common-structs" }

crates/common-structs/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "common-structs"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[derive(PartialEq, Debug, Clone)]
2+
pub enum AppStatus {
3+
Paused,
4+
Playing,
5+
NoMusic,
6+
}

crates/common-structs/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
mod app_status;
2+
mod music_download_status;
3+
4+
pub use app_status::AppStatus;
5+
pub use music_download_status::MusicDownloadStatus;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#[derive(PartialEq, Debug, Clone, Copy)]
2+
pub enum MusicDownloadStatus {
3+
NotDownloaded,
4+
Downloaded,
5+
Downloading(usize),
6+
DownloadFailed,
7+
}
8+
9+
impl MusicDownloadStatus {
10+
pub fn character(&self, playing: Option<bool>) -> String {
11+
match self {
12+
Self::NotDownloaded => {
13+
if let Some(e) = playing {
14+
if e { '▶' } else { '⏸' }
15+
} else {
16+
' '
17+
}
18+
}
19+
Self::Downloaded => ' ',
20+
Self::Downloading(progress) => return format!("⭳ [{:02}%]", progress),
21+
Self::DownloadFailed => '⚠',
22+
}
23+
.into()
24+
}
25+
}

crates/download-manager/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "download-manager"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
ytpapi2.workspace = true
8+
flume = "0.11.0"
9+
once_cell = "1.19.0"
10+
tokio = { version = "1.36.0", features = ["rt-multi-thread"] }
11+
serde = { version = "1.0", features = ["derive"] }
12+
serde_json = "1.0"
13+
database.workspace = true
14+
common-structs.workspace = true
15+
16+
# --- YT Download ---
17+
rusty_ytdl = { git = "https://github.com/Mithronn/rusty_ytdl/", branch = "main", features = ["rustls-tls", "search", "live"], default-features = false}
18+
19+
log = "0.4.20"

crates/download-manager/src/lib.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
mod task;
2+
3+
use std::{
4+
collections::{HashSet, VecDeque},
5+
path::PathBuf,
6+
sync::{Arc, Mutex},
7+
time::Duration,
8+
};
9+
10+
use database::YTLocalDatabase;
11+
use flume::Receiver;
12+
use tokio::{select, task::JoinHandle, time::sleep};
13+
use ytpapi2::YoutubeMusicVideoRef;
14+
15+
use common_structs::MusicDownloadStatus;
16+
17+
pub type MessageHandler = Arc<dyn Fn(DownloadManagerMessage) + Send + Sync + 'static>;
18+
19+
pub enum DownloadManagerMessage {
20+
VideoStatusUpdate(String, MusicDownloadStatus),
21+
}
22+
23+
pub struct DownloadManager {
24+
database: &'static YTLocalDatabase,
25+
cache_dir: PathBuf,
26+
handles: Mutex<Vec<JoinHandle<()>>>,
27+
download_list: Mutex<VecDeque<YoutubeMusicVideoRef>>,
28+
in_download: Mutex<HashSet<String>>,
29+
}
30+
31+
impl DownloadManager {
32+
pub fn new(cache_dir: PathBuf, database: &'static YTLocalDatabase) -> Self {
33+
Self {
34+
database,
35+
cache_dir,
36+
handles: Mutex::new(Vec::new()),
37+
download_list: Mutex::new(VecDeque::new()),
38+
in_download: Mutex::new(HashSet::new()),
39+
}
40+
}
41+
42+
pub fn remove_from_in_downloads(&self, video: &String) {
43+
self.in_download.lock().unwrap().remove(video);
44+
}
45+
46+
fn take(&self) -> Option<YoutubeMusicVideoRef> {
47+
self.download_list.lock().unwrap().pop_front()
48+
}
49+
50+
/// This has to be called as a service stream
51+
/// HANDLES.lock().unwrap().push(run_service(async move {
52+
/// run_service_stream(sender);
53+
/// }));
54+
pub fn run_service_stream(&'static self, cancelation: Receiver<()>, sender: MessageHandler) {
55+
let fut = async move {
56+
loop {
57+
if let Some(id) = self.take() {
58+
self.start_download(id, sender.clone()).await;
59+
} else {
60+
sleep(Duration::from_millis(200)).await;
61+
}
62+
}
63+
};
64+
let service = tokio::task::spawn(async move {
65+
select! {
66+
_ = fut => {},
67+
_ = cancelation.recv_async() => {},
68+
}
69+
});
70+
self.handles.lock().unwrap().push(service);
71+
}
72+
73+
pub fn spawn_system(&'static self, cancelation: Receiver<()>, sender: MessageHandler) {
74+
for _ in 0..DOWNLOADER_COUNT {
75+
self.run_service_stream(cancelation.clone(), sender.clone());
76+
}
77+
}
78+
79+
pub fn clean(&'static self, cancelation: Receiver<()>, sender: MessageHandler) {
80+
self.download_list.lock().unwrap().clear();
81+
self.in_download.lock().unwrap().clear();
82+
{
83+
let mut handle = self.handles.lock().unwrap();
84+
for i in handle.iter() {
85+
i.abort()
86+
}
87+
handle.clear();
88+
}
89+
self.spawn_system(cancelation, sender);
90+
}
91+
92+
pub fn set_download_list(&self, to_add: impl IntoIterator<Item = YoutubeMusicVideoRef>) {
93+
let mut list = self.download_list.lock().unwrap();
94+
list.clear();
95+
list.extend(to_add);
96+
}
97+
98+
pub fn add_to_download_list(&self, to_add: impl IntoIterator<Item = YoutubeMusicVideoRef>) {
99+
let mut list = self.download_list.lock().unwrap();
100+
list.extend(to_add);
101+
}
102+
}
103+
104+
const DOWNLOADER_COUNT: usize = 4;

0 commit comments

Comments
 (0)