Commit fd1ce6ef authored by Eliot Berriot's avatar Eliot Berriot

Merge branch '507-disc-number' into 'develop'

Resolve "Track position don't take care about disc number"

Closes #507

See merge request !486
parents 16aef2e5 a493d34b
Pipeline #2621 passed with stages
in 8 minutes and 42 seconds
......@@ -729,6 +729,7 @@ class AlbumSerializer(MusicEntitySerializer):
class TrackSerializer(MusicEntitySerializer):
position = serializers.IntegerField(min_value=0, allow_null=True, required=False)
disc = serializers.IntegerField(min_value=1, allow_null=True, required=False)
artists = serializers.ListField(child=ArtistSerializer(), min_length=1)
album = AlbumSerializer()
license = serializers.URLField(allow_null=True, required=False)
......@@ -742,6 +743,7 @@ class TrackSerializer(MusicEntitySerializer):
"published": instance.creation_date.isoformat(),
"musicbrainzId": str(instance.mbid) if instance.mbid else None,
"position": instance.position,
"disc": instance.disc_number,
"license": instance.local_license["identifiers"][0]
if instance.local_license
else None,
......
......@@ -92,7 +92,7 @@ def get_mp3_recording_id(f, k):
raise TagNotFound(k)
def convert_track_number(v):
def convert_position(v):
try:
return int(v)
except ValueError:
......@@ -156,8 +156,9 @@ CONF = {
"fields": {
"track_number": {
"field": "TRACKNUMBER",
"to_application": convert_track_number,
"to_application": convert_position,
},
"disc_number": {"field": "DISCNUMBER", "to_application": convert_position},
"title": {},
"artist": {},
"album_artist": {
......@@ -179,8 +180,9 @@ CONF = {
"fields": {
"track_number": {
"field": "TRACKNUMBER",
"to_application": convert_track_number,
"to_application": convert_position,
},
"disc_number": {"field": "DISCNUMBER", "to_application": convert_position},
"title": {},
"artist": {},
"album_artist": {
......@@ -202,8 +204,9 @@ CONF = {
"fields": {
"track_number": {
"field": "TRACKNUMBER",
"to_application": convert_track_number,
"to_application": convert_position,
},
"disc_number": {"field": "DISCNUMBER", "to_application": convert_position},
"title": {},
"artist": {},
"album_artist": {"field": "albumartist"},
......@@ -222,7 +225,8 @@ CONF = {
"getter": get_id3_tag,
"clean_pictures": clean_id3_pictures,
"fields": {
"track_number": {"field": "TRCK", "to_application": convert_track_number},
"track_number": {"field": "TRCK", "to_application": convert_position},
"disc_number": {"field": "TPOS", "to_application": convert_position},
"title": {"field": "TIT2"},
"artist": {"field": "TPE1"},
"album_artist": {"field": "TPE2"},
......@@ -246,8 +250,9 @@ CONF = {
"fields": {
"track_number": {
"field": "tracknumber",
"to_application": convert_track_number,
"to_application": convert_position,
},
"disc_number": {"field": "discnumber", "to_application": convert_position},
"title": {},
"artist": {},
"album_artist": {"field": "albumartist"},
......@@ -267,6 +272,7 @@ CONF = {
ALL_FIELDS = [
"track_number",
"disc_number",
"title",
"artist",
"album_artist",
......
# Generated by Django 2.0.9 on 2018-12-04 15:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('music', '0035_auto_20181203_1515'),
]
operations = [
migrations.AddField(
model_name='track',
name='disc_number',
field=models.PositiveIntegerField(blank=True, null=True),
),
]
......@@ -440,6 +440,12 @@ class TrackQuerySet(models.QuerySet):
models.Prefetch("uploads", queryset=uploads, to_attr="playable_uploads")
)
def order_for_album(self):
"""
Order by disc number then position
"""
return self.order_by("disc_number", "position", "title")
def get_artist(release_list):
return Artist.get_or_create_from_api(
......@@ -450,6 +456,7 @@ def get_artist(release_list):
class Track(APIModelMixin):
title = models.CharField(max_length=255)
artist = models.ForeignKey(Artist, related_name="tracks", on_delete=models.CASCADE)
disc_number = models.PositiveIntegerField(null=True, blank=True)
position = models.PositiveIntegerField(null=True, blank=True)
album = models.ForeignKey(
Album, related_name="tracks", null=True, blank=True, on_delete=models.CASCADE
......@@ -485,7 +492,7 @@ class Track(APIModelMixin):
tags = TaggableManager(blank=True)
class Meta:
ordering = ["album", "position"]
ordering = ["album", "disc_number", "position"]
def __str__(self):
return self.title
......
......@@ -88,6 +88,7 @@ class AlbumTrackSerializer(serializers.ModelSerializer):
"artist",
"creation_date",
"position",
"disc_number",
"uploads",
"listen_url",
"duration",
......@@ -130,10 +131,7 @@ class AlbumSerializer(serializers.ModelSerializer):
)
def get_tracks(self, o):
ordered_tracks = sorted(
o.tracks.all(),
key=lambda v: (v.position, v.title) if v.position else (99999, v.title),
)
ordered_tracks = o.tracks.all()
return AlbumTrackSerializer(ordered_tracks, many=True).data
def get_is_playable(self, obj):
......@@ -193,6 +191,7 @@ class TrackSerializer(serializers.ModelSerializer):
"artist",
"creation_date",
"position",
"disc_number",
"lyrics",
"uploads",
"listen_url",
......
......@@ -274,6 +274,7 @@ def federation_audio_track_to_metadata(payload):
"title": payload["name"],
"album": payload["album"]["name"],
"track_number": payload["position"],
"disc_number": payload.get("disc"),
"artist": payload["artists"][0]["name"],
"album_artist": payload["album"]["artists"][0]["name"],
"date": payload["album"].get("released"),
......@@ -497,6 +498,7 @@ def get_track_from_import_metadata(data):
"mbid": track_mbid,
"artist": artist,
"position": track_number,
"disc_number": data.get("disc_number"),
"fid": track_fid,
"from_activity_id": from_activity_id,
"license": licenses.match(data.get("license"), data.get("copyright")),
......
......@@ -93,8 +93,10 @@ class AlbumViewSet(viewsets.ReadOnlyModelViewSet):
def get_queryset(self):
queryset = super().get_queryset()
tracks = models.Track.objects.select_related("artist").with_playable_uploads(
utils.get_actor_from_request(self.request)
tracks = (
models.Track.objects.select_related("artist")
.with_playable_uploads(utils.get_actor_from_request(self.request))
.order_for_album()
)
qs = queryset.prefetch_related(Prefetch("tracks", queryset=tracks))
return qs.distinct()
......
......@@ -632,7 +632,9 @@ def test_activity_pub_album_serializer_to_ap(factories):
def test_activity_pub_track_serializer_to_ap(factories):
track = factories["music.Track"](license="cc-by-4.0", copyright="test")
track = factories["music.Track"](
license="cc-by-4.0", copyright="test", disc_number=3
)
expected = {
"@context": serializers.AP_CONTEXT,
"published": track.creation_date.isoformat(),
......@@ -641,6 +643,7 @@ def test_activity_pub_track_serializer_to_ap(factories):
"id": track.fid,
"name": track.title,
"position": track.position,
"disc": track.disc_number,
"license": track.license.conf["identifiers"][0],
"copyright": "test",
"artists": [
......@@ -668,6 +671,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock):
"musicbrainzId": str(uuid.uuid4()),
"name": "Black in back",
"position": 5,
"disc": 1,
"album": {
"type": "Album",
"id": "http://hello.album",
......@@ -713,6 +717,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock):
assert track.fid == data["id"]
assert track.title == data["name"]
assert track.position == data["position"]
assert track.disc_number == data["disc"]
assert track.creation_date == published
assert str(track.mbid) == data["musicbrainzId"]
......
......@@ -20,6 +20,7 @@ def test_get_all_metadata_at_once():
"album": "Peer Gynt Suite no. 1, op. 46",
"date": datetime.date(2012, 8, 15),
"track_number": 1,
"disc_number": 1,
"musicbrainz_albumid": uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75"),
"musicbrainz_recordingid": uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656"),
"musicbrainz_artistid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
......@@ -40,6 +41,7 @@ def test_get_all_metadata_at_once():
("album", "Peer Gynt Suite no. 1, op. 46"),
("date", datetime.date(2012, 8, 15)),
("track_number", 1),
("disc_number", 1),
("musicbrainz_albumid", uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75")),
("musicbrainz_recordingid", uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656")),
("musicbrainz_artistid", uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823")),
......@@ -67,6 +69,7 @@ def test_can_get_metadata_from_ogg_file(field, value):
("album", "Peer Gynt Suite no. 1, op. 46"),
("date", datetime.date(2012, 8, 15)),
("track_number", 1),
("disc_number", 1),
("musicbrainz_albumid", uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75")),
("musicbrainz_recordingid", uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656")),
("musicbrainz_artistid", uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823")),
......@@ -94,6 +97,7 @@ def test_can_get_metadata_from_opus_file(field, value):
("album", "Ballast der Republik"),
("date", datetime.date(2012, 5, 4)),
("track_number", 1),
("disc_number", 1),
("musicbrainz_albumid", uuid.UUID("1f0441ad-e609-446d-b355-809c445773cf")),
("musicbrainz_recordingid", uuid.UUID("124d0150-8627-46bc-bc14-789a3bc960c8")),
("musicbrainz_artistid", uuid.UUID("c3bc80a6-1f4a-4e17-8cf0-6b1efe8302f1")),
......@@ -122,6 +126,7 @@ def test_can_get_metadata_from_ogg_theora_file(field, value):
("album", "You Can't Stop Da Funk"),
("date", datetime.date(2006, 2, 7)),
("track_number", 2),
("disc_number", 1),
("musicbrainz_albumid", uuid.UUID("ce40cdb1-a562-4fd8-a269-9269f98d4124")),
("musicbrainz_recordingid", uuid.UUID("f269d497-1cc0-4ae4-a0c4-157ec7d73fcb")),
("musicbrainz_artistid", uuid.UUID("9c6bddde-6228-4d9f-ad0d-03f6fcb19e13")),
......@@ -163,6 +168,7 @@ def test_can_get_pictures(name):
("album", "The Slip"),
("date", datetime.date(2008, 5, 5)),
("track_number", 1),
("disc_number", 1),
("musicbrainz_albumid", uuid.UUID("12b57d46-a192-499e-a91f-7da66790a1c1")),
("musicbrainz_recordingid", uuid.UUID("30f3f33e-8d0c-4e69-8539-cbd701d18f28")),
("musicbrainz_artistid", uuid.UUID("b7ffd2af-418f-4be2-bdd1-22f8b48613da")),
......
......@@ -512,3 +512,13 @@ def test_can_create_license(db):
redistribute=True,
url="http://cc",
)
def test_track_order_for_album(factories):
album = factories["music.Album"]()
t1 = factories["music.Track"](album=album, position=1, disc_number=1)
t2 = factories["music.Track"](album=album, position=1, disc_number=2)
t3 = factories["music.Track"](album=album, position=2, disc_number=1)
t4 = factories["music.Track"](album=album, position=2, disc_number=2)
assert list(models.Track.objects.order_for_album()) == [t1, t3, t2, t4]
......@@ -72,7 +72,7 @@ def test_artist_with_albums_serializer(factories, to_api_date):
def test_album_track_serializer(factories, to_api_date):
upload = factories["music.Upload"](
track__license="cc-by-4.0", track__copyright="test"
track__license="cc-by-4.0", track__copyright="test", track__disc_number=2
)
track = upload.track
setattr(track, "playable_uploads", [upload])
......@@ -84,6 +84,7 @@ def test_album_track_serializer(factories, to_api_date):
"mbid": str(track.mbid),
"title": track.title,
"position": track.position,
"disc_number": track.disc_number,
"uploads": [serializers.TrackUploadSerializer(upload).data],
"creation_date": to_api_date(track.creation_date),
"listen_url": track.listen_url,
......@@ -174,7 +175,7 @@ def test_album_serializer(factories, to_api_date):
def test_track_serializer(factories, to_api_date):
upload = factories["music.Upload"](
track__license="cc-by-4.0", track__copyright="test"
track__license="cc-by-4.0", track__copyright="test", track__disc_number=2
)
track = upload.track
setattr(track, "playable_uploads", [upload])
......@@ -185,6 +186,7 @@ def test_track_serializer(factories, to_api_date):
"mbid": str(track.mbid),
"title": track.title,
"position": track.position,
"disc_number": track.disc_number,
"uploads": [serializers.TrackUploadSerializer(upload).data],
"creation_date": to_api_date(track.creation_date),
"lyrics": track.get_lyrics_url(),
......
......@@ -23,6 +23,7 @@ def test_can_create_track_from_file_metadata_no_mbid(db, mocker):
"album": "Test album",
"date": datetime.date(2012, 8, 15),
"track_number": 4,
"disc_number": 2,
"license": "Hello world: http://creativecommons.org/licenses/by-sa/4.0/",
"copyright": "2018 Someone",
}
......@@ -34,6 +35,7 @@ def test_can_create_track_from_file_metadata_no_mbid(db, mocker):
assert track.title == metadata["title"]
assert track.mbid is None
assert track.position == 4
assert track.disc_number == 2
assert track.license.code == "cc-by-sa-4.0"
assert track.copyright == metadata["copyright"]
assert track.album.title == metadata["album"]
......@@ -66,6 +68,7 @@ def test_can_create_track_from_file_metadata_mbid(factories, mocker):
assert track.title == metadata["title"]
assert track.mbid == metadata["musicbrainz_recordingid"]
assert track.position == 4
assert track.disc_number is None
assert track.album.title == metadata["album"]
assert track.album.mbid == metadata["musicbrainz_albumid"]
assert track.album.artist.mbid == metadata["musicbrainz_albumartistid"]
......@@ -402,6 +405,7 @@ def test_federation_audio_track_to_metadata(now):
"musicbrainzId": str(uuid.uuid4()),
"name": "Black in back",
"position": 5,
"disc": 2,
"published": published.isoformat(),
"license": "http://creativecommons.org/licenses/by-sa/4.0/",
"copyright": "2018 Someone",
......@@ -441,6 +445,7 @@ def test_federation_audio_track_to_metadata(now):
"title": payload["name"],
"date": released,
"track_number": payload["position"],
"disc_number": payload["disc"],
"license": "http://creativecommons.org/licenses/by-sa/4.0/",
"copyright": "2018 Someone",
# musicbrainz
......
Store disc number and order tracks by disc number / position) (#507)
\ No newline at end of file
......@@ -29,7 +29,7 @@ services:
env_file:
- .env.dev
- .env
image: postgres
image: postgres:9.6
command: postgres -c log_min_duration_statement=0
volumes:
- "./data/${COMPOSE_PROJECT_NAME-node1}/postgres:/var/lib/postgresql/data"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment