Skip to content
Snippets Groups Projects
Select Git revision
  • 5d9f1d444ff92cd28f21c627fc58edb7ceef1cc0
  • main default protected
2 results

config.ts

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    client.rs 9.48 KiB
    use futures_signals::signal::Mutable;
    use std::net::TcpStream;
    use tungstenite::{Message, WebSocket};
    use uuid::Uuid;
    
    use crate::song::ApiSong;
    use crate::song::ApiSongState;
    use crate::song::Song;
    use crate::websockets_command::Command;
    
    pub fn handle_client(websocket: &mut WebSocket<TcpStream>, playlist: &Mutable<Vec<Song>>) -> () {
        println!("New client connected!");
    
        loop {
            if !websocket.can_write() {
                println!("Client connection lost!");
    
                break;
            }
    
            handle_client_command(websocket, playlist);
        }
    }
    
    fn handle_client_command(
        websocket: &mut WebSocket<TcpStream>,
        playlist: &Mutable<Vec<Song>>,
    ) -> () {
        let msg = websocket.read_message();
        if let Err(_) = msg {
            eprintln!("Error receiving websocket message!");
            return;
        }
        let msg = msg.unwrap();
    
        match msg {
            Message::Text(json) => {
                let cmd = serde_json::from_str(&json);
                if let Err(_) = cmd {
                    eprintln!("Invalid command json!");
                    return;
                }
                let cmd = cmd.unwrap();
    
                match cmd {
                    Command::Add { url } => {
                        if let Some(host) = url.host_str() {
                            if host != "youtube.com"
                                && host != "www.youtube.com"
                                && host != "youtu.be"
                                && host != "www.youtu.be"
                            {
                                eprintln!("Not a youtube url!");
                                return;
                            }
                        } else {
                            eprintln!("Not a youtube url!");
                            return;
                        }
    
                        if let Some(path_segments) = url.path_segments().map(|c| c.collect::<Vec<_>>())
                        {
                            if path_segments[0] != "watch" && path_segments[0] != "v" {
                                eprintln!("Not a youtube video url!");
                                return;
                            }
                        } else {
                            eprintln!("Not a youtube video url!");
                            return;
                        }
    
                        let mut playlist = playlist.lock_mut();
                        (*playlist).push(Song::Queued {
                            uuid: Uuid::new_v4(),
                            url: url.clone(),
                        });
                        drop(playlist);
    
                        println!("Added song with url {}!", url);
                    }
                    Command::Remove { uuid } => {
                        let uuid = Uuid::parse_str(&uuid);
                        if let Err(_) = uuid {
                            eprintln!("Invalid uuid in command 'Remove'!");
                            return;
                        }
                        let uuid = uuid.unwrap();
    
                        let mut playlist = playlist.lock_mut();
                        if let Some(index) = (*playlist).iter().position(|song| song.equals_uuid(&uuid))
                        {
                            playlist.remove(index);
    
                            println!("Skipped song with uuid {}!", uuid);
                        } else {
                            eprintln!("No song with uuid {} to skip!", uuid);
                        }
                        drop(playlist);
                    }
                    Command::Playlist => {
                        let playlist = playlist.lock_ref();
                        let playlist_api = generate_playlist_api(&playlist);
                        drop(playlist);
    
                        send_playlist_api(websocket, &playlist_api);
                    }
                }
            }
            Message::Close(_) => {
                println!("WebSocket connection closed by peer!");
            }
            _ => {}
        }
    }
    
    fn generate_playlist_api(playlist: &Vec<Song>) -> Vec<ApiSong> {
        playlist
            .iter()
            .map(|song| match song {
                Song::Queued { uuid, url, .. } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: None,
                    artist: None,
                    artist_url: None,
                    length: None,
                    thumbnail_url: None,
                    state: ApiSongState::Queued,
                },
                Song::InfoFetching { uuid, url, .. } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: None,
                    artist: None,
                    artist_url: None,
                    length: None,
                    thumbnail_url: None,
                    state: ApiSongState::InfoFetching,
                },
                Song::InfoFetched {
                    uuid,
                    url,
                    title,
                    artist,
                    artist_url,
                    length,
                    thumbnail_file,
                    ..
                } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: title.to_owned(),
                    artist: artist.to_owned(),
                    artist_url: if let Some(artist_url) = artist_url {
                        Some(artist_url.to_string())
                    } else {
                        None
                    },
                    length: length.to_owned(),
                    thumbnail_url: thumbnail_file.to_owned(),
                    state: ApiSongState::InfoFetched,
                },
                Song::Downloading {
                    uuid,
                    url,
                    title,
                    artist,
                    artist_url,
                    length,
                    thumbnail_file,
                    ..
                } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: title.to_owned(),
                    artist: artist.to_owned(),
                    artist_url: if let Some(artist_url) = artist_url {
                        Some(artist_url.to_string())
                    } else {
                        None
                    },
                    length: length.to_owned(),
                    thumbnail_url: thumbnail_file.to_owned(),
                    state: ApiSongState::Downloading,
                },
                Song::Downloaded {
                    uuid,
                    url,
                    title,
                    artist,
                    artist_url,
                    length,
                    thumbnail_file,
                    ..
                } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: title.to_owned(),
                    artist: artist.to_owned(),
                    artist_url: if let Some(artist_url) = artist_url {
                        Some(artist_url.to_string())
                    } else {
                        None
                    },
                    length: length.to_owned(),
                    thumbnail_url: thumbnail_file.to_owned(),
                    state: ApiSongState::Downloaded,
                },
                Song::Converting {
                    uuid,
                    url,
                    title,
                    artist,
                    artist_url,
                    length,
                    thumbnail_file,
                    ..
                } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: title.to_owned(),
                    artist: artist.to_owned(),
                    artist_url: if let Some(artist_url) = artist_url {
                        Some(artist_url.to_string())
                    } else {
                        None
                    },
                    length: length.to_owned(),
                    thumbnail_url: thumbnail_file.to_owned(),
                    state: ApiSongState::Converting,
                },
                Song::Ready {
                    uuid,
                    url,
                    title,
                    artist,
                    artist_url,
                    length,
                    thumbnail_file,
                    ..
                } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: title.to_owned(),
                    artist: artist.to_owned(),
                    artist_url: if let Some(artist_url) = artist_url {
                        Some(artist_url.to_string())
                    } else {
                        None
                    },
                    length: length.to_owned(),
                    thumbnail_url: thumbnail_file.to_owned(),
                    state: ApiSongState::Ready,
                },
                Song::Playing {
                    uuid,
                    url,
                    title,
                    artist,
                    artist_url,
                    length,
                    thumbnail_file,
                    ..
                } => ApiSong {
                    uuid: uuid.to_string(),
                    url: url.to_string(),
                    title: title.to_owned(),
                    artist: artist.to_owned(),
                    artist_url: if let Some(artist_url) = artist_url {
                        Some(artist_url.to_string())
                    } else {
                        None
                    },
                    length: length.to_owned(),
                    thumbnail_url: thumbnail_file.to_owned(),
                    state: ApiSongState::Playing,
                },
            })
            .collect()
    }
    
    fn send_playlist_api(websocket: &mut WebSocket<TcpStream>, playlist_api: &Vec<ApiSong>) -> () {
        let playlist_json = serde_json::to_string(&playlist_api).unwrap();
    
        let msg = Message::text(playlist_json);
    
        if let Err(_) = websocket.write_message(msg) {
            eprintln!("Error sending websocket message!");
            return;
        }
    
        /* println!("Returned playlist contents!");
        for song in playlist_api {
            println!("{:?}", song);
        } */
    }