commit c0ab490a3490cd2668ab57593b91b8f402e0f02f Author: Bertrand Benjamin Date: Sun Sep 20 20:32:58 2020 +0200 Feat: import from https://github.com/rusconi/TFT-MoodeCoverArt/ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dae418b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +backlight.py +backlight.sh + +stst.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..73d2fe8 --- /dev/null +++ b/README.md @@ -0,0 +1,146 @@ +# TFT-MoodeCoverArt +*version = "0.0.5" : changes* + +* radio icons location changed + +*version = "0.0.4" : changes* + +* added option to display cover art only without overlays (see config file for instructions) + +*version = "0.0.3" : changes* + +* added option to turn off backlight when mpd state = stop (see config file for instructions) + +------------------------------------------------------- + + +Based on the look of the pirate audio plugin for mopidy. + +Works with Pimoroni pirate audio boards with 240*240 TFT (ST7789), as well as standalone ST7789 boards. + +![Sample Image](/pics/display.jpg) + +### Features. + +The script will display cover art (where available) for the moode library or radio stations. + +* For the moode library, embedded art will be displayed first, then folder or cover images if there is no embedded art. +* For radio stations, the moode images are used. +* If no artwork is found a default image is displayed. + +Metadata displayed: +* Artist +* Album/Radio Station +* Title + +Overlays with a Time bar, Volume bar and Play/Pause, Next and Volume icons to match the Pirate Audio buttons are optional. + +There is also an option in config.yml to not display metadata + +The script has a built in test to see if the mpd service is running. This should allow enough delay when +used as a service. If a running mpd service is not found after around 30 seconds the script displays the following and stops. + +``` + MPD not Active! +Ensure MPD is running + Then restart script +``` + +**Limitations** + +Metadata will only be displayed for Radio Stations and the Library. + +For the `Airplay`, `Spotify`, `Bluetooth`, `Squeezelite` and `Dac Input` renderers, different backgrounds will display. + +The overlay colours adjust for light and dark artwork, but can be hard to read with some artwork. + +The script does not search online for artwork + +### Assumptions. + +**You can SSH into your RPI, enter commands at the shell prompt, and use the nano editor.** + +**Your moode installation works and produces audio** + +If your pirate audio board doesn't output anything + +Choose "Pimoroni pHAT DAC" or "HiFiBerry DAC" in moode audio config + +See the Installation section [**here**](https://github.com/pimoroni/pirate-audio) about gpio pin 25. + + +### Preparation. + +**Enable SPI pn your RPI** + +see [**Configuring SPI**](https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-spi) + +Install these pre-requisites: +``` +sudo apt-get update +sudo apt-get install python3-rpi.gpio python3-spidev python3-pip python3-pil python3-numpy +sudo pip3 install mediafile +sudo pip3 install pyyaml +``` +Install the TFT driver. + +I have forked the Pimoroni driver and modified it to work with other ST7789 boards. Install it with the following command: + +``` +sudo pip3 install RPI-ST7789 +``` + +***Ensure 'Metadata file' is turned on in Moode System Configuration*** + +### Install the TFT-MoodeCoverArt script + +``` +cd /home/pi +git clone https://github.com/rusconi/TFT-MoodeCoverArt.git +``` + +### Config File + +The default config should work with Pirate Audio boards + +The config.yml file can be edited to: + +* suit different ST7789 boards +* set overlay display options + +The comments in 'config.yml' should be self explanatory + + +**Make the shell scripts executable:** + +``` +chmod 777 *.sh +``` + +Test the script: + +``` +python3 /home/pi/TFT-MoodeCoverArt/tft_moode_coverart.py + + +Ctrl-c to quit +``` + +**If the script works, you may want to start the display at boot:** + +### Install as a service. + +``` +cd /home/pi/TFT-MoodeCoverArt +./install_service.sh +``` + +Follow the prompts. + +If you wish to remove the script as a service: + +``` +cd /home/pi/TFT-MoodeCoverArt +./remove_service.sh +``` + diff --git a/clear_display.py b/clear_display.py new file mode 100644 index 0000000..0f9df9b --- /dev/null +++ b/clear_display.py @@ -0,0 +1,55 @@ + + +import ST7789 +from PIL import Image, ImageDraw +from os import path +import yaml + +# set default config for pirate audio + +MODE=0 + +OVERLAY=2 + +confile = 'config.yml' + +# Read conf.json for user config +if path.exists(confile): + + with open(confile) as config_file: + data = yaml.load(config_file, Loader=yaml.FullLoader) + displayConf = data['display'] + OVERLAY = displayConf['overlay'] + MODE = displayConf['mode'] + + +# Standard SPI connections for ST7789 +# Create ST7789 LCD display class. +if MODE == 3: + disp = ST7789.ST7789( + port=0, + cs=ST7789.BG_SPI_CS_FRONT, # GPIO 8, Physical pin 24 + dc=9, + rst=22, + backlight=13, + mode=3, + rotation=0, + spi_speed_hz=80 * 1000 * 1000 + ) +else: + disp = ST7789.ST7789( + port=0, + cs=ST7789.BG_SPI_CS_FRONT, # GPIO 8, Physical pin 24 + dc=9, + backlight=13, + spi_speed_hz=80 * 1000 * 1000 + ) + + +disp.begin() +img = Image.new('RGB', (240, 240), color=(0, 0, 0)) +draw = ImageDraw.Draw(img) +draw.rectangle((0, 0, 240, 240), (0, 0, 0)) +disp.display(img) + +disp.set_backlight(False) diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..56533ca --- /dev/null +++ b/config.yml @@ -0,0 +1,23 @@ +# version = "0.0.4" +display: + # Display control overlays: + # 3=Artwork only + # 2=Full overlay displayed + # 1=Volume icon only. + # 0=no overlay displayed + overlay: 2 + + # Display Time Bar: + # 1=time bar displayed + # 0=no time bar displayed + timebar: 1 + + # mode=0 for pirate audio and display boards with cs pin + # mode=3 for display boards without cs pin + mode: 0 + + # Turn backlight off when mpd state=stop + # back on when play restarted + # blank=0 screen will not blank when mpd state=stop + # blank=n screen will blank after roughly n seconds when mpd state=stop + blank: 0 diff --git a/fonts/Roboto-Medium.ttf b/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000..1a7f3b0 Binary files /dev/null and b/fonts/Roboto-Medium.ttf differ diff --git a/images/airplay.png b/images/airplay.png new file mode 100644 index 0000000..fe9b2a0 Binary files /dev/null and b/images/airplay.png differ diff --git a/images/bta.png b/images/bta.png new file mode 100644 index 0000000..be348c1 Binary files /dev/null and b/images/bta.png differ diff --git a/images/controls-pause-dark.png b/images/controls-pause-dark.png new file mode 100644 index 0000000..edf0068 Binary files /dev/null and b/images/controls-pause-dark.png differ diff --git a/images/controls-pause.png b/images/controls-pause.png new file mode 100644 index 0000000..d514a59 Binary files /dev/null and b/images/controls-pause.png differ diff --git a/images/controls-play-dark.png b/images/controls-play-dark.png new file mode 100644 index 0000000..874471d Binary files /dev/null and b/images/controls-play-dark.png differ diff --git a/images/controls-play.png b/images/controls-play.png new file mode 100644 index 0000000..b9a5ed3 Binary files /dev/null and b/images/controls-play.png differ diff --git a/images/controls-vol-dark.png b/images/controls-vol-dark.png new file mode 100644 index 0000000..786739a Binary files /dev/null and b/images/controls-vol-dark.png differ diff --git a/images/controls-vol.png b/images/controls-vol.png new file mode 100644 index 0000000..61eb2fe Binary files /dev/null and b/images/controls-vol.png differ diff --git a/images/default-cover-v6.jpg b/images/default-cover-v6.jpg new file mode 100644 index 0000000..2dfbbc2 Binary files /dev/null and b/images/default-cover-v6.jpg differ diff --git a/images/jack.png b/images/jack.png new file mode 100644 index 0000000..93f1fe6 Binary files /dev/null and b/images/jack.png differ diff --git a/images/spotify.png b/images/spotify.png new file mode 100644 index 0000000..c6f66c8 Binary files /dev/null and b/images/spotify.png differ diff --git a/images/squeeze.png b/images/squeeze.png new file mode 100644 index 0000000..548e0a9 Binary files /dev/null and b/images/squeeze.png differ diff --git a/install_service.sh b/install_service.sh new file mode 100644 index 0000000..2ff1004 --- /dev/null +++ b/install_service.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +echo -e "Install TFT-MoodeCoverArt Service. \n" +cd /home/pi/TFT-MoodeCoverArt + +while true +do + read -p "Do you wish to install TFT-MoodeCoverArt as a service?" yn + case $yn in + [Yy]* ) echo -e "Installing Service \n" + sudo cp tft-moodecoverart.service /lib/systemd/system + sudo chmod 644 /lib/systemd/system/tft-moodecoverart.service + sudo systemctl daemon-reload + sudo systemctl enable tft-moodecoverart.service + echo -e "\nTFT-MoodeCoverArt installed as a service.\n" + echo -e "Please reboot the Raspberry Pi.\n" + break;; + [Nn]* ) echo -e "Service not installed \n"; break;; + * ) echo "Please answer yes or no.";; + esac +done + +while true +do + read -p "Do you wish to reboot now?" yn + case $yn in + [Yy]* ) echo -e "Rebooting \n" + sudo reboot + break;; + [Nn]* ) echo -e "Not rebooting \n" + break;; + * ) echo "Please answer yes or no.";; + esac +done + +echo "TFT-MoodeCoverArt install complete" \ No newline at end of file diff --git a/pics/display.jpg b/pics/display.jpg new file mode 100644 index 0000000..ca74a65 Binary files /dev/null and b/pics/display.jpg differ diff --git a/remove_service.sh b/remove_service.sh new file mode 100644 index 0000000..b8f889f --- /dev/null +++ b/remove_service.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo -e "Remove TFT-MoodeCoverArt Service\n" + + +while true +do + read -p "Do you wish to Remove TFT-MoodeCoverArt as a service?" yn + case $yn in + [Yy]* ) echo -e "Removing Service \n" + sudo systemctl stop tft-moodecoverart.service + sudo systemctl disable tft-moodecoverart.service + sudo rm /etc/systemd/system/tft-moodecoverart.service + sudo systemctl daemon-reload + sudo systemctl reset-failed + echo -e "\nTFT-MoodeCoverArt removed as a service.\n" + echo -e "Please reboot the Raspberry Pi.\n" + break;; + [Nn]* ) echo -e "Service not removed \n"; break;; + * ) echo "Please answer yes or no.";; + esac +done + +while true +do + read -p "Do you wish to reboot now?" yn + case $yn in + [Yy]* ) echo -e "Rebooting \n" + sudo reboot + break;; + [Nn]* ) echo -e "Not rebooting \n" + break;; + * ) echo "Please answer yes or no.";; + esac +done + +echo "TFT-MoodeCoverArt service removal complete" \ No newline at end of file diff --git a/tft-moodecoverart.service b/tft-moodecoverart.service new file mode 100644 index 0000000..8b96a8f --- /dev/null +++ b/tft-moodecoverart.service @@ -0,0 +1,14 @@ +[Unit] +Description=TFT-MoodeCoverArt Display +Requires=mpd.socket mpd.service +After=mpd.socket mpd.service + +[Service] +Type=simple +ExecStart=/usr/bin/python3 /home/pi/TFT-MoodeCoverArt/tft_moode_coverart.py & +#ExecStartPre=/bin/sleep 15 +ExecStop=/home/pi/TFT-MoodeCoverArt/tft_moode_coverart.sh -q +Restart=on-abort + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/tft_moode_coverart.py b/tft_moode_coverart.py new file mode 100644 index 0000000..dddcc02 --- /dev/null +++ b/tft_moode_coverart.py @@ -0,0 +1,383 @@ +from PIL import Image, ImageDraw, ImageColor, ImageFont, ImageStat +import subprocess +import time +import musicpd +import os +import os.path +from os import path +import RPi.GPIO as GPIO +from mediafile import MediaFile +from io import BytesIO +from numpy import mean +import ST7789 +from PIL import ImageFilter +import yaml + +# set default config for pirate audio + +__version__ = "0.0.5" + +# get the path of the script +script_path = os.path.dirname(os.path.abspath( __file__ )) +# set script path as current directory - +os.chdir(script_path) + +MODE=0 +OVERLAY=2 +TIMEBAR=1 +BLANK=0 + +confile = 'config.yml' + +# Read config.yml for user config +if path.exists(confile): + + with open(confile) as config_file: + data = yaml.load(config_file, Loader=yaml.FullLoader) + displayConf = data['display'] + OVERLAY = displayConf['overlay'] + MODE = displayConf['mode'] + TIMEBAR = displayConf['timebar'] + BLANK = displayConf['blank'] + + + + +# Standard SPI connections for ST7789 +# Create ST7789 LCD display class. +if MODE == 3: + disp = ST7789.ST7789( + port=0, + cs=ST7789.BG_SPI_CS_FRONT, # GPIO 8, Physical pin 24 + dc=9, + rst=22, + backlight=13, + mode=3, + rotation=0, + spi_speed_hz=80 * 1000 * 1000 + ) +else: + disp = ST7789.ST7789( + port=0, + cs=ST7789.BG_SPI_CS_FRONT, # GPIO 8, Physical pin 24 + dc=9, + backlight=13, + spi_speed_hz=80 * 1000 * 1000 + ) + + + +# Initialize display. +disp.begin() + + +WIDTH = 240 +HEIGHT = 240 +font_s = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf',20) +font_m = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf',24) +font_l = ImageFont.truetype(script_path + '/fonts/Roboto-Medium.ttf',30) + + +img = Image.new('RGB', (240, 240), color=(0, 0, 0, 25)) + +play_icons = Image.open(script_path + '/images/controls-play.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") +play_icons_dark = Image.open(script_path + '/images/controls-play-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") + +pause_icons = Image.open(script_path + '/images/controls-pause.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") +pause_icons_dark = Image.open(script_path + '/images/controls-pause-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") + +vol_icons = Image.open(script_path + '/images/controls-vol.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") +vol_icons_dark = Image.open(script_path + '/images/controls-vol-dark.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") + +bt_back = Image.open(script_path + '/images/bta.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") +ap_back = Image.open(script_path + '/images/airplay.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") +jp_back = Image.open(script_path + '/images/jack.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") +sp_back = Image.open(script_path + '/images/spotify.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") +sq_back = Image.open(script_path + '/images/squeeze.png').resize((240,240), resample=Image.LANCZOS).convert("RGBA") + +draw = ImageDraw.Draw(img, 'RGBA') + + +def isServiceActive(service): + + waiting = True + count = 0 + active = False + + while (waiting == True): + + process = subprocess.run(['systemctl','is-active',service], check=False, stdout=subprocess.PIPE, universal_newlines=True) + output = process.stdout + stat = output[:6] + + if stat == 'active': + waiting = False + active = True + + if count > 29: + waiting = False + + count += 1 + time.sleep(1) + + return active + + +def getMoodeMetadata(filename): + # Initalise dictionary + metaDict = {} + + if path.exists(filename): + # add each line fo a list removing newline + nowplayingmeta = [line.rstrip('\n') for line in open(filename)] + i = 0 + while i < len(nowplayingmeta): + # traverse list converting to a dictionary + (key, value) = nowplayingmeta[i].split('=') + metaDict[key] = value + i += 1 + + metaDict['source'] = 'library' + if 'file' in metaDict: + if (metaDict['file'].find('http://', 0) > -1) or (metaDict['file'].find('https://', 0) > -1): + # set radio stream to true + metaDict['source'] = 'radio' + # if radio station has arist and title in one line separated by a hyphen, split into correct keys + if metaDict['title'].find(' - ', 0) > -1: + (art,tit) = metaDict['title'].split(' - ', 1) + metaDict['artist'] = art + metaDict['title'] = tit + elif metaDict['file'].find('Bluetooth Active', 0) > -1: + metaDict['source'] = 'bluetooth' + elif metaDict['file'].find('Airplay Active', 0) > -1: + metaDict['source'] = 'airplay' + elif metaDict['file'].find('Spotify Active', 0) > -1: + metaDict['source'] = 'spotify' + elif metaDict['file'].find('Squeezelite Active', 0) > -1: + metaDict['source'] = 'squeeze' + elif metaDict['file'].find('Input Active', 0) > -1: + metaDict['source'] = 'input' + + + # return metadata + return metaDict + +def get_cover(metaDict): + + cover = None + cover = Image.open(script_path + '/images/default-cover-v6.jpg') + covers = ['Cover.jpg', 'cover.jpg', 'Cover.jpeg', 'cover.jpeg', 'Cover.png', 'cover.png', 'Cover.tif', 'cover.tif', 'Cover.tiff', 'cover.tiff', + 'Folder.jpg', 'folder.jpg', 'Folder.jpeg', 'folder.jpeg', 'Folder.png', 'folder.png', 'Folder.tif', 'folder.tif', 'Folder.tiff', 'folder.tiff'] + if metaDict['source'] == 'radio': + if 'coverurl' in metaDict: + rc = '/var/local/www/' + metaDict['coverurl'] + if path.exists(rc): + if rc != '/var/local/www/images/default-cover-v6.svg': + cover = Image.open(rc) + + elif metaDict['source'] == 'airplay': + cover = ap_back + elif metaDict['source'] == 'bluetooth': + cover = bt_back + elif metaDict['source'] == 'input': + cover = jp_back + elif metaDict['source'] == 'spotify': + cover = sp_back + elif metaDict['source'] == 'squeeze': + cover = sq_back + else: + if 'file' in metaDict: + if len(metaDict['file']) > 0: + + fp = '/var/lib/mpd/music/' + metaDict['file'] + mf = MediaFile(fp) + if mf.art: + cover = Image.open(BytesIO(mf.art)) + return cover + else: + for it in covers: + cp = os.path.dirname(fp) + '/' + it + + if path.exists(cp): + cover = Image.open(cp) + return cover + return cover + + +def main(): + + disp.set_backlight(True) + + filename = '/var/local/www/currentsong.txt' + + c = 0 + p = 0 + k=0 + ol=0 + ss = 0 + x1 = 20 + x2 = 20 + x3 = 20 + title_top = 105 + volume_top = 184 + time_top = 222 + act_mpd = isServiceActive('mpd') + + if act_mpd == True: + while True: + client = musicpd.MPDClient() # create client object + try: + client.connect() # use MPD_HOST/MPD_PORT + except: + pass + else: + moode_meta = getMoodeMetadata(filename) + + mpd_current = client.currentsong() + mpd_status = client.status() + cover = get_cover(moode_meta) + + + + mn = 50 + if OVERLAY == 3: + img.paste(cover.resize((WIDTH,HEIGHT), Image.LANCZOS).convert('RGB')) + else: + img.paste(cover.resize((WIDTH,HEIGHT), Image.LANCZOS).filter(ImageFilter.GaussianBlur).convert('RGB')) + + if 'state' in mpd_status: + if (mpd_status['state'] == 'stop') and (BLANK != 0): + if ss < BLANK: + ss = ss + 1 + else: + disp.set_backlight(False) + else: + ss = 0 + disp.set_backlight(True) + + + im_stat = ImageStat.Stat(cover) + im_mean = im_stat.mean + mn = mean(im_mean) + + #txt_col = (255-int(im_mean[0]), 255-int(im_mean[1]), 255-int(im_mean[2])) + txt_col = (255,255,255) + bar_col = (255, 255, 255, 255) + dark = False + if mn > 175: + txt_col = (55,55,55) + dark=True + bar_col = (100,100,100,225) + if mn < 80: + txt_col = (200,200,200) + + if (moode_meta['source'] == 'library') or (moode_meta['source'] == 'radio'): + + if (OVERLAY > 0) and (OVERLAY < 3): + if 'state' in mpd_status: + if OVERLAY == 2: + if mpd_status['state'] != 'play': + if dark is False: + img.paste(pause_icons, (0,0), pause_icons) + else: + img.paste(pause_icons_dark, (0,0), pause_icons_dark) + else: + if dark is False: + img.paste(play_icons, (0,0), play_icons) + else: + img.paste(play_icons_dark, (0,0), play_icons_dark) + elif OVERLAY == 1: + if dark is False: + img.paste(vol_icons, (0,0), vol_icons) + else: + img.paste(vol_icons_dark, (0,0), vol_icons_dark) + + else: + img.paste(play_icons, (0,0), play_icons) + + if 'volume' in mpd_status: + vol = int(mpd_status['volume']) + vol_x = int((vol/100)*(WIDTH - 33)) + draw.rectangle((5, volume_top, WIDTH-34, volume_top+8), (255,255,255,145)) + draw.rectangle((5, volume_top, vol_x, volume_top+8), bar_col) + + if OVERLAY < 3: + if TIMEBAR == 1: + if 'elapsed' in mpd_status: + el_time = int(float(mpd_status['elapsed'])) + if 'duration' in mpd_status: + du_time = int(float(mpd_status['duration'])) + dur_x = int((el_time/du_time)*(WIDTH-10)) + draw.rectangle((5, time_top, WIDTH-5, time_top + 12), (255,255,255,145)) + draw.rectangle((5, time_top, dur_x, time_top + 12), bar_col) + + + top = 7 + if 'artist' in moode_meta: + w1, y1 = draw.textsize(moode_meta['artist'], font_m) + x1 = x1-20 + if x1 < (WIDTH - w1 - 20): + x1 = 0 + if w1 <= WIDTH: + x1 = (WIDTH - w1)//2 + draw.text((x1, top), moode_meta['artist'], font=font_m, fill=txt_col) + + top = 35 + + if 'album' in moode_meta: + w2, y2 = draw.textsize(moode_meta['album'], font_s) + x2 = x2-20 + if x2 < (WIDTH - w2 - 20): + x2 = 0 + if w2 <= WIDTH: + x2 = (WIDTH - w2)//2 + draw.text((x2, top), moode_meta['album'], font=font_s, fill=txt_col) + + + if 'title' in moode_meta: + w3, y3 = draw.textsize(moode_meta['title'], font_l) + x3 = x3-20 + if x3 < (WIDTH - w3 - 20): + x3 = 0 + if w3 <= WIDTH: + x3 = (WIDTH - w3)//2 + draw.text((x3, title_top), moode_meta['title'], font=font_l, fill=txt_col) + + + else: + if 'file' in moode_meta: + txt = moode_meta['file'].replace(' ', '\n') + w3, h3 = draw.multiline_textsize(txt, font_l, spacing=6) + x3 = (WIDTH - w3)//2 + y3 = (HEIGHT - h3)//2 + draw.text((x3, y3), txt, font=font_l, fill=txt_col, spacing=6, align="center") + + + disp.display(img) + + if c == 0: + im7 = img.save(script_path+'/dump.jpg') + c += 1 + + + time.sleep(1) + ol += 1 + + client.disconnect() + else: + draw.rectangle((0,0,240,240), fill=(0,0,0)) + txt = 'MPD not Active!\nEnsure MPD is running\nThen restart script' + mlw, mlh = draw.multiline_textsize(txt, font=font_m, spacing=4) + draw.multiline_text(((WIDTH-mlw)//2, 20), txt, fill=(255,255,255), font=font_m, spacing=4, align="center") + disp.display(img) + + + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + disp.reset() + disp.set_backlight(False) + pass diff --git a/tft_moode_coverart.sh b/tft_moode_coverart.sh new file mode 100644 index 0000000..f55015d --- /dev/null +++ b/tft_moode_coverart.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +while getopts ":sq" opt; do + case ${opt} in + s ) sudo pkill -f tft_moode_coverart.py; sudo /usr/bin/python3 /home/pi/TFT-MoodeCoverArt/clear_display.py; sudo /usr/bin/python3 /home/pi/TFT-MoodeCoverArt/tft_moode_coverart.py & + ;; + q ) sudo pkill -f tft_moode_coverart.py; sudo python3 /home/pi/TFT-MoodeCoverArt/clear_display.py + ;; + \? ) echo "Usage: cmd [-s] [-q]" + ;; + esac +done \ No newline at end of file