diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index e38f7da3b662..89afda8b41ff 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -62,37 +62,44 @@ ADMIN_VERB(play_direct_mob_sound, R_SOUND, "Play Direct Mob Sound", "Play a soun GLOBAL_VAR_INIT(web_sound_cooldown, 0) +// uses MUSIC_SERVER_URL in darkpack_config.txt to resolve via a remote PHP endpoint instead of local yt-dlp // APOC EDIT ADD ///Takes an input from either proc/play_web_sound or the request manager and runs it through yt-dlp and prompts the user before playing it to the server. /proc/web_sound(mob/user, input, credit) if(!check_rights(R_SOUND)) return - var/ytdl = CONFIG_GET(string/invoke_youtubedl) - if(!ytdl) - to_chat(user, span_boldwarning("yt-dlp was not configured, action unavailable"), confidential = TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value + // APOC EDIT CHANGE START + var/music_server = CONFIG_GET(string/music_server_url) + if(!music_server) + to_chat(user, span_boldwarning("php endpoint not configured! set music_server_url or revert your fork to use the traditional web_sound proc"), confidential = TRUE) return + // APOC EDIT CHANGE END var/web_sound_url = "" var/stop_web_sounds = FALSE var/list/music_extra_data = list() var/duration = 0 if(istext(input)) - var/shell_scrubbed_input = shell_url_scrub(input) - var/list/output = world.shelleo("[ytdl] --geo-bypass --format \"bestaudio\[ext=mp3]/best\[ext=mp4]\[height <= 360]/bestaudio\[ext=m4a]/bestaudio\[ext=aac]\" --dump-single-json --no-playlist -- \"[shell_scrubbed_input]\"") - var/errorlevel = output[SHELLEO_ERRORLEVEL] - var/stdout = output[SHELLEO_STDOUT] - var/stderr = output[SHELLEO_STDERR] - if(errorlevel) - to_chat(user, span_boldwarning("yt-dlp URL retrieval FAILED:"), confidential = TRUE) - to_chat(user, span_warning("[stderr]"), confidential = TRUE) + // APOC EDIT CHANGE START - (url stuff) + var/encoded = url_encode(input) + var/request_url = "[trim(music_server)]?url=[encoded]" + to_chat(user, span_notice("DEBUG: [request_url]"), confidential = TRUE) + var/datum/http_request/request = new() + request.prepare(RUSTG_HTTP_METHOD_GET, request_url, "", list("Content-Type" = "application/json")) + request.begin_async() + var/actual_timeout = REALTIMEOFDAY + 20 SECONDS + UNTIL(request.is_complete() || REALTIMEOFDAY > actual_timeout) + var/datum/http_response/http_response = request.into_response() + if(http_response.errored || http_response.status_code != 200) return var/list/data try - data = json_decode(stdout) + data = json_decode(http_response.body) catch(var/exception/e) - to_chat(user, span_boldwarning("yt-dlp JSON parsing FAILED:"), confidential = TRUE) - to_chat(user, span_warning("[e]: [stdout]"), confidential = TRUE) + to_chat(user, span_boldwarning("invalid JSON: [e]"), confidential = TRUE) return - if (data["url"]) - web_sound_url = data["url"] + if(!data || !data["url"]) + return + web_sound_url = data["url"] + // APOC EDIT CHANGE END var/title = "[data["title"]]" var/webpage_url = title if (data["webpage_url"]) @@ -145,7 +152,7 @@ GLOBAL_VAR_INIT(web_sound_cooldown, 0) if(client.prefs.read_preference(/datum/preference/numeric/volume/sound_midi) > 0) recipients += client recipients |= user.client - to_chat(recipients, fieldset_block("Now Playing: [span_bold(music_extra_data["title"])] by [span_bold(music_extra_data["artist"])]", jointext(to_chat_message, ""), "boxed_message")) + to_chat(recipients, fieldset_block("Now Playing: [span_bold(music_extra_data["title"])]", jointext(to_chat_message, ""), "boxed_message")) // APOC EDIT CHANGE - (remove the artist field since its almost always 'unknown') SSblackbox.record_feedback("nested tally", "played_url", 1, list("[user.ckey]", "[input]")) log_admin("[key_name(user)] played web sound: [input]") @@ -181,7 +188,7 @@ GLOBAL_VAR_INIT(web_sound_cooldown, 0) BLACKBOX_LOG_ADMIN_VERB("Play Internet Sound") ADMIN_VERB_CUSTOM_EXIST_CHECK(play_web_sound) - return !!CONFIG_GET(string/invoke_youtubedl) + return !!CONFIG_GET(string/music_server_url) // APOC EDIT CHANGE - (php endpoint url) ADMIN_VERB(play_web_sound, R_SOUND, "Play Internet Sound", "Play a given internet sound to all players.", ADMIN_CATEGORY_FUN) if(!CLIENT_COOLDOWN_FINISHED(GLOB, web_sound_cooldown)) diff --git a/config/config.txt b/config/config.txt index 429ccd48e217..f9b65cdd0ace 100644 --- a/config/config.txt +++ b/config/config.txt @@ -238,7 +238,7 @@ REQUEST_INTERNET_SOUND ## Request Internet Sound Allowed URL'S comma separated, urls here are the only sites allowed through Request Internet Sound, Add more to allow more, or remove to disallow. ## The Defaults here are all supported by yt-dlp ## Ensure . and / are escaped with \ -REQUEST_INTERNET_ALLOWED youtube\.com\/watch?v=,youtu\.be\/,soundcloud\.com\/,bandcamp\.com\/track\/ +REQUEST_INTERNET_ALLOWED youtube\.com\/watch\?v=,youtu\.be\/,soundcloud\.com\/,bandcamp\.com\/track\/ ## In-game features diff --git a/config/darkpack_config.txt b/config/darkpack_config.txt index c6398d2f61e7..d4391dd3f08b 100644 --- a/config/darkpack_config.txt +++ b/config/darkpack_config.txt @@ -59,6 +59,9 @@ LOG_STATS #HUMANITY_SUNLIGHT_RESISTANCE +## url that leads to a php endpoint where yt-dl runs. should return a json package including a url to the mp3 +#MUSIC_SERVER_URL https://vampire-freaks.com/api + #EXTRA_ISSUE_URLS https://github.com/DarkPack13/SecondCity ## Bool for if roleplay only merits/quirks are enabled diff --git a/modular_darkpack/master_files/code/controllers/configuration/entries/general.dm b/modular_darkpack/master_files/code/controllers/configuration/entries/general.dm index 37812cf0de04..96d68d610bcf 100644 --- a/modular_darkpack/master_files/code/controllers/configuration/entries/general.dm +++ b/modular_darkpack/master_files/code/controllers/configuration/entries/general.dm @@ -17,3 +17,7 @@ /datum/config_entry/flag/disable_ghost_looc default = TRUE + +// url for the alternate web_sound server. you can safely leave this alone if you want, vampire +/// e.g. https://vampire-freaks.com/api +/datum/config_entry/string/music_server_url // Not an existing override, bite me. diff --git a/tools/yt-dl/index.php b/tools/yt-dl/index.php new file mode 100644 index 000000000000..cd736f607a78 --- /dev/null +++ b/tools/yt-dl/index.php @@ -0,0 +1,73 @@ + 'no url']); + exit; +} + +if (!preg_match('#^https?://#i', $url)) { + http_response_code(400); + echo json_encode(['error' => 'must use http or https']); + exit; +} + +// dont rely on this, you may still need to fix permissions depending on your setup. www-data my beloathed +if (!is_dir(CACHE_DIR)) { + mkdir(CACHE_DIR, 0755, true); +} + +$escaped = escapeshellarg($url); +$cookies = __DIR__ . '/youtube_cookies.txt'; // use any number of browser plugins to get a cookies file. i used a firefox one called 'cookies.txt'. goes in the same folder as index.php +$cookies_arg = file_exists($cookies) ? '--cookies ' . escapeshellarg($cookies) : ''; +$meta_json = shell_exec(YTDLP . " $cookies_arg --dump-single-json --no-playlist -- $escaped 2>/tmp/errorrr.log"); // 'cat /tmp/errorrr.log' on linux. just incase you need it + +if (!$meta_json) { + http_response_code(500); + echo json_encode(['error' => 'yt-dlp returned nothing']); + exit; +} + +$meta = json_decode($meta_json, true); + +if (!$meta || empty($meta['id'])) { + http_response_code(500); + echo json_encode(['error' => 'dont know what the hell it gave us']); + exit; +} + +$id = preg_replace('/[^a-zA-Z0-9_\-]/', '', $meta['id']); +$filename = $id . '.mp3'; // OGGs are smaller but sound like garbage. YMMV +$filepath = CACHE_DIR . '/' . $filename; +$file_url = CACHE_URL . '/' . $filename; + +if (!file_exists($filepath)) { + $out_template = escapeshellarg(CACHE_DIR . '/%(id)s.%(ext)s'); + shell_exec(YTDLP . " $cookies_arg --geo-bypass --extract-audio --audio-format mp3 --audio-quality 0 --no-playlist --output $out_template -- $escaped 2>/tmp/ytdlp_error.log"); + + if (!file_exists($filepath)) { + http_response_code(500); + echo json_encode(['error' => 'download failed. file was probably gigantic.']); + exit; + } +} + +// most youtube URLs have the artist name in the title, so the artist field is mostly useless here +echo json_encode([ + 'url' => $file_url, + 'title' => $meta['title'] ?? 'Unknown', + 'artist' => $meta['artist'] ?? 'Unknown', + 'album' => $meta['album'] ?? 'Unknown', + 'duration' => $meta['duration'] ?? 0, + 'webpage_url' => $meta['webpage_url'] ?? $url, + 'upload_date' => $meta['upload_date'] ?? '', +]);