Track media server songs list
This commit is contained in:
parent
d217dd0b81
commit
9c689d73d6
12
.idea/dataSources.xml
Normal file
12
.idea/dataSources.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="postgres@localhost" uuid="84798454-83c1-4f0a-870a-8e649a07b493">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://localhost:5432/postgres</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/navidrome-playlists.iml" filepath="$PROJECT_DIR$/.idea/navidrome-playlists.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
13
.idea/navidrome-playlists.iml
Normal file
13
.idea/navidrome-playlists.iml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="CPP_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/navidrome/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/navidrome/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -11,18 +11,20 @@
|
||||
<component name="CargoProjects">
|
||||
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
|
||||
<cargoProject FILE="$PROJECT_DIR$/navidrome/Cargo.toml" />
|
||||
<cargoProject FILE="$PROJECT_DIR$/listenbrainz/Cargo.toml" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="52900e09-9584-4b6c-95ff-fbd4ed5d8b2c" name="Changes" comment="Structure">
|
||||
<change afterPath="$PROJECT_DIR$/src/daemon.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/listenbrainz.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/models.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/navidrome/src/client/library.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/daemon/mod.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/daemon/update_tracks.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/listenbrainz/Cargo.toml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/listenbrainz/src/lib.rs" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/navidrome/src/client/builder.rs" beforeDir="false" afterPath="$PROJECT_DIR$/navidrome/src/client/builder.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/navidrome/src/client/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/navidrome/src/client/mod.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/navidrome/src/client/playlists.rs" beforeDir="false" afterPath="$PROJECT_DIR$/navidrome/src/client/playlists.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/navidrome/src/models/navidrome.rs" beforeDir="false" afterPath="$PROJECT_DIR$/navidrome/src/models/navidrome.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/daemon.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/daemon/update_playlists.rs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
@ -56,12 +58,13 @@
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.cidr.known.project.marker": "true",
|
||||
"WebServerToolWindowFactoryState": "false",
|
||||
"cf.first.check.clang-format": "false",
|
||||
"cidr.known.project.marker": "true",
|
||||
"last_opened_file_path": "/home/jude/listenbrainz-rs",
|
||||
"last_opened_file_path": "/home/jude/Documents/navidrome-playlists/src/daemon",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
@ -72,18 +75,50 @@
|
||||
"org.rust.disableDetachedFileInspection/home/jude/navidrome-playlists/navidrome/src/client/playlists.rs": "true",
|
||||
"org.rust.disableDetachedFileInspection/home/jude/navidrome-playlists/navidrome/src/lib.rs": "true",
|
||||
"org.rust.disableDetachedFileInspection/home/jude/navidrome-playlists/navidrome/src/models.rs": "true",
|
||||
"settings.editor.selected.configurable": "language.rust.rustfmt",
|
||||
"settings.editor.selected.configurable": "language.rust.cargo.check",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
},
|
||||
"keyToStringList": {
|
||||
"DatabaseDriversLRU": [
|
||||
"postgresql"
|
||||
]
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/src/daemon" />
|
||||
<recent name="$PROJECT_DIR$/navidrome/src/client" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/src/daemon" />
|
||||
<recent name="$PROJECT_DIR$/navidrome/src/models" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="Run" type="CargoCommandRunConfiguration" factoryName="Cargo Command" nameIsGenerated="true">
|
||||
<option name="command" value="run" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs>
|
||||
<env name="DATABASE_URL" value="postgres:///navidrome-playlists" />
|
||||
<env name="NAVIDROME_BASE" value="https://navidrome.jellypro.xyz" />
|
||||
<env name="NAVIDROME_TOKEN" value="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG0iOnRydWUsImV4cCI6MTY5NDM2MjkyNywiaWF0IjoxNjk0MjcyNzE1LCJpc3MiOiJORCIsInN1YiI6Imp1ZGUiLCJ1aWQiOiIyZjljNTFiMi03MThmLTRiZmYtYjhkYi03MzE0ODdmZmFhYmIifQ.XNpfkjJI7wXq4EzGM-s7dQAXyCBAyN4Dmy4frbRMXPU" />
|
||||
</envs>
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="RustProjectSettings">
|
||||
<option name="toolchainHomeDirectory" value="$PROJECT_DIR$/../.cargo/bin" />
|
||||
<option name="version" value="2" />
|
||||
<option name="toolchainHomeDirectory" value="$USER_HOME$/.cargo/bin" />
|
||||
</component>
|
||||
<component name="RustfmtProjectSettings">
|
||||
<option name="runRustfmtOnSave" value="true" />
|
||||
@ -100,6 +135,8 @@
|
||||
<workItem from="1691949248703" duration="4525000" />
|
||||
<workItem from="1692003763542" duration="5103000" />
|
||||
<workItem from="1692042976149" duration="10055000" />
|
||||
<workItem from="1694271920428" duration="9295000" />
|
||||
<workItem from="1694285959491" duration="137000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Structure">
|
||||
<created>1692008860369</created>
|
||||
@ -118,4 +155,8 @@
|
||||
<MESSAGE value="Structure" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Structure" />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
<select />
|
||||
</component>
|
||||
</project>
|
73
Cargo.lock
generated
73
Cargo.lock
generated
@ -35,6 +35,21 @@ version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.73"
|
||||
@ -194,6 +209,21 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.5"
|
||||
@ -670,6 +700,29 @@ dependencies = [
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
@ -855,11 +908,22 @@ dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "navidrome"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"reqwest",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "navidrome-playlists"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"navidrome",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"sqlx",
|
||||
@ -2062,6 +2126,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
@ -11,6 +11,7 @@ tokio = { version = "1.0", features = ["full"] }
|
||||
sqlx = { version = "0.7.1", features = ["runtime-tokio", "postgres", "uuid"] }
|
||||
reqwest = { version = "0.11.18", features = ["json"] }
|
||||
serde = { version = "1.0.183", features = ["derive"] }
|
||||
navidrome = { path = "navidrome" }
|
||||
|
||||
[package.metadata.deb]
|
||||
depends = "$auto"
|
||||
|
@ -1,2 +1,59 @@
|
||||
struct NavidromeBuilder {
|
||||
use crate::client::Navidrome;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
pub struct NavidromeBuilder {
|
||||
base: Option<String>,
|
||||
token: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NavidromeBuilderError {
|
||||
MissingParam,
|
||||
Reqwest(reqwest::Error),
|
||||
}
|
||||
|
||||
impl Display for NavidromeBuilderError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for NavidromeBuilderError {}
|
||||
|
||||
impl NavidromeBuilder {
|
||||
pub fn new() -> NavidromeBuilder {
|
||||
return NavidromeBuilder {
|
||||
base: None,
|
||||
token: None,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn base(&mut self, base: impl ToString) -> &mut NavidromeBuilder {
|
||||
self.base = Some(base.to_string());
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn token(&mut self, token: impl ToString) -> &mut NavidromeBuilder {
|
||||
self.token = Some(token.to_string());
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn build(&self) -> Result<Navidrome, NavidromeBuilderError> {
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
.build()
|
||||
.map_err(|e| NavidromeBuilderError::Reqwest(e))?;
|
||||
|
||||
return Ok(Navidrome {
|
||||
base: self
|
||||
.base
|
||||
.clone()
|
||||
.ok_or(NavidromeBuilderError::MissingParam)?,
|
||||
http: client,
|
||||
token: self
|
||||
.token
|
||||
.clone()
|
||||
.ok_or(NavidromeBuilderError::MissingParam)?,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
22
navidrome/src/client/library.rs
Normal file
22
navidrome/src/client/library.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use crate::client::{MediaResult as Result, Navidrome, QualifyPath};
|
||||
use crate::models::generic::Playlist;
|
||||
use crate::models::navidrome::{NavidromePlaylist, NavidromeTrack};
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Library {
|
||||
async fn tracks(&self) -> Result<Vec<NavidromeTrack>>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Library for Navidrome {
|
||||
async fn tracks(&self) -> Result<Vec<NavidromeTrack>> {
|
||||
self.http
|
||||
.get(self.path("api/song"))
|
||||
.header("X-Nd-Authorization", format!("Bearer {}", self.token))
|
||||
.send()
|
||||
.await?
|
||||
.json::<Vec<NavidromeTrack>>()
|
||||
.await
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
pub mod builder;
|
||||
pub mod library;
|
||||
pub mod playlists;
|
||||
|
||||
trait QualifyPath {
|
||||
fn path(&self, path: &str) -> String;
|
||||
fn path(&self, path: impl Display) -> String;
|
||||
}
|
||||
|
||||
pub type MediaResult<U> = Result<U, reqwest::Error>;
|
||||
@ -14,7 +17,7 @@ pub struct Navidrome {
|
||||
}
|
||||
|
||||
impl QualifyPath for Navidrome {
|
||||
fn path(&self, path: &str) -> String {
|
||||
fn path(&self, path: impl Display) -> String {
|
||||
format!("{}/{}", self.base, path)
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
use crate::client::{MediaResult as Result, Navidrome, QualifyPath};
|
||||
use crate::models::generic::Playlist;
|
||||
use crate::models::navidrome::NavidromePlaylist;
|
||||
use crate::models::navidrome::{NavidromePlaylist, NavidromeTrack};
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Playlists {
|
||||
async fn playlists(&self) -> Result<Vec<Playlist>>;
|
||||
async fn playlist(&self, id: String) -> Result<Playlist>;
|
||||
async fn tracks(&self, id: String) -> Result<Vec<NavidromeTrack>>;
|
||||
async fn create_playlist(&self) -> Result<Playlist>;
|
||||
async fn delete_playlist(&self) -> Result<()>;
|
||||
async fn update_playlists(&self) -> Result<()>;
|
||||
@ -26,7 +27,24 @@ impl Playlists for Navidrome {
|
||||
}
|
||||
|
||||
async fn playlist(&self, id: String) -> Result<Playlist> {
|
||||
todo!()
|
||||
self.http
|
||||
.get(self.path(format!("api/playlist/{}", id)))
|
||||
.header("X-Nd-Authorization", format!("Bearer {}", self.token))
|
||||
.send()
|
||||
.await?
|
||||
.json::<NavidromePlaylist>()
|
||||
.await
|
||||
.map(|pv| (&pv).into())
|
||||
}
|
||||
|
||||
async fn tracks(&self, id: String) -> Result<Vec<NavidromeTrack>> {
|
||||
self.http
|
||||
.get(self.path(format!("api/playlist/{}/tracks", id)))
|
||||
.header("X-Nd-Authorization", format!("Bearer {}", self.token))
|
||||
.send()
|
||||
.await?
|
||||
.json::<Vec<NavidromeTrack>>()
|
||||
.await
|
||||
}
|
||||
|
||||
async fn create_playlist(&self) -> Result<Playlist> {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::models::generic::Playlist;
|
||||
use chrono::NaiveDateTime;
|
||||
use serde::Deserialize;
|
||||
use std::iter::Iterator;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct LoginResponse {
|
||||
@ -34,8 +33,6 @@ pub(crate) struct NavidromePlaylist {
|
||||
owner_id: String,
|
||||
#[serde(rename = "ownerName")]
|
||||
owner_name: String,
|
||||
#[serde(skip)] // todo fix
|
||||
rules: Option<NavidromePlaylistRule>,
|
||||
#[serde(rename = "songCount")]
|
||||
song_count: u64,
|
||||
sync: bool,
|
||||
@ -54,5 +51,20 @@ impl From<&NavidromePlaylist> for Playlist {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct NavidromePlaylistRule {}
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub struct NavidromeTrack {
|
||||
title: String,
|
||||
artist: String,
|
||||
#[serde(rename = "albumArtist")]
|
||||
album_artist: String,
|
||||
album: String,
|
||||
#[serde(rename = "albumId")]
|
||||
album_id: String,
|
||||
#[serde(rename = "artistId")]
|
||||
artist_id: String,
|
||||
id: String,
|
||||
#[serde(rename = "mbzTrackId")]
|
||||
pub musicbrainz_track_id: Option<String>,
|
||||
#[serde(rename = "mbzReleaseTrackId")]
|
||||
musicbrainz_release_track_id: Option<String>,
|
||||
}
|
||||
|
5
src/daemon/mod.rs
Normal file
5
src/daemon/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod update_playlists;
|
||||
pub mod update_tracks;
|
||||
|
||||
pub use update_playlists::update_playlists_daemon;
|
||||
pub use update_tracks::update_tracks_daemon;
|
@ -5,6 +5,8 @@ use std::time::Duration;
|
||||
use tokio::time::{interval, MissedTickBehavior};
|
||||
|
||||
pub async fn update_playlists_daemon() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Playlist daemon starting...");
|
||||
|
||||
let database = PgPool::connect(&env::var("DATABASE_URL").unwrap())
|
||||
.await
|
||||
.unwrap();
|
33
src/daemon/update_tracks.rs
Normal file
33
src/daemon/update_tracks.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use navidrome::{
|
||||
client::{library::Library, Navidrome},
|
||||
models::navidrome::NavidromeTrack,
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::time::{interval, MissedTickBehavior};
|
||||
|
||||
pub async fn update_tracks_daemon(
|
||||
media_client: &Navidrome,
|
||||
tracks_map: &mut Arc<RwLock<HashMap<String, NavidromeTrack>>>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Tracks daemon starting...");
|
||||
|
||||
let mut ticker = interval(Duration::from_secs(30));
|
||||
ticker.set_missed_tick_behavior(MissedTickBehavior::Skip);
|
||||
|
||||
loop {
|
||||
let mut tracks_map = tracks_map.write().await;
|
||||
media_client.tracks().await?.iter().for_each(|t| {
|
||||
if let Some(mb_id) = &t.musicbrainz_track_id {
|
||||
tracks_map.insert(mb_id.clone(), t.clone());
|
||||
}
|
||||
});
|
||||
|
||||
println!("Found {} tracks", tracks_map.len());
|
||||
|
||||
ticker.tick().await;
|
||||
}
|
||||
}
|
40
src/main.rs
40
src/main.rs
@ -2,20 +2,54 @@ mod daemon;
|
||||
mod listenbrainz;
|
||||
mod models;
|
||||
|
||||
use crate::daemon::update_playlists_daemon;
|
||||
use navidrome::{
|
||||
client::{builder::NavidromeBuilder, library::Library},
|
||||
models::navidrome::NavidromeTrack,
|
||||
};
|
||||
|
||||
use crate::daemon::{update_playlists_daemon, update_tracks_daemon};
|
||||
use crate::listenbrainz::StatsRange;
|
||||
use axum::extract::State;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use sqlx::postgres::PgPool;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TrackState {
|
||||
tracks: Arc<RwLock<HashMap<String, NavidromeTrack>>>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let database = PgPool::connect(&env::var("DATABASE_URL")?).await?;
|
||||
sqlx::migrate!().run(&database).await?;
|
||||
|
||||
let media_client = NavidromeBuilder::new()
|
||||
.base(env::var("NAVIDROME_BASE")?)
|
||||
.token(env::var("NAVIDROME_TOKEN")?)
|
||||
.build()?;
|
||||
|
||||
let mut tracks = Arc::new(RwLock::new(HashMap::new()));
|
||||
|
||||
let state = TrackState {
|
||||
tracks: tracks.clone(),
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
update_playlists_daemon().await.unwrap();
|
||||
});
|
||||
|
||||
tokio::spawn(async move {
|
||||
update_tracks_daemon(&media_client, &mut tracks)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
let app = Router::new().route("/", get(index)).with_state(database);
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
@ -23,10 +57,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.serve(app.into_make_service())
|
||||
.await?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
update_playlists_daemon().await.unwrap();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user