fix: 完善成人内容过滤功能的部署兼容性

- 为用户设置API添加Edge Runtime配置确保部署兼容性
- 完善所有存储后端的用户设置方法实现
- 为D1数据库添加user_settings表迁移脚本
- 修复TypeScript类型错误和构建兼容性
- 所有25个API路由现在都正确配置了Edge Runtime
- 确保Docker、Cloudflare Pages等各平台部署正常运行
This commit is contained in:
katelya
2025-09-04 21:25:45 +08:00
parent 86ebbb2cf6
commit b06665788f
6 changed files with 161 additions and 3 deletions
+12
View File
@@ -26,6 +26,18 @@ CREATE TABLE IF NOT EXISTS skip_configs (
CREATE INDEX IF NOT EXISTS idx_skip_configs_username ON skip_configs(username);
CREATE INDEX IF NOT EXISTS idx_skip_configs_username_key ON skip_configs(username, key);
CREATE INDEX IF NOT EXISTS idx_skip_configs_username_updated_time ON skip_configs(username, updated_time DESC);
-- 创建用户设置表(成人内容过滤功能)
CREATE TABLE IF NOT EXISTS user_settings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
settings TEXT NOT NULL,
updated_time INTEGER NOT NULL
);
-- 为用户设置添加索引以优化查询性能
CREATE INDEX IF NOT EXISTS idx_user_settings_username ON user_settings(username);
CREATE INDEX IF NOT EXISTS idx_user_settings_updated_time ON user_settings(updated_time DESC);
```
## 🚀 执行迁移的方法
+1 -1
View File
@@ -1 +1 @@
if(!self.define){let e,s={};const n=(n,t)=>(n=new URL(n+".js",t).href,s[n]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()}).then(()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didnt register its module`);return e}));self.define=(t,a)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(s[c])return;let i={};const r=e=>n(e,c),o={module:{uri:c},exports:i,require:r};s[c]=Promise.all(t.map(e=>o[e]||r(e))).then(e=>(a(...e),i))}}define(["./workbox-e9849328"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"7db9e4ef70cbcab3780d6c680dd662a2"},{url:"/_next/static/_tNEn3OI_gHK8Eg73JHHK/_buildManifest.js",revision:"046380ae5bc74b46b6d5eac3eed65355"},{url:"/_next/static/_tNEn3OI_gHK8Eg73JHHK/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/110-9df7e37d43792a8e.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/154-de4a84fd5b2e0100.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/29-0844689411ca7d55.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/459-6bec40a8423cc309.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/51b697cb-f464f3017ac1ea30.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/682-d1dca8d17a3a8e6f.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/900-fb094d8873768e88.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/967-217cdcb80ae3beeb.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/998-568996670b543597.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/_not-found/page-ac328df06cf68f14.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/admin/page-d05d4621a6953d54.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/config/page-11f6321397ad65b1.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/douban/page-2d0023184aa37aff.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/layout-bd0bfbfdb401e15f.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/login/page-1638e1d936c78592.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/page-6a58e37ab3250691.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/play/page-586b6c5a6381cf6d.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/search/page-63fe30b91e0539a7.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/tvbox/page-3a990d4dba7ad091.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/app/warning/page-11cba4cf9332a238.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/c72274ce-06682d6fc8197e6d.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/da9543df-bf6da1a431d8604f.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/framework-6e06c675866dc992.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/main-459a10fe41fde25d.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/main-app-dbd320e104e1a5dc.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/pages/_app-792b631a362c29e1.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/pages/_error-9fde6601392a2a99.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-17170f1d90853b2d.js",revision:"_tNEn3OI_gHK8Eg73JHHK"},{url:"/_next/static/css/00661c2d88d90da0.css",revision:"00661c2d88d90da0"},{url:"/_next/static/css/23100062f5d4aac0.css",revision:"23100062f5d4aac0"},{url:"/_next/static/css/275ed64cc4367444.css",revision:"275ed64cc4367444"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/8e9860b6e62d6359-s.woff2",revision:"01ba6c2a184b8cba08b0d57167664d75"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/e4af272ccee01ff0-s.p.woff2",revision:"65850a373e258f1c897a2b3d75eb74de"},{url:"/favicon.ico",revision:"c5de6e56c5664adda146825f75ea6ecf"},{url:"/icons/icon-192x192.png",revision:"4a56c090828a1ad254c903c7aec0389d"},{url:"/icons/icon-256x256.png",revision:"f6409eb1a001f754121e3a8281c0319c"},{url:"/icons/icon-384x384.png",revision:"f6efc3e357b9ffdf4e0d8c14b2ed0ac1"},{url:"/icons/icon-512x512.png",revision:"9c008cbbeb6a576fe07bb1284a83f4d2"},{url:"/logo.png",revision:"40de611b143c47c6291c7bdad2c959ca"},{url:"/manifest.json",revision:"7bd3dabc1cfbfe40f09577efca223d31"},{url:"/robots.txt",revision:"e2b2cd8514443456bc6fb9d77b3b1f3e"},{url:"/screenshot1.png",revision:"10572bfcea54dc93ac4c5f7c9057fc98"},{url:"/screenshot2.png",revision:"f815a8990973a221899976867365c239"},{url:"/screenshot3.png",revision:"49709e96345dfeeab1d8083821d4b44e"},{url:"/screenshot4.png",revision:"a76c751e41e37556048a487e4f8b8b1c"},{url:"/wechat.jpg",revision:"d0f601311802667cd6ca5a37dc69bfa7"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:n,state:t})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")},new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")},new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>!(self.origin===e.origin),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")});
if(!self.define){let e,s={};const c=(c,n)=>(c=new URL(c+".js",n).href,s[c]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=c,e.onload=s,document.head.appendChild(e)}else e=c,importScripts(c),s()}).then(()=>{let e=s[c];if(!e)throw new Error(`Module ${c} didnt register its module`);return e}));self.define=(n,t)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let a={};const r=e=>c(e,i),o={module:{uri:i},exports:a,require:r};s[i]=Promise.all(n.map(e=>o[e]||r(e))).then(e=>(t(...e),a))}}define(["./workbox-e9849328"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"dc1d5ac623300622e02724e27ecf2e18"},{url:"/_next/static/Cc11st-UPy6zUFRhlXlF0/_buildManifest.js",revision:"046380ae5bc74b46b6d5eac3eed65355"},{url:"/_next/static/Cc11st-UPy6zUFRhlXlF0/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/110-5af0f210f33cfa1d.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/154-211e189482cc0258.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/29-2acace5e289d422b.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/459-0617417b9c423d5b.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/51b697cb-24a59f0c53e2e105.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/682-e64c4c7808d3e611.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/900-c7c9e505cc903ead.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/967-ac2d9567775f072e.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/998-f22ebd15e7bac0f0.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/_not-found/page-4dc7d52fd5d943cc.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/admin/page-03c708c7e6227f30.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/config/page-578e0487b53650a4.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/douban/page-23af0908f4f16f4d.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/layout-41b89aac912b9c2b.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/login/page-bbafa236e79f06c3.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/page-8f189c83607ce0f9.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/play/page-546c607d23bbe9b6.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/search/page-015039692c653292.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/settings/page-ef076e30e268b7f3.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/tvbox/page-443d4dd8e3c842b3.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/app/warning/page-11cba4cf9332a238.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/c72274ce-06682d6fc8197e6d.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/da9543df-bf6da1a431d8604f.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/framework-6e06c675866dc992.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/main-6c3022dbb9d044ff.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/main-app-dbd320e104e1a5dc.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/pages/_app-792b631a362c29e1.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/pages/_error-9fde6601392a2a99.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-17170f1d90853b2d.js",revision:"Cc11st-UPy6zUFRhlXlF0"},{url:"/_next/static/css/23100062f5d4aac0.css",revision:"23100062f5d4aac0"},{url:"/_next/static/css/275ed64cc4367444.css",revision:"275ed64cc4367444"},{url:"/_next/static/css/71c2bf6dfbfb4376.css",revision:"71c2bf6dfbfb4376"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/8e9860b6e62d6359-s.woff2",revision:"01ba6c2a184b8cba08b0d57167664d75"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/e4af272ccee01ff0-s.p.woff2",revision:"65850a373e258f1c897a2b3d75eb74de"},{url:"/favicon.ico",revision:"c5de6e56c5664adda146825f75ea6ecf"},{url:"/icons/icon-192x192.png",revision:"4a56c090828a1ad254c903c7aec0389d"},{url:"/icons/icon-256x256.png",revision:"f6409eb1a001f754121e3a8281c0319c"},{url:"/icons/icon-384x384.png",revision:"f6efc3e357b9ffdf4e0d8c14b2ed0ac1"},{url:"/icons/icon-512x512.png",revision:"9c008cbbeb6a576fe07bb1284a83f4d2"},{url:"/logo.png",revision:"40de611b143c47c6291c7bdad2c959ca"},{url:"/manifest.json",revision:"7bd3dabc1cfbfe40f09577efca223d31"},{url:"/robots.txt",revision:"e2b2cd8514443456bc6fb9d77b3b1f3e"},{url:"/screenshot1.png",revision:"10572bfcea54dc93ac4c5f7c9057fc98"},{url:"/screenshot2.png",revision:"f815a8990973a221899976867365c239"},{url:"/screenshot3.png",revision:"49709e96345dfeeab1d8083821d4b44e"},{url:"/screenshot4.png",revision:"a76c751e41e37556048a487e4f8b8b1c"},{url:"/wechat.jpg",revision:"d0f601311802667cd6ca5a37dc69bfa7"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:c,state:n})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")},new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")},new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>!(self.origin===e.origin),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")});
+3
View File
@@ -4,6 +4,9 @@ import { NextRequest, NextResponse } from 'next/server';
import { getStorage } from '@/lib/db';
import { UserSettings } from '@/lib/types';
// 设置运行时为 Edge Runtime,确保部署兼容性
export const runtime = 'edge';
// 获取用户设置
export async function GET(_request: NextRequest) {
try {
+60 -1
View File
@@ -1,7 +1,7 @@
/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import { AdminConfig } from './admin.types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord } from './types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord, UserSettings } from './types';
// 搜索历史最大条数
const SEARCH_HISTORY_LIMIT = 20;
@@ -573,4 +573,63 @@ export class D1Storage implements IStorage {
throw err;
}
}
// ---------- 用户设置 ----------
async getUserSettings(userName: string): Promise<UserSettings | null> {
try {
const db = await this.getDatabase();
const row = await db
.prepare('SELECT settings FROM user_settings WHERE username = ?')
.bind(userName)
.first();
if (row && row.settings) {
return JSON.parse(row.settings as string) as UserSettings;
}
return null;
} catch (err) {
console.error('Failed to get user settings:', err);
throw err;
}
}
async setUserSettings(
userName: string,
settings: UserSettings
): Promise<void> {
try {
const db = await this.getDatabase();
await db
.prepare(`
INSERT OR REPLACE INTO user_settings (username, settings, updated_time)
VALUES (?, ?, ?)
`)
.bind(userName, JSON.stringify(settings), Date.now())
.run();
} catch (err) {
console.error('Failed to set user settings:', err);
throw err;
}
}
async updateUserSettings(
userName: string,
settings: Partial<UserSettings>
): Promise<void> {
const current = await this.getUserSettings(userName);
const defaultSettings: UserSettings = {
filter_adult_content: true,
theme: 'auto',
language: 'zh-CN',
auto_play: false,
video_quality: 'auto'
};
const updated: UserSettings = {
...defaultSettings,
...current,
...settings,
filter_adult_content: settings.filter_adult_content ?? current?.filter_adult_content ?? true
};
await this.setUserSettings(userName, updated);
}
}
+43 -1
View File
@@ -3,7 +3,7 @@
import { createClient, RedisClientType } from 'redis';
import { AdminConfig } from './admin.types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord } from './types';
import { EpisodeSkipConfig, Favorite, IStorage, PlayRecord, UserSettings } from './types';
// 搜索历史最大条数
const SEARCH_HISTORY_LIMIT = 20;
@@ -337,6 +337,48 @@ export class KvrocksStorage implements IStorage {
this.client.set(this.adminConfigKey(), JSON.stringify(config))
);
}
// ---------- 用户设置 ----------
private userSettingsKey(userName: string) {
return `u:${userName}:settings`;
}
async getUserSettings(userName: string): Promise<UserSettings | null> {
const val = await withRetry(() =>
this.client.get(this.userSettingsKey(userName))
);
return val ? (JSON.parse(val) as UserSettings) : null;
}
async setUserSettings(
userName: string,
settings: UserSettings
): Promise<void> {
await withRetry(() =>
this.client.set(this.userSettingsKey(userName), JSON.stringify(settings))
);
}
async updateUserSettings(
userName: string,
settings: Partial<UserSettings>
): Promise<void> {
const current = await this.getUserSettings(userName);
const defaultSettings: UserSettings = {
filter_adult_content: true,
theme: 'auto',
language: 'zh-CN',
auto_play: false,
video_quality: 'auto'
};
const updated: UserSettings = {
...defaultSettings,
...current,
...settings,
filter_adult_content: settings.filter_adult_content ?? current?.filter_adult_content ?? true
};
await this.setUserSettings(userName, updated);
}
}
// Kvrocks客户端单例
+42
View File
@@ -329,6 +329,48 @@ export class UpstashRedisStorage implements IStorage {
await this.client.srem(this.skipConfigsKey(userName), key);
});
}
// ---------- 用户设置 ----------
private userSettingsKey(userName: string) {
return `u:${userName}:settings`;
}
async getUserSettings(userName: string): Promise<UserSettings | null> {
const val = await withRetry(() =>
this.client.get(this.userSettingsKey(userName))
);
return val ? (val as UserSettings) : null;
}
async setUserSettings(
userName: string,
settings: UserSettings
): Promise<void> {
await withRetry(() =>
this.client.set(this.userSettingsKey(userName), settings)
);
}
async updateUserSettings(
userName: string,
settings: Partial<UserSettings>
): Promise<void> {
const current = await this.getUserSettings(userName);
const defaultSettings: UserSettings = {
filter_adult_content: true,
theme: 'auto',
language: 'zh-CN',
auto_play: false,
video_quality: 'auto'
};
const updated: UserSettings = {
...defaultSettings,
...current,
...settings,
filter_adult_content: settings.filter_adult_content ?? current?.filter_adult_content ?? true
};
await this.setUserSettings(userName, updated);
}
}
// 单例 Upstash Redis 客户端