From 7643af19a8a297d665d493f51e25dd712cea5015 Mon Sep 17 00:00:00 2001 From: Karl Date: Sun, 14 Nov 2021 19:29:35 +0000 Subject: [PATCH] latest updates --- .gitignore | 2 +- .vscode/launch.json | 21 +++++- SongLocations | 4 +- buttons.py | 70 ++++++++++-------- intro.py | 85 ++++++++++++++++++++++ media_change.sh | 4 +- player.py | 64 +++++++++-------- requirements.txt | 2 +- screen.py | 168 ++++++++++++++++++++++++++++++++++++++++++++ screen_output.py | 81 --------------------- startupScript | 3 + sync_screen.py | 84 ---------------------- 12 files changed, 357 insertions(+), 231 deletions(-) mode change 100644 => 100755 buttons.py create mode 100644 intro.py mode change 100644 => 100755 player.py create mode 100644 screen.py delete mode 100644 screen_output.py create mode 100755 startupScript delete mode 100644 sync_screen.py diff --git a/.gitignore b/.gitignore index e192e77..4f951ed 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ venv demo_client.py test.py mount.log -last_disk.txt +last_disk.txt \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 8c96d83..ae8e70c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,13 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + }, { "name": "Screen", "type": "python", @@ -11,6 +18,13 @@ "program": "./screen_output.py", "console": "integratedTerminal" }, + { + "name": "sync-Screen", + "type": "python", + "request": "launch", + "program": "./sync_screen.py", + "console": "integratedTerminal" + }, { "name": "yt diskLoad", "type": "python", @@ -18,7 +32,10 @@ "program": "./player.py", "console": "integratedTerminal", "args": [ - "Daft Punk RAM - ytmusic:album:MPREb_K8qWMWVqXGi" + // "Daft Punk RAM - ytmusic:album:MPREb_K8qWMWVqXGi" + // "-", + // "my likes - ytmusic:playlist:LM" + "Capital Xtra Reloaded - tunein:station:s306339" // " Xtra Reloaded - http://media-ice.musicradio.com/CapitalXTRAReloadedMP3.m3u" ] }, @@ -29,7 +46,7 @@ "program": "./player.py", "console": "integratedTerminal", "args": [ - "stop" + "shuffle" ] } ] diff --git a/SongLocations b/SongLocations index ba7121d..82ef5e8 100644 --- a/SongLocations +++ b/SongLocations @@ -1,4 +1,4 @@ -Chris Brown Indigo - ytmusic:album:MPREb_jlY9mqAHYjR +Chris Brown Indigo - ytmusic:album:MPREb_2UBRpewr9ad Daft Punk RAM - ytmusic:album:MPREb_K8qWMWVqXGi @@ -7,4 +7,4 @@ My Likes - ytmusic:playlist:LM Radio -http://media-ice.musicradio.com/CapitalXTRAReloadedMP3.m3u \ No newline at end of file +Capital Xtra Reloaded - tunein:station:s306339 \ No newline at end of file diff --git a/buttons.py b/buttons.py old mode 100644 new mode 100755 index 352c72f..e7f668b --- a/buttons.py +++ b/buttons.py @@ -1,9 +1,9 @@ + from gpiozero import Button from signal import pause import time import subprocess -import beepy as beep - +import pathlib Button.was_held = False @@ -12,34 +12,44 @@ Button.was_held = False def vol_up(btn): btn.was_held = True while btn.was_held: - # print("Vol Up") + print("Vol Up") result = subprocess.run( [f"mpc volume +10"], stdout=subprocess.PIPE, shell=True, ).stdout.decode("utf-8") - # beep(sound=1) - time.sleep(0.5) + time.sleep(0.3) def vol_down(btn): btn.was_held = True while btn.was_held: - # print("Vol Down") + print("Vol Down") result = subprocess.run( [f"mpc volume -10"], stdout=subprocess.PIPE, shell=True, ).stdout.decode("utf-8") - # beep(sound=1) - time.sleep(0.5) + time.sleep(0.3) + + +def mute(btn): + btn.was_held = True + while btn.was_held: + print("Mute") + result = subprocess.run( + [f"mpc volume -10"], + stdout=subprocess.PIPE, + shell=True, + ).stdout.decode("utf-8") + time.sleep(0.3) def playpause_down(btn): btn.was_held = True while btn.was_held: print("playpause") - time.sleep(1) + time.sleep(0.3) def released(btn): @@ -49,47 +59,51 @@ def released(btn): def pressed(btn): - if btn._pin.number == 15: - # print("next") + if btn._pin.number == up_pin: + print("next") result = subprocess.run( - [f"python ./player.py next"], + [f"{pathlib.Path().resolve()}/venv/bin/python3 ./player.py next"], stdout=subprocess.PIPE, shell=True, ).stdout.decode("utf-8") - elif btn._pin.number == 24: - # print("back") + elif btn._pin.number == down_pin: + print("back") result = subprocess.run( - [f"python ./player.py previous"], + [f"{pathlib.Path().resolve()}/venv/bin/python3 ./player.py previous"], stdout=subprocess.PIPE, shell=True, ).stdout.decode("utf-8") - elif btn._pin.number == 14: - # print("playpause") + elif btn._pin.number == playpause_pin: + print("playpause") result = subprocess.run( - [f"python ./player.py playpause"], + [f"{pathlib.Path().resolve()}/venv/bin/python3 ./player.py playpause"], stdout=subprocess.PIPE, shell=True, ).stdout.decode("utf-8") - elif btn._pin.number == 23: - # print("shuffle") + elif btn._pin.number == shuffle_pin: + print("shuffle") result = subprocess.run( - [f"python ./player.py shuffle"], + [f"{pathlib.Path().resolve()}/venv/bin/python3 ./player.py shuffle"], stdout=subprocess.PIPE, shell=True, ).stdout.decode("utf-8") -up_btn = Button(15) -down_button = Button(24) -playpause_button = Button(14) -shuffle_button = Button(23) +up_pin = 24 +down_pin = 15 +playpause_pin = 14 +shuffle_pin = 23 -down_button.when_held = vol_down -down_button.when_released = released +up_btn = Button(up_pin) +down_button = Button(down_pin) +playpause_button = Button(playpause_pin) +shuffle_button = Button(shuffle_pin) up_btn.when_held = vol_up up_btn.when_released = released - +down_button.when_held = vol_down +down_button.when_released = released +playpause_button.when_held = mute playpause_button.when_released = released shuffle_button.when_released = released pause() diff --git a/intro.py b/intro.py new file mode 100644 index 0000000..72e6fd6 --- /dev/null +++ b/intro.py @@ -0,0 +1,85 @@ +import math +import time + +import Adafruit_GPIO.SPI as SPI +import Adafruit_SSD1306 + +from PIL import Image +from PIL import ImageFont +from PIL import ImageDraw + + +RST = 24 + +# 128x64 display with hardware I2C: +disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) + +# Initialize library. +disp.begin() + +# Get display width and height. +width = disp.width +height = disp.height + +# Clear display. +disp.clear() +disp.display() + +# Create image buffer. +# Make sure to create image with mode '1' for 1-bit color. +image = Image.new('1', (width, height)) + +# Load default font. +font = ImageFont.load_default() + +# Alternatively load a TTF font. Make sure the .ttf font file is in the same directory as this python script! +# Some nice fonts to try: http://www.dafont.com/bitmap.php +# font = ImageFont.truetype('Minecraftia.ttf', 8) + +# Create drawing object. +draw = ImageDraw.Draw(image) + +# Define text and get total width. +text = 'Floppy Player' +maxwidth, unused = draw.textsize(text, font=font) + +# Set animation and sine wave parameters. +amplitude = height/4-10 +offset = height/2 - 4 +velocity = -2 +startpos = width + +# Animate text moving in sine wave. +# print('Press Ctrl-C to quit.') +pos = startpos +while True: + # Clear image buffer by drawing a black filled box. + draw.rectangle((0,0,width,height), outline=0, fill=0) + # Enumerate characters and draw them offset vertically based on a sine wave. + x = pos + for i, c in enumerate(text): + # Stop drawing if off the right side of screen. + if x > width: + break + # Calculate width but skip drawing if off the left side of screen. + if x < -10: + char_width, char_height = draw.textsize(c, font=font) + x += char_width + continue + # Calculate offset from sine wave. + y = offset+math.floor(amplitude*math.sin(x/float(width)*2.0*math.pi)) + # Draw text. + draw.text((x, y), c, font=font, fill=255) + # Increment x position based on chacacter width. + char_width, char_height = draw.textsize(c, font=font) + x += char_width + # Draw the image buffer. + disp.image(image) + disp.display() + # Move position for next frame. + pos += velocity + # Start over if text has scrolled completely off left side of screen. + if pos < -maxwidth: + break + # Pause briefly before drawing next frame. + time.sleep(0.1) \ No newline at end of file diff --git a/media_change.sh b/media_change.sh index 39e4473..0cbcd4f 100755 --- a/media_change.sh +++ b/media_change.sh @@ -19,10 +19,10 @@ if [ $? -eq 0 ]; then echo "$(date) Floppy mounted" var=$(cat /mnt/floppy/diskplayer.contents) echo python3 /home/pi/pythonDiskPlayer/player.py \"$var\" - runuser -l pi -c "python3 /home/pi/pythonDiskPlayer/player.py \"$var\"" + runuser -l pi -c "/home/pi/pythonDiskPlayer/venv/bin/python3 /home/pi/pythonDiskPlayer/player.py \"$var\"" else echo "$(date) Device does not exist on machine." - runuser -l pi -c "python3 /home/pi/pythonDiskPlayer/player.py stop" + runuser -l pi -c "/home/pi/pythonDiskPlayer/venv/bin/python3 /home/pi/pythonDiskPlayer/player.py stop" echo "$(date) Forcing unmount of floppy" /usr/bin/systemd-mount --umount /mnt/floppy fi diff --git a/player.py b/player.py old mode 100644 new mode 100755 index 1e3d3c6..2d3432f --- a/player.py +++ b/player.py @@ -1,60 +1,64 @@ -import asyncio import argparse +import pathlib -from mopidy_async_client import MopidyClient +from mopidy_json_client import MopidyClient parser = argparse.ArgumentParser(description="Mopdiy FloppyPlayer") parser.add_argument("URI_string", help="Mopdiy URI to Album/Playlist.") args = parser.parse_args() inputURI = args.URI_string +disk_file = f"{pathlib.Path().resolve()}/last_disk.txt" -async def selector(action): - last_disk_read = open("/home/pi/pythonDiskPlayer/last_disk.txt", "r+").read() +mopidy = MopidyClient() + + +def selector(action): + last_disk_read = open(disk_file, "r+").read() if action is not "" and last_disk_read != action: - mopidy = await MopidyClient().connect() if action == "stop": - await mopidy.playback.stop() - await mopidy.tracklist.clear() + mopidy.playback.stop() + mopidy.tracklist.clear() elif action == "next": - await mopidy.playback.next() + mopidy.playback.next() elif action == "previous": - await mopidy.playback.previous() + mopidy.playback.previous() elif action == "shuffle": - await mopidy.tracklist.shuffle() - await mopidy.tracklist.move( - start=await mopidy.tracklist.index(), - end=await mopidy.tracklist.index(), + mopidy.tracklist.shuffle() + mopidy.tracklist.move( + start=mopidy.tracklist.index(), + end=mopidy.tracklist.index(), to_position=0, ) elif action == "playpause": - if await mopidy.playback.get_state() == "playing": - await mopidy.playback.pause() + if mopidy.playback.get_state() == "playing": + mopidy.playback.pause() else: - await mopidy.playback.resume() + mopidy.playback.resume() elif action == "": return else: - last_disk = open("/home/pi/pythonDiskPlayer/last_disk.txt", "w") + last_disk = open(disk_file, "w") last_disk.write(action) - await run_floppy(action) - await mopidy.disconnect() + run_floppy(action) + mopidy.disconnect() + elif action == "": + pass else: - mopidy = await MopidyClient().connect() - if await mopidy.playback.get_state() == "playing": + if mopidy.playback.get_state() == "playing": return else: - await run_floppy(action) + run_floppy(action) + mopidy.disconnect() -async def run_floppy(input): +def run_floppy(input): link = input.split(" - ")[1] - mopidy = await MopidyClient().connect() - await mopidy.playback.stop() - await mopidy.tracklist.clear() - await mopidy.tracklist.add(uris=[link]) - await mopidy.playback.play() - await mopidy.disconnect() + mopidy.playback.stop() + mopidy.tracklist.clear() + mopidy.tracklist.add(uris=[link]) + mopidy.playback.play() + mopidy.disconnect() -asyncio.run(selector(inputURI)) +selector(inputURI) diff --git a/requirements.txt b/requirements.txt index a8a4ac0..b5ad7dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ black==21.10b0 click==8.0.3 future==0.18.2 importlib-metadata==4.8.1 -mopidy-async-client==0.6.4 +Mopidy-JSON-Client==0.6.0 mypy-extensions==0.4.3 pathspec==0.9.0 pkg-resources==0.0.0 diff --git a/screen.py b/screen.py new file mode 100644 index 0000000..e0f8b80 --- /dev/null +++ b/screen.py @@ -0,0 +1,168 @@ +from signal import pause +import time +import board +import adafruit_ssd1306 + +from mopidy_json_client import MopidyClient + +from datetime import datetime + + +def print_oled(data): + oled.fill(0) + oled.text("Floppy Player", 26, 0, 1) + oled.text(data["line1"]["text"], data["line1"]["line"], data["line1"]["row"], 1) + oled.text(data["line2"]["text"], data["line2"]["line"], data["line2"]["row"], 1) + oled.text(data["line3"]["text"], data["line3"]["line"], data["line3"]["row"], 1) + oled.text(data["line4"]["text"], data["line4"]["line"], data["line4"]["row"], 1) + oled.show() + + +def clear_old(): + oled.fill(0) + oled.text("Floppy Player", 26, 0, 1) + oled.text("", 0, 0, 1) + oled.text("", 0, 0, 1) + oled.text("", 0, 0, 1) + oled.text("", 0, 0, 1) + oled.show() + + +def print_track_info(tl_track, title=False): + track = tl_track.get("track") if tl_track else None + if not track: + print("No Track") + return + if title != False: + print_oled( + { + "line1": {"text": track.get("album").get("name"), "line": 0, "row": 16}, + "line2": { + "text": track.get("name"), + "line": 0, + "row": 26, + }, + "line3": {"text": title[1], "line": 0, "row": 36}, + "line4": {"text": title[0], "line": 0, "row": 46}, + } + ) + else: + print_oled( + { + "line1": {"text": track.get("name"), "line": 0, "row": 16}, + "line2": { + "text": track.get("artists")[0].get("name"), + "line": 0, + "row": 26, + }, + "line3": {"text": track.get("album").get("name"), "line": 0, "row": 36}, + "line4": {"text": "", "line": 0, "row": 46}, + } + ) + + +def stream_title_changed(title): + data = title.split(" - ") + print_track_info(mopidy.playback.get_current_tl_track(), data) + + +def playback_state_changed(old_state, new_state): + state = new_state + if state == "paused": + print_oled( + { + "line1": {"text": "", "line": 0, "row": 16}, + "line2": {"text": "", "line": 0, "row": 26}, + "line3": {"text": "Paused", "line": 32, "row": 36}, + "line4": {"text": "", "line": 0, "row": 46}, + } + ) + elif state == "stopped": + print_oled( + { + "line1": {"text": "", "line": 0, "row": 16}, + "line2": {"text": "Nothing", "line": 40, "row": 26}, + "line3": {"text": "Playing", "line": 40, "row": 36}, + "line4": {"text": "Insert a Disk", "line": 25, "row": 46}, + } + ) + elif state == "playing": + print_track_info(mopidy.playback.get_current_tl_track()) + + +def volume_changed(volume): + global old_vol + if old_vol != volume: + old_vol = volume + print_oled( + { + "line1": {"text": "", "line": 0, "row": 16}, + "line2": {"text": "Current Volume", "line": 32, "row": 26}, + "line3": {"text": str(volume), "line": 32, "row": 36}, + "line4": {"text": "", "line": 0, "row": 46}, + } + ) + time.sleep(1) + get_state() + + +def mute_changed(mute): + if mute == True: + print_oled( + { + "line1": {"text": "", "line": 0, "row": 16}, + "line2": {"text": "Muted", "line": 32, "row": 26}, + "line3": {"text": "", "line": 32, "row": 36}, + "line4": {"text": "", "line": 0, "row": 46}, + } + ) + else: + get_state() + + +# def options_changed(): +# options = { +# "random": mopidy.tracklist.get_random(timeout=10), +# "single": mopidy.tracklist.get_single(timeout=10), +# "consume": mopidy.tracklist.get_consume(timeout=10), +# "repeat": mopidy.tracklist.get_repeat(timeout=10), +# } +# print("Tracklist Options:", options, format="expand") + + +def seeked(time_position): + print(f" Current Position is {time_position}") + + +mopidy = MopidyClient() +mopidy.bind_event("track_playback_started", print_track_info) +mopidy.bind_event("playback_state_changed", playback_state_changed) +mopidy.bind_event("stream_title_changed", stream_title_changed) +mopidy.bind_event("volume_changed", volume_changed) +mopidy.bind_event("mute_changed", mute_changed) +mopidy.bind_event("seeked", seeked) + + +WIDTH = 128 +HEIGHT = 64 + +# Use for I2C. +i2c = board.I2C() +oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C) + + +def get_state(): + state = mopidy.playback.get_state() + if state == "playing": + print_track_info(mopidy.playback.get_current_tl_track()) + elif state == "paused": + playback_state_changed("running", "paused") + elif state == "stopped": + playback_state_changed("running", "stopped") + + +old_vol = mopidy.mixer.get_volume() +import intro +clear_old() +get_state() +pause() diff --git a/screen_output.py b/screen_output.py deleted file mode 100644 index 277e949..0000000 --- a/screen_output.py +++ /dev/null @@ -1,81 +0,0 @@ -import asyncio -import time -import board -import adafruit_ssd1306 - -from mopidy_async_client import MopidyClient -from datetime import datetime - - -async def current_track(): - mopidy = await MopidyClient().connect() - if await mopidy.playback.get_state() == "stopped": - oled.text("Nothing", 32, 26, 1) - oled.text("Playing", 32, 36, 1) - return - current_track_data = await mopidy.playback.get_current_track() - time_position = datetime.fromtimestamp( - await mopidy.playback.get_time_position() / 1000.0 - ).strftime("%M:%S") - if "ytmusic" in current_track_data["uri"]: - if "album" in current_track_data: - totalTime = current_track_data["length"] - track_total_length = datetime.fromtimestamp(totalTime / 1000.0).strftime( - "%M:%S" - ) - current_data = { - "Artist": current_track_data["artists"][0]["name"], - "Album": current_track_data["album"]["name"], - "Song": current_track_data["name"], - "TrackTime": time_position + "/" + track_total_length, - } - elif "ytmusic:track" in current_track_data["uri"]: - totalTime = current_track_data["length"] - track_total_length = datetime.fromtimestamp(totalTime / 1000.0).strftime( - "%M:%S" - ) - current_data = { - "Artist": "-", - "Album": current_track_data["artists"][0]["name"], - "Song": current_track_data["name"], - "TrackTime": time_position + "/" + track_total_length, - } - else: - try: - stream_title = await mopidy.playback.get_stream_title() - artist_and_song = stream_title.split(" - ") - except: - stream_title = "None" - artist_and_song = ['None','None'] - current_data = { - "Artist": current_track_data["name"], - "Album": artist_and_song[0], - "Song": artist_and_song[1], - "TrackTime": "", - } - await mopidy.disconnect() - oled.text(current_data["Artist"], 0, 16, 1) - oled.text(current_data["Album"], 0, 26, 1) - oled.text(current_data["Song"], 0, 36, 1) - oled.text(current_data["TrackTime"], 0, 46, 1) - return - - -WIDTH = 128 -HEIGHT = 64 - -# Use for I2C. -i2c = board.I2C() -oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C) - - -async def main(): - while True: - oled.fill(0) - oled.text("Floppy Player", 26, 0, 1) - await current_track() - oled.show() - time.sleep(5) - - -asyncio.run(main()) diff --git a/startupScript b/startupScript new file mode 100755 index 0000000..dc1cc9e --- /dev/null +++ b/startupScript @@ -0,0 +1,3 @@ +sudo rm -rf /home/pi/pythonDiskPlayer/mount.log & +screen -S buttons -dm /home/pi/pythonDiskPlayer/venv/bin/python3 /home/pi/pythonDiskPlayer/buttons.py & +screen -S screen -dm /home/pi/pythonDiskPlayer/venv/bin/python3 /home/pi/pythonDiskPlayer/screen.py \ No newline at end of file diff --git a/sync_screen.py b/sync_screen.py deleted file mode 100644 index 520b101..0000000 --- a/sync_screen.py +++ /dev/null @@ -1,84 +0,0 @@ -import time -import board -import adafruit_ssd1306 -from tenacity import retry, stop_after_attempt - -from mopidy_json_client import MopidyClient - -from datetime import datetime - - -@retry(stop=stop_after_attempt(5)) -def current_track(): - mopidy = MopidyClient() - if mopidy.playback.get_state(timeout=5) == "stopped": - oled.text("Nothing", 32, 26, 1) - oled.text("Playing", 32, 36, 1) - return - if mopidy.playback.get_state(timeout=5) == "paused": - oled.text("Paused", 32, 36, 1) - return - current_track_data = mopidy.playback.get_current_track(timeout=5) - time_position = datetime.fromtimestamp( - mopidy.playback.get_time_position(timeout=5) / 1000.0 - ).strftime("%M:%S") - if "ytmusic" in current_track_data["uri"]: - if "album" in current_track_data: - totalTime = current_track_data["length"] - track_total_length = datetime.fromtimestamp(totalTime / 1000.0).strftime( - "%M:%S" - ) - current_data = { - "Artist": current_track_data["artists"][0]["name"], - "Album": current_track_data["album"]["name"], - "Song": current_track_data["name"], - "TrackTime": time_position + "/" + track_total_length, - } - elif "ytmusic:track" in current_track_data["uri"]: - totalTime = current_track_data["length"] - track_total_length = datetime.fromtimestamp(totalTime / 1000.0).strftime( - "%M:%S" - ) - current_data = { - "Artist": "-", - "Album": current_track_data["artists"][0]["name"], - "Song": current_track_data["name"], - "TrackTime": time_position + "/" + track_total_length, - } - else: - try: - stream_title = mopidy.playback.get_stream_title(timeout=5) - artist_and_song = stream_title.split(" - ") - except: - stream_title = "None" - artist_and_song = ["None", "None"] - current_data = { - "Artist": current_track_data["album"]["name"], - "Album": artist_and_song[0], - "Song": artist_and_song[1], - "TrackTime": time_position, - } - mopidy.disconnect() - oled.text(current_data["Artist"], 0, 16, 1) - oled.text(current_data["Album"], 0, 26, 1) - oled.text(current_data["Song"], 0, 36, 1) - oled.text(current_data["TrackTime"], 0, 46, 1) - return - - -WIDTH = 128 -HEIGHT = 64 - -# Use for I2C. -i2c = board.I2C() -oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C) - - -while True: - oled.fill(0) - oled.text("Floppy Player", 26, 0, 1) - current_track() - oled.show() - time.sleep(3) - -