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