From 225af43fd23c9b85cbbc8c83fce2e248ea13a7c2 Mon Sep 17 00:00:00 2001 From: Matthew Fennell Date: Mon, 22 Dec 2025 00:13:29 +0000 Subject: Initial commit Add LordGnome, a bot which syndicates new issues of Private Eye as well as new releases of Page 94 to a specified Lemmy community. The bot is designed to be run in a cronjob. It takes a config file, in which you can provide login/community/instance details. It then checks the Private Eye website, as well as the Page 94 RSS feed, for the latest releases. It compares these to whatever was last posted. If the latest release is newer than the latest post, it will create a new post linking to that release. In order to prevent the bot from posting the latest (and potentially outdated) magazine issue and podcast straight away on the first run, you can also provide a last posted issue. This gets used as a fallback if the bot cannot find any previous posts. --- syndicate.sh | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100755 syndicate.sh (limited to 'syndicate.sh') diff --git a/syndicate.sh b/syndicate.sh new file mode 100755 index 0000000..8ecc68b --- /dev/null +++ b/syndicate.sh @@ -0,0 +1,108 @@ +#!/bin/bash + +set -u +set -o pipefail + +config_file=$1 + +community=$(grep "^community=" "${config_file}" | cut --delimiter = --fields 2) +instance=$(grep "^instance=" "${config_file}" | cut --delimiter = --fields 2) +token=$(grep "^token=" "${config_file}" | cut --delimiter = --fields 2) +username=$(grep "^username=" "${config_file}" | cut --delimiter = --fields 2) +first_posted_magazine=$(grep "^first_posted_magazine=" "${config_file}" | cut --delimiter = --fields 2) +first_posted_podcast=$(grep "^first_posted_podcast=" "${config_file}" | cut --delimiter = --fields 2) + +remote_post_history="${instance}/feeds/u/${username}.xml?sort=New" +local_post_history="/tmp/${username}.rss" + +function post { + local name="$1" + local url="$2" + local image="$3" + local body="$4" + + echo "Creating post \"${name}\" with url \"${url}\", thumbnail \"${image}\" and body \"${body}\" on instance ${instance}, community ${community}" + + community_id=$(curl --silent --fail "${instance}/api/v3/community?name=${community}" | jq --raw-output .community_view.community.id | grep --only-match "[[:digit:]]*") + curl --silent --fail-with-body --oauth2-bearer "${token}" --json "{\"name\":\"${name}\",\"community_id\":${community_id},\"url\":\"${url}\",\"body\":\"${body}\",\"language_id\":37,\"custom_thumbnail\":\"${image}\"}" "${instance}/api/v3/post" +} + +function syndicate_magazine { + echo "Syndicating magazine" + + template="Private Eye Issue" + last_posted_issue=$(xq --extract "/rss/channel/item/title[starts-with(., '${template} ')]" "${local_post_history}" | grep --only-match "[[:digit:]]*") + + if [ -z "${last_posted_issue}" ]; + then + echo "No previous post found: defaulting to issue ${first_posted_magazine}" + last_posted_issue="${first_posted_magazine}" + fi + + issue_to_try_posting=$((last_posted_issue + 1)) + + echo "Last posted issue was ${last_posted_issue}. Checking issue ${issue_to_try_posting}" + + url="https://www.private-eye.co.uk/covers/cover-${issue_to_try_posting}" + image="https://www.private-eye.co.uk/pictures/covers/full/${issue_to_try_posting}_big.jpg" + name="${template} ${issue_to_try_posting}" + + private_eye_response=$(curl --silent --output /dev/null --write-out "%{http_code}" "${image}") + + if [ "${private_eye_response}" != "200" ]; + then + echo "Received ${private_eye_response} for ${image}. Stop" + return + fi + + echo "Received ${private_eye_response} for ${image}. Intend to post it" + post "${name}" "${url}" "${image}" "![](${image})" +} + +function syndicate_podcast { + echo "Syndicating podcast" + + remote_rss="https://audioboom.com/channels/5112392.rss" + local_rss="/tmp/page94.rss" + template="https://www.private-eye.co.uk/podcast/" + + last_posted_issue=$(xq --extract "/rss/channel/item/enclosure/@url[starts-with(., '${template}')]" "${local_post_history}" | cut -d / -f 5 | grep --only-match "[[:digit:]]*") + + if [ -z "${last_posted_issue}" ]; + then + echo "No previous post found: defaulting to issue ${first_posted_podcast}" + last_posted_issue="${first_posted_podcast}" + fi + + curl --silent "${remote_rss}" --output "${local_rss}" + + most_recently_published_issue=$(xq --extract "/rss/channel/item/itunes:episode" "${local_rss}" | grep --only-match "[[:digit:]]*") + + name=$(xq --extract "/rss/channel/item/itunes:title" "${local_rss}") + url="https://www.private-eye.co.uk/podcast/${most_recently_published_issue}" + image=$(xq --extract "/rss/channel/item/itunes:image/@href" "${local_rss}") + audio=$(xq --extract "/rss/channel/item/enclosure/@url" "${local_rss}" | cut -d '?' -f 1) + + rm -f "${local_rss}" + + echo "Last posted issue was ${last_posted_issue}. Last released issue was ${most_recently_published_issue}" + + if [ "${most_recently_published_issue}" -le "${last_posted_issue}" ]; + then + echo "No issue more recently published than ${most_recently_published_issue}. Stop" + return + fi + + echo "${most_recently_published_issue} is newer than ${last_posted_issue}. Intend to post it" + + post "${name}" "${url}" "${image}" "[Direct link to audio](${audio})" +} + +echo "Acting as ${username} on ${instance}" + +curl --silent "${remote_post_history}" --output "${local_post_history}" + +syndicate_magazine +syndicate_podcast + +rm -f "${local_post_history}" -- cgit v1.2.3