Merge branch 'master' into single-instance-gsoc

This commit is contained in:
Laurent Monin
2022-07-04 22:04:36 +02:00
committed by GitHub
12 changed files with 458 additions and 320 deletions

View File

@@ -79,6 +79,7 @@ jobs:
pip3 install -r requirements-build.txt
pip3 install -r requirements-macos-${MACOSX_DEPLOYMENT_TARGET}.txt
- name: Run tests
timeout-minutes: 30
run: |
python3 setup.py test
- name: Prepare code signing certificate
@@ -153,6 +154,7 @@ jobs:
pip install -r requirements-build.txt
pip install -r requirements-win.txt
- name: Run tests
timeout-minutes: 30
run: python setup.py test
- name: Prepare code signing certificate
if: matrix.type != 'store-app'

View File

@@ -20,6 +20,7 @@ jobs:
python -m pip install --upgrade pip
pip install --upgrade -r requirements.txt
- name: Run tests
timeout-minutes: 30
run: |
python setup.py test
- name: Build Python source distribution
@@ -97,6 +98,7 @@ jobs:
python -m pip install --upgrade pip wheel
pip install --upgrade -r requirements.txt
- name: Run tests
timeout-minutes: 30
run: |
python setup.py test
- name: Build Python binary distribution

View File

@@ -120,6 +120,7 @@ jobs:
run: picard --long-version --no-crash-dialog
- name: Verify sdist package
if: runner.os != 'Windows'
timeout-minutes: 30
run: |
pip install pytest
scripts/package/run-sdist-test.sh

View File

@@ -6,7 +6,7 @@
# Copyright (C) 2017-2018 Sambhav Kothari
# Copyright (C) 2018 Vishal Choudhary
# Copyright (C) 2018-2021 Laurent Monin
# Copyright (C) 2018-2021 Philipp Wolfer
# Copyright (C) 2018-2022 Philipp Wolfer
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -36,8 +36,12 @@ from picard import log
from picard.acoustid.json_helpers import parse_recording
from picard.config import get_config
from picard.const import FPCALC_NAMES
from picard.const.sys import IS_WIN
from picard.file import File
from picard.util import find_executable
from picard.util import (
find_executable,
win_prefix_longpath,
)
def get_score(node):
@@ -248,7 +252,10 @@ class AcoustIDClient(QtCore.QObject):
process.setProperty('picard_finished', False)
process.finished.connect(partial(self._on_fpcalc_finished, task))
process.error.connect(partial(self._on_fpcalc_error, task))
process.start(self._fpcalc, ["-json", "-length", "120", task.file.filename])
file_path = task.file.filename
if IS_WIN:
file_path = win_prefix_longpath(file_path)
process.start(self._fpcalc, ["-json", "-length", "120", file_path])
log.debug("Starting fingerprint calculator %r %r", self._fpcalc, task.file.filename)
def analyze(self, file, next_func):

View File

