From 0dff3d981353ac55dc4341070df44b5dfa458e66 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Thu, 1 Jun 2023 18:09:46 -0700 Subject: [PATCH 1/9] Get use sudo from env var --- mopidy_iris/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy_iris/system.py b/mopidy_iris/system.py index 868e30162..6b9378452 100755 --- a/mopidy_iris/system.py +++ b/mopidy_iris/system.py @@ -25,7 +25,7 @@ def __init__(self, path): class IrisSystemThread(Thread): - _USE_SUDO = True + _USE_SUDO = os.environ.get("IRIS_USE_SUDO", True) def __init__(self, action, ioloop, callback): Thread.__init__(self) From 4a3a77419f5998e72e2022c49a6ce47d7587ba35 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Thu, 1 Jun 2023 19:22:31 -0700 Subject: [PATCH 2/9] Add support for env var for IRIS_CONFIG_LOCATION --- mopidy_iris/system.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mopidy_iris/system.sh b/mopidy_iris/system.sh index 6e8dee109..bd46b5693 100755 --- a/mopidy_iris/system.sh +++ b/mopidy_iris/system.sh @@ -28,7 +28,10 @@ elif [[ $1 = "restart" ]]; then elif [[ $1 = "local_scan" ]]; then START=$(date +%s) if $IS_CONTAINER; then - SCAN=$(mopidy --config /config/mopidy.conf local scan) + if [ -n "$IRIS_CONFIG_LOCATION" ]; then + SCAN=$(mopidy --config $IRIS_CONFIG_LOCATION local scan) + else + SCAN=$(mopidy --config /config/mopidy.conf local scan) else SCAN=$(sudo mopidyctl local scan) fi From b011292a8cbe3c60b575483f4ffd5eb1f1a874e2 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Sun, 8 Oct 2023 21:14:08 +1300 Subject: [PATCH 3/9] Search results stored by provider:type:term - This allows storing of per-provider, per-type, per-term results - We can restore old search results, and hide/show by provider without needing to re-query --- src/js/App.js | 2 +- src/js/components/SearchResults.js | 12 +++-- src/js/locale/en.yaml | 2 +- src/js/services/core/actions.js | 5 +- src/js/services/core/middleware.js | 53 ++------------------- src/js/services/core/reducer.js | 18 ++----- src/js/services/mopidy/actions.js | 4 +- src/js/services/mopidy/middleware.js | 37 ++++++++------- src/js/services/mopidy/reducer.js | 27 ----------- src/js/services/spotify/actions.js | 16 +++---- src/js/store/index.js | 1 + src/js/util/helpers.js | 5 ++ src/js/util/selectors.js | 15 +++--- src/js/views/Search.js | 70 ++++++++++++++++++++-------- src/scss/views/_search.scss | 2 +- 15 files changed, 115 insertions(+), 154 deletions(-) diff --git a/src/js/App.js b/src/js/App.js index d097b168f..38ca038ed 100755 --- a/src/js/App.js +++ b/src/js/App.js @@ -54,7 +54,7 @@ const Content = () => ( } /> } /> } /> - } /> + } /> } /> } /> } /> diff --git a/src/js/components/SearchResults.js b/src/js/components/SearchResults.js index 01cd95fd2..d1ef8cb4d 100755 --- a/src/js/components/SearchResults.js +++ b/src/js/components/SearchResults.js @@ -16,12 +16,14 @@ const SearchResults = ({ type, all, }) => { - const { term } = useParams(); + const { term, providers = '' } = useParams(); const [sortField, sortReverse] = useSelector( (state) => getSortSelector(state, SORT_KEY, 'name'), ); - const searchResultsSelector = makeSearchResultsSelector(term, type); + const providersArray = providers.split(','); + const searchResultsSelector = makeSearchResultsSelector(providersArray, term, type); const rawResults = useSelector(searchResultsSelector); + console.debug(rawResults, providersArray, term, type) const encodedTerm = encodeURIComponent(term); let results = [...rawResults]; @@ -43,7 +45,7 @@ const SearchResults = ({

{!all && ( - + {' '} @@ -53,7 +55,7 @@ const SearchResults = ({ )} {all && ( - + )} @@ -66,7 +68,7 @@ const SearchResults = ({ {type === 'tracks' && ( i !== 'spotify:'), // Omit Spotify; handled above + providers.filter((i) => i !== 'spotify:'), // Omit Spotify; handled above )); break; } - case 'SEARCH_RESULTS_LOADED': { - const { - query: { - term, - type, - }, - resultType, - results, - } = action; - const { - core: { - search_results: { - query: { - term: prevTerm, - type: prevType, - } = {}, - ...allResults - } = {}, - } = {}, - } = store.getState(); - - // Add to our existing results, so long as the search term is the same - const search_results = { - query: { term, type }, - ...(term === prevTerm && type === prevType ? allResults : {}), - }; - - // Merge our new results with the existing (if any) - search_results[resultType] = [ - ...(search_results[resultType] || []), - ...results, - ]; - - next({ - ...action, - search_results, - }); - break; - } - case 'PLAYLIST_TRACKS_ADDED': { const { key, diff --git a/src/js/services/core/reducer.js b/src/js/services/core/reducer.js index 7b771b077..9f424d36c 100755 --- a/src/js/services/core/reducer.js +++ b/src/js/services/core/reducer.js @@ -176,23 +176,15 @@ export default function reducer(core = {}, action) { /** * Search results * */ - case 'START_SEARCH': - return { - ...core, - search_results: { - query: action.query, - artists: [], - albums: [], - playlists: [], - tracks: [], - }, - }; case 'SEARCH_RESULTS_LOADED': { - const { search_results } = action; + console.debug(action) return { ...core, - search_results, + search_results: { + ...core?.search_results || {}, + [action.key]: action.results, + }, }; } diff --git a/src/js/services/mopidy/actions.js b/src/js/services/mopidy/actions.js index 48c883157..bbd06dddb 100755 --- a/src/js/services/mopidy/actions.js +++ b/src/js/services/mopidy/actions.js @@ -591,12 +591,12 @@ export function clearSearchResults() { }; } -export function getSearchResults(query, limit = 100, uri_schemes) { +export function getSearchResults(query, providers, limit = 100) { return { type: 'MOPIDY_GET_SEARCH_RESULTS', query, + providers, limit, - uri_schemes, }; } diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index 310019dfe..bc04c878e 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -8,6 +8,7 @@ import { uriSource, setFavicon, titleCase, + getSearchResultKey, } from '../../util/helpers'; import { digestMopidyImages, @@ -263,10 +264,11 @@ const MopidyMiddleware = (function () { type, term, requestType, - uri_scheme, + provider, method = 'library.search', data, } = queue.shift(); + const resultKey = getSearchResultKey({ provider, type, term }); const processKey = 'MOPIDY_GET_SEARCH_RESULTS'; const processor = store.getState().ui.processes[processKey]; @@ -281,7 +283,7 @@ const MopidyMiddleware = (function () { content: i18n( 'services.mopidy.searching', { - provider: titleCase(uri_scheme.replace(':', '')), + provider: titleCase(provider.replace(':', '')), type: requestType, }, ), @@ -348,7 +350,7 @@ const MopidyMiddleware = (function () { playlists: (response) => { const playlists = response.filter( (item) => { - if (!item.uri.includes(uri_scheme)) return false; + if (!item.uri.includes(provider)) return false; return item.name.toLowerCase().includes(term.toLowerCase()); }, ); @@ -371,8 +373,7 @@ const MopidyMiddleware = (function () { (response) => { if (response.length > 0) { store.dispatch(coreActions.searchResultsLoaded( - { term, type }, - requestType, + resultKey, processResults[requestType](response), )); } @@ -1221,35 +1222,35 @@ const MopidyMiddleware = (function () { case 'MOPIDY_GET_SEARCH_RESULTS': { const { - uri_schemes = [], - query = {}, + query: { term, type: queryType } = {}, + providers, } = action; - const types = query.type === 'all' + const types = queryType === 'all' ? ['artists', 'albums', 'tracks', 'playlists'] - : [query.type]; + : [queryType]; const queue = []; - uri_schemes.forEach( - (uri_scheme) => types.forEach( + providers.forEach( + (provider) => types.forEach( (type) => { const item = { - type: query.type, - term: query.term, + type, + term, + provider, requestType: type, - uri_scheme, data: { - uris: [uri_scheme], + uris: [provider], }, }; switch (type) { case 'tracks': - item.data.query = { any: [query.term] }; + item.data.query = { any: [term] }; break; case 'artists': - item.data.query = { artist: [query.term] }; + item.data.query = { artist: [term] }; break; case 'albums': - item.data.query = { album: [query.term] }; + item.data.query = { album: [term] }; break; case 'playlists': // Searching for playlists is not supported, so we get a simple diff --git a/src/js/services/mopidy/reducer.js b/src/js/services/mopidy/reducer.js index 9ab621311..ba6239ca9 100755 --- a/src/js/services/mopidy/reducer.js +++ b/src/js/services/mopidy/reducer.js @@ -103,33 +103,6 @@ export default function reducer(mopidy = {}, action) { directory: { ...mopidy.directory, ...action.directory }, }; - /** - * Searching - * */ - case 'MOPIDY_CLEAR_SEARCH_RESULTS': - return { ...mopidy, search_results: {} }; - - case 'MOPIDY_SEARCH_RESULTS_LOADED': - // Fetch or create our container - if (mopidy.search_results) { - var search_results = { ...mopidy.search_results }; - } else { - var search_results = {}; - } - - search_results = { - ...search_results, - query: action.query, - }; - - if (search_results[action.context]) { - search_results[action.context] = [...search_results[action.context], ...action.results]; - } else { - search_results[action.context] = action.results; - } - - return { ...mopidy, search_results }; - default: return mopidy; } diff --git a/src/js/services/spotify/actions.js b/src/js/services/spotify/actions.js index e34a8c711..0d47a00ed 100755 --- a/src/js/services/spotify/actions.js +++ b/src/js/services/spotify/actions.js @@ -6,6 +6,7 @@ import { getFromUri, uriType, upgradeSpotifyPlaylistUris, + getSearchResultKey, } from '../../util/helpers'; import { formatPlaylistGroup, @@ -613,7 +614,8 @@ export function getMore(endpoint, core_action = null, custom_action = null, extr }; } -export function getSearchResults({ type, term }, limit = 50, offset = 0) { +export function getSearchResults(query, limit = 50, offset = 0) { + const { type, term } = query; const processKey = 'SPOTIFY_GET_SEARCH_RESULTS'; return (dispatch, getState) => { const { @@ -641,24 +643,21 @@ export function getSearchResults({ type, term }, limit = 50, offset = 0) { (response) => { if (response.tracks !== undefined) { dispatch(coreActions.searchResultsLoaded( - { term, type }, - 'tracks', + getSearchResultKey({ provider: 'spotify', type: 'tracks', term }), formatTracks(response.tracks.items), )); } if (response.artists !== undefined) { dispatch(coreActions.searchResultsLoaded( - { term, type }, - 'artists', + getSearchResultKey({ provider: 'spotify', type: 'artists', term }), formatArtists(response.artists.items), )); } if (response.albums !== undefined) { dispatch(coreActions.searchResultsLoaded( - { term, type }, - 'albums', + getSearchResultKey({ provider: 'spotify', type: 'albums', term }), formatAlbums(response.albums.items), )); } @@ -669,8 +668,7 @@ export function getSearchResults({ type, term }, limit = 50, offset = 0) { can_edit: (meId === item.owner.id), })); dispatch(coreActions.searchResultsLoaded( - { term, type }, - 'playlists', + getSearchResultKey({ provider: 'spotify', type: 'playlists', term }), playlists, )); } diff --git a/src/js/store/index.js b/src/js/store/index.js index eb520b929..cd861b384 100755 --- a/src/js/store/index.js +++ b/src/js/store/index.js @@ -38,6 +38,7 @@ let initialState = { tracks: {}, items: {}, libraries: {}, + search_results: {}, }, ui: { language: 'en', diff --git a/src/js/util/helpers.js b/src/js/util/helpers.js index 20f7aa24f..860b106e4 100755 --- a/src/js/util/helpers.js +++ b/src/js/util/helpers.js @@ -603,6 +603,9 @@ const upgradeSpotifyPlaylistUri = function (uri) { return upgradeSpotifyPlaylistUris([uri])[0]; }; +const getSearchResultKey = ({ provider, type, term }) => + [provider.replace(':', ''), type, term].join(':'); + export { debounce, throttle, @@ -626,6 +629,7 @@ export { upgradeSpotifyPlaylistUris, upgradeSpotifyPlaylistUri, iconFromKeyword, + getSearchResultKey, }; export default { @@ -651,4 +655,5 @@ export default { upgradeSpotifyPlaylistUris, upgradeSpotifyPlaylistUri, iconFromKeyword, + getSearchResultKey, }; diff --git a/src/js/util/selectors.js b/src/js/util/selectors.js index 03782f690..a3f707cce 100755 --- a/src/js/util/selectors.js +++ b/src/js/util/selectors.js @@ -1,6 +1,6 @@ import { createSelector } from 'reselect'; import { indexToArray } from './arrays'; -import { isLoading } from './helpers'; +import { getSearchResultKey, isLoading } from './helpers'; import { i18n } from '../locale'; const getItem = (state, uri) => state.core.items[uri]; @@ -68,13 +68,14 @@ const makeLibrarySelector = (name, filtered = true) => createSelector( }, ); -const makeSearchResultsSelector = (term, type) => createSelector( +const makeSearchResultsSelector = (providers = [], term, type) => createSelector( [getSearchResults], - (searchResults) => { - if (!searchResults || searchResults.query.term !== term) return []; - return searchResults[type] || []; - }, -); + (searchResults) => providers.reduce( + (acc, curr) => {[ + ...acc, + ...searchResults[getSearchResultKey({ provider: curr, term, type })] || [], + ]}, []), + ); const makeProcessProgressSelector = (keys) => createSelector( [getProcesses], diff --git a/src/js/views/Search.js b/src/js/views/Search.js index a15ecea2d..cf50da9b5 100755 --- a/src/js/views/Search.js +++ b/src/js/views/Search.js @@ -18,13 +18,21 @@ import { getSortSelector } from '../util/selectors'; const SORT_KEY = 'search_results'; const Search = () => { - const { term, type = 'all' } = useParams(); + const { + term, + providers: providersString = 'all', + type = 'all', + } = useParams(); const dispatch = useDispatch(); const navigate = useNavigate(); const lastQuery = useSelector((state) => state.core?.search_results?.query); const [sortField, sortReverse] = useSelector( (state) => getSortSelector(state, SORT_KEY, 'name'), ); + const allProviders = useSelector((state) => state.mopidy?.uri_schemes || []); + const providers = providersString == 'all' + ? [...allProviders] + : providersString.split(',').filter((str) => allProviders.indexOf(str) > -1); useEffect(() => { dispatch(setWindowTitle('Search')); @@ -32,25 +40,38 @@ const Search = () => { }, []); useEffect(() => { - if (term && type && term !== lastQuery?.term) { + console.debug(providers, lastQuery?.providers) + if (term && type && (term !== lastQuery?.term || providers.length !== lastQuery?.providers?.length)) { + console.debug('STARTING SEARCH', { term, type, providers }) dispatch(setWindowTitle(i18n('search.title_window', { term: decodeURIComponent(term) }))); - dispatch(startSearch({ term, type })); + dispatch(startSearch({ term, type, providers })); } - }, [term, type]) + }, [term, type, providersString]) - const onSubmit = (nextTerm) => { - const encodedTerm = encodeURIComponent(nextTerm); - navigate(`/search/${type}/${encodedTerm}`); + const onSubmit = (term) => { + updateSearchQuery(term, providers); + } + + const updateSearchQuery = (term, providers) => { + const encodedTerm = encodeURIComponent(term); + navigate(`/search/${type}/${providers.join(',')}/${encodedTerm || ''}`); } const onReset = () => navigate('/search'); - const onSortChange = (field) => { + const onProvidersChange = (providers) => { + console.debug(providers) + // ON BLUR then trigger search event + updateSearchQuery(term, providers) + dispatch(hideContextMenu()); + } + + const onSortChange = (value) => { let reverse = false; - if (field !== null && sortField === field) { + if (value !== null && sortField === value) { reverse = !sortReverse; } - dispatch(setSort(SORT_KEY, field, reverse)); + dispatch(setSort(SORT_KEY, value, reverse)); dispatch(hideContextMenu()); } @@ -62,16 +83,27 @@ const Search = () => { { value: 'duration', label: i18n('common.duration') }, ]; + const providerOptions = allProviders.map((value) => ({ value, label: value})) + const options = ( - + <> + + + ); return ( diff --git a/src/scss/views/_search.scss b/src/scss/views/_search.scss index 00e0e4ef2..06a266cda 100755 --- a/src/scss/views/_search.scss +++ b/src/scss/views/_search.scss @@ -5,7 +5,7 @@ position: absolute; top: 30px; left: 90px; - right: 150px; + right: 250px; input { @include feature_font(); From bec0cf95e3130c2c52c69e47f21b4aa56f580842 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Mon, 9 Oct 2023 20:36:16 +1300 Subject: [PATCH 4/9] Experimenting with hook for all search params --- src/js/components/SearchResults.js | 16 ++++++++-------- src/js/components/URILink.js | 2 +- src/js/util/selectors.js | 6 +++--- src/js/util/useSearchQuery.js | 25 +++++++++++++++++++++++++ src/js/views/Search.js | 23 ++++++++++------------- 5 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 src/js/util/useSearchQuery.js diff --git a/src/js/components/SearchResults.js b/src/js/components/SearchResults.js index d1ef8cb4d..308c56528 100755 --- a/src/js/components/SearchResults.js +++ b/src/js/components/SearchResults.js @@ -9,6 +9,7 @@ import { Grid } from './Grid'; import { I18n } from '../locale'; import Button from './Button'; import { makeSearchResultsSelector, getSortSelector } from '../util/selectors'; +import useSearchQuery from '../util/useSearchQuery'; const SORT_KEY = 'search_results'; @@ -16,14 +17,13 @@ const SearchResults = ({ type, all, }) => { - const { term, providers = '' } = useParams(); + const { term, providers } = useSearchQuery(); + const encodedProviders = providers.join(',').replace(/:/g,''); const [sortField, sortReverse] = useSelector( (state) => getSortSelector(state, SORT_KEY, 'name'), ); - const providersArray = providers.split(','); - const searchResultsSelector = makeSearchResultsSelector(providersArray, term, type); + const searchResultsSelector = makeSearchResultsSelector(providers, term, type); const rawResults = useSelector(searchResultsSelector); - console.debug(rawResults, providersArray, term, type) const encodedTerm = encodeURIComponent(term); let results = [...rawResults]; @@ -45,7 +45,7 @@ const SearchResults = ({

{!all && ( - + {' '} @@ -55,7 +55,7 @@ const SearchResults = ({ )} {all && ( - + )} @@ -68,7 +68,7 @@ const SearchResults = ({ {type === 'tracks' && ( */} {resultsCount > results.length && ( - )} diff --git a/src/js/components/URILink.js b/src/js/components/URILink.js index 59ca313e3..fd95a6baa 100755 --- a/src/js/components/URILink.js +++ b/src/js/components/URILink.js @@ -47,7 +47,7 @@ export default memo(({ case 'search': var exploded = uri.split(':'); - to = `/search/${exploded[2]}/${exploded[3]}`; + to = `/search/${exploded[2]}/${exploded[3]}/${exploded[4]}`; break; default: diff --git a/src/js/util/selectors.js b/src/js/util/selectors.js index a3f707cce..f6528a1a2 100755 --- a/src/js/util/selectors.js +++ b/src/js/util/selectors.js @@ -68,13 +68,13 @@ const makeLibrarySelector = (name, filtered = true) => createSelector( }, ); -const makeSearchResultsSelector = (providers = [], term, type) => createSelector( +const makeSearchResultsSelector = (providers, term, type) => createSelector( [getSearchResults], (searchResults) => providers.reduce( - (acc, curr) => {[ + (acc, curr) => [ ...acc, ...searchResults[getSearchResultKey({ provider: curr, term, type })] || [], - ]}, []), + ], []), ); const makeProcessProgressSelector = (keys) => createSelector( diff --git a/src/js/util/useSearchQuery.js b/src/js/util/useSearchQuery.js new file mode 100644 index 000000000..95d0dee0c --- /dev/null +++ b/src/js/util/useSearchQuery.js @@ -0,0 +1,25 @@ +import { useParams } from 'react-router'; +import { useSelector } from 'react-redux'; + +const useSearchQuery = () => { + const { + term = '', + type = 'all', + providers: rawProviders = 'all', + } = useParams(); + const allProviders = useSelector((state) => state.mopidy?.uri_schemes || []); + const providers = rawProviders == 'all' + ? [...allProviders] + : rawProviders.split(',').filter((str) => allProviders.indexOf(str) > -1); + const providersString = providers.join(',').replace(/:/g,''); + + return { + term, + type, + providers, + allProviders, + providersString, + } +}; + +export default useSearchQuery; diff --git a/src/js/views/Search.js b/src/js/views/Search.js index cf50da9b5..0818112fa 100755 --- a/src/js/views/Search.js +++ b/src/js/views/Search.js @@ -14,25 +14,23 @@ import { } from '../services/ui/actions'; import { i18n } from '../locale'; import { getSortSelector } from '../util/selectors'; +import useSearchQuery from '../util/useSearchQuery'; const SORT_KEY = 'search_results'; const Search = () => { - const { - term, - providers: providersString = 'all', - type = 'all', - } = useParams(); const dispatch = useDispatch(); const navigate = useNavigate(); - const lastQuery = useSelector((state) => state.core?.search_results?.query); + const { + term, + type, + providers, + allProviders, + providersString, + } = useSearchQuery(); const [sortField, sortReverse] = useSelector( (state) => getSortSelector(state, SORT_KEY, 'name'), ); - const allProviders = useSelector((state) => state.mopidy?.uri_schemes || []); - const providers = providersString == 'all' - ? [...allProviders] - : providersString.split(',').filter((str) => allProviders.indexOf(str) > -1); useEffect(() => { dispatch(setWindowTitle('Search')); @@ -40,13 +38,12 @@ const Search = () => { }, []); useEffect(() => { - console.debug(providers, lastQuery?.providers) - if (term && type && (term !== lastQuery?.term || providers.length !== lastQuery?.providers?.length)) { + if (term) { console.debug('STARTING SEARCH', { term, type, providers }) dispatch(setWindowTitle(i18n('search.title_window', { term: decodeURIComponent(term) }))); dispatch(startSearch({ term, type, providers })); } - }, [term, type, providersString]) + }, []) const onSubmit = (term) => { updateSearchQuery(term, providers); From 8dfd585a3f8e02e1198da62dd92b2420ed803775 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Tue, 10 Oct 2023 20:33:51 +1300 Subject: [PATCH 5/9] In-memory search results cache - Switching between type and provider now negates need for repeat queries - Mopidy caching varies, so for some providers this has a huge performance gain (eg YouTube) - Spotify will requery anyway, but the browser handles query caching --- src/js/services/core/middleware.js | 4 ++-- src/js/services/mopidy/middleware.js | 28 ++++++++++++++++++---------- src/js/util/helpers.js | 3 +-- src/js/util/useSearchQuery.js | 6 ++++-- src/js/views/Search.js | 7 ++----- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/js/services/core/middleware.js b/src/js/services/core/middleware.js index 623209771..5e349e787 100755 --- a/src/js/services/core/middleware.js +++ b/src/js/services/core/middleware.js @@ -197,12 +197,12 @@ const CoreMiddleware = (function () { // Trigger reducer immediately; this will hose out any previous results next(action); - if (providers.includes('spotify:')) { + if (providers.includes('spotify')) { store.dispatch(spotifyActions.getSearchResults(query)); } store.dispatch(mopidyActions.getSearchResults( query, - providers.filter((i) => i !== 'spotify:'), // Omit Spotify; handled above + providers.filter((i) => i !== 'spotify'), // Omit Spotify; handled above )); break; } diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index bc04c878e..675c4f3e8 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -32,6 +32,7 @@ import { indexToArray, } from '../../util/arrays'; import { getProvider, getSortSelector } from '../../util/selectors'; +import { iterate } from 'localforage'; const mopidyActions = require('./actions.js'); const coreActions = require('../core/actions.js'); @@ -268,28 +269,40 @@ const MopidyMiddleware = (function () { method = 'library.search', data, } = queue.shift(); - const resultKey = getSearchResultKey({ provider, type, term }); const processKey = 'MOPIDY_GET_SEARCH_RESULTS'; const processor = store.getState().ui.processes[processKey]; - if (processor && processor.status === 'cancelling') { store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS')); return; } + const iterateNext = (store, queue) => { + if (queue.length) { + processSearchQueue(store, queue); + } else { + store.dispatch(uiActions.processFinished(processKey)); + } + } + store.dispatch(uiActions.updateProcess( processKey, { content: i18n( 'services.mopidy.searching', { - provider: titleCase(provider.replace(':', '')), + provider: titleCase(provider), type: requestType, }, ), remaining: queue.length, }, )); + + const resultKey = getSearchResultKey({ provider, type, term }); + if (resultKey in store.getState().core.search_results) { + iterateNext(store, queue); + return; + } // Each type has a different method of formatting and destructuring. const processResults = { @@ -377,12 +390,7 @@ const MopidyMiddleware = (function () { processResults[requestType](response), )); } - - if (queue.length) { - processSearchQueue(store, queue); - } else { - store.dispatch(uiActions.processFinished(processKey)); - } + iterateNext(store, queue); }, ); }; @@ -1239,7 +1247,7 @@ const MopidyMiddleware = (function () { provider, requestType: type, data: { - uris: [provider], + uris: [`${provider}:`], }, }; switch (type) { diff --git a/src/js/util/helpers.js b/src/js/util/helpers.js index 860b106e4..cf1d916f1 100755 --- a/src/js/util/helpers.js +++ b/src/js/util/helpers.js @@ -603,8 +603,7 @@ const upgradeSpotifyPlaylistUri = function (uri) { return upgradeSpotifyPlaylistUris([uri])[0]; }; -const getSearchResultKey = ({ provider, type, term }) => - [provider.replace(':', ''), type, term].join(':'); +const getSearchResultKey = ({ provider, type, term }) => [provider, type, term].join(':'); export { debounce, diff --git a/src/js/util/useSearchQuery.js b/src/js/util/useSearchQuery.js index 95d0dee0c..032df70a7 100644 --- a/src/js/util/useSearchQuery.js +++ b/src/js/util/useSearchQuery.js @@ -7,11 +7,13 @@ const useSearchQuery = () => { type = 'all', providers: rawProviders = 'all', } = useParams(); - const allProviders = useSelector((state) => state.mopidy?.uri_schemes || []); + const allProviders = useSelector( + ({ mopidy: { uri_schemes } }) => uri_schemes || [] + ).map((str) => str.replace(/:/g,'')); const providers = rawProviders == 'all' ? [...allProviders] : rawProviders.split(',').filter((str) => allProviders.indexOf(str) > -1); - const providersString = providers.join(',').replace(/:/g,''); + const providersString = providers.join(','); return { term, diff --git a/src/js/views/Search.js b/src/js/views/Search.js index 0818112fa..fceed8052 100755 --- a/src/js/views/Search.js +++ b/src/js/views/Search.js @@ -34,16 +34,15 @@ const Search = () => { useEffect(() => { dispatch(setWindowTitle('Search')); - $(document).find('.search-form input').focus(); + $(document).find('.search-form input').trigger('focus'); }, []); useEffect(() => { if (term) { - console.debug('STARTING SEARCH', { term, type, providers }) dispatch(setWindowTitle(i18n('search.title_window', { term: decodeURIComponent(term) }))); dispatch(startSearch({ term, type, providers })); } - }, []) + }, [providersString, type, term]) const onSubmit = (term) => { updateSearchQuery(term, providers); @@ -57,8 +56,6 @@ const Search = () => { const onReset = () => navigate('/search'); const onProvidersChange = (providers) => { - console.debug(providers) - // ON BLUR then trigger search event updateSearchQuery(term, providers) dispatch(hideContextMenu()); } From 5bef25615997a6ea714ac85e0f922cdab4369de2 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Tue, 10 Oct 2023 21:03:27 +1300 Subject: [PATCH 6/9] Don't load local assets with `loading: true` as default - Subsequent query will load images, if they're available - Fixes #925 --- src/js/services/mopidy/middleware.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index 675c4f3e8..e297c6d1e 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -978,7 +978,6 @@ const MopidyMiddleware = (function () { } case 'MOPIDY_ENQUEUE_URIS': { - console.debug(action) if (!action.uris || action.uris.length <= 0) { this.props.uiActions.createNotification({ content: 'No URIs to enqueue', @@ -1827,13 +1826,13 @@ const MopidyMiddleware = (function () { if (item.__model__ === 'Track') { tracks.push(formatTrack(item)); } else if (item.__model__ === 'Ref' && item.type === 'track') { - tracks.push(formatTrack({ ...item, loading: true })); + tracks.push(formatTrack(item)); trackUrisToLoad.push(item.uri); } else if (item.__model__ === 'Ref' && item.type === 'album') { - subdirectories.push(formatAlbum({ ...item, loading: true })); + subdirectories.push(formatAlbum(item)); subdirectoryImagesToLoad.push(item.uri); } else if (item.__model__ === 'Ref' && item.type === 'artist') { - subdirectories.push(formatArtist({ ...item, loading: true })); + subdirectories.push(formatArtist(item)); subdirectoryImagesToLoad.push(item.uri); } else if (item.__model__ === 'Ref' && item.type === 'playlist') { // Tidal moods and genres incorrectly marked as Playlist type @@ -1846,7 +1845,7 @@ const MopidyMiddleware = (function () { type: 'directory', }); } else { - subdirectories.push(formatPlaylist({ ...item, loading: true })); + subdirectories.push(formatPlaylist(item)); subdirectoryImagesToLoad.push(item.uri); playlistsToLoad.push(item.uri); } From 14cbdf131c91785cf12968b683f0b6ddd18d3cc5 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Tue, 10 Oct 2023 21:09:24 +1300 Subject: [PATCH 7/9] Removing old debug output --- src/js/services/core/middleware.js | 1 - src/js/services/core/reducer.js | 1 - src/js/views/Discover/FeaturedPlaylists.js | 2 -- src/js/views/Discover/Recommendations.js | 1 - 4 files changed, 5 deletions(-) diff --git a/src/js/services/core/middleware.js b/src/js/services/core/middleware.js index 5e349e787..358f5516a 100755 --- a/src/js/services/core/middleware.js +++ b/src/js/services/core/middleware.js @@ -503,7 +503,6 @@ const CoreMiddleware = (function () { case 'LOAD_LIBRARY': store.dispatch(uiActions.startLoading(action.uri, action.uri)); - console.debug(action); const fetchLibrary = () => { switch (uriSource(action.uri)) { case 'spotify': diff --git a/src/js/services/core/reducer.js b/src/js/services/core/reducer.js index 9f424d36c..997e4f620 100755 --- a/src/js/services/core/reducer.js +++ b/src/js/services/core/reducer.js @@ -178,7 +178,6 @@ export default function reducer(core = {}, action) { * */ case 'SEARCH_RESULTS_LOADED': { - console.debug(action) return { ...core, search_results: { diff --git a/src/js/views/Discover/FeaturedPlaylists.js b/src/js/views/Discover/FeaturedPlaylists.js index 6f9f15d44..feeb431bd 100644 --- a/src/js/views/Discover/FeaturedPlaylists.js +++ b/src/js/views/Discover/FeaturedPlaylists.js @@ -197,8 +197,6 @@ class FeaturedPlaylists extends React.Component { }, ]; - console.debug({ source, view }) - const options = ( <> decodeUri(seed)); - console.debug({ uri, uriProp, seeds }) loadUris(seeds); this.setState( { seeds }, From b6c78b5fd5b4f22894cd7232b05f0898d92d355c Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 13 Oct 2023 21:48:36 +1300 Subject: [PATCH 8/9] Tweaking padding for search results --- src/js/components/SearchResults.js | 4 ++-- src/scss/global/_core.scss | 4 ++-- src/scss/views/_artist.scss | 2 +- src/scss/views/_search.scss | 6 +++++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/js/components/SearchResults.js b/src/js/components/SearchResults.js index 308c56528..a434fed07 100755 --- a/src/js/components/SearchResults.js +++ b/src/js/components/SearchResults.js @@ -48,9 +48,9 @@ const SearchResults = ({ - {' '} + - {' '} + )} diff --git a/src/scss/global/_core.scss b/src/scss/global/_core.scss index 0c8d14817..82e4ed1bb 100755 --- a/src/scss/global/_core.scss +++ b/src/scss/global/_core.scss @@ -741,7 +741,7 @@ footer { } h4 { - font-size: 1.3rem; + font-size: 1.4rem; } h5 { @@ -773,7 +773,7 @@ footer { } h4 { - font-size: 1.1rem; + font-size: 1.2rem; } h5 { diff --git a/src/scss/views/_artist.scss b/src/scss/views/_artist.scss index d771199e5..6a3238f48 100755 --- a/src/scss/views/_artist.scss +++ b/src/scss/views/_artist.scss @@ -123,7 +123,7 @@ .sub-views { margin-left: 5px; - padding-top: 10px; + padding-top: 30px; .option { margin: 0 8px; diff --git a/src/scss/views/_search.scss b/src/scss/views/_search.scss index 06a266cda..51ea489c0 100755 --- a/src/scss/views/_search.scss +++ b/src/scss/views/_search.scss @@ -81,6 +81,10 @@ } @include responsive($bp_medium) { + header { + margin-bottom: 0; + } + .search-form { top: 10px; left: 40px; @@ -97,7 +101,7 @@ } .search-result-sections { - padding: 10px 10px 0; + // padding: 10px 10px 0; section { width: auto; From 3293fe8b0fdb7716895b22e761468914d546687e Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Fri, 13 Oct 2023 21:48:50 +1300 Subject: [PATCH 9/9] Version bump 3.69.0 --- IRIS_VERSION | 2 +- mopidy_iris/__init__.py | 2 +- package.json | 2 +- setup.cfg | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/IRIS_VERSION b/IRIS_VERSION index 2d09e4284..b24440d98 100755 --- a/IRIS_VERSION +++ b/IRIS_VERSION @@ -1 +1 @@ -3.68.0 +3.69.0 diff --git a/mopidy_iris/__init__.py b/mopidy_iris/__init__.py index c870ea08b..fd776f665 100755 --- a/mopidy_iris/__init__.py +++ b/mopidy_iris/__init__.py @@ -3,7 +3,7 @@ from mopidy import config, ext -__version__ = "3.68.0" +__version__ = "3.69.0" logger = logging.getLogger(__name__) diff --git a/package.json b/package.json index 36deb5d4f..cca160be6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mopidy-iris", - "version": "3.68.0", + "version": "3.69.0", "description": "Mopidy HTTP interface", "repository": "https://github.com/jaedb/iris", "author": "James Barnsley ", diff --git a/setup.cfg b/setup.cfg index 6b2cbd149..0ab38d488 100755 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = Mopidy-Iris -version = 3.68.0 +version = 3.69.0 url = https://github.com/jaedb/iris author = James Barnsley author_email = james@barnsley.nz