From 082b25c89c5d9e01249493d03330fdd80577b8e2 Mon Sep 17 00:00:00 2001 From: migatu Date: Tue, 23 Apr 2024 12:59:33 +0200 Subject: [PATCH] Music tunneling (#7) * New requirement * SMall fixes for tunnel * First step towards cogization * Tmp chng * Testing of new functions in conjurer_musician.py and radio_conjurer.liq * Fixes! * Fix fix * Mostly working ? * Requests * Fixes * Fix * Radio requests * Radio hardkor * Fix * Fixes * Change log to print * Clearing fetch failed * Small fix * sx * Fix fix fix * test * el fixo stupido * test * Maybe fix ? * FIX! * Fix fix fix * FIx of volume --- bot.py | 96 ++++++++--- cogs/music.py | 46 ++++++ communication_subroutine.py | 23 +++ conjurer_librarian/search_bot.py | 19 +-- conjurer_musician/conjurer_musician.py | 48 ++++-- conjurer_musician/radio_conjurer.liq | 168 ++++++++++++++------ conjurer_musician/requirements_musician.txt | 3 +- install_music_bot.sh | 3 + 8 files changed, 312 insertions(+), 94 deletions(-) create mode 100644 cogs/music.py diff --git a/bot.py b/bot.py index f0bdd5a..365bc59 100644 --- a/bot.py +++ b/bot.py @@ -44,7 +44,7 @@ import yt_dlp from spotify_dl import spotify from spotify_dl import youtube as youtube_download -from communication_subroutine import comm_subroutine, IN_COMM_Q, OUT_COMM_Q +from communication_subroutine import comm_subroutine, IN_COMM_Q, OUT_COMM_Q, QueryControl # *=========================== Classes definition @@ -62,22 +62,6 @@ Music_Config = TypedDict( ) -class QueryControl: - """ - This class `QueryControl` is used to manage queries with information about the author, UUID, - content, logger, context, and replies. - """ - def __init__(self, query_author, query_uuid, query_content, uplogger, ctx) -> None: - self.author = query_author - self.uuid = query_uuid - self.content = query_content - self.logger = uplogger - self.stop = False - self.ctx = ctx - self.logger.info( - f"Created Query control for {self.author}, {self.uuid}: {self.content}" - ) - self.replies = [] class MusicFileList(object): """ @@ -155,6 +139,7 @@ GET_MP3 = "/mp3" SEND_MP3 = "/update_mp3" GET_PLAYLIST = "/get_music" ADD_TO_PRIO_PLAYLIST = "/add_to_priority" +REQUEST_MUSIC = "/request_radio_file" CLEAR_PRIO = "/clear_pr_pls" LIBRARIAN_SERVICE_ADDRESS = "http://192.168.1.192:5001" SEND_QUERY = "/query" @@ -695,7 +680,6 @@ async def check_data_q(): entries = [] if fresh_data.stop: searcher = fresh_data.author - ctx = fresh_data.ctx query = fresh_data.content l_p = 1 for doi in fresh_data.entries: @@ -705,7 +689,14 @@ async def check_data_q(): entries.append(f"{l_p}. {title} pod linkiem https://www.sci-hub.se/{doi} i jest to {desc['type']}\n") l_p+=1 message = '*Z podłogi wysuwa się winda na książki*' - message += f' Dzielny poszukiwaczu @{searcher} w odpowiedzi na twoje zapytanie {query} nr {fresh_data.uuid}' + if fresh_data.ctx is not None: + ctx = fresh_data.ctx + message += f' Dzielny poszukiwaczu @{searcher} w odpowiedzi na twoje zapytanie {query} nr {fresh_data.uuid}' + else: + ctx = client.get_channel(1062047367337095268) + message += f' Mam wynik dla zapytania {fresh_data.uuid} ale że Hammer coś grzebał nie pamiętam kto to chciał i co chciał' + + message += 'nasza biblioteka służy Ci odpowiedzią. Przy dźwięku fanfar winda się otwiera a w środku ' if len(entries)<1: message += "niestety nie ma nic" @@ -1582,6 +1573,40 @@ async def graj_muzyko(ctx): logger.info("Press play on tape completed") check_music.start() +@client.hybrid_command( + name="radio_hardkor", + description="Włącza radio Conjurer na kanale #nocna-zmiana.", + guild=discord.Object(id=664789470779932693), +) +async def radio_hardkor(ctx): + """ + Plays the radio hardkor stream in the voice channel. + + Args: + ctx: The context object representing the invocation context. + + Returns: + None + """ + logger.info("Press play on radio hardkor") + async with ctx.typing(): + global MUZYKA # pylint: disable=global-variable-not-assigned + MUZYKA["ctx"] = ctx + if not client.voice_clients: + await connect(ctx=ctx) + voice_client = client.voice_clients[0] + voice_client.play( + discord.PCMVolumeTransformer( + discord.FFmpegPCMAudio("http://95.175.16.246:666/mp3-stream"), volume=0.3 + ) + ) + logger.info("Press play on radio completed") + else: + logger.error("Already playing") + await asyncio.sleep(12) + check_music.start() + + @client.hybrid_command( name="cisza", @@ -1757,7 +1782,36 @@ async def dodaj_do_ulubionych(ctx): timeout=360, ) _ = await coroutine +@client.hybrid_command( + name="ja_chciol", + description="Dodaje do listy ulubionych w radiu", + guild=discord.Object(id=664789470779932693), +) +async def request_radio(ctx): + """ + Generate a playlist in queue. First word in this command shall be int defining length of the playlist. + Rest of the line are search terms. + :param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It + represents the context in which the command was invoked, including information such as the message, + the channel, the server, and the user who invoked the command. This parameter is required in all + Discord.py commands + """ + async with ctx.typing(): + logger.info("Zaczynam szukać timestamp %s", datetime.now()) + + word_list = ctx.message.content.split() + jrequest = { + "lista_slow": word_list, + "UUID": str(uuid.uuid4()), + } + coroutine = asyncio.to_thread( + requests.post, + f"{FILE_SERVICE_ADDRESS}{REQUEST_MUSIC}", + json=jrequest, + timeout=360, + ) + _ = await coroutine @client.hybrid_command( name="wyczysc_ulubione", description="Czysci liste ulubionych w radiu", @@ -2324,13 +2378,13 @@ if __name__ == "__main__": WRK_CNT = 0 for worker in threads: WRK_CNT+=1 - logger.info("Starting discord bot: Starting thread {WRK_CNT}") + logger.info("Starting discord bot: Starting thread %s", WRK_CNT) worker.start() logger.info("Starting discord bot: Joining threads") WRK_CNT=0 for worker in threads: WRK_CNT+=1 - logger.info("Starting discord bot: Joining thread {WRK_CNT}") + logger.info("Starting discord bot: Joining thread %s", WRK_CNT) worker.join() # widok - generuje się 5 stron po 4 linki diff --git a/cogs/music.py b/cogs/music.py new file mode 100644 index 0000000..8d77915 --- /dev/null +++ b/cogs/music.py @@ -0,0 +1,46 @@ +import discord +from discord.ext import commands +from typing import Optional + +class Music(commands.Cog): + def __init__(self, bot): + self.bot = bot # This is so you can access Bot instance in your cog + +# You must have this function for `bot.load_extension` to call +def setup(bot): + bot.add_cog(Music(bot)) + +@commands.hybrid_command( + name="przytul", description="Przytul kogoś - daj mention po komendzie :)" +) +async def przytul(ctx, arg: Optional[discord.Member] = None): + """ + Generate a text about hugging mentioned user. + + :param ctx: ctx stands for "context" and is a required parameter in Discord.py commands. It + represents the context in which the command was invoked, including information such as the message, + the channel, the server, and the user who invoked the command + :param arg: arg is a parameter of the function "przytul" that expects a Discord member object. The + parameter is optional, meaning that if no member object is provided, it will default to None + :type arg: Optional[discord.Member] + """ + async with ctx.typing(): + nieprzytulac = False + for mention in ctx.message.mentions: + for role in mention.roles: + if role.name == "NIEPRZYTULAĆ!": + nieprzytulac = True + + if arg and nieprzytulac: + await ctx.send( + f"Żebym ja Ciebie nie przytulił {ctx.message.author.mention}" + ) + elif arg: + await ctx.send( + # trunk-ignore(codespell/misspelled) + f"Już dobrze.... Już dobrze... Ojej.. Biedactwo... :( *W ułamku sekundy {arg.mention} znajduje sie w duszącym uścisku. Żebra trzeszczą - kilka pęka. Pacnięcia po plecach grożą odbiciem nerek, a głaskanie po głowie powoduje wstrząs mózgu*" + ) + else: + await ctx.send( + "Kogo mam przytulić? *Wyłamuje kostki i przeciąga się - jego 200 kilowa sylwetka złożona z samych mięśni świadczy o tym że jest gotowy*" + ) diff --git a/communication_subroutine.py b/communication_subroutine.py index 4b53099..3cda26c 100644 --- a/communication_subroutine.py +++ b/communication_subroutine.py @@ -13,6 +13,22 @@ IN_COMM_Q = Queue() awaiting_q = [] incoming_q = Queue() app = Flask(__name__) +class QueryControl: + """ + This class `QueryControl` is used to manage queries with information about the author, UUID, + content, logger, context, and replies. + """ + def __init__(self, query_author, query_uuid, query_content, uplogger, ctx) -> None: + self.author = query_author + self.uuid = query_uuid + self.content = query_content + self.logger = uplogger + self.stop = False + self.ctx = ctx + self.logger.info( + f"Created Query control for {self.author}, {self.uuid}: {self.content}" + ) + self.replies = [] @app.route("/conjurer", methods=["POST"]) def answer_external_command(): @@ -91,6 +107,13 @@ def scan_incoming(_logger): record.stop = True record.entries = answer[record.uuid] IN_COMM_Q.put(record) + else: + for key in answer.keys(): + record = QueryControl("Orphaned", key, "Orphan", _logger, None) + record.stop = True + record.entries = answer[record.uuid] + record.uuid = "000000" + IN_COMM_Q.put(record) except Empty: time.sleep(1) diff --git a/conjurer_librarian/search_bot.py b/conjurer_librarian/search_bot.py index 52898a2..9c1cb8c 100644 --- a/conjurer_librarian/search_bot.py +++ b/conjurer_librarian/search_bot.py @@ -68,7 +68,7 @@ def producer(out_q, control_q, filename, _logger): # IMPORTANT!!! ONLY ONE CONSUMER THREAD AS WE ARE NOT PUTTING SENTINELS BACK -def consumer(in_q, control_q, doi, live_results, result_list, _logger, ): +def consumer(in_q, control_q, doi, live_results, result_list, control_dict, _logger): """ Consumes items from an input queue and checks if DOI exists in the live results list. @@ -79,7 +79,6 @@ def consumer(in_q, control_q, doi, live_results, result_list, _logger, ): live_results (list): List to store the search results. _logger: Logger object for logging. """ - sentinels = 0 for item in doi: result_list.append({"DOI": item[0], "exists": False, "data": item[1]}) while True: @@ -87,7 +86,7 @@ def consumer(in_q, control_q, doi, live_results, result_list, _logger, ): data = in_q.get() if data is _sentinel: _logger.info("Worker finished") - sentinels += 1 + control_dict["sentinels"] += 1 else: for item in result_list: if item["DOI"] in data and not item["exists"]: @@ -98,7 +97,7 @@ def consumer(in_q, control_q, doi, live_results, result_list, _logger, ): done_check = done_check and item["exists"] if done_check: control_q.put(_sentinel) - if sentinels >= MAXTHREADS: + if control_dict["sentinels"] >= MAXTHREADS: _logger.info("All workers finished") break @@ -112,15 +111,17 @@ def search_for_doi(doi, live_results, _logger): live_results (list): List to store the search results. _logger: Logger object for logging. """ + control_dict = {"sentinels":0} result_list = [] threads = [] work_q = Queue(maxsize=WORK_Q_SIZE) control_q = Queue() - t_cons = Thread( - target=consumer, args=(work_q, control_q, doi, live_results, result_list, _logger) - ) - _logger.info("Consumer thread created") - threads.append(t_cons) + for _ in range (1, len(doi)//1000+1): + t_cons = Thread( + target=consumer, args=(work_q, control_q, doi, live_results, result_list, control_dict, _logger) + ) + _logger.info("Consumer thread created") + threads.append(t_cons) for i in range(0, MAXTHREADS): # TEST DATA # filename = "test" + str(i) + CHUNk diff --git a/conjurer_musician/conjurer_musician.py b/conjurer_musician/conjurer_musician.py index fc0742e..b22a1f2 100644 --- a/conjurer_musician/conjurer_musician.py +++ b/conjurer_musician/conjurer_musician.py @@ -238,13 +238,6 @@ def wyszukaj(word_list, how_many, _logger=None, return_to_bot=True): fun_logger.info("Wiele plików do zagrania") search_weight.sort(key=lambda x: x[0], reverse=True) return_list.extend(search_weight[: int(how_many)]) - if not return_to_bot: - - with open( - "/home/pi/Conjurer/priority_queue.playlist", "a", encoding="utf-8" - ) as s_file: - for item in return_list: - s_file.write(item[1] + "\n") return return_list @@ -386,16 +379,41 @@ def look_for_playlist(): return return_data +@app.route("/request_radio_file", methods=["POST"]) +def add_request(): + record = json.loads(request.data) + app.logger.info(record) + app.logger.info(record["lista_slow"]) + app.logger.info(record["UUID"]) + return_data = wyszukaj( + record["lista_slow"], 0, app.logger, False + ) + + with open( + "/home/pi/Conjurer/request.playlist", "a", encoding="utf-8" + ) as s_file: + for item in return_data: + s_file.write(item[1] + "\n") + return_data = ( + jsonify(isError=False, message="Success", statusCode=200, data={"status": "OK"}), + 200, + ) + return return_data + + + @app.route("/add_to_priority", methods=["POST"]) def add_to_priority(): """ The function `add_to_priority` receives a POST request with a JSON payload, logs the received item, adds it to a music file list, and returns a success message along with the updated record. - :return: A tuple containing a JSON response and a status code. The JSON response includes keys `isError`, - `message`, `statusCode`, and `data`, with values indicating the success of the operation and the - data that was received and added to the `music_file_list`. The status code returned is 200, - indicating a successful response. + :return: A tuple containing a JSON response and a status code. + The JSON response includes keys `isError`, + `message`, `statusCode`, and `data`, with values + indicating the success of the operation and the + data that was received and added to the `music_file_list`. + The status code returned is 200,indicating a successful response. """ record = json.loads(request.data) app.logger.info(record) @@ -405,9 +423,13 @@ def add_to_priority(): return_data = wyszukaj( record["lista_slow"], record["dlugosc_plejlisty"], app.logger, False ) - + with open( + "/home/pi/Conjurer/priority_queue.playlist", "a", encoding="utf-8" + ) as s_file: + for item in return_data: + s_file.write(item[1] + "\n") return_data = ( - jsonify(isError=False, message="Success", statusCode=200, data=return_data), + jsonify(isError=False, message="Success", statusCode=200, data={"status": "OK"}), 200, ) return return_data diff --git a/conjurer_musician/radio_conjurer.liq b/conjurer_musician/radio_conjurer.liq index 6ab2f70..fc36524 100644 --- a/conjurer_musician/radio_conjurer.liq +++ b/conjurer_musician/radio_conjurer.liq @@ -5,67 +5,135 @@ # Load icecast credentials from a JSON file let json.parse credentials = file.contents("/home/pi/Conjurer/icecast_credentials.json") -# Enable replaygain metadata processing -enable_replaygain_metadata() + # Enable replaygain metadata processing + enable_replaygain_metadata() + l = playlog(duration = 14400.0, persistency="/home/pi/Conjurer/persistence.log") + def check(r) + m = request.metadata(r) + if l.last(m) < 3600. then + log.info("Rejecting #{m['filename']} (played #{l.last(m)}s ago).") + false + else + l.add(m) + true + end + end -# Define playlists to be used in the stream -s1 = replaygain(playlist(reload_mode="watch", "/home/pi/Conjurer/all_playlist.playlist")) -s2 = replaygain(playlist(reload_mode="watch", "/home/pi/Conjurer/priority_queue.playlist")) -s3 = replaygain(playlist(reload_mode="watch", "/home/pi/Conjurer/hit.playlist")) -# Randomly select a playlist with weights -s = random(id="randomizer", weights=[1, 3, 2], [s1, s2, s3]) -# Set up an interactive harbor for controlling the stream -interactive.harbor(port = 9999) + # Define playlists to be used in the stream + s1 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/all_playlist.playlist")) + s2 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/priority_queue.playlist")) + s3 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/hit.playlist")) + requests_queue = request.queue() + def queue_processing() + f1=file.read("/home/pi/Conjurer/request.playlist") + text = f1() + if text != "" then + requests_queue.push.uri(text) + file.remove("/home/pi/Conjurer/request.playlist") + f = file.open("/home/pi/Conjurer/request.playlist", create=true) + f.close() + log.info("done") + else + log.info("no requests") + end + end + thread.run(every=60., queue_processing) -# Set up interactive controls for bass boost -f = interactive.float("f", description="Frequency", min=0., max=1000., unit="Hz", 200.) -g = interactive.float("g", description="Gain", min=0., max=20., unit="dB", 8.) -b = bass_boost(frequency=f, gain=g, s) -s = add([s, b]) + # Randomly select a playlist with weights + s = random(id="randomizer", weights=[1, 3, 2], [s1, s2, s3]) + #s = delay(duration=5., s) + #radio = add([delay(1800., jingles), music]) + #radio = fallback([delay(1800., jingles), music]) + #p = predicate.signal() + #radio = switch([(p, jingles), ({true}, music)]) + #thread.run(every=1200., {p.signal()}) +# def cmd(_) +# p.signal() +# "Jingle inserted!" +# end +# server.register("insert_jingle", cmd) -# Set up interactive control for main volume -a = interactive.float("main_volume", min=0., max=20., 1.) -s = compress.multiband.interactive(bands=3, s) + # Set up an interactive harbor for controlling the stream + interactive.harbor(port = 9999) + # Set up interactive controls for bass boost + f = interactive.float("f", description="Frequency", min=0., max=1000., unit="Hz", 200.) + g = interactive.float("g", description="Gain", min=0., max=20., unit="dB", 8.) + b = bass_boost(frequency=f, gain=g, s) + s = add([s, b]) + # Set up interactive control for main volume + a = interactive.float("main_volume", min=0., max=20., 1.) + s = compress.multiband.interactive(bands=3, s) -# Apply audio processing effects -s = nrj(normalize(s)) -s = crossfade(fade_out=3., fade_in=3., duration=5., s) -s = amplify(a, s) + # Apply audio processing effects + s = nrj(normalize(s)) + s = crossfade(fade_out=3., fade_in=3., duration=5., s) + s = amplify(a, s) -# Skip blank sections in the stream -s = blank.skip(max_blank=2., s) + # Skip blank sections in the stream + s = blank.skip(max_blank=2., s) -# Configure logging settings -log_to_stdout = true -log_to_file = true -logpath = "/home/pi/Conjurer/radio_log.log" -loglevel = 4 -set("log.stdout", log_to_stdout) -set("log.level", loglevel) + # Configure logging settings + log_to_stdout = true + log_to_file = true + logpath = "/home/pi/Conjurer/radio_log.log" + loglevel = 4 + set("log.stdout", log_to_stdout) + set("log.level", loglevel) -# Enable logging to file -set("log.file", log_to_file) -set("log.file.path", logpath) + # Enable logging to file + set("log.file", log_to_file) + set("log.file.path", logpath) -# Set up emergency fallback track -emergency = single("/home/pi/RetroPie/mp3/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3") + # Set up emergency fallback track + emergency = single("/home/pi/RetroPie/mp3/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3") -# Create a fallback stream with the main stream and emergency track -radio = fallback(id="switcher", track_sensitive=false, [s, emergency]) + # Create a fallback stream with the main stream and emergency track + radio = fallback(id="switcher", track_sensitive=true, [requests_queue, s, emergency]) -# Handle metadata events -handle_metadata = fun (m) -> begin - log.info(m["title"]) - log.info(m["artist"]) - log.info(m["filename"]) -end -radio.on_metadata(handle_metadata) + # Handle metadata events + handle_metadata = fun (m) -> begin + log.info(m["title"]) + log.info(m["artist"]) + log.info(m["filename"]) + end + radio.on_metadata(handle_metadata) -# Enable persistent script parameters -interactive.persistent("script.params") + # Enable persistent script parameters + interactive.persistent("script.params") -# Configure output formats and destinations -output.file.hls("/tmp/hls", [("mp3-low", %mp3(bitrate=96)), ("mp3-hi", %mp3(bitrate=160))], radio) -output.icecast(%mp3, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="mp3-stream", radio) + # Configure output formats and destinations + output.file.hls("/tmp/hls", [("mp3-low", %mp3(bitrate=96)), ("mp3-hi", %mp3(bitrate=160))], radio) + output.icecast(%mp3, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="mp3-stream", radio) +# output.icecast(%opus, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="opus-stream", radio) +# output.icecast(%ogg, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="ogg-stream", radio) +# output.icecast(%aac, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="aac-stream", radio) +# output.icecast(%flac, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="flac-stream", radio) +# output.icecast(%vorbis, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="vorbis-stream", radio) +# output.icecast(%speex, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="speex-stream", radio) +# output.icecast(%wav, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="wav-stream", radio) +# output.icecast(%pcm, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="pcm-stream", radio) +# output.icecast(%raw, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="raw-stream", radio) +# output.icecast(%s16l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s16l-stream", radio) +# output.icecast(%s16b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s16b-stream", radio) +# output.icecast(%s24l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s24l-stream", radio) +# output.icecast(%s24b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s24b-stream", radio) +# output.icecast(%s32l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s32l-stream", radio) +# output.icecast(%s32b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s32b-stream", radio) +# output.icecast(%s64l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s64l-stream", radio) +# output.icecast(%s64b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s64b-stream", radio) +# output.icecast(%s128l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s128l-stream", radio) +# output.icecast(%s128b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s128b-stream", radio) +# output.icecast(%s256l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s256l-stream", radio) +# output.icecast(%s256b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s256b-stream", radio) +# output.icecast(%s512l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s512l-stream", radio) +# output.icecast(%s512b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s512b-stream", radio) +# output.icecast(%s1024l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s1024l-stream", radio) +# output.icecast(%s1024b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s1024b-stream", radio) +# output.icecast(%s2048l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s2048l-stream", radio) +# output.icecast(%s2048b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s2048b-stream", radio) +# output.icecast(%s4096l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s4096l-stream", radio) +# output.icecast(%s4096b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s4096b-stream", radio) +# output.icecast(%s8192l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s8192l-stream", radio) +# output.icecast(%s8192b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s8192b-stream", radio) diff --git a/conjurer_musician/requirements_musician.txt b/conjurer_musician/requirements_musician.txt index 8642e2b..e298c25 100644 --- a/conjurer_musician/requirements_musician.txt +++ b/conjurer_musician/requirements_musician.txt @@ -1,2 +1,3 @@ flask -waitress \ No newline at end of file +waitress +sshtunnel \ No newline at end of file diff --git a/install_music_bot.sh b/install_music_bot.sh index b708d18..210c6c5 100755 --- a/install_music_bot.sh +++ b/install_music_bot.sh @@ -15,6 +15,9 @@ touch /home/pi/Conjurer/prio_playlist.json touch /home/pi/Conjurer/all_playlist.playlist touch /home/pi/Conjurer/priority_queue.playlist touch /home/pi/Conjurer/hit.playlist +touch /home/pi/Conjurer/request.playlist +touch /home/pi/Conjurer/persistence.log +echo "[]" > /home/pi/Conjurer/persistence.log touch /home/pi/Conjurer/radio_log.log ./env/bin/python3 -m pip install --upgrade pip