feat: Add isVisitor check to BasicSettings and useVideoProgress

This commit is contained in:
Peifan Li
2026-01-04 23:35:45 -05:00
parent 91d53f04a4
commit 3e44960ce7
4 changed files with 153 additions and 149 deletions

View File

@@ -1,6 +1,12 @@
# Change Log
## v1.7.34 (2026-01-04)
### Feat
- feat: Add refetchOnMount option to DownloadProvider (91d53f0)
## v1.7.33 (2026-01-04)
### Feat

View File

@@ -12,6 +12,7 @@ interface BasicSettingsProps {
const BasicSettings: React.FC<BasicSettingsProps> = ({ language, websiteName, onChange }) => {
const { t } = useLanguage();
const { userRole } = useAuth();
const isVisitor = userRole === 'visitor';
return (
<Box>
@@ -38,7 +39,7 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({ language, websiteName, on
</Select>
</FormControl>
{userRole !== 'visitor' && (
{!isVisitor && (
<TextField
fullWidth
label={t('websiteName')}

View File

@@ -16,6 +16,7 @@ interface UseVideoProgressProps {
*/
export function useVideoProgress({ videoId, video }: UseVideoProgressProps) {
const { userRole } = useAuth();
const isVisitor = userRole === 'visitor';
const queryClient = useQueryClient();
const [hasViewed, setHasViewed] = useState<boolean>(false);
const lastProgressSave = useRef<number>(0);
@@ -31,7 +32,7 @@ export function useVideoProgress({ videoId, video }: UseVideoProgressProps) {
// Save progress on unmount
useEffect(() => {
return () => {
if (videoId && currentTimeRef.current > 0 && !isDeletingRef.current && userRole !== 'visitor') {
if (videoId && currentTimeRef.current > 0 && !isDeletingRef.current && !isVisitor) {
axios.put(`${API_URL}/videos/${videoId}/progress`, {
progress: Math.floor(currentTimeRef.current)
})
@@ -44,7 +45,7 @@ export function useVideoProgress({ videoId, video }: UseVideoProgressProps) {
currentTimeRef.current = currentTime;
// Increment view count after 10 seconds
if (currentTime > 10 && !hasViewed && videoId && userRole !== 'visitor') {
if (currentTime > 10 && !hasViewed && videoId && !isVisitor) {
setHasViewed(true);
axios.post(`${API_URL}/videos/${videoId}/view`)
.then(res => {
@@ -59,7 +60,7 @@ export function useVideoProgress({ videoId, video }: UseVideoProgressProps) {
// Save progress every 5 seconds
const now = Date.now();
if (now - lastProgressSave.current > 5000 && videoId && userRole !== 'visitor') {
if (now - lastProgressSave.current > 5000 && videoId && !isVisitor) {
lastProgressSave.current = now;
axios.put(`${API_URL}/videos/${videoId}/progress`, {
progress: Math.floor(currentTime)

View File

@@ -3,8 +3,6 @@ import {
Alert,
Box,
Button,
Card,
CardContent,
Container,
Grid,
Snackbar,
@@ -172,161 +170,159 @@ const SettingsPage: React.FC = () => {
</Box>
{/* Settings Card */}
<Card variant="outlined">
<CardContent>
<Grid container spacing={2}>
{/* 1. Basic Settings */}
<Grid container spacing={2}>
{/* 1. Basic Settings */}
<Grid size={12}>
<CollapsibleSection title={t('basicSettings')} defaultExpanded={true}>
<BasicSettings
language={settings.language}
websiteName={settings.websiteName}
onChange={(field, value) => handleChange(field as keyof Settings, value)}
/>
</CollapsibleSection>
</Grid>
{/* 2. Interface & Display */}
{!isVisitor && (
<Grid size={12}>
<CollapsibleSection title={t('interfaceDisplay')} defaultExpanded={false}>
<InterfaceDisplaySettings
itemsPerPage={settings.itemsPerPage}
showYoutubeSearch={settings.showYoutubeSearch}
infiniteScroll={settings.infiniteScroll}
videoColumns={settings.videoColumns}
onChange={(field, value) => handleChange(field as keyof Settings, value)}
/>
</CollapsibleSection>
</Grid>
)}
{/* 3. Security & Access */}
{!isVisitor && (
<Grid size={12}>
<CollapsibleSection title={t('securityAccess')} defaultExpanded={false}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
<Box>
<SecuritySettings
settings={settings}
onChange={handleChange}
/>
</Box>
<Box>
<CookieSettings
onSuccess={(msg) => setMessage({ text: msg, type: 'success' })}
onError={(msg) => setMessage({ text: msg, type: 'error' })}
/>
</Box>
<Box>
<CloudflareSettings
enabled={settings.cloudflaredTunnelEnabled}
token={settings.cloudflaredToken}
onChange={(field, value) => handleChange(field as keyof Settings, value)}
/>
</Box>
</Box>
</CollapsibleSection>
</Grid>
)}
{!isVisitor && (
<>
{/* 4. Video Playback */}
<Grid size={12}>
<CollapsibleSection title={t('basicSettings')} defaultExpanded={true}>
<BasicSettings
language={settings.language}
websiteName={settings.websiteName}
onChange={(field, value) => handleChange(field as keyof Settings, value)}
<CollapsibleSection title={t('videoPlayback')} defaultExpanded={false}>
<VideoDefaultSettings
settings={settings}
onChange={handleChange}
/>
</CollapsibleSection>
</Grid>
{/* 2. Interface & Display */}
{!isVisitor && (
<Grid size={12}>
<CollapsibleSection title={t('interfaceDisplay')} defaultExpanded={false}>
<InterfaceDisplaySettings
itemsPerPage={settings.itemsPerPage}
showYoutubeSearch={settings.showYoutubeSearch}
infiniteScroll={settings.infiniteScroll}
videoColumns={settings.videoColumns}
onChange={(field, value) => handleChange(field as keyof Settings, value)}
/>
</CollapsibleSection>
</Grid>
)}
{/* 3. Security & Access */}
{!isVisitor && userRole !== 'visitor' && (
<Grid size={12}>
<CollapsibleSection title={t('securityAccess')} defaultExpanded={false}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
<Box>
<SecuritySettings
settings={settings}
onChange={handleChange}
/>
</Box>
<Box>
<CookieSettings
onSuccess={(msg) => setMessage({ text: msg, type: 'success' })}
onError={(msg) => setMessage({ text: msg, type: 'error' })}
/>
</Box>
<Box>
<CloudflareSettings
enabled={settings.cloudflaredTunnelEnabled}
token={settings.cloudflaredToken}
onChange={(field, value) => handleChange(field as keyof Settings, value)}
/>
</Box>
{/* 5. Download & Storage */}
<Grid size={12}>
<CollapsibleSection title={t('downloadStorage')} defaultExpanded={false}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
<Box>
<Typography variant="h6" gutterBottom>{t('downloadSettings')}</Typography>
<DownloadSettings
settings={settings}
onChange={handleChange}
activeDownloadsCount={activeDownloads.length}
onCleanup={() => setShowCleanupTempFilesModal(true)}
isSaving={isSaving}
/>
</Box>
</CollapsibleSection>
</Grid>
)}
{!isVisitor && (
<>
{/* 4. Video Playback */}
<Grid size={12}>
<CollapsibleSection title={t('videoPlayback')} defaultExpanded={false}>
<VideoDefaultSettings
<Box>
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>{t('cloudDriveSettings')}</Typography>
<CloudDriveSettings
settings={settings}
onChange={handleChange}
/>
</CollapsibleSection>
</Grid>
{/* 5. Download & Storage */}
<Grid size={12}>
<CollapsibleSection title={t('downloadStorage')} defaultExpanded={false}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
<Box>
<Typography variant="h6" gutterBottom>{t('downloadSettings')}</Typography>
<DownloadSettings
settings={settings}
onChange={handleChange}
activeDownloadsCount={activeDownloads.length}
onCleanup={() => setShowCleanupTempFilesModal(true)}
isSaving={isSaving}
/>
</Box>
<Box>
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>{t('cloudDriveSettings')}</Typography>
<CloudDriveSettings
settings={settings}
onChange={handleChange}
/>
</Box>
<Box>
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>{t('ytDlpConfiguration') || 'yt-dlp Configuration'}</Typography>
<YtDlpSettings
config={settings.ytDlpConfig || ''}
proxyOnlyYoutube={settings.proxyOnlyYoutube || false}
onChange={(config) => handleChange('ytDlpConfig', config)}
onProxyOnlyYoutubeChange={(checked) => handleChange('proxyOnlyYoutube', checked)}
/>
</Box>
</Box>
</CollapsibleSection>
</Grid>
{/* 6. Content Management */}
<Grid size={12}>
<CollapsibleSection title={t('contentManagement')} defaultExpanded={false}>
<TagsSettings
tags={Array.isArray(settings.tags) ? settings.tags : []}
onTagsChange={handleTagsChange}
</Box>
<Box>
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>{t('ytDlpConfiguration') || 'yt-dlp Configuration'}</Typography>
<YtDlpSettings
config={settings.ytDlpConfig || ''}
proxyOnlyYoutube={settings.proxyOnlyYoutube || false}
onChange={(config) => handleChange('ytDlpConfig', config)}
onProxyOnlyYoutubeChange={(checked) => handleChange('proxyOnlyYoutube', checked)}
/>
</CollapsibleSection>
</Grid>
</Box>
</Box>
</CollapsibleSection>
</Grid>
{/* 7. Data Management */}
<Grid size={12}>
<CollapsibleSection title={t('dataManagement')} defaultExpanded={false}>
<DatabaseSettings
onMigrate={() => setShowMigrateConfirmModal(true)}
onDeleteLegacy={() => setShowDeleteLegacyModal(true)}
onFormatFilenames={() => setShowFormatConfirmModal(true)}
onExportDatabase={handleExportDatabase}
onImportDatabase={handleImportDatabase}
onCleanupBackupDatabases={handleCleanupBackupDatabases}
onRestoreFromLastBackup={handleRestoreFromLastBackup}
isSaving={isSaving}
lastBackupInfo={lastBackupInfo}
moveSubtitlesToVideoFolder={settings.moveSubtitlesToVideoFolder || false}
onMoveSubtitlesToVideoFolderChange={(checked) => handleChange('moveSubtitlesToVideoFolder', checked)}
moveThumbnailsToVideoFolder={settings.moveThumbnailsToVideoFolder || false}
onMoveThumbnailsToVideoFolderChange={(checked) => handleChange('moveThumbnailsToVideoFolder', checked)}
/>
</CollapsibleSection>
</Grid>
{/* 6. Content Management */}
<Grid size={12}>
<CollapsibleSection title={t('contentManagement')} defaultExpanded={false}>
<TagsSettings
tags={Array.isArray(settings.tags) ? settings.tags : []}
onTagsChange={handleTagsChange}
/>
</CollapsibleSection>
</Grid>
{/* 7. Data Management */}
<Grid size={12}>
<CollapsibleSection title={t('dataManagement')} defaultExpanded={false}>
<DatabaseSettings
onMigrate={() => setShowMigrateConfirmModal(true)}
onDeleteLegacy={() => setShowDeleteLegacyModal(true)}
onFormatFilenames={() => setShowFormatConfirmModal(true)}
onExportDatabase={handleExportDatabase}
onImportDatabase={handleImportDatabase}
onCleanupBackupDatabases={handleCleanupBackupDatabases}
onRestoreFromLastBackup={handleRestoreFromLastBackup}
isSaving={isSaving}
lastBackupInfo={lastBackupInfo}
moveSubtitlesToVideoFolder={settings.moveSubtitlesToVideoFolder || false}
onMoveSubtitlesToVideoFolderChange={(checked) => handleChange('moveSubtitlesToVideoFolder', checked)}
moveThumbnailsToVideoFolder={settings.moveThumbnailsToVideoFolder || false}
onMoveThumbnailsToVideoFolderChange={(checked) => handleChange('moveThumbnailsToVideoFolder', checked)}
/>
</CollapsibleSection>
</Grid>
{/* 8. Advanced */}
<Grid size={12}>
<CollapsibleSection title={t('advanced')} defaultExpanded={false}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
<AdvancedSettings
debugMode={debugMode}
onDebugModeChange={setDebugMode}
/>
<HookSettings
settings={settings}
onChange={handleChange}
/>
</Box>
</CollapsibleSection>
</Grid>
</>
)}
</Grid>
{/* 8. Advanced */}
<Grid size={12}>
<CollapsibleSection title={t('advanced')} defaultExpanded={false}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
<AdvancedSettings
debugMode={debugMode}
onDebugModeChange={setDebugMode}
/>
<HookSettings
settings={settings}
onChange={handleChange}
/>
</Box>
</CollapsibleSection>
</Grid>
</>
)}
</Grid>
</CardContent>
</Card>
{/* Save Button */}
{/* Save Button Placeholder & Logic */}