use diesel::prelude::*;
use diesel::pg::PgConnection;
use self::models::{Video, Room};
use std::{thread, time};
use schema;
use models;
use std::time::SystemTime;
use std::collections::HashMap;
use std::sync::Mutex;
use establish_connection;
lazy_static! {
static ref PLAYLIST_THREADS: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());
}
pub fn play_current_video<'a>(conn: &PgConnection, room_name: Option<String>) -> bool {
use self::schema::videos::dsl::*;
let video;
match room_name.clone() {
Some(room_name) => {
video = videos
.filter(played.eq(false))
.filter(room.eq(room_name.to_lowercase()))
.order(added_on)
.first::<Video>(conn);
},
None => {
video = videos
.filter(played.eq(false))
.filter(room.is_null())
.order(added_on)
.first::<Video>(conn);
}
};
match video {
Ok(video) => {
let video_duration = time::Duration::from_secs(duration_to_seconds(&video.duration));
super::diesel::update(&video)
.set(played_on.eq(SystemTime::now()))
.execute(conn)
.expect("Unable to start playing the current video.");
println!("Start playing: [{}] With ID: [{}] and duration: [{}] in room: [{:?}].",
&video.title,
&video.id,
&video.duration,
room_name);
let thread_name;
match room_name.clone() {
Some(room_name) => {
thread_name = room_name;
},
None => {
thread_name = "".to_string();
}
}
PLAYLIST_THREADS.lock().unwrap().insert(thread_name.clone(), "play".to_string());
let now = SystemTime::now();
let mut playing: bool = true;
while playing {
match now.elapsed() {
Ok(elapsed) => {
if elapsed.as_secs() >= video_duration.as_secs() {
playing = false;
}
},
Err(e) => {
playing = false;
println!("SystemTime elapsed error: {}", e);
}
}
let thread_name = thread_name.clone();
match PLAYLIST_THREADS.lock().unwrap().get(&thread_name) {
Some(thread_name) => {
if &thread_name[..] != "play" {
playing = false;
}
},
None => {
PLAYLIST_THREADS.lock().unwrap().insert(thread_name, "play".to_string());
}
}
thread::sleep(time::Duration::from_millis(500));
}
println!("Done playing [{}] from room [{:?}]", &video.title, room_name);
super::diesel::update(&video)
.set(played.eq(true))
.execute(conn)
.expect("Unable to mark the current video as played.");
return true
},
Err(_) => return false,
};
}
pub fn play_video_thread<'a>(room: Option<String>) {
let thread_name;
match room.clone() {
Some(room) => {
thread_name = room;
},
None => {
thread_name = "".to_string();
}
}
thread::Builder::new()
.name(thread_name)
.spawn(move || {
let mut result;
let c = establish_connection();
println!("Room name: {:?}", room.clone());
loop {
result = play_current_video(&c, room.clone());
if ! result {
thread::sleep(time::Duration::from_secs(1));
}
}
})
.unwrap();
}
pub fn init_playlist_listener<'a>() {
use self::schema::rooms::dsl::*;
let conn = establish_connection();
let result = rooms.load::<Room>(&conn)
.expect("Error loading videos");
for room in result {
PLAYLIST_THREADS.lock().unwrap().insert(room.name.clone(),"play".to_string());
play_video_thread(Some(room.name));
}
PLAYLIST_THREADS.lock().unwrap().insert("".to_string(),"play".to_string());
play_video_thread(None);
}
pub fn duration_to_seconds(duration: &String) -> u64 {
let v: Vec<&str> = duration.split(|c: char| !c.is_numeric()).collect();
let mut index: u32 = 0;
let mut tmp: i32 = 0;
for i in (0..v.len()).rev() {
if ! v[i].is_empty() {
tmp += v[i].parse::<i32>().unwrap() * (60i32.pow(index));
index += 1;
}
}
return tmp as u64
}
pub fn skip_video(room: Option<String>) {
let room_name;
match room.clone() {
Some(room) => {
room_name = room;
},
None => {
room_name = "".to_string();
}
}
let mut map = PLAYLIST_THREADS.lock().unwrap();
println!("Skipping a song in room [{}]", room_name);
if let Some(mut_key) = map.get_mut(&room_name) {
*mut_key = "skip".to_string();
}
}