File: plexupdate.py

package info (click to toggle)
beets 2.5.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,988 kB
  • sloc: python: 46,429; javascript: 8,018; xml: 334; sh: 261; makefile: 125
file content (120 lines) | stat: -rw-r--r-- 3,594 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""Updates an Plex library whenever the beets library is changed.

Plex Home users enter the Plex Token to enable updating.
Put something like the following in your config.yaml to configure:
    plex:
        host: localhost
        port: 32400
        token: token
"""

from urllib.parse import urlencode, urljoin
from xml.etree import ElementTree

import requests

from beets import config
from beets.plugins import BeetsPlugin


def get_music_section(
    host, port, token, library_name, secure, ignore_cert_errors
):
    """Getting the section key for the music library in Plex."""
    api_endpoint = append_token("library/sections", token)
    url = urljoin(f"{get_protocol(secure)}://{host}:{port}", api_endpoint)

    # Sends request.
    r = requests.get(
        url,
        verify=not ignore_cert_errors,
        timeout=10,
    )

    # Parse xml tree and extract music section key.
    tree = ElementTree.fromstring(r.content)
    for child in tree.findall("Directory"):
        if child.get("title") == library_name:
            return child.get("key")


def update_plex(host, port, token, library_name, secure, ignore_cert_errors):
    """Ignore certificate errors if configured to."""
    if ignore_cert_errors:
        import urllib3

        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    """Sends request to the Plex api to start a library refresh.
    """
    # Getting section key and build url.
    section_key = get_music_section(
        host, port, token, library_name, secure, ignore_cert_errors
    )
    api_endpoint = f"library/sections/{section_key}/refresh"
    api_endpoint = append_token(api_endpoint, token)
    url = urljoin(f"{get_protocol(secure)}://{host}:{port}", api_endpoint)

    # Sends request and returns requests object.
    r = requests.get(
        url,
        verify=not ignore_cert_errors,
        timeout=10,
    )
    return r


def append_token(url, token):
    """Appends the Plex Home token to the api call if required."""
    if token:
        url += f"?{urlencode({'X-Plex-Token': token})}"
    return url


def get_protocol(secure):
    if secure:
        return "https"
    else:
        return "http"


class PlexUpdate(BeetsPlugin):
    def __init__(self):
        super().__init__()

        # Adding defaults.
        config["plex"].add(
            {
                "host": "localhost",
                "port": 32400,
                "token": "",
                "library_name": "Music",
                "secure": False,
                "ignore_cert_errors": False,
            }
        )

        config["plex"]["token"].redact = True
        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 Plex server."""
        self._log.info("Updating Plex library...")

        # Try to send update request.
        try:
            update_plex(
                config["plex"]["host"].get(),
                config["plex"]["port"].get(),
                config["plex"]["token"].get(),
                config["plex"]["library_name"].get(),
                config["plex"]["secure"].get(bool),
                config["plex"]["ignore_cert_errors"].get(bool),
            )
            self._log.info("... started.")

        except requests.exceptions.RequestException:
            self._log.warning("Update failed.")