mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Its a simple plugin that triggers a library refresh after the library got changed. It does the same thing like the plexupdate plugin.
133 lines
3.8 KiB
Python
133 lines
3.8 KiB
Python
"""Updates the Emby Library whenever the beets library is changed.
|
|
|
|
emby:
|
|
host: localhost
|
|
port: 8096
|
|
username: user
|
|
password: password
|
|
"""
|
|
from __future__ import (division, absolute_import, print_function,
|
|
unicode_literals)
|
|
|
|
from beets import config
|
|
from beets.plugins import BeetsPlugin
|
|
from urllib import urlencode
|
|
from urlparse import urljoin, parse_qs, urlsplit, urlunsplit
|
|
import hashlib
|
|
import requests
|
|
|
|
|
|
def api_url(host, port, endpoint):
|
|
"""Returns a joined url.
|
|
"""
|
|
joined = urljoin('http://{0}:{1}'.format(host, port), endpoint)
|
|
scheme, netloc, path, query_string, fragment = urlsplit(joined)
|
|
query_params = parse_qs(query_string)
|
|
|
|
query_params['format'] = ['json']
|
|
new_query_string = urlencode(query_params, doseq=True)
|
|
|
|
return urlunsplit((scheme, netloc, path, new_query_string, fragment))
|
|
|
|
|
|
def password_data(username, password):
|
|
"""Returns a dict with username and its encoded password.
|
|
"""
|
|
return {
|
|
'username': username,
|
|
'password': hashlib.sha1(password).hexdigest(),
|
|
'passwordMd5': hashlib.md5(password).hexdigest()
|
|
}
|
|
|
|
|
|
def create_headers(user_id, token=None):
|
|
"""Return header dict that is needed to talk to the Emby API.
|
|
"""
|
|
headers = {
|
|
'Authorization': 'MediaBrowser',
|
|
'UserId': user_id,
|
|
'Client': 'other',
|
|
'Device': 'empy',
|
|
'DeviceId': 'beets',
|
|
'Version': '0.0.0'
|
|
}
|
|
|
|
if token:
|
|
headers['X-MediaBrowser-Token'] = token
|
|
|
|
return headers
|
|
|
|
|
|
def get_token(host, port, headers, auth_data):
|
|
"""Return token for a user.
|
|
"""
|
|
url = api_url(host, port, '/Users/AuthenticateByName')
|
|
r = requests.post(url, headers=headers, data=auth_data)
|
|
|
|
return r.json().get('AccessToken')
|
|
|
|
|
|
def get_user(host, port, username):
|
|
"""Return user dict from server or None if there is no user.
|
|
"""
|
|
url = api_url(host, port, '/Users/Public')
|
|
r = requests.get(url)
|
|
user = [i for i in r.json() if i['Name'] == username]
|
|
|
|
return user
|
|
|
|
|
|
class EmbyUpdate(BeetsPlugin):
|
|
def __init__(self):
|
|
super(EmbyUpdate, self).__init__()
|
|
|
|
# Adding defaults.
|
|
config['emby'].add({
|
|
u'host': u'localhost',
|
|
u'port': 8096
|
|
})
|
|
|
|
self.register_listener('database_change', self.listen_for_db_change)
|
|
|
|
def listen_for_db_change(self, lib, model):
|
|
"""Listens for beets db change and register the update for the end.
|
|
"""
|
|
self.register_listener('cli_exit', self.update)
|
|
|
|
def update(self, lib):
|
|
"""When the client exists try to send refresh request to Emby.
|
|
"""
|
|
self._log.info(u'Updating Emby library...')
|
|
|
|
host = config['emby']['host'].get()
|
|
port = config['emby']['port'].get()
|
|
username = config['emby']['username'].get()
|
|
password = config['emby']['password'].get()
|
|
|
|
# Get user information from the Emby API.
|
|
user = get_user(host, port, username)
|
|
if not user:
|
|
self._log.warning(u'User {0} could not be found.'.format(username))
|
|
return
|
|
|
|
# Create Authentication data and headers.
|
|
auth_data = password_data(username, password)
|
|
headers = create_headers(user[0]['Id'])
|
|
|
|
# Get authentication token.
|
|
token = get_token(host, port, headers, auth_data)
|
|
if not token:
|
|
self._log.warning(
|
|
u'Couldnt not get token for user {0}'.format(username))
|
|
return
|
|
|
|
# Recreate headers with a token.
|
|
headers = create_headers(user[0]['Id'], token=token)
|
|
|
|
# Trigger the Update.
|
|
url = api_url(host, port, '/Library/Refresh')
|
|
r = requests.post(url, headers=headers)
|
|
if r.status_code != 204:
|
|
self._log.warning(u'Update could not be triggered')
|
|
else:
|
|
self._log.info(u'Update triggered.')
|