diff --git a/api/funkwhale_api/radios/radios.py b/api/funkwhale_api/radios/radios.py index 4f23fb28121727b181a0c80e425391a44063c668..ef1931d5ffeac2382c1885d204a9c7f92afc7228 100644 --- a/api/funkwhale_api/radios/radios.py +++ b/api/funkwhale_api/radios/radios.py @@ -1,3 +1,4 @@ +import logging import random from django.core.exceptions import ValidationError @@ -11,9 +12,11 @@ from funkwhale_api.moderation import filters as moderation_filters from funkwhale_api.music.models import Artist, Library, Track, Upload from funkwhale_api.tags.models import Tag -from . import filters, models +from . import filters, models, utils from .registries import registry +logger = logging.getLogger(__name__) + class SimpleRadio(object): related_object_field = None @@ -201,7 +204,7 @@ class NextNotFound(Exception): pass -@registry.register(name="similar") +@registry.register(name="similar_history") class SimilarRadio(RelatedObjectRadio): model = Track @@ -254,6 +257,27 @@ class SimilarRadio(RelatedObjectRadio): return random.choice([c[0] for c in next_candidates]) +@registry.register(name="similar_mbid") +class SimilarAcousticRadio(RelatedObjectRadio): + model = Track + + def get_regex(self): + related_mbid = str(self.session.related_object.mbid) + if not related_mbid: + logger.info(f"No mbid found for the related object.") + pass + mbids_regex = str() + mbids = utils.get_similar_tracks_mbids_from_mbid(related_mbid, "rosamerica") + for mbid in mbids: + mbids_regex = str(mbids_regex) + str(mbid + "|") + return mbids_regex + + def filter_queryset(self, queryset): + queryset = super().filter_queryset(queryset) + mbids_regex = self.get_regex() + return queryset.filter(mbid__regex=r'({mbids_regex})'.format(mbids_regex=mbids_regex)) + + @registry.register(name="artist") class ArtistRadio(RelatedObjectRadio): model = Artist diff --git a/api/funkwhale_api/radios/utils.py b/api/funkwhale_api/radios/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1190b78b56b1a71fcb32a9b6db9c0c5625640d9b --- /dev/null +++ b/api/funkwhale_api/radios/utils.py @@ -0,0 +1,35 @@ +import json +import logging + +import requests + +logger = logging.getLogger(__name__) + +VALID_METRICS = ['mfccs', 'mfccsw', 'gfccs', 'gfccsw', 'key', 'bpm', 'onsetrate', 'moods', + 'instruments', 'dortmund', 'rosamerica', 'tzanetakis'] + + +class EndpointError(Exception): + pass + + +def get_similar_tracks_mbids_from_mbid(mbid, annoy_similarity): + + if annoy_similarity not in VALID_METRICS: + raise AttributeError("Metric %s is not valid. Must be one of : " + print(VALID_METRICS)) + + headers = {'Content-Type': 'application/json'} + endpoint = "acousticbrainz.org/api/v1/similarity" + similar_tracks_mbids = [] + similar_tracks = requests.get( + 'https://{endpoint}/{annoy_similarity}/?recording_ids={mbid}&remove_dups&n_neighbours=1000' + .format(endpoint=endpoint, annoy_similarity=annoy_similarity, mbid=mbid), headers=headers + ) + if similar_tracks.status_code != 200: + logger.warning("Error while querying {endpoint!r} : {similar_tracks.content!r}") + raise EndpointError + + j = json.loads(similar_tracks.content) + for tracks in j['{mbid}'.format(mbid=mbid)]['0']: + similar_tracks_mbids.append(tracks['recording_mbid']) + return similar_tracks_mbids diff --git a/front/src/components/audio/PlayButton.vue b/front/src/components/audio/PlayButton.vue index dd0e651324a4f1d46200bc81f738f94c3408861a..564ac3d7fa1ee6e4eec89074ea304d10bb9e51f9 100644 --- a/front/src/components/audio/PlayButton.vue +++ b/front/src/components/audio/PlayButton.vue @@ -25,7 +25,7 @@ <button class="item basic" ref="playNow" data-ref="playNow" :disabled="!playable" @click.stop.prevent="addNext(true)" :title="labels.playNow"> <i class="play icon"></i>{{ labels.playNow }} </button> - <button v-if="track" class="item basic" :disabled="!playable" @click.stop.prevent="$store.dispatch('radios/start', {type: 'similar', objectId: track.id})" :title="labels.startRadio"> + <button v-if="track" class="item basic" :disabled="!playable" @click.stop.prevent="$store.dispatch('radios/start', {type: 'similar_history', objectId: track.id})" :title="labels.startRadio"> <i class="feed icon"></i><translate translate-context="*/Queue/Button.Label/Short, Verb">Play radio</translate> </button> <button v-if="track" class="item basic" :disabled="!playable" @click.stop="$store.commit('playlists/chooseTrack', track)">