Merge branch 'master' of github.com:beetbox/beets into deinterlace

This commit is contained in:
Piotrek Kochański 2021-11-01 21:33:27 +01:00
commit 4d94bf8fad
7 changed files with 41 additions and 206 deletions

View file

@ -757,15 +757,21 @@ def show_path_changes(path_changes):
if max_width > col_width: if max_width > col_width:
# Print every change over two lines # Print every change over two lines
for source, dest in zip(sources, destinations): for source, dest in zip(sources, destinations):
log.info('{0} \n -> {1}', source, dest) color_source, color_dest = colordiff(source, dest)
print_('{0} \n -> {1}'.format(color_source, color_dest))
else: else:
# Print every change on a single line, and add a header # Print every change on a single line, and add a header
title_pad = max_width - len('Source ') + len(' -> ') title_pad = max_width - len('Source ') + len(' -> ')
log.info('Source {0} Destination', ' ' * title_pad) print_('Source {0} Destination'.format(' ' * title_pad))
for source, dest in zip(sources, destinations): for source, dest in zip(sources, destinations):
pad = max_width - len(source) pad = max_width - len(source)
log.info('{0} {1} -> {2}', source, ' ' * pad, dest) color_source, color_dest = colordiff(source, dest)
print_('{0} {1} -> {2}'.format(
color_source,
' ' * pad,
color_dest,
))
# Helper functions for option parsing. # Helper functions for option parsing.

View file

@ -19,6 +19,7 @@ import sys
import errno import errno
import locale import locale
import re import re
import tempfile
import shutil import shutil
import fnmatch import fnmatch
import functools import functools
@ -478,6 +479,11 @@ def move(path, dest, replace=False):
instead, in which case metadata will *not* be preserved. Paths are instead, in which case metadata will *not* be preserved. Paths are
translated to system paths. translated to system paths.
""" """
if os.path.isdir(path):
raise FilesystemError(u'source is directory', 'move', (path, dest))
if os.path.isdir(dest):
raise FilesystemError(u'destination is directory', 'move',
(path, dest))
if samefile(path, dest): if samefile(path, dest):
return return
path = syspath(path) path = syspath(path)
@ -487,15 +493,23 @@ def move(path, dest, replace=False):
# First, try renaming the file. # First, try renaming the file.
try: try:
os.rename(path, dest) os.replace(path, dest)
except OSError: except OSError:
# Otherwise, copy and delete the original. tmp = tempfile.mktemp(suffix='.beets',
prefix=py3_path(b'.' + os.path.basename(dest)),
dir=py3_path(os.path.dirname(dest)))
tmp = syspath(tmp)
try: try:
shutil.copyfile(path, dest) shutil.copyfile(path, tmp)
os.replace(tmp, dest)
tmp = None
os.remove(path) os.remove(path)
except OSError as exc: except OSError as exc:
raise FilesystemError(exc, 'move', (path, dest), raise FilesystemError(exc, 'move', (path, dest),
traceback.format_exc()) traceback.format_exc())
finally:
if tmp is not None:
os.remove(tmp)
def link(path, dest, replace=False): def link(path, dest, replace=False):

View file

