From 0f6f0391fd4ae82fe0ff52820cb3fb96023ab2cb Mon Sep 17 00:00:00 2001 From: Rawrmonkeys Date: Sun, 25 Mar 2018 18:58:04 -0700 Subject: [PATCH 1/6] add tag, database entry, data population for musicbrainz release track id --- beets/autotag/__init__.py | 2 ++ beets/autotag/hooks.py | 5 ++++- beets/autotag/mb.py | 1 + beets/library.py | 1 + beets/mediafile.py | 6 ++++++ docs/reference/pathformat.rst | 1 + test/_common.py | 1 + 7 files changed, 16 insertions(+), 1 deletion(-) diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 4c5f09eb4..24f2ebfc0 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -40,6 +40,7 @@ def apply_item_metadata(item, track_info): item.artist_credit = track_info.artist_credit item.title = track_info.title item.mb_trackid = track_info.track_id + item.mb_releasetrackid = track_info.release_track_id if track_info.artist_id: item.mb_artistid = track_info.artist_id if track_info.data_source: @@ -122,6 +123,7 @@ def apply_metadata(album_info, mapping): # MusicBrainz IDs. item.mb_trackid = track_info.track_id + item.mb_releasetrackid = track_info.release_track_id item.mb_albumid = album_info.album_id if track_info.artist_id: item.mb_artistid = track_info.artist_id diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index 053d050c6..cc5f37003 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -129,6 +129,8 @@ class TrackInfo(object): - ``title``: name of the track - ``track_id``: MusicBrainz ID; UUID fragment only + - ``release_track_id``: MusicBrainz ID respective to a track on a + particular release; UUID fragment only - ``artist``: individual track artist name - ``artist_id`` - ``length``: float: duration of the track in seconds @@ -152,7 +154,7 @@ class TrackInfo(object): may be None. The indices ``index``, ``medium``, and ``medium_index`` are all 1-based. """ - def __init__(self, title, track_id, artist=None, artist_id=None, + def __init__(self, title, track_id, release_track_id=None, artist=None, artist_id=None, length=None, index=None, medium=None, medium_index=None, medium_total=None, artist_sort=None, disctitle=None, artist_credit=None, data_source=None, data_url=None, @@ -160,6 +162,7 @@ class TrackInfo(object): arranger=None, track_alt=None): self.title = title self.track_id = track_id + self.release_track_id = release_track_id self.artist = artist self.artist_id = artist_id self.length = length diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py index 9ce449a8b..049b70909 100644 --- a/beets/autotag/mb.py +++ b/beets/autotag/mb.py @@ -304,6 +304,7 @@ def album_info(release): int(track['position']), len(medium['track-list']), ) + ti.release_track_id = track['id'] ti.disctitle = disctitle ti.media = format ti.track_alt = track['number'] diff --git a/beets/library.py b/beets/library.py index 64035e642..ba57407d0 100644 --- a/beets/library.py +++ b/beets/library.py @@ -455,6 +455,7 @@ class Item(LibModel): 'mb_albumid': types.STRING, 'mb_artistid': types.STRING, 'mb_albumartistid': types.STRING, + 'mb_releasetrackid': types.STRING, 'albumtype': types.STRING, 'label': types.STRING, 'acoustid_fingerprint': types.STRING, diff --git a/beets/mediafile.py b/beets/mediafile.py index 34ad49af7..32a32fe1d 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -1865,6 +1865,12 @@ class MediaFile(object): StorageStyle('MUSICBRAINZ_TRACKID'), ASFStorageStyle('MusicBrainz/Track Id'), ) + mb_releasetrackid = MediaField( + MP3DescStorageStyle(u'MusicBrainz Release Track Id'), + MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Release Track Id'), + StorageStyle('MUSICBRAINZ_RELEASETRACKID'), + ASFStorageStyle('MusicBrainz/Release Track Id'), + ) mb_albumid = MediaField( MP3DescStorageStyle(u'MusicBrainz Album Id'), MP4StorageStyle('----:com.apple.iTunes:MusicBrainz Album Id'), diff --git a/docs/reference/pathformat.rst b/docs/reference/pathformat.rst index 667be3150..72907b6df 100644 --- a/docs/reference/pathformat.rst +++ b/docs/reference/pathformat.rst @@ -239,6 +239,7 @@ Audio information: MusicBrainz and fingerprint information: * mb_trackid +* mb_releasetrackid * mb_albumid * mb_artistid * mb_albumartistid diff --git a/test/_common.py b/test/_common.py index fc7b650b3..f5e65ca76 100644 --- a/test/_common.py +++ b/test/_common.py @@ -89,6 +89,7 @@ def item(lib=None): mb_albumid='someID-2', mb_artistid='someID-3', mb_albumartistid='someID-4', + mb_releasetrackid='someID-5', album_id=None, mtime=12345, ) From f74899ab9af4427fc87e6535fffeb0c85329ad65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Detrey?= Date: Mon, 30 Apr 2018 18:26:06 +0200 Subject: [PATCH 2/6] Fix errors due to missing track['id'] in unit tests. --- test/test_importer.py | 1 + test/test_mb.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/test/test_importer.py b/test/test_importer.py index e30f5609c..6721f0dc2 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -1819,6 +1819,7 @@ def mocked_get_release_by_id(id_, includes=[], release_status=[], 'id': id_, 'medium-list': [{ 'track-list': [{ + 'id': 'baz', 'recording': { 'title': 'foo', 'id': 'bar', diff --git a/test/test_mb.py b/test/test_mb.py index 55df22944..b61ebe59a 100644 --- a/test/test_mb.py +++ b/test/test_mb.py @@ -63,12 +63,15 @@ class MBAlbumInfoTest(_common.TestCase): 'country': 'COUNTRY', 'status': 'STATUS', } + i = 0 track_list = [] if tracks: - for i, recording in enumerate(tracks): + for recording in tracks: + i += 1 track = { + 'id': 'RELEASE TRACK ID %d' % i, 'recording': recording, - 'position': i + 1, + 'position': i, 'number': 'A1', } if track_length: @@ -90,10 +93,12 @@ class MBAlbumInfoTest(_common.TestCase): track_list.append(track) data_track_list = [] if data_tracks: - for i, recording in enumerate(data_tracks): + for recording in data_tracks: + i += 1 data_track = { + 'id': 'RELEASE TRACK ID %d' % i, 'recording': recording, - 'position': len(track_list) + i + 1, + 'position': i, 'number': 'A1', } data_track_list.append(data_track) @@ -194,6 +199,7 @@ class MBAlbumInfoTest(_common.TestCase): self._make_track('TITLE TWO', 'ID TWO', 200.0 * 1000.0)] release = self._make_release(tracks=[tracks[0]]) second_track_list = [{ + 'id': 'RELEASE TRACK ID 2', 'recording': tracks[1], 'position': '1', 'number': 'A1', @@ -551,6 +557,7 @@ class MBLibraryTest(unittest.TestCase): 'id': mbid, 'medium-list': [{ 'track-list': [{ + 'id': 'baz', 'recording': { 'title': 'foo', 'id': 'bar', From 9f4c5c8096832fdf1f289e0843250e3758ce05fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Detrey?= Date: Mon, 30 Apr 2018 18:26:46 +0200 Subject: [PATCH 3/6] Do not rely on positional arguments for TrackInfo. --- beetsplug/discogs.py | 7 ++++--- test/test_autotag.py | 14 +++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/beetsplug/discogs.py b/beetsplug/discogs.py index 82c79a023..0e9d7c229 100644 --- a/beetsplug/discogs.py +++ b/beetsplug/discogs.py @@ -474,9 +474,10 @@ class DiscogsPlugin(BeetsPlugin): medium, medium_index, _ = self.get_track_index(track['position']) artist, artist_id = self.get_artist(track.get('artists', [])) length = self.get_track_length(track['duration']) - return TrackInfo(title, track_id, artist, artist_id, length, index, - medium, medium_index, artist_sort=None, - disctitle=None, artist_credit=None) + return TrackInfo(title, track_id, artist=artist, artist_id=artist_id, + length=length, index=index, + medium=medium, medium_index=medium_index, + artist_sort=None, disctitle=None, artist_credit=None) def get_track_index(self, position): """Returns the medium, medium index and subtrack index for a discogs diff --git a/test/test_autotag.py b/test/test_autotag.py index 932616be1..244e48ecc 100644 --- a/test/test_autotag.py +++ b/test/test_autotag.py @@ -103,9 +103,9 @@ def _make_item(title, track, artist=u'some artist'): def _make_trackinfo(): return [ - TrackInfo(u'one', None, u'some artist', length=1, index=1), - TrackInfo(u'two', None, u'some artist', length=1, index=2), - TrackInfo(u'three', None, u'some artist', length=1, index=3), + TrackInfo(u'one', None, artist=u'some artist', length=1, index=1), + TrackInfo(u'two', None, artist=u'some artist', length=1, index=2), + TrackInfo(u'three', None, artist=u'some artist', length=1, index=3), ] @@ -827,15 +827,15 @@ class ApplyCompilationTest(_common.TestCase, ApplyTestUtil): trackinfo.append(TrackInfo( u'oneNew', u'dfa939ec-118c-4d0f-84a0-60f3d1e6522c', - u'artistOneNew', - u'a05686fc-9db2-4c23-b99e-77f5db3e5282', + artist=u'artistOneNew', + artist_id=u'a05686fc-9db2-4c23-b99e-77f5db3e5282', index=1, )) trackinfo.append(TrackInfo( u'twoNew', u'40130ed1-a27c-42fd-a328-1ebefb6caef4', - u'artistTwoNew', - u'80b3cf5e-18fe-4c59-98c7-e5bb87210710', + artist=u'artistTwoNew', + artist_id=u'80b3cf5e-18fe-4c59-98c7-e5bb87210710', index=2, )) self.info = AlbumInfo( From f01799207a11fc71ca1287b20be3a2718c98bcee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Detrey?= Date: Tue, 1 May 2018 08:37:34 +0200 Subject: [PATCH 4/6] Add `mb_releasetrackid` tag to full.* media files. --- test/rsrc/full.aiff | Bin 89296 -> 89296 bytes test/rsrc/full.alac.m4a | Bin 6884 -> 6884 bytes test/rsrc/full.ape | Bin 14005 -> 14076 bytes test/rsrc/full.dsf | Bin 113475 -> 114582 bytes test/rsrc/full.flac | Bin 21890 -> 21890 bytes test/rsrc/full.m4a | Bin 5862 -> 5862 bytes test/rsrc/full.mp3 | Bin 12820 -> 12820 bytes test/rsrc/full.mpc | Bin 2949 -> 3020 bytes test/rsrc/full.ogg | Bin 9073 -> 10176 bytes test/rsrc/full.opus | Bin 7248 -> 8349 bytes test/rsrc/full.wma | Bin 25540 -> 26883 bytes test/rsrc/full.wv | Bin 13593 -> 13664 bytes test/test_mediafile.py | 56 +++++++++++++++++++++------------------- 13 files changed, 29 insertions(+), 27 deletions(-) diff --git a/test/rsrc/full.aiff b/test/rsrc/full.aiff index 5d791b0b7dc4cf1805d83f34929f7c1a05a2f275..e9606f9e74ee1a50d1cca3a4ca4ce7ab51575a58 100644 GIT binary patch delta 245 zcmcbxll8(*)`l&Nev#AfL^4V{2ZTB?Ffed4Fff;7q$=bjCZ*;uggE>A0tNY?g30;0 z1^LCPMGPUHA%;le=|%aa1(|v2(|My9r6faxeL{ee0zgebiUDj|Wl?5w@pRuvM%n51 zQ9!~!no)GRU^JuD^w4NVi|JO;jMCHVq8XK^7eq0-PG1-eB(_E|`noy;4e>24&P;YH zO3ciwQV2@TNlh$HRR}3cOwLyDOkqeivP?5hG&R>vGBLK)H8D#|(M>c;HPW>-Ha9m* VGBh?fOf{IE8Oc~YohgQ~831D3L=FG| delta 161 zcmcbxll8(*)`l&Nev#83L^8@uza7n3G~F+fQF?k^B%{RibwENq#52T@fq{XKfq}Us zBUK^2D8IBIGcSGm??^^D;eb#lpd2?;E+;W5HD~(XC`PyG9?^`x(>7f%n2VXU8?5W^S*0O-9h A1^@s6 diff --git a/test/rsrc/full.alac.m4a b/test/rsrc/full.alac.m4a index 8ec7d377c37176e1b7e98f469eb2801f5e375323..6bfcf317e395c5fe92231ef4decba8088f8f9dd7 100644 GIT binary patch delta 155 zcmaE2`owg@ZYIXroA)r4F;2E+Tfo>b*^gB@LL)CRHLu* z6N^(7LW&ZTvlTp3fYK%@i6x0Znh~Tn*~l`@IMLKxH_61U(%9VG zEXmN=+%R?X1(saK$#>b(CmXRWn(V@^G`Wx6eR3+h1{=%fw4&71%@5hvvTWwyy~7It Dl;$s3 delta 70 zcmV-M0J;Ct<8 diff --git a/test/rsrc/full.ape b/test/rsrc/full.ape index 5bcea98e86f05f90310f46b45d5e2c6931912a8b..e1667505c4665289c78e88f20b84729524dcbd45 100644 GIT binary patch delta 252 zcmdm*`zLpUg$e5hCI$wv$+jlOqArdht_(&728JvQ5D@9=7&N)n#E8emGuYWL)Yr*1 zh{0s?dJ~z+_f2%{-Cg~HTp3C-QWeru^NLbAp_+0MlTvfQ!eAB`RM;^n#4|VqES^|Y zl383b+0aySa{CMOjoX69AJ7p3N;CKjib6eT8S zXQnVD8(F3qCz_h;CYcyp>YA9PrRXLar5fp48k?J&B^er<8>SjK2DpYey1PbPU}sah=?1V#E^?C&{T4AvT5sN4Kv5dFHP+yXPD_KI0m?eIJ&z=TwrHl06Pq#y8&tl0|3f4ER+BM diff --git a/test/rsrc/full.dsf b/test/rsrc/full.dsf index a90e6946fc44cd97a56c9846cbea855201a22808..f13ea694b71e010c1099b0a5afa110aa851c63fa 100644 GIT binary patch delta 412 zcmYk1&rZTX5XNVN_98aMiyl1m1seJX+BDIF6c0oy4J@YDZCS9P6tZm(dLh09eGNUB zC>}icPF{5yAz`zZ-#6cUGxPl;t$!uCGwdiA@c-6d&+?m0?mt#_jdrPlssvD*6iEWq zztNHF$oT_Tn8@QS2Rd+XQ9VS}XqZ5+du_y{ohb>6Id=AkTTipm0@@k4h*hwmX*y81 zf4A2&<*DE+pl#nnwT9n9i|20v{r+fwM#4gl+qwP9E^h}%i}`YqaRGQmwe?P)ibb)E z(`{vemF@I%?CJj8$fELv>8swnE*s Kb*{ZKa_|QOB4BF( delta 330 zcmbRCpY8BBHa?eN7X=vx2your$hVb`F>Gf&b8Lubh!Iefm4Sgdtu!YmB*4`W$mIrd zOEOXw5{pVQi%UWreVl-TTrk0$q|)4wAZKr&7zJ`$9@=FUc^U_0{{XuG=;tI+6xdr*fsYO6xKcFzo z=JeFOqSO#)-vFp_h9Lo=$S%uCOiIlGnglXR5NJheUOEHF8$jc7Q}arSLxX)nfKvQ0 sDNdkVPGwPMa`E(iyBK{Kt*3MEX0+u9iHL{*Dzlp2xQo%26Uc%90O;IFhX4Qo diff --git a/test/rsrc/full.flac b/test/rsrc/full.flac index abc18ac300bdc4d525ef3e983f0033022cd0dbed..e2d4f9bb4622fff0106f87b244b0014d17a3dd8e 100644 GIT binary patch delta 101 zcmZo#&DgY>ae_1Bgo!RHjFKBOHJIG(85kIHON%p;lZp~E^Qz*DQgc!hi&IOA5|gtt zQ*4usEYpk=P0e+aOpGmcP0Z3#bQ6tIjdU%I&CSh{42{hVQwae_0W??e|BMv0A?8cZyW46?U3KV<5co&15xXLEsqkSPHARt)X{ diff --git a/test/rsrc/full.m4a b/test/rsrc/full.m4a index 6105250e6c74f9c4670203f1039b9bd48edf4b33..2ec831e328c8dec15994a9e0a2daa7944958c973 100644 GIT binary patch delta 169 zcmaE+`%HI(FEbMx<7R*6cE-tb*%vT2OkT&P9HEhyn48J~1iq!knaNH?iJ5s-3PGtk zsfop@3L!;_$=M2?DL`qHl*E!mAk7F;n`~s6W}IkhuA5|HY^iHvmX@NMXq0NCYiVq5 zZkA+dY;Ksk*?=vVk#P~oj>&Uac{j7O>M~BY~V~Ym6HqDls8MUxiT{PftZtjvD8f7%b~=nk?0r{ r!oa|wF!>;}D7!*pQAuWT$>cj6UQEpQHV1IVFi$SvY}mYp$BGL8$`2cY diff --git a/test/rsrc/full.mp3 b/test/rsrc/full.mp3 index 9aeca5fb36eaf32acced04005fb8b5417300ccc0..d8c638f9c426b1af8033e80ff286a1d3e6cab80a 100644 GIT binary patch delta 243 zcmbP|G9_g~r>;|gF9QPuGZ33GggE;KKskmCApxOIKn^!hvLqu_Atx~@HD~e%Mk!Cv z5JR9i9}t7Y(~I&;3o`T48A4qBoPlEeK%5y;nwMIvP-d=Yrf0<9?C%S*LI8+U^U^_b z0q%|g3jp$L_`Eo9nc_V-_qjDWT&FU%)Bavpwyhy z#Nt$ikfOxoYz5C0hGZklG~+~5bKN8pV@q8Vv$Pc5M59zAT}xwgbF(BvV{^k)gUPIn U#gl88dNw;TZ)e$T$8k*)09p1vNB{r; delta 131 zcmbP|G9_g~=j88 z%W<+Lw@$hW0|exj7H1|W6(wfoRmB&j=A^%km delta 157 zcmX>j-YULf0SD_vCI$xS$xAs@CST{^n|zW(X!1)A>B*v;f|FT*SdG(SauKHnPfBKS za$ad}Qfd){$>d3#M*Qxnc}1xVB^jv-=^)nRJ)H8BKXHl+=2RACCKrPxAk4{(T#}QG qxmqXx;BuV2lgoax1-Gt(V}NUjqq}Rw1$G7oumc#tpaDWLFaQ8_lP!$^ diff --git a/test/rsrc/full.ogg b/test/rsrc/full.ogg index d2598d0021109bf2e962d82ff6bda9650a5dd9f5..54e1d71eb8474999106eec67423308c4e245f686 100644 GIT binary patch delta 169 zcmez9cEEo^0MCxrdwQb(!Juzqgc+m6#(rTYXL|+)hTPKP%;cn^#LT>^_@dOD)WqV{ zlA^@q?93F~WFyNo<3v+)-6RuZOI;JQv=rS$qf{eZOJj3$vm`@fbHh}F$%3MalMR#| NDZrAO7c-qx007jkII#c# delta 31 ncmX@$|Iuwi0LP|n7uf~>|F@qQW5y`Hak4NIBje^zZ08gJ<6aEx diff --git a/test/rsrc/full.opus b/test/rsrc/full.opus index 9a5534b2215ddf17f1ff9c67b97d5c1ffde630f6..2fb362c2fe05ee4ab33a5b05a2776c22e6554eb3 100644 GIT binary patch delta 1139 zcmca$G1qZ|E6>GR)-~+^!C>!1Ul~TJjah+A_4W)547sJnnaN2-iJ5s-@kOaQsfop@ zB}IwJ*_kP}$wroG#)+opx=AL+mbxZpX(_siMyW=+md57hW=V#|=7y;TKoiIY^b{@sS}Rmnlc*x=+OD9-=@ delta 29 lcmbR1c)?5qoje_rqaH&^McE6GOS`qI+t^lj{ywWH%clpa!%ub@KiQCGv=~0T221V zBFP`bkjjt)#EA^WKvH4yTxN0aWCkM!ONKNCW1y%hgE@mPLlT1tkY@>GnJ}0EWm15w zM4+lvAl3zn8v|9D17(sJ48d$epo{^~HnYisT#~#&46Y15KIp0`(as&{! z0r56tK}jwK2*{}{%1kb1D9K1wfG{^7H#TBSSAk0BmKJ9wClw`T=2gWPrRJn27N?dJ zB_?NQrZ6NMS*95$nwsk-nHXE@nwX`f=q4Ja8tGaZo12>@85)}#rW!Z~xP~~oyGC4K PXJ7!k5n^lu)N}>_^}93Q delta 121 zcmaEmH8X32i4p5XCI$xS$(Ba(lUEuEPM!h8yNoO*vl(kl{$wOFSc z1LAGQf|6Ve5Rh0@l385BP?C|V0AX%EZfwM;;27W<;^^)gae Date: Wed, 2 May 2018 09:21:03 +0200 Subject: [PATCH 5/6] Add support for `musicbrainz_releasetrackid` to changelog. --- docs/changelog.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 8b49b97a1..86d4810d3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -28,6 +28,9 @@ New features: ``mb_releasegroupid`` as well as simulates track ids using release id and tracklist positions. Track ids are stored in ``mb_trackid``. :bug:`#2336` Thanks to :user:`dbogdanov`. +* As a first step to get :bug:`#406` implemented, beets now imports the + ``musicbrainz_releasetrackid`` field into the library and tags media files + accordingly. Thanks to :user:`Rawrmonkeys`. Fixes: From f838dea08bbdd5024c7b9783eb401e8822f659bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Detrey?= Date: Wed, 2 May 2018 09:27:58 +0200 Subject: [PATCH 6/6] Fixed line too long. --- beets/autotag/hooks.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/beets/autotag/hooks.py b/beets/autotag/hooks.py index cc5f37003..7df1f62f4 100644 --- a/beets/autotag/hooks.py +++ b/beets/autotag/hooks.py @@ -154,12 +154,12 @@ class TrackInfo(object): may be None. The indices ``index``, ``medium``, and ``medium_index`` are all 1-based. """ - def __init__(self, title, track_id, release_track_id=None, artist=None, artist_id=None, - length=None, index=None, medium=None, medium_index=None, - medium_total=None, artist_sort=None, disctitle=None, - artist_credit=None, data_source=None, data_url=None, - media=None, lyricist=None, composer=None, composer_sort=None, - arranger=None, track_alt=None): + def __init__(self, title, track_id, release_track_id=None, artist=None, + artist_id=None, length=None, index=None, medium=None, + medium_index=None, medium_total=None, artist_sort=None, + disctitle=None, artist_credit=None, data_source=None, + data_url=None, media=None, lyricist=None, composer=None, + composer_sort=None, arranger=None, track_alt=None): self.title = title self.track_id = track_id self.release_track_id = release_track_id