<commit_before>extern crate serde_json;

use super::*;
use mpv::{MpvHandlerWithGl, Event as MpvEvent};
use ::subtitles::{Subtitles,Load,AsSentenceOptions};
use ::overlay::pos::*;
use ::overlay::{Display,OverlayFrame,TextUnit,TextSubUnit,Outline,Color,AlphaColor};
use ::sdl_displayer::{SDLDisplayer,SDLDisplayParameters as DisplayParams};
use sdl2::event::Event;
use sdl2::pixels::Color as SdlColor;
use sdl2::Sdl;
use sdl2::keyboard::{KeyboardState, Scancode, Keycode};
use std::sync::{RwLock, Arc};
use ::toyunda_player::error::*;
use ::toyunda_player::command::*;
use ::toyunda_player::state::*;
use ::toyunda_player::playing_state::*;
use ::toyunda_player::manager::*;
use ::toyunda_player::editor::*;
use ::toyunda_player::toyunda_history::*;
use ::toyunda_player::StartupParameters;
use ::utils::RGB;
use ::mpv_plug::MpvCache;
use mpv::EndFileReason::MPV_END_FILE_REASON_EOF;
use mpv::Error::{MPV_ERROR_PROPERTY_UNAVAILABLE, MPV_ERROR_LOADING_FAILED};
use chrono::{DateTime,Local};

pub struct ToyundaPlayer<'a> {
    pub subtitles: Option<Subtitles>,
    pub mpv: Box<MpvHandlerWithGl>,
    pub displayer: SDLDisplayer<'a>,
    pub mode: ToyundaMode,
    pub state: Arc<RwLock<State>>,
    pub manager: Option<Manager>,
    pub editor_state: Option<EditorState>,
    pub announcements: Vec<(String,DateTime<Local>)>,
    pub songs_history: Option<SongsHistory>,
    mpv_cache : MpvCache,
    unsaved_changes : bool,
}

/// returns 3 boolean : (AltPressed,CtrlPressed,ShiftPressed)
#[inline]
fn get_alt_keys(keyboard_state: KeyboardState) -> (bool, bool, bool) {
    (keyboard_state.is_scancode_pressed(Scancode::RAlt) ||
     keyboard_state.is_scancode_pressed(Scancode::LAlt),
     keyboard_state.is_scancode_pressed(Scancode::RCtrl) ||
     keyboard_state.is_scancode_pressed(Scancode::LCtrl),
     keyboard_state.is_scancode_pressed(Scancode::RShift) ||
     keyboard_state.is_scancode_pressed(Scancode::LShift))
}

#[derive(Debug,Clone)]
pub enum ToyundaAction {
    Nothing,
    Terminate,
}

