Skip to content

Commit

Permalink
Merge branch 'metabrainz/2.0' of https://github.com/MetaTunes/picard-…
Browse files Browse the repository at this point in the history
…plugins into metabrainz/2.0
  • Loading branch information
MetaTunes committed Jul 1, 2019
2 parents 683dd9e + de5d5c0 commit dac8f1f
Show file tree
Hide file tree
Showing 63 changed files with 5,109 additions and 2,885 deletions.
7 changes: 6 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
dist: xenial
language: python
cache:
pip: true
python:
- "3.4"
- "3.5"
- "3.6"
- "3.7"
before_install:
- pip3 install picard
script: python test.py
13 changes: 7 additions & 6 deletions generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import zipfile

from hashlib import md5
from subprocess import call
from subprocess import check_call

from get_plugin_data import get_plugin_data

VERSION_TO_BRANCH = {
None: 'master',
'1.0': 'master',
None: '2.0',
'1.0': '1.0',
'2.0': '2.0',
}

Expand Down Expand Up @@ -74,7 +74,8 @@ def zip_files(dest_dir):
file_path = os.path.join(root, filename)
plugin_files.append(file_path)

if len(plugin_files) == 1:
if (len(plugin_files) == 1
and os.path.basename(plugin_files[0]) != '__init__.py'):
# There's only one file, put it directly into the zipfile
archive.write(plugin_files[0],
os.path.basename(plugin_files[0]),
Expand Down Expand Up @@ -106,12 +107,12 @@ def zip_files(dest_dir):
parser.add_argument('--no-zip', action='store_false', dest='zip', help="Do not generate the zip files in the build output")
parser.add_argument('--no-json', action='store_false', dest='json', help="Do not generate the json file in the build output")
args = parser.parse_args()
call(["git", "checkout", "-q", VERSION_TO_BRANCH[args.version], '--', 'plugins'])
check_call(["git", "checkout", "-q", VERSION_TO_BRANCH[args.version], '--', 'plugins'])
dest_dir = os.path.abspath(os.path.join(args.build_dir, args.version or ''))
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
if args.pull:
call(["git", "pull", "-q"])
check_call(["git", "pull", "-q"])
if args.json:
build_json(dest_dir)
if args.zip:
Expand Down
41 changes: 13 additions & 28 deletions plugins/abbreviate_artistsort/abbreviate_artistsort.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

from __future__ import print_function
PLUGIN_NAME = "Abbreviate artist-sort"
PLUGIN_AUTHOR = "Sophist"
PLUGIN_DESCRIPTION = '''Abbreviate Artist-Sort and Album-Artist-Sort Tags.
e.g. "Vivaldi, Antonio" becomes "Vivaldi, A."
This is particularly useful for classical albums that can have a long list of artists.
%artistsort% is abbreviated into %_artistsort_abbrev% and
%albumartistsort% is abbreviated into %_albumartistsort_abbrev%.'''
PLUGIN_VERSION = "0.2"
PLUGIN_VERSION = "0.4"
PLUGIN_API_VERSIONS = ["1.0", "2.0"]
PLUGIN_LICENSE = "GPL-2.0"
PLUGIN_LICENSE = "GPL-2.0-or-later"
PLUGIN_LICENSE_URL = "https://www.gnu.org/licenses/gpl-2.0.html"


Expand Down Expand Up @@ -70,7 +69,6 @@
# Case c. If first word is same in sorted and unsorted, move words that match to new strings, then treat as b.
# Case d. Try to handle without abbreviating and get to next name which might not be foreign

_debug_level = 0
_abbreviate_tags = [
('albumartistsort', 'albumartist', '~albumartistsort_abbrev'),
('artistsort', 'artist', '~artistsort_abbrev'),
Expand All @@ -90,11 +88,9 @@ def abbreviate_artistsort(tagger, metadata, track, release):
unsorts = list(metadata.getall(unsortTag))
for i in range(0, min(len(sorts), len(unsorts))):
sort = sorts[i]
if _debug_level > 1:
print("%s: Trying to abbreviate '%s'." % (PLUGIN_NAME, sort))
log.debug("%s: Trying to abbreviate '%s'." % (PLUGIN_NAME, sort))
if sort in _abbreviate_cache:
if _debug_level > 3:
print(" Using abbreviation found in cache: '%s'." % (_abbreviate_cache[sort]))
log.debug(" Using abbreviation found in cache: '%s'." % (_abbreviate_cache[sort]))
sorts[i] = _abbreviate_cache[sort]
continue
unsort = unsorts[i]
Expand All @@ -104,17 +100,15 @@ def abbreviate_artistsort(tagger, metadata, track, release):
while len(sort) > 0 and len(unsort) > 0:

if not _split in sort:
if _debug_level > 3:
print(" Ending without separator '%s' - moving '%s'." % (_split, sort))
log.debug(" Ending without separator '%s' - moving '%s'." % (_split, sort))
new_sort += sort
new_unsort += unsort
sort = unsort = ""
continue

surname, rest = sort.split(_split, 1)
if rest == "":
if _debug_level > 3:
print(" Ending with separator '%s' - moving '%s'." % (_split, surname))
log.debug(" Ending with separator '%s' - moving '%s'." % (_split, surname))
new_sort += sort
new_unsort += unsort
sort = unsort = ""
Expand All @@ -129,8 +123,7 @@ def abbreviate_artistsort(tagger, metadata, track, release):
temp = surname + _split
l = len(temp)
if unsort[:l] == temp:
if _debug_level > 3:
print(" No forename - moving '%s'." % (surname))
log.debug(" No forename - moving '%s'." % (surname))
new_sort += temp
new_unsort += temp
sort = sort[l:]
Expand All @@ -143,8 +136,7 @@ def abbreviate_artistsort(tagger, metadata, track, release):
if unsort.find(' ' + surname) == -1:
while surname.split(None, 1)[0] == unsort.split(None, 1)[0]:
x = unsort.split(None, 1)[0]
if _debug_level > 3:
print(" Moving matching word '%s'." % (x))
log.debug(" Moving matching word '%s'." % (x))
new_sort += x
new_unsort += x
surname = surname[len(x):]
Expand All @@ -165,8 +157,7 @@ def abbreviate_artistsort(tagger, metadata, track, release):
unsortTag,
unsort[i],
)
if _debug_level > 0:
print(" Could not match surname (%s) in remaining unsorted:" % (surname, unsort))
log.warning(" Could not match surname (%s) in remaining unsorted:" % (surname, unsort))
break

# Sorted: Surname, Forename(s)...
Expand All @@ -182,8 +173,7 @@ def abbreviate_artistsort(tagger, metadata, track, release):
unsortTag,
unsort[i],
)
if _debug_level > 0:
print(" Could not match forename (%s) for surname (%s) in remaining unsorted (%s):" % (forename, surname, unsort))
log.warning(" Could not match forename (%s) for surname (%s) in remaining unsorted (%s):" % (forename, surname, unsort))
break

