[MIRROR] Sound updates (#7430)

Co-authored-by: Heroman3003 <31296024+Heroman3003@users.noreply.github.com>
Co-authored-by: Selis <sirlionfur@hotmail.de>
Co-authored-by: Selis <selis@xynolabs.com>
This commit is contained in:
CHOMPStation2
2023-12-20 17:05:40 -07:00
committed by GitHub
parent b011e089d0
commit e3a4d6ad61
10 changed files with 1017 additions and 622 deletions

View File

@@ -1,3 +1,62 @@
//// COOLDOWN SYSTEMS
/*
* We have 2 cooldown systems: timer cooldowns (divided between stoppable and regular) and world.time cooldowns.
*
* When to use each?
*
* * Adding a commonly-checked cooldown, like on a subsystem to check for processing
* * * Use the world.time ones, as they are cheaper.
*
* * Adding a rarely-used one for special situations, such as giving an uncommon item a cooldown on a target.
* * * Timer cooldown, as adding a new variable on each mob to track the cooldown of said uncommon item is going too far.
*
* * Triggering events at the end of a cooldown.
* * * Timer cooldown, registering to its signal.
*
* * Being able to check how long left for the cooldown to end.
* * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this.
*
* * Being able to stop the timer before it ends.
* * * Either world.time or stoppable timer cooldowns, depending on the other factors. Regular timer cooldowns do not support this.
*/
/*
* Cooldown system based on an datum-level associative lazylist using timers.
*/
// admin verb cooldowns
#define COOLDOWN_INTERNET_SOUND "internet_sound"
//TIMER COOLDOWN MACROS
#define COMSIG_CD_STOP(cd_index) "cooldown_[cd_index]"
#define COMSIG_CD_RESET(cd_index) "cd_reset_[cd_index]"
#define TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_cooldown), cd_source, cd_index), cd_time))
/// Checks if a timer based cooldown is NOT finished.
#define TIMER_COOLDOWN_RUNNING(cd_source, cd_index) LAZYACCESS(cd_source.cooldowns, cd_index)
/// Checks if a timer based cooldown is finished.
#define TIMER_COOLDOWN_FINISHED(cd_source, cd_index) (!TIMER_COOLDOWN_RUNNING(cd_source, cd_index))
#define TIMER_COOLDOWN_END(cd_source, cd_index) LAZYREMOVE(cd_source.cooldowns, cd_index)
/*
* Stoppable timer cooldowns.
* Use indexes the same as the regular tiemr cooldowns.
* They make use of the TIMER_COOLDOWN_RUNNING() and TIMER_COOLDOWN_END() macros the same, just not the TIMER_COOLDOWN_START() one.
* A bit more expensive than the regular timers, but can be reset before they end and the time left can be checked.
*/
#define S_TIMER_COOLDOWN_START(cd_source, cd_index, cd_time) LAZYSET(cd_source.cooldowns, cd_index, addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_cooldown), cd_source, cd_index), cd_time, TIMER_STOPPABLE))
#define S_TIMER_COOLDOWN_RESET(cd_source, cd_index) reset_cooldown(cd_source, cd_index)
#define S_TIMER_COOLDOWN_TIMELEFT(cd_source, cd_index) (timeleft(TIMER_COOLDOWN_RUNNING(cd_source, cd_index)))
/* /*
* Cooldown system based on storing world.time on a variable, plus the cooldown time. * Cooldown system based on storing world.time on a variable, plus the cooldown time.
* Better performance over timer cooldowns, lower control. Same functionality. * Better performance over timer cooldowns, lower control. Same functionality.
@@ -5,6 +64,8 @@
#define COOLDOWN_DECLARE(cd_index) var/##cd_index = 0 #define COOLDOWN_DECLARE(cd_index) var/##cd_index = 0
#define STATIC_COOLDOWN_DECLARE(cd_index) var/static/##cd_index = 0
#define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + (cd_time)) #define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + (cd_time))
//Returns true if the cooldown has run its course, false otherwise //Returns true if the cooldown has run its course, false otherwise
@@ -12,4 +73,6 @@
#define COOLDOWN_RESET(cd_source, cd_index) cd_source.cd_index = 0 #define COOLDOWN_RESET(cd_source, cd_index) cd_source.cd_index = 0
#define COOLDOWN_STARTED(cd_source, cd_index) (cd_source.cd_index != 0)
#define COOLDOWN_TIMELEFT(cd_source, cd_index) (max(0, cd_source.cd_index - world.time)) #define COOLDOWN_TIMELEFT(cd_source, cd_index) (max(0, cd_source.cd_index - world.time))

60
code/_helpers/shell.dm Normal file
View File

@@ -0,0 +1,60 @@
//Runs the command in the system's shell, returns a list of (error code, stdout, stderr)
#define SHELLEO_NAME "data/shelleo."
#define SHELLEO_ERR ".err"
#define SHELLEO_OUT ".out"
/world/proc/shelleo(command)
var/static/list/shelleo_ids = list()
var/stdout = ""
var/stderr = ""
var/errorcode = 1
var/shelleo_id
var/out_file = ""
var/err_file = ""
var/static/list/interpreters = list("[MS_WINDOWS]" = "cmd /c", "[UNIX]" = "sh -c")
var/interpreter = interpreters["[world.system_type]"]
if(interpreter)
for(var/seo_id in shelleo_ids)
if(!shelleo_ids[seo_id])
shelleo_ids[seo_id] = TRUE
shelleo_id = "[seo_id]"
break
if(!shelleo_id)
shelleo_id = "[shelleo_ids.len + 1]"
shelleo_ids += shelleo_id
shelleo_ids[shelleo_id] = TRUE
out_file = "[SHELLEO_NAME][shelleo_id][SHELLEO_OUT]"
err_file = "[SHELLEO_NAME][shelleo_id][SHELLEO_ERR]"
if(world.system_type == UNIX)
errorcode = shell("[interpreter] \"[replacetext(command, "\"", "\\\"")]\" > [out_file] 2> [err_file]")
else
errorcode = shell("[interpreter] \"[command]\" > [out_file] 2> [err_file]")
if(fexists(out_file))
stdout = file2text(out_file)
fdel(out_file)
if(fexists(err_file))
stderr = file2text(err_file)
fdel(err_file)
shelleo_ids[shelleo_id] = FALSE
else
CRASH("Operating System: [world.system_type] not supported") // If you encounter this error, you are encouraged to update this proc with support for the new operating system
. = list(errorcode, stdout, stderr)
#undef SHELLEO_NAME
#undef SHELLEO_ERR
#undef SHELLEO_OUT
/proc/shell_url_scrub(url)
var/static/regex/bad_chars_regex = regex("\[^#%&./:=?\\w]*", "g")
var/scrubbed_url = ""
var/bad_match = ""
var/last_good = 1
var/bad_chars = 1
do
bad_chars = bad_chars_regex.Find(url)
scrubbed_url += copytext(url, last_good, bad_chars)
if(bad_chars)
bad_match = url_encode(bad_chars_regex.match)
scrubbed_url += bad_match
last_good = bad_chars + length(bad_chars_regex.match)
while(bad_chars)
. = scrubbed_url

View File

@@ -304,6 +304,8 @@ var/list/gamemode_cache = list()
var/static/suggested_byond_version var/static/suggested_byond_version
var/static/suggested_byond_build var/static/suggested_byond_build
var/static/invoke_youtubedl = null
/datum/configuration/New() /datum/configuration/New()
var/list/L = subtypesof(/datum/game_mode) var/list/L = subtypesof(/datum/game_mode)
for (var/T in L) for (var/T in L)
@@ -982,6 +984,9 @@ var/list/gamemode_cache = list()
config.vgs_server_port = text2num(value) config.vgs_server_port = text2num(value)
// VOREStation Edit End // VOREStation Edit End
if("invoke_youtubedl")
config.invoke_youtubedl = value
else else
log_misc("Unknown setting in configuration: '[name]'") log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -512,6 +512,26 @@ SUBSYSTEM_DEF(timer)
return TRUE return TRUE
return FALSE return FALSE
/**
* Get the remaining deciseconds on a timer
*
* Arguments:
* * id a timerid or a /datum/timedevent
*/
/proc/timeleft(id, datum/controller/subsystem/timer/timer_subsystem)
if (!id)
return null
if (id == TIMER_ID_NULL)
CRASH("Tried to get timeleft of a null timerid. Use TIMER_STOPPABLE flag")
if (istype(id, /datum/timedevent))
var/datum/timedevent/timer = id
return timer.timeToRun - world.time
timer_subsystem = timer_subsystem || SStimer
//id is string
var/datum/timedevent/timer = timer_subsystem.timer_id_dict[id]
if(!timer || timer.spent)
return null
return timer.timeToRun - (timer.flags & TIMER_CLIENT_TIME ? REALTIMEOFDAY : world.time)
#undef BUCKET_LEN #undef BUCKET_LEN
#undef BUCKET_POS #undef BUCKET_POS

View File

@@ -47,6 +47,14 @@
/// A weak reference to another datum /// A weak reference to another datum
var/datum/weakref/weak_reference var/datum/weakref/weak_reference
/*
* Lazy associative list of currently active cooldowns.
*
* cooldowns [ COOLDOWN_INDEX ] = add_timer()
* add_timer() returns the truthy value of -1 when not stoppable, and else a truthy numeric index
*/
var/list/cooldowns
#ifdef REFERENCE_TRACKING #ifdef REFERENCE_TRACKING
var/tmp/running_find_references var/tmp/running_find_references
var/tmp/last_find_references = 0 var/tmp/last_find_references = 0
@@ -104,3 +112,33 @@
tag = null tag = null
SStgui.close_uis(src) SStgui.close_uis(src)
return QDEL_HINT_QUEUE return QDEL_HINT_QUEUE
/**
* Callback called by a timer to end an associative-list-indexed cooldown.
*
* Arguments:
* * source - datum storing the cooldown
* * index - string index storing the cooldown on the cooldowns associative list
*
* This sends a signal reporting the cooldown end.
*/
/proc/end_cooldown(datum/source, index)
if(QDELETED(source))
return
SEND_SIGNAL(source, COMSIG_CD_STOP(index))
TIMER_COOLDOWN_END(source, index)
/**
* Proc used by stoppable timers to end a cooldown before the time has ran out.
*
* Arguments:
* * source - datum storing the cooldown
* * index - string index storing the cooldown on the cooldowns associative list
*
* This sends a signal reporting the cooldown end, passing the time left as an argument.
*/
/proc/reset_cooldown(datum/source, index)
if(QDELETED(source))
return
SEND_SIGNAL(source, COMSIG_CD_RESET(index), S_TIMER_COOLDOWN_TIMELEFT(source, index))
TIMER_COOLDOWN_END(source, index)

View File

@@ -123,7 +123,8 @@ var/list/admin_verbs_ban = list(
var/list/admin_verbs_sounds = list( var/list/admin_verbs_sounds = list(
/client/proc/play_local_sound, /client/proc/play_local_sound,
/client/proc/play_sound, /client/proc/play_sound,
/client/proc/play_server_sound /client/proc/play_server_sound,
/client/proc/play_web_sound
) )
var/list/admin_verbs_fun = list( var/list/admin_verbs_fun = list(
@@ -244,7 +245,8 @@ var/list/admin_verbs_debug = list(
/datum/admins/proc/view_feedback, /datum/admins/proc/view_feedback,
/client/proc/debug_global_variables, /client/proc/debug_global_variables,
/client/proc/ping_webhook, /client/proc/ping_webhook,
/client/proc/reload_webhooks /client/proc/reload_webhooks,
/client/proc/stop_sounds
) )
var/list/admin_verbs_paranoid_debug = list( var/list/admin_verbs_paranoid_debug = list(
@@ -290,6 +292,7 @@ var/list/admin_verbs_hideable = list(
/client/proc/play_local_sound, /client/proc/play_local_sound,
/client/proc/play_sound, /client/proc/play_sound,
/client/proc/play_server_sound, /client/proc/play_server_sound,
/client/proc/play_web_sound,
/client/proc/object_talk, /client/proc/object_talk,
/datum/admins/proc/cmd_admin_dress, /datum/admins/proc/cmd_admin_dress,
/client/proc/cmd_admin_gib_self, /client/proc/cmd_admin_gib_self,
@@ -339,7 +342,8 @@ var/list/admin_verbs_hideable = list(
/proc/possess, /proc/possess,
/proc/release, /proc/release,
/datum/admins/proc/set_tcrystals, /datum/admins/proc/set_tcrystals,
/client/proc/debug_global_variables /client/proc/debug_global_variables,
/client/proc/stop_sounds
) )
var/list/admin_verbs_mod = list( var/list/admin_verbs_mod = list(
/client/proc/cmd_admin_pm_context, //right-click adminPM interface, /client/proc/cmd_admin_pm_context, //right-click adminPM interface,

View File

@@ -143,6 +143,7 @@ var/list/admin_verbs_sounds = list(
/client/proc/play_local_sound, /client/proc/play_local_sound,
/client/proc/play_sound, /client/proc/play_sound,
/client/proc/play_server_sound, /client/proc/play_server_sound,
/client/proc/play_web_sound,
/client/proc/play_z_sound /client/proc/play_z_sound
) )
@@ -279,6 +280,7 @@ var/list/admin_verbs_debug = list(
/client/proc/admin_give_modifier, /client/proc/admin_give_modifier,
/client/proc/simple_DPS, /client/proc/simple_DPS,
/datum/admins/proc/view_feedback, /datum/admins/proc/view_feedback,
/client/proc/stop_sounds,
/datum/admins/proc/quick_nif, //CHOMPStation Add, /datum/admins/proc/quick_nif, //CHOMPStation Add,
/datum/admins/proc/quick_authentic_nif //CHOMPStation add /datum/admins/proc/quick_authentic_nif //CHOMPStation add
) )
@@ -327,6 +329,7 @@ var/list/admin_verbs_hideable = list(
/client/proc/play_local_sound, /client/proc/play_local_sound,
/client/proc/play_sound, /client/proc/play_sound,
/client/proc/play_server_sound, /client/proc/play_server_sound,
/client/proc/play_web_sound,
/client/proc/object_talk, /client/proc/object_talk,
/datum/admins/proc/cmd_admin_dress, /datum/admins/proc/cmd_admin_dress,
/client/proc/cmd_admin_gib_self, /client/proc/cmd_admin_gib_self,
@@ -376,7 +379,8 @@ var/list/admin_verbs_hideable = list(
/proc/possess, /proc/possess,
/proc/release, /proc/release,
/datum/admins/proc/set_uplink, //VOREStation Add, /datum/admins/proc/set_uplink, //VOREStation Add,
/datum/admins/proc/set_tcrystals /datum/admins/proc/set_tcrystals,
/client/proc/stop_sounds
) )
var/list/admin_verbs_mod = list( var/list/admin_verbs_mod = list(
/client/proc/cmd_admin_pm_context, //right-click adminPM interface, /client/proc/cmd_admin_pm_context, //right-click adminPM interface,

View File

@@ -1,35 +1,77 @@
//world/proc/shelleo
#define SHELLEO_ERRORLEVEL 1
#define SHELLEO_STDOUT 2
#define SHELLEO_STDERR 3
var/list/sounds_cache = list() var/list/sounds_cache = list()
/client/proc/play_sound(S as sound) /client/proc/play_sound(S as sound)
set category = "Fun" set category = "Fun"
set name = "Play Global Sound" set name = "Play Global Sound"
if(!check_rights(R_SOUNDS)) return if(!check_rights(R_SOUNDS))
return
var/sound/uploaded_sound = sound(S, volume = 50, repeat = 0, wait = 1, channel = 777) var/freq = 1
uploaded_sound.priority = 250 var/vol = tgui_input_number(usr, "What volume would you like the sound to play at?",, 100, 100, 1)
if(!vol)
return
vol = clamp(vol, 1, 100)
var/sound/admin_sound = new()
admin_sound.file = S
admin_sound.priority = 250
admin_sound.channel = 777
admin_sound.frequency = freq
admin_sound.wait = 1
admin_sound.repeat = FALSE
admin_sound.status = SOUND_STREAM
admin_sound.volume = vol
sounds_cache += S sounds_cache += S
if(tgui_alert(usr, "Do you ready?\nSong: [S]\nNow you can also play this sound using \"Play Server Sound\".", "Confirmation request", list("Play","Cancel")) == "Cancel") var/res = tgui_alert(usr, "Show the title of this song ([S]) to the players?\nOptions 'Yes' and 'No' will play the sound.",, list("Yes", "No", "Cancel"))
return switch(res)
if("Yes")
to_chat(world, "<span class='boldannounce'>An admin played: [S]</span>", confidential = TRUE)
if("Cancel")
return
log_admin("[key_name(src)] played sound [S]") log_admin("[key_name(src)] played sound [S]")
message_admins("[key_name_admin(src)] played sound [S]", 1) message_admins("[key_name_admin(src)] played sound [S]", 1)
for(var/mob/M in player_list) for(var/mob/M in player_list)
if(M.is_preference_enabled(/datum/client_preference/play_admin_midis)) if(M.is_preference_enabled(/datum/client_preference/play_admin_midis))
M << uploaded_sound admin_sound.volume = vol * M.client.admin_music_volume
SEND_SOUND(M, admin_sound)
admin_sound.volume = vol
feedback_add_details("admin_verb","PGS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! feedback_add_details("admin_verb", "Play Global Sound")
/client/proc/play_local_sound(S as sound) /client/proc/play_local_sound(S as sound)
set category = "Fun" set category = "Fun"
set name = "Play Local Sound" set name = "Play Local Sound"
if(!check_rights(R_SOUNDS)) return if(!check_rights(R_SOUNDS))
return
log_admin("[key_name(src)] played a local sound [S]") log_admin("[key_name(src)] played a local sound [S]")
message_admins("[key_name_admin(src)] played a local sound [S]", 1) message_admins("[key_name_admin(src)] played a local sound [S]", 1)
playsound(src.mob, S, 50, 0, 0) playsound(src.mob, S, 50, 0, 0)
feedback_add_details("admin_verb","PLS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! feedback_add_details("admin_verb", "Play Local Sound")
/client/proc/play_direct_mob_sound(S as sound, mob/M)
set category = "Fun"
set name = "Play Direct Mob Sound"
if(!check_rights(R_SOUNDS))
return
if(!M)
M = tgui_input_list(usr, "Choose a mob to play the sound to. Only they will hear it.", "Play Mob Sound", sortNames(player_list))
if(!M || QDELETED(M))
return
log_admin("[key_name(src)] played a direct mob sound [S] to [M].")
message_admins("[key_name_admin(src)] played a direct mob sound [S] to [ADMIN_LOOKUPFLW(M)].")
SEND_SOUND(M, S)
feedback_add_details("admin_verb", "Play Direct Mob Sound")
/client/proc/play_z_sound(S as sound) /client/proc/play_z_sound(S as sound)
set category = "Fun" set category = "Fun"
@@ -50,13 +92,14 @@ var/list/sounds_cache = list()
if(M.is_preference_enabled(/datum/client_preference/play_admin_midis) && M.z == target_z) if(M.is_preference_enabled(/datum/client_preference/play_admin_midis) && M.z == target_z)
M << uploaded_sound M << uploaded_sound
feedback_add_details("admin_verb","PZS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! feedback_add_details("admin_verb", "Play Z Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/play_server_sound() /client/proc/play_server_sound()
set category = "Fun" set category = "Fun"
set name = "Play Server Sound" set name = "Play Server Sound"
if(!check_rights(R_SOUNDS)) return if(!check_rights(R_SOUNDS))
return
var/list/sounds = file2list("sound/serversound_list.txt"); var/list/sounds = file2list("sound/serversound_list.txt");
sounds += "--CANCEL--" sounds += "--CANCEL--"
@@ -64,10 +107,159 @@ var/list/sounds_cache = list()
var/melody = tgui_input_list(usr, "Select a sound from the server to play", "Server sound list", sounds, "--CANCEL--") var/melody = tgui_input_list(usr, "Select a sound from the server to play", "Server sound list", sounds, "--CANCEL--")
if(melody == "--CANCEL--") return if(melody == "--CANCEL--")
return
play_sound(melody) play_sound(melody)
feedback_add_details("admin_verb","PSS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! feedback_add_details("admin_verb", "Play Server Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
///Takes an input from either proc/play_web_sound or the request manager and runs it through youtube-dl and prompts the user before playing it to the server.
/proc/web_sound(mob/user, input, credit)
if(!check_rights(R_SOUNDS))
return
var/ytdl = config.invoke_youtubedl
if(!ytdl)
to_chat(user, "<span class='boldwarning'>Youtube-dl was not configured, action unavailable</span>", confidential = TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value
return
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 class='boldwarning'>Youtube-dl URL retrieval FAILED:</span>", confidential = TRUE)
to_chat(user, "<span class='warning'>[stderr]</span>", confidential = TRUE)
return
var/list/data
try
data = json_decode(stdout)
catch(var/exception/e)
to_chat(user, "<span class='boldwarning'>Youtube-dl JSON parsing FAILED:</span>", confidential = TRUE)
to_chat(user, "<span class='warning'>[e]: [stdout]</span>", confidential = TRUE)
return
if (data["url"])
web_sound_url = data["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["duration"] = DisplayTimeText(data["duration"] * 1 SECONDS)
music_extra_data["link"] = data["webpage_url"]
music_extra_data["artist"] = data["artist"]
music_extra_data["upload_date"] = data["upload_date"]
music_extra_data["album"] = data["album"]
duration = data["duration"] * 1 SECONDS
if (duration > 10 MINUTES)
if((tgui_alert(user, "This song is over 10 minutes long. Are you sure you want to play it?", "Length Warning!", list("No", "Yes", "Cancel")) != "Yes"))
return
var/res = tgui_alert(user, "Show the title of and link to this song to the players?\n[title]", "Show Info?", list("Yes", "No", "Cancel"))
switch(res)
if("Yes")
music_extra_data["title"] = data["title"]
if("No")
music_extra_data["link"] = "Song Link Hidden"
music_extra_data["title"] = "Song Title Hidden"
music_extra_data["artist"] = "Song Artist Hidden"
music_extra_data["upload_date"] = "Song Upload Date Hidden"
music_extra_data["album"] = "Song Album Hidden"
if("Cancel", null)
return
var/anon = tgui_alert(user, "Display who played the song?", "Credit Yourself?", list("Yes", "No", "Cancel"))
switch(anon)
if("Yes")
if(res == "Yes")
to_chat(world, "<span class='boldannounce'>[user.key] played: [webpage_url]</span>", confidential = TRUE)
else
to_chat(world, "<span class='boldannounce'>[user.key] played a sound</span>", confidential = TRUE)
if("No")
if(res == "Yes")
to_chat(world, "<span class='boldannounce'>An admin played: [webpage_url]</span>", confidential = TRUE)
if("Cancel", null)
return
if(credit)
to_chat(world, "<span class='boldannounce'>[credit]</span>", confidential = TRUE)
//SSblackbox.record_feedback("nested tally", "played_url", 1, list("[user.ckey]", "[input]"))
log_admin("[key_name(user)] played web sound: [input]")
message_admins("[key_name(user)] played web sound: [input]")
else
//pressed ok with blank
log_admin("[key_name(user)] stopped web sounds.")
message_admins("[key_name(user)] stopped web sounds.")
web_sound_url = null
stop_web_sounds = TRUE
if(web_sound_url && !findtext(web_sound_url, GLOB.is_http_protocol))
tgui_alert(user, "The media provider returned a content URL that isn't using the HTTP or HTTPS protocol. This is a security risk and the sound will not be played.", "Security Risk", list("OK"))
to_chat(user, "<span class='boldwarning'>BLOCKED: Content URL not using HTTP(S) Protocol!</span>", confidential = TRUE)
return
if(web_sound_url || stop_web_sounds)
for(var/m in player_list)
var/mob/M = m
var/client/C = M.client
if(C.is_preference_enabled(/datum/client_preference/play_admin_midis))
if(!stop_web_sounds)
C.tgui_panel?.play_music(web_sound_url, music_extra_data)
else
C.tgui_panel?.stop_music()
S_TIMER_COOLDOWN_START(SStimer, COOLDOWN_INTERNET_SOUND, duration)
feedback_add_details("admin_verb", "Play Internet Sound")
/client/proc/play_web_sound()
set category = "Fun"
set name = "Play Internet Sound"
if(!check_rights(R_SOUNDS))
return
var/ytdl = config.invoke_youtubedl
if(!ytdl)
to_chat(src, "<span class='boldwarning'>Youtube-dl was not configured, action unavailable</span>", confidential = TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value
return
if(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND))
if(tgui_alert(usr, "Someone else is already playing an Internet sound! It has [DisplayTimeText(S_TIMER_COOLDOWN_TIMELEFT(SStimer, COOLDOWN_INTERNET_SOUND), 1)] remaining. \
Would you like to override?", "Musicalis Interruptus", list("No","Yes")) != "Yes")
return
var/web_sound_input = tgui_input_text(usr, "Enter content URL (supported sites only, leave blank to stop playing)", "Play Internet Sound", null)
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>", confidential = TRUE)
to_chat(src, "<span class='warning'>For youtube-dl shortcuts like ytsearch: please use the appropriate full URL from the website.</span>", confidential = TRUE)
return
web_sound(usr, web_sound_input)
else
web_sound(usr, null)
/client/proc/stop_sounds()
set category = "Debug"
set name = "Stop All Playing Sounds"
if(!src.holder)
return
log_admin("[key_name(src)] stopped all currently playing sounds.")
message_admins("[key_name_admin(src)] stopped all currently playing sounds.")
for(var/mob/M in player_list)
SEND_SOUND(M, sound(null))
var/client/C = M.client
C?.tgui_panel?.stop_music()
S_TIMER_COOLDOWN_RESET(SStimer, COOLDOWN_INTERNET_SOUND)
feedback_add_details("admin_verb", "Stop All Playing Sounds")
//world/proc/shelleo
#undef SHELLEO_ERRORLEVEL
#undef SHELLEO_STDOUT
#undef SHELLEO_STDERR
/* /*
/client/proc/cuban_pete() /client/proc/cuban_pete()

View File

@@ -257,6 +257,14 @@ SERVER your.domain:6000
## Ban appeals URL - usually for a forum or wherever people should go to contact your admins. ## Ban appeals URL - usually for a forum or wherever people should go to contact your admins.
#BANAPPEALS http://bans.your.domain/ #BANAPPEALS http://bans.your.domain/
## System command that invokes yt-dlp, used by Play Internet Sound.
## You can install yt-dlp with
## "pip install yt-dlp" if you have pip installed
## from https://github.com/yt-dlp/yt-dlp
## or your package manager
## The default value assumes yt-dlp is in your system PATH
# INVOKE_YOUTUBEDL yt-dlp
## In-game features ## In-game features
## spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard ## spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard
# FEATURE_OBJECT_SPELL_SYSTEM # FEATURE_OBJECT_SPELL_SYSTEM

View File

@@ -153,6 +153,7 @@
#include "code\_helpers\mobs.dm" #include "code\_helpers\mobs.dm"
#include "code\_helpers\names.dm" #include "code\_helpers\names.dm"
#include "code\_helpers\sanitize_values.dm" #include "code\_helpers\sanitize_values.dm"
#include "code\_helpers\shell.dm"
#include "code\_helpers\storage.dm" #include "code\_helpers\storage.dm"
#include "code\_helpers\string_lists.dm" #include "code\_helpers\string_lists.dm"
#include "code\_helpers\text.dm" #include "code\_helpers\text.dm"