mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-04 21:17:37 +03:00
Fine tune scan status behaviour
This commit is contained in:
parent
0e7163eb2c
commit
c09ba509b2
5 changed files with 76 additions and 26 deletions
|
@ -110,8 +110,22 @@ func (s *scanner) rescan(mediaFolder string, fullRescan bool) error {
|
||||||
log.Debug("Scanning folder (full scan)", "folder", mediaFolder)
|
log.Debug("Scanning folder (full scan)", "folder", mediaFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress := s.startProgressTracker(mediaFolder)
|
||||||
|
defer close(progress)
|
||||||
|
|
||||||
|
err := folderScanner.Scan(log.NewContext(context.TODO()), lastModifiedSince, progress)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error importing MediaFolder", "folder", mediaFolder, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.updateLastModifiedSince(mediaFolder, start)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *scanner) startProgressTracker(mediaFolder string) chan uint32 {
|
||||||
progress := make(chan uint32, 100)
|
progress := make(chan uint32, 100)
|
||||||
go func() {
|
go func() {
|
||||||
|
s.broker.SendMessage(&events.ScanStatus{Scanning: true, Count: 0})
|
||||||
defer func() {
|
defer func() {
|
||||||
s.broker.SendMessage(&events.ScanStatus{Scanning: false, Count: int64(s.status[mediaFolder].count)})
|
s.broker.SendMessage(&events.ScanStatus{Scanning: false, Count: int64(s.status[mediaFolder].count)})
|
||||||
}()
|
}()
|
||||||
|
@ -127,15 +141,7 @@ func (s *scanner) rescan(mediaFolder string, fullRescan bool) error {
|
||||||
s.broker.SendMessage(&events.ScanStatus{Scanning: true, Count: int64(total)})
|
s.broker.SendMessage(&events.ScanStatus{Scanning: true, Count: int64(total)})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
return progress
|
||||||
err := folderScanner.Scan(log.NewContext(context.TODO()), lastModifiedSince, progress)
|
|
||||||
close(progress)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error importing MediaFolder", "folder", mediaFolder, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.updateLastModifiedSince(mediaFolder, start)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scanner) RescanAll(fullRescan bool) error {
|
func (s *scanner) RescanAll(fullRescan bool) error {
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
export const EVENT_SCAN_STATUS = 'ACTIVITY_SCAN_STATUS_UPD'
|
export const EVENT_SCAN_STATUS = 'EVENT_SCAN_STATUS'
|
||||||
|
|
||||||
const actionsMap = { scanStatus: EVENT_SCAN_STATUS }
|
const actionsMap = { scanStatus: EVENT_SCAN_STATUS }
|
||||||
|
|
||||||
export const processEvent = (data) => {
|
export const processEvent = (data) => {
|
||||||
let type = actionsMap[data.name]
|
let type = actionsMap[data.name]
|
||||||
if (!type) type = 'EVENT_UNKNOWN'
|
if (!type) type = data.name
|
||||||
return {
|
return {
|
||||||
type,
|
type,
|
||||||
data: data.data,
|
data: data.data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const scanStatusUpdate = (data) =>
|
||||||
|
processEvent({
|
||||||
|
name: EVENT_SCAN_STATUS,
|
||||||
|
data: data,
|
||||||
|
})
|
||||||
|
|
|
@ -21,4 +21,5 @@ export * from './StarButton'
|
||||||
export * from './Title'
|
export * from './Title'
|
||||||
export * from './SongBulkActions'
|
export * from './SongBulkActions'
|
||||||
export * from './useAlbumsPerPage'
|
export * from './useAlbumsPerPage'
|
||||||
|
export * from './useInterval'
|
||||||
export * from './Writable'
|
export * from './Writable'
|
||||||
|
|
23
ui/src/common/useInterval.js
Normal file
23
ui/src/common/useInterval.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// From https://overreacted.io/making-setinterval-declarative-with-react-hooks/
|
||||||
|
|
||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
|
||||||
|
export const useInterval = (callback, delay) => {
|
||||||
|
const savedCallback = useRef()
|
||||||
|
|
||||||
|
// Remember the latest callback.
|
||||||
|
useEffect(() => {
|
||||||
|
savedCallback.current = callback
|
||||||
|
}, [callback])
|
||||||
|
|
||||||
|
// Set up the interval.
|
||||||
|
useEffect(() => {
|
||||||
|
function tick() {
|
||||||
|
savedCallback.current()
|
||||||
|
}
|
||||||
|
if (delay !== null) {
|
||||||
|
let id = setInterval(tick, delay)
|
||||||
|
return () => clearInterval(id)
|
||||||
|
}
|
||||||
|
}, [delay])
|
||||||
|
}
|
|
@ -1,16 +1,18 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
import { fetchUtils } from 'react-admin'
|
||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
|
MenuItem,
|
||||||
Badge,
|
Badge,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
IconButton,
|
IconButton,
|
||||||
makeStyles,
|
makeStyles,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
MenuItem,
|
|
||||||
} from '@material-ui/core'
|
} from '@material-ui/core'
|
||||||
import { FiActivity } from 'react-icons/fi'
|
import { FiActivity } from 'react-icons/fi'
|
||||||
import subsonic from '../subsonic'
|
import subsonic from '../subsonic'
|
||||||
|
import { scanStatusUpdate } from '../actions'
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
wrapper: {
|
wrapper: {
|
||||||
|
@ -18,8 +20,8 @@ const useStyles = makeStyles((theme) => ({
|
||||||
},
|
},
|
||||||
progress: {
|
progress: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: -1,
|
top: 10,
|
||||||
left: 0,
|
left: 10,
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
|
@ -30,31 +32,43 @@ const useStyles = makeStyles((theme) => ({
|
||||||
const ActivityMenu = () => {
|
const ActivityMenu = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
const [anchorEl, setAnchorEl] = useState(null)
|
||||||
const scanStatus = useSelector((state) => state.activity.scanStatus)
|
|
||||||
|
|
||||||
const open = Boolean(anchorEl)
|
const open = Boolean(anchorEl)
|
||||||
|
const scanStatus = useSelector((state) => state.activity.scanStatus)
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
const handleMenu = (event) => setAnchorEl(event.currentTarget)
|
const handleMenuOpen = (event) => setAnchorEl(event.currentTarget)
|
||||||
const handleClose = () => setAnchorEl(null)
|
const handleCloseClose = () => setAnchorEl(null)
|
||||||
const startScan = () => fetch(subsonic.url('startScan', null))
|
const triggerScan = () => fetch(subsonic.url('startScan'))
|
||||||
|
|
||||||
|
// Get updated status on component mount
|
||||||
|
useEffect(() => {
|
||||||
|
fetchUtils
|
||||||
|
.fetchJson(subsonic.url('getScanStatus'))
|
||||||
|
.then((resp) => resp.json['subsonic-response'])
|
||||||
|
.then((data) => {
|
||||||
|
if (data.status === 'ok') {
|
||||||
|
dispatch(scanStatusUpdate(data.scanStatus))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [dispatch])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.wrapper}>
|
<div className={classes.wrapper}>
|
||||||
<Tooltip title={'Activity'}>
|
<Tooltip title={'Activity'}>
|
||||||
<IconButton className={classes.button} onClick={handleMenu}>
|
<IconButton className={classes.button} onClick={handleMenuOpen}>
|
||||||
<Badge badgeContent={null} color="secondary">
|
<Badge badgeContent={null} color="secondary">
|
||||||
<FiActivity size={'20'} />
|
<FiActivity size={'20'} />
|
||||||
</Badge>
|
</Badge>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{scanStatus.scanning && (
|
{scanStatus.scanning && (
|
||||||
<CircularProgress size={46} className={classes.progress} />
|
<CircularProgress size={24} className={classes.progress} />
|
||||||
)}
|
)}
|
||||||
<Menu
|
<Menu
|
||||||
id="menu-activity"
|
id="menu-activity"
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
anchorOrigin={{
|
anchorOrigin={{
|
||||||
vertical: 'top',
|
vertical: 'bottom',
|
||||||
horizontal: 'right',
|
horizontal: 'right',
|
||||||
}}
|
}}
|
||||||
transformOrigin={{
|
transformOrigin={{
|
||||||
|
@ -62,12 +76,12 @@ const ActivityMenu = () => {
|
||||||
horizontal: 'right',
|
horizontal: 'right',
|
||||||
}}
|
}}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={handleClose}
|
onClose={handleCloseClose}
|
||||||
>
|
>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className={classes.root}
|
className={classes.root}
|
||||||
activeClassName={classes.active}
|
activeClassName={classes.active}
|
||||||
onClick={startScan}
|
onClick={triggerScan}
|
||||||
sidebarIsOpen={true}
|
sidebarIsOpen={true}
|
||||||
>
|
>
|
||||||
{`Scanned: ${scanStatus.count}`}
|
{`Scanned: ${scanStatus.count}`}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue