optimizations, added captions

This commit is contained in:
2023-11-02 10:05:34 +01:00
parent 19f9b10844
commit 00b3fccbdc
7 changed files with 107 additions and 21 deletions

View File

@@ -28,6 +28,7 @@ import FreeSpaceIndicator from './components/FreeSpaceIndicator'
import Logout from './components/Logout' import Logout from './components/Logout'
import SocketSubscriber from './components/SocketSubscriber' import SocketSubscriber from './components/SocketSubscriber'
import ThemeToggler from './components/ThemeToggler' import ThemeToggler from './components/ThemeToggler'
import { useI18n } from './hooks/useI18n'
import Toaster from './providers/ToasterProvider' import Toaster from './providers/ToasterProvider'
export default function Layout() { export default function Layout() {
@@ -50,6 +51,8 @@ export default function Layout() {
const toggleDrawer = () => setOpen(state => !state) const toggleDrawer = () => setOpen(state => !state)
const { i18n } = useI18n()
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<SocketSubscriber> <SocketSubscriber>
@@ -88,10 +91,11 @@ export default function Layout() {
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
flexWrap: 'wrap', flexWrap: 'wrap',
gap: 3,
}}> }}>
<SettingsEthernet /> <SettingsEthernet />
<span> <span>
&nbsp;{isConnected ? settings.serverAddr : 'not connected'} {isConnected ? settings.serverAddr : i18n.t('notConnectedText')}
</span> </span>
</div> </div>
</Toolbar> </Toolbar>
@@ -121,7 +125,7 @@ export default function Layout() {
<ListItemIcon> <ListItemIcon>
<Dashboard /> <Dashboard />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Home" /> <ListItemText primary={i18n.t('homeButtonLabel')} />
</ListItemButton> </ListItemButton>
</Link> </Link>
<Link to={'/archive'} style={ <Link to={'/archive'} style={
@@ -134,7 +138,7 @@ export default function Layout() {
<ListItemIcon> <ListItemIcon>
<DownloadIcon /> <DownloadIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Archive" /> <ListItemText primary={i18n.t('archiveButtonLabel')} />
</ListItemButton> </ListItemButton>
</Link> </Link>
<Link to={'/settings'} style={ <Link to={'/settings'} style={
@@ -147,7 +151,7 @@ export default function Layout() {
<ListItemIcon> <ListItemIcon>
<SettingsIcon /> <SettingsIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Settings" /> <ListItemText primary={i18n.t('settingsButtonLabel')} />
</ListItemButton> </ListItemButton>
</Link> </Link>
<ThemeToggler /> <ThemeToggler />

View File

@@ -35,6 +35,12 @@ languages:
playlistCheckbox: Download playlist (it will take time, after submitting you may close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may close this window)
restartAppMessage: Needs a page reload to take effect restartAppMessage: Needs a page reload to take effect
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -75,6 +81,14 @@ languages:
playlistCheckbox: Télécharger la liste de lecture (cela prendra du temps, vous pouvez fermer cette fenêtre après l'avoir validée) playlistCheckbox: Télécharger la liste de lecture (cela prendra du temps, vous pouvez fermer cette fenêtre après l'avoir validée)
restartAppMessage: Nécessite un rechargement de la page pour prendre effet restartAppMessage: Nécessite un rechargement de la page pour prendre effet
servedFromReverseProxyCheckbox: Est derrière un sous-dossier de proxy inverse servedFromReverseProxyCheckbox: Est derrière un sous-dossier de proxy inverse
notConnectedText: not connected
settingsLabel: Settings
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: Nom de l'application appTitle: Nom de l'application
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -114,6 +128,12 @@ languages:
playlistCheckbox: Download playlist (richiederà tempo, puoi chiudere la finestra dopo l'inoltro) playlistCheckbox: Download playlist (richiederà tempo, puoi chiudere la finestra dopo l'inoltro)
restartAppMessage: La finestra deve essere ricaricata perché abbia effetto restartAppMessage: La finestra deve essere ricaricata perché abbia effetto
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: Nuovo download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: Titolo applicazione appTitle: Titolo applicazione
savedTemplates: Template salvati savedTemplates: Template salvati
templatesEditor: Editor template templatesEditor: Editor template
@@ -154,6 +174,12 @@ languages:
playlistCheckbox: 下载播放列表(可能需要一段时间,提交后可以关闭页面等待) playlistCheckbox: 下载播放列表(可能需要一段时间,提交后可以关闭页面等待)
restartAppMessage: 需要刷新页面才能生效 restartAppMessage: 需要刷新页面才能生效
servedFromReverseProxyCheckbox: 处于反向代理的子目录后 servedFromReverseProxyCheckbox: 处于反向代理的子目录后
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App 标题 appTitle: App 标题
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -192,6 +218,12 @@ languages:
clipboardAction: Copied URL to clipboard clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -230,6 +262,12 @@ languages:
clipboardAction: URL скопирован в буфер обмена clipboardAction: URL скопирован в буфер обмена
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -268,6 +306,12 @@ languages:
clipboardAction: Copied URL to clipboard clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -307,6 +351,12 @@ languages:
clipboardAction: Copied URL to clipboard clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -345,6 +395,12 @@ languages:
clipboardAction: Copied URL to clipboard clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -383,6 +439,12 @@ languages:
clipboardAction: URL скопійовано в буфер обміну clipboardAction: URL скопійовано в буфер обміну
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor
@@ -421,6 +483,12 @@ languages:
clipboardAction: Adres URL zostanie skopiowany do schowka clipboardAction: Adres URL zostanie skopiowany do schowka
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window) playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
newDownloadButton: New download
homeButtonLabel: Home
archiveButtonLabel: Archive
settingsButtonLabel: Settings
rpcAuthenticationLabel: RPC authentication
themeTogglerLabel: Theme toggler
appTitle: App title appTitle: App title
savedTemplates: Saved templates savedTemplates: Saved templates
templatesEditor: Templates editor templatesEditor: Templates editor

View File

@@ -48,7 +48,7 @@ const HomeSpeedDial: React.FC<Props> = ({ onDownloadOpen, onEditorOpen }) => {
/> />
<SpeedDialAction <SpeedDialAction
icon={<AddCircleIcon />} icon={<AddCircleIcon />}
tooltipTitle={i18n.t('newDownload')} tooltipTitle={i18n.t('newDownloadButton')}
onClick={onDownloadOpen} onClick={onDownloadOpen}
/> />
</SpeedDial> </SpeedDial>

View File

@@ -1,8 +1,9 @@
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
import LogoutIcon from '@mui/icons-material/Logout' import LogoutIcon from '@mui/icons-material/Logout'
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { serverURL } from '../atoms/settings' import { serverURL } from '../atoms/settings'
import { useI18n } from '../hooks/useI18n'
export default function Logout() { export default function Logout() {
const navigate = useNavigate() const navigate = useNavigate()
@@ -15,12 +16,14 @@ export default function Logout() {
} }
} }
const { i18n } = useI18n()
return ( return (
<ListItemButton onClick={logout}> <ListItemButton onClick={logout}>
<ListItemIcon> <ListItemIcon>
<LogoutIcon /> <LogoutIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="RPC authentication" /> <ListItemText primary={i18n.t('rpcAuthenticationLabel')} />
</ListItemButton> </ListItemButton>
) )
} }

View File

@@ -4,6 +4,7 @@ import BrightnessAuto from '@mui/icons-material/BrightnessAuto'
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material' import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
import { useRecoilState } from 'recoil' import { useRecoilState } from 'recoil'
import { Theme, themeState } from '../atoms/settings' import { Theme, themeState } from '../atoms/settings'
import { useI18n } from '../hooks/useI18n'
const ThemeToggler: React.FC = () => { const ThemeToggler: React.FC = () => {
const [theme, setTheme] = useRecoilState(themeState) const [theme, setTheme] = useRecoilState(themeState)
@@ -17,6 +18,8 @@ const ThemeToggler: React.FC = () => {
const themes: Theme[] = ['system', 'light', 'dark'] const themes: Theme[] = ['system', 'light', 'dark']
const currentTheme = themes.indexOf(theme) const currentTheme = themes.indexOf(theme)
const { i18n } = useI18n()
return ( return (
<ListItemButton onClick={() => { <ListItemButton onClick={() => {
setTheme(themes[(currentTheme + 1) % themes.length]) setTheme(themes[(currentTheme + 1) % themes.length])
@@ -24,7 +27,7 @@ const ThemeToggler: React.FC = () => {
<ListItemIcon> <ListItemIcon>
{actions[theme]} {actions[theme]}
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Toggle theme" /> <ListItemText primary={i18n.t('themeTogglerLabel')} />
</ListItemButton> </ListItemButton>
) )
} }

View File

@@ -4,9 +4,10 @@ import i18n from "../assets/i18n.yaml"
export default class I18nBuilder { export default class I18nBuilder {
private language: string private language: string
private textMap = i18n.languages private textMap = i18n.languages
private current: string[]
constructor(language: string) { constructor(language: string) {
this.language = language this.setLanguage(language)
} }
getLanguage(): string { getLanguage(): string {
@@ -15,13 +16,12 @@ export default class I18nBuilder {
setLanguage(language: string): void { setLanguage(language: string): void {
this.language = language this.language = language
this.current = this.textMap[this.language]
} }
t(key: string): string { t(key: string): string {
const map = this.textMap[this.language] if (this.current) {
if (map) { return this.current[key] ?? 'caption not defined'
const translation = map[key]
return translation ?? 'caption not defined'
} }
return 'caption not defined' return 'caption not defined'
} }

View File

@@ -27,14 +27,22 @@ type DirectoryEntry struct {
} }
func walkDir(root string) (*[]DirectoryEntry, error) { func walkDir(root string) (*[]DirectoryEntry, error) {
files := []DirectoryEntry{}
dirs, err := os.ReadDir(root) dirs, err := os.ReadDir(root)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var validEntries int
for _, d := range dirs { for _, d := range dirs {
if utils.IsValidEntry(d) {
validEntries++
}
}
files := make([]DirectoryEntry, validEntries)
for i, d := range dirs {
if !utils.IsValidEntry(d) { if !utils.IsValidEntry(d) {
continue continue
} }
@@ -46,7 +54,7 @@ func walkDir(root string) (*[]DirectoryEntry, error) {
return nil, err return nil, err
} }
files = append(files, DirectoryEntry{ files[i] = DirectoryEntry{
Path: path, Path: path,
Name: d.Name(), Name: d.Name(),
Size: info.Size(), Size: info.Size(),
@@ -54,7 +62,7 @@ func walkDir(root string) (*[]DirectoryEntry, error) {
IsVideo: utils.IsVideo(d), IsVideo: utils.IsVideo(d),
IsDirectory: d.IsDir(), IsDirectory: d.IsDir(),
ModTime: info.ModTime(), ModTime: info.ModTime(),
}) }
} }
return &files, err return &files, err
@@ -142,18 +150,18 @@ func SendFile(w http.ResponseWriter, r *http.Request) {
return return
} }
decodedStr := string(decoded) filename := string(decoded)
root := config.Instance().DownloadPath root := config.Instance().DownloadPath
// TODO: further path / file validations // TODO: further path / file validations
if strings.Contains(filepath.Dir(decodedStr), root) { if strings.Contains(filepath.Dir(filename), root) {
w.Header().Add( w.Header().Add(
"Content-Disposition", "Content-Disposition",
"inline; filename="+filepath.Base(decodedStr), "inline; filename="+filepath.Base(filename),
) )
http.ServeFile(w, r, decodedStr) http.ServeFile(w, r, filename)
} }
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)