changes
This commit is contained in:
parent
f67be1d367
commit
c12b4787ca
3 changed files with 258 additions and 183 deletions
73
src/actions.rs
Normal file
73
src/actions.rs
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::structs::{IsPlayingResponse, NowPlayingResponse};
|
||||||
|
|
||||||
|
pub fn get_now_playing() -> Result<NowPlayingResponse, reqwest::Error> {
|
||||||
|
const URL: &str = "http://localhost:10767/api/v1/playback/now-playing";
|
||||||
|
|
||||||
|
// This call blocks until the request is complete.
|
||||||
|
let response = reqwest::blocking::get(URL)?;
|
||||||
|
|
||||||
|
let data: NowPlayingResponse = response.json()?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_playpause() -> Result<serde_json::Value, reqwest::Error> {
|
||||||
|
const URL: &str = "http://localhost:10767/api/v1/playback/playpause";
|
||||||
|
|
||||||
|
let client = reqwest::blocking::Client::new();
|
||||||
|
|
||||||
|
// This call blocks until the request is complete.
|
||||||
|
let response = client.post(URL).send()?;
|
||||||
|
|
||||||
|
let data = response.json()?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skip() -> Result<serde_json::Value, reqwest::Error> {
|
||||||
|
const URL: &str = "http://localhost:10767/api/v1/playback/next";
|
||||||
|
|
||||||
|
let client = reqwest::blocking::Client::new();
|
||||||
|
|
||||||
|
// This call blocks until the request is complete.
|
||||||
|
let response = client.post(URL).send()?;
|
||||||
|
|
||||||
|
let data = response.json()?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn like() -> Result<serde_json::Value, reqwest::Error> {
|
||||||
|
const URL: &str = "http://localhost:10767/api/v1/playback/set-rating";
|
||||||
|
|
||||||
|
let client = reqwest::blocking::Client::new();
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct RatingBody {
|
||||||
|
rating: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This call blocks until the request is complete.
|
||||||
|
let response = client
|
||||||
|
.post(URL)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(serde_json::to_string(&RatingBody { rating: 1 }).unwrap())
|
||||||
|
.send()?;
|
||||||
|
|
||||||
|
let data = response.json()?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_is_playing() -> Result<IsPlayingResponse, reqwest::Error> {
|
||||||
|
const URL: &str = "http://localhost:10767/api/v1/playback/is-playing";
|
||||||
|
|
||||||
|
// This call blocks until the request is complete.
|
||||||
|
let response = reqwest::blocking::get(URL)?;
|
||||||
|
|
||||||
|
let data: IsPlayingResponse = response.json()?;
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
207
src/main.rs
207
src/main.rs
|
|
@ -6,168 +6,15 @@ use std::{
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use crossbeam_channel::unbounded;
|
use crossbeam_channel::unbounded;
|
||||||
use rust_socketio::{ClientBuilder, Payload};
|
use rust_socketio::{ClientBuilder, Payload};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
use crate::{
|
||||||
pub struct PlaybackUpdate {
|
actions::{get_is_playing, get_now_playing, like, skip, toggle_playpause},
|
||||||
pub data: Data,
|
structs::{PlaybackUpdate, StatusUpdate},
|
||||||
#[serde(rename = "type")]
|
};
|
||||||
pub type_field: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
mod actions;
|
||||||
pub struct Data {
|
mod structs;
|
||||||
#[serde(rename = "currentPlaybackDuration")]
|
|
||||||
pub current_playback_duration: Option<f64>,
|
|
||||||
#[serde(rename = "currentPlaybackTime")]
|
|
||||||
pub current_playback_time: Option<f64>,
|
|
||||||
#[serde(rename = "currentPlaybackTimeRemaining")]
|
|
||||||
pub current_playback_time_remaining: Option<f64>,
|
|
||||||
#[serde(rename = "isPlaying")]
|
|
||||||
pub is_playing: Option<bool>,
|
|
||||||
#[serde(rename = "albumName")]
|
|
||||||
pub album_name: Option<String>,
|
|
||||||
#[serde(rename = "artistName")]
|
|
||||||
pub artist_name: Option<String>,
|
|
||||||
pub artwork: Option<Artwork>,
|
|
||||||
#[serde(rename = "audioLocale")]
|
|
||||||
pub audio_locale: Option<String>,
|
|
||||||
#[serde(rename = "audioTraits")]
|
|
||||||
pub audio_traits: Option<Vec<String>>,
|
|
||||||
#[serde(rename = "composerName")]
|
|
||||||
pub composer_name: Option<String>,
|
|
||||||
#[serde(rename = "discNumber")]
|
|
||||||
pub disc_number: Option<i64>,
|
|
||||||
#[serde(rename = "durationInMillis")]
|
|
||||||
pub duration_in_millis: Option<i64>,
|
|
||||||
#[serde(rename = "genreNames")]
|
|
||||||
#[serde(default)]
|
|
||||||
pub genre_names: Vec<String>,
|
|
||||||
#[serde(rename = "hasLyrics")]
|
|
||||||
pub has_lyrics: Option<bool>,
|
|
||||||
#[serde(rename = "hasTimeSyncedLyrics")]
|
|
||||||
pub has_time_synced_lyrics: Option<bool>,
|
|
||||||
#[serde(rename = "isAppleDigitalMaster")]
|
|
||||||
pub is_apple_digital_master: Option<bool>,
|
|
||||||
#[serde(rename = "isMasteredForItunes")]
|
|
||||||
pub is_mastered_for_itunes: Option<bool>,
|
|
||||||
#[serde(rename = "isVocalAttenuationAllowed")]
|
|
||||||
pub is_vocal_attenuation_allowed: Option<bool>,
|
|
||||||
pub isrc: Option<String>,
|
|
||||||
pub name: Option<String>,
|
|
||||||
#[serde(rename = "playParams")]
|
|
||||||
pub play_params: Option<PlayParams>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub previews: Vec<Preview>,
|
|
||||||
#[serde(rename = "releaseDate")]
|
|
||||||
pub release_date: Option<String>,
|
|
||||||
#[serde(rename = "remainingTime")]
|
|
||||||
pub remaining_time: Option<f64>,
|
|
||||||
#[serde(rename = "trackNumber")]
|
|
||||||
pub track_number: Option<i64>,
|
|
||||||
pub url: Option<String>,
|
|
||||||
pub attributes: Option<Attributes>,
|
|
||||||
pub state: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Artwork {
|
|
||||||
pub height: i64,
|
|
||||||
pub url: String,
|
|
||||||
pub width: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct PlayParams {
|
|
||||||
pub id: String,
|
|
||||||
pub kind: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Preview {
|
|
||||||
pub url: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Attributes {
|
|
||||||
#[serde(rename = "albumName")]
|
|
||||||
pub album_name: String,
|
|
||||||
#[serde(rename = "artistName")]
|
|
||||||
pub artist_name: String,
|
|
||||||
pub artwork: Artwork2,
|
|
||||||
#[serde(rename = "audioLocale")]
|
|
||||||
pub audio_locale: String,
|
|
||||||
#[serde(rename = "audioTraits")]
|
|
||||||
pub audio_traits: Vec<String>,
|
|
||||||
#[serde(rename = "composerName")]
|
|
||||||
pub composer_name: String,
|
|
||||||
#[serde(rename = "currentPlaybackTime")]
|
|
||||||
pub current_playback_time: f64,
|
|
||||||
#[serde(rename = "discNumber")]
|
|
||||||
pub disc_number: i64,
|
|
||||||
#[serde(rename = "durationInMillis")]
|
|
||||||
pub duration_in_millis: i64,
|
|
||||||
#[serde(rename = "genreNames")]
|
|
||||||
pub genre_names: Vec<String>,
|
|
||||||
#[serde(rename = "hasLyrics")]
|
|
||||||
pub has_lyrics: bool,
|
|
||||||
#[serde(rename = "hasTimeSyncedLyrics")]
|
|
||||||
pub has_time_synced_lyrics: bool,
|
|
||||||
#[serde(rename = "isAppleDigitalMaster")]
|
|
||||||
pub is_apple_digital_master: bool,
|
|
||||||
#[serde(rename = "isMasteredForItunes")]
|
|
||||||
pub is_mastered_for_itunes: bool,
|
|
||||||
#[serde(rename = "isVocalAttenuationAllowed")]
|
|
||||||
pub is_vocal_attenuation_allowed: bool,
|
|
||||||
pub isrc: String,
|
|
||||||
pub name: String,
|
|
||||||
#[serde(rename = "playParams")]
|
|
||||||
pub play_params: PlayParams2,
|
|
||||||
pub previews: Vec<Preview2>,
|
|
||||||
#[serde(rename = "releaseDate")]
|
|
||||||
pub release_date: String,
|
|
||||||
#[serde(rename = "remainingTime")]
|
|
||||||
pub remaining_time: f64,
|
|
||||||
#[serde(rename = "trackNumber")]
|
|
||||||
pub track_number: i64,
|
|
||||||
pub url: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Artwork2 {
|
|
||||||
pub height: i64,
|
|
||||||
pub url: String,
|
|
||||||
pub width: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct PlayParams2 {
|
|
||||||
pub id: String,
|
|
||||||
pub kind: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Preview2 {
|
|
||||||
pub url: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct NowPlayingResponse {
|
|
||||||
info: Data,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct IsPlayingResponse {
|
|
||||||
is_playing: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
struct StatusUpdate {
|
|
||||||
text: String,
|
|
||||||
tooltip: String,
|
|
||||||
class: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
|
|
@ -178,6 +25,13 @@ struct Cli {
|
||||||
|
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
|
/// Like the current song.
|
||||||
|
Like,
|
||||||
|
/// Skip the current song.
|
||||||
|
Skip,
|
||||||
|
/// Toggle play/pause.
|
||||||
|
PlayPause,
|
||||||
|
|
||||||
/// Monitor song changes from Cider
|
/// Monitor song changes from Cider
|
||||||
Monitor,
|
Monitor,
|
||||||
}
|
}
|
||||||
|
|
@ -261,35 +115,22 @@ fn setup_ctrlc_handler() -> crossbeam_channel::Receiver<()> {
|
||||||
receiver
|
receiver
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_now_playing() -> Result<NowPlayingResponse, reqwest::Error> {
|
|
||||||
const URL: &str = "http://localhost:10767/api/v1/playback/now-playing";
|
|
||||||
|
|
||||||
// This call blocks until the request is complete.
|
|
||||||
let response = reqwest::blocking::get(URL)?;
|
|
||||||
|
|
||||||
let data: NowPlayingResponse = response.json()?;
|
|
||||||
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_is_playing() -> Result<IsPlayingResponse, reqwest::Error> {
|
|
||||||
const URL: &str = "http://localhost:10767/api/v1/playback/is-playing";
|
|
||||||
|
|
||||||
// This call blocks until the request is complete.
|
|
||||||
let response = reqwest::blocking::get(URL)?;
|
|
||||||
|
|
||||||
let data: IsPlayingResponse = response.json()?;
|
|
||||||
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> color_eyre::Result<()> {
|
fn main() -> color_eyre::Result<()> {
|
||||||
color_eyre::install()?;
|
// color_eyre::install()?;
|
||||||
tracing_subscriber::fmt().pretty().init();
|
// tracing_subscriber::fmt().pretty().init();
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
match &cli.command {
|
match &cli.command {
|
||||||
|
Some(Commands::Like) => {
|
||||||
|
like()?;
|
||||||
|
}
|
||||||
|
Some(Commands::Skip) => {
|
||||||
|
skip()?;
|
||||||
|
}
|
||||||
|
Some(Commands::PlayPause) => {
|
||||||
|
toggle_playpause()?;
|
||||||
|
}
|
||||||
Some(Commands::Monitor) => {
|
Some(Commands::Monitor) => {
|
||||||
let ctrlc_receiver = setup_ctrlc_handler();
|
let ctrlc_receiver = setup_ctrlc_handler();
|
||||||
|
|
||||||
|
|
|
||||||
161
src/structs.rs
Normal file
161
src/structs.rs
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct PlaybackUpdate {
|
||||||
|
pub data: Data,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub type_field: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Data {
|
||||||
|
#[serde(rename = "currentPlaybackDuration")]
|
||||||
|
pub current_playback_duration: Option<f64>,
|
||||||
|
#[serde(rename = "currentPlaybackTime")]
|
||||||
|
pub current_playback_time: Option<f64>,
|
||||||
|
#[serde(rename = "currentPlaybackTimeRemaining")]
|
||||||
|
pub current_playback_time_remaining: Option<f64>,
|
||||||
|
#[serde(rename = "isPlaying")]
|
||||||
|
pub is_playing: Option<bool>,
|
||||||
|
#[serde(rename = "albumName")]
|
||||||
|
pub album_name: Option<String>,
|
||||||
|
#[serde(rename = "artistName")]
|
||||||
|
pub artist_name: Option<String>,
|
||||||
|
pub artwork: Option<Artwork>,
|
||||||
|
#[serde(rename = "audioLocale")]
|
||||||
|
pub audio_locale: Option<String>,
|
||||||
|
#[serde(rename = "audioTraits")]
|
||||||
|
pub audio_traits: Option<Vec<String>>,
|
||||||
|
#[serde(rename = "composerName")]
|
||||||
|
pub composer_name: Option<String>,
|
||||||
|
#[serde(rename = "discNumber")]
|
||||||
|
pub disc_number: Option<i64>,
|
||||||
|
#[serde(rename = "durationInMillis")]
|
||||||
|
pub duration_in_millis: Option<i64>,
|
||||||
|
#[serde(rename = "genreNames")]
|
||||||
|
#[serde(default)]
|
||||||
|
pub genre_names: Vec<String>,
|
||||||
|
#[serde(rename = "hasLyrics")]
|
||||||
|
pub has_lyrics: Option<bool>,
|
||||||
|
#[serde(rename = "hasTimeSyncedLyrics")]
|
||||||
|
pub has_time_synced_lyrics: Option<bool>,
|
||||||
|
#[serde(rename = "isAppleDigitalMaster")]
|
||||||
|
pub is_apple_digital_master: Option<bool>,
|
||||||
|
#[serde(rename = "isMasteredForItunes")]
|
||||||
|
pub is_mastered_for_itunes: Option<bool>,
|
||||||
|
#[serde(rename = "isVocalAttenuationAllowed")]
|
||||||
|
pub is_vocal_attenuation_allowed: Option<bool>,
|
||||||
|
pub isrc: Option<String>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
#[serde(rename = "playParams")]
|
||||||
|
pub play_params: Option<PlayParams>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub previews: Vec<Preview>,
|
||||||
|
#[serde(rename = "releaseDate")]
|
||||||
|
pub release_date: Option<String>,
|
||||||
|
#[serde(rename = "remainingTime")]
|
||||||
|
pub remaining_time: Option<f64>,
|
||||||
|
#[serde(rename = "trackNumber")]
|
||||||
|
pub track_number: Option<i64>,
|
||||||
|
pub url: Option<String>,
|
||||||
|
pub attributes: Option<Attributes>,
|
||||||
|
pub state: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Artwork {
|
||||||
|
pub height: i64,
|
||||||
|
pub url: String,
|
||||||
|
pub width: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct PlayParams {
|
||||||
|
pub id: String,
|
||||||
|
pub kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Preview {
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Attributes {
|
||||||
|
#[serde(rename = "albumName")]
|
||||||
|
pub album_name: String,
|
||||||
|
#[serde(rename = "artistName")]
|
||||||
|
pub artist_name: String,
|
||||||
|
pub artwork: Artwork2,
|
||||||
|
#[serde(rename = "audioLocale")]
|
||||||
|
pub audio_locale: String,
|
||||||
|
#[serde(rename = "audioTraits")]
|
||||||
|
pub audio_traits: Vec<String>,
|
||||||
|
#[serde(rename = "composerName")]
|
||||||
|
pub composer_name: String,
|
||||||
|
#[serde(rename = "currentPlaybackTime")]
|
||||||
|
pub current_playback_time: f64,
|
||||||
|
#[serde(rename = "discNumber")]
|
||||||
|
pub disc_number: i64,
|
||||||
|
#[serde(rename = "durationInMillis")]
|
||||||
|
pub duration_in_millis: i64,
|
||||||
|
#[serde(rename = "genreNames")]
|
||||||
|
pub genre_names: Vec<String>,
|
||||||
|
#[serde(rename = "hasLyrics")]
|
||||||
|
pub has_lyrics: bool,
|
||||||
|
#[serde(rename = "hasTimeSyncedLyrics")]
|
||||||
|
pub has_time_synced_lyrics: bool,
|
||||||
|
#[serde(rename = "isAppleDigitalMaster")]
|
||||||
|
pub is_apple_digital_master: bool,
|
||||||
|
#[serde(rename = "isMasteredForItunes")]
|
||||||
|
pub is_mastered_for_itunes: bool,
|
||||||
|
#[serde(rename = "isVocalAttenuationAllowed")]
|
||||||
|
pub is_vocal_attenuation_allowed: bool,
|
||||||
|
pub isrc: String,
|
||||||
|
pub name: String,
|
||||||
|
#[serde(rename = "playParams")]
|
||||||
|
pub play_params: PlayParams2,
|
||||||
|
pub previews: Vec<Preview2>,
|
||||||
|
#[serde(rename = "releaseDate")]
|
||||||
|
pub release_date: String,
|
||||||
|
#[serde(rename = "remainingTime")]
|
||||||
|
pub remaining_time: f64,
|
||||||
|
#[serde(rename = "trackNumber")]
|
||||||
|
pub track_number: i64,
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Artwork2 {
|
||||||
|
pub height: i64,
|
||||||
|
pub url: String,
|
||||||
|
pub width: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct PlayParams2 {
|
||||||
|
pub id: String,
|
||||||
|
pub kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Preview2 {
|
||||||
|
pub url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct NowPlayingResponse {
|
||||||
|
pub info: Data,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct IsPlayingResponse {
|
||||||
|
pub is_playing: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct StatusUpdate {
|
||||||
|
pub text: String,
|
||||||
|
pub tooltip: String,
|
||||||
|
pub class: Vec<String>,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue