add related links
artist links to feed page (/feed/:ID) release links to feed xml (release description)
This commit is contained in:
@@ -68,10 +68,13 @@ class Config:
|
||||
backup_path = f"{file_path}.{datetime.now().strftime('%Y%m%d%H%M%S')}.bak"
|
||||
shutil.copy(file_path, backup_path)
|
||||
|
||||
logger.debug(f"Saving yaml to {file_path}")
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
with open(file_path, 'w') as f:
|
||||
yaml.dump(data, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
logger.debug(f"Saved yaml to {file_path}")
|
||||
|
||||
@property
|
||||
def feeds(self):
|
||||
return self._feeds_data.get('feeds', [])
|
||||
@@ -105,13 +108,16 @@ class Config:
|
||||
self._feeds_data['feeds'] = [feed for feed in self.feeds if feed['id'] != feed_id]
|
||||
self.save_feeds()
|
||||
|
||||
def add_artist_to_feed(self, feed_id, artist_id, artist_name):
|
||||
def add_artist_to_feed(self, feed_id, artist_id, artist_name, links = None):
|
||||
for feed in self.feeds:
|
||||
if feed['id'] == feed_id:
|
||||
if 'artists' not in feed:
|
||||
feed['artists'] = []
|
||||
if not any(a['id'] == artist_id for a in feed['artists']):
|
||||
feed['artists'].append({'id': artist_id, 'name': artist_name})
|
||||
artist_data = {'id': artist_id, 'name': artist_name}
|
||||
if links:
|
||||
artist_data['links'] = links
|
||||
feed['artists'].append(artist_data)
|
||||
feed['updated_at'] = datetime.now(timezone.utc).isoformat()
|
||||
self.save_feeds()
|
||||
break
|
||||
|
||||
@@ -9,6 +9,8 @@ import os
|
||||
import sys
|
||||
from . import musicbrainz
|
||||
|
||||
XML_CONTENT_TYPE = "application/xml"
|
||||
|
||||
log_level_str = os.environ.get('LOG_LEVEL', 'INFO').upper()
|
||||
log_level = getattr(logging, log_level_str, logging.INFO)
|
||||
log_file = os.path.expandvars(os.environ.get('LOG_FILE', '/var/mbz-rss-feeder/log/mbz-rss-feeder.log'))
|
||||
@@ -154,7 +156,7 @@ def _check_cache(feed_id):
|
||||
try:
|
||||
with open(cache_file, 'r') as f:
|
||||
logger.debug(f"Serving cached feed for {feed_id}")
|
||||
return f.read(), {"Content-Type": "application/xml"}
|
||||
return f.read(), {"Content-Type": XML_CONTENT_TYPE}
|
||||
except IOError as e:
|
||||
logger.warning(f"Could not read cache file {cache_file}: {e}")
|
||||
|
||||
@@ -195,7 +197,8 @@ def add_artist(feed_id):
|
||||
artist_name = request.form.get('artist_name')
|
||||
logger.debug(f"Request to add artist '{artist_name}' ({artist_id}) to feed {feed_id}")
|
||||
if artist_id and artist_name:
|
||||
config.add_artist_to_feed(feed_id, artist_id, artist_name)
|
||||
meta = musicbrainz.get_artist_meta_by_id(artist_id)
|
||||
config.add_artist_to_feed(feed_id, artist_id, artist_name, meta['links'])
|
||||
return redirect(url_for('edit_feed', feed_id=feed_id))
|
||||
|
||||
@app.route("/feed/<feed_id>/artist/<artist_id>/remove", methods=["POST"])
|
||||
@@ -228,7 +231,7 @@ def opml():
|
||||
logger.debug("Request for OPML file")
|
||||
feeds = config.feeds
|
||||
opml_content = render_template('opml.xml', feeds=feeds)
|
||||
return opml_content, {"Content-Type": "application/xml"}
|
||||
return opml_content, {"Content-Type": XML_CONTENT_TYPE}
|
||||
|
||||
@app.route('/feed/<feed_id>')
|
||||
def get_feed_rss(feed_id):
|
||||
@@ -277,7 +280,7 @@ def get_feed_rss(feed_id):
|
||||
except IOError as e:
|
||||
logger.warning(f"Could not write feed '{feed_data['name']}' to cache file {cache_file}: {e}")
|
||||
|
||||
return rss_content, {"Content-Type": "application/xml"}
|
||||
return rss_content, {"Content-Type": XML_CONTENT_TYPE}
|
||||
|
||||
@app.route("/health")
|
||||
def health_check():
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import re
|
||||
import musicbrainzngs
|
||||
import logging
|
||||
import os
|
||||
from .config import config
|
||||
from datetime import datetime
|
||||
from email.utils import formatdate
|
||||
@@ -62,6 +62,10 @@ def _process_release(release, artist_id):
|
||||
release_date = release.get('date', 'Unknown')
|
||||
_, pub_date = _parse_release_date(release_date, release['title'])
|
||||
|
||||
links = {}
|
||||
if 'url-relation-list' in release:
|
||||
links = get_artist_relation_links(release['url-relation-list'])
|
||||
|
||||
return {
|
||||
'artist': {
|
||||
'name': config.get_artist_name(artist_id),
|
||||
@@ -72,8 +76,54 @@ def _process_release(release, artist_id):
|
||||
'title': release['title'],
|
||||
'date': release_date,
|
||||
'pub_date': pub_date,
|
||||
'release-group': release.get('release-group', {})
|
||||
'release-group': release.get('release-group', {}),
|
||||
'links': links,
|
||||
}
|
||||
def get_artist_meta_by_id(artist_id):
|
||||
"""get additional meta data about an artist"""
|
||||
meta = {
|
||||
'links': {}
|
||||
}
|
||||
try:
|
||||
logger.debug(f"Fetching artist {artist_id} meta data")
|
||||
# Fetch artist data including URL relations
|
||||
result = musicbrainzngs.get_artist_by_id(artist_id, includes=["url-rels"])
|
||||
artist_data = result.get('artist', {})
|
||||
|
||||
if 'url-relation-list' in artist_data:
|
||||
meta['links'] = get_artist_relation_links(artist_data['url-relation-list'])
|
||||
else:
|
||||
meta['links'] = None
|
||||
|
||||
return meta
|
||||
|
||||
except musicbrainzngs.WebServiceError as exc:
|
||||
logger.error(f"Error fetching artist {artist_id} meta data from MusicBrainz: {exc}")
|
||||
|
||||
return meta
|
||||
|
||||
def get_artist_relation_links(relationlist):
|
||||
"""Parse and extract named links from a MusicBrainz URL relation list."""
|
||||
links = {}
|
||||
for rel in relationlist:
|
||||
target = rel.get('target')
|
||||
if not target:
|
||||
continue
|
||||
if re.match(r'^https://.*imdb\.com', target):
|
||||
links['IMDb'] = target
|
||||
elif re.match(r'^https://music\.apple\.com', target):
|
||||
links['apple'] = target
|
||||
elif re.match(r'^https://music\.amazon\.com', target):
|
||||
links['amazon'] = target
|
||||
elif re.match(r'^https://open\.spotify\.com', target):
|
||||
links['spotify'] = target
|
||||
elif re.match(r'^https://.*qobuz\.com', target):
|
||||
links['qobuz'] = target
|
||||
elif re.match(r'^https://.*deezer\.com', target):
|
||||
links['deezer'] = target
|
||||
elif re.match(r'^https://.*beatport\.com', target):
|
||||
links['beatport'] = target
|
||||
return links
|
||||
|
||||
def get_artist_releases(artist_id):
|
||||
"""Fetch releases for a given artist ID from MusicBrainz."""
|
||||
@@ -83,7 +133,7 @@ def get_artist_releases(artist_id):
|
||||
result = musicbrainzngs.browse_releases(
|
||||
artist=artist_id,
|
||||
release_type=['album'],
|
||||
includes=['release-groups']
|
||||
includes=['release-groups', 'url-rels']
|
||||
)
|
||||
|
||||
releases = []
|
||||
@@ -9,6 +9,11 @@
|
||||
{% for artist in feed.artists %}
|
||||
<li>
|
||||
{{ artist.name }}
|
||||
{% if artist.links %}
|
||||
{% for type, link in artist.links.items() %}
|
||||
<a href="{{ link }}" target="_blank">{{ type }}</a>{% if not loop.last %} | {% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="item-actions">
|
||||
<form class="form-inline" action="{{ url_for('remove_artist', feed_id=feed.id, artist_id=artist.id) }}" method="post">
|
||||
<button type="submit">Remove</button>
|
||||
@@ -14,10 +14,17 @@
|
||||
<link>https://musicbrainz.org/release/{{ release.id }}</link>
|
||||
<guid isPermaLink="false">{{ release.id }}</guid>
|
||||
<description><![CDATA[
|
||||
{% if release.hasCoverArt %}
|
||||
<img src="https://coverartarchive.org/release/{{ release.id }}/front" alt="Cover Art {{ release.title }}">
|
||||
{% endif %}
|
||||
<p><b>{{ release.artist.name }}</b> <i>{{ release.title }}</i><br>
|
||||
Release Date: {{ release.date }}</p>
|
||||
{% if release.hasCoverArt %}
|
||||
<img src="http://coverartarchive.org/release/{{ release.id }}/front-500" alt="Cover Art {{ release.title }}">
|
||||
{% if release.links %}
|
||||
<p><b>Links: </b>
|
||||
{% for type, url in release.links.items() %}
|
||||
<a href="{{ url }}" target="_blank">{{ type | capitalize }}</a>{% if not loop.last %} | {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
]]></description>
|
||||
{% if release.pub_date %}
|
||||
Reference in New Issue
Block a user