@@ -49,7 +52,7 @@ export function Navbar({ onReset }: NavbarProps) {
diff --git a/components/settings/AdultSourceSettings.tsx b/components/settings/AdultSourceSettings.tsx
new file mode 100644
index 0000000..344dda5
--- /dev/null
+++ b/components/settings/AdultSourceSettings.tsx
@@ -0,0 +1,120 @@
+import { useState } from 'react';
+import { SourceManager } from '@/components/settings/SourceManager';
+import type { VideoSource } from '@/lib/types';
+import { ADULT_SOURCES } from '@/lib/api/adult-sources';
+
+interface AdultSourceSettingsProps {
+ sources: VideoSource[];
+ onSourcesChange: (sources: VideoSource[]) => void;
+ onRestoreDefaults: () => void;
+ onAddSource: () => void;
+ onEditSource?: (source: VideoSource) => void;
+}
+
+export function AdultSourceSettings({
+ sources,
+ onSourcesChange,
+ onRestoreDefaults,
+ onAddSource,
+ onEditSource,
+}: AdultSourceSettingsProps) {
+ const [showAllSources, setShowAllSources] = useState(false);
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const filteredSources = sources.filter(source =>
+ source.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ source.baseUrl.toLowerCase().includes(searchQuery.toLowerCase())
+ );
+
+ const displayedSources = showAllSources || searchQuery
+ ? filteredSources
+ : filteredSources.slice(0, 10);
+
+ const handleToggle = (id: string) => {
+ const updated = sources.map(s =>
+ s.id === id ? { ...s, enabled: !s.enabled } : s
+ );
+ onSourcesChange(updated);
+ };
+
+ const handleDelete = (id: string) => {
+ const updated = sources.filter(s => s.id !== id);
+ onSourcesChange(updated);
+ };
+
+ const handleReorder = (id: string, direction: 'up' | 'down') => {
+ const currentIndex = sources.findIndex(s => s.id === id);
+ if (currentIndex === -1) return;
+
+ const newIndex = direction === 'up' ? currentIndex - 1 : currentIndex + 1;
+ if (newIndex < 0 || newIndex >= sources.length) return;
+
+ const updated = [...sources];
+ [updated[currentIndex], updated[newIndex]] = [updated[newIndex], updated[currentIndex]];
+
+ // Update priorities
+ updated.forEach((s, idx) => s.priority = idx + 1);
+ onSourcesChange(updated);
+ };
+
+ return (
+
+
+
成人源管理
+
+
+
+
+
+
+ 管理成人内容来源,调整优先级和启用状态
+
+
+ {/* Search Bar */}
+
+
setSearchQuery(e.target.value)}
+ className="w-full px-4 py-2 pl-10 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] placeholder-[var(--text-color-secondary)] focus:outline-none focus:ring-2 focus:ring-[var(--accent-color)] transition-all duration-200"
+ />
+
+
+
+
s.id)}
+ />
+ {!searchQuery && sources.length > 10 && (
+
+ )}
+
+ );
+}
diff --git a/lib/hooks/useSecretHomePage.ts b/lib/hooks/useSecretHomePage.ts
index 339647e..1759466 100644
--- a/lib/hooks/useSecretHomePage.ts
+++ b/lib/hooks/useSecretHomePage.ts
@@ -1,8 +1,8 @@
-import { useState, useRef, useEffect } from 'react';
+import { useState, useRef, useEffect, useMemo } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useSearchCache } from '@/lib/hooks/useSearchCache';
import { useParallelSearch } from '@/lib/hooks/useParallelSearch';
-import { ADULT_SOURCES } from '@/lib/api/adult-sources';
+import { settingsStore } from '@/lib/store/settings-store';
export function useSecretHomePage() {
const router = useRouter();
@@ -14,6 +14,12 @@ export function useSecretHomePage() {
const [hasSearched, setHasSearched] = useState(false);
const [currentSortBy, setCurrentSortBy] = useState('default');
+ // Get adult sources from settings store (supports user customization)
+ const enabledAdultSources = useMemo(() => {
+ const settings = settingsStore.getSettings();
+ return settings.adultSources.filter(s => s.enabled);
+ }, []);
+
// Search stream hook
const {
loading,
@@ -58,8 +64,8 @@ export function useSecretHomePage() {
const handleSearch = (searchQuery: string) => {
setQuery(searchQuery);
setHasSearched(true);
- // Always use ADULT_SOURCES
- performSearch(searchQuery, ADULT_SOURCES, currentSortBy as any);
+ // Use enabled adult sources from settings
+ performSearch(searchQuery, enabledAdultSources, currentSortBy as any);
};
const handleReset = () => {
diff --git a/lib/store/settings-store.ts b/lib/store/settings-store.ts
index 376dd89..0755f89 100644
--- a/lib/store/settings-store.ts
+++ b/lib/store/settings-store.ts
@@ -4,6 +4,7 @@
import type { VideoSource } from '@/lib/types';
import { DEFAULT_SOURCES } from '@/lib/api/default-sources';
+import { ADULT_SOURCES } from '@/lib/api/adult-sources';
export type SortOption =
| 'default'
@@ -17,6 +18,7 @@ export type SortOption =
export interface AppSettings {
sources: VideoSource[];
+ adultSources: VideoSource[];
sortBy: SortOption;
searchHistory: boolean;
watchHistory: boolean;
@@ -29,12 +31,14 @@ import { exportSettings, importSettings, SEARCH_HISTORY_KEY, WATCH_HISTORY_KEY }
const SETTINGS_KEY = 'kvideo-settings';
export const getDefaultSources = (): VideoSource[] => DEFAULT_SOURCES;
+export const getDefaultAdultSources = (): VideoSource[] => ADULT_SOURCES;
export const settingsStore = {
getSettings(): AppSettings {
if (typeof window === 'undefined') {
return {
sources: getDefaultSources(),
+ adultSources: getDefaultAdultSources(),
sortBy: 'default',
searchHistory: true,
watchHistory: true,
@@ -47,6 +51,7 @@ export const settingsStore = {
if (!stored) {
return {
sources: getDefaultSources(),
+ adultSources: getDefaultAdultSources(),
sortBy: 'default',
searchHistory: true,
watchHistory: true,
@@ -60,6 +65,7 @@ export const settingsStore = {
// Validate that parsed data has all required properties
return {
sources: Array.isArray(parsed.sources) ? parsed.sources : getDefaultSources(),
+ adultSources: Array.isArray(parsed.adultSources) ? parsed.adultSources : getDefaultAdultSources(),
sortBy: parsed.sortBy || 'default',
searchHistory: parsed.searchHistory !== undefined ? parsed.searchHistory : true,
watchHistory: parsed.watchHistory !== undefined ? parsed.watchHistory : true,
@@ -69,6 +75,7 @@ export const settingsStore = {
} catch {
return {
sources: getDefaultSources(),
+ adultSources: getDefaultAdultSources(),
sortBy: 'default',
searchHistory: true,
watchHistory: true,