Compare commits
2
Commits
v0.0.5
...
f4138227ab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4138227ab | ||
|
|
6fbf09b448 |
+42
-13
@@ -5,14 +5,15 @@ use std::io::BufReader;
|
|||||||
use crate::event::{AppEvent, Event, EventHandler};
|
use crate::event::{AppEvent, Event, EventHandler};
|
||||||
use crate::library::{Library, Song};
|
use crate::library::{Library, Song};
|
||||||
|
|
||||||
use audiotags::{MimeType, Tag};
|
use crossterm::event::MediaKeyCode::{self};
|
||||||
use crossterm::event::MediaKeyCode::{self, PlayPause};
|
|
||||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
use discord_rich_presence::activity::{Assets, Timestamps};
|
use discord_rich_presence::activity::{Assets, Timestamps};
|
||||||
use discord_rich_presence::{DiscordIpc, DiscordIpcClient, activity};
|
use discord_rich_presence::{DiscordIpc, DiscordIpcClient, activity};
|
||||||
use ratatui::DefaultTerminal;
|
use ratatui::DefaultTerminal;
|
||||||
use ratatui::widgets::{List, ListItem, ListState};
|
use ratatui::widgets::ListState;
|
||||||
use rodio::Decoder;
|
use rodio::{
|
||||||
|
Decoder, DeviceSinkBuilder, DeviceSinkError, MixerDeviceSink, Player, SampleRate, Source,
|
||||||
|
};
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
@@ -34,8 +35,10 @@ pub struct App {
|
|||||||
|
|
||||||
pub queue: VecDeque<usize>,
|
pub queue: VecDeque<usize>,
|
||||||
|
|
||||||
pub sink_handle: rodio::MixerDeviceSink,
|
pub sink_handle: MixerDeviceSink,
|
||||||
pub player: rodio::Player,
|
pub sample_rate: SampleRate,
|
||||||
|
pub sink_volume: f32,
|
||||||
|
pub player: Player,
|
||||||
|
|
||||||
pub artist_state: ListState,
|
pub artist_state: ListState,
|
||||||
pub album_state: ListState,
|
pub album_state: ListState,
|
||||||
@@ -57,9 +60,9 @@ impl App {
|
|||||||
/// Constructs a new instance of [`App`].
|
/// Constructs a new instance of [`App`].
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let sink_handle =
|
let sink_handle =
|
||||||
rodio::DeviceSinkBuilder::open_default_sink().expect("open default audio stream");
|
DeviceSinkBuilder::open_default_sink().expect("open default audio stream");
|
||||||
let player = rodio::Player::connect_new(sink_handle.mixer());
|
let player = Player::connect_new(sink_handle.mixer());
|
||||||
player.set_volume(1.0);
|
// player.set_volume(1.0);
|
||||||
|
|
||||||
let discord_client = {
|
let discord_client = {
|
||||||
let mut client = DiscordIpcClient::new("1525954755292299426");
|
let mut client = DiscordIpcClient::new("1525954755292299426");
|
||||||
@@ -76,7 +79,6 @@ impl App {
|
|||||||
Self {
|
Self {
|
||||||
running: true,
|
running: true,
|
||||||
library: Library::new(),
|
library: Library::new(),
|
||||||
//songs: get_songs(),
|
|
||||||
queue: vec![].into(),
|
queue: vec![].into(),
|
||||||
artist_state: ListState::default().with_selected(Some(0)),
|
artist_state: ListState::default().with_selected(Some(0)),
|
||||||
album_state: ListState::default().with_selected(Some(0)),
|
album_state: ListState::default().with_selected(Some(0)),
|
||||||
@@ -89,6 +91,8 @@ impl App {
|
|||||||
paused_at: 1,
|
paused_at: 1,
|
||||||
sink_handle,
|
sink_handle,
|
||||||
player,
|
player,
|
||||||
|
sink_volume: 1.0,
|
||||||
|
sample_rate: SampleRate::new(44100).unwrap(),
|
||||||
discord_client,
|
discord_client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,7 +141,7 @@ impl App {
|
|||||||
if self.control_popup == false {
|
if self.control_popup == false {
|
||||||
self.events.send(AppEvent::Quit)
|
self.events.send(AppEvent::Quit)
|
||||||
} else {
|
} else {
|
||||||
self.control_popup = !self.control_popup;
|
self.control_popup = !self.control_popup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Char('c' | 'C') if key_event.modifiers == KeyModifiers::CONTROL => {
|
KeyCode::Char('c' | 'C') if key_event.modifiers == KeyModifiers::CONTROL => {
|
||||||
@@ -252,7 +256,8 @@ impl App {
|
|||||||
if vol >= 1.0 {
|
if vol >= 1.0 {
|
||||||
self.player.set_volume(1.0);
|
self.player.set_volume(1.0);
|
||||||
} else {
|
} else {
|
||||||
self.player.set_volume(vol + 0.05);
|
self.sink_volume = vol + 0.05;
|
||||||
|
self.player.set_volume(self.sink_volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +266,8 @@ impl App {
|
|||||||
if vol <= 0.01 {
|
if vol <= 0.01 {
|
||||||
self.player.set_volume(0.0);
|
self.player.set_volume(0.0);
|
||||||
} else {
|
} else {
|
||||||
self.player.set_volume(vol - 0.05);
|
self.sink_volume = vol - 0.05;
|
||||||
|
self.player.set_volume(self.sink_volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,6 +431,13 @@ impl App {
|
|||||||
File::open(&self.library.songs[*self.queue.front().expect("Queue is empty")].path)
|
File::open(&self.library.songs[*self.queue.front().expect("Queue is empty")].path)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let source = Decoder::new(BufReader::new(file)).unwrap();
|
let source = Decoder::new(BufReader::new(file)).unwrap();
|
||||||
|
|
||||||
|
let rate: SampleRate = source.sample_rate();
|
||||||
|
if rate != self.sample_rate {
|
||||||
|
self.sample_rate = rate;
|
||||||
|
let _ = self.rebuild_sink(self.sample_rate);
|
||||||
|
}
|
||||||
|
|
||||||
self.player.append(source);
|
self.player.append(source);
|
||||||
self.current_song = Some(self.queue.front().unwrap().to_owned());
|
self.current_song = Some(self.queue.front().unwrap().to_owned());
|
||||||
self.update_rpc(self.queue.front().unwrap().to_owned());
|
self.update_rpc(self.queue.front().unwrap().to_owned());
|
||||||
@@ -444,6 +457,22 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rebuild_sink(&mut self, rate: SampleRate) -> Result<(), DeviceSinkError> {
|
||||||
|
self.sink_handle.log_on_drop(false);
|
||||||
|
let mut sink = DeviceSinkBuilder::from_default_device()
|
||||||
|
.unwrap()
|
||||||
|
.with_sample_rate(rate)
|
||||||
|
.open_stream()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
sink.log_on_drop(false);
|
||||||
|
self.sink_handle = sink;
|
||||||
|
self.player = Player::connect_new(self.sink_handle.mixer());
|
||||||
|
self.player.set_volume(self.sink_volume);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Set running to false to quit the application.
|
/// Set running to false to quit the application.
|
||||||
pub fn quit(&mut self) {
|
pub fn quit(&mut self) {
|
||||||
self.running = false;
|
self.running = false;
|
||||||
|
|||||||
@@ -50,8 +50,9 @@ impl Widget for &mut App {
|
|||||||
|
|
||||||
let now_playing_block = Block::bordered()
|
let now_playing_block = Block::bordered()
|
||||||
.title(format!(
|
.title(format!(
|
||||||
"Now Playing | Vol: {:.0}",
|
"Now Playing | Vol: {:.0} | Rate: {}Hz",
|
||||||
self.player.volume() * 100.0
|
self.player.volume() * 100.0,
|
||||||
|
self.sample_rate
|
||||||
))
|
))
|
||||||
.border_type(Rounded);
|
.border_type(Rounded);
|
||||||
let inner = now_playing_block.inner(center_area[1]);
|
let inner = now_playing_block.inner(center_area[1]);
|
||||||
|
|||||||
Reference in New Issue
Block a user