inits = ' '.join([x[0] + '.' for x in forename.split()])
Expand Down Expand Up @@ -216,8 +206,7 @@ def abbreviate_artistsort(tagger, metadata, track, release):
inits,
sortTag,
)
if _debug_level > 2:
print("Abbreviated (%s, %s) to (%s, %s)." % (surname, forename, surname, inits))
log.debug("Abbreviated (%s, %s) to (%s, %s)." % (surname, forename, surname, inits))
else: # while loop ended without a break i.e. no errors
if unsorts[i] != new_unsort:
log.error(
Expand All @@ -228,13 +217,9 @@ def abbreviate_artistsort(tagger, metadata, track, release):
unsorts[i],
new_unsort,
)
if _debug_level > 0:
print()
print("Error: Unsorted text for %s has changed from '%s' to '%s'!" % (unsortTag, unsorts[i], new_unsort))
print()
log.warning("Error: Unsorted text for %s has changed from '%s' to '%s'!" % (unsortTag, unsorts[i], new_unsort))
_abbreviate_cache[sorts[i]] = new_sort
if _debug_level > 1:
print(" Abbreviated and cached (%s) as (%s)." % (sorts[i], new_sort))
log.debug(" Abbreviated and cached (%s) as (%s)." % (sorts[i], new_sort))
if sorts[i] != new_sort:
log.debug(_("%s: Abbreviated tag '%s' to '%s'."),
PLUGIN_NAME,
Expand Down
32 changes: 20 additions & 12 deletions plugins/acousticbrainz/acousticbrainz.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
WARNING: Experimental plugin. All guarantees voided by use.'''
PLUGIN_LICENSE = "GPL-2.0"
PLUGIN_LICENSE_URL = "https://www.gnu.org/licenses/gpl-2.0.txt"
PLUGIN_VERSION = "1.1"
PLUGIN_VERSION = "1.1.1"
PLUGIN_API_VERSIONS = ["2.0"]

from functools import partial
Expand All @@ -39,19 +39,26 @@


def result(album, metadata, data, reply, error):
if error:
album._requests -= 1
album._finalize_loading(None)
return

moods = []
genres = []
try:
data = load_json(data)["highlevel"]
for k, v in data.items():
if k.startswith("genre_") and not v["value"].startswith("not_"):
genres.append(v["value"])
if k.startswith("mood_") and not v["value"].startswith("not_"):
moods.append(v["value"])
data = load_json(data)
if "highlevel" in data:
data = data["highlevel"]
for k, v in data.items():
if k.startswith("genre_") and not v["value"].startswith("not_"):
genres.append(v["value"])
if k.startswith("mood_") and not v["value"].startswith("not_"):
moods.append(v["value"])

metadata["genre"] = genres
metadata["mood"] = moods
log.debug("%s: Track %s (%s) Parsed response (genres: %s, moods: %s)", PLUGIN_NAME, metadata["musicbrainz_recordingid"], metadata["title"], str(genres), str(moods))
metadata["genre"] = genres
metadata["mood"] = moods
log.debug("%s: Track %s (%s) Parsed response (genres: %s, moods: %s)", PLUGIN_NAME, metadata["musicbrainz_recordingid"], metadata["title"], str(genres), str(moods))
except Exception as e:
log.error("%s: Track %s (%s) Error parsing response: %s", PLUGIN_NAME, metadata["musicbrainz_recordingid"], metadata["title"], str(e))
finally:
Expand All @@ -60,12 +67,13 @@ def result(album, metadata, data, reply, error):


def process_track(album, metadata, release, track):
album.tagger.webservice.download(
album.tagger.webservice.get(
ACOUSTICBRAINZ_HOST,
ACOUSTICBRAINZ_PORT,
"/%s/high-level" % (metadata["musicbrainz_recordingid"]),
partial(result, album, metadata),
priority=True
priority=True,
parse_response_type=None
)
album._requests += 1

Expand Down
30 changes: 23 additions & 7 deletions plugins/acousticbrainz_tonal-rhythm/acousticbrainz_tonal-rhythm.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,18 @@
</ul>
from the AcousticBrainz database.<br/><br/>
'''
PLUGIN_LICENSE = "GPL-2.0"
PLUGIN_LICENSE = "GPL-2.0-or-later"
PLUGIN_LICENSE_URL = "https://www.gnu.org/licenses/gpl-2.0.txt"
PLUGIN_VERSION = '1.1'
PLUGIN_VERSION = '1.1.2'
PLUGIN_API_VERSIONS = ["2.0"] # Requires support for TKEY which is in 1.4

from json import JSONDecodeError

from picard import log
from picard.metadata import register_track_metadata_processor
from functools import partial
from picard.webservice import ratecontrol
from picard.util import load_json

ACOUSTICBRAINZ_HOST = "acousticbrainz.org"
ACOUSTICBRAINZ_PORT = 80
Expand All @@ -44,26 +47,38 @@
class AcousticBrainz_Key:

def get_data(self, album, track_metadata, trackXmlNode, releaseXmlNode):
if "musicbrainz_recordingid" not in track_metadata:
log.error("%s: Error parsing response. No MusicBrainz recording id found.",
PLUGIN_NAME)
return
recordingId = track_metadata['musicbrainz_recordingid']
if recordingId:
log.debug("%s: Add AcusticBrainz request for %s (%s)", PLUGIN_NAME, track_metadata['title'], recordingId)
log.debug("%s: Add AcousticBrainz request for %s (%s)",
PLUGIN_NAME, track_metadata['title'], recordingId)
self.album_add_request(album)
path = "/%s/low-level" % recordingId
return album.tagger.webservice.get(
ACOUSTICBRAINZ_HOST,
ACOUSTICBRAINZ_PORT,
path,
partial(self.process_data, album, track_metadata),
priority=True, important=False)
return
priority=True,
important=False,
parse_response_type=None)

