Fully-functional artists and albums for Google - no such luck for Playlists...

This commit is contained in:
James Barnsley
2018-10-17 21:33:54 +13:00
parent 0f4272d0df
commit 056af9d5bf
10 changed files with 1366 additions and 862 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -98,7 +98,7 @@
// Release details
// These are automatically injected to built HTML
var build = "1539675069";
var build = "1539759871";
var version = "3.28.1";
// Construct the script tag

View File

@ -7,7 +7,25 @@ export function set(data){
}
export function getLibraryArtists(){
return {
type: 'GOOGLE_GET_LIBRARY_ARTISTS'
}
}
export function clearLibraryArtists(){
return {
type: 'GOOGLE_CLEAR_LIBRARY_ARTISTS'
}
}
export function getLibraryAlbums(){
return {
'type': 'GOOGLE_GET_LIBRARY_ARTISTS'
'type': 'GOOGLE_GET_LIBRARY_ALBUMS'
}
}
export function clearLibraryAlbums(){
return {
type: 'GOOGLE_CLEAR_LIBRARY_ALBUMS'
}
}

View File

@ -8,11 +8,11 @@ var uiActions = require('../ui/actions');
const GoogleMiddleware = (function(){
// A snapcast request is an alias of the Pusher request
const request = (store, params = null, response_callback = null, error_callback = null) => {
// A Google request is an alias of the Mopidy request
const request = (store, method, params = null, response_callback = null, error_callback = null) => {
store.dispatch(
pusherActions.request(
'snapcast_instruct',
mopidyActions.request(
method,
params,
response_callback,
error_callback
@ -25,6 +25,113 @@ const GoogleMiddleware = (function(){
var google = store.getState().google;
switch(action.type){
case 'GOOGLE_GET_LIBRARY_ALBUMS':
var last_run = store.getState().ui.processes.GOOGLE_LIBRARY_ALBUMS_PROCESSOR
if (!last_run){
request(
store,
'library.browse',
{
uri: 'gmusic:album'
},
response => {
if (response.length <= 0){
return;
}
var uris = helpers.arrayOf('uri',response);
store.dispatch({
type: 'GOOGLE_LIBRARY_ALBUMS_LOADED',
uris: uris
});
// Start our process to load the full album objects
store.dispatch(uiActions.startProcess(
'GOOGLE_LIBRARY_ALBUMS_PROCESSOR',
'Loading '+uris.length+' Google albums',
{
uris: uris,
total: uris.length,
remaining: uris.length
}
));
}
);
} else if (last_run.status == 'cancelled'){
store.dispatch(uiActions.resumeProcess('GOOGLE_LIBRARY_ALBUMS_PROCESSOR'))
} else if (last_run.status == 'finished'){
// TODO: do we want to force a refresh?
}
break;
case 'GOOGLE_LIBRARY_ALBUMS_PROCESSOR':
if (store.getState().ui.processes['GOOGLE_LIBRARY_ALBUMS_PROCESSOR'] !== undefined){
var processor = store.getState().ui.processes['GOOGLE_LIBRARY_ALBUMS_PROCESSOR']
if (processor.status == 'cancelling'){
store.dispatch(uiActions.processCancelled('GOOGLE_LIBRARY_ALBUMS_PROCESSOR'))
return false
}
}
var uris = Object.assign([], action.data.uris);
var uris_to_load = uris.splice(0,50);
if (uris_to_load.length > 0){
store.dispatch(uiActions.updateProcess(
'GOOGLE_LIBRARY_ALBUMS_PROCESSOR',
'Loading '+uris.length+' Google albums',
{
uris: uris,
remaining: uris.length
}
));
store.dispatch(mopidyActions.getAlbums(uris_to_load, {name: 'GOOGLE_LIBRARY_ALBUMS_PROCESSOR', data: {uris: uris}}))
} else {
store.dispatch(uiActions.processFinishing('GOOGLE_LIBRARY_ALBUMS_PROCESSOR'));
}
break
case 'GOOGLE_GET_LIBRARY_ARTISTS':
request(
store,
'library.browse',
{
uri: 'gmusic:artist'
},
response => {
if (response.length <= 0){
return
}
var uris = [];
for (var i = 0; i < response.length; i++){
// Convert local URI to actual artist URI
// See https://github.com/mopidy/mopidy-local-sqlite/issues/39
response[i].uri = response[i].uri.replace('local:directory?albumartist=','');
uris.push(response[i].uri);
}
store.dispatch(coreActions.artistsLoaded(response));
store.dispatch({
type: 'GOOGLE_LIBRARY_ARTISTS_LOADED',
uris: uris
});
},
error => {
store.dispatch(coreActions.handleException(
'Could not load Google artists',
error
));
}
);
break;
// This action is irrelevant to us, pass it on to the next middleware

View File

@ -1,10 +1,34 @@
import * as helpers from '../../helpers';
export default function reducer(google = {}, action){
switch (action.type){
case 'GOOGLE_SET':
return Object.assign({}, google, action.data);
case 'GOOGLE_LIBRARY_ARTISTS_LOADED':
if (google.library_artists){
var uris = [...google.library_artists,...action.uris];
} else {
var uris = action.uris;
}
return Object.assign({}, google, { library_artists: helpers.removeDuplicates(uris) });
case 'GOOGLE_CLEAR_LIBRARY_ARTISTS':
return Object.assign({}, google, { library_artists: null });
case 'GOOGLE_LIBRARY_ALBUMS_LOADED':
if (google.library_albums){
var uris = [...google.library_albums,...action.uris];
} else {
var uris = action.uris;
}
return Object.assign({}, google, { library_albums: helpers.removeDuplicates(uris) });
case 'GOOGLE_CLEAR_LIBRARY_ALBUMS':
return Object.assign({}, google, { library_albums: null });
default:
return google
}

View File

@ -8,7 +8,7 @@ export function set(data){
}
}
export function request(method, params = null, response_callback = null, error_callback = null){
export function request(method, params = {}, response_callback = null, error_callback = null){
return {
type: 'MOPIDY_REQUEST',
method: method,

View File

@ -1,5 +1,5 @@
import * as helpers from '../../helpers'
import * as helpers from '../../helpers';
export default function reducer(mopidy = {}, action){
switch (action.type){

View File

@ -1,25 +1,26 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { Link } from 'react-router'
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Link } from 'react-router';
import AlbumGrid from '../../components/AlbumGrid'
import List from '../../components/List'
import Header from '../../components/Header'
import Thumbnail from '../../components/Thumbnail'
import TrackList from '../../components/TrackList'
import ArtistSentence from '../../components/ArtistSentence'
import DropdownField from '../../components/Fields/DropdownField'
import FilterField from '../../components/Fields/FilterField'
import LazyLoadListener from '../../components/LazyLoadListener'
import Icon from '../../components/Icon'
import AlbumGrid from '../../components/AlbumGrid';
import List from '../../components/List';
import Header from '../../components/Header';
import Thumbnail from '../../components/Thumbnail';
import TrackList from '../../components/TrackList';
import ArtistSentence from '../../components/ArtistSentence';
import DropdownField from '../../components/Fields/DropdownField';
import FilterField from '../../components/Fields/FilterField';
import LazyLoadListener from '../../components/LazyLoadListener';
import Icon from '../../components/Icon';
import * as helpers from '../../helpers'
import * as coreActions from '../../services/core/actions'
import * as uiActions from '../../services/ui/actions'
import * as mopidyActions from '../../services/mopidy/actions'
import * as spotifyActions from '../../services/spotify/actions'
import * as helpers from '../../helpers';
import * as coreActions from '../../services/core/actions';
import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as googleActions from '../../services/google/actions';
import * as spotifyActions from '../../services/spotify/actions';
class LibraryAlbums extends React.Component{
@ -40,6 +41,10 @@ class LibraryAlbums extends React.Component{
this.props.mopidyActions.getLibraryAlbums();
}
if (this.props.google_enabled && this.props.google_library_albums_status != 'finished' && this.props.google_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'google')){
this.props.googleActions.getLibraryAlbums();
}
if (this.props.spotify_enabled && this.props.spotify_library_albums_status != 'finished' && this.props.spotify_library_albums_status != 'started' && (this.props.source == 'all' || this.props.source == 'spotify')){
this.props.spotifyActions.getLibraryAlbums();
}
@ -59,6 +64,19 @@ class LibraryAlbums extends React.Component{
}
}
if (newProps.google_enabled && (newProps.source == 'all' || newProps.source == 'google')){
// We've just been enabled (or detected as such)
if (!this.props.google_enabled){
this.props.googleActions.getLibraryAlbums();
}
// Filter changed, but we haven't got this provider's library yet
if (this.props.source != 'all' && this.props.source != 'google' && newProps.google_library_albums_status != 'finished' && newProps.google_library_albums_status != 'started'){
this.props.googleActions.getLibraryAlbums();
}
}
if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')){
// Filter changed, but we haven't got this provider's library yet
@ -111,22 +129,20 @@ class LibraryAlbums extends React.Component{
// Spotify library items
if (this.props.spotify_library_albums && (this.props.source == 'all' || this.props.source == 'spotify')){
for (var i = 0; i < this.props.spotify_library_albums.length; i++){
var uri = this.props.spotify_library_albums[i]
for (var uri of this.props.spotify_library_albums){
if (this.props.albums.hasOwnProperty(uri)){
albums.push(this.props.albums[uri])
albums.push(this.props.albums[uri]);
}
}
}
// Mopidy library items
if (this.props.mopidy_library_albums && (this.props.source == 'all' || this.props.source == 'local')){
for (var i = 0; i < this.props.mopidy_library_albums.length; i++){
for (var uri of this.props.mopidy_library_albums){
// Construct item placeholder. This is used as Mopidy needs to
// lookup ref objects to get the full object which can take some time
var uri = this.props.mopidy_library_albums[i]
var source = helpers.uriSource(uri)
var source = helpers.uriSource(uri);
var album = {
uri: uri,
source: source
@ -140,6 +156,26 @@ class LibraryAlbums extends React.Component{
}
}
// Google library items
if (this.props.google_library_albums && (this.props.source == 'all' || this.props.source == 'google')){
for (var uri of this.props.google_library_albums){
// Construct item placeholder. This is used as Mopidy needs to
// lookup ref objects to get the full object which can take some time
var source = helpers.uriSource(uri);
var album = {
uri: uri,
source: source
}
if (this.props.albums.hasOwnProperty(uri)){
album = this.props.albums[uri]
}
albums.push(album);
}
}
if (this.props.sort){
albums = helpers.sortItems(albums, this.props.sort, this.props.sort_reverse);
}
@ -225,6 +261,13 @@ class LibraryAlbums extends React.Component{
});
}
if (this.props.google_enabled){
source_options.push({
value: 'google',
label: 'Google'
});
}
var view_options = [
{
value: 'thumbnails',
@ -318,7 +361,10 @@ const mapStateToProps = (state, ownProps) => {
albums: state.core.albums,
mopidy_library_albums: state.mopidy.library_albums,
mopidy_library_albums_status: (state.ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR.status : null),
spotify_enabled: (state.mopidy.uri_schemes && state.mopidy.uri_schemes.includes('spotify:')),
google_enabled: state.google.enabled,
google_library_albums: state.google.library_albums,
google_library_albums_status: (state.ui.processes.GOOGLE_LIBRARY_ALBUMS_PROCESSOR !== undefined ? state.ui.processes.GOOGLE_LIBRARY_ALBUMS_PROCESSOR.status : null),
spotify_enabled: state.spotify.enabled,
spotify_library_albums: state.spotify.library_albums,
spotify_library_albums_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_ALBUMS_PROCESSOR.status : null),
view: state.ui.library_albums_view,
@ -333,6 +379,7 @@ const mapDispatchToProps = (dispatch) => {
coreActions: bindActionCreators(coreActions, dispatch),
uiActions: bindActionCreators(uiActions, dispatch),
mopidyActions: bindActionCreators(mopidyActions, dispatch),
googleActions: bindActionCreators(googleActions, dispatch),
spotifyActions: bindActionCreators(spotifyActions, dispatch)
}
}

View File

@ -37,7 +37,7 @@ class LibraryArtists extends React.Component{
this.props.mopidyActions.getLibraryArtists();
}
if (!this.props.gmusic_library_artists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'google')){
if (this.props.google_enabled && !this.props.google_library_artists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'google')){
this.props.googleActions.getLibraryArtists();
}
@ -60,10 +60,15 @@ class LibraryArtists extends React.Component{
}
}
if (newProps.google_enabled && (newProps.source == 'all' || newProps.source == 'google')){
if (newProps.mopidy_connected && newProps.google_enabled && (newProps.source == 'all' || newProps.source == 'google')){
// We've just been enabled (or detected as such)
if (!this.props.google_enabled){
this.props.googleActions.getLibraryArtists();
}
// Filter changed, but we haven't got this provider's library yet
if (newProps.google_library_artists_status != 'finished' && newProps.google_library_artists_status != 'started'){
if (this.props.source != 'all' && this.props.source != 'google' && !newProps.google_library_artists){
this.props.googleActions.getLibraryArtists();
}
}
@ -71,7 +76,7 @@ class LibraryArtists extends React.Component{
if (newProps.spotify_enabled && (newProps.source == 'all' || newProps.source == 'spotify')){
// Filter changed, but we haven't got this provider's library yet
if (newProps.spotify_library_artists_status != 'finished' && newProps.spotify_library_artists_status != 'started'){
if (!newProps.spotify_library_artists_status != 'finished' && newProps.spotify_library_artists_status != 'started'){
this.props.spotifyActions.getLibraryArtists();
}
}
@ -108,11 +113,30 @@ class LibraryArtists extends React.Component{
// Mopidy library items
if (this.props.mopidy_library_artists && (this.props.source == 'all' || this.props.source == 'local')){
for (var i = 0; i < this.props.mopidy_library_artists.length; i++){
for (uri of this.props.mopidy_library_artists){
// Construct item placeholder. This is used as Mopidy needs to
// lookup ref objects to get the full object which can take some time
var source = helpers.uriSource(uri)
var artist = {
uri: uri,
source: source
}
if (this.props.artists.hasOwnProperty(uri)){
artist = this.props.artists[uri]
}
artists.push(artist)
}
}
// Google library items
if (this.props.google_library_artists && (this.props.source == 'all' || this.props.source == 'google')){
for (uri of this.props.google_library_artists){
// Construct item placeholder. This is used as Mopidy needs to
// lookup ref objects to get the full object which can take some time
var uri = this.props.mopidy_library_artists[i]
var source = helpers.uriSource(uri)
var artist = {
uri: uri,
@ -303,13 +327,11 @@ const mapStateToProps = (state, ownProps) => {
mopidy_connected: state.mopidy.connected,
mopidy_uri_schemes: state.mopidy.uri_schemes,
mopidy_library_artists: state.mopidy.library_artists,
mopidy_library_artists_status: (state.ui.processes.MOPIDY_LIBRARY_ARTISTS_PROCESSOR !== undefined ? state.ui.processes.MOPIDY_LIBRARY_ARTISTS_PROCESSOR.status : null),
google_enabled: state.google.enabled,
google_library_artists: state.google.library_artists,
spotify_enabled: state.spotify.enabled,
spotify_library_artists: state.spotify.library_artists,
spotify_library_artists_status: (state.ui.processes.SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR !== undefined ? state.ui.processes.SPOTIFY_GET_LIBRARY_ARTISTS_PROCESSOR.status : null),
google_enabled: state.google.enabled,
google_library_artists: state.google.library_artists,
google_library_artists_status: (state.ui.processes.GOOGLE_GET_LIBRARY_ARTISTS_PROCESSOR !== undefined ? state.ui.processes.GOOGLE_GET_LIBRARY_ARTISTS_PROCESSOR.status : null),
artists: state.core.artists,
source: (state.ui.library_artists_source ? state.ui.library_artists_source : 'all'),
sort: (state.ui.library_artists_sort ? state.ui.library_artists_sort : null),