mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 08:56:17 +00:00
Jukebox endpoint + some fixes
This commit is contained in:
parent
75b89e5f45
commit
0d40ede256
@ -98,4 +98,5 @@ from .annotation import *
|
||||
from .chat import *
|
||||
from .search import *
|
||||
from .playlists import *
|
||||
from .jukebox import *
|
||||
from .unsupported import *
|
||||
|
94
supysonic/api/jukebox.py
Normal file
94
supysonic/api/jukebox.py
Normal file
@ -0,0 +1,94 @@
|
||||
# coding: utf-8
|
||||
#
|
||||
# This file is part of Supysonic.
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
#
|
||||
# Copyright (C) 2019 Alban 'spl0k' Féron
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
import uuid
|
||||
|
||||
from flask import current_app, request
|
||||
from pony.orm import ObjectNotFound
|
||||
|
||||
from ..daemon import DaemonClient
|
||||
from ..daemon.exceptions import DaemonUnavailableError
|
||||
from ..db import Track
|
||||
|
||||
from . import api
|
||||
from .exceptions import GenericError, MissingParameter
|
||||
|
||||
|
||||
@api.route("/jukeboxControl.view", methods=["GET", "POST"])
|
||||
def jukebox_control():
|
||||
action = request.values["action"]
|
||||
|
||||
index = request.values.get("index")
|
||||
offset = request.values.get("offset")
|
||||
id = request.values.getlist("id")
|
||||
gain = request.values.get("gain")
|
||||
|
||||
if action not in (
|
||||
"get",
|
||||
"status",
|
||||
"set",
|
||||
"start",
|
||||
"stop",
|
||||
"skip",
|
||||
"add",
|
||||
"clear",
|
||||
"remove",
|
||||
"shuffle",
|
||||
"setGain",
|
||||
):
|
||||
raise GenericError("Unknown action")
|
||||
|
||||
arg = None
|
||||
if action == "set":
|
||||
if not id:
|
||||
arg = []
|
||||
else:
|
||||
arg = [uuid.UUID(i) for i in id]
|
||||
elif action == "skip":
|
||||
if not index:
|
||||
raise MissingParameter("index")
|
||||
else:
|
||||
arg = int(index)
|
||||
elif action == "add":
|
||||
if not id:
|
||||
raise MissingParameter("id")
|
||||
else:
|
||||
arg = [uuid.UUID(i) for i in id]
|
||||
elif action == "remove":
|
||||
if not index:
|
||||
raise MissingParameter("index")
|
||||
else:
|
||||
arg = int(index)
|
||||
elif action == "setGain":
|
||||
if not gain:
|
||||
raise MissingParameter("gain")
|
||||
else:
|
||||
arg = float(gain)
|
||||
|
||||
try:
|
||||
status = DaemonClient(current_app.config["DAEMON"]["socket"]).jukebox_control(
|
||||
action, arg
|
||||
)
|
||||
except DaemonUnavailableError:
|
||||
raise GenericError("Jukebox unavaliable")
|
||||
|
||||
rv = dict(currentIndex=status.index, playing=status.playing, gain=status.gain)
|
||||
if action == "get":
|
||||
playlist = []
|
||||
for path in status.playlist:
|
||||
try:
|
||||
playlist.append(Track.get(path=path))
|
||||
except ObjectNotFound:
|
||||
pass
|
||||
rv["entry"] = [
|
||||
t.as_subsonic_child(request.user, request.client) for t in playlist
|
||||
]
|
||||
return request.formatter("jukeboxPlaylist", rv)
|
||||
else:
|
||||
return request.formatter("jukeboxStatus", rv)
|
@ -119,6 +119,7 @@ class JukeboxResult(DaemonCommandResult):
|
||||
self.playing = jukebox.playing
|
||||
self.index = jukebox.index
|
||||
self.gain = jukebox.gain
|
||||
self.playlist = ()
|
||||
|
||||
|
||||
class DaemonClient(object):
|
||||
@ -159,9 +160,9 @@ class DaemonClient(object):
|
||||
with self.__get_connection() as c:
|
||||
c.send(ScannerStartCommand(folders, force))
|
||||
|
||||
def jukebox_control(self, action, *args):
|
||||
def jukebox_control(self, action, arg):
|
||||
if not isinstance(action, strtype):
|
||||
raise TypeError("Expecting string, got " + str(type(action)))
|
||||
with self.__get_connection() as c:
|
||||
c.send(JukeboxCommand(action, args))
|
||||
c.send(JukeboxCommand(action, arg))
|
||||
return c.recv()
|
||||
|
@ -37,7 +37,7 @@ class Daemon(object):
|
||||
|
||||
watcher = property(lambda self: self.__watcher)
|
||||
scanner = property(lambda self: self.__scanner)
|
||||
jukbox = property(lambda self: self.__jukebox)
|
||||
jukebox = property(lambda self: self.__jukebox)
|
||||
|
||||
def __handle_connection(self, connection):
|
||||
cmd = connection.recv()
|
||||
|
@ -11,7 +11,7 @@ import logging
|
||||
import shlex
|
||||
import time
|
||||
|
||||
from pony.orm import select
|
||||
from pony.orm import db_session, ObjectNotFound
|
||||
from random import shuffle
|
||||
from subprocess import Popen, DEVNULL
|
||||
from threading import Thread, Event, RLock
|
||||
@ -59,20 +59,22 @@ class Jukebox(object):
|
||||
self.__stop.set()
|
||||
|
||||
def skip(self, index):
|
||||
if not self.playing:
|
||||
return
|
||||
|
||||
if index < 0 or index >= len(self.__playlist):
|
||||
raise IndexError()
|
||||
|
||||
with self.__lock:
|
||||
self.__index = index - 1
|
||||
self.__skip.set()
|
||||
self.start()
|
||||
|
||||
def add(self, tracks):
|
||||
paths = select(t.path for t in Track if t.id in tracks)
|
||||
with self.__lock:
|
||||
self.__playlist += paths[:]
|
||||
with db_session:
|
||||
for t in tracks:
|
||||
try:
|
||||
self.__playlist.append(Track[t].path)
|
||||
except ObjectNotFound:
|
||||
pass
|
||||
|
||||
def clear(self):
|
||||
with self.__lock:
|
||||
@ -101,10 +103,11 @@ class Jukebox(object):
|
||||
self.__thread.join()
|
||||
|
||||
def __play_thread(self):
|
||||
proc = None
|
||||
while not self.__stop.is_set():
|
||||
if self.__skip.is_set():
|
||||
proc.terminate()
|
||||
proc.join()
|
||||
proc.wait()
|
||||
self.__skip.clear()
|
||||
|
||||
if proc is None or proc.poll() is not None:
|
||||
|
Loading…
Reference in New Issue
Block a user