@@ -75,7 +75,6 @@ _MEDIUM_TO_METADATA = {
'format': 'media',
'position': 'discnumber',
'title': 'discsubtitle',
'track-count': 'totaltracks',
}
_RECORDING_TO_METADATA = {
@@ -478,6 +477,11 @@ def medium_to_metadata(node, m):
for key, value in _node_skip_empty_iter(node):
if key in _MEDIUM_TO_METADATA:
m[_MEDIUM_TO_METADATA[key]] = value
totaltracks = node.get('track-count', 0)
if node.get('pregap'):
totaltracks += 1
if totaltracks:
m['totaltracks'] = totaltracks
def artist_to_metadata(node, m):

View File

@@ -188,7 +188,8 @@ class Tagger(QtWidgets.QApplication):
_debug = False
_no_restore = False
def __init__(self, picard_args, unparsed_args, localedir, autoupdate, pipe_handler=None):
def __init__(self, picard_args, localedir, autoupdate, pipe_handler=None):
super().__init__(sys.argv)
self.__class__.__instance = self
@@ -1066,8 +1067,8 @@ def process_picard_args():
parser.add_argument("-V", "--long-version", action='store_true',
help="display long version information and exit")
parser.add_argument('FILE', nargs='*')
picard_args, unparsed_args = parser.parse_known_args()
return picard_args, unparsed_args
return parser.parse_known_args()[0]
class OverrideStyle(QtWidgets.QProxyStyle):
@@ -1106,7 +1107,7 @@ def main(localedir=None, autoupdate=True):
signal.signal(signal.SIGINT, signal.SIG_DFL)
picard_args, unparsed_args = process_picard_args()
picard_args = process_picard_args()
if picard_args.version:
return version()
if picard_args.long_version:
@@ -1142,7 +1143,7 @@ def main(localedir=None, autoupdate=True):
except ImportError:
pass
tagger = Tagger(picard_args, unparsed_args, localedir, autoupdate, pipe_handler=pipe_handler)
tagger = Tagger(picard_args, localedir, autoupdate, pipe_handler=pipe_handler)
# Initialize Qt default translations
translator = QtCore.QTranslator()

View File

@@ -2,7 +2,7 @@
#
# Picard, the next-generation MusicBrainz tagger
#
# Copyright (C) 2021 Bob Swift
# Copyright (C) 2021-2022 Bob Swift
# Copyright (C) 2021 Laurent Monin
# Copyright (C) 2021-2022 Philipp Wolfer
#
@@ -50,6 +50,7 @@ from picard.const import (
PICARD_URLS,
)
from picard.file import File
from picard.metadata import Metadata
from picard.script import (
ScriptError,
ScriptParser,
@@ -154,14 +155,18 @@ class ScriptEditorExamples():
Returns:
tuple: Example before and after names for the specified file
"""
# Operate on a copy of the file object metadata to avoid multiple changes to file metadata. See PICARD-2508.
c_metadata = Metadata()
c_metadata.copy(file.metadata)
try:
if self.settings["enable_tagger_scripts"]:
# Only apply scripts if the original file metadata has not been changed.
if self.settings["enable_tagger_scripts"] and not c_metadata.diff(file.orig_metadata):
for s_pos, s_name, s_enabled, s_text in self.settings["list_of_scripts"]:
if s_enabled and s_text:
parser = ScriptParser()
parser.eval(s_text, file.metadata)
parser.eval(s_text, c_metadata)
filename_before = file.filename
filename_after = file.make_filename(filename_before, file.metadata, self.settings, self.script_text)
filename_after = file.make_filename(filename_before, c_metadata, self.settings, self.script_text)
if not self.settings["move_files"]:
return os.path.basename(filename_before), os.path.basename(filename_after)
return filename_before, filename_after

View File

@@ -228,8 +228,13 @@ def normpath(path):
# If the path is longer than 259 characters on Windows, prepend the \\?\
# prefix. This enables access to long paths using the Windows API. See
# https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
if (IS_WIN and len(path) > WIN_MAX_FILEPATH_LEN and not system_supports_long_paths()
and not path.startswith(WIN_LONGPATH_PREFIX)):
if IS_WIN and not system_supports_long_paths():
path = win_prefix_longpath(path)
return path
def win_prefix_longpath(path):
if len(path) > WIN_MAX_FILEPATH_LEN and not path.startswith(WIN_LONGPATH_PREFIX):
path = WIN_LONGPATH_PREFIX + path
return path

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
{
"track-count": 8,
"discs": [
{
"sectors": 134481,
"offset-count": 8,
"id": "7v3LmtkMIT49mHs7LobaAwBNsck-",
"offsets": [
6824,
18966,
37134,
52930,
69024,
80329,
98814,
117353
]
}
],
"format-id": "8a08dc62-1aa2-34de-a904-fa467c53052c",
"position": 1,
"track-offset": 0,
"format": "Enhanced CD",
"title": "",
"pregap": {
"number": "0",
"position": 0,
"artist-credit": [
{
"name": "Lemon Demon",
"joinphrase": "",
"artist": {
"type": "Person",
"sort-name": "Lemon Demon",
"disambiguation": "",
"id": "6b014cfd-4927-4187-a741-715998e6d785",
"type-id": "b6e035f4-3ce9-331c-97df-83397230b0df",
"aliases": [
{
"name": "Deporitaz",
"primary": null,
"type-id": null,
"locale": null,
"begin": null,
"ended": false,
"end": null,
"sort-name": "Deporitaz",
"type": null
}
],
"name": "Lemon Demon"
}
}
],
"recording": {
"video": false,
"id": "a6f68447-7810-4d1e-a5a2-d10ff0943aee",
"first-release-date": "2019",
"aliases": [],
"title": "Sexy DVD",
"length": 88000,
"disambiguation": "",
"artist-credit": [
{
"artist": {
"id": "6b014cfd-4927-4187-a741-715998e6d785",
"type": "Person",
"sort-name": "Lemon Demon",
"type-id": "b6e035f4-3ce9-331c-97df-83397230b0df",
"disambiguation": "",
"name": "Lemon Demon"
},
"joinphrase": "",
"name": "Lemon Demon"
}
]
},
"length": 88000,
"title": "Sexy DVD",
"id": "74fa2a03-325a-4a6b-bcfd-12f95ba30d16"
},
"tracks": []
}

View File

@@ -402,6 +402,18 @@ class MediaTest(MBJSONTest):
self.assertEqual(m['totaltracks'], '10')
class MediaPregapTest(MBJSONTest):
filename = 'media_pregap.json'
def test_track(self):
m = Metadata()
medium_to_metadata(self.json_doc, m)
self.assertEqual(m['discnumber'], '1')
self.assertEqual(m['media'], 'Enhanced CD')
self.assertEqual(m['totaltracks'], '9')
class NullMediaTest(MBJSONTest):
filename = 'media_null.json'

View File

@@ -71,6 +71,7 @@ from picard.util import (
tracknum_from_filename,
uniqify,
wildcards_to_regex_pattern,
win_prefix_longpath,
)
@@ -738,6 +739,17 @@ class NormpathTest(PicardTestCase):
self.assertEqual('\\\\?\\' + path, normpath(path))
class WinPrefixLongpathTest(PicardTestCase):
def test_win_prefix_longpath_is_long(self):
path = 'C:\\foo\\' + (253 * 'a')
self.assertEqual('\\\\?\\' + path, win_prefix_longpath(path))
def test_win_prefix_longpath_is_short(self):
path = 'C:\\foo\\' + (252 * 'a')
self.assertEqual(path, win_prefix_longpath(path))
class SystemSupportsLongPathsTest(PicardTestCase):
def setUp(self):