@ -1,5 +1,4 @@
# This file is part of beets. # This file is part of beets.
# Copyright 2017, Tigran Kostandyan.
# #
# Permission is hereby granted, free of charge, to any person obtaining # Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the # a copy of this software and associated documentation files (the
@ -12,124 +11,15 @@
# The above copyright notice and this permission notice shall be # The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software. # included in all copies or substantial portions of the Software.
"""Upload files to Google Play Music and list songs in its library.""" """Deprecation warning for the removed gmusic plugin."""
import os.path
from beets.plugins import BeetsPlugin from beets.plugins import BeetsPlugin
from beets import ui
from beets import config
from beets.ui import Subcommand
from gmusicapi import Musicmanager, Mobileclient
from gmusicapi.exceptions import NotLoggedIn
import gmusicapi.clients
class Gmusic(BeetsPlugin): class Gmusic(BeetsPlugin):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.m = Musicmanager()
# OAUTH_FILEPATH was moved in gmusicapi 12.0.0. self._log.warning("The 'gmusic' plugin has been removed following the"
if hasattr(Musicmanager, 'OAUTH_FILEPATH'): " shutdown of Google Play Music. Remove the plugin"
oauth_file = Musicmanager.OAUTH_FILEPATH " from your configuration to silence this warning.")
else:
oauth_file = gmusicapi.clients.OAUTH_FILEPATH
self.config.add({
'auto': False,
'uploader_id': '',
'uploader_name': '',
'device_id': '',
'oauth_file': oauth_file,
})
if self.config['auto']:
self.import_stages = [self.autoupload]
def commands(self):
gupload = Subcommand('gmusic-upload',
help='upload your tracks to Google Play Music')
gupload.func = self.upload
search = Subcommand('gmusic-songs',
help='list of songs in Google Play Music library')
search.parser.add_option('-t', '--track', dest='track',
action='store_true',
help='Search by track name')
search.parser.add_option('-a', '--artist', dest='artist',
action='store_true',
help='Search by artist')
search.func = self.search
return [gupload, search]
def authenticate(self):
if self.m.is_authenticated():
return
# Checks for OAuth2 credentials,
# if they don't exist - performs authorization
oauth_file = self.config['oauth_file'].as_filename()
if os.path.isfile(oauth_file):
uploader_id = self.config['uploader_id']
uploader_name = self.config['uploader_name']
self.m.login(oauth_credentials=oauth_file,
uploader_id=uploader_id.as_str().upper() or None,
uploader_name=uploader_name.as_str() or None)
else:
self.m.perform_oauth(oauth_file)
def upload(self, lib, opts, args):
items = lib.items(ui.decargs(args))
files = self.getpaths(items)
self.authenticate()
ui.print_('Uploading your files...')
self.m.upload(filepaths=files)
ui.print_('Your files were successfully added to library')
def autoupload(self, session, task):
items = task.imported_items()
files = self.getpaths(items)
self.authenticate()
self._log.info('Uploading files to Google Play Music...', files)
self.m.upload(filepaths=files)
self._log.info('Your files were successfully added to your '
+ 'Google Play Music library')
def getpaths(self, items):
return [x.path for x in items]
def search(self, lib, opts, args):
password = config['gmusic']['password']
email = config['gmusic']['email']
uploader_id = config['gmusic']['uploader_id']
device_id = config['gmusic']['device_id']
password.redact = True
email.redact = True
# Since Musicmanager doesn't support library management
# we need to use mobileclient interface
mobile = Mobileclient()
try:
new_device_id = (device_id.as_str()
or uploader_id.as_str().replace(':', '')
or Mobileclient.FROM_MAC_ADDRESS).upper()
mobile.login(email.as_str(), password.as_str(), new_device_id)
files = mobile.get_all_songs()
except NotLoggedIn:
ui.print_(
'Authentication error. Please check your email and password.'
)
return
if not args:
for i, file in enumerate(files, start=1):
print(i, ui.colorize('blue', file['artist']),
file['title'], ui.colorize('red', file['album']))
else:
if opts.track:
self.match(files, args, 'title')
else:
self.match(files, args, 'artist')
@staticmethod
def match(files, args, search_by):
for file in files:
if ' '.join(ui.decargs(args)) in file[search_by]:
print(file['artist'], file['title'], file['album'])

View file

@ -16,6 +16,9 @@ For packagers:
:bug:`4037` :bug:`4038` :bug:`4037` :bug:`4038`
* This version of beets no longer depends on the `six`_ library. * This version of beets no longer depends on the `six`_ library.
:bug:`4030` :bug:`4030`
* The `gmusic` plugin was removed since Google Play Music has been shut down.
Thus, the optional dependency on `gmusicapi` does not exist anymore.
:bug:`4089`
Major new features: Major new features:
@ -37,6 +40,12 @@ Other new things:
subdirectories in library. subdirectories in library.
* :doc:`/plugins/info`: Support ``--album`` flag. * :doc:`/plugins/info`: Support ``--album`` flag.
* :doc:`/plugins/export`: Support ``--album`` flag. * :doc:`/plugins/export`: Support ``--album`` flag.
* ``beet move`` path differences are now highlighted in color (when enabled).
* When moving files and a direct rename of a file is not possible, beets now
copies to a temporary file in the target folder first instead of directly
using the target path. This gets us closer to always updating files
atomically. Thanks to :user:`catap`.
:bug:`4060`
* :doc:`/plugins/fetchart`: A new option to store cover art as non-progressive * :doc:`/plugins/fetchart`: A new option to store cover art as non-progressive
image. Useful for DAPs that support progressive images. Set ``deinterlace: image. Useful for DAPs that support progressive images. Set ``deinterlace:
yes`` in your configuration to enable. yes`` in your configuration to enable.

