Merge branch 'master' into develop
This commit is contained in:
@ -1 +1 @@
|
||||
3.57.5
|
||||
3.57.6
|
||||
@ -4,6 +4,7 @@ Iris is an extension for the Mopidy music server. With support for Spotify, Last
|
||||
|
||||
Built and maintained by James Barnsley.
|
||||
|
||||
[](https://pepy.tech/project/mopidy-iris)
|
||||
[]()
|
||||

|
||||

|
||||
|
||||
@ -3,7 +3,7 @@ import pathlib
|
||||
|
||||
from mopidy import config, ext
|
||||
|
||||
__version__ = "3.57.5"
|
||||
__version__ = "3.57.6"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -135160,7 +135160,8 @@ var Button = function Button(_ref) {
|
||||
onClickProp = _ref.onClick,
|
||||
to = _ref.to,
|
||||
uri = _ref.uri,
|
||||
rest = _objectWithoutProperties(_ref, ["className", "primary", "type", "size", "icon", "pullRight", "colour", "confirming", "timingOut", "destructiveHover", "discrete", "working", "disabled", "noHover", "submit", "tracking", "href", "onClick", "to", "uri"]);
|
||||
uriType = _ref.uriType,
|
||||
rest = _objectWithoutProperties(_ref, ["className", "primary", "type", "size", "icon", "pullRight", "colour", "confirming", "timingOut", "destructiveHover", "discrete", "working", "disabled", "noHover", "submit", "tracking", "href", "onClick", "to", "uri", "uriType"]);
|
||||
|
||||
var classNames = [];
|
||||
|
||||
@ -135183,8 +135184,7 @@ var Button = function Button(_ref) {
|
||||
if (noHover) classNames.push('no-hover');
|
||||
var Element = 'button';
|
||||
if (to) Element = _Link__WEBPACK_IMPORTED_MODULE_1__["default"];
|
||||
if (uri) Element = _URILink__WEBPACK_IMPORTED_MODULE_2__["default"]; // MISSING URI TYPE
|
||||
|
||||
if (uri) Element = _URILink__WEBPACK_IMPORTED_MODULE_2__["default"];
|
||||
if (href) Element = 'a';
|
||||
|
||||
var onClick = function onClick(e) {
|
||||
@ -135199,7 +135199,7 @@ var Button = function Button(_ref) {
|
||||
};
|
||||
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Element, _extends({
|
||||
type: submit ? 'submit' : 'button',
|
||||
type: uri ? uriType : submit ? 'submit' : 'button',
|
||||
className: "button ".concat(className, " ").concat(classNames.map(function (s) {
|
||||
return " button--".concat(s);
|
||||
}).join(' ')),
|
||||
@ -139066,25 +139066,6 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _locale__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../locale */ "./src/js/locale/index.js");
|
||||
/* harmony import */ var _Button__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../Button */ "./src/js/components/Button.js");
|
||||
/* harmony import */ var _util_selectors__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../util/selectors */ "./src/js/util/selectors.js");
|
||||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
|
||||
|
||||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
|
||||
|
||||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
|
||||
|
||||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
|
||||
|
||||
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
||||
|
||||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
||||
|
||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
|
||||
|
||||
|
||||
@ -139095,106 +139076,77 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
||||
|
||||
|
||||
|
||||
var FollowButton = function FollowButton(_ref) {
|
||||
var following = _ref.spotifyActions.following,
|
||||
createNotification = _ref.uiActions.createNotification,
|
||||
uri = _ref.uri,
|
||||
addText = _ref.addText,
|
||||
removeText = _ref.removeText,
|
||||
spotify_authorized = _ref.spotify_authorized,
|
||||
is_following = _ref.is_following,
|
||||
loading = _ref.loading;
|
||||
|
||||
var FollowButton = /*#__PURE__*/function (_React$Component) {
|
||||
_inherits(FollowButton, _React$Component);
|
||||
var remove = function remove() {
|
||||
return following(uri, 'DELETE');
|
||||
};
|
||||
|
||||
var _super = _createSuper(FollowButton);
|
||||
var add = function add() {
|
||||
return following(uri, 'PUT');
|
||||
};
|
||||
|
||||
function FollowButton() {
|
||||
var _this;
|
||||
|
||||
_classCallCheck(this, FollowButton);
|
||||
|
||||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
||||
args[_key] = arguments[_key];
|
||||
}
|
||||
|
||||
_this = _super.call.apply(_super, [this].concat(args));
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "remove", function () {
|
||||
var _this$props = _this.props,
|
||||
actions = _this$props.spotifyActions,
|
||||
uri = _this$props.uri;
|
||||
actions.following(uri, 'DELETE');
|
||||
var unauthorized = function unauthorized() {
|
||||
return createNotification({
|
||||
content: Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('errors.authorization_required', {
|
||||
provider: Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('services.spotify.title')
|
||||
}),
|
||||
level: 'warning'
|
||||
});
|
||||
};
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "add", function () {
|
||||
var _this$props2 = _this.props,
|
||||
actions = _this$props2.spotifyActions,
|
||||
uri = _this$props2.uri;
|
||||
actions.following(uri, 'PUT');
|
||||
});
|
||||
if (!uri) return null;
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "unauthorized", function () {
|
||||
var createNotification = _this.props.uiActions.createNotification;
|
||||
createNotification({
|
||||
content: Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('errors.authorization_required', {
|
||||
provider: Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('services.spotify.title')
|
||||
}),
|
||||
level: 'warning'
|
||||
});
|
||||
});
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "render", function () {
|
||||
var _this$props3 = _this.props,
|
||||
uri = _this$props3.uri,
|
||||
addText = _this$props3.addText,
|
||||
removeText = _this$props3.removeText,
|
||||
spotify_authorized = _this$props3.spotify_authorized,
|
||||
is_following = _this$props3.is_following,
|
||||
loading = _this$props3.loading;
|
||||
if (!uri) return null;
|
||||
|
||||
if (!spotify_authorized) {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Button__WEBPACK_IMPORTED_MODULE_7__["Button"], {
|
||||
disabled: true,
|
||||
working: loading,
|
||||
onClick: _this.unauthorized,
|
||||
tracking: {
|
||||
category: 'FollowButton',
|
||||
action: 'Add (disabled)'
|
||||
},
|
||||
"data-qa-node": "Button",
|
||||
"data-qa-file": "FollowButton"
|
||||
}, addText || Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('actions.add_to_library'));
|
||||
}
|
||||
|
||||
if (is_following === true) {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Button__WEBPACK_IMPORTED_MODULE_7__["Button"], {
|
||||
type: "destructive",
|
||||
working: loading,
|
||||
onClick: _this.remove,
|
||||
tracking: {
|
||||
category: 'FollowButton',
|
||||
action: 'Remove'
|
||||
},
|
||||
"data-qa-node": "Button",
|
||||
"data-qa-file": "FollowButton"
|
||||
}, removeText || Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('actions.remove_from_library'));
|
||||
}
|
||||
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Button__WEBPACK_IMPORTED_MODULE_7__["Button"], {
|
||||
onClick: _this.add,
|
||||
working: loading,
|
||||
tracking: {
|
||||
category: 'FollowButton',
|
||||
action: 'Add'
|
||||
},
|
||||
"data-qa-node": "Button",
|
||||
"data-qa-file": "FollowButton"
|
||||
}, addText || Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('actions.add_to_library'));
|
||||
});
|
||||
|
||||
return _this;
|
||||
if (!spotify_authorized) {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Button__WEBPACK_IMPORTED_MODULE_7__["Button"], {
|
||||
disabled: true,
|
||||
working: loading,
|
||||
onClick: unauthorized,
|
||||
tracking: {
|
||||
category: 'FollowButton',
|
||||
action: 'Add (disabled)'
|
||||
},
|
||||
"data-qa-node": "Button",
|
||||
"data-qa-file": "FollowButton"
|
||||
}, addText || Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('actions.add_to_library'));
|
||||
}
|
||||
|
||||
return FollowButton;
|
||||
}(react__WEBPACK_IMPORTED_MODULE_0___default.a.Component);
|
||||
if (is_following === true) {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Button__WEBPACK_IMPORTED_MODULE_7__["Button"], {
|
||||
type: "destructive",
|
||||
working: loading,
|
||||
onClick: remove,
|
||||
tracking: {
|
||||
category: 'FollowButton',
|
||||
action: 'Remove'
|
||||
},
|
||||
"data-qa-node": "Button",
|
||||
"data-qa-file": "FollowButton"
|
||||
}, removeText || Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('actions.remove_from_library'));
|
||||
}
|
||||
|
||||
var mapStateToProps = function mapStateToProps(state, ownProps) {
|
||||
var uri = ownProps.uri;
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_8__["makeLoadingSelector"])(['spotify_me/tracks?', 'spotify_me/albums?', 'spotify_me/following?', "spotify_playlists/".concat(Object(_util_helpers__WEBPACK_IMPORTED_MODULE_5__["getFromUri"])('playlistid', uri), "/followers?")]);
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Button__WEBPACK_IMPORTED_MODULE_7__["Button"], {
|
||||
onClick: add,
|
||||
working: loading,
|
||||
tracking: {
|
||||
category: 'FollowButton',
|
||||
action: 'Add'
|
||||
},
|
||||
"data-qa-node": "Button",
|
||||
"data-qa-file": "FollowButton"
|
||||
}, addText || Object(_locale__WEBPACK_IMPORTED_MODULE_6__["i18n"])('actions.add_to_library'));
|
||||
};
|
||||
|
||||
var mapStateToProps = function mapStateToProps(state) {
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_8__["makeLoadingSelector"])(['(.*)(follow)|(me\/albums)(.*)']);
|
||||
return {
|
||||
loading: loadingSelector(state),
|
||||
spotify_authorized: state.spotify.authorization
|
||||
@ -145155,7 +145107,8 @@ var SearchResults = function SearchResults(_ref) {
|
||||
"data-qa-file": "SearchResults"
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_URILink__WEBPACK_IMPORTED_MODULE_3__["default"], {
|
||||
uri: "iris:search:all:".concat(encodedTerm),
|
||||
type: "search",
|
||||
uriType: "search",
|
||||
unencoded: true,
|
||||
"data-qa-node": "URILink",
|
||||
"data-qa-file": "SearchResults"
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_7__["I18n"], {
|
||||
@ -145173,7 +145126,8 @@ var SearchResults = function SearchResults(_ref) {
|
||||
"data-qa-file": "SearchResults"
|
||||
})), all && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_URILink__WEBPACK_IMPORTED_MODULE_3__["default"], {
|
||||
uri: "iris:search:".concat(type, ":").concat(encodedTerm),
|
||||
type: "search",
|
||||
uriType: "search",
|
||||
unencoded: true,
|
||||
"data-qa-node": "URILink",
|
||||
"data-qa-file": "SearchResults"
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_7__["I18n"], {
|
||||
@ -145210,7 +145164,8 @@ var SearchResults = function SearchResults(_ref) {
|
||||
"data-qa-file": "SearchResults"
|
||||
}), resultsCount > results.length && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Button__WEBPACK_IMPORTED_MODULE_8__["default"], {
|
||||
uri: "iris:search:".concat(type, ":").concat(encodedTerm),
|
||||
debug: true,
|
||||
uriType: "search",
|
||||
unencoded: true,
|
||||
"data-qa-node": "Button",
|
||||
"data-qa-file": "SearchResults"
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_locale__WEBPACK_IMPORTED_MODULE_7__["I18n"], {
|
||||
@ -150609,15 +150564,16 @@ __webpack_require__.r(__webpack_exports__);
|
||||
|
||||
|
||||
|
||||
/* harmony default export */ __webpack_exports__["default"] = (/*#__PURE__*/Object(react__WEBPACK_IMPORTED_MODULE_0__["memo"])(function (props) {
|
||||
/* harmony default export */ __webpack_exports__["default"] = (/*#__PURE__*/Object(react__WEBPACK_IMPORTED_MODULE_0__["memo"])(function (_ref) {
|
||||
var type = _ref.type,
|
||||
rawUri = _ref.uri,
|
||||
className = _ref.className,
|
||||
handleContextMenu = _ref.handleContextMenu,
|
||||
children = _ref.children,
|
||||
unencoded = _ref.unencoded;
|
||||
var to = null;
|
||||
var uri = props.uri,
|
||||
type = props.type;
|
||||
var uriType = type || Object(_util_helpers__WEBPACK_IMPORTED_MODULE_2__["uriType"])(uri);
|
||||
|
||||
if (!props.unencoded) {
|
||||
uri = Object(_util_format__WEBPACK_IMPORTED_MODULE_3__["encodeUri"])(uri);
|
||||
}
|
||||
var uriType = type || Object(_util_helpers__WEBPACK_IMPORTED_MODULE_2__["uriType"])(rawUri);
|
||||
var uri = !unencoded ? Object(_util_format__WEBPACK_IMPORTED_MODULE_3__["encodeUri"])(rawUri) : rawUri;
|
||||
|
||||
switch (uriType) {
|
||||
case 'playlist':
|
||||
@ -150649,7 +150605,7 @@ __webpack_require__.r(__webpack_exports__);
|
||||
break;
|
||||
|
||||
case 'search':
|
||||
var exploded = uri.split('%3A');
|
||||
var exploded = uri.split(':');
|
||||
to = "/search/".concat(exploded[2], "/").concat(exploded[3]);
|
||||
break;
|
||||
|
||||
@ -150659,21 +150615,19 @@ __webpack_require__.r(__webpack_exports__);
|
||||
|
||||
if (uri) {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Link__WEBPACK_IMPORTED_MODULE_1__["default"], {
|
||||
className: props.className ? props.className : null,
|
||||
className: className,
|
||||
to: to,
|
||||
onContextMenu: function onContextMenu(e) {
|
||||
return props.handleContextMenu ? props.handleContextMenu(e) : null;
|
||||
},
|
||||
onContextMenu: handleContextMenu,
|
||||
"data-qa-node": "Link",
|
||||
"data-qa-file": "URILink"
|
||||
}, props.children);
|
||||
}, children);
|
||||
}
|
||||
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
|
||||
className: props.className ? props.className : null,
|
||||
className: className,
|
||||
"data-qa-node": "span",
|
||||
"data-qa-file": "URILink"
|
||||
}, props.children);
|
||||
}, children);
|
||||
}));
|
||||
|
||||
/***/ }),
|
||||
@ -152356,7 +152310,10 @@ var CoreMiddleware = function () {
|
||||
})));
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.removeItem(action.itemUri));
|
||||
store.dispatch(coreActions.itemLoaded({
|
||||
uri: action.itemUri,
|
||||
in_library: false
|
||||
}));
|
||||
localforage__WEBPACK_IMPORTED_MODULE_2___default.a.removeItem(action.itemUri);
|
||||
next(action);
|
||||
break;
|
||||
@ -159612,7 +159569,7 @@ function following(uri) {
|
||||
content: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
|
||||
"data-qa-node": "span",
|
||||
"data-qa-file": "actions"
|
||||
}, "Removed", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_URILink__WEBPACK_IMPORTED_MODULE_4__["default"], {
|
||||
}, "Removed", ' ', /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_URILink__WEBPACK_IMPORTED_MODULE_4__["default"], {
|
||||
type: type,
|
||||
uri: uri,
|
||||
"data-qa-node": "URILink",
|
||||
@ -159625,7 +159582,7 @@ function following(uri) {
|
||||
content: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
|
||||
"data-qa-node": "span",
|
||||
"data-qa-file": "actions"
|
||||
}, "Added", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_URILink__WEBPACK_IMPORTED_MODULE_4__["default"], {
|
||||
}, "Added", ' ', /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_URILink__WEBPACK_IMPORTED_MODULE_4__["default"], {
|
||||
type: type,
|
||||
uri: uri,
|
||||
"data-qa-node": "URILink",
|
||||
@ -165470,7 +165427,7 @@ var Album = /*#__PURE__*/function (_React$Component) {
|
||||
var mapStateToProps = function mapStateToProps(state, ownProps) {
|
||||
var uri = Object(_util_format__WEBPACK_IMPORTED_MODULE_26__["decodeUri"])(ownProps.match.params.uri);
|
||||
var itemSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_23__["makeItemSelector"])(uri);
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_23__["makeLoadingSelector"])(["(.*)".concat(uri, "(.*)"), '^((?!contains).)*$', '^((?!me\/albums).)*$']);
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_23__["makeLoadingSelector"])(["(.*)".concat(uri, "(.*)"), '^((?!contains).)*$', '^((?!me\/albums).)*$', '^((?!followers).)*$']);
|
||||
return {
|
||||
uri: uri,
|
||||
slim_mode: state.ui.slim_mode,
|
||||
@ -166363,7 +166320,7 @@ var Artist = /*#__PURE__*/function (_React$Component) {
|
||||
|
||||
var mapStateToProps = function mapStateToProps(state, props) {
|
||||
var uri = Object(_util_format__WEBPACK_IMPORTED_MODULE_21__["decodeUri"])(props.match.params.uri);
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_26__["makeLoadingSelector"])(["(.*)".concat(uri, "(.*)"), '^((?!contains).)*$', '^((?!albums).)*$', '^((?!related-artists).)*$', '^((?!top-tracks).)*$']);
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_26__["makeLoadingSelector"])(["(.*)".concat(uri, "(.*)"), '^((?!contains).)*$', '^((?!albums).)*$', '^((?!related-artists).)*$', '^((?!top-tracks).)*$', '^((?!following).)*$']);
|
||||
var artistSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_26__["makeItemSelector"])(uri);
|
||||
var artist = artistSelector(state);
|
||||
var albums = null;
|
||||
@ -167850,7 +167807,7 @@ var mapStateToProps = function mapStateToProps(state, ownProps) {
|
||||
var local_library_playlists = _state$mopidy.library_playlists;
|
||||
var uri = Object(_util_format__WEBPACK_IMPORTED_MODULE_26__["decodeUri"])(ownProps.match.params.uri);
|
||||
var itemSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_24__["makeItemSelector"])(uri);
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_24__["makeLoadingSelector"])(["(.*)".concat(uri, "(.*)"), '^((?!contains).)*$', '^((?!tracks).)*$']);
|
||||
var loadingSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_24__["makeLoadingSelector"])(["(.*)".concat(uri, "(.*)"), '^((?!contains).)*$', '^((?!tracks).)*$', '^((?!followers).)*$']);
|
||||
var loadingTracksSelector = Object(_util_selectors__WEBPACK_IMPORTED_MODULE_24__["makeLoadingSelector"])(["(.*)".concat(uri, "(.*)tracks(.*)")]);
|
||||
return {
|
||||
uri: uri,
|
||||
|
||||
File diff suppressed because one or more lines are too long
8
mopidy_iris/static/app.min.js
vendored
8
mopidy_iris/static/app.min.js
vendored
File diff suppressed because one or more lines are too long
@ -106,8 +106,8 @@
|
||||
|
||||
// Release details
|
||||
// These are automatically injected to built HTML
|
||||
var build = "1617608354";
|
||||
var version = "3.57.5";
|
||||
var build = "1618219813";
|
||||
var version = "3.57.6";
|
||||
|
||||
// Construct the script tag
|
||||
var js = document.createElement("script");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"manifest_version": "3.57.5",
|
||||
"manifest_version": "3.57.6",
|
||||
"short_name": "Iris",
|
||||
"name": "Iris",
|
||||
"icons": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mopidy-iris",
|
||||
"version": "3.57.5",
|
||||
"version": "3.57.6",
|
||||
"description": "Mopidy HTTP interface",
|
||||
"repository": "https://github.com/jaedb/iris",
|
||||
"author": "James Barnsley <james@barnsley.nz>",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = Mopidy-Iris
|
||||
version = 3.57.5
|
||||
version = 3.57.6
|
||||
url = https://github.com/jaedb/iris
|
||||
author = James Barnsley
|
||||
author_email = james@barnsley.nz
|
||||
|
||||
@ -24,6 +24,7 @@ const Button = ({
|
||||
onClick: onClickProp,
|
||||
to,
|
||||
uri,
|
||||
uriType,
|
||||
...rest
|
||||
}) => {
|
||||
const classNames = [];
|
||||
@ -46,7 +47,7 @@ const Button = ({
|
||||
|
||||
let Element = 'button';
|
||||
if (to) Element = Link;
|
||||
if (uri) Element = URILink; // MISSING URI TYPE
|
||||
if (uri) Element = URILink;
|
||||
if (href) Element = 'a';
|
||||
|
||||
const onClick = (e) => {
|
||||
@ -63,7 +64,7 @@ const Button = ({
|
||||
|
||||
return (
|
||||
<Element
|
||||
type={submit ? 'submit' : 'button'}
|
||||
type={uri ? uriType : (submit ? 'submit' : 'button')}
|
||||
className={`button ${className} ${classNames.map((s) => ` button--${s}`).join(' ')}`}
|
||||
disabled={disabled}
|
||||
to={to}
|
||||
|
||||
@ -3,89 +3,70 @@ import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import { isLoading, getFromUri } from '../../util/helpers';
|
||||
import { getFromUri } from '../../util/helpers';
|
||||
import { i18n } from '../../locale';
|
||||
import { Button } from '../Button';
|
||||
import { makeLoadingSelector } from '../../util/selectors';
|
||||
|
||||
class FollowButton extends React.Component {
|
||||
remove = () => {
|
||||
const { spotifyActions: actions, uri } = this.props;
|
||||
actions.following(uri, 'DELETE');
|
||||
}
|
||||
const FollowButton = ({
|
||||
spotifyActions: {
|
||||
following,
|
||||
},
|
||||
uiActions: {
|
||||
createNotification,
|
||||
},
|
||||
uri,
|
||||
addText,
|
||||
removeText,
|
||||
spotify_authorized,
|
||||
is_following,
|
||||
loading,
|
||||
}) => {
|
||||
const remove = () => following(uri, 'DELETE');
|
||||
const add = () => following(uri, 'PUT');
|
||||
const unauthorized = () => createNotification({
|
||||
content: i18n('errors.authorization_required', { provider: i18n('services.spotify.title') }),
|
||||
level: 'warning',
|
||||
});
|
||||
|
||||
add = () => {
|
||||
const { spotifyActions: actions, uri } = this.props;
|
||||
actions.following(uri, 'PUT');
|
||||
}
|
||||
if (!uri) return null;
|
||||
|
||||
unauthorized = () => {
|
||||
const { uiActions: { createNotification } } = this.props;
|
||||
|
||||
createNotification({
|
||||
content: i18n('errors.authorization_required', { provider: i18n('services.spotify.title') }),
|
||||
level: 'warning',
|
||||
});
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const {
|
||||
uri,
|
||||
addText,
|
||||
removeText,
|
||||
spotify_authorized,
|
||||
is_following,
|
||||
loading,
|
||||
} = this.props;
|
||||
|
||||
if (!uri) return null;
|
||||
|
||||
if (!spotify_authorized) {
|
||||
return (
|
||||
<Button
|
||||
disabled
|
||||
working={loading}
|
||||
onClick={this.unauthorized}
|
||||
tracking={{ category: 'FollowButton', action: 'Add (disabled)' }}
|
||||
>
|
||||
{addText || i18n('actions.add_to_library')}
|
||||
</Button>
|
||||
);
|
||||
} if (is_following === true) {
|
||||
return (
|
||||
<Button
|
||||
type="destructive"
|
||||
working={loading}
|
||||
onClick={this.remove}
|
||||
tracking={{ category: 'FollowButton', action: 'Remove' }}
|
||||
>
|
||||
{removeText || i18n('actions.remove_from_library')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
if (!spotify_authorized) {
|
||||
return (
|
||||
<Button
|
||||
onClick={this.add}
|
||||
disabled
|
||||
working={loading}
|
||||
tracking={{ category: 'FollowButton', action: 'Add' }}
|
||||
onClick={unauthorized}
|
||||
tracking={{ category: 'FollowButton', action: 'Add (disabled)' }}
|
||||
>
|
||||
{addText || i18n('actions.add_to_library')}
|
||||
</Button>
|
||||
);
|
||||
} if (is_following === true) {
|
||||
return (
|
||||
<Button
|
||||
type="destructive"
|
||||
working={loading}
|
||||
onClick={remove}
|
||||
tracking={{ category: 'FollowButton', action: 'Remove' }}
|
||||
>
|
||||
{removeText || i18n('actions.remove_from_library')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
onClick={add}
|
||||
working={loading}
|
||||
tracking={{ category: 'FollowButton', action: 'Add' }}
|
||||
>
|
||||
{addText || i18n('actions.add_to_library')}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const {
|
||||
uri,
|
||||
} = ownProps;
|
||||
|
||||
const loadingSelector = makeLoadingSelector([
|
||||
'spotify_me/tracks?',
|
||||
'spotify_me/albums?',
|
||||
'spotify_me/following?',
|
||||
`spotify_playlists/${getFromUri('playlistid', uri)}/followers?`,
|
||||
]);
|
||||
const mapStateToProps = (state) => {
|
||||
const loadingSelector = makeLoadingSelector(['(.*)(follow)|(me\/albums)(.*)']);
|
||||
|
||||
return {
|
||||
loading: loadingSelector(state),
|
||||
|
||||
@ -56,7 +56,7 @@ const SearchResults = ({
|
||||
<h4>
|
||||
{!all && (
|
||||
<span>
|
||||
<URILink uri={`iris:search:all:${encodedTerm}`} type="search">
|
||||
<URILink uri={`iris:search:all:${encodedTerm}`} uriType="search" unencoded>
|
||||
<I18n path="search.title" />
|
||||
</URILink>
|
||||
{' '}
|
||||
@ -66,7 +66,7 @@ const SearchResults = ({
|
||||
</span>
|
||||
)}
|
||||
{all && (
|
||||
<URILink uri={`iris:search:${type}:${encodedTerm}`} type="search">
|
||||
<URILink uri={`iris:search:${type}:${encodedTerm}`} uriType="search" unencoded>
|
||||
<I18n path={`search.${type}.title`} />
|
||||
</URILink>
|
||||
)}
|
||||
@ -79,7 +79,7 @@ const SearchResults = ({
|
||||
{/* <LazyLoadListener enabled={this.props.artists_more && spotify_search_enabled} loadMore={loadMore} /> */}
|
||||
|
||||
{resultsCount > results.length && (
|
||||
<Button uri={`iris:search:${type}:${encodedTerm}`} debug>
|
||||
<Button uri={`iris:search:${type}:${encodedTerm}`} uriType="search" unencoded>
|
||||
<I18n path={`search.${type}.more`} count={resultsCount} />
|
||||
</Button>
|
||||
)}
|
||||
@ -89,7 +89,12 @@ const SearchResults = ({
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const { query: { term }, type } = ownProps;
|
||||
const {
|
||||
query: {
|
||||
term,
|
||||
},
|
||||
type,
|
||||
} = ownProps;
|
||||
const {
|
||||
ui: {
|
||||
uri_schemes_priority = [],
|
||||
|
||||
@ -3,13 +3,17 @@ import Link from './Link';
|
||||
import { uriType as uriTypeHelper } from '../util/helpers';
|
||||
import { encodeUri } from '../util/format';
|
||||
|
||||
export default memo((props) => {
|
||||
export default memo(({
|
||||
type,
|
||||
uri: rawUri,
|
||||
className,
|
||||
handleContextMenu,
|
||||
children,
|
||||
unencoded,
|
||||
}) => {
|
||||
let to = null;
|
||||
let { uri, type } = props;
|
||||
const uriType = type || uriTypeHelper(uri);
|
||||
if (!props.unencoded) {
|
||||
uri = encodeUri(uri);
|
||||
}
|
||||
const uriType = type || uriTypeHelper(rawUri);
|
||||
const uri = (!unencoded) ? encodeUri(rawUri) : rawUri;
|
||||
|
||||
switch (uriType) {
|
||||
case 'playlist':
|
||||
@ -41,7 +45,7 @@ export default memo((props) => {
|
||||
break;
|
||||
|
||||
case 'search':
|
||||
var exploded = uri.split('%3A');
|
||||
var exploded = uri.split(':');
|
||||
to = `/search/${exploded[2]}/${exploded[3]}`;
|
||||
break;
|
||||
|
||||
@ -52,17 +56,17 @@ export default memo((props) => {
|
||||
if (uri) {
|
||||
return (
|
||||
<Link
|
||||
className={props.className ? props.className : null}
|
||||
className={className}
|
||||
to={to}
|
||||
onContextMenu={(e) => (props.handleContextMenu ? props.handleContextMenu(e) : null)}
|
||||
onContextMenu={handleContextMenu}
|
||||
>
|
||||
{props.children}
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span className={props.className ? props.className : null}>
|
||||
{props.children}
|
||||
<span className={className}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
@ -628,10 +628,11 @@ const CoreMiddleware = (function () {
|
||||
items_uris,
|
||||
}));
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.removeItem(action.itemUri));
|
||||
store.dispatch(coreActions.itemLoaded({
|
||||
uri: action.itemUri,
|
||||
in_library: false,
|
||||
}));
|
||||
localForage.removeItem(action.itemUri);
|
||||
|
||||
next(action);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -809,21 +809,23 @@ export function following(uri, method = 'GET') {
|
||||
if (method === 'DELETE') {
|
||||
dispatch(coreActions.removeFromLibrary(`spotify:library:${type}s`, uri));
|
||||
dispatch(uiActions.createNotification({
|
||||
content: <span>
|
||||
Removed
|
||||
<URILink type={type} uri={uri}>{asset ? asset.name : type}</URILink>
|
||||
{' '}
|
||||
from library
|
||||
content: <span>
|
||||
Removed
|
||||
{' '}
|
||||
<URILink type={type} uri={uri}>{asset ? asset.name : type}</URILink>
|
||||
{' '}
|
||||
from library
|
||||
</span>,
|
||||
}));
|
||||
} else if (method === 'PUT' || method === 'POST') {
|
||||
dispatch(coreActions.addToLibrary(`spotify:library:${type}s`, asset));
|
||||
dispatch(uiActions.createNotification({
|
||||
content: <span>
|
||||
Added
|
||||
<URILink type={type} uri={uri}>{asset ? asset.name : type}</URILink>
|
||||
{' '}
|
||||
to library
|
||||
content: <span>
|
||||
Added
|
||||
{' '}
|
||||
<URILink type={type} uri={uri}>{asset ? asset.name : type}</URILink>
|
||||
{' '}
|
||||
to library
|
||||
</span>,
|
||||
}));
|
||||
}
|
||||
@ -929,11 +931,11 @@ export function getArtist(uri, { full, forceRefetch } = {}) {
|
||||
);
|
||||
|
||||
// Do we want a full artist, with all supporting material?
|
||||
if (full) {
|
||||
if (full) {
|
||||
// All albums (gets all pages, may take some time to iterate them all)
|
||||
let albums = [];
|
||||
const fetchAlbums = (endpoint) => request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
const fetchAlbums = (endpoint) => request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
})
|
||||
.then((response) => {
|
||||
albums = [...albums, ...formatAlbums(response.items)];
|
||||
@ -953,8 +955,8 @@ export function getArtist(uri, { full, forceRefetch } = {}) {
|
||||
let tracksEndpoint = `artists/${getFromUri('artistid', uri)}`;
|
||||
tracksEndpoint += `/top-tracks?country=${getState().spotify.country}`;
|
||||
if (forceRefetch) tracksEndpoint += `&refetch=${Date.now()}`;
|
||||
request({
|
||||
dispatch, getState, endpoint: tracksEndpoint, uri,
|
||||
request({
|
||||
dispatch, getState, endpoint: tracksEndpoint, uri,
|
||||
})
|
||||
.then(
|
||||
(response) => {
|
||||
@ -968,8 +970,8 @@ export function getArtist(uri, { full, forceRefetch } = {}) {
|
||||
// Related artists
|
||||
let relatedEndpoint = `artists/${getFromUri('artistid', uri)}/related-artists`;
|
||||
if (forceRefetch) relatedEndpoint += `?refetch=${Date.now()}`;
|
||||
request({
|
||||
dispatch, getState, endpoint: relatedEndpoint, uri,
|
||||
request({
|
||||
dispatch, getState, endpoint: relatedEndpoint, uri,
|
||||
})
|
||||
.then(
|
||||
(response) => {
|
||||
@ -1049,8 +1051,8 @@ export function getUser(uri, { full, forceRefetch } = {}) {
|
||||
|
||||
if (full) {
|
||||
let playlists = [];
|
||||
const fetchPlaylists = (endpoint) => request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
const fetchPlaylists = (endpoint) => request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
})
|
||||
.then((response) => {
|
||||
playlists = [...playlists, ...formatPlaylists(response.items)];
|
||||
@ -1115,7 +1117,7 @@ export function getAlbum(uri, { full, forceRefetch } = {}) {
|
||||
tracks,
|
||||
}));
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.tracks.next) {
|
||||
@ -1276,8 +1278,8 @@ export function getPlaylistTracks(uri, { forceRefetch, callbackAction } = {}) {
|
||||
|
||||
let tracks = [];
|
||||
|
||||
const fetchTracks = (endpoint) => request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
const fetchTracks = (endpoint) => request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
})
|
||||
.then((response) => {
|
||||
tracks = [...tracks, ...formatTracks(response.items)];
|
||||
@ -1333,8 +1335,8 @@ export function getPlaylist(uri, options = {}) {
|
||||
endpoint += `?market=${getState().spotify.country}`;
|
||||
if (forceRefetch) endpoint += `&refetch=${Date.now()}`;
|
||||
|
||||
request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
request({
|
||||
dispatch, getState, endpoint, uri,
|
||||
})
|
||||
.then(
|
||||
(response) => {
|
||||
|
||||
@ -348,7 +348,7 @@ class Album extends React.Component {
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const uri = decodeUri(ownProps.match.params.uri);
|
||||
const itemSelector = makeItemSelector(uri);
|
||||
const loadingSelector = makeLoadingSelector([`(.*)${uri}(.*)`, '^((?!contains).)*$', '^((?!me\/albums).)*$']);
|
||||
const loadingSelector = makeLoadingSelector([`(.*)${uri}(.*)`, '^((?!contains).)*$', '^((?!me\/albums).)*$', '^((?!followers).)*$']);
|
||||
return {
|
||||
uri,
|
||||
slim_mode: state.ui.slim_mode,
|
||||
|
||||
@ -602,7 +602,7 @@ class Artist extends React.Component {
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const uri = decodeUri(props.match.params.uri);
|
||||
const loadingSelector = makeLoadingSelector([`(.*)${uri}(.*)`, '^((?!contains).)*$', '^((?!albums).)*$', '^((?!related-artists).)*$', '^((?!top-tracks).)*$']);
|
||||
const loadingSelector = makeLoadingSelector([`(.*)${uri}(.*)`, '^((?!contains).)*$', '^((?!albums).)*$', '^((?!related-artists).)*$', '^((?!top-tracks).)*$', '^((?!following).)*$']);
|
||||
const artistSelector = makeItemSelector(uri);
|
||||
const artist = artistSelector(state);
|
||||
let albums = null;
|
||||
|
||||
@ -496,7 +496,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const uri = decodeUri(ownProps.match.params.uri);
|
||||
const itemSelector = makeItemSelector(uri);
|
||||
const loadingSelector = makeLoadingSelector([`(.*)${uri}(.*)`, '^((?!contains).)*$', '^((?!tracks).)*$']);
|
||||
const loadingSelector = makeLoadingSelector([`(.*)${uri}(.*)`, '^((?!contains).)*$', '^((?!tracks).)*$', '^((?!followers).)*$']);
|
||||
const loadingTracksSelector = makeLoadingSelector([`(.*)${uri}(.*)tracks(.*)`]);
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user