From f270d140af8fcbe99184de40ec9821e6fb051353 Mon Sep 17 00:00:00 2001 From: Petitminion Date: Sat, 1 Mar 2025 00:08:10 +0100 Subject: [PATCH] Create tracks from troi recommendations (#2408) --- api/config/settings/common.py | 7 +++++++ api/funkwhale_api/music/models.py | 9 +++++++++ api/funkwhale_api/radios/lb_recommendations.py | 18 +++++++++++++++++- api/funkwhale_api/radios/radios.py | 3 +-- api/funkwhale_api/radios/radios_v2.py | 3 +-- api/funkwhale_api/typesense/factories.py | 3 ++- api/tests/radios/test_lb_recommendations.py | 1 + changes/changelog.d/2408.feature | 1 + 8 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 changes/changelog.d/2408.feature diff --git a/api/config/settings/common.py b/api/config/settings/common.py index e93d01018..fb12c3b14 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -1541,3 +1541,10 @@ Each api request to playlist tracks or radio tracks trigger the hook if tracks u If your instance is big your ip might get rate limited. """ THIRD_PARTY_UPLOAD_MAX_UPLOADS = env.int("THIRD_PARTY_UPLOAD_MAX_UPLOADS", default=10) + + +""" +This will enable the creation of metadata for tracks recommended by troi but missing in the db. +If you have a lot of user using the troi radios this might generate a lot of metadata. +""" +TROI_CREATE_METADATA = env.bool("TROI_CREATE_METADATA", default=True) diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index abff1a7cf..cc93e7c96 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -706,6 +706,15 @@ class Track(APIModelMixin): track[0].artist_credit.set(artists_credits) return track + @classmethod + def create_from_api(cls, **kwargs): + if kwargs.get("id"): + raw_data = cls.api.get(id=kwargs["id"], includes=cls.api_includes) + else: + raw_data = cls.api.search(**kwargs)[0] + cleaned_data = cls.clean_musicbrainz_data(raw_data) + return importers.load(cls, cleaned_data, raw_data, cls.import_hooks) + @property def listen_url(self) -> str: # Not using reverse because this is slow diff --git a/api/funkwhale_api/radios/lb_recommendations.py b/api/funkwhale_api/radios/lb_recommendations.py index 1ec84d4c8..eeb3108dd 100644 --- a/api/funkwhale_api/radios/lb_recommendations.py +++ b/api/funkwhale_api/radios/lb_recommendations.py @@ -3,11 +3,13 @@ import time import troi import troi.core +from django.conf import settings from django.core.cache import cache from django.core.exceptions import ValidationError from django.db.models import Q from requests.exceptions import ConnectTimeout +from config import plugins from funkwhale_api.music import models as music_models from funkwhale_api.typesense import utils @@ -38,6 +40,18 @@ def validate(config): return True +def create_and_fetch_troi_tracks(recommended_recordings): + """Create a track in Funkwhale database from a troi recording""" + # to do : settings.THIRD_PARTY_UPLOAD_MAX_UPLOADS + for recording in recommended_recordings: + track, created = music_models.Track.create_from_api(recording.mbid) + + plugins.trigger_hook( + plugins.TRIGGER_THIRD_PARTY_UPLOAD, + track=track, + ) + + def build_radio_queryset(patch, radio_qs): """Take a troi patch, match the missing mbid and then build a radio queryset""" @@ -102,11 +116,13 @@ def build_radio_queryset(patch, radio_qs): end_time_resolv = time.time() logger.info( - "Resolving " + "Resolved " + str(len(recommended_recordings_not_found)) + " tracks in " + str(end_time_resolv - start_time_resolv) ) + if settings.TROI_CREATE_METADATA: + create_and_fetch_troi_tracks(recommended_recordings_not_found) cached_match = cache.get_many(recommended_mbids) diff --git a/api/funkwhale_api/radios/radios.py b/api/funkwhale_api/radios/radios.py index 590705e05..d0172d6f6 100644 --- a/api/funkwhale_api/radios/radios.py +++ b/api/funkwhale_api/radios/radios.py @@ -1,5 +1,4 @@ import datetime -import json import logging import random from typing import List, Optional, Tuple @@ -487,6 +486,6 @@ class Troi(SessionRadio): def get_queryset(self, **kwargs): qs = super().get_queryset(**kwargs) - config = self.append_lb_config(json.loads(kwargs["config"])) + config = self.append_lb_config(kwargs["config"]) return lb_recommendations.run(config, candidates=qs) diff --git a/api/funkwhale_api/radios/radios_v2.py b/api/funkwhale_api/radios/radios_v2.py index d13d1eb82..ef6c93bfe 100644 --- a/api/funkwhale_api/radios/radios_v2.py +++ b/api/funkwhale_api/radios/radios_v2.py @@ -1,5 +1,4 @@ import datetime -import json import logging import pickle import random @@ -521,6 +520,6 @@ class Troi(SessionRadio): def get_queryset(self, **kwargs): qs = super().get_queryset(**kwargs) - config = self.append_lb_config(json.loads(kwargs["config"])) + config = self.append_lb_config(kwargs["config"]) return lb_recommendations.run(config, candidates=qs) diff --git a/api/funkwhale_api/typesense/factories.py b/api/funkwhale_api/typesense/factories.py index fdeef622f..8338d6775 100644 --- a/api/funkwhale_api/typesense/factories.py +++ b/api/funkwhale_api/typesense/factories.py @@ -9,6 +9,7 @@ recording_list = [ ), Recording( name="Untouchable", + mbid="87dfa566-21c3-45ed-bc42-1d345b8563fa", artist_credit=ArtistCredit(artists=[Artist(name="Another lol")]), ), Recording( @@ -41,7 +42,7 @@ class DummyElement(Element): Recording( name="I Want It That Way", mbid="87dfa566-21c3-45ed-bc42-1d345b8563fa" ), - Recording(name="Untouchable"), + Recording(name="Untouchable", mbid="87dfa566-21c3-45ed-bc42-1d345b8563fa"), Recording( name="The Perfect Kiss", mbid="ec0da94e-fbfe-4eb0-968e-024d4c32d1d0" ), diff --git a/api/tests/radios/test_lb_recommendations.py b/api/tests/radios/test_lb_recommendations.py index 9ce700e8d..6ddfe21b7 100644 --- a/api/tests/radios/test_lb_recommendations.py +++ b/api/tests/radios/test_lb_recommendations.py @@ -34,6 +34,7 @@ def test_can_build_radio_queryset_with_fw_db(factories, mocker): assert list( Track.objects.all().filter(Q(mbid__in=recommended_recording_mbids)) ) == list(radio_qs) + assert Track.objects.filter(mbid="395bd5a1-79cc-4e04-8869-ca9eabc78d09").exists() def test_build_radio_queryset_without_fw_db(mocker): diff --git a/changes/changelog.d/2408.feature b/changes/changelog.d/2408.feature new file mode 100644 index 000000000..1e0aec902 --- /dev/null +++ b/changes/changelog.d/2408.feature @@ -0,0 +1 @@ +Create tracks from troi recommendations (#2408)