wmt.py (4320B)
1 #!/usr/bin/env python 2 """ 3 ██ 4 ░██ 5 ███ ██ ██████████ ██████ 6 ░░██ █ ░██░░██░░██░░██░░░██░ 7 ░██ ███░██ ░██ ░██ ░██ ░██ 8 ░████░████ ░██ ░██ ░██ ░██ 9 ███░ ░░░██ ███ ░██ ░██ ░░██ 10 ░░░ ░░░ ░░░ ░░ ░░ ░░ 11 w e e k l y m u s i c t o o t 12 13 author ▓▒ pyratebeard <root@pyratebeard.net> 14 code ▓▒ https://git.pyratebeard.net/wmt 15 16 `wmt` is used for sending an automated toot 17 to my mastodon profile listing the music that 18 has been listened to on my navidrome server 19 since the previous monday. 20 21 it is an advancement of my wmt script used 22 with cmus. since i am on the move a bit more 23 i don't use cmus all the time. i also wanted 24 to include music that i listen to outside of 25 work. 26 27 the main difference is the cmus script put 28 the list into most to least played. this one 29 does not, yet. i would like to combine the 30 two lists if possible but for now this will 31 be the list posted to mastodon. 32 """ 33 34 import requests 35 import os 36 import datetime 37 from dotenv import load_dotenv, dotenv_values 38 from subprocess import check_output 39 from mastodon import Mastodon 40 41 # pull vars and secrets from .env file 42 # if the file does not exist write the 43 # required vars to a new file and exit 44 var_file = '.env' 45 local_vars = ['NAVIDROME_URL', # instance url 46 'USERNAME', # navidrome username 47 'PASSWORD', # navidrome password 48 'ALBUM_LIMIT', # request result album limit, default 20 49 'NTFY_URL', # instance and tag url 50 'MASTODON_URL', # instance url 51 'ACCESS_TOKEN'] # app access token 52 53 if not os.path.exists(var_file): 54 # add `=""` to each var to make it as 55 # easy as possible to populate 56 content = '=""\n'.join(local_vars) + '=""\n' 57 with open(var_file, "x", encoding="utf-8") as f: 58 f.writelines(content) 59 print(f"local var file {var_file} created\npopulate and run again") 60 exit() 61 else: 62 load_dotenv() 63 64 # log in to navidrome instance 65 NAVIDROME_URL = os.getenv('NAVIDROME_URL') 66 login_url = f'{NAVIDROME_URL}/auth/login' 67 login_data = { 68 'username': os.getenv("USERNAME"), 69 'password': os.getenv("PASSWORD") 70 } 71 72 try: 73 login_res = requests.post(login_url, json=login_data) 74 login_res.raise_for_status() 75 token = login_res.json().get('token') 76 if not token: 77 print("login succeeded but no token received.") 78 exit() 79 except Exception as e: 80 print(f"login failed: {e}") 81 exit() 82 83 headers = { 84 'X-ND-Authorization': f'Bearer {token}' 85 } 86 87 # set data and pull album list 88 params = { 89 '_start': 0, 90 '_end': os.getenv("ALBUM_LIMIT", 20), 91 '_sort': 'play_date', 92 '_order': 'DESC', 93 'recently_played': 'true' 94 } 95 96 try: 97 res = requests.get(f'{NAVIDROME_URL}/api/album', headers=headers, params=params) 98 res.raise_for_status() 99 albums = res.json() 100 except Exception as e: 101 print(f"failed to fetch albums: {e}") 102 exit() 103 104 # get last monday date to start new week 105 today = datetime.date.today() 106 monday = today - datetime.timedelta(days=today.weekday()) 107 108 # find all albums played since monday 109 week_music = [] 110 for a in albums: 111 play_date = datetime.datetime.fromisoformat(a.get('playDate')) 112 if play_date.date() >= monday: 113 week_music.append(f"{a['name']} by {a['artist']}") 114 115 # compose toot 116 toot = (f"""(automated) #weeklymusictoot 117 118 this week i listened to: 119 120 """) 121 122 # 500 char max 123 # toot is 54 chars inc newlines 124 # albums no more than 446 so slice 125 # last album until list fits 126 while True: 127 char_count = sum(len(s) for s in week_music) 128 if char_count > 446: 129 week_music = week_music[:-1] 130 else: 131 break 132 133 # add albums to toot 134 for album in week_music: 135 toot += f"* {album}\n" 136 137 # post toot 138 try: 139 MASTODON_URL = os.getenv("MASTODON_URL") 140 mastodon = Mastodon(api_base_url = MASTODON_URL, access_token = ACCESS_TOKEN) 141 mastodon.toot(toot) 142 except Exception as e: 143 NTFY_URL = os.getenv("NTFY_URL") 144 requests.post(NTFY_URL, 145 data="wmt toot failed".encode(encoding='utf-8')) 146 exit()