optimizations, added captions
This commit is contained in:
@@ -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>
|
||||||
{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 />
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user