removed --no-mtime and -x switches in settings
Custom templates are powerful: --no-mtime has been set as default behavior (template named default), -x is another template named "audio only"
This commit is contained in:
@@ -64,8 +64,7 @@ export const serverAddressState = atom<string>({
|
|||||||
|
|
||||||
export const serverPortState = atom<number>({
|
export const serverPortState = atom<number>({
|
||||||
key: 'serverPortState',
|
key: 'serverPortState',
|
||||||
default: Number(localStorage.getItem('server-port')) ||
|
default: Number(localStorage.getItem('server-port')) || Number(window.location.port),
|
||||||
Number(window.location.port),
|
|
||||||
effects: [
|
effects: [
|
||||||
({ onSet }) =>
|
({ onSet }) =>
|
||||||
onSet(a => localStorage.setItem('server-port', a.toString()))
|
onSet(a => localStorage.setItem('server-port', a.toString()))
|
||||||
@@ -197,7 +196,7 @@ export const cookiesState = atom({
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
export const themeSelector = selector<ThemeNarrowed>({
|
const themeSelector = selector<ThemeNarrowed>({
|
||||||
key: 'themeSelector',
|
key: 'themeSelector',
|
||||||
get: ({ get }) => {
|
get: ({ get }) => {
|
||||||
const theme = get(themeState)
|
const theme = get(themeState)
|
||||||
|
|||||||
@@ -6,16 +6,6 @@ export const connectedState = atom({
|
|||||||
default: false
|
default: false
|
||||||
})
|
})
|
||||||
|
|
||||||
export const updatedBinaryState = atom({
|
|
||||||
key: 'updatedBinaryState',
|
|
||||||
default: false
|
|
||||||
})
|
|
||||||
|
|
||||||
export const isDownloadingState = atom({
|
|
||||||
key: 'isDownloadingState',
|
|
||||||
default: false
|
|
||||||
})
|
|
||||||
|
|
||||||
export const freeSpaceBytesState = selector({
|
export const freeSpaceBytesState = selector({
|
||||||
key: 'freeSpaceBytesState',
|
key: 'freeSpaceBytesState',
|
||||||
get: async ({ get }) => {
|
get: async ({ get }) => {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { styled } from '@mui/material';
|
import { styled } from '@mui/material'
|
||||||
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar';
|
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'
|
||||||
|
|
||||||
interface AppBarProps extends MuiAppBarProps {
|
interface AppBarProps extends MuiAppBarProps {
|
||||||
open?: boolean
|
open?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const drawerWidth = 240;
|
const drawerWidth = 240
|
||||||
|
|
||||||
const AppBar = styled(MuiAppBar, {
|
const AppBar = styled(MuiAppBar, {
|
||||||
shouldForwardProp: (prop) => prop !== 'open',
|
shouldForwardProp: (prop) => prop !== 'open',
|
||||||
@@ -23,6 +23,6 @@ const AppBar = styled(MuiAppBar, {
|
|||||||
duration: theme.transitions.duration.enteringScreen,
|
duration: theme.transitions.duration.enteringScreen,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}));
|
}))
|
||||||
|
|
||||||
export default AppBar
|
export default AppBar
|
||||||
@@ -26,19 +26,17 @@ import {
|
|||||||
Suspense,
|
Suspense,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
useTransition
|
useTransition
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { customArgsState, downloadTemplateState, filenameTemplateState, savedTemplatesState } from '../atoms/downloadTemplate'
|
import { customArgsState, downloadTemplateState, filenameTemplateState, savedTemplatesState } from '../atoms/downloadTemplate'
|
||||||
import { latestCliArgumentsState, settingsState } from '../atoms/settings'
|
import { settingsState } from '../atoms/settings'
|
||||||
import { availableDownloadPathsState, connectedState } from '../atoms/status'
|
import { availableDownloadPathsState, connectedState } from '../atoms/status'
|
||||||
import FormatsGrid from '../components/FormatsGrid'
|
import FormatsGrid from '../components/FormatsGrid'
|
||||||
import { useI18n } from '../hooks/useI18n'
|
import { useI18n } from '../hooks/useI18n'
|
||||||
import { useRPC } from '../hooks/useRPC'
|
import { useRPC } from '../hooks/useRPC'
|
||||||
import { CliArguments } from '../lib/argsParser'
|
|
||||||
import type { DLMetadata } from '../types'
|
import type { DLMetadata } from '../types'
|
||||||
import { toFormatArgs } from '../utils'
|
import { toFormatArgs } from '../utils'
|
||||||
import ExtraDownloadOptions from './ExtraDownloadOptions'
|
import ExtraDownloadOptions from './ExtraDownloadOptions'
|
||||||
@@ -71,7 +69,6 @@ const DownloadDialog: FC<Props> = ({ open, onClose, onDownloadStart }) => {
|
|||||||
const [pickedBestFormat, setPickedBestFormat] = useState('')
|
const [pickedBestFormat, setPickedBestFormat] = useState('')
|
||||||
|
|
||||||
const [customArgs, setCustomArgs] = useRecoilState(customArgsState)
|
const [customArgs, setCustomArgs] = useRecoilState(customArgsState)
|
||||||
const [, setCliArgs] = useRecoilState(latestCliArgumentsState)
|
|
||||||
|
|
||||||
const [downloadPath, setDownloadPath] = useState('')
|
const [downloadPath, setDownloadPath] = useState('')
|
||||||
|
|
||||||
@@ -83,10 +80,6 @@ const DownloadDialog: FC<Props> = ({ open, onClose, onDownloadStart }) => {
|
|||||||
|
|
||||||
const [isPlaylist, setIsPlaylist] = useState(false)
|
const [isPlaylist, setIsPlaylist] = useState(false)
|
||||||
|
|
||||||
const argsBuilder = useMemo(() =>
|
|
||||||
new CliArguments().fromString(settings.cliArgs), [settings.cliArgs]
|
|
||||||
)
|
|
||||||
|
|
||||||
const { i18n } = useI18n()
|
const { i18n } = useI18n()
|
||||||
const { client } = useRPC()
|
const { client } = useRPC()
|
||||||
|
|
||||||
@@ -112,7 +105,7 @@ const DownloadDialog: FC<Props> = ({ open, onClose, onDownloadStart }) => {
|
|||||||
await new Promise(r => setTimeout(r, 10))
|
await new Promise(r => setTimeout(r, 10))
|
||||||
await client.download({
|
await client.download({
|
||||||
url: immediate || line,
|
url: immediate || line,
|
||||||
args: `${argsBuilder.toString()} ${toFormatArgs(codes)} ${downloadTemplate}`,
|
args: `${toFormatArgs(codes)} ${downloadTemplate}`,
|
||||||
pathOverride: downloadPath ?? '',
|
pathOverride: downloadPath ?? '',
|
||||||
renameTo: settings.fileRenaming ? filenameTemplate : '',
|
renameTo: settings.fileRenaming ? filenameTemplate : '',
|
||||||
playlist: isPlaylist,
|
playlist: isPlaylist,
|
||||||
@@ -327,19 +320,6 @@ const DownloadDialog: FC<Props> = ({ open, onClose, onDownloadStart }) => {
|
|||||||
label={i18n.t('playlistCheckbox')}
|
label={i18n.t('playlistCheckbox')}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
onChange={() => setCliArgs(argsBuilder.toggleExtractAudio().toString())}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
checked={argsBuilder.extractAudio}
|
|
||||||
onChange={() => setCliArgs(argsBuilder.toggleExtractAudio().toString())}
|
|
||||||
disabled={settings.formatSelection}
|
|
||||||
label={i18n.t('extractAudioCheckbox')}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ const ExtraDownloadOptions: React.FC = () => {
|
|||||||
disablePortal
|
disablePortal
|
||||||
options={customTemplates.map(({ name, content }) => ({ label: name, content }))}
|
options={customTemplates.map(({ name, content }) => ({ label: name, content }))}
|
||||||
autoHighlight
|
autoHighlight
|
||||||
|
defaultValue={
|
||||||
|
customTemplates
|
||||||
|
.filter(({ id, name }) => id === "0" || name === "default")
|
||||||
|
.map(({ name, content }) => ({ label: name, content }))
|
||||||
|
.at(0)
|
||||||
|
}
|
||||||
getOptionLabel={(option) => option.label}
|
getOptionLabel={(option) => option.label}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
setCustomArgs(value?.content!)
|
setCustomArgs(value?.content!)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import AddCircleIcon from '@mui/icons-material/AddCircle'
|
import AddCircleIcon from '@mui/icons-material/AddCircle'
|
||||||
import BuildCircleIcon from '@mui/icons-material/BuildCircle'
|
import BuildCircleIcon from '@mui/icons-material/BuildCircle'
|
||||||
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'
|
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'
|
||||||
|
import FolderZipIcon from '@mui/icons-material/FolderZip'
|
||||||
import FormatListBulleted from '@mui/icons-material/FormatListBulleted'
|
import FormatListBulleted from '@mui/icons-material/FormatListBulleted'
|
||||||
import ViewAgendaIcon from '@mui/icons-material/ViewAgenda'
|
import ViewAgendaIcon from '@mui/icons-material/ViewAgenda'
|
||||||
import FolderZipIcon from '@mui/icons-material/FolderZip'
|
|
||||||
import {
|
import {
|
||||||
SpeedDial,
|
SpeedDial,
|
||||||
SpeedDialAction,
|
SpeedDialAction,
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import LogoutIcon from '@mui/icons-material/Logout'
|
import LogoutIcon from '@mui/icons-material/Logout'
|
||||||
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
|
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { useRecoilValue } from 'recoil'
|
|
||||||
import { serverURL } from '../atoms/settings'
|
|
||||||
import { useI18n } from '../hooks/useI18n'
|
import { useI18n } from '../hooks/useI18n'
|
||||||
|
|
||||||
export default function Logout() {
|
export default function Logout() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const url = useRecoilValue(serverURL)
|
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
localStorage.removeItem('token')
|
localStorage.removeItem('token')
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
export class CliArguments {
|
|
||||||
private _extractAudio: boolean
|
|
||||||
private _noMTime: boolean
|
|
||||||
|
|
||||||
constructor(extractAudio = false, noMTime = true) {
|
|
||||||
this._extractAudio = extractAudio
|
|
||||||
this._noMTime = noMTime
|
|
||||||
}
|
|
||||||
|
|
||||||
public get extractAudio(): boolean {
|
|
||||||
return this._extractAudio
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleExtractAudio() {
|
|
||||||
this._extractAudio = !this._extractAudio
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
public disableExtractAudio() {
|
|
||||||
this._extractAudio = false
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
public get noMTime(): boolean {
|
|
||||||
return this._noMTime
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleNoMTime() {
|
|
||||||
this._noMTime = !this._noMTime
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
public toString(): string {
|
|
||||||
let args = ''
|
|
||||||
|
|
||||||
if (this._extractAudio) {
|
|
||||||
args += '-x '
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._noMTime) {
|
|
||||||
args += '--no-mtime '
|
|
||||||
}
|
|
||||||
|
|
||||||
return args.trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
private reset() {
|
|
||||||
this._extractAudio = false
|
|
||||||
this._noMTime = false
|
|
||||||
}
|
|
||||||
|
|
||||||
public fromString(str: string): CliArguments {
|
|
||||||
this.reset()
|
|
||||||
|
|
||||||
if (str) {
|
|
||||||
if (str.includes('-x')) {
|
|
||||||
this._extractAudio = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str.includes('--no-mtime')) {
|
|
||||||
this._noMTime = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,6 @@ import {
|
|||||||
formatSelectionState,
|
formatSelectionState,
|
||||||
languageState,
|
languageState,
|
||||||
languages,
|
languages,
|
||||||
latestCliArgumentsState,
|
|
||||||
pathOverridingState,
|
pathOverridingState,
|
||||||
servedFromReverseProxyState,
|
servedFromReverseProxyState,
|
||||||
servedFromReverseProxySubDirState,
|
servedFromReverseProxySubDirState,
|
||||||
@@ -49,7 +48,6 @@ import CookiesTextField from '../components/CookiesTextField'
|
|||||||
import { useToast } from '../hooks/toast'
|
import { useToast } from '../hooks/toast'
|
||||||
import { useI18n } from '../hooks/useI18n'
|
import { useI18n } from '../hooks/useI18n'
|
||||||
import { useRPC } from '../hooks/useRPC'
|
import { useRPC } from '../hooks/useRPC'
|
||||||
import { CliArguments } from '../lib/argsParser'
|
|
||||||
import { validateDomain, validateIP } from '../utils'
|
import { validateDomain, validateIP } from '../utils'
|
||||||
|
|
||||||
// NEED ABSOLUTELY TO BE SPLIT IN MULTIPLE COMPONENTS
|
// NEED ABSOLUTELY TO BE SPLIT IN MULTIPLE COMPONENTS
|
||||||
@@ -64,7 +62,6 @@ export default function Settings() {
|
|||||||
|
|
||||||
const [serverAddr, setServerAddr] = useRecoilState(serverAddressState)
|
const [serverAddr, setServerAddr] = useRecoilState(serverAddressState)
|
||||||
const [serverPort, setServerPort] = useRecoilState(serverPortState)
|
const [serverPort, setServerPort] = useRecoilState(serverPortState)
|
||||||
const [cliArgs, setCliArgs] = useRecoilState(latestCliArgumentsState)
|
|
||||||
|
|
||||||
const [pollingTime, setPollingTime] = useRecoilState(rpcPollingTimeState)
|
const [pollingTime, setPollingTime] = useRecoilState(rpcPollingTimeState)
|
||||||
const [language, setLanguage] = useRecoilState(languageState)
|
const [language, setLanguage] = useRecoilState(languageState)
|
||||||
@@ -79,8 +76,6 @@ export default function Settings() {
|
|||||||
|
|
||||||
const { pushMessage } = useToast()
|
const { pushMessage } = useToast()
|
||||||
|
|
||||||
const argsBuilder = useMemo(() => new CliArguments().fromString(cliArgs), [])
|
|
||||||
|
|
||||||
const baseURL$ = useMemo(() => new Subject<string>(), [])
|
const baseURL$ = useMemo(() => new Subject<string>(), [])
|
||||||
const serverAddr$ = useMemo(() => new Subject<string>(), [])
|
const serverAddr$ = useMemo(() => new Subject<string>(), [])
|
||||||
const serverPort$ = useMemo(() => new Subject<string>(), [])
|
const serverPort$ = useMemo(() => new Subject<string>(), [])
|
||||||
@@ -296,32 +291,12 @@ export default function Settings() {
|
|||||||
<Typography variant="h6" color="primary" sx={{ mt: 2, mb: 0.5 }}>
|
<Typography variant="h6" color="primary" sx={{ mt: 2, mb: 0.5 }}>
|
||||||
General download settings
|
General download settings
|
||||||
</Typography>
|
</Typography>
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch
|
|
||||||
defaultChecked={argsBuilder.noMTime}
|
|
||||||
onChange={() => setCliArgs(argsBuilder.toggleNoMTime().toString())}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={i18n.t('noMTimeCheckbox')}
|
|
||||||
|
|
||||||
/>
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch
|
|
||||||
defaultChecked={argsBuilder.extractAudio}
|
|
||||||
onChange={() => setCliArgs(argsBuilder.toggleExtractAudio().toString())}
|
|
||||||
disabled={formatSelection}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={i18n.t('extractAudioCheckbox')}
|
|
||||||
/>
|
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
<Switch
|
<Switch
|
||||||
defaultChecked={formatSelection}
|
defaultChecked={formatSelection}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setCliArgs(argsBuilder.disableExtractAudio().toString())
|
|
||||||
setFormatSelection(!formatSelection)
|
setFormatSelection(!formatSelection)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -22,6 +22,18 @@ func AutoMigrate(ctx context.Context, db *sql.DB) error {
|
|||||||
content TEXT NOT NULL
|
content TEXT NOT NULL
|
||||||
)`,
|
)`,
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
db.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`INSERT INTO templates (id, name, content) VALUES
|
||||||
|
($1, $2, $3),
|
||||||
|
($4, $5, $6);`,
|
||||||
|
"0", "default", "--no-mtime",
|
||||||
|
"1", "audio only", "-x",
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user