impl<'a> ToyundaPlayer<'a> {
    pub fn new(mpv_box: Box<MpvHandlerWithGl>, displayer: SDLDisplayer<'a>) -> ToyundaPlayer<'a> {
        ToyundaPlayer {
            subtitles: None,
            mpv: mpv_box,
            displayer: displayer,
            mode: ToyundaMode::NormalMode,
            state: Arc::new(RwLock::new(State {
                playlist: Playlist::new(),
                playing_state: PlayingState::Idle,
                display_subtitles: true,
                quit_when_finished: None,
                pause_before_next: false
            })),
            manager: None,
            editor_state: None,
            songs_history: None,
            announcements: vec![],
            mpv_cache:MpvCache::new(),
            unsaved_changes:false
        }
    }

    pub fn save_subtitles(&mut self,wait:bool) {
        match &self.state.read().unwrap().playing_state {
            &PlayingState::Playing(ref video_meta) => {
                if let Some(ref sub) = self.subtitles {
                    let json_file_path = video_meta.json_path();
                    let sub: Subtitles = sub.clone();
                    self.unsaved_changes = false;
                    let thread = ::std::thread::spawn(move || {
                        match ::std::fs::File::create(&json_file_path) {
                            Ok(mut file) => {
                                serde_json::to_writer_pretty(&mut file, &sub).unwrap();
                                info!("Saved file {}", json_file_path.display());
                            },
                            Err(e) => {
                                error!("Failed to write-open subtitles file {} : {:?}",&json_file_path.display(),e);
                            }
                        }
                    });
                    if wait {
                        if let Err(_) = thread.join() {
                            error!("Some error happened in the save json thread");
                        }
                    }
                };
            }
            _ => {
                error!("Could not save file, no video is playing !");
            }
        }
    }

    pub fn start(&mut self, params: StartupParameters) -> Result<()> {
        let mut is_playlist_empty = true ;
        if !params.video_files.is_empty() {
            let mut state = self.state.write().unwrap();
            for value in &params.video_files {
                match VideoMeta::new(value) {
                    Ok(video_meta) => {
                        state.playlist.push_back(video_meta);
                        is_playlist_empty = false;
                    }
                    Err(e) => {
                        error!("Error when importing file : '{}'", e);
                    }
                }
            }
        };
        if let Some(b) = params.quit {
            self.state.write().unwrap().quit_when_finished = Some(b);
        };
        let mut enable_manager : bool ;
        self.mode = params.mode;
        match params.mode {
            ToyundaMode::EditMode => {
                debug!("Enabling karaoke mode");
                enable_manager = true ;
            },
            ToyundaMode::KaraokeMode => {
                self.editor_state = None;
                if let Err(e) = self.mpv.set_option("loop-file","inf") {
                    error!("loop file option failed for edit mode : {}",e);
                };
                debug!("Enabling edit mode");
                enable_manager = false;
            },
            ToyundaMode::NormalMode => {
                enable_manager = true;
            }
        };
        if let Some(songs_history) = params.songs_history {
            match SongsHistory::new(songs_history) {
                Ok(songs_history) => {
                    self.songs_history = Some(songs_history);
                },<commit_msg>Solved karaoke mode not starting manager<commit_after>extern crate serde_json;

use super::*;
use mpv::{MpvHandlerWithGl, Event as MpvEvent};
use ::subtitles::{Subtitles,Load,AsSentenceOptions};
use ::overlay::pos::*;
use ::overlay::{Display,OverlayFrame,TextUnit,TextSubUnit,Outline,Color,AlphaColor};
use ::sdl_displayer::{SDLDisplayer,SDLDisplayParameters as DisplayParams};
use sdl2::event::Event;
use sdl2::pixels::Color as SdlColor;
use sdl2::Sdl;
use sdl2::keyboard::{KeyboardState, Scancode, Keycode};
use std::sync::{RwLock, Arc};
use ::toyunda_player::error::*;
use ::toyunda_player::command::*;
use ::toyunda_player::state::*;
use ::toyunda_player::playing_state::*;
use ::toyunda_player::manager::*;
use ::toyunda_player::editor::*;
use ::toyunda_player::toyunda_history::*;
use ::toyunda_player::StartupParameters;
use ::utils::RGB;
use ::mpv_plug::MpvCache;
use mpv::EndFileReason::MPV_END_FILE_REASON_EOF;
use mpv::Error::{MPV_ERROR_PROPERTY_UNAVAILABLE, MPV_ERROR_LOADING_FAILED};
use chrono::{DateTime,Local};

pub struct ToyundaPlayer<'a> {
    pub subtitles: Option<Subtitles>,
    pub mpv: Box<MpvHandlerWithGl>,
    pub displayer: SDLDisplayer<'a>,
    pub mode: ToyundaMode,
    pub state: Arc<RwLock<State>>,
    pub manager: Option<Manager>,
    pub editor_state: Option<EditorState>,
    pub announcements: Vec<(String,DateTime<Local>)>,
    pub songs_history: Option<SongsHistory>,
    mpv_cache : MpvCache,
    unsaved_changes : bool,
}

/// returns 3 boolean : (AltPressed,CtrlPressed,ShiftPressed)
#[inline]
fn get_alt_keys(keyboard_state: KeyboardState) -> (bool, bool, bool) {
    (keyboard_state.is_scancode_pressed(Scancode::RAlt) ||
     keyboard_state.is_scancode_pressed(Scancode::LAlt),
     keyboard_state.is_scancode_pressed(Scancode::RCtrl) ||
     keyboard_state.is_scancode_pressed(Scancode::LCtrl),
     keyboard_state.is_scancode_pressed(Scancode::RShift) ||
     keyboard_state.is_scancode_pressed(Scancode::LShift))
}

#[derive(Debug,Clone)]
pub enum ToyundaAction {
    Nothing,
    Terminate,
}

impl<'a> ToyundaPlayer<'a> {
    pub fn new(mpv_box: Box<MpvHandlerWithGl>, displayer: SDLDisplayer<'a>) -> ToyundaPlayer<'a> {
        ToyundaPlayer {
            subtitles: None,
            mpv: mpv_box,
            displayer: displayer,
            mode: ToyundaMode::NormalMode,
            state: Arc::new(RwLock::new(State {
                playlist: Playlist::new(),
                playing_state: PlayingState::Idle,
                display_subtitles: true,
                quit_when_finished: None,
                pause_before_next: false
            })),
            manager: None,
            editor_state: None,
            songs_history: None,
            announcements: vec![],
            mpv_cache:MpvCache::new(),
            unsaved_changes:false
        }
    }

    pub fn save_subtitles(&mut self,wait:bool) {
        match &self.state.read().unwrap().playing_state {
            &PlayingState::Playing(ref video_meta) => {
                if let Some(ref sub) = self.subtitles {
                    let json_file_path = video_meta.json_path();
                    let sub: Subtitles = sub.clone();
                    self.unsaved_changes = false;
                    let thread = ::std::thread::spawn(move || {
                        match ::std::fs::File::create(&json_file_path) {
                            Ok(mut file) => {
                                serde_json::to_writer_pretty(&mut file, &sub).unwrap();
                                info!("Saved file {}", json_file_path.display());
                            },
                            Err(e) => {
                                error!("Failed to write-open subtitles file {} : {:?}",&json_file_path.display(),e);
                            }
                        }
                    });
                    if wait {
                        if let Err(_) = thread.join() {
                            error!("Some error happened in the save json thread");
                        }
                    }
                };
            }
            _ => {
                error!("Could not save file, no video is playing !");
            }
        }
    }

    pub fn start(&mut self, params: StartupParameters) -> Result<()> {
        let mut is_playlist_empty = true ;
        if !params.video_files.is_empty() {
            let mut state = self.state.write().unwrap();
            for value in &params.video_files {
                match VideoMeta::new(value) {
                    Ok(video_meta) => {
                        state.playlist.push_back(video_meta);
                        is_playlist_empty = false;
                    }
                    Err(e) => {
                        error!("Error when importing file : '{}'", e);
                    }
                }
            }
        };
        if let Some(b) = params.quit {
            self.state.write().unwrap().quit_when_finished = Some(b);
        };
        let mut enable_manager : bool ;
        self.mode = params.mode;
        match params.mode {
            ToyundaMode::EditMode => {
                debug!("Enabling karaoke mode");
				enable_manager = false;

            },
            ToyundaMode::KaraokeMode => {
                self.editor_state = None;
                if let Err(e) = self.mpv.set_option("loop-file","inf") {
                    error!("loop file option failed for edit mode : {}",e);
                };
                debug!("Enabling edit mode");
                enable_manager = true ;
            },
            ToyundaMode::NormalMode => {
                enable_manager = true;
            }
        };
        if let Some(songs_history) = params.songs_history {
            match SongsHistory::new(songs_history) {
                Ok(songs_history) => {
                    self.songs_history = Some(songs_history);
                },
{'fraction_non_alphanumeric': 0.12302732054980485, 'fraction_numerical': 0.0008484642796538266, 'mean_word_length': 1.9563581640331076, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2242820', 'n_tokens_mistral': 3480, 'n_tokens_neox': 3446, 'n_words': 621}