mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06: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 .chat import *
|
||||||
from .search import *
|
from .search import *
|
||||||
from .playlists import *
|
from .playlists import *
|
||||||
|
from .jukebox import *
|
||||||
from .unsupported 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.playing = jukebox.playing
|
||||||
self.index = jukebox.index
|
self.index = jukebox.index
|
||||||
self.gain = jukebox.gain
|
self.gain = jukebox.gain
|
||||||
|
self.playlist = ()
|
||||||
|
|
||||||
|
|
||||||
class DaemonClient(object):
|
class DaemonClient(object):
|
||||||
@ -159,9 +160,9 @@ class DaemonClient(object):
|
|||||||
with self.__get_connection() as c:
|
with self.__get_connection() as c:
|
||||||
c.send(ScannerStartCommand(folders, force))
|
c.send(ScannerStartCommand(folders, force))
|
||||||
|
|
||||||
def jukebox_control(self, action, *args):
|
def jukebox_control(self, action, arg):
|
||||||
if not isinstance(action, strtype):
|
if not isinstance(action, strtype):
|
||||||
raise TypeError("Expecting string, got " + str(type(action)))
|
raise TypeError("Expecting string, got " + str(type(action)))
|
||||||
with self.__get_connection() as c:
|
with self.__get_connection() as c:
|
||||||
c.send(JukeboxCommand(action, args))
|
c.send(JukeboxCommand(action, arg))
|
||||||
return c.recv()
|
return c.recv()
|
||||||
|
@ -37,7 +37,7 @@ class Daemon(object):
|
|||||||
|
|
||||||
watcher = property(lambda self: self.__watcher)
|
watcher = property(lambda self: self.__watcher)
|
||||||
scanner = property(lambda self: self.__scanner)
|
scanner = property(lambda self: self.__scanner)
|
||||||
jukbox = property(lambda self: self.__jukebox)
|
jukebox = property(lambda self: self.__jukebox)
|
||||||
|
|
||||||
def __handle_connection(self, connection):
|
def __handle_connection(self, connection):
|
||||||
cmd = connection.recv()
|
cmd = connection.recv()
|
||||||
|
@ -11,7 +11,7 @@ import logging
|
|||||||
import shlex
|
import shlex
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from pony.orm import select
|
from pony.orm import db_session, ObjectNotFound
|
||||||
from random import shuffle
|
from random import shuffle
|
||||||
from subprocess import Popen, DEVNULL
|
from subprocess import Popen, DEVNULL
|
||||||
from threading import Thread, Event, RLock
|
from threading import Thread, Event, RLock
|
||||||
@ -59,20 +59,22 @@ class Jukebox(object):
|
|||||||
self.__stop.set()
|
self.__stop.set()
|
||||||
|
|
||||||
def skip(self, index):
|
def skip(self, index):
|
||||||
if not self.playing:
|
|
||||||
return
|
|
||||||
|
|
||||||
if index < 0 or index >= len(self.__playlist):
|
if index < 0 or index >= len(self.__playlist):
|
||||||
raise IndexError()
|
raise IndexError()
|
||||||
|
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
self.__index = index - 1
|
self.__index = index - 1
|
||||||
self.__skip.set()
|
self.__skip.set()
|
||||||
|
self.start()
|
||||||
|
|
||||||
def add(self, tracks):
|
def add(self, tracks):
|
||||||
paths = select(t.path for t in Track if t.id in tracks)
|
|
||||||
with self.__lock:
|
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):
|
def clear(self):
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
@ -101,10 +103,11 @@ class Jukebox(object):
|
|||||||
self.__thread.join()
|
self.__thread.join()
|
||||||
|
|
||||||
def __play_thread(self):
|
def __play_thread(self):
|
||||||
|
proc = None
|
||||||
while not self.__stop.is_set():
|
while not self.__stop.is_set():
|
||||||
if self.__skip.is_set():
|
if self.__skip.is_set():
|
||||||
proc.terminate()
|
proc.terminate()
|
||||||
proc.join()
|
proc.wait()
|
||||||
self.__skip.clear()
|
self.__skip.clear()
|
||||||
|
|
||||||
if proc is None or proc.poll() is not None:
|
if proc is None or proc.poll() is not None:
|
||||||
|
Loading…
Reference in New Issue
Block a user