def process_data(self, album, track_metadata, response, reply, error):
if error:
log.error("%s: Network error retrieving acousticBrainz data for recordingId %s",
PLUGIN_NAME, track_metadata['musicbrainz_recordingid'])
PLUGIN_NAME, track_metadata['musicbrainz_recordingid'])
self.album_remove_request(album)
return
try:
data = load_json(response)
except JSONDecodeError:
log.error("%s: Network error retrieving AcousticBrainz data for recordingId %s",
PLUGIN_NAME, track_metadata['musicbrainz_recordingid'])
self.album_remove_request(album)
return
data = response
if "tonal" in data:
if "key_key" in data["tonal"]:
key = data["tonal"]["key_key"]
Expand All @@ -88,4 +103,5 @@ def album_remove_request(self, album):
if album._requests == 0:
album._finalize_loading(None)


register_track_metadata_processor(AcousticBrainz_Key().get_data)
51 changes: 51 additions & 0 deletions plugins/add_album_column/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# -*- coding: UTF-8 -*-

#
# Licensing
#
# Add Album Column, Add the Album column to the main window panel
# Copyright (C) 2019 Evandro Coan <https://github.com/evandrocoan>
#
# Redistributions of source code must retain the above
# copyright notice, this list of conditions and the
# following disclaimer.
#
# Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# Neither the name Evandro Coan nor the names of any
# contributors may be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or ( at
# your option ) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

PLUGIN_NAME = u"Add Album Column"
PLUGIN_AUTHOR = u"Evandro Coan"
PLUGIN_DESCRIPTION = """Add the Album column to the main window panel.
WARNING: This plugin cannot be disabled. See:
https://github.com/metabrainz/picard-plugins/pull/195
"""

PLUGIN_VERSION = "1.0"
PLUGIN_API_VERSIONS = ["2.0"]
PLUGIN_LICENSE = "GPL-3.0-or-later"
PLUGIN_LICENSE_URL = "http://www.gnu.org/licenses/"

from picard.ui.itemviews import MainPanel
MainPanel.columns.append((N_('Album'), 'album'))
Loading

0 comments on commit dac8f1f

Please sign in to comment.