<commit_before>use hyper::{Body, Client, Method, Request};
#[allow(unused)]
use log::{error, info, warn};

use serde_json::json;
use std::fs;
use std::process::exit;

use librespot::core::authentication::Credentials;
use librespot::core::config::SessionConfig;
use librespot::core::keymaster;
use librespot::core::session::Session;
use librespot::core::spotify_id::SpotifyId;

use librespot::playback::audio_backend;
use librespot::playback::config::{AudioFormat, PlayerConfig};
use librespot::playback::player::{Player, PlayerEvent};

const VERSION: &'static str = concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION"));

const SCOPES: &str = "user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read,user-read-recently-played";

#[cfg(debug_assertions)]
const DEBUGMODE: bool = true;
#[cfg(not(debug_assertions))]
const DEBUGMODE: bool = false;

pub fn check(version_info: String) {
    println!("ok {}", version_info.to_string());

    let capabilities = json!({
        "version": env!("CARGO_PKG_VERSION").to_string(),
        "autoplay": true,
        "lms-auth": true,
        "volume-normalisation": true,
        "debug": DEBUGMODE,
        "ogg-direct": true,
        "save-token": true,
        "podcasts": true,
        "zeroconf-port": true
    });

    println!("{}", capabilities.to_string());
    exit(0);
}

// inspired by examples/get_token.rs
pub async fn get_token(
    client_id: Option<String>,
    scopes: Option<String>,
    save_token: Option<String>,
    last_credentials: Option<Credentials>,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            if let Some(client_id) = client_id {
                let scopes = scopes.unwrap_or(SCOPES.to_string());

                match Session::connect(session_config, last_credentials, None).await {
                    Ok(session) => {
                        match keymaster::get_token(&session, &client_id, &scopes).await {
                            Ok(token) => {
                                let json_token = json!({
                                    "accessToken": token.access_token.to_string(),
                                    "expiresIn": token.expires_in,
                                });

                                if let Some(save_token) = save_token {
                                    fs::write(save_token.to_string(), format!("{}", json_token))
                                        .expect("Can't write token file");
                                } else {
                                    println!("{}", json_token);
                                }
                            }
                            Err(error) => {
                                error!("Failed to fetch token: {:?}", error);
                                println!("{{ \"error\": \"Failed to get token.\" }}");
                            }
                        }
                    }
                    Err(error) => {
                        error!("Failed to create session: {:?}", error);
                        println!("{{ \"error\": \"Failed to create session.\" }}");
                    }
                }
            } else {
                println!("Use --client-id to provide a CLIENT_ID");
            }
        }
        None => {
            println!("Missing credentials");
        }
    }
}

// inspired by examples/play.rs
pub async fn play_track(
    track_id: String,
    start_position: u32,
    last_credentials: Option<Credentials>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            let backend = audio_backend::find(None).unwrap();
            let audio_format = AudioFormat::default();

            let track = SpotifyId::from_uri(
                track_id
                    .replace("spotty://", "spotify:track:")
                    .replace("://", ":")
                    .as_str(),
            );

            match track {
                Ok(track) => match Session::connect(session_config, last_credentials, None).await {
                    Ok(session) => {
                        let (mut player, _) =
                            Player::new(player_config, session, None, move || {
                                backend(None, audio_format)<commit_msg>Report errors back to LMS, unify response handling.<commit_after>use hyper::{Body, Client, Method, Request};
#[allow(unused)]
use log::{error, info, warn};

use serde_json::{json, Value};
use std::fs;
use std::process::exit;

use librespot::core::authentication::Credentials;
use librespot::core::config::SessionConfig;
use librespot::core::keymaster;
use librespot::core::session::Session;
use librespot::core::spotify_id::SpotifyId;

use librespot::playback::audio_backend;
use librespot::playback::config::{AudioFormat, PlayerConfig};
use librespot::playback::player::{Player, PlayerEvent};

const VERSION: &'static str = concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION"));

const SCOPES: &str = "user-read-private,playlist-read-private,playlist-read-collaborative,playlist-modify-public,playlist-modify-private,user-follow-modify,user-follow-read,user-library-read,user-library-modify,user-top-read,user-read-recently-played";

#[cfg(debug_assertions)]
const DEBUGMODE: bool = true;
#[cfg(not(debug_assertions))]
const DEBUGMODE: bool = false;

pub fn check(version_info: String) {
    println!("ok {}", version_info.to_string());

    let capabilities = json!({
        "version": env!("CARGO_PKG_VERSION").to_string(),
        "autoplay": true,
        "lms-auth": true,
        "volume-normalisation": true,
        "debug": DEBUGMODE,
        "ogg-direct": true,
        "save-token": true,
        "podcasts": true,
        "zeroconf-port": true
    });

    println!("{}", capabilities.to_string());
    exit(0);
}

// inspired by examples/get_token.rs
pub async fn get_token(
    client_id: Option<String>,
    scopes: Option<String>,
    save_token: Option<String>,
    last_credentials: Option<Credentials>,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            if let Some(client_id) = client_id {
                let scopes = scopes.unwrap_or(SCOPES.to_string());

                match Session::connect(session_config, last_credentials, None).await {
                    Ok(session) => {
                        match keymaster::get_token(&session, &client_id, &scopes).await {
                            Ok(token) => {
                                write_response(
                                    json!({
                                        "accessToken": token.access_token.to_string(),
                                        "expiresIn": token.expires_in,
                                    }),
                                    save_token,
                                );
                            }
                            Err(error) => {
                                error!("Failed to fetch token: {:?}", error);
                                write_response(
                                    json!({
                                        "error": "Failed to get access token."
                                    }),
                                    save_token,
                                );
                            }
                        }
                    }
                    Err(error) => {
                        error!("Failed to create session: {:?}", error);
                        write_response(
                            json!({
                                "error": "Failed to create session or connect to servers."
                            }),
                            save_token,
                        );
                    }
                }
            } else {
                println!("Use --client-id to provide a CLIENT_ID");
            }
        }
        None => {
            println!("Missing credentials");
        }
    }
}

fn write_response(json_token: Value, save_token: Option<String>) {
    if let Some(save_token) = save_token {
        fs::write(save_token.to_string(), json_token.to_string()).expect("Can't write token file");
    } else {
        println!("{}", json_token);
    }
}

// inspired by examples/play.rs
pub async fn play_track(
    track_id: String,
    start_position: u32,
    last_credentials: Option<Credentials>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
) {
    match last_credentials {
        Some(last_credentials) => {
            let backend = audio_backend::find(None).unwrap();
            let audio_format = AudioFormat::default();

            let track = SpotifyId::from_uri(
                track_id
                    .replace("spotty://", "spotify:track:")
                    .replace("://", ":")
                    .as_str(),
            );

            match track {
                Ok(track) => match Session::connect(session_config, last_credentials, None).await {
                    Ok(session) => {
                        let (mut player, _) =
                            Player::new(player_config, session, None, move || {
                                backend(None, audio_format)
{'fraction_non_alphanumeric': 0.12789345735123137, 'fraction_numerical': 0.0006341824331466019, 'mean_word_length': 1.6691114245416079, 'pattern_counts': {'":': 30, '<': 14, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5344334', 'n_tokens_mistral': 2576, 'n_tokens_neox': 2515, 'n_words': 475}