From 923e3bacd609bde6109f4b4dddeb4b99d5360e10 Mon Sep 17 00:00:00 2001 From: Andrew Rogl Date: Mon, 3 May 2021 16:03:40 +1000 Subject: [PATCH 1/6] Attempt to fix duplicates #2873 --- beetsplug/duplicates.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/beetsplug/duplicates.py b/beetsplug/duplicates.py index 4e6e540ea..0492fea65 100644 --- a/beetsplug/duplicates.py +++ b/beetsplug/duplicates.py @@ -17,14 +17,17 @@ """ from __future__ import division, absolute_import, print_function +import platform import shlex +import six +from beets import util from beets.plugins import BeetsPlugin from beets.ui import decargs, print_, Subcommand, UserError from beets.util import command_output, displayable_path, subprocess, \ bytestring_path, MoveOperation from beets.library import Item, Album -import six + PLUGIN = 'duplicates' @@ -197,7 +200,20 @@ class DuplicatesPlugin(BeetsPlugin): output as flexattr on a key that is the name of the program, and return the key, checksum tuple. """ - args = [p.format(file=item.path) for p in shlex.split(prog)] + # On Python 3, we need to construct the command to invoke as a + # Unicode string. On Unix, this is a little unfortunate---the OS is + # expecting bytes---so we use surrogate escaping and decode with the + # argument encoding, which is the same encoding that will then be + # *reversed* to recover the same bytes before invoking the OS. On + # Windows, we want to preserve the Unicode filename "as is." + if not six.PY2: + if platform.system() == 'Windows': + args = [p.format(file=item.path.decode(util._fsencoding())) + for p in shlex.split(prog)] + else: + args = [p.format(file=item.path.decode(util.arg_encoding(), + 'surrogateescape')) for p in shlex.split(prog)] + key = args[0] checksum = getattr(item, key, False) if not checksum: From b59da2e4f53cadf0710faea1a30cd7f80a960a25 Mon Sep 17 00:00:00 2001 From: Andrew Rogl Date: Sat, 8 May 2021 16:10:19 +1000 Subject: [PATCH 2/6] Changelog entry --- docs/changelog.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index f8debb3da..79b2135da 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -180,6 +180,9 @@ New features: :bug:`3478` * Removes usage of the bs1770gain replaygain backend. Thanks to :user:`SamuelCook`. +* Duplicates can now generate checksums. Thanks user:`wisp3rwind` for the + pointer to how to solve. + Thanks to :user:`arogl`. :bug:`2873` Fixes: From 0c6f82647864d7b77212d2fe3d1c9aef1afeccbb Mon Sep 17 00:00:00 2001 From: Andrew Rogl Date: Sat, 8 May 2021 16:14:23 +1000 Subject: [PATCH 3/6] It's a fix, not a change :-( --- docs/changelog.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 79b2135da..2f7a95f5f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -180,9 +180,6 @@ New features: :bug:`3478` * Removes usage of the bs1770gain replaygain backend. Thanks to :user:`SamuelCook`. -* Duplicates can now generate checksums. Thanks user:`wisp3rwind` for the - pointer to how to solve. - Thanks to :user:`arogl`. :bug:`2873` Fixes: @@ -307,6 +304,9 @@ Fixes: information. Thanks to :user:`dosoe`. * :doc:`/plugins/discogs`: Replace deprecated discogs-client library with community supported python3-discogs-client library. :bug:`3608` +* Fix :bug:`2873`. Duplicates can now generate checksums. Thanks user:`wisp3rwind` + for the pointer to how to solve. Thanks to :user:`arogl`. + For plugin developers: From 39ca5b7be65d6654ae778de022ee931ee3a16a14 Mon Sep 17 00:00:00 2001 From: Andrew Rogl Date: Sun, 23 May 2021 14:45:02 +1000 Subject: [PATCH 4/6] Changes as requested --- beets/util/__init__.py | 22 ++++++++++++++++++++++ beetsplug/convert.py | 19 +++---------------- beetsplug/duplicates.py | 20 +++----------------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 248096730..0ae646a22 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -1108,3 +1108,25 @@ def lazy_property(func): return value return wrapper + + +def decode_commandline_path(path): + """Prepare a path for substitution into commandline template. + + On Python 3, we need to construct the subprocess commands to invoke as a + Unicode string. On Unix, this is a little unfortunate---the OS is + expecting bytes---so we use surrogate escaping and decode with the + argument encoding, which is the same encoding that will then be + *reversed* to recover the same bytes before invoking the OS. On + Windows, we want to preserve the Unicode filename "as is." + """ + if six.PY2: + # On Python 2, substitute the bytestring directly into the template. + return path + else: + # On Python 3, the template is a Unicode string, which only supports + # substitution of Unicode variables. + if platform.system() == 'Windows': + return path.decode(_fsencoding()) + else: + return path.decode(arg_encoding(), 'surrogateescape') diff --git a/beetsplug/convert.py b/beetsplug/convert.py index 275703e97..ae91cd155 100644 --- a/beetsplug/convert.py +++ b/beetsplug/convert.py @@ -16,7 +16,7 @@ """Converts tracks or albums to external directory """ from __future__ import division, absolute_import, print_function -from beets.util import par_map +from beets.util import par_map, decode_commandline_path import os import threading @@ -25,7 +25,6 @@ import tempfile import shlex import six from string import Template -import platform from beets import ui, util, plugins, config from beets.plugins import BeetsPlugin @@ -205,20 +204,8 @@ class ConvertPlugin(BeetsPlugin): if not quiet and not pretend: self._log.info(u'Encoding {0}', util.displayable_path(source)) - # On Python 3, we need to construct the command to invoke as a - # Unicode string. On Unix, this is a little unfortunate---the OS is - # expecting bytes---so we use surrogate escaping and decode with the - # argument encoding, which is the same encoding that will then be - # *reversed* to recover the same bytes before invoking the OS. On - # Windows, we want to preserve the Unicode filename "as is." - if not six.PY2: - command = command.decode(util.arg_encoding(), 'surrogateescape') - if platform.system() == 'Windows': - source = source.decode(util._fsencoding()) - dest = dest.decode(util._fsencoding()) - else: - source = source.decode(util.arg_encoding(), 'surrogateescape') - dest = dest.decode(util.arg_encoding(), 'surrogateescape') + source = decode_commandline_path(source) + dest = decode_commandline_path(dest) # Substitute $source and $dest in the argument list. args = shlex.split(command) diff --git a/beetsplug/duplicates.py b/beetsplug/duplicates.py index 0492fea65..bc9e3ff3c 100644 --- a/beetsplug/duplicates.py +++ b/beetsplug/duplicates.py @@ -17,15 +17,13 @@ """ from __future__ import division, absolute_import, print_function -import platform import shlex import six -from beets import util from beets.plugins import BeetsPlugin from beets.ui import decargs, print_, Subcommand, UserError from beets.util import command_output, displayable_path, subprocess, \ - bytestring_path, MoveOperation + bytestring_path, MoveOperation, decode_commandline_path from beets.library import Item, Album @@ -200,20 +198,8 @@ class DuplicatesPlugin(BeetsPlugin): output as flexattr on a key that is the name of the program, and return the key, checksum tuple. """ - # On Python 3, we need to construct the command to invoke as a - # Unicode string. On Unix, this is a little unfortunate---the OS is - # expecting bytes---so we use surrogate escaping and decode with the - # argument encoding, which is the same encoding that will then be - # *reversed* to recover the same bytes before invoking the OS. On - # Windows, we want to preserve the Unicode filename "as is." - if not six.PY2: - if platform.system() == 'Windows': - args = [p.format(file=item.path.decode(util._fsencoding())) - for p in shlex.split(prog)] - else: - args = [p.format(file=item.path.decode(util.arg_encoding(), - 'surrogateescape')) for p in shlex.split(prog)] - + args = [p.format(file=decode_commandline_path(item.path)) + for p in shlex.split(prog)] key = args[0] checksum = getattr(item, key, False) if not checksum: From 81e50cb630ec68fd40006c8908cd290ae8668aec Mon Sep 17 00:00:00 2001 From: Andrew Rogl Date: Sun, 23 May 2021 15:43:14 +1000 Subject: [PATCH 5/6] Too quick to delete --- beetsplug/convert.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/beetsplug/convert.py b/beetsplug/convert.py index ae91cd155..acbd6fe41 100644 --- a/beetsplug/convert.py +++ b/beetsplug/convert.py @@ -16,7 +16,7 @@ """Converts tracks or albums to external directory """ from __future__ import division, absolute_import, print_function -from beets.util import par_map, decode_commandline_path +from beets.util import par_map, decode_commandline_path, arg_encoding import os import threading @@ -204,6 +204,9 @@ class ConvertPlugin(BeetsPlugin): if not quiet and not pretend: self._log.info(u'Encoding {0}', util.displayable_path(source)) + if not six.PY2: + command = command.decode(arg_encoding(), 'surrogateescape') + source = decode_commandline_path(source) dest = decode_commandline_path(dest) From 78f25575c3423c5c2ecfffe1fe7897b29597f350 Mon Sep 17 00:00:00 2001 From: Andrew Rogl Date: Mon, 24 May 2021 16:23:04 +1000 Subject: [PATCH 6/6] Resolve changelog conflict --- docs/changelog.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0a468313c..6487a304d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -371,6 +371,9 @@ Fixes: * :doc:`/plugins/lyrics`: Fix crashes for Tekstowo false positives :bug:`3904` * :doc`/reference/cli`: Remove reference to rarfile version in link +* Fix :bug:`2873`. Duplicates can now generate checksums. Thanks user:`wisp3rwind` + for the pointer to how to solve. Thanks to :user:`arogl`. + For plugin developers: