Fix #799: Removed broken/instable lyrics feature
This commit is contained in:
parent
a414461f49
commit
0b94227782
|
@ -39,22 +39,6 @@ class ImportJobAdmin(admin.ModelAdmin):
|
||||||
list_filter = ["status"]
|
list_filter = ["status"]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Work)
|
|
||||||
class WorkAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ["title", "mbid", "language", "nature"]
|
|
||||||
list_select_related = True
|
|
||||||
search_fields = ["title"]
|
|
||||||
list_filter = ["language", "nature"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Lyrics)
|
|
||||||
class LyricsAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ["url", "id", "url"]
|
|
||||||
list_select_related = True
|
|
||||||
search_fields = ["url", "work__title"]
|
|
||||||
list_filter = ["work__language"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Upload)
|
@admin.register(models.Upload)
|
||||||
class UploadAdmin(admin.ModelAdmin):
|
class UploadAdmin(admin.ModelAdmin):
|
||||||
list_display = [
|
list_display = [
|
||||||
|
|
|
@ -164,27 +164,6 @@ class UploadVersionFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
||||||
model = "music.UploadVersion"
|
model = "music.UploadVersion"
|
||||||
|
|
||||||
|
|
||||||
@registry.register
|
|
||||||
class WorkFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
|
||||||
mbid = factory.Faker("uuid4")
|
|
||||||
language = "eng"
|
|
||||||
nature = "song"
|
|
||||||
title = factory.Faker("sentence", nb_words=3)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = "music.Work"
|
|
||||||
|
|
||||||
|
|
||||||
@registry.register
|
|
||||||
class LyricsFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
|
||||||
work = factory.SubFactory(WorkFactory)
|
|
||||||
url = factory.Faker("url")
|
|
||||||
content = factory.Faker("paragraphs", nb=4)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = "music.Lyrics"
|
|
||||||
|
|
||||||
|
|
||||||
@registry.register
|
@registry.register
|
||||||
class TagFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
class TagFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
||||||
name = factory.SelfAttribute("slug")
|
name = factory.SelfAttribute("slug")
|
||||||
|
|
|
@ -47,4 +47,4 @@ class Mapping(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
registry = {"Artist": Importer, "Track": Importer, "Album": Importer, "Work": Importer}
|
registry = {"Artist": Importer, "Track": Importer, "Album": Importer}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
|
|
||||||
def _get_html(url):
|
|
||||||
with urllib.request.urlopen(url) as response:
|
|
||||||
html = response.read()
|
|
||||||
return html.decode("utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def extract_content(html):
|
|
||||||
soup = BeautifulSoup(html, "html.parser")
|
|
||||||
return soup.find_all("div", class_="lyricbox")[0].contents
|
|
||||||
|
|
||||||
|
|
||||||
def clean_content(contents):
|
|
||||||
final_content = ""
|
|
||||||
for e in contents:
|
|
||||||
if e == "\n":
|
|
||||||
continue
|
|
||||||
if e.name == "script":
|
|
||||||
continue
|
|
||||||
if e.name == "br":
|
|
||||||
final_content += "\n"
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
final_content += e.text
|
|
||||||
except AttributeError:
|
|
||||||
final_content += str(e)
|
|
||||||
return final_content
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Generated by Django 2.1.7 on 2019-04-23 08:20
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('music', '0038_attributed_to'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='lyrics',
|
||||||
|
name='work',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='work',
|
||||||
|
name='from_activity',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='track',
|
||||||
|
name='work',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Lyrics',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Work',
|
||||||
|
),
|
||||||
|
]
|
|
@ -6,7 +6,6 @@ import tempfile
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import markdown
|
|
||||||
import pendulum
|
import pendulum
|
||||||
import pydub
|
import pydub
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -379,77 +378,6 @@ def import_album(v):
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
|
||||||
def link_recordings(instance, cleaned_data, raw_data):
|
|
||||||
tracks = [r["target"] for r in raw_data["recording-relation-list"]]
|
|
||||||
Track.objects.filter(mbid__in=tracks).update(work=instance)
|
|
||||||
|
|
||||||
|
|
||||||
def import_lyrics(instance, cleaned_data, raw_data):
|
|
||||||
try:
|
|
||||||
url = [
|
|
||||||
url_data
|
|
||||||
for url_data in raw_data["url-relation-list"]
|
|
||||||
if url_data["type"] == "lyrics"
|
|
||||||
][0]["target"]
|
|
||||||
except (IndexError, KeyError):
|
|
||||||
return
|
|
||||||
l, _ = Lyrics.objects.get_or_create(work=instance, url=url)
|
|
||||||
|
|
||||||
return l
|
|
||||||
|
|
||||||
|
|
||||||
class Work(APIModelMixin):
|
|
||||||
language = models.CharField(max_length=20)
|
|
||||||
nature = models.CharField(max_length=50)
|
|
||||||
title = models.CharField(max_length=255)
|
|
||||||
|
|
||||||
api = musicbrainz.api.works
|
|
||||||
api_includes = ["url-rels", "recording-rels"]
|
|
||||||
musicbrainz_model = "work"
|
|
||||||
federation_namespace = "works"
|
|
||||||
|
|
||||||
musicbrainz_mapping = {
|
|
||||||
"mbid": {"musicbrainz_field_name": "id"},
|
|
||||||
"title": {"musicbrainz_field_name": "title"},
|
|
||||||
"language": {"musicbrainz_field_name": "language"},
|
|
||||||
"nature": {"musicbrainz_field_name": "type", "converter": lambda v: v.lower()},
|
|
||||||
}
|
|
||||||
import_hooks = [import_lyrics, link_recordings]
|
|
||||||
|
|
||||||
def fetch_lyrics(self):
|
|
||||||
lyric = self.lyrics.first()
|
|
||||||
if lyric:
|
|
||||||
return lyric
|
|
||||||
data = self.api.get(self.mbid, includes=["url-rels"])["work"]
|
|
||||||
lyric = import_lyrics(self, {}, data)
|
|
||||||
|
|
||||||
return lyric
|
|
||||||
|
|
||||||
def get_federation_id(self):
|
|
||||||
if self.fid:
|
|
||||||
return self.fid
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class Lyrics(models.Model):
|
|
||||||
uuid = models.UUIDField(unique=True, db_index=True, default=uuid.uuid4)
|
|
||||||
work = models.ForeignKey(
|
|
||||||
Work, related_name="lyrics", null=True, blank=True, on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
url = models.URLField(unique=True)
|
|
||||||
content = models.TextField(null=True, blank=True)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def content_rendered(self):
|
|
||||||
return markdown.markdown(
|
|
||||||
self.content,
|
|
||||||
safe_mode=True,
|
|
||||||
enable_attributes=False,
|
|
||||||
extensions=["markdown.extensions.nl2br"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TrackQuerySet(common_models.LocalFromFidQuerySet, models.QuerySet):
|
class TrackQuerySet(common_models.LocalFromFidQuerySet, models.QuerySet):
|
||||||
def for_nested_serialization(self):
|
def for_nested_serialization(self):
|
||||||
return self.select_related().select_related("album__artist", "artist")
|
return self.select_related().select_related("album__artist", "artist")
|
||||||
|
@ -499,9 +427,6 @@ class Track(APIModelMixin):
|
||||||
album = models.ForeignKey(
|
album = models.ForeignKey(
|
||||||
Album, related_name="tracks", null=True, blank=True, on_delete=models.CASCADE
|
Album, related_name="tracks", null=True, blank=True, on_delete=models.CASCADE
|
||||||
)
|
)
|
||||||
work = models.ForeignKey(
|
|
||||||
Work, related_name="tracks", null=True, blank=True, on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
license = models.ForeignKey(
|
license = models.ForeignKey(
|
||||||
License,
|
License,
|
||||||
null=True,
|
null=True,
|
||||||
|
@ -523,7 +448,7 @@ class Track(APIModelMixin):
|
||||||
federation_namespace = "tracks"
|
federation_namespace = "tracks"
|
||||||
musicbrainz_model = "recording"
|
musicbrainz_model = "recording"
|
||||||
api = musicbrainz.api.recordings
|
api = musicbrainz.api.recordings
|
||||||
api_includes = ["artist-credits", "releases", "media", "tags", "work-rels"]
|
api_includes = ["artist-credits", "releases", "media", "tags"]
|
||||||
musicbrainz_mapping = {
|
musicbrainz_mapping = {
|
||||||
"mbid": {"musicbrainz_field_name": "id"},
|
"mbid": {"musicbrainz_field_name": "id"},
|
||||||
"title": {"musicbrainz_field_name": "title"},
|
"title": {"musicbrainz_field_name": "title"},
|
||||||
|
@ -552,20 +477,6 @@ class Track(APIModelMixin):
|
||||||
self.artist = self.album.artist
|
self.artist = self.album.artist
|
||||||
super().save(**kwargs)
|
super().save(**kwargs)
|
||||||
|
|
||||||
def get_work(self):
|
|
||||||
if self.work:
|
|
||||||
return self.work
|
|
||||||
data = self.api.get(self.mbid, includes=["work-rels"])
|
|
||||||
try:
|
|
||||||
work_data = data["recording"]["work-relation-list"][0]["work"]
|
|
||||||
except (IndexError, KeyError):
|
|
||||||
return
|
|
||||||
work, _ = Work.get_or_create_from_api(mbid=work_data["id"])
|
|
||||||
return work
|
|
||||||
|
|
||||||
def get_lyrics_url(self):
|
|
||||||
return reverse("api:v1:tracks-lyrics", kwargs={"pk": self.pk})
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_name(self):
|
def full_name(self):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -190,7 +190,6 @@ class TrackUploadSerializer(serializers.ModelSerializer):
|
||||||
class TrackSerializer(serializers.ModelSerializer):
|
class TrackSerializer(serializers.ModelSerializer):
|
||||||
artist = ArtistSimpleSerializer(read_only=True)
|
artist = ArtistSimpleSerializer(read_only=True)
|
||||||
album = TrackAlbumSerializer(read_only=True)
|
album = TrackAlbumSerializer(read_only=True)
|
||||||
lyrics = serializers.SerializerMethodField()
|
|
||||||
uploads = serializers.SerializerMethodField()
|
uploads = serializers.SerializerMethodField()
|
||||||
listen_url = serializers.SerializerMethodField()
|
listen_url = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
@ -206,7 +205,6 @@ class TrackSerializer(serializers.ModelSerializer):
|
||||||
"creation_date",
|
"creation_date",
|
||||||
"position",
|
"position",
|
||||||
"disc_number",
|
"disc_number",
|
||||||
"lyrics",
|
|
||||||
"uploads",
|
"uploads",
|
||||||
"listen_url",
|
"listen_url",
|
||||||
"copyright",
|
"copyright",
|
||||||
|
@ -214,9 +212,6 @@ class TrackSerializer(serializers.ModelSerializer):
|
||||||
"is_local",
|
"is_local",
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_lyrics(self, obj):
|
|
||||||
return obj.get_lyrics_url()
|
|
||||||
|
|
||||||
def get_listen_url(self, obj):
|
def get_listen_url(self, obj):
|
||||||
return obj.listen_url
|
return obj.listen_url
|
||||||
|
|
||||||
|
@ -377,12 +372,6 @@ class SimpleAlbumSerializer(serializers.ModelSerializer):
|
||||||
fields = ("id", "mbid", "title", "release_date", "cover")
|
fields = ("id", "mbid", "title", "release_date", "cover")
|
||||||
|
|
||||||
|
|
||||||
class LyricsSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = models.Lyrics
|
|
||||||
fields = ("id", "work", "content", "content_rendered")
|
|
||||||
|
|
||||||
|
|
||||||
class TrackActivitySerializer(activity_serializers.ModelSerializer):
|
class TrackActivitySerializer(activity_serializers.ModelSerializer):
|
||||||
type = serializers.SerializerMethodField()
|
type = serializers.SerializerMethodField()
|
||||||
name = serializers.CharField(source="title")
|
name = serializers.CharField(source="title")
|
||||||
|
|
|
@ -17,7 +17,6 @@ from funkwhale_api.federation import library as lb
|
||||||
from funkwhale_api.taskapp import celery
|
from funkwhale_api.taskapp import celery
|
||||||
|
|
||||||
from . import licenses
|
from . import licenses
|
||||||
from . import lyrics as lyrics_utils
|
|
||||||
from . import models
|
from . import models
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from . import signals
|
from . import signals
|
||||||
|
@ -70,16 +69,6 @@ def get_cover_from_fs(dir_path):
|
||||||
return {"mimetype": m, "content": c.read()}
|
return {"mimetype": m, "content": c.read()}
|
||||||
|
|
||||||
|
|
||||||
@celery.app.task(name="Lyrics.fetch_content")
|
|
||||||
@celery.require_instance(models.Lyrics, "lyrics")
|
|
||||||
def fetch_content(lyrics):
|
|
||||||
html = lyrics_utils._get_html(lyrics.url)
|
|
||||||
content = lyrics_utils.extract_content(html)
|
|
||||||
cleaned_content = lyrics_utils.clean_content(content)
|
|
||||||
lyrics.content = cleaned_content
|
|
||||||
lyrics.save(update_fields=["content"])
|
|
||||||
|
|
||||||
|
|
||||||
@celery.app.task(name="music.start_library_scan")
|
@celery.app.task(name="music.start_library_scan")
|
||||||
@celery.require_instance(
|
@celery.require_instance(
|
||||||
models.LibraryScan.objects.select_related().filter(status="pending"), "library_scan"
|
models.LibraryScan.objects.select_related().filter(status="pending"), "library_scan"
|
||||||
|
|
|
@ -219,31 +219,6 @@ class TrackViewSet(
|
||||||
)
|
)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
@action(methods=["get"], detail=True)
|
|
||||||
@transaction.non_atomic_requests
|
|
||||||
def lyrics(self, request, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
track = models.Track.objects.get(pk=kwargs["pk"])
|
|
||||||
except models.Track.DoesNotExist:
|
|
||||||
return Response(status=404)
|
|
||||||
|
|
||||||
work = track.work
|
|
||||||
if not work:
|
|
||||||
work = track.get_work()
|
|
||||||
|
|
||||||
if not work:
|
|
||||||
return Response({"error": "unavailable work "}, status=404)
|
|
||||||
|
|
||||||
lyrics = work.fetch_lyrics()
|
|
||||||
try:
|
|
||||||
if not lyrics.content:
|
|
||||||
tasks.fetch_content(lyrics_id=lyrics.pk)
|
|
||||||
lyrics.refresh_from_db()
|
|
||||||
except AttributeError:
|
|
||||||
return Response({"error": "unavailable lyrics"}, status=404)
|
|
||||||
serializer = serializers.LyricsSerializer(lyrics)
|
|
||||||
return Response(serializer.data)
|
|
||||||
|
|
||||||
libraries = action(methods=["get"], detail=True)(
|
libraries = action(methods=["get"], detail=True)(
|
||||||
get_libraries(filter_uploads=lambda o, uploads: uploads.filter(track=o))
|
get_libraries(filter_uploads=lambda o, uploads: uploads.filter(track=o))
|
||||||
)
|
)
|
||||||
|
|
|
@ -40,10 +40,6 @@ class API(object):
|
||||||
_api.get_recording_by_id, max_age=settings.MUSICBRAINZ_CACHE_DURATION
|
_api.get_recording_by_id, max_age=settings.MUSICBRAINZ_CACHE_DURATION
|
||||||
)
|
)
|
||||||
|
|
||||||
class works(object):
|
|
||||||
search = memo(_api.search_works, max_age=settings.MUSICBRAINZ_CACHE_DURATION)
|
|
||||||
get = memo(_api.get_work_by_id, max_age=settings.MUSICBRAINZ_CACHE_DURATION)
|
|
||||||
|
|
||||||
class releases(object):
|
class releases(object):
|
||||||
search = memo(_api.search_releases, max_age=settings.MUSICBRAINZ_CACHE_DURATION)
|
search = memo(_api.search_releases, max_age=settings.MUSICBRAINZ_CACHE_DURATION)
|
||||||
get = memo(_api.get_release_by_id, max_age=settings.MUSICBRAINZ_CACHE_DURATION)
|
get = memo(_api.get_release_by_id, max_age=settings.MUSICBRAINZ_CACHE_DURATION)
|
||||||
|
|
|
@ -36,7 +36,6 @@ persisting-theory>=0.2,<0.3
|
||||||
django-versatileimagefield>=1.9,<1.10
|
django-versatileimagefield>=1.9,<1.10
|
||||||
django-filter>=2.0,<2.1
|
django-filter>=2.0,<2.1
|
||||||
django-rest-auth>=0.9,<0.10
|
django-rest-auth>=0.9,<0.10
|
||||||
beautifulsoup4>=4.6,<4.7
|
|
||||||
Markdown>=2.6,<2.7
|
Markdown>=2.6,<2.7
|
||||||
ipython>=6,<7
|
ipython>=6,<7
|
||||||
mutagen>=1.42,<1.43
|
mutagen>=1.42,<1.43
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from funkwhale_api.music import lyrics as lyrics_utils
|
|
||||||
from funkwhale_api.music import models, tasks
|
|
||||||
|
|
||||||
|
|
||||||
def test_lyrics_tasks(lyricswiki_content, mocker, factories):
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.music.lyrics._get_html", return_value=lyricswiki_content
|
|
||||||
)
|
|
||||||
lyrics = factories["music.Lyrics"](
|
|
||||||
url="http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!"
|
|
||||||
)
|
|
||||||
|
|
||||||
tasks.fetch_content(lyrics_id=lyrics.pk)
|
|
||||||
lyrics.refresh_from_db()
|
|
||||||
assert "Grab a brush and put on a little makeup" in lyrics.content
|
|
||||||
|
|
||||||
|
|
||||||
def test_clean_content():
|
|
||||||
c = """<div class="lyricbox">Hello<br /><script>alert('hello');</script>Is it me you're looking for?<br /></div>"""
|
|
||||||
d = lyrics_utils.extract_content(c)
|
|
||||||
d = lyrics_utils.clean_content(d)
|
|
||||||
|
|
||||||
expected = """Hello
|
|
||||||
Is it me you're looking for?
|
|
||||||
"""
|
|
||||||
assert d == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_markdown_rendering(factories):
|
|
||||||
content = """Hello
|
|
||||||
Is it me you're looking for?"""
|
|
||||||
|
|
||||||
lyrics = factories["music.Lyrics"](content=content)
|
|
||||||
|
|
||||||
expected = "<p>Hello<br />\nIs it me you're looking for?</p>"
|
|
||||||
assert expected == lyrics.content_rendered
|
|
||||||
|
|
||||||
|
|
||||||
def test_works_import_lyrics_if_any(
|
|
||||||
lyricswiki_content, works, tracks, mocker, factories, logged_in_client
|
|
||||||
):
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.musicbrainz.api.works.get",
|
|
||||||
return_value=works["get"]["chop_suey"],
|
|
||||||
)
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.musicbrainz.api.recordings.get",
|
|
||||||
return_value=tracks["get"]["chop_suey"],
|
|
||||||
)
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.music.lyrics._get_html", return_value=lyricswiki_content
|
|
||||||
)
|
|
||||||
track = factories["music.Track"](
|
|
||||||
work=None, mbid="07ca77cf-f513-4e9c-b190-d7e24bbad448"
|
|
||||||
)
|
|
||||||
|
|
||||||
url = reverse("api:v1:tracks-lyrics", kwargs={"pk": track.pk})
|
|
||||||
response = logged_in_client.get(url)
|
|
||||||
|
|
||||||
assert response.status_code == 200
|
|
||||||
|
|
||||||
track.refresh_from_db()
|
|
||||||
lyrics = models.Lyrics.objects.latest("id")
|
|
||||||
work = models.Work.objects.latest("id")
|
|
||||||
|
|
||||||
assert track.work == work
|
|
||||||
assert lyrics.work == work
|
|
|
@ -198,7 +198,6 @@ def test_track_serializer(factories, to_api_date):
|
||||||
"disc_number": track.disc_number,
|
"disc_number": track.disc_number,
|
||||||
"uploads": [serializers.TrackUploadSerializer(upload).data],
|
"uploads": [serializers.TrackUploadSerializer(upload).data],
|
||||||
"creation_date": to_api_date(track.creation_date),
|
"creation_date": to_api_date(track.creation_date),
|
||||||
"lyrics": track.get_lyrics_url(),
|
|
||||||
"listen_url": track.listen_url,
|
"listen_url": track.listen_url,
|
||||||
"license": upload.track.license.code,
|
"license": upload.track.license.code,
|
||||||
"copyright": upload.track.copyright,
|
"copyright": upload.track.copyright,
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
from funkwhale_api.music import models
|
|
||||||
|
|
||||||
|
|
||||||
def test_can_import_work(factories, mocker, works):
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.musicbrainz.api.works.get",
|
|
||||||
return_value=works["get"]["chop_suey"],
|
|
||||||
)
|
|
||||||
recording = factories["music.Track"](mbid="07ca77cf-f513-4e9c-b190-d7e24bbad448")
|
|
||||||
mbid = "e2ecabc4-1b9d-30b2-8f30-3596ec423dc5"
|
|
||||||
work = models.Work.create_from_api(id=mbid)
|
|
||||||
|
|
||||||
assert work.title == "Chop Suey!"
|
|
||||||
assert work.nature == "song"
|
|
||||||
assert work.language == "eng"
|
|
||||||
assert work.mbid == mbid
|
|
||||||
|
|
||||||
# a imported work should also be linked to corresponding recordings
|
|
||||||
|
|
||||||
recording.refresh_from_db()
|
|
||||||
assert recording.work == work
|
|
||||||
|
|
||||||
|
|
||||||
def test_can_get_work_from_recording(factories, mocker, works, tracks):
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.musicbrainz.api.works.get",
|
|
||||||
return_value=works["get"]["chop_suey"],
|
|
||||||
)
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.musicbrainz.api.recordings.get",
|
|
||||||
return_value=tracks["get"]["chop_suey"],
|
|
||||||
)
|
|
||||||
recording = factories["music.Track"](
|
|
||||||
work=None, mbid="07ca77cf-f513-4e9c-b190-d7e24bbad448"
|
|
||||||
)
|
|
||||||
mbid = "e2ecabc4-1b9d-30b2-8f30-3596ec423dc5"
|
|
||||||
|
|
||||||
assert recording.work is None
|
|
||||||
|
|
||||||
work = recording.get_work()
|
|
||||||
|
|
||||||
assert work.title == "Chop Suey!"
|
|
||||||
assert work.nature == "song"
|
|
||||||
assert work.language == "eng"
|
|
||||||
assert work.mbid == mbid
|
|
||||||
|
|
||||||
recording.refresh_from_db()
|
|
||||||
assert recording.work == work
|
|
||||||
|
|
||||||
|
|
||||||
def test_works_import_lyrics_if_any(db, mocker, works):
|
|
||||||
mocker.patch(
|
|
||||||
"funkwhale_api.musicbrainz.api.works.get",
|
|
||||||
return_value=works["get"]["chop_suey"],
|
|
||||||
)
|
|
||||||
mbid = "e2ecabc4-1b9d-30b2-8f30-3596ec423dc5"
|
|
||||||
work = models.Work.create_from_api(id=mbid)
|
|
||||||
|
|
||||||
lyrics = models.Lyrics.objects.latest("id")
|
|
||||||
assert lyrics.work == work
|
|
||||||
assert lyrics.url == "http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!"
|
|
|
@ -0,0 +1 @@
|
||||||
|
Removed broken/instable lyrics feature (#799)
|
|
@ -76,24 +76,6 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
<section class="ui vertical stripe center aligned segment">
|
|
||||||
<h2>
|
|
||||||
<translate translate-context="Content/Track/Title">Lyrics</translate>
|
|
||||||
</h2>
|
|
||||||
<div v-if="isLoadingLyrics" class="ui vertical segment">
|
|
||||||
<div :class="['ui', 'centered', 'active', 'inline', 'loader']"></div>
|
|
||||||
</div>
|
|
||||||
<div v-if="lyrics" v-html="lyrics.content_rendered"></div>
|
|
||||||
<template v-if="!isLoadingLyrics & !lyrics">
|
|
||||||
<p>
|
|
||||||
<translate translate-context="Content/Track/Paragraph">No lyrics available for this track.</translate>
|
|
||||||
</p>
|
|
||||||
<a class="ui button" target="_blank" :href="lyricsSearchUrl">
|
|
||||||
<i class="search icon"></i>
|
|
||||||
<translate translate-context="Content/Track/Link/Verb">Search on lyrics.wikia.com</translate>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</section>
|
|
||||||
<section class="ui vertical stripe segment">
|
<section class="ui vertical stripe segment">
|
||||||
<h2>
|
<h2>
|
||||||
<translate translate-context="Content/*/Title/Noun">User libraries</translate>
|
<translate translate-context="Content/*/Title/Noun">User libraries</translate>
|
||||||
|
@ -123,13 +105,10 @@ export default {
|
||||||
return {
|
return {
|
||||||
time,
|
time,
|
||||||
id: this.track.id,
|
id: this.track.id,
|
||||||
isLoadingLyrics: true,
|
|
||||||
lyrics: null,
|
|
||||||
licenseData: null
|
licenseData: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.fetchLyrics()
|
|
||||||
if (this.track && this.track.license) {
|
if (this.track && this.track.license) {
|
||||||
this.fetchLicenseData(this.track.license)
|
this.fetchLicenseData(this.track.license)
|
||||||
}
|
}
|
||||||
|
@ -142,22 +121,6 @@ export default {
|
||||||
self.licenseData = response.data
|
self.licenseData = response.data
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchLyrics() {
|
|
||||||
var self = this
|
|
||||||
this.isLoadingLyrics = true
|
|
||||||
let url = FETCH_URL + this.id + "/lyrics/"
|
|
||||||
logger.default.debug('Fetching lyrics for track "' + this.id + '"')
|
|
||||||
axios.get(url).then(
|
|
||||||
response => {
|
|
||||||
self.lyrics = response.data
|
|
||||||
self.isLoadingLyrics = false
|
|
||||||
},
|
|
||||||
response => {
|
|
||||||
console.error("No lyrics available")
|
|
||||||
self.isLoadingLyrics = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
labels() {
|
labels() {
|
||||||
|
@ -170,11 +133,6 @@ export default {
|
||||||
return this.track.uploads[0]
|
return this.track.uploads[0]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
lyricsSearchUrl() {
|
|
||||||
let base = "http://lyrics.wikia.com/wiki/Special:Search?query="
|
|
||||||
let query = this.track.artist.name + ":" + this.track.title
|
|
||||||
return base + encodeURI(query)
|
|
||||||
},
|
|
||||||
license() {
|
license() {
|
||||||
if (!this.track || !this.track.license) {
|
if (!this.track || !this.track.license) {
|
||||||
return null
|
return null
|
||||||
|
|
Loading…
Reference in New Issue