From c9fae1f266760c9894c84fccf704d97514e02fc3 Mon Sep 17 00:00:00 2001 From: ROdenFL Date: Sat, 24 Aug 2024 21:09:37 +0300 Subject: [PATCH] add: yt-dlp music system (#5792) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add: yogstation music system * flag name change * lobby music cfg * cfg * MORECFG * style * хуйню сделал * better cfg * prettier * blya * v1.5 * avtobundle * Revert "avtobundle" This reverts commit 291cb6454b4b3514523ae81455e1b8c397748cc6. * fix logging * fix and tweaks * doble equels * fix quotes in path --------- Co-authored-by: Aziz Chynaliev --- code/_globalvars/_regexes.dm | 1 + .../configuration/configuration.dm | 2 +- .../configuration/entries/config.dm | 6 + code/controllers/subsystem/statpanel.dm | 1 + code/controllers/subsystem/ticker.dm | 61 +++++- code/game/sound.dm | 27 ++- code/modules/admin/admin_verbs.dm | 1 + code/modules/admin/verbs/playsound.dm | 107 +++++++++ code/modules/asset_cache/asset_list.dm | 25 +++ .../client/preference/preferences_toggles.dm | 3 +- code/modules/holiday/holiday.dm | 1 + code/modules/tgui/tgui_panel/audio.dm | 2 + config/example/config.txt | 8 + config/example/music.txt | 207 ++++++++++++++++++ 14 files changed, 438 insertions(+), 14 deletions(-) create mode 100644 config/example/music.txt diff --git a/code/_globalvars/_regexes.dm b/code/_globalvars/_regexes.dm index d0098e3711f..7c2a73a4548 100644 --- a/code/_globalvars/_regexes.dm +++ b/code/_globalvars/_regexes.dm @@ -1,2 +1,3 @@ +GLOBAL_DATUM_INIT(is_http_protocol, /regex, regex("^https?://")) GLOBAL_DATUM_INIT(filename_forbidden_chars, /regex, regex(@{""|[\\\n\t/?%*:|<>]|\.\."}, "g")) GLOBAL_PROTECT(filename_forbidden_chars) diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index aa6b0eb5789..96bef8fd7b8 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -52,7 +52,7 @@ GLOBAL_LIST_EMPTY(overflow_whitelist) InitEntries() //Note: `$include`s are supported. Feel free to use them. - var/list/configs = list("game_options.txt", "dbconfig.txt", "config.txt", "emojis.txt", "resources.txt") + var/list/configs = list("game_options.txt", "dbconfig.txt", "config.txt", "emojis.txt", "resources.txt", "music.txt") for(var/I in configs) if(fexists("[directory]/[I]")) for(var/J in configs) diff --git a/code/controllers/configuration/entries/config.dm b/code/controllers/configuration/entries/config.dm index 70f356089c1..c6c0f5f1d50 100644 --- a/code/controllers/configuration/entries/config.dm +++ b/code/controllers/configuration/entries/config.dm @@ -825,3 +825,9 @@ /datum/config_entry/flag/save_spritesheets default = FALSE + + +/datum/config_entry/string/invoke_youtubedl + protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN + +/datum/config_entry/str_list/lobby_music diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index d0373240f05..14b6d85a410 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -201,6 +201,7 @@ SUBSYSTEM_DEF(statpanels) list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time / world.tick_lag]) (TickDrift:[round(Master.tickdrift, 1)]([round((Master.tickdrift / (world.time / world.tick_lag)) * 100, 0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE, 0.1)]%)"), list("Master Controller:", Master.stat_entry(), "[Master.UID()]"), list("Failsafe Controller:", Failsafe.stat_entry(), "[Failsafe.UID()]"), + list("Configuration Controller:", config.stat_entry(), "[config.UID()]"), list("","") ) for(var/datum/controller/subsystem/sub_system as anything in Master.subsystems) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index e7d1ba522da..5062c71e5aa 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -27,6 +27,8 @@ SUBSYSTEM_DEF(ticker) var/datum/game_mode/mode = null /// The current pick of lobby music played in the lobby var/login_music + var/login_music_data + var/selected_lobby_music /// List of all minds in the game. Used for objective tracking var/list/datum/mind/minds = list() /// icon_state the chaplain has chosen for his bible @@ -75,17 +77,14 @@ SUBSYSTEM_DEF(ticker) var/list/randomtips = list() var/list/memetips = list() + var/music_available = 0 /datum/controller/subsystem/ticker/Initialize() - login_music = pick(\ - 'sound/music/thunderdome.ogg',\ - 'sound/music/space.ogg',\ - 'sound/music/pilotpriest-origin-one.ogg',\ - 'sound/music/pilotpriest-tell-them-now.ogg',\ - 'sound/music/pilotpriest-now-be-the-light.ogg',\ - 'sound/music/title1.ogg',\ - 'sound/music/title2.ogg',\ - 'sound/music/title3.ogg',) + login_music_data = list() + login_music = choose_lobby_music() + + if(!login_music) + to_chat(world, span_boldwarning("Could not load lobby music.")) //yogs end randomtips = file2list("strings/tips.txt") memetips = file2list("strings/sillytips.txt") @@ -390,6 +389,50 @@ SUBSYSTEM_DEF(ticker) //addtimer(VARSET_CALLBACK(SStime_track, update_gliding, TRUE), 1 MINUTES) return TRUE +/datum/controller/subsystem/ticker/proc/choose_lobby_music() + var/list/songs = CONFIG_GET(str_list/lobby_music) + selected_lobby_music = pick(songs) + + if(SSholiday.holidays) // What's this? Events are initialized before tickers? Let's do something with that! + for(var/holidayname in SSholiday.holidays) + var/datum/holiday/holiday = SSholiday.holidays[holidayname] + if(LAZYLEN(holiday.lobby_music)) + selected_lobby_music = pick(holiday.lobby_music) + break + + var/ytdl = CONFIG_GET(string/invoke_youtubedl) + if(!ytdl) + to_chat(world, span_boldwarning("yt-dlp was not configured.")) + log_world("Could not play lobby song because yt-dlp is not configured properly, check the config.") + return + + var/list/output = world.shelleo("[ytdl] -x --audio-format mp3 --audio-quality 0 --geo-bypass --no-playlist -o \"cache/songs/%(id)s.%(ext)s\" --dump-single-json --no-simulate \"[selected_lobby_music]\"") + var/errorlevel = output[SHELLEO_ERRORLEVEL] + var/stdout = output[SHELLEO_STDOUT] + var/stderr = output[SHELLEO_STDERR] + + if(!errorlevel) + var/list/data + try + data = json_decode(stdout) + catch(var/exception/e) + to_chat(world, span_boldwarning("yt-dlp JSON parsing FAILED.")) + log_world(span_boldwarning("yt-dlp JSON parsing FAILED:")) + log_world(span_warning("[e]: [stdout]")) + return + if(data["title"]) + login_music_data["title"] = data["title"] + login_music_data["url"] = data["url"] + login_music_data["link"] = data["webpage_url"] + login_music_data["path"] = "cache/songs/[data["id"]].mp3" + login_music_data["title_link"] = data["webpage_url"] ? "[data["title"]]" : data["title"] + + if(errorlevel) + to_chat(world, span_boldwarning("yt-dlp failed.")) + log_world("Could not play lobby song [selected_lobby_music]: [stderr]") + return + return stdout + /datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed = 0, override = null) diff --git a/code/game/sound.dm b/code/game/sound.dm index 8d7bbc71e46..ee87c3036ec 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -1,3 +1,4 @@ +GLOBAL_LIST_EMPTY(cached_songs) ///Default override for echo /sound @@ -184,12 +185,32 @@ falloff_distance - Distance at which falloff begins. Sound is at peak volume (in S.status = SOUND_UPDATE SEND_SOUND(src, S) +/client/proc/playtitlemusic(vol = 85) + set waitfor = FALSE -/client/proc/playtitlemusic() - if(!SSticker || !SSticker.login_music || CONFIG_GET(flag/disable_lobby_music)) + if(!SSticker || CONFIG_GET(flag/disable_lobby_music) || !CONFIG_GET(string/invoke_youtubedl)) return + + UNTIL(SSticker.login_music) //wait for SSticker init to set the login music + UNTIL(tgui_panel) + UNTIL(SSassets.initialized) + + var/url = SSticker.login_music_data["url"] + switch(CONFIG_GET(string/asset_transport)) + if ("webroot") + var/datum/asset/music/my_asset + var/filepath = SSticker.login_music_data["path"] + if(GLOB.cached_songs[filepath]) + my_asset = GLOB.cached_songs[filepath] + else + my_asset = new /datum/asset/music(filepath) + GLOB.cached_songs[filepath] = my_asset + + url = my_asset.get_url() + if(prefs.sound & SOUND_LOBBY) - SEND_SOUND(src, sound(SSticker.login_music, repeat = 0, wait = 0, volume = 85 * prefs.get_channel_volume(CHANNEL_LOBBYMUSIC), channel = CHANNEL_LOBBYMUSIC)) // MAD JAMS + tgui_panel?.play_music(url, SSticker.login_music_data) + to_chat(src, span_notice("Сейчас играет: [SSticker.login_music_data["title_link"]]")) /proc/get_rand_frequency() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 711515cec19..87871acdcd6 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -82,6 +82,7 @@ GLOBAL_LIST_INIT(admin_verbs_sounds, list( /client/proc/play_server_sound, /client/proc/play_intercomm_sound, /client/proc/stop_global_admin_sounds, + /client/proc/play_web_sound, )) GLOBAL_LIST_INIT(admin_verbs_event, list( /client/proc/secrets, diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index a4f62de7262..5eca0d73533 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -46,6 +46,113 @@ GLOBAL_LIST_EMPTY(sounds_cache) playsound(get_turf(src.mob), S, 50, 0, 0) SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Local Sound") //If you are copy-pasting this, ensure the 4th parameter is unique to the new proc! + +/client/proc/play_web_sound() + set category = "Event" + set name = "Play Internet Sound" + if(!check_rights(R_SOUNDS)) + return + + if(!tgui_panel || !SSassets.initialized) + return + + var/ytdl = CONFIG_GET(string/invoke_youtubedl) + if(!ytdl) + to_chat(src, span_boldwarning("yt-dlp was not configured, action unavailable"), confidential=TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value + return + + var/web_sound_input = input("Enter content URL (supported sites only, leave blank to stop playing)", "Play Internet Sound via yt-dlp") as text|null + if(istext(web_sound_input)) + var/web_sound_path = "" + 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_boldwarning("Non-http(s) URIs are not allowed."), confidential=TRUE) + to_chat(src, span_warning("For yt-dlp shortcuts like ytsearch: please use the appropriate full url from the website."), confidential=TRUE) + return + var/shell_scrubbed_input = shell_url_scrub(web_sound_input) + var/list/output = world.shelleo("[ytdl] -x --audio-format mp3 --audio-quality 0 --geo-bypass --no-playlist -o \"cache/songs/%(id)s.%(ext)s\" --dump-single-json --no-simulate \"[shell_scrubbed_input]\"") + var/errorlevel = output[SHELLEO_ERRORLEVEL] + var/stdout = output[SHELLEO_STDOUT] + var/stderr = output[SHELLEO_STDERR] + if(!errorlevel) + var/list/data + try + data = json_decode(stdout) + catch(var/exception/e) + to_chat(src, span_boldwarning("yt-dlp JSON parsing FAILED:"), confidential=TRUE) + to_chat(src, span_warning("[e]: [stdout]"), confidential=TRUE) + return + + if(data["url"]) + web_sound_path = "cache/songs/[data["id"]].mp3" + web_sound_url = data["url"] + var/title = "[data["title"]]" + var/webpage_url = title + if(data["webpage_url"]) + webpage_url = "[title]" + music_extra_data["start"] = data["start_time"] + music_extra_data["end"] = data["end_time"] + music_extra_data["link"] = data["webpage_url"] + music_extra_data["title"] = data["title"] + if(data["duration"]) + var/mus_len = data["duration"] SECONDS + if(data["start_time"]) + mus_len -= data["start_time"] SECONDS + if(data["end_time"]) + mus_len -= (data["duration"] SECONDS - data["end_time"] SECONDS) + SSticker.music_available = REALTIMEOFDAY + mus_len + + var/res = tgui_alert(usr, "Show the title of and link to this song to the players?\n[title]",, list("No", "Yes", "Cancel")) + switch(res) + if("Yes") + to_chat(world, span_boldannounceooc("Сейчас играет: [webpage_url]")) + if("Cancel") + return + + SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]")) + log_admin("[key_name(src)] played web sound: [web_sound_input]") + message_admins("[key_name(src)] played web sound: [web_sound_input]") + else + to_chat(src, span_boldwarning("yt-dlp URL retrieval FAILED:"), confidential=TRUE) + to_chat(src, span_warning("[stderr]"), confidential=TRUE) + + else //pressed ok with blank + log_admin("[key_name(src)] stopped web sound") + message_admins("[key_name(src)] stopped web sound") + web_sound_path = null + stop_web_sounds = TRUE + SSticker.music_available = 0 + + if(stop_web_sounds) + for(var/m in GLOB.player_list) + var/mob/M = m + var/client/C = M.client + if(C.prefs.toggles & SOUND_MIDI) + C.tgui_panel?.stop_music() + else + var/url = web_sound_url + switch(CONFIG_GET(string/asset_transport)) + if ("webroot") + var/datum/asset/music/my_asset + if(GLOB.cached_songs[web_sound_path]) + my_asset = GLOB.cached_songs[web_sound_path] + else + my_asset = new /datum/asset/music(web_sound_path) + GLOB.cached_songs[web_sound_path] = my_asset + url = my_asset.get_url() + + for(var/m in GLOB.player_list) + var/mob/M = m + var/client/C = M.client + if(C.prefs.sound & SOUND_MIDI) + C.tgui_panel?.play_music(url, music_extra_data) + + SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Internet Sound") + /client/proc/play_server_sound() set category = "Event" set name = "Play Server Sound" diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index 5b5c2da2cf8..a508459a9ef 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -116,6 +116,12 @@ GLOBAL_LIST_EMPTY(asset_datums) for(var/asset_name in assets) .[asset_name] = SSassets.transport.get_asset_url(asset_name, assets[asset_name]) +/datum/asset/simple/music + legacy = TRUE + keep_local_name = TRUE + +/datum/asset/simple/music/New() + GLOB.asset_datums[type] = src /// For registering or sending multiple others at once /datum/asset/group @@ -522,6 +528,25 @@ GLOBAL_LIST_EMPTY(asset_datums) return . = list("[item_filename]" = SSassets.transport.get_asset_url(item_filename)) +/datum/asset/music + _abstract = /datum/asset/music + var/item_filename + +/datum/asset/music/New(path) + item_filename = sanitize_filename(path) + SSassets.transport.register_asset(item_filename, file(path)) + fdel(path) + +/datum/asset/music/send(client) + if(!item_filename) + return + . = SSassets.transport.send_assets(client, item_filename) + +/datum/asset/music/proc/get_url() + if(!item_filename) + return + . = url_decode(SSassets.transport.get_asset_url(item_filename)) + /datum/asset/spritesheet/simple _abstract = /datum/asset/spritesheet/simple var/list/assets diff --git a/code/modules/client/preference/preferences_toggles.dm b/code/modules/client/preference/preferences_toggles.dm index 302c6c62ef5..e084dd0a46f 100644 --- a/code/modules/client/preference/preferences_toggles.dm +++ b/code/modules/client/preference/preferences_toggles.dm @@ -153,7 +153,8 @@ if(isnewplayer(usr)) user.playtitlemusic() else - usr.stop_sound_channel(CHANNEL_LOBBYMUSIC) + // usr.stop_sound_channel(CHANNEL_LOBBYMUSIC) + user.tgui_panel?.stop_music() /datum/preference_toggle/toggle_admin_midis name = "Toggle Admin Midis" diff --git a/code/modules/holiday/holiday.dm b/code/modules/holiday/holiday.dm index 647450e3c95..4e96b111d48 100644 --- a/code/modules/holiday/holiday.dm +++ b/code/modules/holiday/holiday.dm @@ -7,6 +7,7 @@ var/end_day = 0 // Default of 0 means the holiday lasts a single day var/end_month = 0 var/eventChance = 0 + var/list/lobby_music = null // list of youtube URLs for lobby music to use during this holiday /** * NOTE FOR EVERYONE TRYING TO DO STUFF WHICH REQUIRES MAPPING, PLACING OBJECTS, ETC: diff --git a/code/modules/tgui/tgui_panel/audio.dm b/code/modules/tgui/tgui_panel/audio.dm index 1659f336683..b91dc6bd5a7 100644 --- a/code/modules/tgui/tgui_panel/audio.dm +++ b/code/modules/tgui/tgui_panel/audio.dm @@ -22,6 +22,8 @@ /datum/tgui_panel/proc/play_music(url, extra_data) if(!is_ready()) return + if(!findtext(url, GLOB.is_http_protocol)) + return var/list/payload = list() if(length(extra_data) > 0) for(var/key in extra_data) diff --git a/config/example/config.txt b/config/example/config.txt index 9f5999b529c..4fa904cd5b8 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -721,3 +721,11 @@ CACHE_ASSETS 0 ## Useful for developers to debug potential spritesheet issues to determine where the issue is cropping up (either in DM-side sprite generation or in the TGUI-side display of said spritesheet). ## Will only seek to waste disk space if ran on production. #SAVE_SPRITESHEETS + +## 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/releases +## or your package manager +## The default value assumes yt-dlp is in your system PATH +# INVOKE_YOUTUBEDL yt-dlp diff --git a/config/example/music.txt b/config/example/music.txt new file mode 100644 index 00000000000..16ddeb5b858 --- /dev/null +++ b/config/example/music.txt @@ -0,0 +1,207 @@ +## This file is used for customing lobby music playlist +## Add/remove songs from this list individually, rather than multiple at once. This makes it easier to judge PRs that change the list, since PRs that change it up heavily are less likely to meet broad support +## Add a comment after the song link in the format [Artist - Name] + +#### Classic SS13 Music + +## Space Station 13 Music - Endless Space +LOBBY_MUSIC https://www.youtube.com/watch?v=Ae2N5310MXE + +## Space Station 13 Music - Title1 (Flip-Flap) +LOBBY_MUSIC https://www.youtube.com/watch?v=UaD4AiqYDyA + +## Space Station 13 Music - Title3 +LOBBY_MUSIC https://www.youtube.com/watch?v=YKVmXn-Gv0M + +## Space Station 13 Music - THUNDERDOME (Sector11) +LOBBY_MUSIC https://www.youtube.com/watch?v=-K3ztneTQuA + +## Space Station 13 Music - clown.wmv +LOBBY_MUSIC https://www.youtube.com/watch?v=9whQIbNmu9s + +## Space Station 14 - Tin Tin On Moon Mark II +LOBBY_MUSIC https://www.youtube.com/watch?v=d7hc_GrZP4Y + +## PILOTPRIEST - Tell Them Now +LOBBY_MUSIC https://www.youtube.com/watch?v=r4aqBG20ruo + +## PILOTPRIEST - Origin One +LOBBY_MUSIC https://pilotpriest.bandcamp.com/track/origin-one + +## PILOTPRIEST - Now Be The Light +LOBBY_MUSIC https://pilotpriest.bandcamp.com/track/now-be-the-light-2 + + +#### Yogstation Music + +## Jim Carrey - Cuban Pete +#LOBBY_MUSIC https://www.youtube.com/watch?v=jA4u5Pur5KA + +## Electric Light Orchestra - Mr. Blue Sky +#LOBBY_MUSIC https://www.youtube.com/watch?v=lIrum6iFz6U + +## SolusLunes - Endless Space +#LOBBY_MUSIC https://www.youtube.com/watch?v=Ae2N5310MXE + +## MashedByMachines - Sector11 +#LOBBY_MUSIC https://www.youtube.com/watch?v=UPHmazxB38g + +## Jeff Imam - Title - Plasma Attack +#LOBBY_MUSIC https://soundcloud.com/jeffimam/title-plasma-attack + +## David Bowie - Space Oddity (Cover by Chris Hadfield) +#LOBBY_MUSIC https://www.youtube.com/watch?v=KaOC9danxNo + +## X-CEED - Flip-Flap +#LOBBY_MUSIC https://www.youtube.com/watch?v=UaD4AiqYDyA + +## Monster860 - Orion Trail +#LOBBY_MUSIC https://www.youtube.com/watch?v=a90kqxX3jPg + +## Monster860 - Journey to Cygni +#LOBBY_MUSIC https://www.youtube.com/watch?v=zKxwED8-Hws + +## Joseph "Zhaytee" Toscano - Absconditus +#LOBBY_MUSIC https://www.youtube.com/watch?v=icy4-CQHVh4 + +## Hiroaki Yoshida, Hitomi Komatsu - Robocop Theme (Remix by Cboyardee) +#LOBBY_MUSIC https://www.youtube.com/watch?v=dCPWE4WexM8 + +## Stellardrone - Comet Haley +#LOBBY_MUSIC https://www.youtube.com/watch?v=3W7mwRpUbqQ + +## Jeroen Tel - Tintin on the Moon (Noisemaker's Remix) +#LOBBY_MUSIC https://www.youtube.com/watch?v=BY-1SrsLER0 + +## Jeroen Tel - Tintin on the Moon (Remix by Cuboos) +#LOBBY_MUSIC https://www.youtube.com/watch?v=YKVmXn-Gv0M + +## Chris Remo - Space Asshole +#LOBBY_MUSIC https://www.youtube.com/watch?v=GISnTECX8Eg + +## Ronald Jenkee - Piano Wire +#LOBBY_MUSIC https://www.youtube.com/watch?v=le1eD6I7k4s + +## Kelly Bailey - Nuclear Missile Jam/Something Secret Steers Us (Remix) +#LOBBY_MUSIC https://www.youtube.com/watch?v=r-eMVfiT8_c + +## Wintergatan - Local Cluster +#LOBBY_MUSIC https://www.youtube.com/watch?v=WcWix770cvQ + +## Michael Giacchino - Main Theme (STAR TREK Beyond) +#LOBBY_MUSIC https://www.youtube.com/watch?v=w5hBQDepXOE + +## Admiral Hippie - Clown.wmv +#LOBBY_MUSIC https://www.youtube.com/watch?v=9whQIbNmu9s + +## Chris Christodoulou - Risk of Rain Coalescence +#LOBBY_MUSIC https://www.youtube.com/watch?v=67BwWgrMlxk + +## Star Trek The Motion Picture: Main Theme Album Style Edit +#LOBBY_MUSIC https://www.youtube.com/watch?v=SQOdPQQf2Uo + +## Chris Remo - The Wizard +#LOBBY_MUSIC https://www.youtube.com/watch?v=jJDAV9vSmYc + +## Blue Oyster Cult - Sole Survivor +#LOBBY_MUSIC https://www.youtube.com/watch?v=nRjLv1L0WF8 + +## J.G. Thirlwell - In a Spaceage Mood +#LOBBY_MUSIC https://www.youtube.com/watch?v=xhlH91k-86E + +## Carpenter Brut - Escape from Midwich Valley +#LOBBY_MUSIC https://www.youtube.com/watch?v=ZhhQrFfzFM4 + +## God Hand "Rock a Bay" +#LOBBY_MUSIC https://www.youtube.com/watch?v=YGulLVWu-s0 + +## Streets Of Rogue - 5-1 +#LOBBY_MUSIC https://www.youtube.com/watch?v=IhEqUKBTffU + +## Rain World THS - Action Scene +#LOBBY_MUSIC https://www.youtube.com/watch?v=fXvxnDmwB_I + +## The Kinks - Super Sonic Ship +#LOBBY_MUSIC https://www.youtube.com/watch?v=MPPCNM85eRY + +## David Bowie - Starman +#LOBBY_MUSIC https://www.youtube.com/watch?v=tRcPA7Fzebw + +## Dungeons of Dredmor - Diggle Hell +#LOBBY_MUSIC https://www.youtube.com/watch?v=zquJ6AqvVNw + +## Ribbiks - Chasing Suns +#LOBBY_MUSIC https://www.youtube.com/watch?v=uiPJQgw6M_g + +## Ataraxia - Deja Vuzz +#LOBBY_MUSIC https://www.youtube.com/watch?v=7F_xOzLWy5U + +## The Penis (Eek!) - Surasshu +#LOBBY_MUSIC https://www.youtube.com/watch?v=dxDpdfzwuD4 + +## Short Circuit - Daft Punk +#LOBBY_MUSIC https://www.youtube.com/watch?v=TszmdpUtf0A + +## Ben Prunty - FTL - Theme Song +#LOBBY_MUSIC https://www.youtube.com/watch?v=VJ817kvh_DM + +## Stuck in the Sound - Let's G +#LOBBY_MUSIC https://www.youtube.com/watch?v=52Gg9CqhbP8 + +## HOME - Resonance +#LOBBY_MUSIC https://www.youtube.com/watch?v=8GW6sLrK40k + +## Chris Christodoulou - Dies Irae +#LOBBY_MUSIC https://www.youtube.com/watch?v=8DNoXUnaQ9k + +## Chris Christodoulou - ...con lentitud poderosa +#LOBBY_MUSIC https://www.youtube.com/watch?v=Nn9trJXUrp0 + +## Clint Eastwood - Magnum Force Theme +#LOBBY_MUSIC https://www.youtube.com/watch?v=rkas-NHQnsI + +## DM Dokuro - Treasures Within The Abomination +#LOBBY_MUSIC https://www.youtube.com/watch?v=e3t_dbLaw-M + +## Blinch - Loop Hero OST - Loop Blues +#LOBBY_MUSIC https://www.youtube.com/watch?v=2O4C8J4bcXw + +## Blinch - Loop Hero OST - Dark Matter Moon +#LOBBY_MUSIC https://www.youtube.com/watch?v=4q-La8uR0HU + +## Banda Municipal de Manizales - El Pilon +#LOBBY_MUSIC https://www.youtube.com/watch?v=pP6nEgo9UTs + +## Alistair Lindsay - RimWorld OST - Waiting For The Sun +#LOBBY_MUSIC https://www.youtube.com/watch?v=V52QTyn6e-A + +## Pizza Tower OST - Tunnely Shimbers +#LOBBY_MUSIC https://www.youtube.com/watch?v=0-CLAPJ1PLs + +## Jamiroquai - Virtual Insanity +#LOBBY_MUSIC https://www.youtube.com/watch?v=4JkIs37a2JE + +## PilotRedSun - The Grinch's Ultimatum +#LOBBY_MUSIC https://www.youtube.com/watch?v=z01VlftkqY8 + +## Nightmargin - IT'S TIME TO FIGHT CRIME +#LOBBY_MUSIC https://www.youtube.com/watch?v=rcmQefeyPBs + +## Bear McCreary - Wander My Friends +#LOBBY_MUSIC https://www.youtube.com/watch?v=OGcMPp7TNo4 + +## LEMMiNO - Firecracker - CC BY-SA 4.0 +#LOBBY_MUSIC https://soundcloud.com/lemmino/firecracker + +## Bright Primate - Bio-Engineering +#LOBBY_MUSIC https://www.youtube.com/watch?v=bJNXazHoLkE + +## Jeff Imam - The Sadness Club At The Edge Of The Universe +#LOBBY_MUSIC https://soundcloud.com/jeffimam/the-sadness-club-at-the-edge-of-the-universe + +## Jeff Imam - Forest +#LOBBY_MUSIC https://soundcloud.com/jeffimam/forest + +#### Holiday Music +## If you want to make holidays custom lobby music, you should make new config entry +## with special holiday music and change holiday's var value