Allows MP3 files to be uploaded to the TGchat player - renames play internet sound (#28575)

* first commit

* review

* review again

* renames adds alert

* updates alert

---------

Co-authored-by: Bmon <no@email.com>
This commit is contained in:
Bm0n
2025-07-06 17:45:32 -04:00
committed by GitHub
parent 69ce6aee7f
commit dc529f084f
3 changed files with 125 additions and 96 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ GLOBAL_LIST_INIT(admin_verbs_sounds, list(
/client/proc/play_intercomm_sound,
/client/proc/stop_global_admin_sounds,
/client/proc/stop_sounds_global,
/client/proc/play_web_sound
/client/proc/play_sound_tgchat
))
GLOBAL_LIST_INIT(admin_verbs_event, list(
/client/proc/object_talk,
+124 -93
View File
@@ -17,9 +17,12 @@ GLOBAL_LIST_EMPTY(sounds_cache)
/client/proc/play_sound(S as sound)
set category = "Event"
set name = "Play Global Sound"
set name = "Legacy Play Global Sound"
if(!check_rights(R_SOUNDS)) return
if(alert("WARNING: Legacy Play Global Sound does not support CDN asset sending. Sounds will have to be sent directly to players, which may freeze the game for long durations. Are you SURE?", "Really use Legacy Play Global Sound?", "Yes", "No") == "No")
return
var/sound/uploaded_sound = sound(S, repeat = 0, wait = 1, channel = CHANNEL_ADMIN)
uploaded_sound.priority = 250
@@ -130,107 +133,135 @@ GLOBAL_LIST_EMPTY(sounds_cache)
var/client/C = M.client
C?.tgui_panel?.stop_music()
/client/proc/play_web_sound()
/client/proc/play_sound_tgchat()
set category = "Event"
set name = "Play Internet Sound"
set name = "Play Global Sound"
if(!check_rights(R_SOUNDS))
return
if(!GLOB.configuration.system.ytdlp_url)
to_chat(src, "<span class='boldwarning'>yt-dlp was not configured, action unavailable</span>") //Check config
var/sound_mode = tgui_alert(src, "Play a sound from which source?", "Select Source", list("Web", "Upload MP3"))
if(!sound_mode)
return
var/web_sound_input
var/asset_name
var/must_send_assets = FALSE
var/web_sound_url = ""
var/list/music_extra_data = list()
var/list/data = list()
var/web_sound_input = tgui_input_text(src, "Enter content URL (supported sites only, leave blank to stop playing)", "Play Internet Sound", null)
if(istext(web_sound_input))
var/web_sound_url = ""
var/stop_web_sounds = FALSE
var/list/music_extra_data = list()
if(length(web_sound_input))
web_sound_input = trim(web_sound_input)
if(findtext(web_sound_input, ":") && !findtext(web_sound_input, GLOB.is_http_protocol))
to_chat(src, "<span class='boldwarning'>Non-http(s) URIs are not allowed.</span>")
to_chat(src, "<span class='warning'>For yt-dlp shortcuts like ytsearch: please use the appropriate full url from the website.</span>")
return
// Prepare the body
var/list/request_body = list("url" = web_sound_input)
// Send the request off
var/datum/http_request/media_poll_request = new()
// The fact we are using GET with a body offends me
media_poll_request.prepare(RUSTLIBS_HTTP_METHOD_GET, GLOB.configuration.system.ytdlp_url, json_encode(request_body))
// Start it off and wait
media_poll_request.begin_async()
UNTIL(media_poll_request.is_complete())
var/datum/http_response/media_poll_response = media_poll_request.into_response()
if(media_poll_response.status_code == 200)
var/list/data
try
data = json_decode(media_poll_response.body)
catch(var/exception/e)
to_chat(src, "<span class='boldwarning'>yt-dlp JSON parsing FAILED:</span>")
to_chat(src, "<span class='warning'>[e]: [media_poll_response.body]</span>")
return
if(data["sound_url"])
web_sound_url = data["sound_url"]
var/title = "[data["title"]]"
var/webpage_url = title
if(data["webpage_url"])
webpage_url = "<a href=\"[data["webpage_url"]]\">[title]</a>"
music_extra_data["start"] = data["start"]
music_extra_data["end"] = data["end"]
music_extra_data["link"] = data["webpage_url"]
music_extra_data["title"] = data["title"]
var/res = tgui_alert(src, "Show the title of and link to this song to the players?\n[title]", "Show Info?", list("Yes", "No", "Cancel"))
switch(res)
if("Yes")
log_admin("[key_name(src)] played web sound: [web_sound_input]")
message_admins("[key_name(src)] played web sound: [web_sound_input]")
to_chat(world, "<span class='boldannounceooc'>[src.ckey] played: [webpage_url]</span>")
if("No")
music_extra_data["link"] = "Song Link Hidden"
music_extra_data["title"] = "Song Title Hidden"
music_extra_data["artist"] = "Song Artist Hidden"
log_admin("[key_name(src)] played web sound: [web_sound_input]")
message_admins("[key_name(src)] played web sound: [web_sound_input]")
to_chat(world, "<span class='boldannounceooc'>[src.ckey] played an internet sound</span>")
if("Cancel")
return
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Internet Sound")
else
to_chat(src, "<span class='boldwarning'>yt-dlp URL retrieval FAILED:</span>")
to_chat(src, "<span class='warning'>[media_poll_response.body]</span>")
else //pressed ok with blank
log_admin("[key_name(src)] stopped web sound")
message_admins("[key_name(src)] stopped web sound")
web_sound_url = null
stop_web_sounds = TRUE
if(web_sound_url && !findtext(web_sound_url, GLOB.is_http_protocol))
to_chat(src, "<span class='boldwarning'>BLOCKED: Content URL not using http(s) protocol</span>", confidential = TRUE)
to_chat(src, "<span class='warning'>The media provider returned a content URL that isn't using the HTTP or HTTPS protocol</span>", confidential = TRUE)
if(sound_mode == "Web")
if(!GLOB.configuration.system.ytdlp_url)
to_chat(src, "<span class='boldwarning'>yt-dlp was not configured, action unavailable</span>") //Check config
return
if(web_sound_url || stop_web_sounds)
for(var/mob/M in GLOB.player_list)
var/client/C = M.client
var/this_uid = M.client.UID()
if(stop_web_sounds)
C.tgui_panel?.stop_music()
web_sound_input = tgui_input_text(src, "Enter content URL", "Play Internet Sound", null)
if(!length(web_sound_input))
return
web_sound_input = trim(web_sound_input)
if(findtext(web_sound_input, ":") && !findtext(web_sound_input, GLOB.is_http_protocol))
to_chat(src, "<span class='boldwarning'>Non-http(s) URIs are not allowed.</span>")
to_chat(src, "<span class='warning'>For yt-dlp shortcuts like ytsearch: please use the appropriate full url from the website.</span>")
return
// Prepare the body
var/list/request_body = list("url" = web_sound_input)
// Send the request off
var/datum/http_request/media_poll_request = new()
// The fact we are using GET with a body offends me
media_poll_request.prepare(RUSTLIBS_HTTP_METHOD_GET, GLOB.configuration.system.ytdlp_url, json_encode(request_body))
// Start it off and wait
media_poll_request.begin_async()
UNTIL(media_poll_request.is_complete())
var/datum/http_response/media_poll_response = media_poll_request.into_response()
if(media_poll_response.status_code == 200)
try
data = json_decode(media_poll_response.body)
catch(var/exception/e)
to_chat(src, "<span class='boldwarning'>yt-dlp JSON parsing FAILED:</span>")
to_chat(src, "<span class='warning'>[e]: [media_poll_response.body]</span>")
return
else
to_chat(src, "<span class='boldwarning'>yt-dlp URL retrieval FAILED:</span>")
to_chat(src, "<span class='warning'>[media_poll_response.body]</span>")
return
else if(sound_mode == "Upload MP3")
if(GLOB.configuration.asset_cache.asset_transport == "simple")
if(tgui_alert(src, "WARNING: Your server is using simple asset transport. Sounds will have to be sent directly to players, which may freeze the game for long durations. Are you SURE?", "Really play direct sound?", list("Yes", "No")) != "Yes")
return
must_send_assets = TRUE
var/soundfile = input(src, "Choose an MP3 file to play", "Upload Sound") as null|file
if(!soundfile)
return
var/static/regex/only_extension = regex(@{"^.*\.([a-z0-9]{1,5})$"}, "gi")
var/extension = only_extension.Replace("[soundfile]", "$1")
if(!length(extension) || extension != "mp3")
to_chat(src, "<span class='boldwarning'>Invalid filename extension.</span>")
return
var/static/playsound_notch = 1
asset_name = "admin_sound_[playsound_notch++].[extension]"
SSassets.transport.register_asset(asset_name, soundfile)
log_admin("[key_name_admin(src)] uploaded admin sound '[soundfile]' to asset transport.")
message_admins("[key_name_admin(src)] uploaded admin sound '[soundfile]' to asset transport.")
var/static/regex/remove_extension = regex(@{"\.[a-z0-9]+$"}, "gi")
data["title"] = remove_extension.Replace("[soundfile]", "")
data["sound_url"] = SSassets.transport.get_asset_url(asset_name)
web_sound_input = "[soundfile]"
if(data["sound_url"])
web_sound_url = data["sound_url"]
var/title = "[data["title"]]"
var/webpage_url = title
if(data["webpage_url"])
webpage_url = "<a href=\"[data["webpage_url"]]\">[title]</a>"
music_extra_data["start"] = data["start"]
music_extra_data["end"] = data["end"]
music_extra_data["link"] = data["webpage_url"]
music_extra_data["title"] = data["title"]
var/res = tgui_alert(src, "Show the title of and link to this song to the players?\n[title]", "Show Info?", list("Yes", "No"))
if(!res)
return
if(res == "Yes")
log_admin("[key_name(src)] played sound: [web_sound_input]")
message_admins("[key_name(src)] played sound: [web_sound_input]")
to_chat(world, "<span class='boldannounceooc'>[src.ckey] played: [webpage_url]</span>")
else if(res == "No")
music_extra_data["link"] = "Song Link Hidden"
music_extra_data["title"] = "Song Title Hidden"
music_extra_data["artist"] = "Song Artist Hidden"
log_admin("[key_name(src)] played sound: [web_sound_input]")
message_admins("[key_name(src)] played sound: [web_sound_input]")
to_chat(world, "<span class='boldannounceooc'>[src.ckey] played a sound</span>")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Global Sound TGchat")
if(!must_send_assets && web_sound_url && !findtext(web_sound_url, GLOB.is_http_protocol))
to_chat(src, "<span class='boldwarning'>BLOCKED: Content URL not using http(s) protocol</span>", confidential = TRUE)
to_chat(src, "<span class='warning'>The media provider returned a content URL that isn't using the HTTP or HTTPS protocol</span>", confidential = TRUE)
return
if(web_sound_url)
for(var/mob/M in GLOB.player_list)
var/client/C = M.client
var/player_uid = M.client.UID()
if(C.prefs.sound & SOUND_MIDI)
if(ckey in M.client.prefs.admin_sound_ckey_ignore)
to_chat(C, "<span class='warning'>But [src.ckey] is muted locally in preferences!</span>")
continue
if(C.prefs.sound & SOUND_MIDI)
if(ckey in M.client.prefs.admin_sound_ckey_ignore)
to_chat(C, "<span class='warning'>But [src.ckey] is muted locally in preferences!</span>")
continue
else
C.tgui_panel?.play_music(web_sound_url, music_extra_data)
to_chat(C, "<span class='warning'>(<a href='byond://?src=[this_uid];action=silenceSound'>SILENCE</a>) (<a href='byond://?src=[this_uid];action=muteAdmin&a=[ckey]'>ALWAYS SILENCE THIS ADMIN</a>)</span>")
else
to_chat(C, "<span class='warning'>But Admin MIDIs are disabled in preferences!</span>")
if(must_send_assets)
SSassets.transport.send_assets(C, asset_name)
C.tgui_panel?.play_music(web_sound_url, music_extra_data)
to_chat(C, "<span class='warning'>(<a href='byond://?src=[player_uid];action=silenceSound'>SILENCE</a>) (<a href='byond://?src=[player_uid];action=muteAdmin&a=[ckey]'>ALWAYS SILENCE THIS ADMIN</a>)</span>")
else
to_chat(C, "<span class='warning'>But Admin MIDIs are disabled in preferences!</span>")
return