optimizations, added captions
This commit is contained in:
@@ -28,6 +28,7 @@ import FreeSpaceIndicator from './components/FreeSpaceIndicator'
|
||||
import Logout from './components/Logout'
|
||||
import SocketSubscriber from './components/SocketSubscriber'
|
||||
import ThemeToggler from './components/ThemeToggler'
|
||||
import { useI18n } from './hooks/useI18n'
|
||||
import Toaster from './providers/ToasterProvider'
|
||||
|
||||
export default function Layout() {
|
||||
@@ -50,6 +51,8 @@ export default function Layout() {
|
||||
|
||||
const toggleDrawer = () => setOpen(state => !state)
|
||||
|
||||
const { i18n } = useI18n()
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<SocketSubscriber>
|
||||
@@ -88,10 +91,11 @@ export default function Layout() {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
gap: 3,
|
||||
}}>
|
||||
<SettingsEthernet />
|
||||
<span>
|
||||
{isConnected ? settings.serverAddr : 'not connected'}
|
||||
{isConnected ? settings.serverAddr : i18n.t('notConnectedText')}
|
||||
</span>
|
||||
</div>
|
||||
</Toolbar>
|
||||
@@ -121,7 +125,7 @@ export default function Layout() {
|
||||
<ListItemIcon>
|
||||
<Dashboard />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Home" />
|
||||
<ListItemText primary={i18n.t('homeButtonLabel')} />
|
||||
</ListItemButton>
|
||||
</Link>
|
||||
<Link to={'/archive'} style={
|
||||
@@ -134,7 +138,7 @@ export default function Layout() {
|
||||
<ListItemIcon>
|
||||
<DownloadIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Archive" />
|
||||
<ListItemText primary={i18n.t('archiveButtonLabel')} />
|
||||
</ListItemButton>
|
||||
</Link>
|
||||
<Link to={'/settings'} style={
|
||||
@@ -147,7 +151,7 @@ export default function Layout() {
|
||||
<ListItemIcon>
|
||||
<SettingsIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Settings" />
|
||||
<ListItemText primary={i18n.t('settingsButtonLabel')} />
|
||||
</ListItemButton>
|
||||
</Link>
|
||||
<ThemeToggler />
|
||||
|
||||
@@ -35,6 +35,12 @@ languages:
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may close this window)
|
||||
restartAppMessage: Needs a page reload to take effect
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
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)
|
||||
restartAppMessage: Nécessite un rechargement de la page pour prendre effet
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -114,6 +128,12 @@ languages:
|
||||
playlistCheckbox: Download playlist (richiederà tempo, puoi chiudere la finestra dopo l'inoltro)
|
||||
restartAppMessage: La finestra deve essere ricaricata perché abbia effetto
|
||||
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
|
||||
savedTemplates: Template salvati
|
||||
templatesEditor: Editor template
|
||||
@@ -154,6 +174,12 @@ languages:
|
||||
playlistCheckbox: 下载播放列表(可能需要一段时间,提交后可以关闭页面等待)
|
||||
restartAppMessage: 需要刷新页面才能生效
|
||||
servedFromReverseProxyCheckbox: 处于反向代理的子目录后
|
||||
newDownloadButton: New download
|
||||
homeButtonLabel: Home
|
||||
archiveButtonLabel: Archive
|
||||
settingsButtonLabel: Settings
|
||||
rpcAuthenticationLabel: RPC authentication
|
||||
themeTogglerLabel: Theme toggler
|
||||
appTitle: App 标题
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -192,6 +218,12 @@ languages:
|
||||
clipboardAction: Copied URL to clipboard
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -230,6 +262,12 @@ languages:
|
||||
clipboardAction: URL скопирован в буфер обмена
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -268,6 +306,12 @@ languages:
|
||||
clipboardAction: Copied URL to clipboard
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -307,6 +351,12 @@ languages:
|
||||
clipboardAction: Copied URL to clipboard
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -345,6 +395,12 @@ languages:
|
||||
clipboardAction: Copied URL to clipboard
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -383,6 +439,12 @@ languages:
|
||||
clipboardAction: URL скопійовано в буфер обміну
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
@@ -421,6 +483,12 @@ languages:
|
||||
clipboardAction: Adres URL zostanie skopiowany do schowka
|
||||
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
|
||||
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
|
||||
savedTemplates: Saved templates
|
||||
templatesEditor: Templates editor
|
||||
|
||||
@@ -48,7 +48,7 @@ const HomeSpeedDial: React.FC<Props> = ({ onDownloadOpen, onEditorOpen }) => {
|
||||
/>
|
||||
<SpeedDialAction
|
||||
icon={<AddCircleIcon />}
|
||||
tooltipTitle={i18n.t('newDownload')}
|
||||
tooltipTitle={i18n.t('newDownloadButton')}
|
||||
onClick={onDownloadOpen}
|
||||
/>
|
||||
</SpeedDial>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
|
||||
import LogoutIcon from '@mui/icons-material/Logout'
|
||||
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { serverURL } from '../atoms/settings'
|
||||
import { useI18n } from '../hooks/useI18n'
|
||||
|
||||
export default function Logout() {
|
||||
const navigate = useNavigate()
|
||||
@@ -15,12 +16,14 @@ export default function Logout() {
|
||||
}
|
||||
}
|
||||
|
||||
const { i18n } = useI18n()
|
||||
|
||||
return (
|
||||
<ListItemButton onClick={logout}>
|
||||
<ListItemIcon>
|
||||
<LogoutIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="RPC authentication" />
|
||||
<ListItemText primary={i18n.t('rpcAuthenticationLabel')} />
|
||||
</ListItemButton>
|
||||
)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import BrightnessAuto from '@mui/icons-material/BrightnessAuto'
|
||||
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { Theme, themeState } from '../atoms/settings'
|
||||
import { useI18n } from '../hooks/useI18n'
|
||||
|
||||
const ThemeToggler: React.FC = () => {
|
||||
const [theme, setTheme] = useRecoilState(themeState)
|
||||
@@ -17,6 +18,8 @@ const ThemeToggler: React.FC = () => {
|
||||
const themes: Theme[] = ['system', 'light', 'dark']
|
||||
const currentTheme = themes.indexOf(theme)
|
||||
|
||||
const { i18n } = useI18n()
|
||||
|
||||
return (
|
||||
<ListItemButton onClick={() => {
|
||||
setTheme(themes[(currentTheme + 1) % themes.length])
|
||||
@@ -24,7 +27,7 @@ const ThemeToggler: React.FC = () => {
|
||||
<ListItemIcon>
|
||||
{actions[theme]}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Toggle theme" />
|
||||
<ListItemText primary={i18n.t('themeTogglerLabel')} />
|
||||
</ListItemButton>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@ import i18n from "../assets/i18n.yaml"
|
||||
export default class I18nBuilder {
|
||||
private language: string
|
||||
private textMap = i18n.languages
|
||||
private current: string[]
|
||||
|
||||
constructor(language: string) {
|
||||
this.language = language
|
||||
this.setLanguage(language)
|
||||
}
|
||||
|
||||
getLanguage(): string {
|
||||
@@ -15,13 +16,12 @@ export default class I18nBuilder {
|
||||
|
||||
setLanguage(language: string): void {
|
||||
this.language = language
|
||||
this.current = this.textMap[this.language]
|
||||
}
|
||||
|
||||
t(key: string): string {
|
||||
const map = this.textMap[this.language]
|
||||
if (map) {
|
||||
const translation = map[key]
|
||||
return translation ?? 'caption not defined'
|
||||
if (this.current) {
|
||||
return this.current[key] ?? 'caption not defined'
|
||||
}
|
||||
return 'caption not defined'
|
||||
}
|
||||
|
||||
@@ -27,14 +27,22 @@ type DirectoryEntry struct {
|
||||
}
|
||||
|
||||
func walkDir(root string) (*[]DirectoryEntry, error) {
|
||||
files := []DirectoryEntry{}
|
||||
|
||||
dirs, err := os.ReadDir(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var validEntries int
|
||||
|
||||
for _, d := range dirs {
|
||||
if utils.IsValidEntry(d) {
|
||||
validEntries++
|
||||
}
|
||||
}
|
||||
|
||||
files := make([]DirectoryEntry, validEntries)
|
||||
|
||||
for i, d := range dirs {
|
||||
if !utils.IsValidEntry(d) {
|
||||
continue
|
||||
}
|
||||
@@ -46,7 +54,7 @@ func walkDir(root string) (*[]DirectoryEntry, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
files = append(files, DirectoryEntry{
|
||||
files[i] = DirectoryEntry{
|
||||
Path: path,
|
||||
Name: d.Name(),
|
||||
Size: info.Size(),
|
||||
@@ -54,7 +62,7 @@ func walkDir(root string) (*[]DirectoryEntry, error) {
|
||||
IsVideo: utils.IsVideo(d),
|
||||
IsDirectory: d.IsDir(),
|
||||
ModTime: info.ModTime(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &files, err
|
||||
@@ -142,18 +150,18 @@ func SendFile(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
decodedStr := string(decoded)
|
||||
filename := string(decoded)
|
||||
|
||||
root := config.Instance().DownloadPath
|
||||
|
||||
// TODO: further path / file validations
|
||||
if strings.Contains(filepath.Dir(decodedStr), root) {
|
||||
if strings.Contains(filepath.Dir(filename), root) {
|
||||
w.Header().Add(
|
||||
"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)
|
||||
|
||||
Reference in New Issue
Block a user