diff options
author | Dashie <dashie@sigpipe.me> | 2020-04-06 17:20:17 +0200 |
---|---|---|
committer | Dashie <dashie@sigpipe.me> | 2020-04-06 17:20:17 +0200 |
commit | 465ad01956169c1b95a19f48790a5b3bc387ee25 (patch) | |
tree | 8d0ea154a8d7c6188439f1dc7e89b7d733d0cbd9 | |
parent | 9fa5988bfe144c0caea48cdf8c6c54216b650a52 (diff) |
Add support for feeds in Actor for funkwhale; Also add RSS to feeds
-rw-r--r-- | api/controllers/feeds.py | 48 | ||||
-rw-r--r-- | api/models.py | 11 |
2 files changed, 48 insertions, 11 deletions
diff --git a/api/controllers/feeds.py b/api/controllers/feeds.py index 5da30713..32004008 100644 --- a/api/controllers/feeds.py +++ b/api/controllers/feeds.py @@ -3,13 +3,15 @@ from models import User, Sound, Album from utils.defaults import Reel2bitsDefaults from feedgen.feed import FeedGenerator import pytz +import sqlalchemy bp_feeds = Blueprint("bp_feeds", __name__) -def gen_feed(title, author, feed_url, url, subtitle, logo, categories=None, album=False, licenses=False): +def gen_feed(title, author, feed_url, url, subtitle, logo, categories=None, album=False, licenses=False, typ="atom"): fg = FeedGenerator() - fg.load_extension("podcast") + if typ != "rss": + fg.load_extension("podcast") fg.id(feed_url) fg.title(title) @@ -23,13 +25,15 @@ def gen_feed(title, author, feed_url, url, subtitle, logo, categories=None, albu generator="reel2bits", uri=f"https://{current_app.config['AP_DOMAIN']}", version=g.cfg["REEL2BITS_VERSION"] ) - if album and categories: + if album and categories and typ != "rss": fg.podcast.itunes_category(categories[0]) fg.category([{"term": c, "label": c} for c in categories]) if licenses: fg.rights("See individual tracks: " + ", ".join(licenses)) + print(typ) + return fg @@ -38,12 +42,18 @@ def utcdate(date): @bp_feeds.route("/feeds/tracks/<string:user_id>", methods=["GET"]) -@bp_feeds.route("/feeds/tracks/<string:user_id>.atom", methods=["GET"]) +@bp_feeds.route("/feeds/tracks/<string:user_id>.atom", methods=["GET"], endpoint="tracks_atom") +@bp_feeds.route("/feeds/tracks/<string:user_id>.rss", methods=["GET"], endpoint="tracks_rss") def tracks(user_id): - user = User.query.filter(User.flake_id == user_id).first() + try: + user = User.query.filter(User.flake_id == user_id).first() + except sqlalchemy.exc.DataError: + abort(500) if not user: abort(404) + typ = "rss" if request.endpoint in ["bp_feeds.tracks_rss"] else "atom" + q = Sound.query.filter(Sound.user_id == user.id, Sound.private.is_(False)) q = q.filter(Sound.transcode_state == Sound.TRANSCODE_DONE) q = q.order_by(Sound.uploaded.desc()) @@ -53,7 +63,7 @@ def tracks(user_id): author = {"name": user.name, "uri": f"https://{current_app.config['AP_DOMAIN']}/{user.name}"} logo = None or f"https://{current_app.config['AP_DOMAIN']}/static/userpic_placeholder.png" - feed = gen_feed(f"{user.name} tracks", author, feed_url, url, f"Tracks of {user.name}", logo) + feed = gen_feed(f"{user.name} tracks", author, feed_url, url, f"Tracks of {user.name}", logo, typ=typ) for track in q: path_sound = track.path_sound(orig=False) @@ -73,19 +83,31 @@ def tracks(user_id): fe.pubDate(utcdate(track.uploaded)) fe.updated(utcdate(track.updated)) fe.content(track.description) - return feed.atom_str(pretty=True) + if typ == "rss": + return feed.rss_str(pretty=True) + else: + return feed.atom_str(pretty=True) @bp_feeds.route("/feeds/album/<string:user_id>/<int:album_id>", methods=["GET"]) -@bp_feeds.route("/feeds/album/<string:user_id>/<int:album_id>.atom", methods=["GET"]) +@bp_feeds.route("/feeds/album/<string:user_id>/<int:album_id>.atom", methods=["GET"], endpoint="album_atom") +@bp_feeds.route("/feeds/album/<string:user_id>/<int:album_id>.rss", methods=["GET"], endpoint="album_rss") def album(user_id, album_id): - user = User.query.filter(User.flake_id == user_id).first() + try: + user = User.query.filter(User.flake_id == user_id).first() + except sqlalchemy.exc.DataError: + abort(500) if not user: abort(404) - album = Album.query.filter(Album.id == album_id, Album.user_id == user.id, Album.private.is_(False)).first() + try: + album = Album.query.filter(Album.id == album_id, Album.user_id == user.id, Album.private.is_(False)).first() + except sqlalchemy.exc.DataError: + abort(500) if not album: abort(404) + typ = "rss" if request.endpoint in ["bp_feeds.album_rss"] else "atom" + feed_url = request.url url = f"https://{current_app.config['AP_DOMAIN']}/{user.name}/album/{album.title}" author = {"name": user.name, "uri": f"https://{current_app.config['AP_DOMAIN']}/{user.name}"} @@ -114,6 +136,7 @@ def album(user_id, album_id): categories=categories, album=True, licenses=lics, + typ=typ, ) for track in album.sounds.filter(Sound.transcode_state == Sound.TRANSCODE_DONE): @@ -135,4 +158,7 @@ def album(user_id, album_id): fe.updated(utcdate(track.updated)) fe.content(track.description) fe.category([{"term": c, "label": c} for c in [track.genre]]) - return feed.atom_str(pretty=True) + if typ == "rss": + return feed.rss_str(pretty=True) + else: + return feed.atom_str(pretty=True) diff --git a/api/models.py b/api/models.py index d057d6b1..42ec3de9 100644 --- a/api/models.py +++ b/api/models.py @@ -669,6 +669,8 @@ class Actor(db.Model): url_avatar = url_for("get_uploads_stuff", thing="avatars", stuff=self.user.path_avatar(), _external=True) else: url_avatar = f"{current_app.config['REEL2BITS_URL']}/static/userpic_placeholder.svg" + url_feed_atom = url_for("bp_feeds.tracks_atom", user_id=self.user.flake_id, _external=True) + url_feed_rss = url_for("bp_feeds.tracks_rss", user_id=self.user.flake_id, _external=True) return { "@context": DEFAULT_CTX, @@ -684,6 +686,15 @@ class Actor(db.Model): "publicKey": {"id": self.private_key_id(), "owner": self.url, "publicKeyPem": self.public_key}, "endpoints": {"sharedInbox": self.shared_inbox_url}, "icon": {"type": "Image", "url": url_avatar}, + "url": [ + { + "type": "Link", + "mediaType": "text/html", + "href": f"{current_app.config['REEL2BITS_URL']}/user/{self.preferred_username}", + }, + {"type": "Link", "mediaType": "application/atom+xml", "href": url_feed_atom}, + {"type": "Link", "mediaType": "application/atom+xml", "href": url_feed_rss}, + ], } |