mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
Compare commits
8 Commits
bbcbbd5118
...
03b1a5952a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03b1a5952a | ||
|
|
e86dc03619 | ||
|
|
775626e037 | ||
|
|
5cb851f2a8 | ||
|
|
5c18951e31 | ||
|
|
2b744c878e | ||
|
|
4548e75d49 | ||
|
|
841af03393 |
@ -400,23 +400,16 @@ func (r *artistRepository) RefreshStats(allArtists bool) (int64, error) {
|
|||||||
// This now calculates per-library statistics and stores them in library_artist.stats
|
// This now calculates per-library statistics and stores them in library_artist.stats
|
||||||
batchUpdateStatsSQL := `
|
batchUpdateStatsSQL := `
|
||||||
WITH artist_role_counters AS (
|
WITH artist_role_counters AS (
|
||||||
SELECT jt.atom AS artist_id,
|
SELECT mfa.artist_id,
|
||||||
mf.library_id,
|
mf.library_id,
|
||||||
substr(
|
mfa.role,
|
||||||
replace(jt.path, '$.', ''),
|
|
||||||
1,
|
|
||||||
CASE WHEN instr(replace(jt.path, '$.', ''), '[') > 0
|
|
||||||
THEN instr(replace(jt.path, '$.', ''), '[') - 1
|
|
||||||
ELSE length(replace(jt.path, '$.', ''))
|
|
||||||
END
|
|
||||||
) AS role,
|
|
||||||
count(DISTINCT mf.album_id) AS album_count,
|
count(DISTINCT mf.album_id) AS album_count,
|
||||||
count(mf.id) AS count,
|
count(DISTINCT mf.id) AS count,
|
||||||
sum(mf.size) AS size
|
sum(mf.size) AS size
|
||||||
FROM media_file mf
|
FROM media_file_artists mfa
|
||||||
JOIN json_tree(mf.participants) jt ON jt.key = 'id' AND jt.atom IS NOT NULL
|
JOIN media_file mf ON mfa.media_file_id = mf.id
|
||||||
WHERE jt.atom IN (ROLE_IDS_PLACEHOLDER) -- Will replace with actual placeholders
|
WHERE mfa.artist_id IN (ROLE_IDS_PLACEHOLDER) -- Will replace with actual placeholders
|
||||||
GROUP BY jt.atom, mf.library_id, role
|
GROUP BY mfa.artist_id, mf.library_id, mfa.role
|
||||||
),
|
),
|
||||||
artist_total_counters AS (
|
artist_total_counters AS (
|
||||||
SELECT mfa.artist_id,
|
SELECT mfa.artist_id,
|
||||||
@ -445,24 +438,24 @@ func (r *artistRepository) RefreshStats(allArtists bool) (int64, error) {
|
|||||||
),
|
),
|
||||||
combined_counters AS (
|
combined_counters AS (
|
||||||
SELECT artist_id, library_id, role, album_count, count, size FROM artist_role_counters
|
SELECT artist_id, library_id, role, album_count, count, size FROM artist_role_counters
|
||||||
UNION
|
UNION ALL
|
||||||
SELECT artist_id, library_id, role, album_count, count, size FROM artist_total_counters
|
SELECT artist_id, library_id, role, album_count, count, size FROM artist_total_counters
|
||||||
UNION
|
UNION ALL
|
||||||
SELECT artist_id, library_id, role, album_count, count, size FROM artist_participant_counter
|
SELECT artist_id, library_id, role, album_count, count, size FROM artist_participant_counter
|
||||||
),
|
),
|
||||||
library_artist_counters AS (
|
library_artist_counters AS (
|
||||||
SELECT artist_id,
|
SELECT artist_id,
|
||||||
library_id,
|
library_id,
|
||||||
json_group_object(
|
json_group_object(
|
||||||
replace(role, '"', ''),
|
role,
|
||||||
json_object('a', album_count, 'm', count, 's', size)
|
json_object('a', album_count, 'm', count, 's', size)
|
||||||
) AS counters
|
) AS counters
|
||||||
FROM combined_counters
|
FROM combined_counters
|
||||||
GROUP BY artist_id, library_id
|
GROUP BY artist_id, library_id
|
||||||
)
|
)
|
||||||
UPDATE library_artist
|
UPDATE library_artist
|
||||||
SET stats = coalesce((SELECT counters FROM library_artist_counters lac
|
SET stats = coalesce((SELECT counters FROM library_artist_counters lac
|
||||||
WHERE lac.artist_id = library_artist.artist_id
|
WHERE lac.artist_id = library_artist.artist_id
|
||||||
AND lac.library_id = library_artist.library_id), '{}')
|
AND lac.library_id = library_artist.library_id), '{}')
|
||||||
WHERE library_artist.artist_id IN (ROLE_IDS_PLACEHOLDER);` // Will replace with actual placeholders
|
WHERE library_artist.artist_id IN (ROLE_IDS_PLACEHOLDER);` // Will replace with actual placeholders
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
import ReactGA from 'react-ga'
|
import ReactGA from 'react-ga'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { createHashHistory } from 'history'
|
import { createHashHistory } from 'history'
|
||||||
import { Admin as RAAdmin, Resource } from 'react-admin'
|
import {
|
||||||
|
Admin as RAAdmin,
|
||||||
|
Resource,
|
||||||
|
useSetLocale,
|
||||||
|
useRefresh,
|
||||||
|
} from 'react-admin'
|
||||||
import { HotKeys } from 'react-hotkeys'
|
import { HotKeys } from 'react-hotkeys'
|
||||||
import dataProvider from './dataProvider'
|
import dataProvider from './dataProvider'
|
||||||
import authProvider from './authProvider'
|
import authProvider from './authProvider'
|
||||||
@ -34,7 +39,7 @@ import {
|
|||||||
shareDialogReducer,
|
shareDialogReducer,
|
||||||
} from './reducers'
|
} from './reducers'
|
||||||
import createAdminStore from './store/createAdminStore'
|
import createAdminStore from './store/createAdminStore'
|
||||||
import { i18nProvider } from './i18n'
|
import { i18nProvider, retrieveTranslation } from './i18n'
|
||||||
import config, { shareInfo } from './config'
|
import config, { shareInfo } from './config'
|
||||||
import { keyMap } from './hotkeys'
|
import { keyMap } from './hotkeys'
|
||||||
import useChangeThemeColor from './useChangeThemeColor'
|
import useChangeThemeColor from './useChangeThemeColor'
|
||||||
@ -42,6 +47,7 @@ import SharePlayer from './share/SharePlayer'
|
|||||||
import { HTML5Backend } from 'react-dnd-html5-backend'
|
import { HTML5Backend } from 'react-dnd-html5-backend'
|
||||||
import { DndProvider } from 'react-dnd'
|
import { DndProvider } from 'react-dnd'
|
||||||
import missing from './missing/index.js'
|
import missing from './missing/index.js'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
const history = createHashHistory()
|
const history = createHashHistory()
|
||||||
|
|
||||||
@ -81,6 +87,24 @@ const App = () => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const Admin = (props) => {
|
const Admin = (props) => {
|
||||||
|
const setLocale = useSetLocale()
|
||||||
|
const refresh = useRefresh()
|
||||||
|
useEffect(() => {
|
||||||
|
if (config.defaultLanguage !== '' && !localStorage.getItem('locale')) {
|
||||||
|
retrieveTranslation(config.defaultLanguage)
|
||||||
|
.then(() => setLocale(config.defaultLanguage))
|
||||||
|
.then(() => {
|
||||||
|
localStorage.setItem('locale', config.defaultLanguage)
|
||||||
|
refresh(true)
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(
|
||||||
|
'Cannot load language "' + config.defaultLanguage + '": ' + e,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [setLocale, refresh])
|
||||||
useChangeThemeColor()
|
useChangeThemeColor()
|
||||||
/* eslint-disable react/jsx-key */
|
/* eslint-disable react/jsx-key */
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -127,6 +127,7 @@ const Player = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
locale: locale(translate),
|
locale: locale(translate),
|
||||||
|
sortableOptions: { delay: 200, delayOnTouchOnly: true },
|
||||||
}),
|
}),
|
||||||
[gainInfo, isDesktop, playerTheme, translate, playerState.mode],
|
[gainInfo, isDesktop, playerTheme, translate, playerState.mode],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback, useEffect } from 'react'
|
import React, { useState, useCallback } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Field, Form } from 'react-final-form'
|
import { Field, Form } from 'react-final-form'
|
||||||
import { useDispatch } from 'react-redux'
|
import { useDispatch } from 'react-redux'
|
||||||
@ -13,8 +13,6 @@ import {
|
|||||||
createMuiTheme,
|
createMuiTheme,
|
||||||
useLogin,
|
useLogin,
|
||||||
useNotify,
|
useNotify,
|
||||||
useRefresh,
|
|
||||||
useSetLocale,
|
|
||||||
useTranslate,
|
useTranslate,
|
||||||
useVersion,
|
useVersion,
|
||||||
} from 'react-admin'
|
} from 'react-admin'
|
||||||
@ -24,7 +22,6 @@ import Notification from './Notification'
|
|||||||
import useCurrentTheme from '../themes/useCurrentTheme'
|
import useCurrentTheme from '../themes/useCurrentTheme'
|
||||||
import config from '../config'
|
import config from '../config'
|
||||||
import { clearQueue } from '../actions'
|
import { clearQueue } from '../actions'
|
||||||
import { retrieveTranslation } from '../i18n'
|
|
||||||
import { INSIGHTS_DOC_URL } from '../consts.js'
|
import { INSIGHTS_DOC_URL } from '../consts.js'
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
@ -400,27 +397,8 @@ Login.propTypes = {
|
|||||||
// the right theme
|
// the right theme
|
||||||
const LoginWithTheme = (props) => {
|
const LoginWithTheme = (props) => {
|
||||||
const theme = useCurrentTheme()
|
const theme = useCurrentTheme()
|
||||||
const setLocale = useSetLocale()
|
|
||||||
const refresh = useRefresh()
|
|
||||||
const version = useVersion()
|
const version = useVersion()
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (config.defaultLanguage !== '' && !localStorage.getItem('locale')) {
|
|
||||||
retrieveTranslation(config.defaultLanguage)
|
|
||||||
.then(() => {
|
|
||||||
setLocale(config.defaultLanguage).then(() => {
|
|
||||||
localStorage.setItem('locale', config.defaultLanguage)
|
|
||||||
})
|
|
||||||
refresh(true)
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
throw new Error(
|
|
||||||
'Cannot load language "' + config.defaultLanguage + '": ' + e,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [refresh, setLocale])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={createMuiTheme(theme)}>
|
<ThemeProvider theme={createMuiTheme(theme)}>
|
||||||
<Login key={version} {...props} />
|
<Login key={version} {...props} />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user