View file

@ -1,87 +1,5 @@
Gmusic Plugin Gmusic Plugin
============= =============
The ``gmusic`` plugin lets you upload songs to Google Play Music and query The ``gmusic`` plugin interfaced beets to Google Play Music. It has been
songs in your library. removed after the shutdown of this service.
Installation
------------
The plugin requires :pypi:`gmusicapi`. You can install it using ``pip``::
pip install gmusicapi
.. _gmusicapi: https://github.com/simon-weber/gmusicapi/
Then, you can enable the ``gmusic`` plugin in your configuration (see
:ref:`using-plugins`).
Usage
-----
Configuration is required before use. Below is an example configuration::
gmusic:
email: user@example.com
password: seekrit
auto: yes
uploader_id: 00:11:22:33:AA:BB
device_id: 00112233AABB
oauth_file: ~/.config/beets/oauth.cred
To upload tracks to Google Play Music, use the ``gmusic-upload`` command::
beet gmusic-upload [QUERY]
If you don't include a query, the plugin will upload your entire collection.
To list your music collection, use the ``gmusic-songs`` command::
beet gmusic-songs [-at] [ARGS]
Use the ``-a`` option to search by artist and ``-t`` to search by track. For
example::
beet gmusic-songs -a John Frusciante
beet gmusic-songs -t Black Hole Sun
For a list of all songs in your library, run ``beet gmusic-songs`` without any
arguments.
Configuration
-------------
To configure the plugin, make a ``gmusic:`` section in your configuration file.
The available options are:
- **email**: Your Google account email address.
Default: none.
- **password**: Password to your Google account. Required to query songs in
your collection.
For accounts with 2-step-verification, an
`app password <https://support.google.com/accounts/answer/185833?hl=en>`__
will need to be generated. An app password for an account without
2-step-verification is not required but is recommended.
Default: none.
- **auto**: Set to ``yes`` to automatically upload new imports to Google Play
Music.
Default: ``no``
- **uploader_id**: Unique id as a MAC address, eg ``00:11:22:33:AA:BB``.
This option should be set before the maximum number of authorized devices is
reached.
If provided, use the same id for all future runs on this, and other, beets
installations as to not reach the maximum number of authorized devices.
Default: device's MAC address.
- **device_id**: Unique device ID for authorized devices. It is usually
the same as your MAC address with the colons removed, eg ``00112233AABB``.
This option only needs to be set if you receive an `InvalidDeviceId`
exception. Below the exception will be a list of valid device IDs.
Default: none.
- **oauth_file**: Filepath for oauth credentials file.
Default: `{user_data_dir} <https://pypi.org/project/appdirs/>`__/gmusicapi/oauth.cred
Refer to the `Google Play Music Help
<https://support.google.com/googleplaymusic/answer/3139562?hl=en>`__
page for more details on authorized devices.

View file

@ -231,7 +231,6 @@ Miscellaneous
* :doc:`filefilter`: Automatically skip files during the import process based * :doc:`filefilter`: Automatically skip files during the import process based
on regular expressions. on regular expressions.
* :doc:`fuzzy`: Search albums and tracks with fuzzy string matching. * :doc:`fuzzy`: Search albums and tracks with fuzzy string matching.
* :doc:`gmusic`: Search and upload files to Google Play Music.
* :doc:`hook`: Run a command when an event is emitted by beets. * :doc:`hook`: Run a command when an event is emitted by beets.
* :doc:`ihate`: Automatically skip albums and tracks during the import process. * :doc:`ihate`: Automatically skip albums and tracks during the import process.
* :doc:`info`: Print music files' tags to the console. * :doc:`info`: Print music files' tags to the console.

View file

@ -126,7 +126,6 @@ setup(
'embedart': ['Pillow'], 'embedart': ['Pillow'],
'embyupdate': ['requests'], 'embyupdate': ['requests'],
'chroma': ['pyacoustid'], 'chroma': ['pyacoustid'],
'gmusic': ['gmusicapi'],
'discogs': ['python3-discogs-client>=2.3.10'], 'discogs': ['python3-discogs-client>=2.3.10'],
'beatport': ['requests-oauthlib>=0.6.1'], 'beatport': ['requests-oauthlib>=0.6.1'],
'kodiupdate': ['requests'], 'kodiupdate': ['requests'],