mirror of
https://github.com/beetbox/beets.git
synced 2025-12-15 21:14:19 +01:00
embyupdate: Fix authentication header problem
There was a problem with the authentication header in the latest versions. The header creation function changed to fix that. Username and passwort authentication should work again. The `host` config variable takes now a full hostname. For example `http://localhost` instead of just `localhost`. This makes it easier to use https hosts.
This commit is contained in:
parent
78171ee560
commit
a282d4abc5
4 changed files with 99 additions and 41 deletions
|
|
@ -3,25 +3,38 @@
|
|||
"""Updates the Emby Library whenever the beets library is changed.
|
||||
|
||||
emby:
|
||||
host: localhost
|
||||
host: http://localhost
|
||||
port: 8096
|
||||
username: user
|
||||
password: password
|
||||
"""
|
||||
from __future__ import division, absolute_import, print_function
|
||||
|
||||
from beets import config
|
||||
from beets.plugins import BeetsPlugin
|
||||
from six.moves.urllib.parse import urlencode
|
||||
from six.moves.urllib.parse import urljoin, parse_qs, urlsplit, urlunsplit
|
||||
import hashlib
|
||||
import requests
|
||||
|
||||
from six.moves.urllib.parse import urlencode
|
||||
from six.moves.urllib.parse import urljoin, parse_qs, urlsplit, urlunsplit
|
||||
|
||||
from beets import config
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
|
||||
def api_url(host, port, endpoint):
|
||||
"""Returns a joined url.
|
||||
|
||||
Takes host, port and endpoint and generates a valid emby API url.
|
||||
|
||||
:param host: Hostname of the emby server
|
||||
:param port: Portnumber of the emby server
|
||||
:param endpoint: API endpoint
|
||||
:type host: str
|
||||
:type port: int
|
||||
:type endpoint: str
|
||||
:returns: Full API url
|
||||
:rtype: str
|
||||
"""
|
||||
joined = urljoin('http://{0}:{1}'.format(host, port), endpoint)
|
||||
joined = urljoin('{0}:{1}'.format(host, port), endpoint)
|
||||
scheme, netloc, path, query_string, fragment = urlsplit(joined)
|
||||
query_params = parse_qs(query_string)
|
||||
|
||||
|
|
@ -33,6 +46,13 @@ def api_url(host, port, endpoint):
|
|||
|
||||
def password_data(username, password):
|
||||
"""Returns a dict with username and its encoded password.
|
||||
|
||||
:param username: Emby username
|
||||
:param password: Emby password
|
||||
:type username: str
|
||||
:type password: str
|
||||
:returns: Dictionary with username and encoded password
|
||||
:rtype: dict
|
||||
"""
|
||||
return {
|
||||
'username': username,
|
||||
|
|
@ -43,24 +63,45 @@ def password_data(username, password):
|
|||
|
||||
def create_headers(user_id, token=None):
|
||||
"""Return header dict that is needed to talk to the Emby API.
|
||||
|
||||
:param user_id: Emby user ID
|
||||
:param token: Authentication token for Emby
|
||||
:type user_id: str
|
||||
:type token: str
|
||||
:returns: Headers for requests
|
||||
:rtype: dict
|
||||
"""
|
||||
headers = {
|
||||
'Authorization': 'MediaBrowser',
|
||||
'UserId': user_id,
|
||||
'Client': 'other',
|
||||
'Device': 'empy',
|
||||
'DeviceId': 'beets',
|
||||
'Version': '0.0.0'
|
||||
}
|
||||
headers = {}
|
||||
|
||||
authorization = (
|
||||
'MediaBrowser UserId="{user_id}", '
|
||||
'Client="other", '
|
||||
'Device="beets", '
|
||||
'DeviceId="beets", '
|
||||
'Version="0.0.0"'
|
||||
).format(user_id=user_id)
|
||||
|
||||
headers['x-emby-authorization'] = authorization
|
||||
|
||||
if token:
|
||||
headers['X-MediaBrowser-Token'] = token
|
||||
headers['x-mediabrowser-token'] = token
|
||||
|
||||
return headers
|
||||
|
||||
|
||||
def get_token(host, port, headers, auth_data):
|
||||
"""Return token for a user.
|
||||
|
||||
:param host: Emby host
|
||||
:param port: Emby port
|
||||
:param headers: Headers for requests
|
||||
:param auth_data: Username and encoded password for authentication
|
||||
:type host: str
|
||||
:type port: int
|
||||
:type headers: dict
|
||||
:type auth_data: dict
|
||||
:returns: Access Token
|
||||
:rtype: str
|
||||
"""
|
||||
url = api_url(host, port, '/Users/AuthenticateByName')
|
||||
r = requests.post(url, headers=headers, data=auth_data)
|
||||
|
|
@ -70,6 +111,15 @@ def get_token(host, port, headers, auth_data):
|
|||
|
||||
def get_user(host, port, username):
|
||||
"""Return user dict from server or None if there is no user.
|
||||
|
||||
:param host: Emby host
|
||||
:param port: Emby port
|
||||
:username: Username
|
||||
:type host: str
|
||||
:type port: int
|
||||
:type username: str
|
||||
:returns: Matched Users
|
||||
:rtype: list
|
||||
"""
|
||||
url = api_url(host, port, '/Users/Public')
|
||||
r = requests.get(url)
|
||||
|
|
@ -84,7 +134,7 @@ class EmbyUpdate(BeetsPlugin):
|
|||
|
||||
# Adding defaults.
|
||||
config['emby'].add({
|
||||
u'host': u'localhost',
|
||||
u'host': u'http://localhost',
|
||||
u'port': 8096
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ And there are a few bug fixes too:
|
|||
omitted.
|
||||
* With :ref:`ignore_hidden` enabled, non-UTF-8 filenames would cause a crash.
|
||||
This is fixed. :bug:`2168`
|
||||
* :doc:`/plugins/embyupdate`: Fixes authentication header problem that caused
|
||||
a problem that it was not possible to get tokens from the Emby API.
|
||||
|
||||
The last release, 1.3.19, also erroneously reported its version as "1.3.18"
|
||||
when you typed ``beet version``. This has been corrected.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ EmbyUpdate Plugin
|
|||
To use ``embyupdate`` plugin, enable it in your configuration (see :ref:`using-plugins`). Then, you'll probably want to configure the specifics of your Emby server. You can do that using an ``emby:`` section in your ``config.yaml``, which looks like this::
|
||||
|
||||
emby:
|
||||
host: localhost
|
||||
host: http://localhost
|
||||
port: 8096
|
||||
username: user
|
||||
apikey: apikey
|
||||
|
|
@ -25,8 +25,8 @@ Configuration
|
|||
|
||||
The available options under the ``emby:`` section are:
|
||||
|
||||
- **host**: The Emby server name.
|
||||
Default: ``localhost``
|
||||
- **host**: The Emby server host. You have to include ``http://`` or ``https://``.
|
||||
Default: ``http://localhost``
|
||||
- **port**: The Emby server port.
|
||||
Default: 8096
|
||||
- **username**: A username of a Emby user that is allowed to refresh the library.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class EmbyUpdateTest(unittest.TestCase, TestHelper):
|
|||
self.load_plugins('embyupdate')
|
||||
|
||||
self.config['emby'] = {
|
||||
u'host': u'localhost',
|
||||
u'host': u'http://localhost',
|
||||
u'port': 8096,
|
||||
u'username': u'username',
|
||||
u'password': u'password'
|
||||
|
|
@ -47,12 +47,14 @@ class EmbyUpdateTest(unittest.TestCase, TestHelper):
|
|||
self.assertEqual(
|
||||
embyupdate.create_headers('e8837bc1-ad67-520e-8cd2-f629e3155721'),
|
||||
{
|
||||
'Authorization': 'MediaBrowser',
|
||||
'UserId': 'e8837bc1-ad67-520e-8cd2-f629e3155721',
|
||||
'Client': 'other',
|
||||
'Device': 'empy',
|
||||
'DeviceId': 'beets',
|
||||
'Version': '0.0.0'
|
||||
'x-emby-authorization': (
|
||||
'MediaBrowser '
|
||||
'UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", '
|
||||
'Client="other", '
|
||||
'Device="beets", '
|
||||
'DeviceId="beets", '
|
||||
'Version="0.0.0"'
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -61,13 +63,15 @@ class EmbyUpdateTest(unittest.TestCase, TestHelper):
|
|||
embyupdate.create_headers('e8837bc1-ad67-520e-8cd2-f629e3155721',
|
||||
token='abc123'),
|
||||
{
|
||||
'Authorization': 'MediaBrowser',
|
||||
'UserId': 'e8837bc1-ad67-520e-8cd2-f629e3155721',
|
||||
'Client': 'other',
|
||||
'Device': 'empy',
|
||||
'DeviceId': 'beets',
|
||||
'Version': '0.0.0',
|
||||
'X-MediaBrowser-Token': 'abc123'
|
||||
'x-emby-authorization': (
|
||||
'MediaBrowser '
|
||||
'UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", '
|
||||
'Client="other", '
|
||||
'Device="beets", '
|
||||
'DeviceId="beets", '
|
||||
'Version="0.0.0"'
|
||||
),
|
||||
'x-mediabrowser-token': 'abc123'
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -132,12 +136,14 @@ class EmbyUpdateTest(unittest.TestCase, TestHelper):
|
|||
content_type='application/json')
|
||||
|
||||
headers = {
|
||||
'Authorization': 'MediaBrowser',
|
||||
'UserId': 'e8837bc1-ad67-520e-8cd2-f629e3155721',
|
||||
'Client': 'other',
|
||||
'Device': 'empy',
|
||||
'DeviceId': 'beets',
|
||||
'Version': '0.0.0'
|
||||
'x-emby-authorization': (
|
||||
'MediaBrowser '
|
||||
'UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", '
|
||||
'Client="other", '
|
||||
'Device="beets", '
|
||||
'DeviceId="beets", '
|
||||
'Version="0.0.0"'
|
||||
)
|
||||
}
|
||||
|
||||
auth_data = {
|
||||
|
|
@ -147,7 +153,7 @@ class EmbyUpdateTest(unittest.TestCase, TestHelper):
|
|||
}
|
||||
|
||||
self.assertEqual(
|
||||
embyupdate.get_token('localhost', 8096, headers, auth_data),
|
||||
embyupdate.get_token('http://localhost', 8096, headers, auth_data),
|
||||
'4b19180cf02748f7b95c7e8e76562fc8')
|
||||
|
||||
@responses.activate
|
||||
|
|
@ -196,7 +202,7 @@ class EmbyUpdateTest(unittest.TestCase, TestHelper):
|
|||
status=200,
|
||||
content_type='application/json')
|
||||
|
||||
response = embyupdate.get_user('localhost', 8096, 'username')
|
||||
response = embyupdate.get_user('http://localhost', 8096, 'username')
|
||||
|
||||
self.assertEqual(response[0]['Id'],
|
||||
'2ec276a2642e54a19b612b9418a8bd3b')
|
||||
|
|
|
|||
Loading…
Reference in a new issue