mirror of
https://github.com/beetbox/beets.git
synced 2026-02-25 00:32:50 +01:00
Merge pull request #4719 from arsaboo/embedart_url
Added option to embedart using an image URL [small PR]
This commit is contained in:
commit
f6b0311221
4 changed files with 91 additions and 19 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue