1# -*- coding: utf-8 -*- 2 3"""Updates an Plex library whenever the beets library is changed. 4 5Plex Home users enter the Plex Token to enable updating. 6Put something like the following in your config.yaml to configure: 7 plex: 8 host: localhost 9 port: 32400 10 token: token 11""" 12from __future__ import division, absolute_import, print_function 13 14import requests 15import xml.etree.ElementTree as ET 16from six.moves.urllib.parse import urljoin, urlencode 17from beets import config 18from beets.plugins import BeetsPlugin 19 20 21def get_music_section(host, port, token, library_name): 22 """Getting the section key for the music library in Plex. 23 """ 24 api_endpoint = append_token('library/sections', token) 25 url = urljoin('http://{0}:{1}'.format(host, port), api_endpoint) 26 27 # Sends request. 28 r = requests.get(url) 29 30 # Parse xml tree and extract music section key. 31 tree = ET.fromstring(r.content) 32 for child in tree.findall('Directory'): 33 if child.get('title') == library_name: 34 return child.get('key') 35 36 37def update_plex(host, port, token, library_name): 38 """Sends request to the Plex api to start a library refresh. 39 """ 40 # Getting section key and build url. 41 section_key = get_music_section(host, port, token, library_name) 42 api_endpoint = 'library/sections/{0}/refresh'.format(section_key) 43 api_endpoint = append_token(api_endpoint, token) 44 url = urljoin('http://{0}:{1}'.format(host, port), api_endpoint) 45 46 # Sends request and returns requests object. 47 r = requests.get(url) 48 return r 49 50 51def append_token(url, token): 52 """Appends the Plex Home token to the api call if required. 53 """ 54 if token: 55 url += '?' + urlencode({'X-Plex-Token': token}) 56 return url 57 58 59class PlexUpdate(BeetsPlugin): 60 def __init__(self): 61 super(PlexUpdate, self).__init__() 62 63 # Adding defaults. 64 config['plex'].add({ 65 u'host': u'localhost', 66 u'port': 32400, 67 u'token': u'', 68 u'library_name': u'Music'}) 69 70 config['plex']['token'].redact = True 71 self.register_listener('database_change', self.listen_for_db_change) 72 73 def listen_for_db_change(self, lib, model): 74 """Listens for beets db change and register the update for the end""" 75 self.register_listener('cli_exit', self.update) 76 77 def update(self, lib): 78 """When the client exists try to send refresh request to Plex server. 79 """ 80 self._log.info(u'Updating Plex library...') 81 82 # Try to send update request. 83 try: 84 update_plex( 85 config['plex']['host'].get(), 86 config['plex']['port'].get(), 87 config['plex']['token'].get(), 88 config['plex']['library_name'].get()) 89 self._log.info(u'... started.') 90 91 except requests.exceptions.RequestException: 92 self._log.warning(u'Update failed.') 93