Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 25 additions & 18 deletions code/modules/admin/verbs/playsound.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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"])
Expand Down Expand Up @@ -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]")
Expand Down Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion config/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions config/darkpack_config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
73 changes: 73 additions & 0 deletions tools/yt-dl/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
header('Content-Type: application/json');

define('YTDLP', '/usr/local/bin/yt-dlp');
define('CACHE_DIR', __DIR__ . '/cache');

// using a separate cache folder than the index file is good for tidiness
// this index.php file, in this example, should be located at your-website-url.com/api
define('CACHE_URL', 'https://your-website-url.com/api/cache');
$url = $_GET['url'] ?? '';

if (!$url) {
http_response_code(400);
echo json_encode(['error' => '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'] ?? '',
]);
Loading