chore: Update to edition 2024
* chore(deps): `cargo update` * chore: update to Rust edition 2024 and apply fixes Update the Rust edition and apply changes required in the new edition. Also update the Cargo manifests to reflect the edition change, and ensure changes automatically apply to workspace members in the future. * chore: format all code with `rustfmt` The new Rust edition comes with some new formatting defaults, which need to be applied since the edition was increased. * style: change suggested matches back to `if let` There has been a breaking change in Rust edition 2024 that changed the behavior of `if let` statements slightly. The new behavior is more in line with what users would expect, but could lead to problems in existing code. The automatic edition update therefore changed such `if let` statements to match statements instead. That lead to deeply nested code which was hard to reason about. This changes most of them back to regular `if let` chains, as the new behavior shouldn't cause problems for these cases. --------- Co-authored-by: Henrik Friedrichsen <henrik@affekt.org>
This commit is contained in:
560
Cargo.lock
generated
560
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
20
Cargo.toml
@@ -1,14 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["Henrik Friedrichsen <henrik@affekt.org>"]
|
|
||||||
description = "ncurses Spotify client written in Rust using librespot, inspired by ncmpc and the likes."
|
|
||||||
edition = "2021"
|
|
||||||
exclude = ["images/**"]
|
|
||||||
keywords = ["spotify", "ncurses", "librespot", "terminal"]
|
|
||||||
license = "BSD-2-Clause"
|
|
||||||
name = "ncspot"
|
name = "ncspot"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/hrkfdn/ncspot"
|
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
|
description = "ncurses Spotify client written in Rust using librespot, inspired by ncmpc and the likes."
|
||||||
|
exclude = ["images/**"]
|
||||||
|
keywords = ["spotify", "ncurses", "librespot", "terminal"]
|
||||||
|
authors.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = {status = "actively-developed"}
|
maintenance = {status = "actively-developed"}
|
||||||
@@ -19,6 +19,12 @@ members = [
|
|||||||
"xtask"
|
"xtask"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
authors = ["Henrik Friedrichsen <henrik@affekt.org>"]
|
||||||
|
edition = "2024"
|
||||||
|
license = "BSD-2-Clause"
|
||||||
|
repository = "https://github.com/hrkfdn/ncspot"
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
enum_glob_use = "warn"
|
enum_glob_use = "warn"
|
||||||
use_self = "deny"
|
use_self = "deny"
|
||||||
|
|||||||
@@ -790,7 +790,7 @@ pub fn parse(input: &str) -> Result<Vec<Command>, CommandParseError> {
|
|||||||
_ => {
|
_ => {
|
||||||
return Err(E::NoSuchCommand {
|
return Err(E::NoSuchCommand {
|
||||||
cmd: command.into(),
|
cmd: command.into(),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
commands.push(command);
|
commands.push(command);
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use crate::application::UserData;
|
use crate::application::UserData;
|
||||||
use crate::command::{
|
use crate::command::{
|
||||||
parse, Command, GotoMode, JumpMode, MoveAmount, MoveMode, SeekDirection, ShiftMode, TargetMode,
|
Command, GotoMode, JumpMode, MoveAmount, MoveMode, SeekDirection, ShiftMode, TargetMode, parse,
|
||||||
};
|
};
|
||||||
use crate::config::{user_configuration_directory, Config};
|
use crate::config::{Config, user_configuration_directory};
|
||||||
use crate::events::EventManager;
|
use crate::events::EventManager;
|
||||||
use crate::ext_traits::CursiveExt;
|
use crate::ext_traits::CursiveExt;
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
@@ -20,10 +20,10 @@ use crate::ui::help::HelpView;
|
|||||||
use crate::ui::layout::Layout;
|
use crate::ui::layout::Layout;
|
||||||
use crate::ui::modal::Modal;
|
use crate::ui::modal::Modal;
|
||||||
use crate::ui::search_results::SearchResultsView;
|
use crate::ui::search_results::SearchResultsView;
|
||||||
|
use cursive::Cursive;
|
||||||
use cursive::event::{Event, Key};
|
use cursive::event::{Event, Key};
|
||||||
use cursive::traits::View;
|
use cursive::traits::View;
|
||||||
use cursive::views::Dialog;
|
use cursive::views::Dialog;
|
||||||
use cursive::Cursive;
|
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use ncspot::CONFIGURATION_FILE_NAME;
|
use ncspot::CONFIGURATION_FILE_NAME;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use platform_dirs::AppDirs;
|
|||||||
use crate::command::{SortDirection, SortKey};
|
use crate::command::{SortDirection, SortKey};
|
||||||
use crate::model::playable::Playable;
|
use crate::model::playable::Playable;
|
||||||
use crate::queue;
|
use crate::queue;
|
||||||
use crate::serialization::{Serializer, CBOR, TOML};
|
use crate::serialization::{CBOR, Serializer, TOML};
|
||||||
|
|
||||||
pub const CACHE_VERSION: u16 = 1;
|
pub const CACHE_VERSION: u16 = 1;
|
||||||
pub const DEFAULT_COMMAND_KEY: char = ':';
|
pub const DEFAULT_COMMAND_KEY: char = ':';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crossbeam_channel::{unbounded, Receiver, Sender, TryIter};
|
use crossbeam_channel::{Receiver, Sender, TryIter, unbounded};
|
||||||
use cursive::{CbSink, Cursive};
|
use cursive::{CbSink, Cursive};
|
||||||
|
|
||||||
use crate::queue::QueueEvent;
|
use crate::queue::QueueEvent;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use log::{debug, error, info};
|
|||||||
use tokio::net::{UnixListener, UnixStream};
|
use tokio::net::{UnixListener, UnixStream};
|
||||||
use tokio::runtime::Handle;
|
use tokio::runtime::Handle;
|
||||||
use tokio::sync::watch::{Receiver, Sender};
|
use tokio::sync::watch::{Receiver, Sender};
|
||||||
use tokio_stream::wrappers::WatchStream;
|
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
use tokio_stream::wrappers::WatchStream;
|
||||||
use tokio_util::codec::{FramedRead, FramedWrite, LinesCodec};
|
use tokio_util::codec::{FramedRead, FramedWrite, LinesCodec};
|
||||||
|
|
||||||
use crate::events::{Event, EventManager};
|
use crate::events::{Event, EventManager};
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use std::thread;
|
|||||||
|
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use rspotify::model::Id;
|
use rspotify::model::Id;
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::config::{self, CACHE_VERSION};
|
use crate::config::{self, CACHE_VERSION};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ extern crate serde;
|
|||||||
|
|
||||||
use std::{path::PathBuf, process::exit};
|
use std::{path::PathBuf, process::exit};
|
||||||
|
|
||||||
use application::{setup_logging, Application};
|
use application::{Application, setup_logging};
|
||||||
use config::set_configuration_base_path;
|
use config::set_configuration_base_path;
|
||||||
use log::error;
|
use log::error;
|
||||||
use ncspot::program_arguments;
|
use ncspot::program_arguments;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use rspotify::model::artist::{FullArtist, SimplifiedArtist};
|
|
||||||
use rspotify::model::Id;
|
use rspotify::model::Id;
|
||||||
|
use rspotify::model::artist::{FullArtist, SimplifiedArtist};
|
||||||
|
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::model::playable::Playable;
|
use crate::model::playable::Playable;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ use crate::queue::Queue;
|
|||||||
use crate::traits::{ListItem, ViewExt};
|
use crate::traits::{ListItem, ViewExt};
|
||||||
use crate::utils::ms_to_hms;
|
use crate::utils::ms_to_hms;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use rspotify::model::show::{FullEpisode, SimplifiedEpisode};
|
|
||||||
use rspotify::model::Id;
|
use rspotify::model::Id;
|
||||||
|
use rspotify::model::show::{FullEpisode, SimplifiedEpisode};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use std::{cmp::Ordering, iter::Iterator};
|
|||||||
use rand::{rng, seq::IteratorRandom};
|
use rand::{rng, seq::IteratorRandom};
|
||||||
|
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
use rspotify::model::playlist::{FullPlaylist, SimplifiedPlaylist};
|
|
||||||
use rspotify::model::Id;
|
use rspotify::model::Id;
|
||||||
|
use rspotify::model::playlist::{FullPlaylist, SimplifiedPlaylist};
|
||||||
|
|
||||||
use crate::model::playable::Playable;
|
use crate::model::playable::Playable;
|
||||||
use crate::model::track::Track;
|
use crate::model::track::Track;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use crate::queue::Queue;
|
|||||||
use crate::spotify::Spotify;
|
use crate::spotify::Spotify;
|
||||||
use crate::traits::{IntoBoxedViewExt, ListItem, ViewExt};
|
use crate::traits::{IntoBoxedViewExt, ListItem, ViewExt};
|
||||||
use crate::ui::show::ShowView;
|
use crate::ui::show::ShowView;
|
||||||
use rspotify::model::show::{FullShow, SimplifiedShow};
|
|
||||||
use rspotify::model::Id;
|
use rspotify::model::Id;
|
||||||
|
use rspotify::model::show::{FullShow, SimplifiedShow};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use std::sync::{Arc, RwLock};
|
|||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::utils::ms_to_hms;
|
use crate::utils::ms_to_hms;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
use rspotify::model::Id;
|
||||||
use rspotify::model::album::FullAlbum;
|
use rspotify::model::album::FullAlbum;
|
||||||
use rspotify::model::track::{FullTrack, SavedTrack, SimplifiedTrack};
|
use rspotify::model::track::{FullTrack, SavedTrack, SimplifiedTrack};
|
||||||
use rspotify::model::Id;
|
|
||||||
|
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::model::album::Album;
|
use crate::model::album::Album;
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use std::error::Error;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
use zbus::object_server::SignalEmitter;
|
use zbus::object_server::SignalEmitter;
|
||||||
use zbus::zvariant::{ObjectPath, Value};
|
use zbus::zvariant::{ObjectPath, Value};
|
||||||
use zbus::{connection, interface};
|
use zbus::{connection, interface};
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ use librespot_playback::audio_backend;
|
|||||||
use librespot_playback::audio_backend::SinkBuilder;
|
use librespot_playback::audio_backend::SinkBuilder;
|
||||||
use librespot_playback::config::Bitrate;
|
use librespot_playback::config::Bitrate;
|
||||||
use librespot_playback::config::PlayerConfig;
|
use librespot_playback::config::PlayerConfig;
|
||||||
use librespot_playback::mixer::softmixer::SoftMixer;
|
|
||||||
use librespot_playback::mixer::MixerConfig;
|
use librespot_playback::mixer::MixerConfig;
|
||||||
|
use librespot_playback::mixer::softmixer::SoftMixer;
|
||||||
use librespot_playback::player::Player;
|
use librespot_playback::player::Player;
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
@@ -167,10 +167,9 @@ impl Spotify {
|
|||||||
credentials: Credentials,
|
credentials: Credentials,
|
||||||
) -> Result<Session, librespot_core::Error> {
|
) -> Result<Session, librespot_core::Error> {
|
||||||
let librespot_cache_path = config::cache_path("librespot");
|
let librespot_cache_path = config::cache_path("librespot");
|
||||||
let audio_cache_path = if let Some(false) = cfg.values().audio_cache {
|
let audio_cache_path = match cfg.values().audio_cache {
|
||||||
None
|
Some(false) => None,
|
||||||
} else {
|
_ => Some(librespot_cache_path.join("files")),
|
||||||
Some(librespot_cache_path.join("files"))
|
|
||||||
};
|
};
|
||||||
let cache = Cache::new(
|
let cache = Cache::new(
|
||||||
Some(librespot_cache_path.clone()),
|
Some(librespot_cache_path.clone()),
|
||||||
@@ -206,9 +205,12 @@ impl Spotify {
|
|||||||
|
|
||||||
info!("Initializing audio backend {}", backend_name);
|
info!("Initializing audio backend {}", backend_name);
|
||||||
if backend_name == "pulseaudio" {
|
if backend_name == "pulseaudio" {
|
||||||
env::set_var("PULSE_PROP_application.name", "ncspot");
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||||
env::set_var("PULSE_PROP_stream.description", "ncurses Spotify client");
|
unsafe { env::set_var("PULSE_PROP_application.name", "ncspot") };
|
||||||
env::set_var("PULSE_PROP_media.role", "music");
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||||
|
unsafe { env::set_var("PULSE_PROP_stream.description", "ncurses Spotify client") };
|
||||||
|
// TODO: Audit that the environment access only happens in single-threaded code.
|
||||||
|
unsafe { env::set_var("PULSE_PROP_media.role", "music") };
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(backend.1)
|
Ok(backend.1)
|
||||||
@@ -376,10 +378,13 @@ impl Spotify {
|
|||||||
#[cfg(feature = "mpris")]
|
#[cfg(feature = "mpris")]
|
||||||
fn send_mpris(&self, cmd: MprisCommand) {
|
fn send_mpris(&self, cmd: MprisCommand) {
|
||||||
debug!("Sending mpris command: {:?}", cmd);
|
debug!("Sending mpris command: {:?}", cmd);
|
||||||
if let Some(mpris_manager) = self.mpris.lock().unwrap().as_ref() {
|
match self.mpris.lock().unwrap().as_ref() {
|
||||||
mpris_manager.send(cmd);
|
Some(mpris_manager) => {
|
||||||
} else {
|
mpris_manager.send(cmd);
|
||||||
warn!("mpris context is unitialized");
|
}
|
||||||
|
_ => {
|
||||||
|
warn!("mpris context is unitialized");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use rspotify::model::{
|
|||||||
PlaylistResult, PrivateUser, Recommendations, SavedAlbum, SavedTrack, SearchResult, SearchType,
|
PlaylistResult, PrivateUser, Recommendations, SavedAlbum, SavedTrack, SearchResult, SearchType,
|
||||||
Show, ShowId, SimplifiedTrack, TrackId, UserId,
|
Show, ShowId, SimplifiedTrack, TrackId, UserId,
|
||||||
};
|
};
|
||||||
use rspotify::{prelude::*, AuthCodeSpotify, ClientError, ClientResult, Config, Token};
|
use rspotify::{AuthCodeSpotify, ClientError, ClientResult, Config, Token, prelude::*};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
@@ -101,21 +101,27 @@ impl WebApi {
|
|||||||
channel.send(cmd).unwrap();
|
channel.send(cmd).unwrap();
|
||||||
let api_token = self.api.token.clone();
|
let api_token = self.api.token.clone();
|
||||||
let api_token_expiration = self.token_expiration.clone();
|
let api_token_expiration = self.token_expiration.clone();
|
||||||
Some(ASYNC_RUNTIME.get().unwrap().spawn_blocking(move || {
|
Some(
|
||||||
if let Ok(Some(token)) = token_rx.recv() {
|
ASYNC_RUNTIME
|
||||||
*api_token.lock().unwrap() = Some(Token {
|
.get()
|
||||||
access_token: token.access_token,
|
.unwrap()
|
||||||
expires_in: chrono::Duration::from_std(token.expires_in).unwrap(),
|
.spawn_blocking(move || match token_rx.recv() {
|
||||||
scopes: HashSet::from_iter(token.scopes),
|
Ok(Some(token)) => {
|
||||||
expires_at: None,
|
*api_token.lock().unwrap() = Some(Token {
|
||||||
refresh_token: None,
|
access_token: token.access_token,
|
||||||
});
|
expires_in: chrono::Duration::from_std(token.expires_in).unwrap(),
|
||||||
*api_token_expiration.write().unwrap() =
|
scopes: HashSet::from_iter(token.scopes),
|
||||||
Utc::now() + ChronoDuration::from_std(token.expires_in).unwrap();
|
expires_at: None,
|
||||||
} else {
|
refresh_token: None,
|
||||||
error!("Failed to update token");
|
});
|
||||||
}
|
*api_token_expiration.write().unwrap() =
|
||||||
}))
|
Utc::now() + ChronoDuration::from_std(token.expires_in).unwrap();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error!("Failed to update token");
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
panic!("worker channel is not set");
|
panic!("worker channel is not set");
|
||||||
}
|
}
|
||||||
@@ -131,8 +137,8 @@ impl WebApi {
|
|||||||
Ok(v) => Some(v),
|
Ok(v) => Some(v),
|
||||||
Err(ClientError::Http(error)) => {
|
Err(ClientError::Http(error)) => {
|
||||||
debug!("http error: {:?}", error);
|
debug!("http error: {:?}", error);
|
||||||
if let HttpError::StatusCode(response) = error.as_ref() {
|
match error.as_ref() {
|
||||||
match response.status() {
|
HttpError::StatusCode(response) => match response.status() {
|
||||||
429 => {
|
429 => {
|
||||||
let waiting_duration = response
|
let waiting_duration = response
|
||||||
.header("Retry-After")
|
.header("Retry-After")
|
||||||
@@ -150,9 +156,8 @@ impl WebApi {
|
|||||||
error!("unhandled api error: {:?}", response);
|
error!("unhandled api error: {:?}", response);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
} else {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ use librespot_core::token::Token;
|
|||||||
use librespot_playback::mixer::Mixer;
|
use librespot_playback::mixer::Mixer;
|
||||||
use librespot_playback::player::{Player, PlayerEvent as LibrespotPlayerEvent};
|
use librespot_playback::player::{Player, PlayerEvent as LibrespotPlayerEvent};
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use std::sync::mpsc::Sender;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{pin::Pin, time::SystemTime};
|
use std::{pin::Pin, time::SystemTime};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum WorkerCommand {
|
pub(crate) enum WorkerCommand {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use crate::config::ConfigTheme;
|
|||||||
/// load_color!(config_theme, primary, TerminalDefault)
|
/// load_color!(config_theme, primary, TerminalDefault)
|
||||||
/// ```
|
/// ```
|
||||||
macro_rules! load_color {
|
macro_rules! load_color {
|
||||||
( $theme: expr, $member: ident, $default: expr ) => {
|
( $theme: expr_2021, $member: ident, $default: expr_2021 ) => {
|
||||||
$theme
|
$theme
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|t| t.$member.clone())
|
.and_then(|t| t.$member.clone())
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use cursive::Cursive;
|
||||||
use cursive::view::{View, ViewWrapper};
|
use cursive::view::{View, ViewWrapper};
|
||||||
use cursive::views::NamedView;
|
use cursive::views::NamedView;
|
||||||
use cursive::Cursive;
|
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use cursive::view::ViewWrapper;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use cursive::view::ViewWrapper;
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use cursive::view::ViewWrapper;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use cursive::view::ViewWrapper;
|
||||||
use rspotify::model::AlbumType;
|
use rspotify::model::AlbumType;
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cursive::view::ViewWrapper;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use cursive::view::ViewWrapper;
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use cursive::Cursive;
|
||||||
use cursive::view::{Margins, ViewWrapper};
|
use cursive::view::{Margins, ViewWrapper};
|
||||||
use cursive::views::{Dialog, NamedView, ScrollView, SelectView};
|
use cursive::views::{Dialog, NamedView, ScrollView, SelectView};
|
||||||
use cursive::Cursive;
|
|
||||||
|
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
use crate::ext_traits::SelectViewExt;
|
use crate::ext_traits::SelectViewExt;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::sync::{Arc, RwLock};
|
|||||||
|
|
||||||
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
|
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
|
||||||
use cursive::{Cursive, Printer, Vec2, View};
|
use cursive::{Cursive, Printer, Vec2, View};
|
||||||
use ioctl_rs::{ioctl, TIOCGWINSZ};
|
use ioctl_rs::{TIOCGWINSZ, ioctl};
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
|
|
||||||
use crate::command::{Command, GotoMode};
|
use crate::command::{Command, GotoMode};
|
||||||
@@ -117,9 +117,12 @@ impl CoverView {
|
|||||||
draw_offset.x += (draw_size.x - size.x) / 2;
|
draw_offset.x += (draw_size.x - size.x) / 2;
|
||||||
draw_offset.y += (draw_size.y - size.y) - (draw_size.y - size.y) / 2;
|
draw_offset.y += (draw_size.y - size.y) - (draw_size.y - size.y) / 2;
|
||||||
|
|
||||||
let cmd = format!("{{\"action\":\"add\",\"scaler\":\"fit_contain\",\"identifier\":\"cover\",\"x\":{},\"y\":{},\"width\":{},\"height\":{},\"path\":\"{}\"}}\n",
|
let cmd = format!(
|
||||||
draw_offset.x, draw_offset.y,
|
"{{\"action\":\"add\",\"scaler\":\"fit_contain\",\"identifier\":\"cover\",\"x\":{},\"y\":{},\"width\":{},\"height\":{},\"path\":\"{}\"}}\n",
|
||||||
size.x, size.y,
|
draw_offset.x,
|
||||||
|
draw_offset.y,
|
||||||
|
size.x,
|
||||||
|
size.y,
|
||||||
path.to_str().unwrap()
|
path.to_str().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use cursive::Cursive;
|
||||||
use cursive::theme::Effect;
|
use cursive::theme::Effect;
|
||||||
use cursive::utils::markup::StyledString;
|
use cursive::utils::markup::StyledString;
|
||||||
use cursive::view::ViewWrapper;
|
use cursive::view::ViewWrapper;
|
||||||
use cursive::views::{ScrollView, TextView};
|
use cursive::views::{ScrollView, TextView};
|
||||||
use cursive::Cursive;
|
|
||||||
use ncspot::CONFIGURATION_FILE_NAME;
|
use ncspot::CONFIGURATION_FILE_NAME;
|
||||||
|
|
||||||
use crate::command::{Command, MoveAmount, MoveMode};
|
use crate::command::{Command, MoveAmount, MoveMode};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cursive::view::ViewWrapper;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use cursive::view::ViewWrapper;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use cursive::view::scroll::Scroller;
|
use cursive::view::scroll::Scroller;
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::cmp::{max, min, Ordering};
|
use std::cmp::{Ordering, max, min};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use cursive::align::HAlign;
|
use cursive::align::HAlign;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use cursive::view::ViewWrapper;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use cursive::view::ViewWrapper;
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use cursive::Cursive;
|
||||||
use cursive::view::{Margins, ViewWrapper};
|
use cursive::view::{Margins, ViewWrapper};
|
||||||
use cursive::views::Dialog;
|
use cursive::views::Dialog;
|
||||||
use cursive::Cursive;
|
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
use cursive::Cursive;
|
||||||
use cursive::traits::{Nameable, Resizable};
|
use cursive::traits::{Nameable, Resizable};
|
||||||
use cursive::view::{Margins, ViewWrapper};
|
use cursive::view::{Margins, ViewWrapper};
|
||||||
use cursive::views::{Dialog, EditView, ScrollView, SelectView};
|
use cursive::views::{Dialog, EditView, ScrollView, SelectView};
|
||||||
use cursive::Cursive;
|
|
||||||
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ use crate::traits::{ListItem, ViewExt};
|
|||||||
use crate::ui::listview::ListView;
|
use crate::ui::listview::ListView;
|
||||||
use crate::ui::pagination::Pagination;
|
use crate::ui::pagination::Pagination;
|
||||||
use crate::ui::tabbedview::TabbedView;
|
use crate::ui::tabbedview::TabbedView;
|
||||||
use cursive::view::ViewWrapper;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
use rspotify::model::search::SearchResult;
|
use cursive::view::ViewWrapper;
|
||||||
use rspotify::model::SearchType;
|
use rspotify::model::SearchType;
|
||||||
|
use rspotify::model::search::SearchResult;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
pub struct SearchResultsView {
|
pub struct SearchResultsView {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cursive::view::ViewWrapper;
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
use cursive::view::ViewWrapper;
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::commands::CommandResult;
|
use crate::commands::CommandResult;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use cursive::Printer;
|
||||||
use cursive::align::HAlign;
|
use cursive::align::HAlign;
|
||||||
use cursive::event::{Event, EventResult, MouseButton, MouseEvent};
|
use cursive::event::{Event, EventResult, MouseButton, MouseEvent};
|
||||||
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
|
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
|
||||||
use cursive::traits::View;
|
use cursive::traits::View;
|
||||||
use cursive::vec::Vec2;
|
use cursive::vec::Vec2;
|
||||||
use cursive::Printer;
|
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
use cursive::{
|
use cursive::{
|
||||||
|
Cursive, Printer, Vec2, View,
|
||||||
align::HAlign,
|
align::HAlign,
|
||||||
event::{Event, EventResult, MouseButton, MouseEvent},
|
event::{Event, EventResult, MouseButton, MouseEvent},
|
||||||
theme::ColorStyle,
|
theme::ColorStyle,
|
||||||
view::Nameable,
|
view::Nameable,
|
||||||
views::NamedView,
|
views::NamedView,
|
||||||
Cursive, Printer, Vec2, View,
|
|
||||||
};
|
};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "xtask"
|
name = "xtask"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
authors.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap_mangen = "0.2.26"
|
clap_mangen = "0.2.26"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
|
use clap::ArgMatches;
|
||||||
use clap::builder::PathBufValueParser;
|
use clap::builder::PathBufValueParser;
|
||||||
use clap::error::{Error, ErrorKind};
|
use clap::error::{Error, ErrorKind};
|
||||||
use clap::ArgMatches;
|
|
||||||
use clap_complete::Shell;
|
use clap_complete::Shell;
|
||||||
use ncspot::{AUTHOR, BIN_NAME};
|
use ncspot::{AUTHOR, BIN_NAME};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user