Merge pull request #4719 from arsaboo/embedart_url

Added option to embedart using an image URL [small PR]
This commit is contained in:
J0J0 Todos 2023-04-21 21:52:04 +02:00 committed by GitHub
commit f6b0311221
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 19 deletions

View file

@ -15,14 +15,16 @@
"""Allows beets to embed album art into file metadata."""
import os.path
import tempfile
from mimetypes import guess_extension
import requests
from beets import art, config, ui
from beets.plugins import BeetsPlugin
from beets import ui
from beets.ui import print_, decargs
from beets.util import syspath, normpath, displayable_path, bytestring_path
from beets.ui import decargs, print_
from beets.util import bytestring_path, displayable_path, normpath, syspath
from beets.util.artresizer import ArtResizer
from beets import config
from beets import art
def _confirm(objs, album):
@ -75,15 +77,17 @@ class EmbedCoverArtPlugin(BeetsPlugin):
def commands(self):
# Embed command.
embed_cmd = ui.Subcommand(
'embedart', help='embed image files into file metadata'
)
embed_cmd.parser.add_option(
'-f', '--file', metavar='PATH', help='the image file to embed'
)
embed_cmd.parser.add_option(
"-y", "--yes", action="store_true", help="skip confirmation"
)
embed_cmd = ui.Subcommand('embedart',
help='embed image files into file metadata')
embed_cmd.parser.add_option('-f', '--file', metavar='PATH',
help='the image file to embed')
embed_cmd.parser.add_option("-y", "--yes", action="store_true",
help="skip confirmation")
embed_cmd.parser.add_option('-u', '--url', metavar='URL',
help='the URL of the image file to embed')
maxwidth = self.config['maxwidth'].get(int)
quality = self.config['quality'].get(int)
compare_threshold = self.config['compare_threshold'].get(int)
@ -107,13 +111,41 @@ class EmbedCoverArtPlugin(BeetsPlugin):
art.embed_item(self._log, item, imagepath, maxwidth,
None, compare_threshold, ifempty,
quality=quality)
elif opts.url:
try:
response = requests.get(opts.url, timeout=5)
response.raise_for_status()
except requests.exceptions.RequestException as e:
self._log.error("{}".format(e))
return
extension = guess_extension(response.headers
['Content-Type'])
if extension is None:
self._log.error('Invalid image file')
return
file = f'image{extension}'
tempimg = os.path.join(tempfile.gettempdir(), file)
try:
with open(tempimg, 'wb') as f:
f.write(response.content)
except Exception as e:
self._log.error("Unable to save image: {}".format(e))
return
items = lib.items(decargs(args))
# Confirm with user.
if not opts.yes and not _confirm(items, not opts.url):
os.remove(tempimg)
return
for item in items:
art.embed_item(self._log, item, tempimg, maxwidth,
None, compare_threshold, ifempty,
quality=quality)
os.remove(tempimg)
else:
albums = lib.albums(decargs(args))
# Confirm with user.
if not opts.yes and not _confirm(albums, not opts.file):
return
for album in albums:
art.embed_album(self._log, album, maxwidth,
False, compare_threshold, ifempty,

View file

@ -11,10 +11,12 @@ for Python 3.6).
New features:
* Added option to specify a URL in the `embedart` plugin.
:bug:`83`
* :ref:`list-cmd` `singleton:true` queries have been made faster
* :ref:`list-cmd` `singleton:1` and `singleton:0` can now alternatively be used in queries, same as `comp`
* --from-logfile now parses log files using a UTF-8 encoding in `beets/beets/ui/commands.py`.
:bug:`4693`
:bug:`4693`
* :doc:`/plugins/bareasc` lookups have been made faster
* :ref:`list-cmd` lookups using the pattern operator `::` have been made faster
* Added additional error handling for `spotify` plugin.

View file

@ -85,12 +85,15 @@ Manually Embedding and Extracting Art
The ``embedart`` plugin provides a couple of commands for manually managing
embedded album art:
* ``beet embedart [-f IMAGE] QUERY``: embed images into the every track on the
* ``beet embedart [-f IMAGE] QUERY``: embed images in every track of the
albums matching the query. If the ``-f`` (``--file``) option is given, then
use a specific image file from the filesystem; otherwise, each album embeds
its own currently associated album art. The command prompts for confirmation
before making the change unless you specify the ``-y`` (``--yes``) option.
* ``beet embedart [-u IMAGE_URL] QUERY``: embed image specified in the URL
into every track of the albums matching the query. The ``-u`` (``--url``) option can be used to specify the URL of the image to be used. The command prompts for confirmation before making the change unless you specify the ``-y`` (``--yes``) option.
* ``beet extractart [-a] [-n FILE] QUERY``: extracts the images for all albums
matching the query. The images are placed inside the album folder. You can
specify the destination file name using the ``-n`` option, but leave off the

View file

@ -28,6 +28,7 @@ from beets import config, logging, ui
from beets.util import syspath, displayable_path
from beets.util.artresizer import ArtResizer
from beets import art
from test.test_art import FetchImageHelper
def require_artresizer_compare(test):
@ -42,7 +43,7 @@ def require_artresizer_compare(test):
return wrapper
class EmbedartCliTest(_common.TestCase, TestHelper):
class EmbedartCliTest(TestHelper, FetchImageHelper):
small_artpath = os.path.join(_common.RSRC, b'image-2x3.jpg')
abbey_artpath = os.path.join(_common.RSRC, b'abbey.jpg')
@ -216,6 +217,40 @@ class EmbedartCliTest(_common.TestCase, TestHelper):
mediafile = MediaFile(syspath(item.path))
self.assertEqual(mediafile.images[0].data, self.image_data)
def test_embed_art_from_url_with_yes_input(self):
self._setup_data()
album = self.add_album_fixture()
item = album.items()[0]
self.mock_response('http://example.com/test.jpg', 'image/jpeg')
self.io.addinput('y')
self.run_command('embedart', '-u', 'http://example.com/test.jpg')
mediafile = MediaFile(syspath(item.path))
self.assertEqual(
mediafile.images[0].data,
self.IMAGEHEADER.get('image/jpeg').ljust(32, b'\x00')
)
def test_embed_art_from_url_png(self):
self._setup_data()
album = self.add_album_fixture()
item = album.items()[0]
self.mock_response('http://example.com/test.png', 'image/png')
self.run_command('embedart', '-y', '-u', 'http://example.com/test.png')
mediafile = MediaFile(syspath(item.path))
self.assertEqual(
mediafile.images[0].data,
self.IMAGEHEADER.get('image/png').ljust(32, b'\x00')
)
def test_embed_art_from_url_not_image(self):
self._setup_data()
album = self.add_album_fixture()
item = album.items()[0]
self.mock_response('http://example.com/test.html', 'text/html')
self.run_command('embedart', '-y', '-u', 'http://example.com/test.txt')
mediafile = MediaFile(syspath(item.path))
self.assertFalse(mediafile.images)
class DummyArtResizer(ArtResizer):
"""An `ArtResizer` which pretends that ImageMagick is available, and has