The Complete Computer

My "Now Playing" on Fediverse

LifeTechEmacsArcology

,#+CCEANSIBLE: npbot

When I am active on the Fediverse and I am Intentionally Listening to some Important Albums , it's nice to be able to share those tracks with others. I amalgamate all my listening stats ("scrobbles") on a roam:Last.FM Pro account, except for some years where I was only using gnu.fm instances which don't exist any more. Anyways, this bot includes a youtube link, or a link to my roam:MPD Server HTTP stream.

dot source: :file data/scrobble-dataflow.png :cmd fdp
digraph { subgraph cluster_0 { label="server" "server mpd" -> "server mpdscribble" "npbot" } "server mpdscribble" -> "LastFM" subgraph cluster_1 { label="laptop" "laptop mpd" -> "laptop mpdscribble" } "laptop mpdscribble" -> "LastFM" subgraph cluster_2 { label="phone" "notifications" -> "scrooble" } scrooble -> LastFM LastFM -> npbot -> "botsin.space" }

NEXT fix npbot...

Container build using Ansible Bender and Podman

This generates a dynamic playbook and then tells you how to run it:

shell source: :results drawer :exports code
cat <<EOF | python ~/org/cce/make-container-playbook.py template: ~/org/cce/containers/simple.yml friendly: Now Playing on Fediverse service_name: npbot build_roles: - nowplaying-bot-build build_reqs: - python-devel - python-pip - libffi-devel - python3-cffi cmd: ananas /config.cfg task_tags: - comms - media - npbot EOF
[[shell:ANSIBLE_ROLES_PATH=~/org/cce/roles ansible-bender build /home/rrix/org/cce/containers/npbot/build.yml &][Execute =ANSIBLE_ROLES_PATH=~/org/cce/roles ansible-bender build /home/rrix/org/cce/containers/npbot/build.yml &=]]
yaml source: :tangle roles/nowplaying-bot-build/tasks/main.yml :mkdirp yes
- name: requirements copied in copy: src: requirements.txt dest: "{{build_dir}}/requirements.txt" - name: python dependencies installed pip: state: present requirements: "{{build_dir}}/requirements.txt" - name: files installed copy: src: "{{item}}" dest: / with_items: - nowplaying.py - config.cfg

Nowplaying plugin source for roam:Ananas

txt source: :tangle containers/npbot/requirements.txt :mkdirp yes :comments none
pylast==2.1.0 ananas==1.0.0b17 requests==2.18.4
python source: :tangle containers/npbot/nowplaying.py :mkdirp yes
import requests from pylast import LastFMNetwork from ananas import PineappleBot, ConfigurationError, interval def search_youtube(q, max_results=1, key=None): if not key: raise ValueError('search_youtube() requires a key to authorize with the Youtube v3 API') r = requests.get('https://www.googleapis.com/youtube/v3/search', params={'q': q, 'type': 'video', 'maxResults': max_results, 'part': 'snippet', 'key': key}) items = [] for item in r.json().get('items', []): items.append({'id': item['id']['videoId'], 'title': item['snippet']['title']}) return items class NowplayingBot(PineappleBot): def init(self): self.last_posted_track = None def start(self): for k in ['lastfm_api_key', 'lastfm_api_secret', 'lastfm_username', 'lastfm_password_hash', 'youtube_key', 'use_last_played']: if k not in self.config: raise ConfigurationError(f"NowplayingBot requires a '{k}'") self.lastfm = LastFMNetwork(api_key=self.config.lastfm_api_key, api_secret=self.config.lastfm_api_secret, username=self.config.lastfm_username, password_hash=self.config.lastfm_password_hash) self.post_np() @interval(30) def post_np(self): # grab the track from the last.fm api if self.config.use_last_played == 'yes': currently_playing = self.lastfm.get_user(self.config.lastfm_username).get_recent_tracks(1)[0][0] else: currently_playing = self.lastfm.get_user(self.config.lastfm_username).get_now_playing() # don't try to post if nothing is being played if currently_playing is None: return # don't repost if we've already posted about this track if currently_playing.__hash__() == self.last_posted_track: return else: self.last_posted_track = currently_playing.__hash__() # make a best-effort guess at the youtube link for this track yt_search = search_youtube(str(currently_playing), key=self.config.youtube_key) if len(yt_search) > 0: yt_link = f"https://www.youtube.com/watch?v={yt_search[0]['id']}" else: yt_link = '🎇 no youtube link, sorry 🎇' # template the post post_template = '''\ #np #nowplaying {artist} - {track} {yt_link} - https://music.fontkeming.fail/mpd (live) ''' post = post_template.format(artist=currently_playing.get_artist().get_name(properly_capitalized=True), track=currently_playing.get_title(), yt_link=yt_link) # do the thing self.mastodon.status_post(post, visibility='unlisted')
ini source: :tangle containers/npbot/config.cfg :comments none
[np] class = nowplaying.NowplayingBot domain = botsin.space client_id = 5cd455c225935b1fa0585cc48e81a2985c41a0517330a3e39d30aa5a437e930e client_secret = 7c645a9444d55f11f1f6f42bbd2fa7e611207e0045b1cbc789a67280885037cb access_token = eaeaae60f1feebba5d7fc27c8b43ed0159ab5c06f20b52d4a27eabfa1e3b2bff lastfm_api_key = da6e1d6f81f6813500c5900de742e06c lastfm_api_secret = 915f9884d0868f19529ec25bf59d6718 lastfm_username = aes256thetic lastfm_password_hash = ce92be174edf74689ce89d48b1613267 youtube_key = AIzaSyCJhDRlK5qzisk_dvv-crGe54EOd2bjfoI use_last_played = no