Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librespot: update python scripts #9497

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 0 additions & 66 deletions packages/addons/service/librespot/source/bin/onevent.py

This file was deleted.

23 changes: 3 additions & 20 deletions packages/addons/service/librespot/source/default.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
import os
import sys
import xbmcaddon
import xbmcvfs

sys.path.append(os.path.join(os.path.dirname(__file__), "resources", "lib"))

def _set_home():
home = xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
os.makedirs(home, exist_ok=True)
os.chdir(home)
import monitor


def _set_paths():
path = xbmcaddon.Addon().getAddonInfo('path')
os.environ['PATH'] += os.pathsep + os.path.join(path, 'bin')
os.environ['LD_LIBRARY_PATH'] += os.pathsep + os.path.join(path, 'lib')
sys.path.append(os.path.join(path, 'bin'))
sys.path.append(os.path.join(path, 'resources', 'lib'))


if __name__ == '__main__':
_set_home()
_set_paths()
import service
service.Monitor().run()
monitor.run()
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ msgid "Do not disturb Kodi"
msgstr ""

msgctxt "#30103"
msgid "User options"
msgid "Backend"
msgstr ""

msgctxt "#30104"
msgid "Backend"
msgid "Player"
msgstr ""

msgctxt "#30105"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import json
import socket
import threading

import onevent
import utils

_BUFFER = 1024


class EventHandler:
@utils.logged_method
def __init__(self, target):
self._target = target
self._socket = socket.socket(onevent.SOCK_AF, onevent.SOCK_TYPE)
self._socket.settimeout(None)
self._socket.bind((onevent.HOST, 0))
self._port = self._socket.getsockname()[1]
self._receiver = threading.Thread(target=self._handle_events)
self._receiver.start()

@utils.logged_method
def __enter__(self):
return self

@utils.logged_method
def __exit__(self, *_):
onevent.send_event(self._port)
self._receiver.join()

def _handle_events(self):
utils.log(f"Event handler listening on port {self._port}")
with self._socket:
while True:
data, _ = self._socket.recvfrom(_BUFFER)
event, dict = json.loads(data)
if event:
try:
utils.log(f"Event handler handling {event}{dict}")
method = f"on_event_{event}"
getattr(self._target, method)(**dict)
except Exception as e:
utils.log(f"Event handler failed to handle {event}: {e}")
else:
break
utils.log("Event handler ended")

def get_onevent(self):
return f"python {onevent.__file__} {self._port}"

This file was deleted.

This file was deleted.

137 changes: 61 additions & 76 deletions packages/addons/service/librespot/source/resources/lib/librespot.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,78 @@
import shlex
import socket
import subprocess
import threading

import external_player
import internal_player
import service
import utils


class Librespot:
@utils.logged_method
def __init__(self, target, backend, device):
self._target = target
name = utils.get_setting("name").format(socket.gethostname())
self._command = [
"librespot",
"--backend", backend,
"--bitrate", "320",
"--device", device,
"--device-type", "tv",
"--disable-audio-cache",
"--disable-credential-cache",
"--name", name,
"--onevent", target.event_handler.get_onevent(),
"--quiet",
]
self._failures = 0
self._max_failures = 5
self._librespot = None
self._get_librespot = self._schedule_librespot()

@utils.logged_method
def __enter__(self):
return self

def __init__(self,
bitrate='320',
device_type='tv',
max_retries='5',
name='Librespot@{}',
options='',
**kwargs):
name = name.format(socket.gethostname())
self.command = [
'librespot',
'--bitrate', f'{bitrate}',
'--device-type', f'{device_type}',
'--disable-audio-cache',
'--disable-credential-cache',
'--name', f'{name}',
'--onevent', 'onevent.py',
'--quiet',
] + shlex.split(options)
service.log(self.command)
self.file = ''
self._is_started = threading.Event()
self._is_stopped = threading.Event()
@utils.logged_method
def __exit__(self, *_):
self._get_librespot.close()

def _schedule_librespot(self):
while self._failures < self._max_failures:
with subprocess.Popen(
self._command, stderr=subprocess.PIPE, text=True
) as self._librespot:
threading.Thread(target=self._monitor_librespot).start()
try:
yield
finally:
self._librespot.terminate()
utils.call_if_has(self._target, "on_librespot_broken")
utils.log("Librespot crashed too many times", True)
self._librespot = None
self._max_retries = int(max_retries)
self._retries = 0
self._thread = threading.Thread()
while True:
yield

def get_player(self, **kwargs):
return (internal_player if self.file else external_player).Player(**kwargs)
def _monitor_librespot(self):
self._target.on_librespot_started()
with self._librespot as librespot:
for line in librespot.stderr:
utils.log(line.rstrip())
self._target.on_librespot_stopped()
if librespot.returncode < 0:
self._failures = 0
else:
self._failures += 1
next(self._get_librespot)

@utils.logged_method
def restart(self):
if self._thread.is_alive():
self._librespot.terminate()
else:
self.start()
next(self._get_librespot)

@utils.logged_method
def start(self):
if not self._thread.is_alive() and self._retries < self._max_retries:
self._thread = threading.Thread(daemon=True, target=self._run)
self._thread.start()
self._is_started.wait(1)
if self._librespot is None or self._librespot.poll() is not None:
next(self._get_librespot)

@utils.logged_method
def stop(self):
if self._thread.is_alive():
self._is_stopped.set()
if self._librespot is not None:
self._librespot.terminate()
self._thread.join()

def start_sink(self):
pass

def stop_sink(self):
pass

def _run(self):
service.log('librespot thread started')
self._is_started.clear()
self._is_stopped.clear()
while not self._is_stopped.is_set():
with subprocess.Popen(self.command, stderr=subprocess.PIPE, text=True) as self._librespot:
self._is_started.set()
for line in self._librespot.stderr:
service.log(line.rstrip())
self.stop_sink()
if self._librespot.returncode <= 0:
self._retries = 0
else:
self._retries += 1
if self._retries < self._max_retries:
service.notification(
f'librespot failed {self._retries}/{self._max_retries}')
else:
service.notification('librespot failed too many times')
break
service.log('librespot thread stopped')

def __enter__(self):
return self

def __exit__(self, *args):
self.stop()

This file was deleted.

Loading