Compare commits
12 Commits
67e74ecde2
...
0.2.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 178496582c | |||
| b4c4cec883 | |||
| 0cac2e0a47 | |||
| 2edf49e78e | |||
| ff5f9e0c3e | |||
| 3e33f6b464 | |||
| 2db63ad49c | |||
| a140140322 | |||
| 34a03bed6a | |||
| 53b0abe03a | |||
| 47317081f9 | |||
| b988e4bf0a |
70
.gitea/workflows/release.yml
Normal file
70
.gitea/workflows/release.yml
Normal file
@ -0,0 +1,70 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["*"]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install build
|
||||
run: python -m pip install --upgrade pip build
|
||||
|
||||
- name: Verify tag matches package version
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VERSION="${{ gitea.ref_name }}"
|
||||
PKG_VERSION=$(python -c "import configparser; c = configparser.ConfigParser(); c.read('setup.cfg'); print(c['metadata']['version'].strip())")
|
||||
echo "Tag: ${VERSION}, setup.cfg: ${PKG_VERSION}"
|
||||
test "${VERSION}" = "${PKG_VERSION}"
|
||||
|
||||
- name: Build sdist and wheel
|
||||
run: python -m build
|
||||
|
||||
- name: Publish to Gitea release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VERSION="${{ gitea.ref_name }}"
|
||||
API="http://gitea.service:3000/api/v1/repos/${{ gitea.repository }}"
|
||||
AUTH="Authorization: token ${GITEA_TOKEN}"
|
||||
|
||||
RELEASE_ID=$(curl -sf "${API}/releases/tags/${VERSION}" -H "${AUTH}" \
|
||||
| python3 -c "import sys, json; print(json.load(sys.stdin).get('id', ''))" || true)
|
||||
|
||||
if [ -z "${RELEASE_ID}" ]; then
|
||||
echo "Creating release ${VERSION}"
|
||||
RELEASE_ID=$(curl -f -X POST "${API}/releases" \
|
||||
-H "${AUTH}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\": \"${VERSION}\", \"name\": \"${VERSION}\", \"target_commitish\": \"${{ gitea.sha }}\"}" \
|
||||
| python3 -c "import sys, json; print(json.load(sys.stdin)['id'])")
|
||||
else
|
||||
echo "Using existing release ${RELEASE_ID}"
|
||||
fi
|
||||
|
||||
for ASSET in dist/*; do
|
||||
NAME=$(basename "${ASSET}")
|
||||
OLD_ID=$(curl -sf "${API}/releases/${RELEASE_ID}/assets" -H "${AUTH}" \
|
||||
| python3 -c "import sys, json; print(next((a['id'] for a in json.load(sys.stdin) if a['name'] == '${NAME}'), ''))" || true)
|
||||
if [ -n "${OLD_ID}" ]; then
|
||||
echo "Deleting existing asset ${NAME} (id ${OLD_ID})"
|
||||
curl -f -X DELETE "${API}/releases/assets/${OLD_ID}" -H "${AUTH}"
|
||||
fi
|
||||
echo "Uploading ${NAME}"
|
||||
curl -f -X POST "${API}/releases/${RELEASE_ID}/assets?name=${NAME}" \
|
||||
-H "${AUTH}" \
|
||||
-F "attachment=@${ASSET}"
|
||||
done
|
||||
|
||||
echo "Released ${VERSION} with $(ls dist | wc -l) asset(s)"
|
||||
@ -1,10 +1,5 @@
|
||||
****************
|
||||
Mopidy-Webhooks
|
||||
****************
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/Mopidy-Webhooks
|
||||
:target: https://pypi.org/project/Mopidy-Webhooks/
|
||||
:alt: Latest PyPI version
|
||||
===============
|
||||
|
||||
`Mopidy <https://www.mopidy.com/>`_ extension for sending mopidy play status to
|
||||
arbitrary URL endpoints
|
||||
@ -41,9 +36,9 @@ The following configuration values are available:
|
||||
Project resources
|
||||
=================
|
||||
|
||||
- `Source code <https://github.com/powellc/mopidy-webhooks>`_
|
||||
- `Issue tracker <https://github.com/powellc/mopidy-webhooks/issues>`_
|
||||
- `Changelog <https://github.com/powellc/mopidy-webhooks/releases>`_
|
||||
- `Source code <https://code.unbl.ink/secstate/mopidy-webhooks>`_
|
||||
- `Issue tracker <https://code.unbl.ink/secstate/mopidy-webhooks/issues>`_
|
||||
- `Changelog <https://code.unbl.ink/secstate/mopidy-webhooks/releases>`_
|
||||
|
||||
|
||||
Credits
|
||||
@ -18,9 +18,9 @@ class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
|
||||
self.last_start_time = None
|
||||
|
||||
def on_start(self):
|
||||
logger.info("Parsing webhook URLs and tokens")
|
||||
self.webhook_urls = self.config["webhooks"]["urls"].split(",")
|
||||
self.webhook_tokens = self.config["webhooks"]["tokens"].split(",")
|
||||
logger.info(f"Parsing webhook URLs and tokens: {self.webhook_urls}")
|
||||
|
||||
def _build_post_data(self, track, time_position: Optional[int]=None) -> dict:
|
||||
artists = ", ".join(sorted([a.name for a in track.artists]))
|
||||
@ -33,6 +33,7 @@ class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
|
||||
album_name = ""
|
||||
if track.album:
|
||||
album_name = getattr(track.album, "name")
|
||||
|
||||
return {
|
||||
"name": track.name,
|
||||
"artist": artists,
|
||||
@ -45,6 +46,7 @@ class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
|
||||
"musicbrainz_album_id": track.album.musicbrainz_id if track.album else "",
|
||||
"musicbrainz_artist_id": musicbrainz_artist_id,
|
||||
"mopidy_uri": track.uri,
|
||||
"primary_artist_mopidy_uri": artists_list[0].uri,
|
||||
}
|
||||
|
||||
def _post_update_to_webhooks(self, post_data: dict, status: str):
|
||||
@ -59,7 +61,7 @@ class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
|
||||
logger.info(f"No token found for Webhook URL: {webhook_url}")
|
||||
|
||||
if token:
|
||||
headers["Authorization"] = "Token {token}"
|
||||
headers["Authorization"] = f"Token {token}"
|
||||
|
||||
response = requests.post(
|
||||
webhook_url, json=json.dumps(post_data), headers=headers
|
||||
@ -71,7 +73,7 @@ class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
|
||||
artists = ", ".join(sorted([a.name for a in track.artists]))
|
||||
self.last_start_time = int(time.time())
|
||||
logger.debug(f"Now playing track: {artists} - {track.name}")
|
||||
post_data = self._build_post_data(tl_track.track)
|
||||
post_data = self._build_post_data(tl_track.track, time_position=0)
|
||||
|
||||
# Build post data to send to urls
|
||||
if not self.webhook_urls:
|
||||
@ -84,11 +86,11 @@ class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
|
||||
track = tl_track.track
|
||||
artists = ", ".join(sorted([a.name for a in track.artists]))
|
||||
duration = track.length and track.length // 1000 or 0
|
||||
time_position = time_position // 1000
|
||||
time_position_sec = time_position // 1000
|
||||
|
||||
post_data = self._build_post_data(tl_track.track, time_position=time_position)
|
||||
|
||||
if time_position < duration // 2 and time_position < 240:
|
||||
if time_position_sec < duration // 2 and time_position_sec < 240:
|
||||
logger.debug(
|
||||
"Track not played long enough to scrobble. (50% or 240s)"
|
||||
)
|
||||
@ -106,16 +108,10 @@ class WebhooksFrontend(pykka.ThreadingActor, CoreListener):
|
||||
track = tl_track.track
|
||||
artists = ", ".join(sorted([a.name for a in track.artists]))
|
||||
duration = track.length and track.length // 1000 or 0
|
||||
time_position = time_position // 1000
|
||||
time_position_sec = time_position // 1000
|
||||
|
||||
post_data = self._build_post_data(tl_track.track, time_position=time_position)
|
||||
|
||||
if time_position < duration // 2 and time_position < 240:
|
||||
logger.debug(
|
||||
"Track not played long enough to scrobble. (50% or 240s)"
|
||||
)
|
||||
return
|
||||
|
||||
if self.last_start_time is None:
|
||||
self.last_start_time = int(time.time()) - duration
|
||||
logger.info(
|
||||
|
||||
Reference in New Issue
Block a user