13 Commits
Author SHA1 Message Date
phoenix f32f6812b3 Adding openssl (#104)
sidm / build (push) Successful in 3m26s
Reviewed-on: #104
2026-07-21 15:32:48 -04:00
phoenix 68c0b06280 Dependency name change (#103)
sidm / build (push) Successful in 1m36s
Reviewed-on: #103
2026-07-16 13:47:33 -04:00
phoenix 592c5aaf60 Update rust (#102)
Rust / build (push) Successful in 3m25s
Reviewed-on: phoenix/idm#102
2026-07-10 19:29:05 -04:00
phoenix a8ed05c278 tsk-100: Name change (#101)
Rust / build (push) Successful in 1m44s
Rust / build (pull_request) Successful in 3m10s
From `icarus_dm` -> `idm`.

Closes #100

Reviewed-on: phoenix/icarus_dm#101
2026-07-10 19:03:11 -04:00
phoenixandGitHub 489d13227b Update rust (#99)
Rust / build (pull_request) Failing after 4s
* bump: rust

* bump: rust ci

* Updated License

* bump: reqwest

* bump: tokio

* bump: uuid

* bump: icarus_models

* cargo update

* bump: icarus_dm
2026-05-05 21:05:40 -04:00
phoenixandGitHub 0e6438cf0d Updated rust (#95)
* Updated rust version in workflow

* Using variable in workflow file

* Updating packages

* cargo update

* Version bump
2026-04-05 17:14:50 -04:00
KDandGitHub 00615532ce icarus_models version bump (#93)
* icarus_models version bump

* Build fix

* Removed method

* Some refactoring

* More cleanup

* Version bump

* Using standard version
2025-10-30 15:33:09 -04:00
KDandGitHub abd16eeba2 tsk-79: Simplifying functions (#92)
* tsk-79: Changed return type of function and cleaned up other functions

* tsk-79: Version bump

* tsk-79: Code formatting
2025-10-27 12:42:42 -04:00
KDandGitHub 5c9fcf2ec5 tsk-83: Add token code prior to action execution (#91)
* tsk-83: Code cleanup

* tsk-83: Added code to get token before an action begins

* tsk-83: Small fix

* tsk-83: Version bump

* tsk-83: Cleanup
2025-10-26 16:39:16 -04:00
KDandGitHub 6bedab0d88 tsk-82: Refactor validate_args() method (#90)
* tsk-82: Refactored validate_flags() method

* tsk-82: Warning fix

* tsk-82: Code formatting

* tsk-82: Version bump

* tsk-82: Forgot this

* tsk-82: Fix
2025-10-24 20:51:33 -04:00
KDandGitHub 686e0d8f1f tsk-81: Simplify downloading song (#89)
* tsk-81: Using method in Song to save to filesystem

* tsk-81: icaurs_models version bump

* tsk-81: Code formatting

* tsk-81: icarus_models version bump

* tsk-81: Version bump
2025-10-24 13:34:55 -04:00
KDandGitHub 05a9134aaa tsk-80: Removing unused serde references (#88)
* tsk-80: Removing unused serde references

* tsk-80: Version bump

* tsk-80: Formatting code
2025-10-23 21:10:08 -04:00
KDandGitHub 3cadac4efd tsk-78: Updating returned error on converting ostring to string (#87)
* tsk-78: Making error to get string from o string more robust

* tsk-78: Version bump
2025-10-23 16:52:26 -04:00
19 changed files with 883 additions and 885 deletions
@@ -1,4 +1,4 @@
name: Rust
name: sidm
on:
push:
@@ -15,19 +15,17 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- name: Install Rust version
run: rustup install 1.90.0 && rustup default 1.90.0
- name: Debug secret
run: echo "${{ secrets.MYREPO_TOKEN }}" | head -c 10 ; echo "..."
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.97
- uses: Swatinem/rust-cache@v2
- name: Build
run: |
mkdir -p ~/.ssh
echo "$EXTREPO_KEY" > ~/.ssh/gitlab_deploy_key
chmod 600 ~/.ssh/gitlab_deploy_key
ssh-keyscan git.kundeng.us ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLl/OZiKVDxwnyvMxa+rjKvDpKqTxH1GWuGuDPLmENGQMbTVulajZWr9x8Q1cotoJiHZkt7DA5vczcjB/4lwgWA= >> ~/.ssh/known_hosts
ssh-keyscan ${{ secrets.MYHOST }}= >> ~/.ssh/known_hosts
eval $(ssh-agent -s)
ssh-add -v ~/.ssh/gitlab_deploy_key
Generated
+666 -588
View File
File diff suppressed because it is too large Load Diff
+13 -11
View File
@@ -1,17 +1,19 @@
[package]
name = "icarus-dm"
version = "0.8.4"
rust-version = "1.90"
name = "sidm"
version = "0.10.1"
rust-version = "1.95"
edition = "2024"
license = "MIT"
description = "CLI tool to download and upload music from soaricarus"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
futures = { version = "0.3.31" }
http = { version = "1.3.1" }
reqwest = { version = "0.12.23", features = ["json", "blocking", "multipart", "stream"] }
http = { version = "1.4.2" }
reqwest = { version = "0.13.4", features = ["json", "blocking", "multipart", "stream"] }
openssl = { version = "0.10.81", features = ["vendored"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
tokio = { version = "1.47.1", features = ["full"] }
tokio-util = { version = "0.7.16", features = ["codec"] }
uuid = { version = "1.18.1", features = ["v4", "serde"] }
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.8.0" }
serde_json = { version = "1.0.150" }
tokio = { version = "1.52.4", features = ["full"] }
tokio-util = { version = "0.7.18", features = ["codec"] }
uuid = { version = "1.23.4", features = ["v4", "serde"] }
simodels = { git = "ssh://git@git.kundeng.us/phoenix/simodels.git", tag = "v0.11.3-main-fe9d101bd0-111" }
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2025 Kun Deng
Copyright (c) 2026 Kun Deng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+9 -27
View File
@@ -1,72 +1,54 @@
# IcarusDownloadManager
# sidm
IcarusDownloadManager is a CLI software client application that has the feature of uploading and downloading songs from the [Icarus](https://github.com/kdeng00/Icarus) Music Server.
sidm (SoarIcarusDownloadManager) is a CLI software client application that has the feature of uploading and downloading songs from the [soaricarus_api](https://git.kundeng.us/phoenix/soaricarus_api) Music Server.
## Built With
* Rust
* Cargo
* futures
* http
* reqwst
* serde
* serde_json
* tokio
* tokio-util
* icarus_models
### Getting Started
Clone the repo
```BASH
git clone git@github.com:kdeng00/IcarusDownloadManager.git
git clone git@git.kundeng.us:phoenix/sidm.git
```
Build the project:
```BASH
cd IcarusDownloadManager
cd sidm
cargo build
```
Even though this project is open source, there are some libraries that are closed source (may be opened later).
In order to successfully build it, your ssh public key would be needed to add to the closed libraries. If you
have interest, something could be worked out to provide access.
The program has been built and can be executed by the binary file *icarus-dm*. For information on how to use icarua-dm, merely execute the program without any command line arguments.
### Downloading Song
```BASH
icarus-dm download -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -b e8407fc6-edd2-44c1-993f-08dd7324d91a
sidm download -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -b e8407fc6-edd2-44c1-993f-08dd7324d91a
```
### Uploading Song with metadata
```BASH
icarus-dm upload-meta -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -s /path/of/song.flac -t 1 -m /path/to/metadata/config/collection.json -ca /path/to/cover/art/image.png
sidm upload-meta -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -s /path/of/song.flac -t 1 -m /path/to/metadata/config/collection.json -ca /path/to/cover/art/image.png
```
### Uploading Song with metadata from directory
```BASH
icarus-dm upload-meta -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -smca /path/where/songs/and/metadata/exists/
sidm upload-meta -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -smca /path/where/songs/and/metadata/exists/
```
### Retrieving Song in json
```Bash
icarus-dm retrieve -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -rt songs
sidm retrieve -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -rt songs
```
### Deleting Song
```BASH
icarus-dm delete -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -D e8407fc6-edd2-44c1-993f-08dd7324d91a
sidm delete -u spacecadet -p stellar40 -h https://icarus.com -ha https://auth.icarus.com -D e8407fc6-edd2-44c1-993f-08dd7324d91a
```
+6 -5
View File
@@ -33,6 +33,7 @@ async fn main() {
let mut cmt_mgr = managers::commit_manager::CommitManager {
ica_action: chosen_act,
..Default::default()
};
cmt_mgr.commit_action().await;
@@ -50,7 +51,7 @@ mod tests {
assert!(false, "File does not exists: {meta_path:?}");
}
match icarus_models::album::collection::parse_album(&meta_path) {
match simodels::album::collection::parse_album(&meta_path) {
Ok(album) => {
for track in 1..3 {
let directory_path = std::path::Path::new(&meta_path);
@@ -58,17 +59,17 @@ mod tests {
let filename: String = if track < 10 {
String::from("track0")
+ &track.to_string()
+ icarus_models::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
+ simodels::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
} else {
String::from("track")
+ &track.to_string()
+ icarus_models::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
+ simodels::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
};
let disc = 1;
match managers::commit_manager::retrieve_song(
&album, track, disc, &directory, &filename,
) {
Ok(song) => match icarus_models::song::io::to_data(&song) {
Ok(song) => match simodels::song::io::to_data(&song) {
Ok(_) => {
print!("Success");
}
@@ -91,7 +92,7 @@ mod tests {
#[test]
fn test_minimum_action_and_args() {
let args: Vec<String> = vec![
"icarus-dm".to_string(),
"idm".to_string(),
"download".to_string(),
"-u".to_string(),
"jamborie".to_string(),
+9 -11
View File
@@ -1,8 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::{models, utilities};
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug)]
pub struct ActionManager {
pub action: String,
pub flags: Vec<models::flags::Flags>,
@@ -70,17 +68,17 @@ impl ActionManager {
while i < flag_vals.len() {
let flag = &flag_vals[i];
let mut flg = models::flags::Flags::default();
// TODO: Refactor this
if self.is_valid_flag(flag) && self.does_flag_have_value(flag) {
flg.flag = String::from(flag);
flg.value = String::from(&flag_vals[i + 1]);
if self.is_valid_flag(flag) {
if self.does_flag_have_value(flag) {
flg.flag = String::from(flag);
flg.value = String::from(&flag_vals[i + 1]);
i += 1;
} else if self.is_valid_flag(flag) {
flg.flag = String::from(flag);
i += 1;
} else {
flg.flag = String::from(flag);
}
} else {
utilities::checks::exit_program(-1);
}
+115 -162
View File
@@ -1,20 +1,20 @@
use std::collections::HashMap;
use std::default::Default;
use std::fs::read_dir;
use std::io::{Result, Write};
use std::io::Result;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use crate::managers;
use crate::models::{self};
use crate::parsers;
use crate::syncers;
use crate::utilities;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default)]
pub struct CommitManager {
pub ica_action: models::icarus_action::IcarusAction,
pub api: models::api::Api,
pub auth_api: models::api::Api,
}
#[derive(Clone, Debug)]
@@ -36,21 +36,21 @@ enum En {
#[derive(Debug)]
struct UploadSongMembers {
pub song: icarus_models::song::Song,
pub coverart: icarus_models::coverart::CoverArt,
pub token: icarus_models::token::AccessToken,
pub album: icarus_models::album::collection::Album,
pub song: simodels::song::Song,
pub coverart: simodels::coverart::CoverArt,
pub token: simodels::token::AccessToken,
pub album: simodels::album::collection::Album,
}
pub fn retrieve_song(
album: &icarus_models::album::collection::Album,
album: &simodels::album::collection::Album,
track: i32,
disc: i32,
directory: &str,
filename: &str,
) -> Result<icarus_models::song::Song> {
) -> Result<simodels::song::Song> {
let mut found = false;
let mut song = icarus_models::song::Song::default();
let mut song = simodels::song::Song::default();
for song_i in &album.tracks {
if song_i.track == track && song_i.disc == disc {
@@ -58,9 +58,8 @@ pub fn retrieve_song(
song.album = album.title.clone();
song.album_artist = album.artist.clone();
song.artist = track.artist.clone();
song.audio_type = String::from(
icarus_models::constants::file_extensions::audio::DEFAULTMUSICEXTENSION,
);
song.audio_type =
String::from(simodels::constants::file_extensions::audio::DEFAULTMUSICEXTENSION);
song.disc = track.disc;
song.disc_count = album.disc_count;
song.duration = track.duration as i32;
@@ -86,27 +85,36 @@ pub fn retrieve_song(
impl CommitManager {
pub async fn commit_action(&mut self) {
self.init_api().await;
let action = &self.ica_action.action;
println!("Committing {action} action");
let mapped_actions = &self.map_actions();
let mapped_action = self.find_mapped_action(mapped_actions, action);
let token = self.parse_token(&self.auth_api).await;
println!("{mapped_action:?}");
// TODO: Move code to get token here and then pass it to the respective functions
match mapped_action {
ActionValues::DeleteAct => self.delete_song().await,
ActionValues::DownloadAct => self.download_song().await,
ActionValues::RetrieveAct => self.retrieve_object().await,
ActionValues::UploadSongWithMetadata => self.upload_song_with_metadata().await,
match self.find_mapped_action(mapped_actions, action) {
ActionValues::DeleteAct => self.delete_song(&token).await,
ActionValues::DownloadAct => self.download_song(&token).await,
ActionValues::RetrieveAct => self.retrieve_object(&token).await,
ActionValues::UploadSongWithMetadata => self.upload_song_with_metadata(&token).await,
_ => {
println!("Nothing good here");
}
}
}
async fn init_api(&mut self) {
let mut prsr = parsers::api_parser::APIParser {
apis: vec![models::api::Api::default(), models::api::Api::default()],
ica_act: self.ica_action.clone(),
};
prsr.parse_api(parsers::api_parser::APIType::Main);
prsr.parse_api(parsers::api_parser::APIType::Auth);
self.api = prsr.retrieve_api(parsers::api_parser::APIType::Main);
self.auth_api = prsr.retrieve_api(parsers::api_parser::APIType::Auth);
}
fn find_mapped_action(
&self,
actions: &HashMap<String, ActionValues>,
@@ -122,7 +130,7 @@ impl CommitManager {
}
fn map_actions(&self) -> HashMap<String, ActionValues> {
let actions: HashMap<String, ActionValues> = HashMap::from([
HashMap::from([
("download".to_string(), ActionValues::DownloadAct),
("download".to_string(), ActionValues::DownloadAct),
(
@@ -131,25 +139,16 @@ impl CommitManager {
),
("retrieve".to_string(), ActionValues::RetrieveAct),
("delete".to_string(), ActionValues::DeleteAct),
]);
actions
])
}
async fn delete_song(&self) {
let mut prsr = parsers::api_parser::APIParser {
apis: vec![models::api::Api::default(), models::api::Api::default()],
ica_act: self.ica_action.clone(),
};
prsr.parse_api(parsers::api_parser::APIType::Main);
prsr.parse_api(parsers::api_parser::APIType::Auth);
let auth_api = prsr.retrieve_api(parsers::api_parser::APIType::Auth);
let token = self.parse_token(&auth_api).await;
async fn delete_song(&self, token: &simodels::token::AccessToken) {
println!("Deleting song");
let mut song = icarus_models::song::Song::default();
let mut del = syncers::delete::Delete {
api: self.api.clone(),
};
let mut song = simodels::song::Song::default();
for arg in &self.ica_action.flags {
let flag = &arg.flag;
@@ -160,12 +159,7 @@ impl CommitManager {
}
}
let api = prsr.retrieve_api(parsers::api_parser::APIType::Main);
let mut del = syncers::delete::Delete { api: api.clone() };
println!("Deleting song..");
match del.delete_song(&token, &song).await {
match del.delete_song(token, &song).await {
Ok((song, _coverart)) => {
println!("Song (Id {:?}) has been successfully deleted", song.id);
}
@@ -175,39 +169,42 @@ impl CommitManager {
}
}
async fn download_song(&self) {
println!("Deleting song");
async fn download_song(&self, token: &simodels::token::AccessToken) {
println!("Downloading song");
let dwn = self.ica_action.retrieve_flag_value(&String::from("-b"));
let song_id = uuid::Uuid::from_str(dwn.as_str()).unwrap();
let mut prsr = parsers::api_parser::APIParser {
apis: vec![models::api::Api::default(), models::api::Api::default()],
ica_act: self.ica_action.clone(),
let mut dwn_loader = syncers::download::Download {
api: self.api.clone(),
};
prsr.parse_api(parsers::api_parser::APIType::Main);
prsr.parse_api(parsers::api_parser::APIType::Auth);
let auth_api = prsr.retrieve_api(parsers::api_parser::APIType::Auth);
let token = self.parse_token(&auth_api).await;
println!("Message: {}", token.message);
let api = prsr.retrieve_api(parsers::api_parser::APIType::Main);
let mut dwn_loader = syncers::download::Download { api: api.clone() };
let song = icarus_models::song::Song {
id: song_id,
let mut song = simodels::song::Song {
id: uuid::Uuid::from_str(dwn.as_str()).unwrap(),
..Default::default()
};
match dwn_loader.download_song(&token, &song).await {
match dwn_loader.download_song(token, &song).await {
Ok(o) => {
println!("Success");
let filename = String::from("audio")
+ icarus_models::constants::file_extensions::audio::DEFAULTMUSICEXTENSION;
let data = o.as_bytes();
let mut file = std::fs::File::create(filename).expect("Failed to save");
file.write_all(data)
.expect("Failed to save downloaded song");
println!("Song downloaded");
song.data = o.as_bytes().to_vec();
song.directory = String::from(".");
song.filename = match simodels::song::generate_filename(
simodels::types::MusicType::FlacExtension,
true,
) {
Ok(filename) => filename,
Err(err) => {
eprintln!("Error generating song filename: {err:?}");
utilities::checks::exit_program(-3);
return;
}
};
match song.save_to_filesystem() {
Ok(_) => {
println!("Song saved");
}
Err(err) => {
eprintln!("Error saving song: {err:?}");
}
}
}
Err(er) => {
println!("Error {er:?}");
@@ -223,7 +220,7 @@ impl CommitManager {
}
}
async fn retrieve_object(&self) {
async fn retrieve_object(&self, token: &simodels::token::AccessToken) {
println!("Retrieving song");
let rt = self.ica_action.retrieve_flag_value(&String::from("-rt"));
@@ -231,22 +228,11 @@ impl CommitManager {
panic!("Unsupported -rt: {rt}");
}
let mut prsr = parsers::api_parser::APIParser {
apis: vec![models::api::Api::default(), models::api::Api::default()],
ica_act: self.ica_action.clone(),
let mut repo = syncers::retrieve_records::RetrieveRecords {
api: self.api.clone(),
};
prsr.parse_api(parsers::api_parser::APIType::Main);
prsr.parse_api(parsers::api_parser::APIType::Auth);
let auth_api = prsr.retrieve_api(parsers::api_parser::APIType::Auth);
let token = self.parse_token(&auth_api).await;
println!("Token {token:?}");
let api = prsr.retrieve_api(parsers::api_parser::APIType::Main);
let mut repo = syncers::retrieve_records::RetrieveRecords { api: api.clone() };
match repo.get_all_songs(&token).await {
match repo.get_all_songs(token).await {
Ok(o) => {
println!("Songs");
println!("=====");
@@ -263,12 +249,12 @@ impl CommitManager {
}
}
async fn parse_token(&self, api: &models::api::Api) -> icarus_models::token::AccessToken {
async fn parse_token(&self, api: &models::api::Api) -> simodels::token::AccessToken {
println!("Fetching token");
let mut usr_mgr: managers::user_manager::UserManager =
managers::user_manager::UserManager {
user: icarus_models::user::User::default(),
user: simodels::user::User::default(),
ica_action: self.ica_action.clone(),
};
usr_mgr.parse_user_from_actions();
@@ -285,7 +271,7 @@ impl CommitManager {
token.unwrap()
}
async fn upload_song_with_metadata(&mut self) {
async fn upload_song_with_metadata(&mut self, token: &simodels::token::AccessToken) {
println!("Uplodaring song with metadara");
let songpath = self.ica_action.retrieve_flag_value(&String::from("-s"));
@@ -313,12 +299,12 @@ impl CommitManager {
println!("cover art path: {coverpath}");
let _ = self
.sing_target_upload(&songpath, &track_id, &metadata_path, &coverpath)
.sing_target_upload(&songpath, &track_id, &metadata_path, &coverpath, token)
.await;
} else if multitarget {
let _ = self.multi_target_upload(&uni).await;
let _ = self.multi_target_upload(&uni, token).await;
} else {
println!("Single or Multi target has not been chosen");
eprintln!("Single or Multi target has not been chosen");
}
}
@@ -329,19 +315,8 @@ impl CommitManager {
track_id: &str,
meta_path: &String,
cover_path: &str,
token: &simodels::token::AccessToken,
) -> Result<()> {
let mut prsr = parsers::api_parser::APIParser {
apis: vec![models::api::Api::default(), models::api::Api::default()],
ica_act: self.ica_action.clone(),
};
prsr.parse_api(parsers::api_parser::APIType::Main);
prsr.parse_api(parsers::api_parser::APIType::Auth);
let auth_api = prsr.retrieve_api(parsers::api_parser::APIType::Auth);
let token = self.parse_token(&auth_api).await;
println!("Token: {:?}", token.token);
let song_file = std::path::Path::new(&songpath);
if !song_file.exists() {
@@ -351,7 +326,7 @@ impl CommitManager {
let pa = std::path::Path::new(&cover_path);
let mut cover_art = icarus_models::coverart::CoverArt {
let mut cover_art = simodels::coverart::CoverArt {
directory: String::from(pa.parent().unwrap().to_str().unwrap()),
filename: String::from(pa.file_name().unwrap().to_str().unwrap()),
..Default::default()
@@ -363,7 +338,7 @@ impl CommitManager {
Ok(s) => {
println!("file name: {file_name:?}");
match icarus_models::album::collection::parse_album(meta_path) {
match simodels::album::collection::parse_album(meta_path) {
Ok(album) => {
let filename = s.clone();
let directory = song_file.parent().unwrap().display().to_string();
@@ -373,15 +348,13 @@ impl CommitManager {
println!("Directory: {:?}", s.directory);
println!("Filename: {:?}", s.filename);
println!("Path: {:?}", s.song_path());
s.data = icarus_models::song::io::to_data(&s).unwrap();
cover_art.data =
icarus_models::coverart::io::to_data(&cover_art).unwrap();
s.data = simodels::song::io::to_data(&s).unwrap();
cover_art.data = simodels::coverart::io::to_data(&cover_art).unwrap();
let members = UploadSongMembers {
song: s,
coverart: cover_art,
token,
token: token.clone(),
album,
};
@@ -459,44 +432,37 @@ impl CommitManager {
println!("Queued coverart Id: {id:?}");
println!("Linked queued song to queued coverart");
println!("Queued status updated");
Ok(())
}
Err(err) => {
return Err(std::io::Error::other(err.to_string()));
}
Err(err) => Err(std::io::Error::other(err.to_string())),
},
Err(err) => {
return Err(std::io::Error::other(err.to_string()));
}
Err(err) => Err(std::io::Error::other(err.to_string())),
},
Err(err) => {
return Err(std::io::Error::other(err.to_string()));
}
Err(err) => Err(std::io::Error::other(err.to_string())),
}
Ok(())
}
fn get_songs(
&self,
metadata_path: &String,
source_directory: &str,
) -> Result<Vec<icarus_models::song::Song>> {
match icarus_models::album::collection::parse_album(metadata_path) {
) -> Result<Vec<simodels::song::Song>> {
match simodels::album::collection::parse_album(metadata_path) {
Ok(albums) => {
let mut songs: Vec<icarus_models::song::Song> = Vec::new();
let mut songs: Vec<simodels::song::Song> = Vec::new();
for track in &albums.tracks {
let song_filename = if track.track < 10 {
"track0".to_owned()
+ &track.track.to_string()
+ icarus_models::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
+ simodels::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
} else {
"track".to_owned()
+ &track.track.to_string()
+ icarus_models::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
+ simodels::constants::file_extensions::audio::DEFAULTMUSICEXTENSION
};
songs.push(icarus_models::song::Song {
songs.push(simodels::song::Song {
title: track.title.clone(),
artist: track.artist.clone(),
disc: track.disc,
@@ -516,20 +482,15 @@ impl CommitManager {
}
Ok(songs)
}
Err(_) => Ok(Vec::new()),
Err(_) => Err(std::io::Error::other("Songs not retrieved")),
}
}
async fn multi_target_upload(&mut self, sourcepath: &String) -> std::io::Result<()> {
let mut prsr = parsers::api_parser::APIParser {
apis: vec![models::api::Api::default(), models::api::Api::default()],
ica_act: self.ica_action.clone(),
};
prsr.parse_api(parsers::api_parser::APIType::Main);
prsr.parse_api(parsers::api_parser::APIType::Auth);
let auth_api = prsr.retrieve_api(parsers::api_parser::APIType::Auth);
let token = self.parse_token(&auth_api).await;
async fn multi_target_upload(
&mut self,
sourcepath: &String,
token: &simodels::token::AccessToken,
) -> std::io::Result<()> {
let directory_path = std::path::Path::new(&sourcepath);
if !directory_path.exists() {
@@ -538,7 +499,7 @@ impl CommitManager {
let (coverart_directory, coverart_filename) =
self.get_coverart_dir_and_filename(sourcepath).unwrap();
let mut cover_art = icarus_models::coverart::init::init_coverart_dir_and_filename(
let mut cover_art = simodels::coverart::init::init_coverart_dir_and_filename(
&coverart_directory,
&coverart_filename,
);
@@ -548,10 +509,10 @@ impl CommitManager {
let host = self.ica_action.retrieve_flag_value(&String::from("-h"));
up.set_api(&host);
cover_art.data = icarus_models::coverart::io::to_data(&cover_art).unwrap();
cover_art.data = simodels::coverart::io::to_data(&cover_art).unwrap();
match self.get_songs(&metadatapath, sourcepath) {
Ok(sngs) => match icarus_models::album::collection::parse_album(&metadatapath) {
Ok(sngs) => match simodels::album::collection::parse_album(&metadatapath) {
Ok(album) => {
for song in sngs {
let members = UploadSongMembers {
@@ -566,7 +527,7 @@ impl CommitManager {
println!("Response: {o:?}");
}
Err(err) => {
println!("Error: {err:?}");
eprintln!("Error: {err:?}");
return Err(err);
}
}
@@ -575,12 +536,12 @@ impl CommitManager {
Ok(())
}
Err(err) => {
println!("Error: {err:?}");
eprintln!("Error: {err:?}");
Err(std::io::Error::other(err.to_string()))
}
},
Err(error) => {
println!("Error: {error:?}");
eprintln!("Error: {error:?}");
Err(std::io::Error::other(error.to_string()))
}
}
@@ -602,7 +563,9 @@ impl CommitManager {
}
}
Ok((String::new(), String::new()))
Err(std::io::Error::other(
"CoverArt directory and filename not found",
))
}
fn find_file_extension(&self, file_name: &std::ffi::OsString) -> En {
@@ -630,15 +593,14 @@ impl CommitManager {
index += 1;
}
if extension == icarus_models::constants::file_extensions::audio::WAVEXTENSION[1..]
|| extension
== icarus_models::constants::file_extensions::audio::FLACEXTENSION[1..]
if extension == simodels::constants::file_extensions::audio::WAVEXTENSION[1..]
|| extension == simodels::constants::file_extensions::audio::FLACEXTENSION[1..]
{
return En::SongFile;
} else if extension == "json" {
return En::MetadataFile;
} else if extension
== icarus_models::constants::file_extensions::image::JPGEXTENSION[1..]
== simodels::constants::file_extensions::image::JPGEXTENSION[1..]
|| extension == "jpeg"
|| extension == "png"
{
@@ -670,15 +632,6 @@ impl CommitManager {
}
}
Ok(String::new())
}
fn _check_for_no_confirm(&self) -> bool {
for flag in self.ica_action.flags.iter() {
if flag.flag == "-nc" {
return true;
}
}
false
Err(std::io::Error::other("Metadata path not found"))
}
}
+10 -17
View File
@@ -7,23 +7,22 @@ mod response {
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct Response {
pub message: String,
pub data: Vec<icarus_models::login_result::LoginResult>,
pub data: Vec<simodels::login_result::LoginResult>,
}
}
}
pub struct TokenManager {
pub user: icarus_models::user::User,
pub user: simodels::user::User,
pub api: models::api::Api,
}
impl Default for TokenManager {
fn default() -> Self {
let mut token = TokenManager {
user: icarus_models::user::User::default(),
user: simodels::user::User::default(),
api: models::api::Api::default(),
};
token.init();
token
@@ -31,14 +30,13 @@ impl Default for TokenManager {
}
impl TokenManager {
pub async fn request_token(&self) -> Result<icarus_models::token::AccessToken, std::io::Error> {
pub async fn request_token(&self) -> Result<simodels::token::AccessToken, std::io::Error> {
println!("Sending request for a token");
let url = self.retrieve_url();
println!("URL: {url}");
let mut token = icarus_models::token::AccessToken {
let mut token = simodels::token::AccessToken {
user_id: uuid::Uuid::nil(),
username: String::new(),
token: String::new(),
@@ -62,19 +60,18 @@ impl TokenManager {
token.token_type = login_result.token_type.clone();
token.expiration = login_result.expiration;
token.message = response.message;
Ok(token)
}
Err(_) => println!("Hm, the response didn't match the shape we expected."),
};
Err(err) => Err(std::io::Error::other(err.to_string())),
}
}
reqwest::StatusCode::UNAUTHORIZED => {
println!("Need to grab a new token");
Err(std::io::Error::other("Need to grab a new token"))
}
other => {
panic!("Uh oh! Something unexpected happened: {other:?}");
}
}
Ok(token)
}
pub fn init(&mut self) {
@@ -84,10 +81,6 @@ impl TokenManager {
}
pub fn retrieve_url(&self) -> String {
let api = &self.api;
let mut url = String::from(&api.url);
url += &String::from(&api.endpoint);
url
format!("{}{}", self.api.url, self.api.endpoint)
}
}
+3 -5
View File
@@ -1,17 +1,15 @@
use std::default::Default;
use serde::{Deserialize, Serialize};
use crate::models::{self};
#[derive(Debug, Default, Deserialize, Serialize)]
#[derive(Debug, Default)]
pub struct UserManager {
pub user: icarus_models::user::User,
pub user: simodels::user::User,
pub ica_action: models::icarus_action::IcarusAction,
}
impl UserManager {
pub fn retrieve_user(&self) -> icarus_models::user::User {
pub fn retrieve_user(&self) -> simodels::user::User {
self.user.clone()
}
+1 -3
View File
@@ -1,8 +1,6 @@
use std::default::Default;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[derive(Clone, Debug, Default)]
pub struct Api {
pub url: String,
pub endpoint: String,
+1 -3
View File
@@ -1,8 +1,6 @@
use std::default::Default;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[derive(Clone, Debug, Default)]
pub struct Flags {
pub flag: String,
pub value: String,
+1 -3
View File
@@ -1,10 +1,8 @@
use std::default::Default;
use serde::{Deserialize, Serialize};
use crate::models;
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[derive(Clone, Debug, Default)]
pub struct IcarusAction {
pub action: String,
pub flags: Vec<models::flags::Flags>,
+8 -12
View File
@@ -9,22 +9,18 @@ pub fn retrieve_url(api: &models::api::Api, with_id: bool, id: &uuid::Uuid) -> S
}
fn retrieve_url_reg(api: &models::api::Api) -> String {
let url = format!("{}api/{}/{}/", api.url, api.version, api.endpoint);
url
format!("{}api/{}/{}/", api.url, api.version, api.endpoint)
}
fn retrieve_url_with_id(api: &models::api::Api, id: &uuid::Uuid) -> String {
let url = format!("{}api/{}/{}/{}", api.url, api.version, api.endpoint, id);
url
format!("{}api/{}/{}/{}", api.url, api.version, api.endpoint, id)
}
pub async fn auth_header(
token: &icarus_models::token::AccessToken,
) -> (http::HeaderName, http::HeaderValue) {
let auth = reqwest::header::AUTHORIZATION;
let auth_value = http::HeaderValue::from_str(&token.bearer_token()).unwrap();
(auth, auth_value)
token: &simodels::token::AccessToken,
) -> Result<(http::HeaderName, http::HeaderValue), http::header::InvalidHeaderValue> {
match http::HeaderValue::from_str(&token.bearer_token()) {
Ok(auth_value) => Ok((reqwest::header::AUTHORIZATION, auth_value)),
Err(err) => Err(err),
}
}
+5 -6
View File
@@ -13,8 +13,8 @@ mod response {
pub mod delete_song {
#[derive(Debug, serde::Deserialize)]
pub struct SongAndCoverArt {
pub song: icarus_models::song::Song,
pub coverart: icarus_models::coverart::CoverArt,
pub song: simodels::song::Song,
pub coverart: simodels::coverart::CoverArt,
}
#[derive(Debug, serde::Deserialize)]
@@ -28,10 +28,9 @@ mod response {
impl Delete {
pub async fn delete_song(
&mut self,
token: &icarus_models::token::AccessToken,
song: &icarus_models::song::Song,
) -> Result<(icarus_models::song::Song, icarus_models::coverart::CoverArt), std::io::Error>
{
token: &simodels::token::AccessToken,
song: &simodels::song::Song,
) -> Result<(simodels::song::Song, simodels::coverart::CoverArt), std::io::Error> {
self.api.endpoint = "api/v2/song".to_owned();
let url = format!("{}{}/{}", self.api.url, self.api.endpoint, song.id);
println!("Url: {url:?}");
+2 -2
View File
@@ -17,8 +17,8 @@ pub enum MyError {
impl Download {
pub async fn download_song(
&mut self,
token: &icarus_models::token::AccessToken,
song: &icarus_models::song::Song,
token: &simodels::token::AccessToken,
song: &simodels::song::Song,
) -> Result<String, MyError> {
self.api.endpoint = String::from("song/download");
let url = syncers::common::retrieve_url(&self.api, true, &song.id);
+3 -3
View File
@@ -13,7 +13,7 @@ mod response {
#[derive(Debug, serde::Deserialize)]
pub struct Response {
pub message: String,
pub data: Vec<icarus_models::song::Song>,
pub data: Vec<simodels::song::Song>,
}
}
}
@@ -21,8 +21,8 @@ mod response {
impl RetrieveRecords {
pub async fn get_all_songs(
&mut self,
token: &icarus_models::token::AccessToken,
) -> Result<Vec<icarus_models::song::Song>, Error> {
token: &simodels::token::AccessToken,
) -> Result<Vec<simodels::song::Song>, Error> {
self.api.endpoint = String::from("api/v2/song/all");
let url = format!("{}{}", self.api.url, self.api.endpoint);
let access_token = token.bearer_token();
+16 -16
View File
@@ -40,8 +40,8 @@ mod response {
impl Upload {
pub async fn queue_song(
&self,
token: &icarus_models::token::AccessToken,
song: &icarus_models::song::Song,
token: &simodels::token::AccessToken,
song: &simodels::song::Song,
) -> Result<uuid::Uuid, reqwest::Error> {
let songpath = song.song_path().unwrap();
let file = tokio::fs::File::open(&songpath).await.unwrap();
@@ -61,7 +61,7 @@ impl Upload {
println!("Url: {url:?}");
let mut headers = reqwest::header::HeaderMap::new();
let (auth, auth_val) = syncers::common::auth_header(token).await;
let (auth, auth_val) = syncers::common::auth_header(token).await.unwrap();
headers.insert(auth, auth_val);
headers.insert("Accept", HeaderValue::from_str("*/*").unwrap());
headers.insert("Connection", HeaderValue::from_str("keep-alive").unwrap());
@@ -92,14 +92,14 @@ impl Upload {
pub async fn link_user_to_queued_song(
&self,
token: &icarus_models::token::AccessToken,
token: &simodels::token::AccessToken,
queued_song_id: &uuid::Uuid,
) -> Result<(), reqwest::Error> {
let endpoint = String::from("api/v2/song/queue/link");
let url = format!("{}/{endpoint}", self.api.url);
let mut headers = reqwest::header::HeaderMap::new();
let (auth, auth_val) = syncers::common::auth_header(token).await;
let (auth, auth_val) = syncers::common::auth_header(token).await.unwrap();
headers.insert(auth, auth_val);
let payload = serde_json::json!({
@@ -123,16 +123,16 @@ impl Upload {
pub async fn queue_metadata(
&self,
token: &icarus_models::token::AccessToken,
album: &icarus_models::album::collection::Album,
song: &icarus_models::song::Song,
token: &simodels::token::AccessToken,
album: &simodels::album::collection::Album,
song: &simodels::song::Song,
queued_song_id: &uuid::Uuid,
) -> Result<uuid::Uuid, reqwest::Error> {
let endpoint = String::from("api/v2/song/metadata/queue");
let url = format!("{}/{endpoint}", self.api.url);
let mut headers = reqwest::header::HeaderMap::new();
let (auth, auth_val) = syncers::common::auth_header(token).await;
let (auth, auth_val) = syncers::common::auth_header(token).await.unwrap();
headers.insert(auth, auth_val);
let payload = serde_json::json!({
@@ -173,8 +173,8 @@ impl Upload {
pub async fn queue_coverart(
&self,
token: &icarus_models::token::AccessToken,
coverart: &icarus_models::coverart::CoverArt,
token: &simodels::token::AccessToken,
coverart: &simodels::coverart::CoverArt,
) -> Result<uuid::Uuid, reqwest::Error> {
let coverartpath = coverart.get_path().unwrap();
let file = tokio::fs::File::open(&coverartpath).await.unwrap();
@@ -200,7 +200,7 @@ impl Upload {
println!("Url: {url:?}");
let mut headers = reqwest::header::HeaderMap::new();
let (auth, auth_val) = syncers::common::auth_header(token).await;
let (auth, auth_val) = syncers::common::auth_header(token).await.unwrap();
headers.insert(auth, auth_val);
headers.insert("Accept", HeaderValue::from_str("*/*").unwrap());
headers.insert("Connection", HeaderValue::from_str("keep-alive").unwrap());
@@ -231,7 +231,7 @@ impl Upload {
pub async fn link_queued_song_to_queued_coverart(
&self,
token: &icarus_models::token::AccessToken,
token: &simodels::token::AccessToken,
queued_song_id: &uuid::Uuid,
queued_coverart_id: &uuid::Uuid,
) -> Result<(), reqwest::Error> {
@@ -239,7 +239,7 @@ impl Upload {
let url = format!("{}/{endpoint}", self.api.url);
let mut headers = reqwest::header::HeaderMap::new();
let (auth, auth_val) = syncers::common::auth_header(token).await;
let (auth, auth_val) = syncers::common::auth_header(token).await.unwrap();
headers.insert(auth, auth_val);
let payload = serde_json::json!({
@@ -263,7 +263,7 @@ impl Upload {
pub async fn update_queued_song_status(
&self,
token: &icarus_models::token::AccessToken,
token: &simodels::token::AccessToken,
queued_song_id: &uuid::Uuid,
status: &str,
) -> Result<(), reqwest::Error> {
@@ -271,7 +271,7 @@ impl Upload {
let url = format!("{}/{endpoint}", self.api.url);
let mut headers = reqwest::header::HeaderMap::new();
let (auth, auth_val) = syncers::common::auth_header(token).await;
let (auth, auth_val) = syncers::common::auth_header(token).await.unwrap();
headers.insert(auth, auth_val);
let payload = serde_json::json!({
+7 -1
View File
@@ -1,6 +1,12 @@
pub fn o_to_string(val: &std::ffi::OsString) -> Result<std::string::String, std::io::Error> {
match val.clone().into_string() {
Ok(value) => Ok(value),
Err(_) => Err(std::io::Error::other(String::from("Error"))),
Err(err) => match err.into_string() {
Ok(res) => Err(std::io::Error::other(res.to_string())),
Err(err) => match err.to_str() {
Some(err) => Err(std::io::Error::other(err)),
None => Err(std::io::Error::other("Undefined error")),
},
},
}
}