Lint code

This commit is contained in:
oSumAtrIX 2021-10-18 04:29:23 +02:00
parent e81e0da7e6
commit 7a86351998
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
5 changed files with 900 additions and 909 deletions

View file

@ -7,7 +7,7 @@ use crate::error::SpotifyError::{LameConverterError, InvalidFormat};
/// Converts audio to MP3 /// Converts audio to MP3
pub enum AudioConverter { pub enum AudioConverter {
OGG { Ogg {
decoder: OggStreamReader<ReadWrap>, decoder: OggStreamReader<ReadWrap>,
lame: lame::Lame, lame: lame::Lame,
lame_end: bool, lame_end: bool,
@ -48,10 +48,10 @@ impl AudioConverter {
}; };
match format { match format {
AudioFormat::AAC => todo!(), AudioFormat::Aac => todo!(),
AudioFormat::MP4 => todo!(), AudioFormat::Mp4 => todo!(),
// Lewton decoder // Lewton decoder
AudioFormat::OGG => { AudioFormat::Ogg => {
let decoder = OggStreamReader::new(ReadWrap::new(Box::new(read)))?; let decoder = OggStreamReader::new(ReadWrap::new(Box::new(read)))?;
let sample_rate = decoder.ident_hdr.audio_sample_rate; let sample_rate = decoder.ident_hdr.audio_sample_rate;
// Init lame // Init lame
@ -64,13 +64,13 @@ impl AudioConverter {
Err(_) => return Err(LameConverterError("Init".to_string())) Err(_) => return Err(LameConverterError("Init".to_string()))
}; };
Ok(AudioConverter::OGG { Ok(AudioConverter::Ogg {
lame, lame,
decoder, decoder,
lame_end: false, lame_end: false,
}) })
} }
AudioFormat::MP3 => panic!("No reencoding allowd!"), AudioFormat::Mp3 => panic!("No reencoding allowd!"),
_ => Err(InvalidFormat), _ => Err(InvalidFormat),
} }
} }
@ -79,7 +79,7 @@ impl AudioConverter {
impl Read for AudioConverter { impl Read for AudioConverter {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self { match self {
AudioConverter::OGG { AudioConverter::Ogg {
decoder, decoder,
lame, lame,
lame_end, lame_end,

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
use aspotify::{ use aspotify::{
Album, Client, ClientCredentials, Playlist, PlaylistItemType, Track, TrackSimplified, Artist Album, Artist, Client, ClientCredentials, Playlist, PlaylistItemType, Track, TrackSimplified,
}; };
use librespot::core::authentication::Credentials; use librespot::core::authentication::Credentials;
use librespot::core::config::SessionConfig; use librespot::core::config::SessionConfig;
@ -10,191 +10,183 @@ use url::Url;
use crate::error::SpotifyError; use crate::error::SpotifyError;
pub struct Spotify { pub struct Spotify {
// librespotify sessopm // librespotify sessopm
pub session: Session, pub session: Session,
pub spotify: Client, pub spotify: Client,
} }
impl Spotify { impl Spotify {
/// Create new instance
pub async fn new(
username: &str,
password: &str,
client_id: &str,
client_secret: &str,
) -> Result<Spotify, SpotifyError> {
// librespot
let credentials = Credentials::with_password(username, password);
let session = Session::connect(SessionConfig::default(), credentials, None).await?;
//aspotify
let credentials = ClientCredentials {
id: client_id.to_string(),
secret: client_secret.to_string(),
};
let spotify = Client::new(credentials);
/// Create new instance Ok(Spotify { session, spotify })
pub async fn new( }
username: &str,
password: &str,
client_id: &str,
client_secret: &str,
) -> Result<Spotify, SpotifyError> {
// librespot
let credentials = Credentials::with_password(username, password);
let session = Session::connect(SessionConfig::default(), credentials, None).await?;
//aspotify
let credentials = ClientCredentials {
id: client_id.to_string(),
secret: client_secret.to_string(),
};
let spotify = Client::new(credentials);
Ok(Spotify { session, spotify }) /// Parse URI or URL into URI
} pub fn parse_uri(uri: &str) -> Result<String, SpotifyError> {
// Already URI
if uri.starts_with("spotify:") {
if uri.split(':').count() < 3 {
return Err(SpotifyError::InvalidUri);
}
return Ok(uri.to_string());
}
/// Parse URI or URL into URI // Parse URL
pub fn parse_uri(uri: &str) -> Result<String, SpotifyError> { let url = Url::parse(uri)?;
// Already URI // Spotify Web Player URL
if uri.starts_with("spotify:") { if url.host_str() == Some("open.spotify.com") {
if uri.split(':').collect::<Vec<&str>>().len() < 3 { let path = url
return Err(SpotifyError::InvalidUri); .path_segments()
} .ok_or_else(|| SpotifyError::Error("Missing URL path".into()))?
return Ok(uri.to_string()); .collect::<Vec<&str>>();
} if path.len() < 2 {
return Err(SpotifyError::InvalidUri);
}
return Ok(format!("spotify:{}:{}", path[0], path[1]));
}
Err(SpotifyError::InvalidUri)
}
// Parse URL /// Fetch data for URI
let url = Url::parse(uri)?; pub async fn resolve_uri(&self, uri: &str) -> Result<SpotifyItem, SpotifyError> {
// Spotify Web Player URL let parts = uri.split(':').skip(1).collect::<Vec<&str>>();
if url.host_str() == Some("open.spotify.com") { let id = parts[1];
let path = url match parts[0] {
.path_segments() "track" => {
.ok_or(SpotifyError::Error("Missing URL path".into()))? let track = self.spotify.tracks().get_track(id, None).await?;
.collect::<Vec<&str>>(); Ok(SpotifyItem::Track(track.data))
if path.len() < 2 { }
return Err(SpotifyError::InvalidUri); "playlist" => {
} let playlist = self.spotify.playlists().get_playlist(id, None).await?;
return Ok(format!("spotify:{}:{}", path[0], path[1])); Ok(SpotifyItem::Playlist(playlist.data))
} }
Err(SpotifyError::InvalidUri) "album" => {
} let album = self.spotify.albums().get_album(id, None).await?;
Ok(SpotifyItem::Album(album.data))
}
"artist" => {
let artist = self.spotify.artists().get_artist(id).await?;
Ok(SpotifyItem::Artist(artist.data))
}
// Unsupported / Unimplemented
_ => Ok(SpotifyItem::Other(uri.to_string())),
}
}
/// Fetch data for URI /// Get all tracks from playlist
pub async fn resolve_uri(&self, uri: &str) -> Result<SpotifyItem, SpotifyError> { pub async fn full_playlist(&self, id: &str) -> Result<Vec<Track>, SpotifyError> {
let parts = uri.split(':').skip(1).collect::<Vec<&str>>(); let mut items = vec![];
let id = parts[1]; let mut offset = 0;
match parts[0] { loop {
"track" => { let page = self
let track = self.spotify.tracks().get_track(id, None).await?; .spotify
Ok(SpotifyItem::Track(track.data)) .playlists()
} .get_playlists_items(id, 100, offset, None)
"playlist" => { .await?;
let playlist = self.spotify.playlists().get_playlist(id, None).await?; items.append(
Ok(SpotifyItem::Playlist(playlist.data)) &mut page
} .data
"album" => { .items
let album = self.spotify.albums().get_album(id, None).await?; .iter()
Ok(SpotifyItem::Album(album.data)) .filter_map(|i| -> Option<Track> {
} if let Some(PlaylistItemType::Track(t)) = &i.item {
"artist" => { Some(t.to_owned())
let artist = self.spotify.artists().get_artist(id).await?; } else {
Ok(SpotifyItem::Artist(artist.data)) None
} }
// Unsupported / Unimplemented })
_ => Ok(SpotifyItem::Other(uri.to_string())), .collect(),
} );
}
/// Get all tracks from playlist // End
pub async fn full_playlist(&self, id: &str) -> Result<Vec<Track>, SpotifyError> { offset += page.data.items.len();
let mut items = vec![]; if page.data.total == offset {
let mut offset = 0; return Ok(items);
loop { }
let page = self }
.spotify }
.playlists()
.get_playlists_items(id, 100, offset, None)
.await?;
items.append(
&mut page
.data
.items
.iter()
.filter_map(|i| {
if let Some(item) = &i.item {
if let PlaylistItemType::Track(t) = item {
Some(t.to_owned())
} else {
None
}
} else {
None
}
})
.collect(),
);
// End /// Get all tracks from album
offset += page.data.items.len(); pub async fn full_album(&self, id: &str) -> Result<Vec<TrackSimplified>, SpotifyError> {
if page.data.total == offset { let mut items = vec![];
return Ok(items); let mut offset = 0;
} loop {
} let page = self
} .spotify
.albums()
.get_album_tracks(id, 50, offset, None)
.await?;
items.append(&mut page.data.items.to_vec());
/// Get all tracks from album // End
pub async fn full_album(&self, id: &str) -> Result<Vec<TrackSimplified>, SpotifyError> { offset += page.data.items.len();
let mut items = vec![]; if page.data.total == offset {
let mut offset = 0; return Ok(items);
loop { }
let page = self }
.spotify }
.albums()
.get_album_tracks(id, 50, offset, None)
.await?;
items.append(&mut page.data.items.to_vec());
// End /// Get all tracks from artist
offset += page.data.items.len(); pub async fn full_artist(&self, id: &str) -> Result<Vec<TrackSimplified>, SpotifyError> {
if page.data.total == offset { let mut items = vec![];
return Ok(items); let mut offset = 0;
} loop {
} let page = self
} .spotify
.artists()
.get_artist_albums(id, None, 50, offset, None)
.await?;
/// Get all tracks from artist for album in &mut page.data.items.iter() {
pub async fn full_artist(&self, id: &str) -> Result<Vec<TrackSimplified>, SpotifyError> { items.append(&mut self.full_album(&album.id).await?)
let mut items = vec![]; }
let mut offset = 0;
loop {
let page = self
.spotify
.artists()
.get_artist_albums(id, None, 50, offset, None)
.await?;
for album in &mut page // End
.data offset += page.data.items.len();
.items if page.data.total == offset {
.iter() { return Ok(items);
items.append(&mut self.full_album(&album.id).await?) }
} }
}
// End
offset += page.data.items.len();
if page.data.total == offset {
return Ok(items);
}
}
}
} }
impl Clone for Spotify { impl Clone for Spotify {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
session: self.session.clone(), session: self.session.clone(),
spotify: Client::new(self.spotify.credentials.clone()), spotify: Client::new(self.spotify.credentials.clone()),
} }
} }
} }
/// Basic debug implementation so can be used in other structs /// Basic debug implementation so can be used in other structs
impl fmt::Debug for Spotify { impl fmt::Debug for Spotify {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<Spotify Instance>") write!(f, "<Spotify Instance>")
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum SpotifyItem { pub enum SpotifyItem {
Track(Track), Track(Track),
Album(Album), Album(Album),
Playlist(Playlist), Playlist(Playlist),
Artist(Artist), Artist(Artist),
/// Unimplemented /// Unimplemented
Other(String), Other(String),
} }

View file

@ -5,53 +5,53 @@ use crate::downloader::AudioFormat;
use crate::error::SpotifyError; use crate::error::SpotifyError;
use self::id3::ID3Tag; use self::id3::ID3Tag;
use ogg::OGGTag; use ogg::OggTag;
mod id3; mod id3;
mod ogg; mod ogg;
pub enum TagWrap { pub enum TagWrap {
OGG(OGGTag), Ogg(OggTag),
ID3(ID3Tag), Id3(ID3Tag),
} }
impl TagWrap { impl TagWrap {
/// Load from file /// Load from file
pub fn new(path: impl AsRef<Path>, format: AudioFormat) -> Result<TagWrap, SpotifyError> { pub fn new(path: impl AsRef<Path>, format: AudioFormat) -> Result<TagWrap, SpotifyError> {
match format { match format {
AudioFormat::OGG => Ok(TagWrap::OGG(OGGTag::open(path)?)), AudioFormat::Ogg => Ok(TagWrap::Ogg(OggTag::open(path)?)),
AudioFormat::MP3 => Ok(TagWrap::ID3(ID3Tag::open(path)?)), AudioFormat::Mp3 => Ok(TagWrap::Id3(ID3Tag::open(path)?)),
_ => Err(SpotifyError::Error("Invalid format!".into())), _ => Err(SpotifyError::Error("Invalid format!".into())),
} }
} }
/// Get Tag trait /// Get Tag trait
pub fn get_tag(&mut self) -> Box<&mut dyn Tag> { pub fn get_tag(&mut self) -> Box<&mut dyn Tag> {
match self { match self {
TagWrap::OGG(tag) => Box::new(tag), TagWrap::Ogg(tag) => Box::new(tag),
TagWrap::ID3(tag) => Box::new(tag), TagWrap::Id3(tag) => Box::new(tag),
} }
} }
} }
pub trait Tag { pub trait Tag {
// Set tag values separator // Set tag values separator
fn set_separator(&mut self, separator: &str); fn set_separator(&mut self, separator: &str);
fn set_raw(&mut self, tag: &str, value: Vec<String>); fn set_raw(&mut self, tag: &str, value: Vec<String>);
fn set_field(&mut self, field: Field, value: Vec<String>); fn set_field(&mut self, field: Field, value: Vec<String>);
fn set_release_date(&mut self, date: NaiveDate); fn set_release_date(&mut self, date: NaiveDate);
fn add_cover(&mut self, mime: &str, data: Vec<u8>); fn add_cover(&mut self, mime: &str, data: Vec<u8>);
fn save(&mut self) -> Result<(), SpotifyError>; fn save(&mut self) -> Result<(), SpotifyError>;
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Field { pub enum Field {
Title, Title,
Artist, Artist,
Album, Album,
TrackNumber, TrackNumber,
DiscNumber, DiscNumber,
AlbumArtist, AlbumArtist,
Genre, Genre,
Label, Label,
} }

View file

@ -6,24 +6,24 @@ use std::path::{Path, PathBuf};
use super::Field; use super::Field;
use crate::error::SpotifyError; use crate::error::SpotifyError;
pub struct OGGTag { pub struct OggTag {
path: PathBuf, path: PathBuf,
tag: CommentHeader, tag: CommentHeader,
} }
impl OGGTag { impl OggTag {
/// Load tag from file /// Load tag from file
pub fn open(path: impl AsRef<Path>) -> Result<OGGTag, SpotifyError> { pub fn open(path: impl AsRef<Path>) -> Result<OggTag, SpotifyError> {
let mut file = File::open(&path)?; let mut file = File::open(&path)?;
let tag = read_comment_header(&mut file); let tag = read_comment_header(&mut file);
Ok(OGGTag { Ok(OggTag {
path: path.as_ref().to_owned(), path: path.as_ref().to_owned(),
tag, tag,
}) })
} }
} }
impl super::Tag for OGGTag { impl super::Tag for OggTag {
fn set_separator(&mut self, _separator: &str) {} fn set_separator(&mut self, _separator: &str) {}
fn set_field(&mut self, field: Field, value: Vec<String>) { fn set_field(&mut self, field: Field, value: Vec<String>) {