Skip to content

Commit

Permalink
Merge pull request #32 from soup-bowl/edge
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
soup-bowl authored Jul 28, 2024
2 parents c081521 + 667cba7 commit 4aac8ff
Show file tree
Hide file tree
Showing 14 changed files with 595 additions and 720 deletions.
15 changes: 15 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "monthly"
groups:
dev-dependencies:
patterns:
- "*"
4 changes: 2 additions & 2 deletions .github/workflows/make-it-so.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Run Hot this Week (production)

on:
schedule:
- cron: 0 14 * * 5
- cron: 0 14 1 * *
workflow_dispatch:

jobs:
Expand All @@ -14,4 +14,4 @@ jobs:
run: echo ${{ secrets.HTK_CONFIG }} | base64 --decode > htw-config.json

- name: Run Hot-this-week!
run: docker run -v "$(realpath .)/htw-config.json:/opt/app/config.json" ghcr.io/soup-bowl/hot-this-week:latest
run: docker run -v "$(realpath .)/htw-config.json:/opt/app/config.json" ghcr.io/soup-bowl/hot-this-week:latest -p monthly
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"configurations": [
{
"name": "Python: Module",
"type": "python",
"type": "debugpy",
"request": "launch",
"module": "htw",
"args": ["-d", "-f", "config.json", "-p", "month"]
Expand Down
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
20 changes: 10 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
FROM python:3.8-slim

LABEL org.opencontainers.image.title="Soup-bowl's Hot this Week"
LABEL org.opencontainers.image.authors="code@soupbowl.io"
LABEL org.opencontainers.image.source="https://github.com/soup-bowl/hot-this-week"
LABEL org.opencontainers.image.licenses="MIT"
FROM python:3-slim

WORKDIR /opt/app

COPY htw htw
COPY assets assets
COPY pyproject.toml pyproject.toml
COPY poetry.lock poetry.lock
COPY pyproject.toml poetry.lock ./

RUN pip install --no-cache-dir poetry
RUN poetry install --no-dev --no-interaction --no-ansi

COPY htw htw
COPY assets assets

ENTRYPOINT [ "poetry", "run", "python", "-m", "htw" ]

LABEL org.opencontainers.image.title="Soup-bowl's Hot this Week"
LABEL org.opencontainers.image.authors="code@soupbowl.io"
LABEL org.opencontainers.image.source="https://github.com/soup-bowl/hot-this-week"
LABEL org.opencontainers.image.licenses="MIT"
20 changes: 8 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 🔥🎶🐦 soup-bowl's Hot This Week
# 🔥 soup-bowl's Hot This Week

<p align="center">
<a href="https://hub.docker.com/r/soupbowl/hot-this-week">
Expand All @@ -10,10 +10,10 @@
</p>

<p align="center">
<img src="https://user-images.githubusercontent.com/11209477/145074448-0894535e-5438-4fed-98d3-975584994590.png" alt="A view of a tweet showing a 5-picture collage, 1 larger image on the left and 4 small images in a grid orientation"/>
<img src="https://user-images.githubusercontent.com/11209477/214368280-532459b4-eb5d-46f7-82cd-2913d4da1633.png" alt="A view of a Mastodon post showing a 5-picture collage, 1 larger image on the left and 4 small images in a grid orientation"/>
</p>

An experimental bot that posts a rundown of your musical week on Twitter and/or Mastodon.
An experimental bot that posts a rundown of your musical week on Mastodon.

## 🤔 What does this do?

Expand All @@ -23,9 +23,9 @@ This clever bot does the following:
* API kindly hands over the info (or gives us a whack of the handbag if we have no API key).
* We sneakily scrape the last.fm website for the artist pictures 🤫 (better solutions welcome).
* We do some arts and crafts wizardary 🪄 to formulate a collage picture.
* Lastly, the app phones up Twitter/Mastodon 📞, asks how their turtle is hanging 🐢, and posts the info and picture.
* Lastly, the app phones up Mastodon 📞, asks how their turtle is hanging 🐢, and posts the info and picture.

⭐ Collage is made using the power of Python using [Pillow][p-pillow] for image manipulation, [Twython][p-twython]/[Mastodon][p-mstdn] and [urllib3][p-urllib3] for API communication, and [lxml][p-lxml] for scraping the internet.
⭐ Collage is made using the power of Python using [Pillow][p-pillow] for image manipulation, [Mastodon][p-mstdn] and [urllib3][p-urllib3] for API communication, and [lxml][p-lxml] for scraping the internet.

## 🚀 Set-up

Expand All @@ -49,19 +49,15 @@ See the [configuration example](/config.json.example) to see how to setup the to

* last.fm: global `LASTFM_KEY`, `LASTFM_SECRET`, and per-user `LASTFM_SCAN_USER_NAME`.
* You can [register an API key here](https://www.last.fm/api/account/create).
* Twitter: global `TWITTER_CONSUMER_KEY`, `TWITTER_CONSUMER_SECRET`, and per-user `TWITTER_ACCESS_TOKEN`, and `TWITTER_ACCESS_TOKEN`.
* You can [register for Twitter API keys here](https://developer.twitter.com/en/portal/dashboard).
* Ensure your access token has **read and write** capabilities (default is read only).
* Mastodon: global `MASTODON_URL`, `MASTODON_KEY` and `MASTODON_SECRET`.
* Easily register an application in **Preferences**, then **Development**.
* Permissions needed are **write:media** and **write:statuses**.
* Mastodon: global `MASTODON_URL`, `MASTODON_KEY` and `MASTODON_SECRET`.
* Easily register an application in **Preferences**, then **Development**.
* Permissions needed are **write:media** and **write:statuses**.

With everything set, you can just run `python3 -m htw` from CLI, and all the magic should happen. You can see the optional arguments by running `python3 -m htw --help`.

This uses **[pytest](https://docs.pytest.org/en/6.2.x/)** for Unit Testing, and **[pylint](https://pypi.org/project/pylint/)** for linting.

[p-pillow]: https://pypi.org/project/Pillow/
[p-twython]: https://pypi.org/project/twython/
[p-mstdn]: https://github.com/halcy/Mastodon.py
[p-urllib3]: https://pypi.org/project/urllib3/
[p-lxml]: https://pypi.org/project/lxml/
4 changes: 0 additions & 4 deletions config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@
"clients": [
{
"lastfmUsername": "example",
"twitterAccessToken": "key",
"twitterAccessSecret": "key",
"mastodonUsername": "example@mastodon.social",
"mastodonAccessToken": "key"
}
],
"config": {
"lastfmKey": "key",
"twitterConsumerKey": "key",
"twitterConsumerSecret": "key",
"mastodonURL": "https://mastodon.social",
"mastodonKey": "key",
"mastodonSecret": "key"
Expand Down
1 change: 0 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: '3.6'
services:
bot:
build:
Expand Down
34 changes: 5 additions & 29 deletions htw/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from htw.lfm import LFM, LFMPeriod
from htw.collage import Collage
from htw.twitter import Twitter
from htw.compose import Compose
from htw.mastodon import Mastodon

class CLI():
Expand All @@ -24,8 +24,6 @@ def __init__(self):
self.conf_path = "config.json"
self.lfm_period = LFMPeriod.WEEK
self.lastfm_key = getenv('LASTFM_KEY')
self.twitter_key = getenv('TWITTER_CONSUMER_KEY')
self.twitter_srt = getenv('TWITTER_CONSUMER_SECRET')
self.mastodon_key = getenv('MASTODON_KEY')
self.mastodon_srt = getenv('MASTODON_SECRET')
self.mastodon_url = getenv('MASTODON_URL')
Expand Down Expand Up @@ -138,32 +136,14 @@ def process_user(self, user_conf):

if not self.suppress:
print("- Composing tweet...")
tweet = Twitter().compose_tweet(artists, user_conf['lastfmUsername'])
tweet = Compose().compose_tweet(artists, user_conf['lastfmUsername'])

if self.display_only:
print(tweet)
print("---")
print(f"\033[92mCollage\033[00m: {pic}")
colgen.cleanup()
return True

if 'twitterAccessToken' in user_conf:
if not self.suppress:
print("- Posting to \033[96mTwitter\033[00m...")

try:
Twitter(
self.twitter_key,
self.twitter_srt,
user_conf['twitterAccessToken'],
user_conf['twitterAccessSecret']
).post_to_twitter(tweet, pic)
return True
except Exception as error:
print("\033[91mError\033[00m: " + str(error) + ".")
return False
finally:
colgen.cleanup()

if 'mastodonAccessToken' in user_conf:
if not self.suppress:
Expand Down Expand Up @@ -200,10 +180,6 @@ def read_config(self, location):

if 'lastfmKey' in conf['config']:
self.lastfm_key = conf['config']['lastfmKey'] if self.lastfm_key is None else self.lastfm_key
if 'twitterConsumerKey' in conf['config']:
self.twitter_key = conf['config']['twitterConsumerKey'] if self.twitter_key is None else self.twitter_key
if 'twitterConsumerSecret' in conf['config']:
self.twitter_srt = conf['config']['twitterConsumerSecret'] if self.twitter_srt is None else self.twitter_srt

if 'mastodonURL' in conf['config']:
self.mastodon_url = conf['config']['mastodonURL'] if self.mastodon_url is None else self.mastodon_url
Expand All @@ -219,7 +195,7 @@ def print_help(self):
if self.suppress:
return

print("Run without arguments to process last.fm & Twitter using environmental variables.")
print("Run without arguments to process last.fm & Mastodon using environmental variables.")
print("Script will also check and use environment variables stored in '.env'.")
print("")
print("\033[93mOptions:\033[00m")
Expand All @@ -231,7 +207,7 @@ def print_help(self):
print("\033[92m-k, --keep \033[00mThe collage is dumped into the working directory instead ", end='')
print("of a temporary disposable directory.")
print("\033[92m-s, --silent \033[00mScript does not output anything, just success/fail code.")
print("\033[92m-d, --display \033[00mDisplays tweet, but does not post to Twitter.")
print("\033[92m-d, --display \033[00mDisplays tweet, but does not post to Mastodon.")
print("")
print("\033[92m-v, --version \033[00mDisplay script version.")
print("\033[92m-h, --help \033[00mDisplay help information.")
Expand All @@ -244,4 +220,4 @@ def print_version(self):
return

print("Hot this Week by soup-bowl - \033[93mpre-alpha\033[00m.")
print("https://github.com/soup-bowl/lastfm-twitter/")
print("https://github.com/soup-bowl/hot-this-week")
23 changes: 23 additions & 0 deletions htw/compose.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
Contains the communication class for composing messages.
"""

class Compose():
"""Contains the communication class for composing messages.
"""

def compose_tweet(self, lfm_collection, name):
"""Compose tweet message contents.
Args:
lfm_collection ([type]): Last.fm user data collection.
name (str): Last.fm username.
Returns:
[str]: Message contents.
"""
message = "\U0001F4BF my week with #lastfm:\n"
for artist in lfm_collection:
message = message + f"{artist['name']} ({artist['plays']})\n"
message = message + f"https://www.last.fm/user/{name}"
return message
58 changes: 0 additions & 58 deletions htw/twitter.py

This file was deleted.

Loading

0 comments on commit 4aac8ff

Please sign in to comment.