aboutsummaryrefslogtreecommitdiffstats
path: root/src/daemon.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon.rs')
-rw-r--r--src/daemon.rs216
1 files changed, 149 insertions, 67 deletions
diff --git a/src/daemon.rs b/src/daemon.rs
index 20f4e7e..c794495 100644
--- a/src/daemon.rs
+++ b/src/daemon.rs
@@ -34,6 +34,14 @@ impl ScrobbleState {
34 } 34 }
35 35
36 fn start(&mut self, track: Track) { 36 fn start(&mut self, track: Track) {
37 if track.is_stream {
38 crate::debug_eprintln(format_args!(
39 "scrobble: not tracking stream '{}'",
40 track.path.display()
41 ));
42 self.clear();
43 return;
44 }
37 let ts = SystemTime::now() 45 let ts = SystemTime::now()
38 .duration_since(SystemTime::UNIX_EPOCH) 46 .duration_since(SystemTime::UNIX_EPOCH)
39 .unwrap_or_default() 47 .unwrap_or_default()
@@ -109,6 +117,7 @@ mod tests {
109 artist: Some("Artist".into()), 117 artist: Some("Artist".into()),
110 album: None, 118 album: None,
111 duration_secs: Some(200.0), 119 duration_secs: Some(200.0),
120 is_stream: false,
112 }; 121 };
113 s.start(t); 122 s.start(t);
114 assert!(s.track.is_some()); 123 assert!(s.track.is_some());
@@ -161,6 +170,13 @@ mod tests {
161} 170}
162 171
163fn try_scrobble_current(scrobbler: &RwLock<Scrobbler>, state: &mut ScrobbleState) { 172fn try_scrobble_current(scrobbler: &RwLock<Scrobbler>, state: &mut ScrobbleState) {
173 if let Some(ref track) = state.track
174 && track.is_stream
175 {
176 crate::debug_eprintln(format_args!("scrobble: skipping scrobble for stream track"));
177 state.clear();
178 return;
179 }
164 if state.should_scrobble() 180 if state.should_scrobble()
165 && let (Some(track), Some(ts)) = (&state.track, state.timestamp) 181 && let (Some(track), Some(ts)) = (&state.track, state.timestamp)
166 { 182 {
@@ -189,6 +205,12 @@ fn try_scrobble_current(scrobbler: &RwLock<Scrobbler>, state: &mut ScrobbleState
189} 205}
190 206
191fn send_now_playing(scrobbler: &RwLock<Scrobbler>, track: &Track) { 207fn send_now_playing(scrobbler: &RwLock<Scrobbler>, track: &Track) {
208 if track.is_stream {
209 crate::debug_eprintln(format_args!(
210 "scrobble: skipping now_playing for stream track"
211 ));
212 return;
213 }
192 let artist = track.artist.as_deref().unwrap_or("(unknown artist)"); 214 let artist = track.artist.as_deref().unwrap_or("(unknown artist)");
193 let title = track.title.as_deref().unwrap_or("(unknown title)"); 215 let title = track.title.as_deref().unwrap_or("(unknown title)");
194 let album = track.album.as_deref(); 216 let album = track.album.as_deref();
@@ -845,16 +867,18 @@ fn process_command(
845 return "Usage: play [now|next|last] <path>\n".to_string(); 867 return "Usage: play [now|next|last] <path>\n".to_string();
846 } 868 }
847 869
848 let path = std::path::PathBuf::from(path_str.clone()); 870 let is_url = path_str.starts_with("http://") || path_str.starts_with("https://");
849 if path.is_file() { 871
872 if is_url {
850 if let Ok(mut q) = queue.lock() { 873 if let Ok(mut q) = queue.lock() {
851 let was_empty = q.is_empty(); 874 let was_empty = q.is_empty();
875 let track = Track::from_url(&path_str);
852 match position { 876 match position {
853 "now" => { 877 "now" => {
854 if let Ok(mut s) = scrobble_state.lock() { 878 if let Ok(mut s) = scrobble_state.lock() {
855 try_scrobble_current(scrobbler, &mut s); 879 try_scrobble_current(scrobbler, &mut s);
856 } 880 }
857 q.insert_after_current(path.clone()); 881 q.push_track(track.clone());
858 if !was_empty { 882 if !was_empty {
859 let new_pos = q.position() + 1; 883 let new_pos = q.position() + 1;
860 q.set_position(new_pos); 884 q.set_position(new_pos);
@@ -872,84 +896,103 @@ fn process_command(
872 format!("Playing now: {}\n", path_str) 896 format!("Playing now: {}\n", path_str)
873 } 897 }
874 "next" => { 898 "next" => {
875 q.insert_after_current(path.clone()); 899 q.push_track(track);
876 format!("Queued next: {}\n", path_str) 900 format!("Queued next: {}\n", path_str)
877 } 901 }
878 _ => { 902 _ => {
879 let was_empty = q.is_empty();
880 let was_playing = audio.is_playing(); 903 let was_playing = audio.is_playing();
881 q.add_track(path.clone()); 904 q.push_track(track.clone());
882 if was_empty && !was_playing { 905 if was_empty
883 let track = Track::from_path(path.clone()); 906 && !was_playing
884 audio.play(path); 907 && let Some(track) = q.current()
885 send_now_playing(scrobbler, &track); 908 {
909 audio.play(track.path.clone());
910 send_now_playing(scrobbler, track);
886 if let Ok(mut s) = scrobble_state.lock() { 911 if let Ok(mut s) = scrobble_state.lock() {
887 s.start(track.clone()); 912 s.start(track.clone());
888 } 913 }
889 let fmt = 914 let fmt =
890 Config::load().ok().and_then(|c| c.display_format.clone()); 915 Config::load().ok().and_then(|c| c.display_format.clone());
891 notification::notify_track(&track, fmt.as_deref()); 916 notification::notify_track(track, fmt.as_deref());
892 format!("Playing: {}\n", path_str)
893 } else {
894 format!("Queued: {}\n", path_str)
895 } 917 }
918 format!("Queued: {}\n", path_str)
896 } 919 }
897 } 920 }
898 } else { 921 } else {
899 "Error accessing queue\n".to_string() 922 "Error accessing queue\n".to_string()
900 } 923 }
901 } else if path.is_dir() { 924 } else {
902 match find_audio_in_dir(&path) { 925 let path = std::path::PathBuf::from(path_str.clone());
903 Some(files) if !files.is_empty() => { 926 if path.is_file() {
904 if let Ok(mut q) = queue.lock() { 927 if let Ok(mut q) = queue.lock() {
905 let was_empty = q.is_empty(); 928 let was_empty = q.is_empty();
906 match position { 929 match position {
907 "now" => { 930 "now" => {
931 if let Ok(mut s) = scrobble_state.lock() {
932 try_scrobble_current(scrobbler, &mut s);
933 }
934 q.insert_after_current(path.clone());
935 if !was_empty {
936 let new_pos = q.position() + 1;
937 q.set_position(new_pos);
938 }
939 if let Some(track) = q.track_at(q.position()) {
940 audio.play(track.path.clone());
941 send_now_playing(scrobbler, track);
908 if let Ok(mut s) = scrobble_state.lock() { 942 if let Ok(mut s) = scrobble_state.lock() {
909 try_scrobble_current(scrobbler, &mut s); 943 s.start(track.clone());
910 }
911 for file in files.iter().rev() {
912 q.insert_after_current(file.clone());
913 }
914 if !was_empty {
915 let new_pos = q.position() + 1;
916 q.set_position(new_pos);
917 }
918 if let Some(track) = q.track_at(q.position()) {
919 audio.play(track.path.clone());
920 send_now_playing(scrobbler, track);
921 if let Ok(mut s) = scrobble_state.lock() {
922 s.start(track.clone());
923 }
924 let fmt = Config::load()
925 .ok()
926 .and_then(|c| c.display_format.clone());
927 notification::notify_track(track, fmt.as_deref());
928 } 944 }
929 format!( 945 let fmt =
930 "Playing now: {} tracks from {}\n", 946 Config::load().ok().and_then(|c| c.display_format.clone());
931 files.len(), 947 notification::notify_track(track, fmt.as_deref());
932 path_str
933 )
934 } 948 }
935 "next" => { 949 format!("Playing now: {}\n", path_str)
936 for file in files.iter().rev() { 950 }
937 q.insert_after_current(file.clone()); 951 "next" => {
952 q.insert_after_current(path.clone());
953 format!("Queued next: {}\n", path_str)
954 }
955 _ => {
956 let was_empty = q.is_empty();
957 let was_playing = audio.is_playing();
958 q.add_track(path.clone());
959 if was_empty && !was_playing {
960 let track = Track::from_path(path.clone());
961 audio.play(path);
962 send_now_playing(scrobbler, &track);
963 if let Ok(mut s) = scrobble_state.lock() {
964 s.start(track.clone());
938 } 965 }
939 format!( 966 let fmt =
940 "Queued next: {} tracks from {}\n", 967 Config::load().ok().and_then(|c| c.display_format.clone());
941 files.len(), 968 notification::notify_track(&track, fmt.as_deref());
942 path_str 969 format!("Playing: {}\n", path_str)
943 ) 970 } else {
971 format!("Queued: {}\n", path_str)
944 } 972 }
945 _ => { 973 }
946 let was_playing = audio.is_playing(); 974 }
947 for file in &files { 975 } else {
948 q.add_track(file.clone()); 976 "Error accessing queue\n".to_string()
949 } 977 }
950 if was_empty && !was_playing { 978 } else if path.is_dir() {
951 q.shuffle_initial(); 979 match find_audio_in_dir(&path) {
952 if let Some(track) = q.current() { 980 Some(files) if !files.is_empty() => {
981 if let Ok(mut q) = queue.lock() {
982 let was_empty = q.is_empty();
983 match position {
984 "now" => {
985 if let Ok(mut s) = scrobble_state.lock() {
986 try_scrobble_current(scrobbler, &mut s);
987 }
988 for file in files.iter().rev() {
989 q.insert_after_current(file.clone());
990 }
991 if !was_empty {
992 let new_pos = q.position() + 1;
993 q.set_position(new_pos);
994 }
995 if let Some(track) = q.track_at(q.position()) {
953 audio.play(track.path.clone()); 996 audio.play(track.path.clone());
954 send_now_playing(scrobbler, track); 997 send_now_playing(scrobbler, track);
955 if let Ok(mut s) = scrobble_state.lock() { 998 if let Ok(mut s) = scrobble_state.lock() {
@@ -960,18 +1003,57 @@ fn process_command(
960 .and_then(|c| c.display_format.clone()); 1003 .and_then(|c| c.display_format.clone());
961 notification::notify_track(track, fmt.as_deref()); 1004 notification::notify_track(track, fmt.as_deref());
962 } 1005 }
1006 format!(
1007 "Playing now: {} tracks from {}\n",
1008 files.len(),
1009 path_str
1010 )
1011 }
1012 "next" => {
1013 for file in files.iter().rev() {
1014 q.insert_after_current(file.clone());
1015 }
1016 format!(
1017 "Queued next: {} tracks from {}\n",
1018 files.len(),
1019 path_str
1020 )
1021 }
1022 _ => {
1023 let was_playing = audio.is_playing();
1024 for file in &files {
1025 q.add_track(file.clone());
1026 }
1027 if was_empty && !was_playing {
1028 q.shuffle_initial();
1029 if let Some(track) = q.current() {
1030 audio.play(track.path.clone());
1031 send_now_playing(scrobbler, track);
1032 if let Ok(mut s) = scrobble_state.lock() {
1033 s.start(track.clone());
1034 }
1035 let fmt = Config::load()
1036 .ok()
1037 .and_then(|c| c.display_format.clone());
1038 notification::notify_track(track, fmt.as_deref());
1039 }
1040 }
1041 format!(
1042 "Queued {} tracks from: {}\n",
1043 files.len(),
1044 path_str
1045 )
963 } 1046 }
964 format!("Queued {} tracks from: {}\n", files.len(), path_str)
965 } 1047 }
1048 } else {
1049 "Error accessing queue\n".to_string()
966 } 1050 }
967 } else {
968 "Error accessing queue\n".to_string()
969 } 1051 }
1052 _ => format!("Error: No audio files found in '{}'\n", path_str),
970 } 1053 }
971 _ => format!("Error: No audio files found in '{}'\n", path_str), 1054 } else {
1055 format!("File not found: {}\n", path_str)
972 } 1056 }
973 } else {
974 format!("File not found: {}\n", path_str)
975 } 1057 }
976 } 1058 }
977 _ if cmd == "volume" => { 1059 _ if cmd == "volume" => {