Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@ -3,7 +3,7 @@ import pathlib
|
||||
|
||||
from mopidy import config, ext
|
||||
|
||||
__version__ = "3.51.0"
|
||||
__version__ = "3.52.4"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -38,6 +38,10 @@ class IrisCore(pykka.ThreadingActor):
|
||||
"seed_tracks": [],
|
||||
"results": [],
|
||||
}
|
||||
data = {
|
||||
"commands": [],
|
||||
"pinned": [],
|
||||
}
|
||||
ioloop = None
|
||||
|
||||
@classmethod
|
||||
@ -55,8 +59,9 @@ class IrisCore(pykka.ThreadingActor):
|
||||
def start(self):
|
||||
logger.info("Starting Iris " + Extension.version)
|
||||
|
||||
# Load our commands from file
|
||||
self.commands = self.load_from_file("commands")
|
||||
# Load our commands and pinned items from file
|
||||
self.data["commands"] = self.load_from_file("commands")
|
||||
self.data["pinned"] = self.load_from_file("pinned")
|
||||
|
||||
##
|
||||
# Mopidy is shutting down
|
||||
@ -79,7 +84,10 @@ class IrisCore(pykka.ThreadingActor):
|
||||
f.close()
|
||||
return content
|
||||
except Exception:
|
||||
return {}
|
||||
if name == "pinned":
|
||||
return []
|
||||
else:
|
||||
return {}
|
||||
|
||||
##
|
||||
# Save dict object to disk
|
||||
@ -654,6 +662,7 @@ class IrisCore(pykka.ThreadingActor):
|
||||
return response
|
||||
|
||||
async def load_more_tracks(self, *args, **kwargs):
|
||||
logger.info("Loading more radio tracks from Spotify")
|
||||
try:
|
||||
await self.get_spotify_token()
|
||||
spotify_token = self.spotify_token
|
||||
@ -702,7 +711,7 @@ class IrisCore(pykka.ThreadingActor):
|
||||
|
||||
except (urllib.error.HTTPError, urllib.error.URLError) as e:
|
||||
error = json.loads(e.read())
|
||||
error = {
|
||||
error_response = {
|
||||
"message": "Could not fetch Spotify recommendations: "
|
||||
+ error["error_description"]
|
||||
}
|
||||
@ -710,10 +719,10 @@ class IrisCore(pykka.ThreadingActor):
|
||||
"Could not fetch Spotify recommendations: "
|
||||
+ error["error_description"]
|
||||
)
|
||||
logger.debug(error)
|
||||
logger.debug(error_response)
|
||||
return False
|
||||
|
||||
def check_for_radio_update(self):
|
||||
async def check_for_radio_update(self):
|
||||
tracklistLength = self.core.tracklist.get_length().get()
|
||||
if tracklistLength < 3 and self.radio["enabled"] == 1:
|
||||
|
||||
@ -723,7 +732,7 @@ class IrisCore(pykka.ThreadingActor):
|
||||
# We've run out of pre-fetched tracks, so we need to get more
|
||||
# recommendations
|
||||
if len(uris) < 3:
|
||||
uris = self.load_more_tracks()
|
||||
uris = await self.load_more_tracks()
|
||||
|
||||
# Remove the next batch, and update our results
|
||||
self.radio["results"] = uris[3:]
|
||||
@ -822,49 +831,70 @@ class IrisCore(pykka.ThreadingActor):
|
||||
self.queue_metadata = cleaned_queue_metadata
|
||||
|
||||
##
|
||||
# Commands
|
||||
# Server-side data assets
|
||||
#
|
||||
# These are stored locally for all users to access
|
||||
# These functions are used internally to store data locally for all users to access
|
||||
##
|
||||
|
||||
def get_commands(self, *args, **kwargs):
|
||||
def get_data(self, name, *args, **kwargs):
|
||||
callback = kwargs.get("callback", False)
|
||||
|
||||
response = {"commands": self.commands}
|
||||
response = {name: self.data[name]}
|
||||
|
||||
if callback:
|
||||
callback(response)
|
||||
else:
|
||||
return response
|
||||
|
||||
def set_commands(self, *args, **kwargs):
|
||||
def set_data(self, name, *args, **kwargs):
|
||||
callback = kwargs.get("callback", False)
|
||||
data = kwargs.get("data", {})
|
||||
|
||||
# Update our temporary variable
|
||||
self.commands = data["commands"]
|
||||
self.data[name] = data[name]
|
||||
|
||||
# Save the new commands to file storage
|
||||
self.save_to_file(self.commands, "commands")
|
||||
self.save_to_file(self.data[name], name)
|
||||
|
||||
self.broadcast(
|
||||
data={
|
||||
"method": "commands_changed",
|
||||
"params": {"commands": self.commands},
|
||||
"method": f"{name}_changed",
|
||||
"params": {name: self.data[name]},
|
||||
}
|
||||
)
|
||||
|
||||
response = {"message": "Commands saved"}
|
||||
response = {"message": f"Saved {name}"}
|
||||
if callback:
|
||||
callback(response)
|
||||
else:
|
||||
return response
|
||||
|
||||
##
|
||||
# Pinned assets
|
||||
##
|
||||
|
||||
def get_pinned(self, *args, **kwargs):
|
||||
return self.get_data("pinned", *args, **kwargs)
|
||||
|
||||
def set_pinned(self, *args, **kwargs):
|
||||
return self.set_data("pinned", *args, **kwargs)
|
||||
|
||||
##
|
||||
# Commands
|
||||
##
|
||||
|
||||
def get_commands(self, *args, **kwargs):
|
||||
return self.get_data("commands", *args, **kwargs)
|
||||
|
||||
def set_commands(self, *args, **kwargs):
|
||||
return self.set_data("commands", *args, **kwargs)
|
||||
|
||||
async def run_command(self, *args, **kwargs):
|
||||
callback = kwargs.get("callback", False)
|
||||
data = kwargs.get("data", {})
|
||||
error = False
|
||||
|
||||
if str(data["id"]) not in self.commands:
|
||||
if str(data["id"]) not in self.data["commands"]:
|
||||
error = {
|
||||
"message": "Command failed",
|
||||
"description": "Could not find command by ID "
|
||||
@ -873,7 +903,7 @@ class IrisCore(pykka.ThreadingActor):
|
||||
+ '"',
|
||||
}
|
||||
else:
|
||||
command = self.commands[str(data["id"])]
|
||||
command = self.data["commands"][str(data["id"])]
|
||||
if "method" not in command:
|
||||
error = {
|
||||
"message": "Command failed",
|
||||
@ -991,14 +1021,24 @@ class IrisCore(pykka.ThreadingActor):
|
||||
async def refresh_spotify_token(self, *args, **kwargs):
|
||||
callback = kwargs.get("callback", None)
|
||||
|
||||
# Use client_id and client_secret from config
|
||||
# This was introduced in Mopidy-Spotify 3.1.0
|
||||
url = "https://auth.mopidy.com/spotify/token"
|
||||
data = {
|
||||
"client_id": self.config["spotify"]["client_id"],
|
||||
"client_secret": self.config["spotify"]["client_secret"],
|
||||
"grant_type": "client_credentials",
|
||||
}
|
||||
try:
|
||||
# Use client_id and client_secret from config
|
||||
# This was introduced in Mopidy-Spotify 3.1.0
|
||||
url = "https://auth.mopidy.com/spotify/token"
|
||||
data = {
|
||||
"client_id": self.config["spotify"]["client_id"],
|
||||
"client_secret": self.config["spotify"]["client_secret"],
|
||||
"grant_type": "client_credentials",
|
||||
}
|
||||
except (Exception):
|
||||
error = {
|
||||
"message": "Could not refresh Spotify token: invalid configuration"
|
||||
}
|
||||
|
||||
if callback:
|
||||
callback(False, error)
|
||||
else:
|
||||
return error
|
||||
|
||||
try:
|
||||
http_client = tornado.httpclient.AsyncHTTPClient()
|
||||
@ -1027,7 +1067,7 @@ class IrisCore(pykka.ThreadingActor):
|
||||
except (urllib.error.HTTPError, urllib.error.URLError) as e:
|
||||
error = json.loads(e.read())
|
||||
error = {
|
||||
"message": "Could not refresh token: "
|
||||
"message": "Could not refresh Spotify token: "
|
||||
+ error["error_description"]
|
||||
}
|
||||
|
||||
@ -1098,12 +1138,11 @@ class IrisCore(pykka.ThreadingActor):
|
||||
except (urllib.error.HTTPError, urllib.error.URLError) as e:
|
||||
error = json.loads(e.read())
|
||||
error = {
|
||||
"message": "Could not fetch Spotify recommendations: "
|
||||
"message": "Could not fetch Genius lyrics: "
|
||||
+ error["error_description"]
|
||||
}
|
||||
logger.error(
|
||||
"Could not fetch Spotify recommendations: "
|
||||
+ error["error_description"]
|
||||
"Could not fetch Genius lyrics: " + error["error_description"]
|
||||
)
|
||||
logger.debug(error)
|
||||
return error
|
||||
|
||||
@ -23,7 +23,13 @@ class IrisFrontend(pykka.ThreadingActor, CoreListener):
|
||||
iris.stop()
|
||||
|
||||
def track_playback_ended(self, tl_track, time_position):
|
||||
iris.ioloop.add_callback(functools.partial(iris.check_for_radio_update))
|
||||
if iris.ioloop:
|
||||
iris.ioloop.add_callback(
|
||||
functools.partial(iris.check_for_radio_update)
|
||||
)
|
||||
|
||||
def tracklist_changed(self):
|
||||
iris.ioloop.add_callback(functools.partial(iris.clean_queue_metadata))
|
||||
if iris.ioloop:
|
||||
iris.ioloop.add_callback(
|
||||
functools.partial(iris.clean_queue_metadata)
|
||||
)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
mopidy_iris/static/app.min.css
vendored
2
mopidy_iris/static/app.min.css
vendored
File diff suppressed because one or more lines are too long
49
mopidy_iris/static/app.min.js
vendored
49
mopidy_iris/static/app.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
mopidy_iris/static/assets/backgrounds/browse-mixcloud.jpg
Normal file
BIN
mopidy_iris/static/assets/backgrounds/browse-mixcloud.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -106,8 +106,8 @@
|
||||
|
||||
// Release details
|
||||
// These are automatically injected to built HTML
|
||||
var build = "1597898076";
|
||||
var version = "3.51.0";
|
||||
var build = "1598940390";
|
||||
var version = "3.52.4";
|
||||
|
||||
// Construct the script tag
|
||||
var js = document.createElement("script");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"manifest_version": "3.51.0",
|
||||
"manifest_version": "3.52.4",
|
||||
"short_name": "Iris",
|
||||
"name": "Iris",
|
||||
"icons": [
|
||||
|
||||
Reference in New Issue
Block a user