feat: Enhance settings import to support source list merging, improve environment subscription parsing, and add page reload after import.

This commit is contained in:
kuekhaoyang
2025-12-25 11:56:45 +08:00
parent 082437a961
commit 0da172bbad
5 changed files with 75 additions and 16 deletions
+4
View File
@@ -146,6 +146,10 @@ export function useSettingsPage() {
setSubscriptions(settings.subscriptions || []);
setPasswordAccess(settings.passwordAccess);
setAccessPasswords(settings.accessPasswords);
// Reload to apply changes
setTimeout(() => window.location.reload(), 1000);
return true;
}
+38 -4
View File
@@ -30,26 +30,60 @@ export function exportSettings(settings: AppSettings, includeHistory: boolean =
return JSON.stringify(exportData, null, 2);
}
import { parseSourcesFromJson, mergeSources } from '@/lib/utils/source-import-utils';
export function importSettings(
jsonString: string,
saveSettings: (settings: AppSettings) => void
saveSettings: (settings: AppSettings) => void,
currentSettings?: AppSettings
): boolean {
try {
const data = JSON.parse(jsonString);
let imported = false;
if (data.settings) {
// Case 1: Full Settings Export
if (data.settings && typeof data.settings === 'object') {
saveSettings(data.settings);
imported = true;
}
// Case 2: History only (can be independent)
if (data.searchHistory && typeof window !== 'undefined') {
localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(data.searchHistory));
imported = true;
}
if (data.watchHistory && typeof window !== 'undefined') {
localStorage.setItem(WATCH_HISTORY_KEY, JSON.stringify(data.watchHistory));
imported = true;
}
return true;
if (imported) return true;
// Case 3: Source List (Array or Object wrapper)
// If we didn't find "settings" key, try to parse the whole thing as sources
if (currentSettings) {
try {
const result = parseSourcesFromJson(jsonString);
if (result.totalCount > 0) {
const newSettings = { ...currentSettings };
if (result.normalSources.length > 0) {
newSettings.sources = mergeSources(newSettings.sources, result.normalSources);
}
if (result.adultSources.length > 0) {
newSettings.adultSources = mergeSources(newSettings.adultSources, result.adultSources);
}
saveSettings(newSettings);
return true;
}
} catch (e) {
// Not a valid source format either
}
}
return false;
} catch {
return false;
}
+30 -9
View File
@@ -49,17 +49,38 @@ function getEnvSubscriptions(): SourceSubscription[] {
return [];
}
try {
const raw = JSON.parse(process.env.NEXT_PUBLIC_SUBSCRIPTION_SOURCES);
if (!Array.isArray(raw)) return [];
const envValue = process.env.NEXT_PUBLIC_SUBSCRIPTION_SOURCES.trim();
if (!envValue) return [];
return raw
.filter((item: any) => item && typeof item.name === 'string' && typeof item.url === 'string')
.map((item: any) => createSubscription(item.name, item.url));
// 1. Try JSON
try {
const raw = JSON.parse(envValue);
if (Array.isArray(raw)) {
return raw
.filter((item: any) => item && typeof item.name === 'string' && typeof item.url === 'string')
.map((item: any) => createSubscription(item.name, item.url));
}
} catch (e) {
console.error('Failed to parse NEXT_PUBLIC_SUBSCRIPTION_SOURCES', e);
return [];
// Ignore JSON parse error, try direct URL
}
// 2. Try Simple URL (or comma separated)
// Check if it looks like a URL (basic check)
if (envValue.includes('http')) {
const urls = envValue.split(',').map(u => u.trim()).filter(u => u.length > 0);
return urls.map((url, index) => {
// Basic URL validation
if (!url.startsWith('http')) return null;
const name = urls.length > 1
? `系统预设源 ${index + 1}`
: `系统预设源`;
return createSubscription(name, url);
}).filter((s): s is SourceSubscription => s !== null);
}
return [];
}
// Debugging helper
// console.log("Environment Subscriptions:", getEnvSubscriptions());
@@ -207,7 +228,7 @@ export const settingsStore = {
},
importSettings(jsonString: string): boolean {
return importSettings(jsonString, (s) => this.saveSettings(s));
return importSettings(jsonString, (s) => this.saveSettings(s), this.getSettings());
},
resetToDefaults(): void {
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "kvideo",
"version": "3.0.0",
"version": "3.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "kvideo",
"version": "3.0.0",
"version": "3.1.0",
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "kvideo",
"version": "3.0.0",
"version": "3.1.0",
"private": true,
"scripts": {
"dev": "next dev",