Added more multi-upload code
This commit is contained in:
+2
-1
@@ -10,9 +10,10 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = { version = "0.3.30" }
|
futures = { version = "0.3.30" }
|
||||||
reqwest = { version = "0.12.4", features = ["json", "blocking"] }
|
reqwest = { version = "0.12.4", features = ["json", "blocking", "multipart", "stream"] }
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
serde_json = "1.0.115"
|
serde_json = "1.0.115"
|
||||||
tokio = { version = "1.37", features = ["full"] }
|
tokio = { version = "1.37", features = ["full"] }
|
||||||
|
tokio-util = { version = "0.7.11", features = ["codec"] }
|
||||||
# rodio = "0.17.3"
|
# rodio = "0.17.3"
|
||||||
# metadata = "0.1.8"
|
# metadata = "0.1.8"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use crate::models;
|
use crate::models;
|
||||||
|
use crate::models::song::Album;
|
||||||
use crate::parsers;
|
use crate::parsers;
|
||||||
use crate::syncers;
|
use crate::syncers;
|
||||||
use crate::utilities;
|
use crate::utilities;
|
||||||
@@ -20,30 +21,6 @@ pub struct CommitManager {
|
|||||||
pub ica_action: models::icarus_action::IcarusAction,
|
pub ica_action: models::icarus_action::IcarusAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
pub struct Album {
|
|
||||||
pub title: String,
|
|
||||||
pub album_artist: String,
|
|
||||||
pub genre: String,
|
|
||||||
pub year: i32,
|
|
||||||
pub track_count: i32,
|
|
||||||
pub disc_count: i32,
|
|
||||||
pub songs: Vec<models::song::Song>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Album {
|
|
||||||
fn default() -> Self {
|
|
||||||
Album {
|
|
||||||
title: String::new(),
|
|
||||||
album_artist: String::new(),
|
|
||||||
genre: String::new(),
|
|
||||||
year: 0,
|
|
||||||
track_count: 0,
|
|
||||||
disc_count: 0,
|
|
||||||
songs: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum ActionValues {
|
enum ActionValues {
|
||||||
@@ -264,6 +241,7 @@ impl CommitManager {
|
|||||||
|
|
||||||
let mut cover_art = models::song::CoverArt::default();
|
let mut cover_art = models::song::CoverArt::default();
|
||||||
let mut songs: Vec<models::song::Song> = Vec::new();
|
let mut songs: Vec<models::song::Song> = Vec::new();
|
||||||
|
let mut filenames: Vec<String> = Vec::new();
|
||||||
let mut metadatapath: String = String::new();
|
let mut metadatapath: String = String::new();
|
||||||
|
|
||||||
// iterate files in metadatapath
|
// iterate files in metadatapath
|
||||||
@@ -298,10 +276,16 @@ impl CommitManager {
|
|||||||
En::SongFile => {
|
En::SongFile => {
|
||||||
let mut song = models::song::Song::default();
|
let mut song = models::song::Song::default();
|
||||||
let fname = self.o_to_string(&file_name);
|
let fname = self.o_to_string(&file_name);
|
||||||
song.filepath = Some(fname.unwrap());
|
|
||||||
song.directory = Some(sourcepath.clone());
|
match fname {
|
||||||
// song.filepath = Some(
|
Ok(s) => {
|
||||||
self.initialize_disc_and_track(&mut song);
|
filenames.push(s.clone());
|
||||||
|
song.filepath = Some(s.clone());
|
||||||
|
song.directory = Some(sourcepath.clone());
|
||||||
|
self.initialize_disc_and_track(&mut song);
|
||||||
|
},
|
||||||
|
Err(er) => println!("Error: {:?}", er),
|
||||||
|
}
|
||||||
|
|
||||||
songs.push(song)
|
songs.push(song)
|
||||||
}
|
}
|
||||||
@@ -309,22 +293,74 @@ impl CommitManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let album = self.retrieve_metadata(&metadatapath);
|
let mut album = self.retrieve_metadata(&metadatapath);
|
||||||
songs.clear();
|
|
||||||
songs = album.songs.clone();
|
self.song_parsing(&mut album, &sourcepath, &filenames);
|
||||||
|
|
||||||
|
// songs.clear();
|
||||||
|
// songs = album.songs;
|
||||||
|
|
||||||
let mut up = syncers::upload::Upload::default();
|
let mut up = syncers::upload::Upload::default();
|
||||||
|
let host = self.ica_action.retrieve_flag_value(&String::from("-h"));
|
||||||
|
up.set_api(&host);
|
||||||
|
|
||||||
for _ in songs {
|
for song in &album.songs {
|
||||||
// Upload each song
|
// Upload each song
|
||||||
// TODO: Add functions to Upload struct that uploads song
|
// TODO: Add functions to Upload struct that uploads song
|
||||||
// with metadata and img
|
// with metadata and img
|
||||||
|
up.upload_song_with_metadata(&token, &song, &cover_art, &album);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement
|
|
||||||
|
// Makes sure the elements in album.songs is populated
|
||||||
|
fn song_parsing(&self, album: &mut models::song::Album, directory: &String, filenames: &Vec<String>) {
|
||||||
|
// Apply directory
|
||||||
|
for song in &mut album.songs {
|
||||||
|
// let bor = song.as_mut();
|
||||||
|
let mut dir = &song.directory;
|
||||||
|
match dir {
|
||||||
|
Some(s) => println!("{}", s),
|
||||||
|
None => {
|
||||||
|
song.directory = Some(directory.clone());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply filename
|
||||||
|
let mut index = 0;
|
||||||
|
for song in &mut album.songs {
|
||||||
|
let filename = filenames[index].clone();
|
||||||
|
song.filepath = Some(filename);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for song in &mut album.songs {
|
||||||
|
match &mut song.album {
|
||||||
|
Some(_) => {},
|
||||||
|
None => {
|
||||||
|
song.album = Some(album.title.clone());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
match &mut song.genre {
|
||||||
|
Some(_) => {},
|
||||||
|
None => {
|
||||||
|
song.genre = Some(album.genre.clone());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
match &mut song.year {
|
||||||
|
Some(_) => {},
|
||||||
|
None => {
|
||||||
|
song.year = Some(album.year.clone());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn find_file_extension(&self, file_name: &std::ffi::OsString) -> En {
|
fn find_file_extension(&self, file_name: &std::ffi::OsString) -> En {
|
||||||
let file_name_str = Some(file_name.clone().into_string());
|
let file_name_str = Some(file_name.clone().into_string());
|
||||||
|
|
||||||
@@ -528,26 +564,19 @@ impl CommitManager {
|
|||||||
|
|
||||||
let content = self.retrieve_file_content(&path);
|
let content = self.retrieve_file_content(&path);
|
||||||
// let alb = serde_json::from_str(&content.unwrap());
|
// let alb = serde_json::from_str(&content.unwrap());
|
||||||
|
let val = content.unwrap();
|
||||||
/*
|
|
||||||
let mut file: std::fs::File = std::fs::File::open(filepath).unwrap();
|
|
||||||
let mut data = String::new();
|
|
||||||
file.read_to_string(&mut data).unwrap();
|
|
||||||
|
|
||||||
return serde_json::from_str(&data).unwrap();
|
|
||||||
*/
|
|
||||||
|
|
||||||
// return alb.unwrap();
|
// return alb.unwrap();
|
||||||
return serde_json::from_str(&content.unwrap()).unwrap();
|
let converted = serde_json::from_str(&val);
|
||||||
|
|
||||||
|
match &converted {
|
||||||
|
Ok(res) => println!("Good!"),
|
||||||
|
Err(er) => println!("Error {:?}", er),
|
||||||
|
}
|
||||||
|
return converted.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retrieve_file_content(&self, path: &String) -> Result<String> {
|
fn retrieve_file_content(&self, path: &String) -> Result<String> {
|
||||||
/*
|
|
||||||
let mut file = File::open(path)?;
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
file.read_to_end(&mut buffer)?;
|
|
||||||
*/
|
|
||||||
|
|
||||||
return std::fs::read_to_string(path);
|
return std::fs::read_to_string(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -20,6 +21,33 @@ pub struct Song {
|
|||||||
pub directory: Option<String>,
|
pub directory: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct Album {
|
||||||
|
#[serde(alias = "album")]
|
||||||
|
pub title: String,
|
||||||
|
pub album_artist: String,
|
||||||
|
pub genre: String,
|
||||||
|
pub year: i32,
|
||||||
|
pub track_count: i32,
|
||||||
|
pub disc_count: i32,
|
||||||
|
#[serde(alias = "tracks")]
|
||||||
|
pub songs: Vec<Song>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Album {
|
||||||
|
fn default() -> Self {
|
||||||
|
Album {
|
||||||
|
title: String::new(),
|
||||||
|
album_artist: String::new(),
|
||||||
|
genre: String::new(),
|
||||||
|
year: 0,
|
||||||
|
track_count: 0,
|
||||||
|
disc_count: 0,
|
||||||
|
songs: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Song {
|
impl Default for Song {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Song {
|
Song {
|
||||||
@@ -62,6 +90,15 @@ impl Song {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_data(&self) -> Result<Vec<u8>, std::io::Error> {
|
||||||
|
let path = self.song_path();
|
||||||
|
// let content = std::fs::read_to_string(path);
|
||||||
|
let mut file = std::fs::File::open(path)?;
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
file.read(&mut buffer)?;
|
||||||
|
Ok(buffer)
|
||||||
|
// return content;
|
||||||
|
}
|
||||||
// if 1 - wav, if 0 - mp3, anything else defaults to wav
|
// if 1 - wav, if 0 - mp3, anything else defaults to wav
|
||||||
pub fn generate_filename_from_track(&mut self, i_type: i32) -> i32 {
|
pub fn generate_filename_from_track(&mut self, i_type: i32) -> i32 {
|
||||||
let mut filename: String = String::new();
|
let mut filename: String = String::new();
|
||||||
@@ -103,3 +140,22 @@ impl Default for CoverArt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CoverArt {
|
||||||
|
pub fn to_data(&self) -> Result<Vec<u8>, std::io::Error> {
|
||||||
|
let mut path: String = String::new();
|
||||||
|
match &self.path {
|
||||||
|
Some(val) => {
|
||||||
|
path = String::from(val);
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut file = std::fs::File::open(path)?;
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
file.read(&mut buffer)?;
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
+112
-4
@@ -1,7 +1,13 @@
|
|||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
||||||
|
use reqwest::blocking::multipart;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use reqwest;
|
use reqwest;
|
||||||
|
// use reqwest::blocking::
|
||||||
|
use reqwest::{Body, Client};
|
||||||
|
use reqwest::multipart::{Form, Part};
|
||||||
use reqwest::Response;
|
use reqwest::Response;
|
||||||
|
use tokio::fs::File;
|
||||||
|
|
||||||
use crate::models;
|
use crate::models;
|
||||||
|
|
||||||
@@ -9,6 +15,22 @@ pub struct Upload {
|
|||||||
pub api: models::api::API,
|
pub api: models::api::API,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
struct Song {
|
||||||
|
title: String,
|
||||||
|
album: String,
|
||||||
|
artist: String,
|
||||||
|
album_artist: String,
|
||||||
|
year: i32,
|
||||||
|
genre: String,
|
||||||
|
duration: f64,
|
||||||
|
track: i32,
|
||||||
|
track_count: i32,
|
||||||
|
disc: i32,
|
||||||
|
disc_count: i32,
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Upload {
|
impl Default for Upload {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Upload {
|
Upload {
|
||||||
@@ -39,17 +61,103 @@ impl Upload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Implement
|
||||||
|
pub async fn upload_song_with_metadata(&mut self, token: &models::token::Token, song: &models::song::Song,
|
||||||
|
cover: &models::song::CoverArt, album: &models::song::Album) {
|
||||||
|
self.api.endpoint = String::from("song/data/upload/with/data");
|
||||||
|
let url = self.retrieve_url(&song);
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let new_song = self.initialize_song(&song, &album);
|
||||||
|
let access_token = token.bearer_token();
|
||||||
|
|
||||||
|
let song_data = song.to_data();
|
||||||
|
let cover_data = cover.to_data();
|
||||||
|
|
||||||
|
match song_data {
|
||||||
|
Ok(sd) => {
|
||||||
|
},
|
||||||
|
Err(er) => {
|
||||||
|
println!("Error: {:?}", er);
|
||||||
|
std::process::exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match cover_data {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(er) => {
|
||||||
|
println!("Error: {:?}", er);
|
||||||
|
std::process::exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if url.is_empty() {
|
||||||
|
println!("Url is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
let s_file = std::fs::File::open(song.song_path());
|
||||||
|
let s_stream = tokio_util::codec::FramedRead::new(s_file, tokio_util::codec::BytesCodec::new());
|
||||||
|
let s_file_body = Body::wrap_stream(s_stream);
|
||||||
|
let s_some_file = multipart::Part::stream(s_file_body)
|
||||||
|
.file_name("track.cdda.wav");
|
||||||
|
|
||||||
|
let s_data = Part::file(song.song_path());
|
||||||
|
let c_data = multipart::Part::stream(&cover.path);
|
||||||
|
|
||||||
|
let mut form = Form::new();
|
||||||
|
let meta = serde_json::to_string_pretty(&new_song);
|
||||||
|
form = form.text("metadata", meta.unwrap());
|
||||||
|
|
||||||
|
form = form.part("file", s_some_file)
|
||||||
|
.part("cover", c_data);
|
||||||
|
|
||||||
|
let response = client.post(url).multipart(form).send();
|
||||||
|
let result = response.text;
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn set_api(&mut self, host: &String) {
|
||||||
|
let mut api = models::api::API::default();
|
||||||
|
api.url = host.clone();
|
||||||
|
api.version = String::from("v1");
|
||||||
|
self.api = api;
|
||||||
|
}
|
||||||
fn retrieve_url(&self, song: &models::song::Song) -> String {
|
fn retrieve_url(&self, song: &models::song::Song) -> String {
|
||||||
// let mut url: String = String::new();
|
|
||||||
let api = &self.api;
|
let api = &self.api;
|
||||||
let mut url: String = String::from(&api.url);
|
let mut buffer = api.url.clone();
|
||||||
|
let count = buffer.len();
|
||||||
|
|
||||||
|
if buffer.chars().nth(count - 1) != Some('/') {
|
||||||
|
buffer += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut url: String = String::from(&buffer);
|
||||||
url += &String::from("api/");
|
url += &String::from("api/");
|
||||||
url += &String::from(&api.version);
|
url += &String::from(&api.version);
|
||||||
url += &String::from("/");
|
url += &String::from("/");
|
||||||
url += &String::from(&api.endpoint);
|
url += &String::from(&api.endpoint);
|
||||||
// url += &String::from("/");
|
|
||||||
// url += &song.id.unwrap().to_string();
|
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn initialize_song(&self, song: &models::song::Song, album: &models::song::Album) -> Song {
|
||||||
|
return Song {
|
||||||
|
title: String::from(&song.title.clone().unwrap()),
|
||||||
|
album: album.title.clone(),
|
||||||
|
artist: String::from(&song.artist.clone().unwrap().clone()),
|
||||||
|
album_artist: album.album_artist.clone(),
|
||||||
|
year: album.year.clone(),
|
||||||
|
genre: album.genre.clone(),
|
||||||
|
duration: song.duration.clone().unwrap(),
|
||||||
|
track: (song.track.clone().unwrap()),
|
||||||
|
track_count: album.track_count.clone(),
|
||||||
|
disc: song.disc.clone().unwrap(),
|
||||||
|
disc_count: album.disc_count.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user