v0.3.25: 外部依赖内置化 — qrcodejs/Hitokoto/IPgeo/代理测试

This commit is contained in:
2026-05-17 18:31:23 +08:00
parent 32dcc44524
commit 0bc848e196
47 changed files with 1756 additions and 822 deletions

View File

@@ -1 +1 @@
0.3.23 0.3.25

View File

@@ -1 +1 @@
0.3.23 0.3.25

View File

@@ -1,4 +1,4 @@
import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-D_srC3bj.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-3znuBWUR.js";import u1 from"./SystemConfig-BbG7uBv0.js";import f1 from"./SaveRecords-B5cCMWaP.js";import"./index-Bn7NwETH.js";import"./CloudBadge-CbpZHKLy.js";/*! ***************************************************************************** import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-B3brQT6g.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-0YLAk8H4.js";import u1 from"./SystemConfig-0RdDTGNd.js";import f1 from"./SaveRecords-BjfouS_I.js";import"./index-Bn7NwETH.js";import"./CloudBadge-CDvk35W2.js";/*! *****************************************************************************
Copyright (c) Microsoft Corporation. Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any

View File

@@ -1 +1 @@
import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as u,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-D_srC3bj.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","sys-daily-report":"每日汇报","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const i=u("el-icon"),a=u("el-menu-item"),v=u("el-sub-menu"),C=u("el-menu"),k=u("el-button"),S=u("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1}),e(a,{index:"sys-daily-report"},{default:t(()=>[...s[12]||(s[12]=[l("📊 每日汇报",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(q))]),_:1}),s[13]||(s[13]=n("span",null,"转存日志",-1))]),_:1}),s[15]||(s[15]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(z))]),_:1}),s[14]||(s[14]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(i,null,{default:t(()=>[e(r(A))]),_:1}),s[16]||(s[16]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-469751e8"]]);export{es as default}; import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as u,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-B3brQT6g.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","sys-daily-report":"每日汇报","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const i=u("el-icon"),a=u("el-menu-item"),v=u("el-sub-menu"),C=u("el-menu"),k=u("el-button"),S=u("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1}),e(a,{index:"sys-daily-report"},{default:t(()=>[...s[12]||(s[12]=[l("📊 每日汇报",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(q))]),_:1}),s[13]||(s[13]=n("span",null,"转存日志",-1))]),_:1}),s[15]||(s[15]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(z))]),_:1}),s[14]||(s[14]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(i,null,{default:t(()=>[e(r(A))]),_:1}),s[16]||(s[16]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-469751e8"]]);export{es as default};

View File

@@ -1 +1 @@
import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-D_srC3bj.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default}; import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-B3brQT6g.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default};

View File

@@ -1 +1 @@
import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-D_srC3bj.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C}; import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-B3brQT6g.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C};

View File

@@ -1,4 +1,4 @@
import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-D_srC3bj.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-CbpZHKLy.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li> import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-B3brQT6g.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-CDvk35W2.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li>
<li> <code>F12</code> <strong> (Network)</strong> </li> <li> <code>F12</code> <strong> (Network)</strong> </li>
<li>刷新页面在请求列表中点击任意一个请求 <code>account/info</code></li> <li>刷新页面在请求列表中点击任意一个请求 <code>account/info</code></li>
<li>在右侧 <strong>请求头 (Request Headers)</strong> <code>Cookie</code> </li> <li>在右侧 <strong>请求头 (Request Headers)</strong> <code>Cookie</code> </li>

View File

@@ -0,0 +1 @@
.home-page[data-v-c48c836b]{min-height:100vh;display:flex;flex-direction:column}.hero-section[data-v-c48c836b]{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px 40px}.logo-text[data-v-c48c836b]{font-size:64px;font-weight:700;color:var(--primary-color);margin-bottom:32px;letter-spacing:-2px}.logo-img[data-v-c48c836b]{max-width:500px;max-height:120px;width:auto;height:auto;object-fit:contain;margin-bottom:32px}.search-box[data-v-c48c836b]{display:flex;align-items:center;width:100%;max-width:640px;border:1px solid #dfe1e5;border-radius:24px;background:#fff;box-shadow:none;transition:box-shadow .2s,border-color .2s;overflow:hidden}.search-box[data-v-c48c836b]:focus-within{box-shadow:0 1px 6px #20212447;border-color:#dfe1e500}.search-box[data-v-c48c836b] .el-input__wrapper{border:none;box-shadow:none;background:transparent;padding:4px 20px;border-radius:0}.search-box[data-v-c48c836b] .el-input__inner{font-size:15px}.search-btn[data-v-c48c836b]{flex-shrink:0;border:none;border-radius:999px;padding:0 24px;height:38px;line-height:38px;margin:4px;font-size:14px;font-weight:600;background:var(--primary-color);color:#fff;cursor:pointer;transition:all .2s;letter-spacing:1px}.search-btn[data-v-c48c836b]:hover{background:#3a7be0}.search-btn[data-v-c48c836b]:active{background:#2d6ccf}.quote-section[data-v-c48c836b]{margin-top:18px;max-width:640px;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.quote-text[data-v-c48c836b]{font-size:14px;color:#aab0b8;font-style:italic;letter-spacing:.5px}.quote-author[data-v-c48c836b]{font-size:12px;color:#c0c4cc;display:inline-block;margin-left:4px}.content-section[data-v-c48c836b]{max-width:1500px;width:100%;margin:0 auto;padding:0 16px 60px}.rankings-grid[data-v-c48c836b]{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;margin-top:8px}.rank-panel[data-v-c48c836b]{background:var(--bg-white,#fff);border-radius:12px;padding:14px;border:1px solid #ebeef5;box-shadow:0 1px 4px #0000000a;display:flex;flex-direction:column}.panel-header[data-v-c48c836b]{display:flex;align-items:center;justify-content:space-between;padding-bottom:10px;border-bottom:2px solid #f0f0f0;margin-bottom:4px}.panel-title[data-v-c48c836b]{font-size:15px;font-weight:700;color:#303133;white-space:nowrap}.panel-tabs[data-v-c48c836b]{display:flex;gap:2px;background:#f0f2f5;border-radius:6px;padding:2px}.panel-tab[data-v-c48c836b]{font-size:11px;padding:3px 10px;border-radius:5px;cursor:pointer;color:#909399;font-weight:500;transition:all .2s;-webkit-user-select:none;user-select:none}.panel-tab.active[data-v-c48c836b]{background:#fff;color:var(--primary-color);font-weight:600;box-shadow:0 1px 3px #0000000f}.panel-body[data-v-c48c836b]{flex:1;display:flex;flex-direction:column;gap:1px}.rank-item[data-v-c48c836b]{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:6px;cursor:pointer;transition:background .15s}.rank-item[data-v-c48c836b]:hover{background:#f0f5ff}.rank-item[data-v-c48c836b]:active{background:#e6f0ff}.rank-idx[data-v-c48c836b]{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#909399;background:#f0f0f0;flex-shrink:0}.rank-idx.top-three[data-v-c48c836b]{background:var(--primary-color);color:#fff}.rank-name[data-v-c48c836b]{flex:1;min-width:0;font-size:13px;font-weight:500;color:#303133;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rank-cnt[data-v-c48c836b]{font-size:11px;color:#c0c4cc;white-space:nowrap;flex-shrink:0}.rank-expand[data-v-c48c836b]{text-align:center;padding:6px;margin-top:2px;font-size:12px;color:var(--primary-color);cursor:pointer;border-radius:6px;transition:background .15s;-webkit-user-select:none;user-select:none}.rank-expand[data-v-c48c836b]:hover{background:#ecf5ff}.panel-footer[data-v-c48c836b]{margin-top:8px;padding-top:8px;border-top:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;font-size:11px;color:#c0c4cc}.footer-time[data-v-c48c836b]{font-family:monospace;font-size:10px}@media (max-width: 900px){.hero-section[data-v-c48c836b]{padding:36px 16px 24px}.logo-text[data-v-c48c836b]{font-size:36px;margin-bottom:20px}.logo-img[data-v-c48c836b]{max-width:360px;max-height:100px;margin-bottom:20px}.rankings-scroll[data-v-c48c836b]{gap:12px}}.site-footer[data-v-c48c836b]{margin-top:auto;padding:20px 16px 32px;background:#f9fafb;border-top:1px solid #ebeef5}.footer-inner[data-v-c48c836b]{max-width:800px;margin:0 auto;font-size:12px;line-height:1.8;color:#909399;text-align:center;white-space:pre-line}.footer-actions[data-v-c48c836b]{display:flex;justify-content:center;align-items:center;gap:12px;margin-top:12px}.footer-disclaimer-btn[data-v-c48c836b]{font-size:12px!important;color:#909399!important}.footer-disclaimer-btn[data-v-c48c836b]:hover{color:#409eff!important}

View File

@@ -1 +0,0 @@
.home-page[data-v-1f536d99]{min-height:100vh;display:flex;flex-direction:column}.hero-section[data-v-1f536d99]{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px 40px}.logo-text[data-v-1f536d99]{font-size:64px;font-weight:700;color:var(--primary-color);margin-bottom:32px;letter-spacing:-2px}.logo-img[data-v-1f536d99]{max-width:500px;max-height:120px;width:auto;height:auto;object-fit:contain;margin-bottom:32px}.search-box[data-v-1f536d99]{display:flex;align-items:center;width:100%;max-width:640px;border:1px solid #dfe1e5;border-radius:24px;background:#fff;box-shadow:none;transition:box-shadow .2s,border-color .2s;overflow:hidden}.search-box[data-v-1f536d99]:focus-within{box-shadow:0 1px 6px #20212447;border-color:#dfe1e500}.search-box[data-v-1f536d99] .el-input__wrapper{border:none;box-shadow:none;background:transparent;padding:4px 20px;border-radius:0}.search-box[data-v-1f536d99] .el-input__inner{font-size:15px}.search-btn[data-v-1f536d99]{flex-shrink:0;border:none;border-radius:999px;padding:0 24px;height:38px;line-height:38px;margin:4px;font-size:14px;font-weight:600;background:var(--primary-color);color:#fff;cursor:pointer;transition:all .2s;letter-spacing:1px}.search-btn[data-v-1f536d99]:hover{background:#3a7be0}.search-btn[data-v-1f536d99]:active{background:#2d6ccf}.quote-section[data-v-1f536d99]{margin-top:18px;max-width:640px;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.quote-text[data-v-1f536d99]{font-size:14px;color:#aab0b8;font-style:italic;letter-spacing:.5px}.quote-author[data-v-1f536d99]{font-size:12px;color:#c0c4cc;display:inline-block;margin-left:4px}.content-section[data-v-1f536d99]{max-width:1500px;width:100%;margin:0 auto;padding:0 16px 60px}.rankings-grid[data-v-1f536d99]{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;margin-top:8px}.rank-panel[data-v-1f536d99]{background:var(--bg-white,#fff);border-radius:12px;padding:14px;border:1px solid #ebeef5;box-shadow:0 1px 4px #0000000a;display:flex;flex-direction:column}.panel-header[data-v-1f536d99]{display:flex;align-items:center;justify-content:space-between;padding-bottom:10px;border-bottom:2px solid #f0f0f0;margin-bottom:4px}.panel-title[data-v-1f536d99]{font-size:15px;font-weight:700;color:#303133;white-space:nowrap}.panel-tabs[data-v-1f536d99]{display:flex;gap:2px;background:#f0f2f5;border-radius:6px;padding:2px}.panel-tab[data-v-1f536d99]{font-size:11px;padding:3px 10px;border-radius:5px;cursor:pointer;color:#909399;font-weight:500;transition:all .2s;-webkit-user-select:none;user-select:none}.panel-tab.active[data-v-1f536d99]{background:#fff;color:var(--primary-color);font-weight:600;box-shadow:0 1px 3px #0000000f}.panel-body[data-v-1f536d99]{flex:1;display:flex;flex-direction:column;gap:1px}.rank-item[data-v-1f536d99]{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:6px;cursor:pointer;transition:background .15s}.rank-item[data-v-1f536d99]:hover{background:#f0f5ff}.rank-item[data-v-1f536d99]:active{background:#e6f0ff}.rank-idx[data-v-1f536d99]{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#909399;background:#f0f0f0;flex-shrink:0}.rank-idx.top-three[data-v-1f536d99]{background:var(--primary-color);color:#fff}.rank-name[data-v-1f536d99]{flex:1;min-width:0;font-size:13px;font-weight:500;color:#303133;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rank-cnt[data-v-1f536d99]{font-size:11px;color:#c0c4cc;white-space:nowrap;flex-shrink:0}.rank-expand[data-v-1f536d99]{text-align:center;padding:6px;margin-top:2px;font-size:12px;color:var(--primary-color);cursor:pointer;border-radius:6px;transition:background .15s;-webkit-user-select:none;user-select:none}.rank-expand[data-v-1f536d99]:hover{background:#ecf5ff}.panel-footer[data-v-1f536d99]{margin-top:8px;padding-top:8px;border-top:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;font-size:11px;color:#c0c4cc}.footer-time[data-v-1f536d99]{font-family:monospace;font-size:10px}@media (max-width: 900px){.hero-section[data-v-1f536d99]{padding:36px 16px 24px}.logo-text[data-v-1f536d99]{font-size:36px;margin-bottom:20px}.logo-img[data-v-1f536d99]{max-width:360px;max-height:100px;margin-bottom:20px}.rankings-scroll[data-v-1f536d99]{gap:12px}}.site-footer[data-v-1f536d99]{margin-top:auto;padding:20px 16px 32px;background:#f9fafb;border-top:1px solid #ebeef5}.footer-inner[data-v-1f536d99]{max-width:800px;margin:0 auto;font-size:12px;line-height:1.8;color:#909399;text-align:center;white-space:pre-line}.footer-actions[data-v-1f536d99]{display:flex;justify-content:center;align-items:center;gap:12px;margin-top:12px}.footer-disclaimer-btn[data-v-1f536d99]{font-size:12px!important;color:#909399!important}.footer-disclaimer-btn[data-v-1f536d99]:hover{color:#409eff!important}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{d as K,o as G,a as n,c as a,b as o,F as w,t as c,e as h,f as v,w as f,g as Q,r as z,h as l,i as B,j as x,u as W,k as Y,s as J,l as D,n as I}from"./index-D_srC3bj.js";import{g as X,a as Z,_ as ee}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const te={class:"home-page"},se={class:"hero-section"},oe=["src","alt"],ne={key:1,class:"logo-text"},ae={class:"search-box"},ie={key:1,class:"quote-section"},ce={class:"quote-text"},le={class:"quote-author"},re={class:"content-section"},ue={key:0,class:"rankings-grid"},de={class:"panel-header"},_e={class:"panel-title"},he={class:"panel-tabs"},ve=["onClick"],pe=["onClick"],ge={class:"panel-body"},fe=["onClick"],me={class:"rank-name"},ye={class:"rank-cnt"},ke=["onClick"],Ce={class:"panel-footer"},be={key:0},we={key:1},xe={key:2},Ie={key:3},qe={class:"footer-time"},Ae={key:0,class:"site-footer"},Se={class:"footer-inner"},Ne={class:"footer-actions"},R=8,Te=K({__name:"HomePage",setup(Ve){const q=W(),m=l(""),u=l([]),d=B({}),_=B({}),p=l(""),y=l(""),k=l(""),A=l(!1),g=l(""),C=l(""),S=l(""),F={movie:"🎬",western_movie:"🎥",western_tv:"🌍",donghua:"🐉",global_anime:"🌐",tv:"📺",niche:"💎",hotsite:"🏆"};function L(e){return F[e]||"📋"}function j(e){const t=[];if(e.rating&&t.push(`${e.rating}`),e.searchCount>0){const i=e.searchCount;i>=1e8?t.push(`${(i/1e8).toFixed(1)}亿`):i>=1e4?t.push(`${(i/1e4).toFixed(0)}`):t.push(String(i))}return t.join(" ")||""}function N(e){return(_[e.category]||"hot")==="hot"?e.hot||[]:e.newest||[]}function E(e){const t=N(e);return d[e.category]?t:t.slice(0,R)}function H(e){return N(e).length>R&&!d[e.category]}function M(e){d[e]=!0}function T(e,t){_[e]=t,d[e]=!1}function O(){window.open("/disclaimer/","_blank")}G(async()=>{try{const t=await(await fetch("https://v1.hitokoto.cn/")).json();g.value=t.hitokoto||"",C.value=t.from_who||t.from||""}catch{g.value="学而时习之,不亦说乎。",C.value="孔子"}try{const[e,t]=await Promise.all([X(),Z()]);e.fetchedAt?(S.value=e.fetchedAt,u.value=e.categories||[]):u.value=Array.isArray(e)?e:[];for(const i of u.value)_[i.category]="hot",d[i.category]=!1;t.site_logo&&(p.value=t.site_logo),t.site_name&&(y.value=t.site_name),t.site_disclaimer&&(k.value=t.site_disclaimer),A.value=!0}catch(e){console.error("加载首页数据失败",e)}});function V(){const e=m.value.trim();e&&q.push("/search?q="+encodeURIComponent(e))}function P(e){q.push("/search?q="+encodeURIComponent(e))}return(e,t)=>{const i=x("el-icon"),U=x("el-input"),$=x("el-button");return n(),a("div",te,[o("div",se,[A.value?(n(),a(w,{key:0},[p.value?(n(),a("img",{key:0,src:p.value,alt:y.value||"CloudSearch",class:"logo-img",onError:t[0]||(t[0]=s=>{s.target.style.display="none",p.value=""})},null,40,oe)):(n(),a("div",ne,c(y.value||"CloudSearch"),1))],64)):h("",!0),o("div",ae,[v(U,{modelValue:m.value,"onUpdate:modelValue":t[1]||(t[1]=s=>m.value=s),placeholder:"搜索网盘资源,或粘贴视频/网盘链接...",size:"large",clearable:"",onKeyup:Q(V,["enter"])},{prefix:f(()=>[v(i,null,{default:f(()=>[v(Y(J))]),_:1})]),_:1},8,["modelValue"]),v($,{type:"primary",size:"large",onClick:V,class:"search-btn"},{default:f(()=>[...t[2]||(t[2]=[D(" 搜 索 ",-1)])]),_:1})]),g.value?(n(),a("div",ie,[o("span",ce,"「 "+c(g.value)+" 」",1),o("span",le,"---"+c(C.value),1)])):h("",!0)]),o("div",re,[u.value.length>0?(n(),a("div",ue,[(n(!0),a(w,null,z(u.value,s=>(n(),a("div",{key:s.category,class:"rank-panel"},[o("div",de,[o("span",_e,c(L(s.category))+" "+c(s.label),1),o("div",he,[o("span",{class:I(["panel-tab",{active:_[s.category]==="hot"}]),onClick:r=>T(s.category,"hot")},"热榜",10,ve),o("span",{class:I(["panel-tab",{active:_[s.category]==="newest"}]),onClick:r=>T(s.category,"newest")},"最新",10,pe)])]),o("div",ge,[(n(!0),a(w,null,z(E(s),(r,b)=>(n(),a("div",{key:s.category+"-"+b,class:"rank-item",onClick:$e=>P(r.keyword)},[o("span",{class:I(["rank-idx",{"top-three":b<3}])},c(b+1),3),o("span",me,c(r.keyword),1),o("span",ye,c(j(r)),1)],8,fe))),128)),H(s)?(n(),a("div",{key:0,class:"rank-expand",onClick:r=>M(s.category)}," 展开全部 ▼ ",8,ke)):h("",!0)]),o("div",Ce,[s.category==="hotsite"?(n(),a("span",be,"基于本站搜索数据")):s.category==="donghua"||s.category==="global_anime"?(n(),a("span",we,"数据来源Bilibili")):s.category==="movie"||s.category==="tv"?(n(),a("span",xe,"数据来源:百度")):(n(),a("span",Ie,"数据来源TMDB")),o("span",qe,c(S.value),1)])]))),128))])):h("",!0)]),k.value?(n(),a("div",Ae,[o("div",Se,c(k.value),1),o("div",Ne,[v($,{class:"footer-disclaimer-btn",size:"small",onClick:O},{default:f(()=>[...t[3]||(t[3]=[D("📜 免责声明",-1)])]),_:1})])])):h("",!0)])}}}),De=ee(Te,[["__scopeId","data-v-1f536d99"]]);export{De as default};

View File

@@ -13,7 +13,7 @@
if(cfg.site_name) document.title = cfg.site_name + ' - 搜索'; if(cfg.site_name) document.title = cfg.site_name + ' - 搜索';
}).catch(function(){}); }).catch(function(){});
</script> </script>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script> <script src="/h5/qrcode.min.js"></script>
<style> <style>
/* ===== Reset & Base ===== */ /* ===== Reset & Base ===== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0} *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}

View File

@@ -21,7 +21,7 @@
} }
})(); })();
</script> </script>
<script type="module" crossorigin src="/assets/index-D_srC3bj.js"></script> <script type="module" crossorigin src="/assets/index-B3brQT6g.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Ekbe64zQ.css"> <link rel="stylesheet" crossorigin href="/assets/index-Ekbe64zQ.css">
</head> </head>
<body> <body>

View File

@@ -46,13 +46,11 @@
const categories=data.categories||[] const categories=data.categories||[]
const fetchedAt=data.fetchedAt||'' const fetchedAt=data.fetchedAt||''
// Quote // Quote
fetch('https://v1.hitokoto.cn/').then(r=>r.json()).then(d=>{ fetch('https://v1.(function(){
document.getElementById('homeQuote').textContent='「 '+d.hitokoto+' 」' var q=QUOTES[Math.floor(Math.random()*QUOTES.length)];
document.getElementById('homeQuoteAuthor').textContent='---'+(d.from_who||d.from||'') document.getElementById('homeQuote').textContent=' '+q+' ';
}).catch(()=>{ document.getElementById('homeQuoteAuthor').textContent='古籍经典';
document.getElementById('homeQuote').textContent='「 学而时习之,不亦说乎。 」' })()
document.getElementById('homeQuoteAuthor').textContent='---孔子'
})
// Store expanded state per category // Store expanded state per category
window.__expanded=window.__expanded||{} window.__expanded=window.__expanded||{}

View File

@@ -13,7 +13,7 @@
if(cfg.site_name) document.title = cfg.site_name + ' - 搜索'; if(cfg.site_name) document.title = cfg.site_name + ' - 搜索';
}).catch(function(){}); }).catch(function(){});
</script> </script>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script> <script src="/h5/qrcode.min.js"></script>
<link rel="stylesheet" href="/h5/style.css" /> <link rel="stylesheet" href="/h5/style.css" />
</head> </head>
<body> <body>
@@ -148,7 +148,7 @@
<!-- Toast --> <!-- Toast -->
<div class="toast" id="toast"></div> <div class="toast" id="toast"></div>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script> <script src="/h5/qrcode.min.js"></script>
<script src="/h5/app.js"></script> <script src="/h5/app.js"></script>
<!-- Footer --> <!-- Footer -->
<div id="siteFooter" class="site-footer" style="display:none"> <div id="siteFooter" class="site-footer" style="display:none">

File diff suppressed because one or more lines are too long

View File

@@ -13,7 +13,7 @@
if(cfg.site_name) document.title = cfg.site_name + ' - 搜索'; if(cfg.site_name) document.title = cfg.site_name + ' - 搜索';
}).catch(function(){}); }).catch(function(){});
</script> </script>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script> <script src="/h5/qrcode.min.js"></script>
<style> <style>
/* ===== Reset & Base ===== */ /* ===== Reset & Base ===== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0} *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}

View File

@@ -94,6 +94,8 @@ const siteDisclaimer = ref('')
const configLoaded = ref(false) const configLoaded = ref(false)
const currentQuote = ref('') const currentQuote = ref('')
const quoteAuthor = ref('') const quoteAuthor = ref('')
const QUOTES = ['学而时习之,不亦说乎。','温故而知新,可以为师矣。','三人行,必有我师焉。','学而不思则罔,思而不学则殆。','博学之,审问之,慎思之,明辨之,笃行之。','千里之行,始于足下。','不积跬步,无以至千里。','知之为知之,不知为不知,是知也。','工欲善其事,必先利其器。','玉不琢,不成器;人不学,不知道。','学以致用,知行合一。','学海无涯,勤作舟。','书山有路,勤为径。','宝剑锋从磨砺出,梅花香自苦寒来。','锲而不舍,金石可镂。','业精于勤,荒于嬉。','读书破万卷,下笔如有神。','路漫漫其修远兮,吾将上下而求索。','采菊东篱下,悠然见南山。','海内存知己,天涯若比邻。','长风破浪会有时,直挂云帆济沧海。','会当凌绝顶,一览众山小。','山重水复疑无路,柳暗花明又一村。']
const fetchedAt = ref('') const fetchedAt = ref('')
const INITIAL_SHOW = 8 const INITIAL_SHOW = 8
@@ -157,16 +159,10 @@ function openDisclaimer() {
} }
onMounted(async () => { onMounted(async () => {
// 一言 API // 一言(内置格言)
try { const q = QUOTES[Math.floor(Math.random() * QUOTES.length)]
const res = await fetch('https://v1.hitokoto.cn/') currentQuote.value = q
const data = await res.json() quoteAuthor.value = '古籍经典'
currentQuote.value = data.hitokoto || ''
quoteAuthor.value = data.from_who || data.from || ''
} catch {
currentQuote.value = '学而时习之,不亦说乎。'
quoteAuthor.value = '孔子'
}
try { try {
const [catsData, siteCfg] = await Promise.all([ const [catsData, siteCfg] = await Promise.all([

View File

@@ -1,4 +1,4 @@
import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-D_srC3bj.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-3znuBWUR.js";import u1 from"./SystemConfig-BbG7uBv0.js";import f1 from"./SaveRecords-B5cCMWaP.js";import"./index-Bn7NwETH.js";import"./CloudBadge-CbpZHKLy.js";/*! ***************************************************************************** import{x as qu,m as $_,h as Ce,B as Hg,d as q_,o as K_,a as Tt,c as Nt,K as ml,L as _l,b as Q,F as Vr,r as Gr,f as $t,w as qt,e as Oe,v as Ka,j as Hr,i as Q_,t as wt,n as Nc,y as Ei,l as zc,p as J_,E as j_,u as t1}from"./index-B3brQT6g.js";import{a as e1,h as r1,c as i1,i as n1,j as a1,t as o1,_ as s1}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import l1 from"./CloudConfig-0YLAk8H4.js";import u1 from"./SystemConfig-0RdDTGNd.js";import f1 from"./SaveRecords-BjfouS_I.js";import"./index-Bn7NwETH.js";import"./CloudBadge-CDvk35W2.js";/*! *****************************************************************************
Copyright (c) Microsoft Corporation. Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any

View File

@@ -1 +1 @@
import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as u,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-D_srC3bj.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","sys-daily-report":"每日汇报","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const i=u("el-icon"),a=u("el-menu-item"),v=u("el-sub-menu"),C=u("el-menu"),k=u("el-button"),S=u("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1}),e(a,{index:"sys-daily-report"},{default:t(()=>[...s[12]||(s[12]=[l("📊 每日汇报",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(q))]),_:1}),s[13]||(s[13]=n("span",null,"转存日志",-1))]),_:1}),s[15]||(s[15]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(z))]),_:1}),s[14]||(s[14]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(i,null,{default:t(()=>[e(r(A))]),_:1}),s[16]||(s[16]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-469751e8"]]);export{es as default}; import{d as B,o as N,a as V,c as I,b as n,t as c,f as e,w as t,h as g,v as y,j as u,k as r,C as M,l,D as T,G as j,H as q,I as z,J as A,u as D,z as H}from"./index-B3brQT6g.js";import{a as L,_ as R}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const E={class:"admin-layout"},G={class:"admin-sidebar"},J={class:"sidebar-brand"},W={class:"sidebar-brand-text"},F={class:"sidebar-version"},K={class:"admin-content"},O={class:"content-header"},P={class:"content-breadcrumb"},Q={class:"breadcrumb-current"},U={class:"content-actions"},X={class:"content-body"},Y=B({__name:"AdminLayout",setup(Z){const d=D(),f=H(),m=g(""),_=g(""),b={dashboard:"仪表盘","cloud-configs-toggle":"网盘设置及授权","cloud-configs-cleanup":"存储清理","sys-site":"网站设置","sys-services":"外部服务 & 缓存","sys-strategy":"性能配置","sys-password":"修改管理员密码","sys-notify":"消息推送","sys-daily-report":"每日汇报","save-records":"转存日志"},p=y(()=>{const o=f.name;return o==="admin-cloud-configs"?"cloud-configs-toggle":o==="admin-cleanup"?"cloud-configs-cleanup":o==="admin-system"?f.query.section||"sys-site":o==="admin-save-records"?"save-records":"dashboard"}),x=y(()=>b[p.value]||"仪表盘");function w(o){o==="dashboard"?d.push("/admin/dashboard"):o==="cloud-configs-toggle"?d.push("/admin/cloud-configs"):o==="cloud-configs-cleanup"?d.push("/admin/cleanup"):o.startsWith("sys-")?d.push({path:"/admin/system",query:{section:o}}):o==="save-records"?d.push("/admin/save-records"):o==="logout"&&(localStorage.removeItem("admin_token"),d.push("/admin/login"))}function h(){d.push("/")}return N(async()=>{try{const o=await L();m.value=o.site_name||""}catch{}try{const s=await(await fetch("/health")).json();_.value=s.version}catch{}}),(o,s)=>{const i=u("el-icon"),a=u("el-menu-item"),v=u("el-sub-menu"),C=u("el-menu"),k=u("el-button"),S=u("router-view");return V(),I("div",E,[n("aside",G,[n("div",J,[s[1]||(s[1]=n("div",{class:"sidebar-logo"},"☁️",-1)),n("div",W,[n("h2",null,c(m.value||"CloudSearch"),1),s[0]||(s[0]=n("p",null,"管理控制台",-1))])]),e(C,{"default-active":p.value,class:"sidebar-menu",onSelect:w},{default:t(()=>[e(a,{index:"dashboard"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(M))]),_:1}),s[2]||(s[2]=n("span",null,"仪表盘",-1))]),_:1}),e(v,{index:"cloud-configs"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(T))]),_:1}),s[3]||(s[3]=n("span",null,"网盘管理",-1))]),default:t(()=>[e(a,{index:"cloud-configs-toggle"},{default:t(()=>[...s[4]||(s[4]=[l("📋 设置及授权",-1)])]),_:1}),e(a,{index:"cloud-configs-cleanup"},{default:t(()=>[...s[5]||(s[5]=[l("🧹 存储清理",-1)])]),_:1})]),_:1}),e(v,{index:"system"},{title:t(()=>[e(i,null,{default:t(()=>[e(r(j))]),_:1}),s[6]||(s[6]=n("span",null,"系统设置",-1))]),default:t(()=>[e(a,{index:"sys-site"},{default:t(()=>[...s[7]||(s[7]=[l("🌐 网站设置",-1)])]),_:1}),e(a,{index:"sys-services"},{default:t(()=>[...s[8]||(s[8]=[l("🔗 外部服务 & 缓存",-1)])]),_:1}),e(a,{index:"sys-strategy"},{default:t(()=>[...s[9]||(s[9]=[l("⚡ 性能配置",-1)])]),_:1}),e(a,{index:"sys-password"},{default:t(()=>[...s[10]||(s[10]=[l("🔑 修改密码",-1)])]),_:1}),e(a,{index:"sys-notify"},{default:t(()=>[...s[11]||(s[11]=[l("📬 消息推送",-1)])]),_:1}),e(a,{index:"sys-daily-report"},{default:t(()=>[...s[12]||(s[12]=[l("📊 每日汇报",-1)])]),_:1})]),_:1}),e(a,{index:"save-records"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(q))]),_:1}),s[13]||(s[13]=n("span",null,"转存日志",-1))]),_:1}),s[15]||(s[15]=n("div",{class:"sidebar-spacer"},null,-1)),n("div",F,"v"+c(_.value),1),e(a,{index:"logout"},{default:t(()=>[e(i,null,{default:t(()=>[e(r(z))]),_:1}),s[14]||(s[14]=n("span",null,"退出登录",-1))]),_:1})]),_:1},8,["default-active"])]),n("div",K,[n("header",O,[n("div",P,[n("span",Q,c(x.value),1)]),n("div",U,[e(k,{text:"",size:"small",onClick:h},{default:t(()=>[e(i,null,{default:t(()=>[e(r(A))]),_:1}),s[16]||(s[16]=l(" 返回前台 ",-1))]),_:1})])]),n("main",X,[e(S)])])])}}}),es=R(Y,[["__scopeId","data-v-469751e8"]]);export{es as default};

View File

@@ -1 +1 @@
import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-D_srC3bj.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default}; import{d as k,o as C,a as w,c as y,b as a,t as m,f as t,w as i,g as x,e as L,h as d,j as p,l as N,i as S,E as B}from"./index-B3brQT6g.js";import{a as E,d as M,_ as U}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const j={class:"admin-login-page"},q={class:"login-card"},A={class:"login-brand"},I={class:"login-title"},K={key:0,class:"error-msg"},R={class:"login-footer"},z=k({__name:"AdminLogin",setup(D){const f=d(),u=d(!1),c=d(""),g=d(""),v=d("");E().then(l=>{l.site_name&&(g.value=l.site_name)}).catch(()=>{});const s=S({username:"",password:""}),b={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]};async function h(){var e,r,n;if(await((e=f.value)==null?void 0:e.validate().catch(()=>!1))){u.value=!0,c.value="";try{const o=await M(s.username,s.password);localStorage.setItem("admin_token",o.token),B.success("登录成功"),window.location.href="/admin"}catch(o){c.value=((n=(r=o==null?void 0:o.response)==null?void 0:r.data)==null?void 0:n.message)||(o==null?void 0:o.message)||"登录失败"}finally{u.value=!1}}}return C(async()=>{try{const e=await(await fetch("/health")).json();v.value=e.version||""}catch{}}),(l,e)=>{const r=p("el-input"),n=p("el-form-item"),o=p("el-button"),V=p("el-form");return w(),y("div",j,[e[4]||(e[4]=a("div",{class:"login-bg-pattern"},null,-1)),a("div",q,[a("div",A,[e[2]||(e[2]=a("div",{class:"login-logo"},"☁️",-1)),a("h1",I,m(g.value||"CloudSearch"),1),e[3]||(e[3]=a("p",{class:"login-subtitle"},"管理后台",-1))]),t(V,{ref_key:"formRef",ref:f,model:s,rules:b,"label-width":"0",size:"large",onKeyup:x(h,["enter"])},{default:i(()=>[t(n,{prop:"username"},{default:i(()=>[t(r,{modelValue:s.username,"onUpdate:modelValue":e[0]||(e[0]=_=>s.username=_),placeholder:"用户名","prefix-icon":"User"},null,8,["modelValue"])]),_:1}),t(n,{prop:"password"},{default:i(()=>[t(r,{modelValue:s.password,"onUpdate:modelValue":e[1]||(e[1]=_=>s.password=_),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":""},null,8,["modelValue"])]),_:1}),t(n,null,{default:i(()=>[t(o,{type:"primary",loading:u.value,class:"login-btn",onClick:h},{default:i(()=>[N(m(u.value?"登录中...":"登 录"),1)]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"]),c.value?(w(),y("p",K,m(c.value),1)):L("",!0),a("p",R,"CloudSearch v"+m(v.value),1)])])}}}),G=U(z,[["__scopeId","data-v-bd0b6672"]]);export{G as default};

View File

@@ -1 +1 @@
import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-D_srC3bj.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C}; import{C as s,b as a,a as n}from"./index-Bn7NwETH.js";import{d as l,a as t,c,p as d,k as o,e as r,l as u,t as m}from"./index-B3brQT6g.js";import{_}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const p=["src"],i=l({__name:"CloudBadge",props:{cloud_type:{},showIcon:{type:Boolean}},setup(e){return(C,y)=>(t(),c("span",{class:"cloud-badge",style:d({background:o(s)[e.cloud_type]})},[e.showIcon&&o(a)[e.cloud_type]?(t(),c("img",{key:0,src:o(a)[e.cloud_type],class:"badge-icon"},null,8,p)):r("",!0),u(" "+m(o(n)[e.cloud_type]),1)],4))}}),L=_(i,[["__scopeId","data-v-9106805f"]]);export{L as C};

View File

@@ -1,4 +1,4 @@
import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-D_srC3bj.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-CbpZHKLy.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li> import{d as ke,o as L,m as ve,E as _,a as c,c as k,f as n,w as a,b as r,h as C,j as p,i as be,F as R,r as K,t as v,y as g,l as d,e as A,k as Ce,M as he,p as xe,n as H,K as Be,L as Te,v as h}from"./index-B3brQT6g.js";import{a as x}from"./index-Bn7NwETH.js";import{c as we,k as Fe,h as Ne,l as G,t as Ve,u as P,m as ze,n as Se,o as $e,_ as Ue}from"./_plugin-vue_export-helper-1Z-znrfZ.js";import{C as De}from"./CloudBadge-CDvk35W2.js";const Ie={class:"cloud-config"},Me={class:"cloud-toggle-grid"},Oe=["src"],qe={class:"cloud-label"},Ee={class:"toolbar"},Le={key:0,class:"nickname-text"},Re={key:0,class:"promotion-text"},Ke={key:0,class:"uid-cell"},Ae={key:0,class:"verifying"},He={key:0,class:"storage-cell"},Ge={class:"storage-bar-wrap"},Pe={class:"storage-text"},je={class:"storage-used"},Je={class:"storage-total"},Qe={class:"storage-free"},We={key:0,class:"save-count"},Xe={style:{"line-height":"1.6"}},Ye={class:"cookie-tips-header"},Ze={class:"cookie-tips-title"},et=["innerHTML"],tt=ke({__name:"CloudConfig",setup(ot){const z=C([]),D=C(),F=C([]),B=C(!1),T=C(!1),b=C(null),l=be({cloud_type:"",nickname:"",promotion_account:"",is_transfer_enabled:!1,cookie:"",_verifying:!1,_storageUsed:"",_storageTotal:""}),j=h(()=>({cloud_type:[{required:!0,message:"请选择网盘类型",trigger:"change"}],nickname:[{required:!1,message:"请填写昵称(区分多个同类型网盘)",trigger:"blur"}],promotion_account:[{required:!0,message:"请填写推广平台及账号",trigger:"blur"}]})),J=h(()=>Object.entries(x)),Q=h(()=>{if(!l.cloud_type)return"请先选择网盘类型";const t=l.cloud_type;return t==="quark"||t==="baidu"?`请输入 ${x[t]||t} 的完整 Cookie`:b.value?"留空则保持原有":"输入完整 Cookie"}),W=h(()=>x[l.cloud_type]||l.cloud_type||""),X=h(()=>{const t=l.cloud_type;return t?{quark:`<li>在电脑上打开 <a href="https://pan.quark.cn" target="_blank">pan.quark.cn</a> 并登录你的夸克账号</li>
<li> <code>F12</code> <strong> (Network)</strong> </li> <li> <code>F12</code> <strong> (Network)</strong> </li>
<li>刷新页面在请求列表中点击任意一个请求 <code>account/info</code></li> <li>刷新页面在请求列表中点击任意一个请求 <code>account/info</code></li>
<li>在右侧 <strong>请求头 (Request Headers)</strong> <code>Cookie</code> </li> <li>在右侧 <strong>请求头 (Request Headers)</strong> <code>Cookie</code> </li>

View File

@@ -0,0 +1 @@
.home-page[data-v-c48c836b]{min-height:100vh;display:flex;flex-direction:column}.hero-section[data-v-c48c836b]{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px 40px}.logo-text[data-v-c48c836b]{font-size:64px;font-weight:700;color:var(--primary-color);margin-bottom:32px;letter-spacing:-2px}.logo-img[data-v-c48c836b]{max-width:500px;max-height:120px;width:auto;height:auto;object-fit:contain;margin-bottom:32px}.search-box[data-v-c48c836b]{display:flex;align-items:center;width:100%;max-width:640px;border:1px solid #dfe1e5;border-radius:24px;background:#fff;box-shadow:none;transition:box-shadow .2s,border-color .2s;overflow:hidden}.search-box[data-v-c48c836b]:focus-within{box-shadow:0 1px 6px #20212447;border-color:#dfe1e500}.search-box[data-v-c48c836b] .el-input__wrapper{border:none;box-shadow:none;background:transparent;padding:4px 20px;border-radius:0}.search-box[data-v-c48c836b] .el-input__inner{font-size:15px}.search-btn[data-v-c48c836b]{flex-shrink:0;border:none;border-radius:999px;padding:0 24px;height:38px;line-height:38px;margin:4px;font-size:14px;font-weight:600;background:var(--primary-color);color:#fff;cursor:pointer;transition:all .2s;letter-spacing:1px}.search-btn[data-v-c48c836b]:hover{background:#3a7be0}.search-btn[data-v-c48c836b]:active{background:#2d6ccf}.quote-section[data-v-c48c836b]{margin-top:18px;max-width:640px;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.quote-text[data-v-c48c836b]{font-size:14px;color:#aab0b8;font-style:italic;letter-spacing:.5px}.quote-author[data-v-c48c836b]{font-size:12px;color:#c0c4cc;display:inline-block;margin-left:4px}.content-section[data-v-c48c836b]{max-width:1500px;width:100%;margin:0 auto;padding:0 16px 60px}.rankings-grid[data-v-c48c836b]{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;margin-top:8px}.rank-panel[data-v-c48c836b]{background:var(--bg-white,#fff);border-radius:12px;padding:14px;border:1px solid #ebeef5;box-shadow:0 1px 4px #0000000a;display:flex;flex-direction:column}.panel-header[data-v-c48c836b]{display:flex;align-items:center;justify-content:space-between;padding-bottom:10px;border-bottom:2px solid #f0f0f0;margin-bottom:4px}.panel-title[data-v-c48c836b]{font-size:15px;font-weight:700;color:#303133;white-space:nowrap}.panel-tabs[data-v-c48c836b]{display:flex;gap:2px;background:#f0f2f5;border-radius:6px;padding:2px}.panel-tab[data-v-c48c836b]{font-size:11px;padding:3px 10px;border-radius:5px;cursor:pointer;color:#909399;font-weight:500;transition:all .2s;-webkit-user-select:none;user-select:none}.panel-tab.active[data-v-c48c836b]{background:#fff;color:var(--primary-color);font-weight:600;box-shadow:0 1px 3px #0000000f}.panel-body[data-v-c48c836b]{flex:1;display:flex;flex-direction:column;gap:1px}.rank-item[data-v-c48c836b]{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:6px;cursor:pointer;transition:background .15s}.rank-item[data-v-c48c836b]:hover{background:#f0f5ff}.rank-item[data-v-c48c836b]:active{background:#e6f0ff}.rank-idx[data-v-c48c836b]{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#909399;background:#f0f0f0;flex-shrink:0}.rank-idx.top-three[data-v-c48c836b]{background:var(--primary-color);color:#fff}.rank-name[data-v-c48c836b]{flex:1;min-width:0;font-size:13px;font-weight:500;color:#303133;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rank-cnt[data-v-c48c836b]{font-size:11px;color:#c0c4cc;white-space:nowrap;flex-shrink:0}.rank-expand[data-v-c48c836b]{text-align:center;padding:6px;margin-top:2px;font-size:12px;color:var(--primary-color);cursor:pointer;border-radius:6px;transition:background .15s;-webkit-user-select:none;user-select:none}.rank-expand[data-v-c48c836b]:hover{background:#ecf5ff}.panel-footer[data-v-c48c836b]{margin-top:8px;padding-top:8px;border-top:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;font-size:11px;color:#c0c4cc}.footer-time[data-v-c48c836b]{font-family:monospace;font-size:10px}@media (max-width: 900px){.hero-section[data-v-c48c836b]{padding:36px 16px 24px}.logo-text[data-v-c48c836b]{font-size:36px;margin-bottom:20px}.logo-img[data-v-c48c836b]{max-width:360px;max-height:100px;margin-bottom:20px}.rankings-scroll[data-v-c48c836b]{gap:12px}}.site-footer[data-v-c48c836b]{margin-top:auto;padding:20px 16px 32px;background:#f9fafb;border-top:1px solid #ebeef5}.footer-inner[data-v-c48c836b]{max-width:800px;margin:0 auto;font-size:12px;line-height:1.8;color:#909399;text-align:center;white-space:pre-line}.footer-actions[data-v-c48c836b]{display:flex;justify-content:center;align-items:center;gap:12px;margin-top:12px}.footer-disclaimer-btn[data-v-c48c836b]{font-size:12px!important;color:#909399!important}.footer-disclaimer-btn[data-v-c48c836b]:hover{color:#409eff!important}

View File

@@ -1 +0,0 @@
.home-page[data-v-1f536d99]{min-height:100vh;display:flex;flex-direction:column}.hero-section[data-v-1f536d99]{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px 40px}.logo-text[data-v-1f536d99]{font-size:64px;font-weight:700;color:var(--primary-color);margin-bottom:32px;letter-spacing:-2px}.logo-img[data-v-1f536d99]{max-width:500px;max-height:120px;width:auto;height:auto;object-fit:contain;margin-bottom:32px}.search-box[data-v-1f536d99]{display:flex;align-items:center;width:100%;max-width:640px;border:1px solid #dfe1e5;border-radius:24px;background:#fff;box-shadow:none;transition:box-shadow .2s,border-color .2s;overflow:hidden}.search-box[data-v-1f536d99]:focus-within{box-shadow:0 1px 6px #20212447;border-color:#dfe1e500}.search-box[data-v-1f536d99] .el-input__wrapper{border:none;box-shadow:none;background:transparent;padding:4px 20px;border-radius:0}.search-box[data-v-1f536d99] .el-input__inner{font-size:15px}.search-btn[data-v-1f536d99]{flex-shrink:0;border:none;border-radius:999px;padding:0 24px;height:38px;line-height:38px;margin:4px;font-size:14px;font-weight:600;background:var(--primary-color);color:#fff;cursor:pointer;transition:all .2s;letter-spacing:1px}.search-btn[data-v-1f536d99]:hover{background:#3a7be0}.search-btn[data-v-1f536d99]:active{background:#2d6ccf}.quote-section[data-v-1f536d99]{margin-top:18px;max-width:640px;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.quote-text[data-v-1f536d99]{font-size:14px;color:#aab0b8;font-style:italic;letter-spacing:.5px}.quote-author[data-v-1f536d99]{font-size:12px;color:#c0c4cc;display:inline-block;margin-left:4px}.content-section[data-v-1f536d99]{max-width:1500px;width:100%;margin:0 auto;padding:0 16px 60px}.rankings-grid[data-v-1f536d99]{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;margin-top:8px}.rank-panel[data-v-1f536d99]{background:var(--bg-white,#fff);border-radius:12px;padding:14px;border:1px solid #ebeef5;box-shadow:0 1px 4px #0000000a;display:flex;flex-direction:column}.panel-header[data-v-1f536d99]{display:flex;align-items:center;justify-content:space-between;padding-bottom:10px;border-bottom:2px solid #f0f0f0;margin-bottom:4px}.panel-title[data-v-1f536d99]{font-size:15px;font-weight:700;color:#303133;white-space:nowrap}.panel-tabs[data-v-1f536d99]{display:flex;gap:2px;background:#f0f2f5;border-radius:6px;padding:2px}.panel-tab[data-v-1f536d99]{font-size:11px;padding:3px 10px;border-radius:5px;cursor:pointer;color:#909399;font-weight:500;transition:all .2s;-webkit-user-select:none;user-select:none}.panel-tab.active[data-v-1f536d99]{background:#fff;color:var(--primary-color);font-weight:600;box-shadow:0 1px 3px #0000000f}.panel-body[data-v-1f536d99]{flex:1;display:flex;flex-direction:column;gap:1px}.rank-item[data-v-1f536d99]{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:6px;cursor:pointer;transition:background .15s}.rank-item[data-v-1f536d99]:hover{background:#f0f5ff}.rank-item[data-v-1f536d99]:active{background:#e6f0ff}.rank-idx[data-v-1f536d99]{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#909399;background:#f0f0f0;flex-shrink:0}.rank-idx.top-three[data-v-1f536d99]{background:var(--primary-color);color:#fff}.rank-name[data-v-1f536d99]{flex:1;min-width:0;font-size:13px;font-weight:500;color:#303133;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rank-cnt[data-v-1f536d99]{font-size:11px;color:#c0c4cc;white-space:nowrap;flex-shrink:0}.rank-expand[data-v-1f536d99]{text-align:center;padding:6px;margin-top:2px;font-size:12px;color:var(--primary-color);cursor:pointer;border-radius:6px;transition:background .15s;-webkit-user-select:none;user-select:none}.rank-expand[data-v-1f536d99]:hover{background:#ecf5ff}.panel-footer[data-v-1f536d99]{margin-top:8px;padding-top:8px;border-top:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;font-size:11px;color:#c0c4cc}.footer-time[data-v-1f536d99]{font-family:monospace;font-size:10px}@media (max-width: 900px){.hero-section[data-v-1f536d99]{padding:36px 16px 24px}.logo-text[data-v-1f536d99]{font-size:36px;margin-bottom:20px}.logo-img[data-v-1f536d99]{max-width:360px;max-height:100px;margin-bottom:20px}.rankings-scroll[data-v-1f536d99]{gap:12px}}.site-footer[data-v-1f536d99]{margin-top:auto;padding:20px 16px 32px;background:#f9fafb;border-top:1px solid #ebeef5}.footer-inner[data-v-1f536d99]{max-width:800px;margin:0 auto;font-size:12px;line-height:1.8;color:#909399;text-align:center;white-space:pre-line}.footer-actions[data-v-1f536d99]{display:flex;justify-content:center;align-items:center;gap:12px;margin-top:12px}.footer-disclaimer-btn[data-v-1f536d99]{font-size:12px!important;color:#909399!important}.footer-disclaimer-btn[data-v-1f536d99]:hover{color:#409eff!important}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{d as K,o as G,a as n,c as a,b as o,F as w,t as c,e as h,f as v,w as f,g as Q,r as z,h as l,i as B,j as x,u as W,k as Y,s as J,l as D,n as I}from"./index-D_srC3bj.js";import{g as X,a as Z,_ as ee}from"./_plugin-vue_export-helper-1Z-znrfZ.js";const te={class:"home-page"},se={class:"hero-section"},oe=["src","alt"],ne={key:1,class:"logo-text"},ae={class:"search-box"},ie={key:1,class:"quote-section"},ce={class:"quote-text"},le={class:"quote-author"},re={class:"content-section"},ue={key:0,class:"rankings-grid"},de={class:"panel-header"},_e={class:"panel-title"},he={class:"panel-tabs"},ve=["onClick"],pe=["onClick"],ge={class:"panel-body"},fe=["onClick"],me={class:"rank-name"},ye={class:"rank-cnt"},ke=["onClick"],Ce={class:"panel-footer"},be={key:0},we={key:1},xe={key:2},Ie={key:3},qe={class:"footer-time"},Ae={key:0,class:"site-footer"},Se={class:"footer-inner"},Ne={class:"footer-actions"},R=8,Te=K({__name:"HomePage",setup(Ve){const q=W(),m=l(""),u=l([]),d=B({}),_=B({}),p=l(""),y=l(""),k=l(""),A=l(!1),g=l(""),C=l(""),S=l(""),F={movie:"🎬",western_movie:"🎥",western_tv:"🌍",donghua:"🐉",global_anime:"🌐",tv:"📺",niche:"💎",hotsite:"🏆"};function L(e){return F[e]||"📋"}function j(e){const t=[];if(e.rating&&t.push(`${e.rating}`),e.searchCount>0){const i=e.searchCount;i>=1e8?t.push(`${(i/1e8).toFixed(1)}亿`):i>=1e4?t.push(`${(i/1e4).toFixed(0)}`):t.push(String(i))}return t.join(" ")||""}function N(e){return(_[e.category]||"hot")==="hot"?e.hot||[]:e.newest||[]}function E(e){const t=N(e);return d[e.category]?t:t.slice(0,R)}function H(e){return N(e).length>R&&!d[e.category]}function M(e){d[e]=!0}function T(e,t){_[e]=t,d[e]=!1}function O(){window.open("/disclaimer/","_blank")}G(async()=>{try{const t=await(await fetch("https://v1.hitokoto.cn/")).json();g.value=t.hitokoto||"",C.value=t.from_who||t.from||""}catch{g.value="学而时习之,不亦说乎。",C.value="孔子"}try{const[e,t]=await Promise.all([X(),Z()]);e.fetchedAt?(S.value=e.fetchedAt,u.value=e.categories||[]):u.value=Array.isArray(e)?e:[];for(const i of u.value)_[i.category]="hot",d[i.category]=!1;t.site_logo&&(p.value=t.site_logo),t.site_name&&(y.value=t.site_name),t.site_disclaimer&&(k.value=t.site_disclaimer),A.value=!0}catch(e){console.error("加载首页数据失败",e)}});function V(){const e=m.value.trim();e&&q.push("/search?q="+encodeURIComponent(e))}function P(e){q.push("/search?q="+encodeURIComponent(e))}return(e,t)=>{const i=x("el-icon"),U=x("el-input"),$=x("el-button");return n(),a("div",te,[o("div",se,[A.value?(n(),a(w,{key:0},[p.value?(n(),a("img",{key:0,src:p.value,alt:y.value||"CloudSearch",class:"logo-img",onError:t[0]||(t[0]=s=>{s.target.style.display="none",p.value=""})},null,40,oe)):(n(),a("div",ne,c(y.value||"CloudSearch"),1))],64)):h("",!0),o("div",ae,[v(U,{modelValue:m.value,"onUpdate:modelValue":t[1]||(t[1]=s=>m.value=s),placeholder:"搜索网盘资源,或粘贴视频/网盘链接...",size:"large",clearable:"",onKeyup:Q(V,["enter"])},{prefix:f(()=>[v(i,null,{default:f(()=>[v(Y(J))]),_:1})]),_:1},8,["modelValue"]),v($,{type:"primary",size:"large",onClick:V,class:"search-btn"},{default:f(()=>[...t[2]||(t[2]=[D(" 搜 索 ",-1)])]),_:1})]),g.value?(n(),a("div",ie,[o("span",ce,"「 "+c(g.value)+" 」",1),o("span",le,"---"+c(C.value),1)])):h("",!0)]),o("div",re,[u.value.length>0?(n(),a("div",ue,[(n(!0),a(w,null,z(u.value,s=>(n(),a("div",{key:s.category,class:"rank-panel"},[o("div",de,[o("span",_e,c(L(s.category))+" "+c(s.label),1),o("div",he,[o("span",{class:I(["panel-tab",{active:_[s.category]==="hot"}]),onClick:r=>T(s.category,"hot")},"热榜",10,ve),o("span",{class:I(["panel-tab",{active:_[s.category]==="newest"}]),onClick:r=>T(s.category,"newest")},"最新",10,pe)])]),o("div",ge,[(n(!0),a(w,null,z(E(s),(r,b)=>(n(),a("div",{key:s.category+"-"+b,class:"rank-item",onClick:$e=>P(r.keyword)},[o("span",{class:I(["rank-idx",{"top-three":b<3}])},c(b+1),3),o("span",me,c(r.keyword),1),o("span",ye,c(j(r)),1)],8,fe))),128)),H(s)?(n(),a("div",{key:0,class:"rank-expand",onClick:r=>M(s.category)}," 展开全部 ▼ ",8,ke)):h("",!0)]),o("div",Ce,[s.category==="hotsite"?(n(),a("span",be,"基于本站搜索数据")):s.category==="donghua"||s.category==="global_anime"?(n(),a("span",we,"数据来源Bilibili")):s.category==="movie"||s.category==="tv"?(n(),a("span",xe,"数据来源:百度")):(n(),a("span",Ie,"数据来源TMDB")),o("span",qe,c(S.value),1)])]))),128))])):h("",!0)]),k.value?(n(),a("div",Ae,[o("div",Se,c(k.value),1),o("div",Ne,[v($,{class:"footer-disclaimer-btn",size:"small",onClick:O},{default:f(()=>[...t[3]||(t[3]=[D("📜 免责声明",-1)])]),_:1})])])):h("",!0)])}}}),De=ee(Te,[["__scopeId","data-v-1f536d99"]]);export{De as default};

View File

@@ -0,0 +1,599 @@
// ===== Anime keywords for categorization =====
const ANIME_KWS=['仙逆','凡人修仙传','斗破苍穹','斗破','盘龙','完美世界','一念永恒','妖神记','星辰变','遮天','神墓','吞噬星空','武动乾坤','大主宰','全职高手','鬼灭之刃','海贼王','火影忍者','死神','龙珠','进击的巨人','咒术回战','一人之下','狐妖小红娘','魔道祖师','天官赐福','时光代理人','大王饶命','斗罗大陆','绝世唐门','不良人','秦时明月','全职法师','牧神记','三体','灵笼','雾山五行','凡人','仙王的日常生活','百妖谱','眷思量','镖人','伍六七','刺客伍六七','葬送的芙莉莲','间谍过家家']
// ===== Quotes =====
const QUOTES=['学而时习之,不亦说乎。','温故而知新,可以为师矣。','三人行,必有我师焉。','学而不思则罔,思而不学则殆。','博学之,审问之,慎思之,明辨之,笃行之。','千里之行,始于足下。','不积跬步,无以至千里。','知之为知之,不知为不知,是知也。','工欲善其事,必先利其器。','玉不琢,不成器;人不学,不知道。','学以致用,知行合一。','学海无涯,勤作舟。','书山有路,勤为径。','宝剑锋从磨砺出,梅花香自苦寒来。','锲而不舍,金石可镂。','业精于勤,荒于嬉。','读书破万卷,下笔如有神。','路漫漫其修远兮,吾将上下而求索。','采菊东篱下,悠然见南山。','海内存知己,天涯若比邻。','长风破浪会有时,直挂云帆济沧海。','会当凌绝顶,一览众山小。','山重水复疑无路,柳暗花明又一村。']
// ===== Home Page =====
function homeSearch(){
const q=document.getElementById('homeSearchInput').value.trim()
if(q)doSearchFromHome(q)
}
function doSearchFromHome(q){
document.getElementById('homePage').style.display='none'
document.getElementById('searchView').style.display='block'
document.getElementById('searchInput').value=q
window.history.replaceState({},'','/h5?q='+encodeURIComponent(q))
doSearch()
}
function renderHomePage(data){
fetch("/api/site-config").then(r=>r.json()).then(cfg=>{
// 显示 Logo优先图片其次文字
var logoEl=document.getElementById("homeLogo");
var headerEl=document.getElementById("headerTitle");
if(cfg.site_logo){
logoEl.innerHTML='<img src="'+cfg.site_logo+'" class="home-logo-img" alt="logo" />';
logoEl.style.display="";
headerEl.innerHTML='<img src="'+cfg.site_logo+'" class="header-logo-img" alt="logo" />';
headerEl.style.display="";
}else if(cfg.site_name){
logoEl.textContent=cfg.site_name;
logoEl.style.display="";
headerEl.textContent=cfg.site_name;
headerEl.style.display="";
}else{
logoEl.textContent="CloudSearch";
logoEl.style.display="";
headerEl.textContent="CloudSearch";
headerEl.style.display="";
}
if(cfg.site_disclaimer){
document.getElementById("footerContent").innerHTML=cfg.site_disclaimer.replace(/\n/g,'<br>');
document.getElementById("siteFooter").style.display="block";
}
}).catch(()=>{})
const categories=data.categories||[]
const fetchedAt=data.fetchedAt||''
// Quote
fetch('https://v1.(function(){
var q=QUOTES[Math.floor(Math.random()*QUOTES.length)];
document.getElementById('homeQuote').textContent=' '+q+' ';
document.getElementById('homeQuoteAuthor').textContent='古籍经典';
})()
// Store expanded state per category
window.__expanded=window.__expanded||{}
window.__activeTab=window.__activeTab||{}
const el=document.getElementById('homeRankings')
let html=''
for(const cat of categories){
const icons={movie:'🎬',tv:'📺',western_movie:'🎥',western:'🌍',donghua:'🐉',global_anime:'🌐',variety:'🎤',niche:'💎',hotsite:'🏆'}
const icon=icons[cat.category]||'📋'
const key=cat.category
if(!window.__activeTab[key])window.__activeTab[key]='hot'
html+='<div class="rank-block">'
html+='<div class="rank-block-hdr">'+
'<span class="rank-block-title">'+icon+' '+cat.label+'</span>'+
'<div class="rank-block-tabs" id="rtabs-'+key+'">'+
'<span class="rank-tab'+(window.__activeTab[key]==='hot'?' active':'')+'" onclick="switchRankTab(\''+key+'\',\'hot\')">热榜</span>'+
'<span class="rank-tab'+(window.__activeTab[key]==='newest'?' active':'')+'" onclick="switchRankTab(\''+key+'\',\'newest\')">最新</span>'+
'</div>'+
'</div>'
html+='<div class="rank-block-items" id="ritems-'+key+'" data-hot=\''+JSON.stringify({items:cat.hot||[]}).replace(/'/g,"&#39;")+'\' data-newest=\''+JSON.stringify({items:cat.newest||[]}).replace(/'/g,"&#39;")+'\'>'
const items=window.__activeTab[key]==='hot'?(cat.hot||[]):(cat.newest||[])
html+=renderRankItems(items,key,false)
html+='</div>'
// 数据来源
html+='<div class="rank-block-ftr">'+
'<span>'+(cat.category!=='hotsite'?'数据来源TMDB':'本站搜索数据')+'</span>'+
'<span class="ftr-time">'+fetchedAt+'</span>'+
'</div></div>'
}
el.innerHTML=html
}
function renderRankItems(items,key,expanded){
if(!items||items.length===0)return'<div style="padding:10px;text-align:center;color:#c0c4cc;font-size:12px">暂无数据</div>'
const limit=3
const show=expanded?items.length:Math.min(limit,items.length)
let html=items.slice(0,show).map((item,i)=>{
const c=i<3?' rank-idx top3':' rank-idx'
return '<div class="rank-item" onclick="doSearchFromHome(\''+item.keyword.replace(/'/g,"\\'")+'\')">'+
'<span class="'+c+'">'+(i+1)+'</span>'+
'<span class="rank-name">'+item.keyword+'</span>'+
'<span class="rank-cnt">'+(item.rating?'⭐'+item.rating:item.searchCount)+'</span>'+
'</div>'
}).join('')
if(items.length>limit&&!expanded){
html+='<div class="rank-expand" onclick="expandRank(\''+key+'\')">展开全部 ▼</div>'
}
return html
}
function expandRank(key){
const container=document.getElementById('ritems-'+key)
if(!container)return
const tab=window.__activeTab[key]||'hot'
const data=JSON.parse(tab==='hot'?container.dataset.hot:container.dataset.newest)
container.innerHTML=renderRankItems(data.items,key,true)
}
function switchRankTab(category,tab){
window.__activeTab[category]=tab
const tabsContainer=document.getElementById('rtabs-'+category)
if(tabsContainer){
tabsContainer.querySelectorAll('.rank-tab').forEach(t=>t.className='rank-tab')
tabsContainer.querySelector(tab==='hot'?'.rank-tab:first-child':'.rank-tab:last-child').className='rank-tab active'
}
const container=document.getElementById('ritems-'+category)
if(container){
const data=JSON.parse(tab==='hot'?container.dataset.hot:container.dataset.newest)
container.innerHTML=renderRankItems(data.items,category,false)
}
}
let userInfo = null
let allResults = []
let allChannels = []
let activeTab = ''
let currentSaveItem = null
const CLOUD_ICONS = {quark:'☁️',baidu:'🔵',aliyun:'🟠','115':'🟣',tianyi:'🔷','123pan':'🔴',uc:'🟡',xunlei:'🟢',pikpak:'🟤',magnet:'🧲',ed2k:'🔗',others:'📁'}
const CLOUD_LABELS = {quark:'夸克网盘',baidu:'百度网盘',aliyun:'阿里云盘','115':'115网盘',tianyi:'天翼云盘','123pan':'123云盘',uc:'UC网盘',xunlei:'迅雷云盘',pikpak:'PikPak',magnet:'磁力链接',ed2k:'电驴链接',others:'其他'}
const CLOUD_COLORS = {quark:'#07c160',baidu:'#4e6ef2',aliyun:'#ff6a00','115':'#9b59b6',tianyi:'#00a1d6','123pan':'#e74c3c',uc:'#f39c12',xunlei:'#2ecc71',pikpak:'#8e44ad',magnet:'#95a5a6',ed2k:'#7f8c8d',others:'#95a5a6'}
const CLOUD_ORDER = {quark:1,baidu:2,aliyun:3,'115':4,tianyi:5,'123pan':6,uc:7,xunlei:8,pikpak:9,magnet:10,ed2k:11,others:12}
// ===== Fetch helpers =====
function getToken(){return localStorage.getItem('h5_admin_token')}
function apiHeaders(){const h={'Content-Type':'application/json'};const t=getToken();if(t)h['Authorization']='Bearer '+t;return h}
// ===== Toast =====
let toastTimer
function showToast(msg,isError){
const el=document.getElementById('toast')
el.textContent=msg
el.className='toast show'+(isError?' error':'')
clearTimeout(toastTimer)
toastTimer=setTimeout(()=>el.className='toast',2000)
}
// ===== User =====
async function checkLogin(){
try{
const res=await fetch('/api/me',{headers:apiHeaders()})
if(res.ok){
const data=await res.json()
if(data.loggedIn){
userInfo=data
document.getElementById('userArea').innerHTML='<span class="user-badge">'+data.username+'</span><button class="logout-btn-small" onclick="logout()">退出</button>'
}
}
}catch(e){}
}
function logout(){
localStorage.removeItem('h5_admin_token')
userInfo=null
document.getElementById('userArea').innerHTML='<button class="login-btn-small" onclick="showLogin()">登录</button>'
showToast('已退出')
}
function showLogin(){
document.getElementById('loginErr').textContent=''
document.getElementById('loginUser').value=''
document.getElementById('loginPass').value=''
document.getElementById('loginModal').style.display='block'
document.getElementById('overlay').style.display='block'
}
function closeLogin(){
document.getElementById('loginModal').style.display='none'
document.getElementById('overlay').style.display='none'
}
async function handleLogin(){
const user=document.getElementById('loginUser').value.trim()
const pass=document.getElementById('loginPass').value
if(!user||!pass){showToast('请输入用户名和密码',true);return}
const btn=document.getElementById('loginBtn')
btn.disabled=true;btn.textContent='登录中...'
try{
const res=await fetch('/api/admin/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:user,password:pass})})
if(res.ok){
const data=await res.json()
localStorage.setItem('h5_admin_token',data.token)
userInfo={username:user}
document.getElementById('userArea').innerHTML='<span class="user-badge">'+user+'</span><button class="logout-btn-small" onclick="logout()">退出</button>'
closeLogin()
showToast('登录成功')
}else{
const err=await res.json().catch(()=>({}))
document.getElementById('loginErr').textContent=err.error||'登录失败'
}
}catch(e){
document.getElementById('loginErr').textContent='网络错误'
}finally{
btn.disabled=false;btn.textContent='登录'
}
}
// ===== Search =====
function handleKeydown(e){if(e.key==='Enter')doSearch()}
let searchTimer
function doSearch(){
const q=document.getElementById('searchInput').value.trim()
if(!q)return
// Update URL
window.history.replaceState({},'','/h5?q='+encodeURIComponent(q))
// Show loading
document.getElementById('results').innerHTML=''
document.getElementById('tabs').style.display='none'
document.getElementById('infoBar').style.display='none'
document.getElementById('loading').style.display='block'
document.getElementById('loadingText').textContent='🔍 正在搜索中...'
document.getElementById('searchBtn').disabled=true
let progress=0
const bar=document.getElementById('loadingBar')
const progressTimer=setInterval(()=>{
if(progress<60)progress+=1+Math.random()*3
else if(progress<85)progress+=0.5+Math.random()
bar.style.width=progress+'%'
},200)
// Use streaming search for live updates
streamSearch(q,progressTimer,bar)
}
async function streamSearch(q,progressTimer,bar){
const startTime=Date.now()
try{
const response=await fetch('/api/query',{method:'POST',headers:apiHeaders(),body:JSON.stringify({q})})
if(!response.ok)throw new Error('搜索失败 ('+response.status+')')
const reader=response.body.getReader()
const decoder=new TextDecoder()
let buffer=''
let allItems=[]
let channels=[]
let totalCount=0
let filteredCount=0
while(true){
const {done,value}=await reader.read()
if(done)break
buffer+=decoder.decode(value,{stream:true})
const lines=buffer.split('\n')
buffer=lines.pop()||''
for(const line of lines){
if(!line.trim())continue
try{
const msg=JSON.parse(line)
if(msg.type==='stats'){
totalCount=msg.total||0
filteredCount=msg.filtered||0
document.getElementById('loadingText').textContent='🔍 搜索到 '+totalCount+' 条,正在验证...'
}else if(msg.type==='result'){
if(msg.valid&&msg.id){
allItems.push(msg.id)
}
}else if(msg.type==='complete'){
const results=msg.results||[]
channels=msg.channels||[]
clearInterval(progressTimer)
bar.style.width='100%'
setTimeout(()=>renderResults(results,channels,totalCount,filteredCount,Date.now()-startTime),300)
return
}
}catch(e){}
}
}
}catch(e){
clearInterval(progressTimer)
document.getElementById('loading').style.display='none'
document.getElementById('searchBtn').disabled=false
document.getElementById('results').innerHTML='<div class="empty">搜索失败:'+e.message+'</div>'
}
}
// ===== Render =====
function renderResults(results,channels,totalCount,filteredCount,time){
document.getElementById('loading').style.display='none'
document.getElementById('searchBtn').disabled=false
allResults=results
allChannels=channels||[]
// Info bar
if(totalCount>0){
document.getElementById('infoBar').style.display='flex'
document.getElementById('infoCount').textContent='已为您挑选到最符合 '+totalCount+' 条结果'
document.getElementById('infoTime').textContent='⏱ '+time+'ms'
if(filteredCount>0)document.getElementById('infoFiltered').textContent='❌ 失效 '+filteredCount
else document.getElementById('infoFiltered').textContent=''
}else{
document.getElementById('infoBar').style.display='none'
}
// Build tabs
const tabsEl=document.getElementById('tabs')
tabsEl.innerHTML=''
const typeCounts={}
for(const r of results){const ct=r.cloud_type||'others';typeCounts[ct]=(typeCounts[ct]||0)+1}
const sorted=Object.keys(typeCounts).sort((a,b)=>(CLOUD_ORDER[a]||99)-(CLOUD_ORDER[b]||99))
// "全部" tab
const allTab=document.createElement('div')
allTab.className='tab active'
allTab.textContent='📋 全部 ('+results.length+')'
allTab.onclick=()=>{setActiveTab('');renderCardList(results)}
tabsEl.appendChild(allTab)
for(const ct of sorted){
const tab=document.createElement('div')
tab.className='tab'
tab.textContent=(CLOUD_ICONS[ct]||'📁')+' '+(CLOUD_LABELS[ct]||ct)+' ('+typeCounts[ct]+')'
tab.onclick=()=>{setActiveTab(ct);renderCardList(results.filter(r=>(r.cloud_type||'others')===ct))}
tabsEl.appendChild(tab)
}
tabsEl.style.display=results.length>0?'flex':'none'
activeTab=''
// Render cards
renderCardList(results)
}
function setActiveTab(ct){
activeTab=ct
document.querySelectorAll('.tab').forEach((t,i)=>{
const isAll=i===0&&!ct
const active=i>0&&ct&&t.textContent.includes(CLOUD_LABELS[ct])
t.className='tab'+(active||isAll?' active':'')
})
}
function renderCardList(items){
const el=document.getElementById('results')
if(items.length===0){
el.innerHTML='<div class="empty">暂无结果</div>'
return
}
el.innerHTML=items.map((item,idx)=>{
const coverHtml=item.cover
? '<img src="'+escapeHtml(item.cover)+'" alt="" onerror="this.parentElement.innerHTML=\'<div class=placeholder>'+escapeHtml(CLOUD_ICONS[item.cloud_type||'others'])+'</div>\'" loading="lazy" />'
: '<div class="placeholder">'+escapeHtml(CLOUD_ICONS[item.cloud_type||'others'])+'</div>'
const cloudLabel=CLOUD_LABELS[item.cloud_type]||item.cloud_type||''
const cloudColor=CLOUD_COLORS[item.cloud_type]||'#95a5a6'
const tags=extractTags(item.title||'')
const cleanTitle=(item.title||'').replace(/【[^】]+】/g,'').trim()
const relativeTime=formatTime(item.update_time||item.datetime||'')
return '<div class="card" onclick="saveItem('+idx+')">'+
'<div class="card-cover">'+coverHtml+'<span class="tag" style="background:'+cloudColor+'">'+cloudLabel+'</span></div>'+
'<div class="card-body">'+
'<div class="card-title">'+escapeHtml(cleanTitle)+'</div>'+
'<div class="card-meta"><span>🕐 '+relativeTime+'</span>'+(item.file_size?'<span class="size">📦 '+escapeHtml(item.file_size)+'</span>':'')+'</div>'+
(tags.length>0?'<div class="card-tags">'+tags.map(t=>'<span'+(isQualityTag(t)?' class="quality"':'')+'>'+escapeHtml(t)+'</span>').join('')+'</div>':'')+
'<div class="card-actions">'+
'<span class="card-source">'+(item.source?escapeHtml(item.source):'网盘')+'</span>'+
'<button class="card-btn" onclick="event.stopPropagation();saveItem('+idx+')">🔗 获取分享链接</button>'+
'</div>'+
'</div>'+
'</div>'
}).join('')
// Store items for save reference
window.__h5Results=items
}
function escapeHtml(s){if(!s)return '';return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;')}
function extractTags(title){
const tags=[]
// Quality tags
const quality=['4K','1080P','2160P','720P','480P','HDR','HDR10','BluRay','REMUX','HEVC','x264','x265','WEB-DL','WEBRip']
for(const q of quality){if(title.includes(q)&&!tags.includes(q))tags.push(q)}
const kw=['杜比视界','杜比全景声','高码率','内封简繁英字幕','内嵌字幕','中文字幕','中英字幕']
for(const k of kw){if(title.includes(k)&&!tags.includes(k))tags.push(k)}
return tags.slice(0,6)
}
function isQualityTag(t){const q=['4K','1080P','2160P','720P','480P','HDR','HDR10','BluRay','REMUX','HEVC','x264','x265','臻彩','高清','WEB-DL','WEBRip'];return q.includes(t)}
function formatTime(s){
if(!s)return ''
const d=new Date(s)
if(isNaN(d.getTime()))return s.slice(0,10)
const diff=Date.now()-d.getTime()
if(diff<0)return s.slice(0,10)
const mins=Math.floor(diff/60000)
if(mins<60)return mins<=1?'刚刚':mins+' 分钟前'
const hours=Math.floor(mins/60)
if(hours<24)return hours+' 小时前'
const days=Math.floor(hours/24)
if(days<30)return days+' 天前'
return Math.floor(days/30)+' 个月前'
}
// ===== Save / Share =====
function saveItem(idx){
const items=window.__h5Results||[]
currentSaveItem=items[idx]
if(!currentSaveItem)return
document.getElementById('progressSteps').style.display='block'
document.getElementById('shareContent').style.display='none'
document.getElementById('saveError').style.display='none'
document.getElementById('copyBtn2').style.display='none'
const title=(currentSaveItem.title||'').replace(/【[^】]+】/g,'').trim()||'资源'
document.getElementById('shareTitle').textContent=title
// Show modal
document.getElementById('overlay').style.display='block'
document.getElementById('shareModal').style.display='block'
// Reset steps
resetSteps()
advanceStep(1)
// Call save API
doSave()
}
async function doSave(){
try{
const res=await fetch('/api/save',{method:'POST',headers:apiHeaders(),body:JSON.stringify({type:'search',source:currentSaveItem,target_cloud:currentSaveItem.cloud_type||'quark'})})
const data=await res.json()
if(!data.success){
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent=data.message||data.error||'保存失败'
return
}
// Step 2
advanceStep(2)
await sleep(500)
// Step 3
advanceStep(3)
await sleep(300)
if(data.share_url){
advanceStep(4)
await sleep(200)
showShareResult(data)
}else{
advanceStep(4)
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent='生成分享链接失败'
}
}catch(e){
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent=e.message||'保存请求失败'
}
}
function showShareResult(data){
document.getElementById('progressSteps').style.display='none'
document.getElementById('shareContent').style.display='block'
const link=data.share_url
document.getElementById('shareLinkInput').value=link
const diskLabel=CLOUD_LABELS[currentSaveItem.cloud_type]||'夸克网盘'
document.getElementById('qrLabel').textContent=diskLabel+' APP扫码转存'
// Generate QR
const qrContainer=document.getElementById('qrContainer')
qrContainer.innerHTML=''
new QRCode(qrContainer,{text:link,width:140,height:140})
// Password
const pwd=data.share_pwd||data.sharePwd||''
if(pwd){
document.getElementById('sharePwdRow').style.display='flex'
document.getElementById('sharePwdTag').textContent=pwd
}else{
document.getElementById('sharePwdRow').style.display='none'
}
document.getElementById('copyBtn2').style.display='inline-block'
}
function resetSteps(){
for(let i=1;i<=3;i++){
const el=document.getElementById('step'+i)
el.className='step'
el.querySelector('.step-dot').innerHTML='<span>'+i+'</span>'
el.querySelector('.step-status').textContent='等待中'
el.querySelector('.step-status').className='step-status wait'
}
}
function advanceStep(n){
for(let i=1;i<=3;i++){
const el=document.getElementById('step'+i)
if(i<n){
el.className='step done'
el.querySelector('.step-dot').innerHTML='<span class="step-check">✓</span>'
el.querySelector('.step-status').textContent='已完成'
el.querySelector('.step-status').className='step-status done'
}else if(i===n){
el.className='step active'
el.querySelector('.step-dot').innerHTML='<span>'+i+'</span>'
const titles=['正在转存到','正在重命名文件(防和谐)','正在生成分享链接']
el.querySelector('.step-title').textContent=titles[i-1]+'...'
el.querySelector('.step-status').textContent='进行中'
el.querySelector('.step-status').className='step-status doing'
}
}
}
function sleep(ms){return new Promise(r=>setTimeout(r,ms))}
function copyShareLink(){
const input=document.getElementById('shareLinkInput')
if(!input.value)return
if(navigator.clipboard&&navigator.clipboard.writeText){
navigator.clipboard.writeText(input.value).then(()=>showToast('链接已复制')).catch(()=>fallbackCopy(input.value))
}else{
fallbackCopy(input.value)
}
}
function fallbackCopy(text){
const ta=document.createElement('textarea')
ta.value=text;ta.style.position='fixed';ta.style.left='-9999px';document.body.appendChild(ta)
ta.select()
try{document.execCommand('copy');showToast('链接已复制')}catch{showToast('复制失败',true)}
document.body.removeChild(ta)
}
function openDisclaimer(){
window.open('/disclaimer/','_blank')
}
function closeModal(){
document.getElementById('overlay').style.display='none'
document.getElementById('shareModal').style.display='none'
document.getElementById('loginModal').style.display='none'
}
// ===== Init =====
checkLogin()
// Add Enter key handler for home search
document.getElementById('homeSearchInput').addEventListener('keydown',function(e){if(e.key==='Enter')homeSearch()})
// Also add for search view input
document.getElementById('searchInput').addEventListener('keydown',function(e){if(e.key==='Enter')doSearch()})
// Fetch home page data
fetch('/api/rankings/categorized').then(r=>r.json()).then(data=>{
renderHomePage(data)
}).catch(()=>{
document.getElementById('homeQuote').textContent='「 学而时习之,不亦说乎。 」'
document.getElementById('homeQuoteAuthor').textContent='---孔子'
})
// Check URL for query
const params=new URLSearchParams(window.location.search)
const q=params.get('q')
if(q){
document.getElementById('homePage').style.display='none'
document.getElementById('searchView').style.display='block'
document.getElementById('searchInput').value=q
doSearch()
}
// ===== Dark Mode Toggle =====
(function() {
var btn = document.createElement('button');
btn.className = 'theme-btn';
btn.title = '切换暗色模式';
var isDark = localStorage.getItem('h5_theme') === 'dark';
if (!isDark && window.matchMedia('(prefers-color-scheme: dark)').matches) isDark = true;
btn.textContent = isDark ? '☀️' : '🌙';
if (isDark) document.documentElement.setAttribute('data-theme', 'dark');
btn.onclick = function() {
var dark = document.documentElement.getAttribute('data-theme') !== 'dark';
document.documentElement.setAttribute('data-theme', dark ? 'dark' : '');
localStorage.setItem('h5_theme', dark ? 'dark' : 'light');
btn.textContent = dark ? '☀️' : '🌙';
};
document.body.appendChild(btn);
})();

View File

@@ -0,0 +1,923 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>CloudSearch - 搜索</title>
<script>
// 替换标题为网站名称
fetch('/api/site-config').then(function(r){return r.json()}).then(function(cfg){
if(cfg.site_name) document.title = cfg.site_name + ' - 搜索';
}).catch(function(){});
</script>
<script src="/h5/qrcode.min.js"></script>
<style>
/* ===== Reset & Base ===== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:16px;-webkit-text-size-adjust:100%}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;background:#f5f5f5;color:#303133;min-height:100vh;overflow-x:hidden}
:root{--primary:#409eff;--primary-dark:#337ecc;--primary-light:rgba(64,158,255,0.08);--text:#303133;--text2:#909399;--border:#ebeef5;--bg:#f5f5f5;--white:#fff;--radius:10px;--shadow:0 1px 4px rgba(0,0,0,0.04);--safe-bottom:env(safe-area-inset-bottom,0px)}
a{color:var(--primary);text-decoration:none}
img{display:block;max-width:100%}
/* ===== Home Page ===== */
.home-page{padding-bottom:calc(30px + var(--safe-bottom))}
.home-hero{display:flex;flex-direction:column;align-items:center;padding:36px 16px 20px}
.home-logo{font-size:32px;font-weight:700;color:var(--primary);margin-bottom:20px;text-align:center}
.home-logo-img{max-width:360px;max-height:80px;width:auto;height:auto;object-fit:contain}
.home-search-box{display:flex;width:100%;max-width:500px;border:1px solid var(--border);border-radius:20px;overflow:hidden;background:var(--bg);transition:border-color .2s}
.home-search-box:focus-within{border-color:var(--primary);background:var(--white);box-shadow:0 0 0 3px rgba(64,158,255,.1)}
.home-search-box input{flex:1;height:40px;border:none;padding:0 14px;font-size:14px;outline:none;background:transparent}
.home-search-box button{flex-shrink:0;height:32px;margin:4px;padding:0 22px;border:none;border-radius:999px;background:var(--primary);color:var(--white);font-size:13px;font-weight:600;cursor:pointer}
.home-search-box button:active{background:var(--primary-dark)}
.home-quote{margin-top:12px;font-size:12px;color:#b0b8c4;font-style:italic;text-align:center;max-width:500px;line-height:1.5}
.home-quote-author{font-size:11px;color:#c0c4cc;display:inline-block;margin-top:2px}
/* ===== Home Rankings ===== */
.home-rankings{padding:8px 12px;display:flex;flex-direction:column;gap:10px}
.rank-block{background:var(--white);border-radius:var(--radius);padding:12px;border:1px solid var(--border);box-shadow:var(--shadow)}
.rank-block-hdr{display:flex;align-items:center;justify-content:space-between;padding-bottom:8px;border-bottom:2px solid #f0f0f0;margin-bottom:4px}
.rank-block-title{font-size:14px;font-weight:700;color:var(--text);white-space:nowrap}
.rank-block-tabs{display:flex;gap:2px;background:#f0f2f5;border-radius:5px;padding:2px}
.rank-tab{font-size:11px;padding:2px 9px;border-radius:4px;cursor:pointer;color:#909399;font-weight:500;transition:all .2s;user-select:none}
.rank-tab.active{background:var(--white);color:var(--primary);font-weight:600;box-shadow:0 1px 2px rgba(0,0,0,.06)}
.rank-item{display:flex;align-items:center;gap:7px;padding:5px 6px;border-radius:6px;cursor:pointer;transition:background .15s}
.rank-item:active{background:#f0f5ff}
.rank-idx{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#909399;background:#f0f0f0;flex-shrink:0}
.rank-idx.top3{background:var(--primary);color:var(--white);font-size:12px}
.rank-name{flex:1;min-width:0;font-size:13px;font-weight:500;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rank-cnt{font-size:11px;color:#c0c4cc;white-space:nowrap;flex-shrink:0}
.rank-expand{text-align:center;padding:5px;margin-top:2px;font-size:12px;color:var(--primary);cursor:pointer;border-radius:5px;user-select:none}
.rank-expand:active{background:#ecf5ff}
.rank-block-ftr{margin-top:6px;padding-top:6px;border-top:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;font-size:10px;color:#c0c4cc}
.ftr-time{font-family:monospace;font-size:9px}
/* ===== Layout ===== */
.app{max-width:100%;margin:0 auto;padding-bottom:calc(20px + var(--safe-bottom))}
.header{position:sticky;top:0;z-index:50;background:var(--white);border-bottom:1px solid var(--border);padding:8px 12px}
.header-row{display:flex;align-items:center;gap:10px}
.header-title{font-size:18px;font-weight:700;color:var(--primary);flex-shrink:0}
.header-title-link{text-decoration:none;flex-shrink:0;display:flex;align-items:center}
.header-logo-img{max-width:160px;max-height:36px;width:auto;height:auto;object-fit:contain;display:block}
.header-actions{margin-left:auto;display:flex;gap:6px;align-items:center}
/* ===== Search Bar ===== */
.search-wrap{flex:1;display:flex;border:1px solid var(--border);border-radius:18px;overflow:hidden;background:var(--bg);transition:border-color .2s}
.search-wrap:focus-within{border-color:var(--primary);background:var(--white)}
.search-wrap input{flex:1;height:36px;border:none;padding:0 14px;font-size:14px;outline:none;background:transparent}
.search-wrap button{flex-shrink:0;height:28px;margin:4px;padding:0 18px;border:none;border-radius:999px;background:var(--primary);color:var(--white);font-size:13px;font-weight:600;cursor:pointer;transition:background .2s}
.search-wrap button:active{background:var(--primary-dark)}
.search-wrap button:disabled{opacity:.5}
/* ===== Footer ===== */
.site-footer{margin-top:30px;padding:16px 12px 24px;background:#f9fafb;border-top:1px solid var(--border)}
.footer-inner{max-width:500px;margin:0 auto;font-size:11px;line-height:1.8;color:#909399;text-align:center;white-space:pre-line}
.footer-actions{display:flex;justify-content:center;gap:10px;margin-top:12px;flex-wrap:wrap}
.footer-btn{padding:8px 20px;border:1px solid var(--border);border-radius:8px;background:var(--white);color:var(--text);font-size:13px;cursor:pointer;transition:all .2s}
.footer-btn:active{background:var(--primary-light);border-color:var(--primary);color:var(--primary)}
/* ===== Info Bar ===== */
.info-bar{display:flex;align-items:center;gap:8px;padding:10px 12px 0;font-size:12px;color:var(--text2);flex-wrap:wrap}
.info-bar .count{font-weight:600;color:var(--text)}
.info-bar .time{font-family:monospace;background:#f4f4f5;padding:1px 6px;border-radius:4px}
.info-bar .badge-err{background:#fef0f0;color:#f56c6c;padding:1px 6px;border-radius:4px}
/* ===== Loading ===== */
.loading{padding:24px 12px;text-align:center;font-size:13px;color:var(--text2)}
.loading-bar{width:100%;height:3px;background:#e8e8e8;border-radius:2px;overflow:hidden;margin-top:8px}
.loading-bar-inner{height:100%;background:linear-gradient(90deg,var(--primary),#67c23a);border-radius:2px;transition:width .3s ease;width:0%}
/* ===== Tabs ===== */
.tabs{display:flex;gap:4px;padding:8px 12px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tab{flex-shrink:0;padding:5px 12px;border-radius:16px;font-size:12px;color:#606266;background:#f0f2f5;cursor:pointer;white-space:nowrap;transition:all .2s;user-select:none}
.tab:active{transform:scale(.95)}
.tab.active{background:var(--primary-light);color:var(--primary);font-weight:600}
/* ===== Results ===== */
.results{display:flex;flex-direction:column;gap:10px;padding:8px 12px}
.empty{padding:40px 12px;text-align:center;color:var(--text2);font-size:14px}
/* ===== Card ===== */
.card{display:flex;gap:10px;background:var(--white);border-radius:var(--radius);padding:10px;border:1px solid var(--border);transition:border-color .2s}
.card:active{border-color:#c0c4cc}
.card-cover{flex-shrink:0;width:90px;height:120px;border-radius:8px;overflow:hidden;background:var(--bg);position:relative}
.card-cover img{width:100%;height:100%;object-fit:cover}
.card-cover .placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:linear-gradient(135deg,#667eea,#764ba2);color:rgba(255,255,255,.6)}
.card-cover .tag{position:absolute;bottom:3px;left:3px;padding:1px 5px;border-radius:3px;color:#fff;font-size:10px;font-weight:600;backdrop-filter:blur(2px)}
.card-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.card-title{font-size:14px;font-weight:700;color:var(--text);line-height:1.3;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
.card-meta{font-size:11px;color:var(--text2);display:flex;align-items:center;gap:8px}
.card-meta .size{color:#67c23a}
.card-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:2px}
.card-tags span{font-size:10px;padding:1px 6px;border-radius:4px;background:#ecf5ff;color:#409eff;white-space:nowrap}
.card-tags .quality{background:#fef0f0;color:#e74c3c}
.card-actions{margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:6px}
.card-source{font-size:10px;color:var(--text2);background:#f4f4f5;padding:1px 6px;border-radius:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}
.card-btn{padding:4px 10px;border:none;border-radius:6px;background:var(--primary);color:var(--white);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background .2s}
.card-btn:active{background:var(--primary-dark)}
.card-btn:disabled{opacity:.5}
/* ===== Toast ===== */
.toast{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,.75);color:#fff;padding:10px 20px;border-radius:8px;font-size:14px;z-index:200;pointer-events:none;opacity:0;transition:opacity .3s}
.toast.show{opacity:1}
.toast.error{background:rgba(245,108,108,.9)}
/* ===== Overlay / Modal ===== */
.overlay{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;padding:16px;animation:fadeIn .2s}
.modal{background:var(--white);border-radius:14px;width:100%;max-width:420px;max-height:90vh;overflow-y:auto;padding:0;animation:slideUp .25s}
.modal-hdr{padding:14px 16px;border-bottom:1px solid var(--border);font-size:15px;font-weight:700;color:var(--text)}
.modal-body{padding:14px 16px}
.modal-ftr{padding:10px 16px;border-top:1px solid var(--border);display:flex;gap:8px;justify-content:flex-end}
.modal-ftr button{height:36px;padding:0 16px;border:none;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer}
.modal-ftr .btn-close{background:#f4f4f5;color:#606266}
.modal-ftr .btn-disclaimer{background:#fdf6ec;color:#d46b08;margin-right:auto}
.modal-ftr .btn-primary{background:var(--primary);color:var(--white)}
.modal-ftr .btn-primary:active{background:var(--primary-dark)}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes slideUp{from{transform:translateY(40px);opacity:0}to{transform:translateY(0);opacity:1}}
/* ===== Share Modal ===== */
.share-section{display:flex;flex-direction:column;gap:10px}
.share-row{display:flex;gap:8px}
.share-row input{flex:1;height:36px;border:1px solid var(--border);border-radius:6px;padding:0 10px;font-size:13px;outline:none;background:var(--bg);color:var(--text)}
.share-row input:focus{border-color:var(--primary)}
.share-row .copy-btn{height:36px;padding:0 12px;border:none;border-radius:6px;background:var(--primary);color:var(--white);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.share-pwd{display:flex;align-items:center;gap:6px;font-size:13px}
.share-pwd .pwd-tag{padding:2px 8px;background:#fdf6ec;color:#e6a23c;border-radius:4px;font-weight:700}
.share-pwd .pwd-hint{font-size:11px;color:var(--text2)}
.share-tip{padding:8px 10px;background:#fdf6ec;border-radius:6px;font-size:12px;line-height:1.5;color:#d46b08;display:flex;gap:6px;align-items:flex-start}
.share-tip .warn-icon{font-size:18px;line-height:1.5;flex-shrink:0}
.share-tip .tip-text{flex:1;min-width:0}
.share-tip strong{font-weight:700}
.warning-box{background:#fff2f0;border:1px solid #ffccc7;border-radius:8px;padding:8px 10px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.warning-item{margin:0;font-size:12px;line-height:1.8;font-weight:700;white-space:nowrap}
.warning-item:nth-child(odd){color:#cf1322}
.warning-item:nth-child(even){color:#d46b08}
.warning-item:last-child{color:#b71c1c;font-size:13px}
.share-qr{display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px}
.share-qr canvas{border-radius:8px}
.share-qr .qr-label{font-size:12px;font-weight:600;color:var(--primary)}
.share-qr .qr-sub{font-size:11px;color:var(--text2)}
.share-disclaimer{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:10px;padding:8px 10px;background:#fdf6ec;border-radius:6px;font-size:12px;color:#d46b08;flex-wrap:wrap}
/* ===== Login Modal ===== */
.login-form{display:flex;flex-direction:column;gap:12px}
.login-form input{height:40px;border:1px solid var(--border);border-radius:8px;padding:0 12px;font-size:14px;outline:none}
.login-form input:focus{border-color:var(--primary)}
.login-form .login-btn{height:40px;border:none;border-radius:8px;background:var(--primary);color:var(--white);font-size:14px;font-weight:600;cursor:pointer;transition:background .2s}
.login-form .login-btn:active{background:var(--primary-dark)}
.login-form .login-btn:disabled{opacity:.5}
.login-form .login-err{font-size:12px;color:#f56c6c;text-align:center}
/* ===== Progress Steps ===== */
.steps{display:flex;flex-direction:column;gap:10px;padding:8px 0}
.step{display:flex;align-items:flex-start;gap:10px;opacity:.4;transition:opacity .3s}
.step.active{opacity:1}
.step.done{opacity:.7}
.step-dot{flex-shrink:0;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;background:#e4e7ed;color:#909399}
.step.active .step-dot{background:var(--primary);color:#fff;box-shadow:0 0 0 3px rgba(64,158,255,.2)}
.step.done .step-dot{background:#67c23a;color:#fff}
.step-body{flex:1;padding-top:3px;display:flex;align-items:center;gap:8px}
.step-title{font-size:13px;color:var(--text);font-weight:500}
.step-status{font-size:11px;padding:1px 7px;border-radius:10px;white-space:nowrap}
.step-status.doing{background:#ecf5ff;color:var(--primary)}
.step-status.done{background:#f0f9eb;color:#67c23a}
.step-status.wait{background:#f4f4f5;color:#c0c4cc}
.error-alert{padding:12px 16px;background:#fef0f0;border:1px solid #fde2e2;border-radius:8px;display:flex;align-items:center;gap:8px;font-size:14px;color:#f56c6c}
/* ===== User Badge ===== */
.user-badge{font-size:12px;color:var(--primary);font-weight:600;white-space:nowrap}
.login-btn-small{height:30px;padding:0 10px;border:none;border-radius:6px;background:var(--primary-light);color:var(--primary);font-size:12px;font-weight:600;cursor:pointer}
.logout-btn-small{height:30px;padding:0 8px;border:none;border-radius:6px;background:transparent;color:var(--text2);font-size:12px;cursor:pointer}
</style>
</head>
<body>
<div class="app" id="app">
<!-- ===== Home Page (shown when no search) ===== -->
<div id="homePage" class="home-page">
<div class="home-hero">
<div class="home-logo" id="homeLogo" style="display:none"></div>
<div class="home-search-box">
<input id="homeSearchInput" type="text" placeholder="搜索网盘资源..." />
<button id="homeSearchBtn" onclick="homeSearch()">搜 索</button>
</div>
<div class="home-quote" id="homeQuote"></div>
<div class="home-quote-author" id="homeQuoteAuthor"></div>
</div>
<div class="home-rankings" id="homeRankings"></div>
</div>
<!-- ===== Search Results View ===== -->
<div id="searchView" style="display:none">
<!-- Header -->
<div class="header">
<div class="header-row">
<a href="/h5" class="header-title-link"><div class="header-title" id="headerTitle" style="display:none">CloudSearch</div></a>
<div class="search-wrap">
<input id="searchInput" type="text" placeholder="搜索网盘资源..." @keydown="handleKeydown" />
<button id="searchBtn" onclick="doSearch()">搜 索</button>
</div>
<div class="header-actions" id="userArea">
<template id="userLoggedIn">
<span class="user-badge" id="usernameDisplay"></span>
<button class="logout-btn-small" onclick="logout()">退出</button>
</template>
<template id="userLoggedOut">
<button class="login-btn-small" onclick="showLogin()">登录</button>
</template>
</div>
</div>
</div>
<!-- Info Bar -->
<div id="infoBar" class="info-bar" style="display:none">
<span id="infoCount" class="count"></span>
<span id="infoTime" class="time"></span>
<span id="infoFiltered" class="badge-err"></span>
</div>
<!-- Loading -->
<div id="loading" class="loading" style="display:none">
<div id="loadingText">🔍 正在搜索中...</div>
<div class="loading-bar"><div class="loading-bar-inner" id="loadingBar"></div></div>
</div>
<!-- Tabs -->
<div id="tabs" class="tabs" style="display:none"></div>
<!-- Results -->
<div id="results" class="results"></div>
<!-- Overlay -->
<div class="overlay" id="overlay" style="display:none" onclick="closeModal()"></div>
<!-- Share Modal -->
<div class="modal" id="shareModal" style="display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:101">
<div class="modal-hdr" id="shareTitle">分享链接</div>
<div class="modal-body">
<div id="progressSteps" class="steps" style="display:none">
<div class="step" id="step1"><div class="step-dot"><span>1</span></div><div class="step-body"><span class="step-title">正在转存...</span><span class="step-status doing">进行中</span></div></div>
<div class="step" id="step2"><div class="step-dot"><span>2</span></div><div class="step-body"><span class="step-title">重命名文件(防和谐)...</span><span class="step-status wait">等待中</span></div></div>
<div class="step" id="step3"><div class="step-dot"><span>3</span></div><div class="step-body"><span class="step-title">生成分享链接...</span><span class="step-status wait">等待中</span></div></div>
</div>
<div id="saveError" class="error-alert" style="display:none"></div>
<div id="shareContent" style="display:none">
<div class="share-qr">
<div id="qrContainer"></div>
<div class="qr-label" id="qrLabel"></div>
<div class="qr-sub">保存到你自己的网盘</div>
</div>
<div class="share-section">
<div class="share-row">
<input id="shareLinkInput" type="text" readonly />
</div>
<div id="sharePwdRow" class="share-pwd" style="display:none">
<span>🔑 提取密码:</span>
<span class="pwd-tag" id="sharePwdTag"></span>
<span class="pwd-hint">打开链接后需输入密码</span>
</div>
<div class="share-tip">
<span class="warn-icon">⚠️</span>
<div class="tip-text">
<strong>请尽快复制链接到浏览器打开</strong><strong>用夸克APP扫码</strong><br>
<strong>转存至您的网盘,以免资源被官方和谐</strong>
</div>
</div>
<div class="warning-box">
<p class="warning-item">郑重警告一:网盘内除您所需资源外,不要打开任何不相关内容。</p>
<p class="warning-item">郑重警告二:网盘内除您所需资源外,不要打开任何不相关内容。</p>
<p class="warning-item">郑重警告三:网盘内除您所需资源外,不要打开任何不相关内容。</p>
<p class="warning-item">郑重警告四:以上警告说三遍,你还要明知故犯吗?</p>
</div>
<div class="share-disclaimer">
<span>⚠️ 本站资源仅供学习交流请于24h内删除</span>
</div>
</div>
</div>
</div>
<div class="modal-ftr">
<button class="btn-disclaimer" onclick="openDisclaimer()">📜 免责声明</button>
<button class="btn-close" onclick="closeModal()">关闭</button>
<button class="btn-primary" id="copyBtn2" onclick="copyShareLink()" style="display:none">一键复制链接</button>
</div>
</div>
<!-- Login Modal -->
<div class="modal" id="loginModal" style="display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:101">
<div class="modal-hdr">登录</div>
<div class="modal-body">
<div class="login-form">
<input id="loginUser" type="text" placeholder="用户名" />
<input id="loginPass" type="password" placeholder="密码" />
<button class="login-btn" id="loginBtn" onclick="handleLogin()">登录</button>
<div class="login-err" id="loginErr"></div>
</div>
</div>
<div class="modal-ftr">
<button class="btn-close" onclick="closeLogin()">取消</button>
</div>
</div>
</div>
</div>
<!-- Toast -->
<div class="toast" id="toast"></div>
<script>
// ===== Anime keywords for categorization =====
const ANIME_KWS=['仙逆','凡人修仙传','斗破苍穹','斗破','盘龙','完美世界','一念永恒','妖神记','星辰变','遮天','神墓','吞噬星空','武动乾坤','大主宰','全职高手','鬼灭之刃','海贼王','火影忍者','死神','龙珠','进击的巨人','咒术回战','一人之下','狐妖小红娘','魔道祖师','天官赐福','时光代理人','大王饶命','斗罗大陆','绝世唐门','不良人','秦时明月','全职法师','牧神记','三体','灵笼','雾山五行','凡人','仙王的日常生活','百妖谱','眷思量','镖人','伍六七','刺客伍六七','葬送的芙莉莲','间谍过家家']
// ===== Quotes =====
const QUOTES=['学而时习之,不亦说乎。','温故而知新,可以为师矣。','三人行,必有我师焉。','学而不思则罔,思而不学则殆。','博学之,审问之,慎思之,明辨之,笃行之。','千里之行,始于足下。','不积跬步,无以至千里。','知之为知之,不知为不知,是知也。','工欲善其事,必先利其器。','玉不琢,不成器;人不学,不知道。','学以致用,知行合一。','学海无涯,勤作舟。','书山有路,勤为径。','宝剑锋从磨砺出,梅花香自苦寒来。','锲而不舍,金石可镂。','业精于勤,荒于嬉。','读书破万卷,下笔如有神。','路漫漫其修远兮,吾将上下而求索。','采菊东篱下,悠然见南山。','海内存知己,天涯若比邻。','长风破浪会有时,直挂云帆济沧海。','会当凌绝顶,一览众山小。','山重水复疑无路,柳暗花明又一村。']
// ===== Home Page =====
function homeSearch(){
const q=document.getElementById('homeSearchInput').value.trim()
if(q)doSearchFromHome(q)
}
function doSearchFromHome(q){
document.getElementById('homePage').style.display='none'
document.getElementById('searchView').style.display='block'
document.getElementById('searchInput').value=q
window.history.replaceState({},'','/h5?q='+encodeURIComponent(q))
doSearch()
}
function renderHomePage(data){
fetch("/api/site-config").then(r=>r.json()).then(cfg=>{
// 显示 Logo优先图片其次文字
var logoEl=document.getElementById("homeLogo");
var headerEl=document.getElementById("headerTitle");
if(cfg.site_logo){
logoEl.innerHTML='<img src="'+cfg.site_logo+'" class="home-logo-img" alt="logo" />';
logoEl.style.display="";
headerEl.innerHTML='<img src="'+cfg.site_logo+'" class="header-logo-img" alt="logo" />';
headerEl.style.display="";
}else if(cfg.site_name){
logoEl.textContent=cfg.site_name;
logoEl.style.display="";
headerEl.textContent=cfg.site_name;
headerEl.style.display="";
}else{
logoEl.textContent="CloudSearch";
logoEl.style.display="";
headerEl.textContent="CloudSearch";
headerEl.style.display="";
}
if(cfg.site_disclaimer){
document.getElementById("footerContent").innerHTML=cfg.site_disclaimer.replace(/\n/g,'<br>');
document.getElementById("siteFooter").style.display="block";
}
}).catch(()=>{})
const categories=data.categories||[]
const fetchedAt=data.fetchedAt||''
// Quote
fetch('https://v1.hitokoto.cn/').then(r=>r.json()).then(d=>{
document.getElementById('homeQuote').textContent='「 '+d.hitokoto+' 」'
document.getElementById('homeQuoteAuthor').textContent='---'+(d.from_who||d.from||'')
}).catch(()=>{
document.getElementById('homeQuote').textContent='「 学而时习之,不亦说乎。 」'
document.getElementById('homeQuoteAuthor').textContent='---孔子'
})
// Store expanded state per category
window.__expanded=window.__expanded||{}
window.__activeTab=window.__activeTab||{}
const el=document.getElementById('homeRankings')
let html=''
for(const cat of categories){
const icons={movie:'🎬',tv:'📺',western_movie:'🎥',western:'🌍',donghua:'🐉',global_anime:'🌐',variety:'🎤',niche:'💎',hotsite:'🏆'}
const icon=icons[cat.category]||'📋'
const key=cat.category
if(!window.__activeTab[key])window.__activeTab[key]='hot'
html+='<div class="rank-block">'
html+='<div class="rank-block-hdr">'+
'<span class="rank-block-title">'+icon+' '+cat.label+'</span>'+
'<div class="rank-block-tabs" id="rtabs-'+key+'">'+
'<span class="rank-tab'+(window.__activeTab[key]==='hot'?' active':'')+'" onclick="switchRankTab(\''+key+'\',\'hot\')">热榜</span>'+
'<span class="rank-tab'+(window.__activeTab[key]==='newest'?' active':'')+'" onclick="switchRankTab(\''+key+'\',\'newest\')">最新</span>'+
'</div>'+
'</div>'
html+='<div class="rank-block-items" id="ritems-'+key+'" data-hot=\''+JSON.stringify({items:cat.hot||[]}).replace(/'/g,"&#39;")+'\' data-newest=\''+JSON.stringify({items:cat.newest||[]}).replace(/'/g,"&#39;")+'\'>'
const items=window.__activeTab[key]==='hot'?(cat.hot||[]):(cat.newest||[])
html+=renderRankItems(items,key,false)
html+='</div>'
// 数据来源
html+='<div class="rank-block-ftr">'+
'<span>'+(cat.category!=='hotsite'?'数据来源TMDB':'本站搜索数据')+'</span>'+
'<span class="ftr-time">'+fetchedAt+'</span>'+
'</div></div>'
}
el.innerHTML=html
}
function renderRankItems(items,key,expanded){
if(!items||items.length===0)return'<div style="padding:10px;text-align:center;color:#c0c4cc;font-size:12px">暂无数据</div>'
const limit=3
const show=expanded?items.length:Math.min(limit,items.length)
let html=items.slice(0,show).map((item,i)=>{
const c=i<3?' rank-idx top3':' rank-idx'
return '<div class="rank-item" onclick="doSearchFromHome(\''+item.keyword.replace(/'/g,"\\'")+'\')">'+
'<span class="'+c+'">'+(i+1)+'</span>'+
'<span class="rank-name">'+item.keyword+'</span>'+
'<span class="rank-cnt">'+(item.rating?'⭐'+item.rating:item.searchCount)+'</span>'+
'</div>'
}).join('')
if(items.length>limit&&!expanded){
html+='<div class="rank-expand" onclick="expandRank(\''+key+'\')">展开全部 ▼</div>'
}
return html
}
function expandRank(key){
const container=document.getElementById('ritems-'+key)
if(!container)return
const tab=window.__activeTab[key]||'hot'
const data=JSON.parse(tab==='hot'?container.dataset.hot:container.dataset.newest)
container.innerHTML=renderRankItems(data.items,key,true)
}
function switchRankTab(category,tab){
window.__activeTab[category]=tab
const tabsContainer=document.getElementById('rtabs-'+category)
if(tabsContainer){
tabsContainer.querySelectorAll('.rank-tab').forEach(t=>t.className='rank-tab')
tabsContainer.querySelector(tab==='hot'?'.rank-tab:first-child':'.rank-tab:last-child').className='rank-tab active'
}
const container=document.getElementById('ritems-'+category)
if(container){
const data=JSON.parse(tab==='hot'?container.dataset.hot:container.dataset.newest)
container.innerHTML=renderRankItems(data.items,category,false)
}
}
let userInfo = null
let allResults = []
let allChannels = []
let activeTab = ''
let currentSaveItem = null
const CLOUD_ICONS = {quark:'☁️',baidu:'🔵',aliyun:'🟠','115':'🟣',tianyi:'🔷','123pan':'🔴',uc:'🟡',xunlei:'🟢',pikpak:'🟤',magnet:'🧲',ed2k:'🔗',others:'📁'}
const CLOUD_LABELS = {quark:'夸克网盘',baidu:'百度网盘',aliyun:'阿里云盘','115':'115网盘',tianyi:'天翼云盘','123pan':'123云盘',uc:'UC网盘',xunlei:'迅雷云盘',pikpak:'PikPak',magnet:'磁力链接',ed2k:'电驴链接',others:'其他'}
const CLOUD_COLORS = {quark:'#07c160',baidu:'#4e6ef2',aliyun:'#ff6a00','115':'#9b59b6',tianyi:'#00a1d6','123pan':'#e74c3c',uc:'#f39c12',xunlei:'#2ecc71',pikpak:'#8e44ad',magnet:'#95a5a6',ed2k:'#7f8c8d',others:'#95a5a6'}
const CLOUD_ORDER = {quark:1,baidu:2,aliyun:3,'115':4,tianyi:5,'123pan':6,uc:7,xunlei:8,pikpak:9,magnet:10,ed2k:11,others:12}
// ===== Fetch helpers =====
function getToken(){return localStorage.getItem('h5_admin_token')}
function apiHeaders(){const h={'Content-Type':'application/json'};const t=getToken();if(t)h['Authorization']='Bearer '+t;return h}
// ===== Toast =====
let toastTimer
function showToast(msg,isError){
const el=document.getElementById('toast')
el.textContent=msg
el.className='toast show'+(isError?' error':'')
clearTimeout(toastTimer)
toastTimer=setTimeout(()=>el.className='toast',2000)
}
// ===== User =====
async function checkLogin(){
try{
const res=await fetch('/api/me',{headers:apiHeaders()})
if(res.ok){
const data=await res.json()
if(data.loggedIn){
userInfo=data
document.getElementById('userArea').innerHTML='<span class="user-badge">'+data.username+'</span><button class="logout-btn-small" onclick="logout()">退出</button>'
}
}
}catch(e){}
}
function logout(){
localStorage.removeItem('h5_admin_token')
userInfo=null
document.getElementById('userArea').innerHTML='<button class="login-btn-small" onclick="showLogin()">登录</button>'
showToast('已退出')
}
function showLogin(){
document.getElementById('loginErr').textContent=''
document.getElementById('loginUser').value=''
document.getElementById('loginPass').value=''
document.getElementById('loginModal').style.display='block'
document.getElementById('overlay').style.display='block'
}
function closeLogin(){
document.getElementById('loginModal').style.display='none'
document.getElementById('overlay').style.display='none'
}
async function handleLogin(){
const user=document.getElementById('loginUser').value.trim()
const pass=document.getElementById('loginPass').value
if(!user||!pass){showToast('请输入用户名和密码',true);return}
const btn=document.getElementById('loginBtn')
btn.disabled=true;btn.textContent='登录中...'
try{
const res=await fetch('/api/admin/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:user,password:pass})})
if(res.ok){
const data=await res.json()
localStorage.setItem('h5_admin_token',data.token)
userInfo={username:user}
document.getElementById('userArea').innerHTML='<span class="user-badge">'+user+'</span><button class="logout-btn-small" onclick="logout()">退出</button>'
closeLogin()
showToast('登录成功')
}else{
const err=await res.json().catch(()=>({}))
document.getElementById('loginErr').textContent=err.error||'登录失败'
}
}catch(e){
document.getElementById('loginErr').textContent='网络错误'
}finally{
btn.disabled=false;btn.textContent='登录'
}
}
// ===== Search =====
function handleKeydown(e){if(e.key==='Enter')doSearch()}
let searchTimer
function doSearch(){
const q=document.getElementById('searchInput').value.trim()
if(!q)return
// Update URL
window.history.replaceState({},'','/h5?q='+encodeURIComponent(q))
// Show loading
document.getElementById('results').innerHTML=''
document.getElementById('tabs').style.display='none'
document.getElementById('infoBar').style.display='none'
document.getElementById('loading').style.display='block'
document.getElementById('loadingText').textContent='🔍 正在搜索中...'
document.getElementById('searchBtn').disabled=true
let progress=0
const bar=document.getElementById('loadingBar')
const progressTimer=setInterval(()=>{
if(progress<60)progress+=1+Math.random()*3
else if(progress<85)progress+=0.5+Math.random()
bar.style.width=progress+'%'
},200)
// Use streaming search for live updates
streamSearch(q,progressTimer,bar)
}
async function streamSearch(q,progressTimer,bar){
const startTime=Date.now()
try{
const response=await fetch('/api/query',{method:'POST',headers:apiHeaders(),body:JSON.stringify({q})})
if(!response.ok)throw new Error('搜索失败 ('+response.status+')')
const reader=response.body.getReader()
const decoder=new TextDecoder()
let buffer=''
let allItems=[]
let channels=[]
let totalCount=0
let filteredCount=0
while(true){
const {done,value}=await reader.read()
if(done)break
buffer+=decoder.decode(value,{stream:true})
const lines=buffer.split('\n')
buffer=lines.pop()||''
for(const line of lines){
if(!line.trim())continue
try{
const msg=JSON.parse(line)
if(msg.type==='stats'){
totalCount=msg.total||0
filteredCount=msg.filtered||0
document.getElementById('loadingText').textContent='🔍 搜索到 '+totalCount+' 条,正在验证...'
}else if(msg.type==='result'){
if(msg.valid&&msg.id){
allItems.push(msg.id)
}
}else if(msg.type==='complete'){
const results=msg.results||[]
channels=msg.channels||[]
clearInterval(progressTimer)
bar.style.width='100%'
setTimeout(()=>renderResults(results,channels,totalCount,filteredCount,Date.now()-startTime),300)
return
}
}catch(e){}
}
}
}catch(e){
clearInterval(progressTimer)
document.getElementById('loading').style.display='none'
document.getElementById('searchBtn').disabled=false
document.getElementById('results').innerHTML='<div class="empty">搜索失败:'+e.message+'</div>'
}
}
// ===== Render =====
function renderResults(results,channels,totalCount,filteredCount,time){
document.getElementById('loading').style.display='none'
document.getElementById('searchBtn').disabled=false
allResults=results
allChannels=channels||[]
// Info bar
if(totalCount>0){
document.getElementById('infoBar').style.display='flex'
document.getElementById('infoCount').textContent='已为您挑选到最符合 '+totalCount+' 条结果'
document.getElementById('infoTime').textContent='⏱ '+time+'ms'
if(filteredCount>0)document.getElementById('infoFiltered').textContent='❌ 失效 '+filteredCount
else document.getElementById('infoFiltered').textContent=''
}else{
document.getElementById('infoBar').style.display='none'
}
// Build tabs
const tabsEl=document.getElementById('tabs')
tabsEl.innerHTML=''
const typeCounts={}
for(const r of results){const ct=r.cloud_type||'others';typeCounts[ct]=(typeCounts[ct]||0)+1}
const sorted=Object.keys(typeCounts).sort((a,b)=>(CLOUD_ORDER[a]||99)-(CLOUD_ORDER[b]||99))
// "全部" tab
const allTab=document.createElement('div')
allTab.className='tab active'
allTab.textContent='📋 全部 ('+results.length+')'
allTab.onclick=()=>{setActiveTab('');renderCardList(results)}
tabsEl.appendChild(allTab)
for(const ct of sorted){
const tab=document.createElement('div')
tab.className='tab'
tab.textContent=(CLOUD_ICONS[ct]||'📁')+' '+(CLOUD_LABELS[ct]||ct)+' ('+typeCounts[ct]+')'
tab.onclick=()=>{setActiveTab(ct);renderCardList(results.filter(r=>(r.cloud_type||'others')===ct))}
tabsEl.appendChild(tab)
}
tabsEl.style.display=results.length>0?'flex':'none'
activeTab=''
// Render cards
renderCardList(results)
}
function setActiveTab(ct){
activeTab=ct
document.querySelectorAll('.tab').forEach((t,i)=>{
const isAll=i===0&&!ct
const active=i>0&&ct&&t.textContent.includes(CLOUD_LABELS[ct])
t.className='tab'+(active||isAll?' active':'')
})
}
function renderCardList(items){
const el=document.getElementById('results')
if(items.length===0){
el.innerHTML='<div class="empty">暂无结果</div>'
return
}
el.innerHTML=items.map((item,idx)=>{
const coverHtml=item.cover
? '<img src="'+escapeHtml(item.cover)+'" alt="" onerror="this.parentElement.innerHTML=\'<div class=placeholder>'+escapeHtml(CLOUD_ICONS[item.cloud_type||'others'])+'</div>\'" loading="lazy" />'
: '<div class="placeholder">'+escapeHtml(CLOUD_ICONS[item.cloud_type||'others'])+'</div>'
const cloudLabel=CLOUD_LABELS[item.cloud_type]||item.cloud_type||''
const cloudColor=CLOUD_COLORS[item.cloud_type]||'#95a5a6'
const tags=extractTags(item.title||'')
const cleanTitle=(item.title||'').replace(/【[^】]+】/g,'').trim()
const relativeTime=formatTime(item.update_time||item.datetime||'')
return '<div class="card" onclick="saveItem('+idx+')">'+
'<div class="card-cover">'+coverHtml+'<span class="tag" style="background:'+cloudColor+'">'+cloudLabel+'</span></div>'+
'<div class="card-body">'+
'<div class="card-title">'+escapeHtml(cleanTitle)+'</div>'+
'<div class="card-meta"><span>🕐 '+relativeTime+'</span>'+(item.file_size?'<span class="size">📦 '+escapeHtml(item.file_size)+'</span>':'')+'</div>'+
(tags.length>0?'<div class="card-tags">'+tags.map(t=>'<span'+(isQualityTag(t)?' class="quality"':'')+'>'+escapeHtml(t)+'</span>').join('')+'</div>':'')+
'<div class="card-actions">'+
'<span class="card-source">'+(item.source?escapeHtml(item.source):'网盘')+'</span>'+
'<button class="card-btn" onclick="event.stopPropagation();saveItem('+idx+')">🔗 获取分享链接</button>'+
'</div>'+
'</div>'+
'</div>'
}).join('')
// Store items for save reference
window.__h5Results=items
}
function escapeHtml(s){if(!s)return '';return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;')}
function extractTags(title){
const tags=[]
// Quality tags
const quality=['4K','1080P','2160P','720P','480P','HDR','HDR10','BluRay','REMUX','HEVC','x264','x265','WEB-DL','WEBRip']
for(const q of quality){if(title.includes(q)&&!tags.includes(q))tags.push(q)}
const kw=['杜比视界','杜比全景声','高码率','内封简繁英字幕','内嵌字幕','中文字幕','中英字幕']
for(const k of kw){if(title.includes(k)&&!tags.includes(k))tags.push(k)}
return tags.slice(0,6)
}
function isQualityTag(t){const q=['4K','1080P','2160P','720P','480P','HDR','HDR10','BluRay','REMUX','HEVC','x264','x265','臻彩','高清','WEB-DL','WEBRip'];return q.includes(t)}
function formatTime(s){
if(!s)return ''
const d=new Date(s)
if(isNaN(d.getTime()))return s.slice(0,10)
const diff=Date.now()-d.getTime()
if(diff<0)return s.slice(0,10)
const mins=Math.floor(diff/60000)
if(mins<60)return mins<=1?'刚刚':mins+' 分钟前'
const hours=Math.floor(mins/60)
if(hours<24)return hours+' 小时前'
const days=Math.floor(hours/24)
if(days<30)return days+' 天前'
return Math.floor(days/30)+' 个月前'
}
// ===== Save / Share =====
function saveItem(idx){
const items=window.__h5Results||[]
currentSaveItem=items[idx]
if(!currentSaveItem)return
document.getElementById('progressSteps').style.display='block'
document.getElementById('shareContent').style.display='none'
document.getElementById('saveError').style.display='none'
document.getElementById('copyBtn2').style.display='none'
const title=(currentSaveItem.title||'').replace(/【[^】]+】/g,'').trim()||'资源'
document.getElementById('shareTitle').textContent=title
// Show modal
document.getElementById('overlay').style.display='block'
document.getElementById('shareModal').style.display='block'
// Reset steps
resetSteps()
advanceStep(1)
// Call save API
doSave()
}
async function doSave(){
try{
const res=await fetch('/api/save',{method:'POST',headers:apiHeaders(),body:JSON.stringify({type:'search',source:currentSaveItem,target_cloud:currentSaveItem.cloud_type||'quark'})})
const data=await res.json()
if(!data.success){
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent=data.message||data.error||'保存失败'
return
}
// Step 2
advanceStep(2)
await sleep(500)
// Step 3
advanceStep(3)
await sleep(300)
if(data.share_url){
advanceStep(4)
await sleep(200)
showShareResult(data)
}else{
advanceStep(4)
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent='生成分享链接失败'
}
}catch(e){
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent=e.message||'保存请求失败'
}
}
function showShareResult(data){
document.getElementById('progressSteps').style.display='none'
document.getElementById('shareContent').style.display='block'
const link=data.share_url
document.getElementById('shareLinkInput').value=link
const diskLabel=CLOUD_LABELS[currentSaveItem.cloud_type]||'夸克网盘'
document.getElementById('qrLabel').textContent=diskLabel+' APP扫码转存'
// Generate QR
const qrContainer=document.getElementById('qrContainer')
qrContainer.innerHTML=''
new QRCode(qrContainer,{text:link,width:140,height:140})
// Password
const pwd=data.share_pwd||data.sharePwd||''
if(pwd){
document.getElementById('sharePwdRow').style.display='flex'
document.getElementById('sharePwdTag').textContent=pwd
}else{
document.getElementById('sharePwdRow').style.display='none'
}
document.getElementById('copyBtn2').style.display='inline-block'
}
function resetSteps(){
for(let i=1;i<=3;i++){
const el=document.getElementById('step'+i)
el.className='step'
el.querySelector('.step-dot').innerHTML='<span>'+i+'</span>'
el.querySelector('.step-status').textContent='等待中'
el.querySelector('.step-status').className='step-status wait'
}
}
function advanceStep(n){
for(let i=1;i<=3;i++){
const el=document.getElementById('step'+i)
if(i<n){
el.className='step done'
el.querySelector('.step-dot').innerHTML='<span class="step-check">✓</span>'
el.querySelector('.step-status').textContent='已完成'
el.querySelector('.step-status').className='step-status done'
}else if(i===n){
el.className='step active'
el.querySelector('.step-dot').innerHTML='<span>'+i+'</span>'
const titles=['正在转存到','正在重命名文件(防和谐)','正在生成分享链接']
el.querySelector('.step-title').textContent=titles[i-1]+'...'
el.querySelector('.step-status').textContent='进行中'
el.querySelector('.step-status').className='step-status doing'
}
}
}
function sleep(ms){return new Promise(r=>setTimeout(r,ms))}
function copyShareLink(){
const input=document.getElementById('shareLinkInput')
if(!input.value)return
if(navigator.clipboard&&navigator.clipboard.writeText){
navigator.clipboard.writeText(input.value).then(()=>showToast('链接已复制')).catch(()=>fallbackCopy(input.value))
}else{
fallbackCopy(input.value)
}
}
function fallbackCopy(text){
const ta=document.createElement('textarea')
ta.value=text;ta.style.position='fixed';ta.style.left='-9999px';document.body.appendChild(ta)
ta.select()
try{document.execCommand('copy');showToast('链接已复制')}catch{showToast('复制失败',true)}
document.body.removeChild(ta)
}
function openDisclaimer(){
window.open('/disclaimer/','_blank')
}
function closeModal(){
document.getElementById('overlay').style.display='none'
document.getElementById('shareModal').style.display='none'
document.getElementById('loginModal').style.display='none'
}
// ===== Init =====
checkLogin()
// Add Enter key handler for home search
document.getElementById('homeSearchInput').addEventListener('keydown',function(e){if(e.key==='Enter')homeSearch()})
// Also add for search view input
document.getElementById('searchInput').addEventListener('keydown',function(e){if(e.key==='Enter')doSearch()})
// Fetch home page data
fetch('/api/rankings/categorized').then(r=>r.json()).then(data=>{
renderHomePage(data)
}).catch(()=>{
document.getElementById('homeQuote').textContent='「 学而时习之,不亦说乎。 」'
document.getElementById('homeQuoteAuthor').textContent='---孔子'
})
// Check URL for query
const params=new URLSearchParams(window.location.search)
const q=params.get('q')
if(q){
document.getElementById('homePage').style.display='none'
document.getElementById('searchView').style.display='block'
document.getElementById('searchInput').value=q
doSearch()
}
</script>
</body>
<!-- Footer -->
<div id="siteFooter" class="site-footer" style="display:none">
<div id="footerContent" class="footer-inner"></div>
<div class="footer-actions" id="footerActions">
<button class="footer-btn" onclick="openDisclaimer()">📜 免责声明</button>
</div>
</div>
</html>

View File

@@ -13,187 +13,8 @@
if(cfg.site_name) document.title = cfg.site_name + ' - 搜索'; if(cfg.site_name) document.title = cfg.site_name + ' - 搜索';
}).catch(function(){}); }).catch(function(){});
</script> </script>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script> <script src="/h5/qrcode.min.js"></script>
<style> <link rel="stylesheet" href="/h5/style.css" />
/* ===== Reset & Base ===== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:16px;-webkit-text-size-adjust:100%}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;background:#f5f5f5;color:#303133;min-height:100vh;overflow-x:hidden}
:root{--primary:#409eff;--primary-dark:#337ecc;--primary-light:rgba(64,158,255,0.08);--text:#303133;--text2:#909399;--border:#ebeef5;--bg:#f5f5f5;--white:#fff;--radius:10px;--shadow:0 1px 4px rgba(0,0,0,0.04);--safe-bottom:env(safe-area-inset-bottom,0px)}
a{color:var(--primary);text-decoration:none}
img{display:block;max-width:100%}
/* ===== Home Page ===== */
.home-page{padding-bottom:calc(30px + var(--safe-bottom))}
.home-hero{display:flex;flex-direction:column;align-items:center;padding:36px 16px 20px}
.home-logo{font-size:32px;font-weight:700;color:var(--primary);margin-bottom:20px;text-align:center}
.home-logo-img{max-width:360px;max-height:80px;width:auto;height:auto;object-fit:contain}
.home-search-box{display:flex;width:100%;max-width:500px;border:1px solid var(--border);border-radius:20px;overflow:hidden;background:var(--bg);transition:border-color .2s}
.home-search-box:focus-within{border-color:var(--primary);background:var(--white);box-shadow:0 0 0 3px rgba(64,158,255,.1)}
.home-search-box input{flex:1;height:40px;border:none;padding:0 14px;font-size:14px;outline:none;background:transparent}
.home-search-box button{flex-shrink:0;height:32px;margin:4px;padding:0 22px;border:none;border-radius:999px;background:var(--primary);color:var(--white);font-size:13px;font-weight:600;cursor:pointer}
.home-search-box button:active{background:var(--primary-dark)}
.home-quote{margin-top:12px;font-size:12px;color:#b0b8c4;font-style:italic;text-align:center;max-width:500px;line-height:1.5}
.home-quote-author{font-size:11px;color:#c0c4cc;display:inline-block;margin-top:2px}
/* ===== Home Rankings ===== */
.home-rankings{padding:8px 12px;display:flex;flex-direction:column;gap:10px}
.rank-block{background:var(--white);border-radius:var(--radius);padding:12px;border:1px solid var(--border);box-shadow:var(--shadow)}
.rank-block-hdr{display:flex;align-items:center;justify-content:space-between;padding-bottom:8px;border-bottom:2px solid #f0f0f0;margin-bottom:4px}
.rank-block-title{font-size:14px;font-weight:700;color:var(--text);white-space:nowrap}
.rank-block-tabs{display:flex;gap:2px;background:#f0f2f5;border-radius:5px;padding:2px}
.rank-tab{font-size:11px;padding:2px 9px;border-radius:4px;cursor:pointer;color:#909399;font-weight:500;transition:all .2s;user-select:none}
.rank-tab.active{background:var(--white);color:var(--primary);font-weight:600;box-shadow:0 1px 2px rgba(0,0,0,.06)}
.rank-item{display:flex;align-items:center;gap:7px;padding:5px 6px;border-radius:6px;cursor:pointer;transition:background .15s}
.rank-item:active{background:#f0f5ff}
.rank-idx{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#909399;background:#f0f0f0;flex-shrink:0}
.rank-idx.top3{background:var(--primary);color:var(--white);font-size:12px}
.rank-name{flex:1;min-width:0;font-size:13px;font-weight:500;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rank-cnt{font-size:11px;color:#c0c4cc;white-space:nowrap;flex-shrink:0}
.rank-expand{text-align:center;padding:5px;margin-top:2px;font-size:12px;color:var(--primary);cursor:pointer;border-radius:5px;user-select:none}
.rank-expand:active{background:#ecf5ff}
.rank-block-ftr{margin-top:6px;padding-top:6px;border-top:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;font-size:10px;color:#c0c4cc}
.ftr-time{font-family:monospace;font-size:9px}
/* ===== Layout ===== */
.app{max-width:100%;margin:0 auto;padding-bottom:calc(20px + var(--safe-bottom))}
.header{position:sticky;top:0;z-index:50;background:var(--white);border-bottom:1px solid var(--border);padding:8px 12px}
.header-row{display:flex;align-items:center;gap:10px}
.header-title{font-size:18px;font-weight:700;color:var(--primary);flex-shrink:0}
.header-title-link{text-decoration:none;flex-shrink:0;display:flex;align-items:center}
.header-logo-img{max-width:160px;max-height:36px;width:auto;height:auto;object-fit:contain;display:block}
.header-actions{margin-left:auto;display:flex;gap:6px;align-items:center}
/* ===== Search Bar ===== */
.search-wrap{flex:1;display:flex;border:1px solid var(--border);border-radius:18px;overflow:hidden;background:var(--bg);transition:border-color .2s}
.search-wrap:focus-within{border-color:var(--primary);background:var(--white)}
.search-wrap input{flex:1;height:36px;border:none;padding:0 14px;font-size:14px;outline:none;background:transparent}
.search-wrap button{flex-shrink:0;height:28px;margin:4px;padding:0 18px;border:none;border-radius:999px;background:var(--primary);color:var(--white);font-size:13px;font-weight:600;cursor:pointer;transition:background .2s}
.search-wrap button:active{background:var(--primary-dark)}
.search-wrap button:disabled{opacity:.5}
/* ===== Footer ===== */
.site-footer{margin-top:30px;padding:16px 12px 24px;background:#f9fafb;border-top:1px solid var(--border)}
.footer-inner{max-width:500px;margin:0 auto;font-size:11px;line-height:1.8;color:#909399;text-align:center;white-space:pre-line}
.footer-actions{display:flex;justify-content:center;gap:10px;margin-top:12px;flex-wrap:wrap}
.footer-btn{padding:8px 20px;border:1px solid var(--border);border-radius:8px;background:var(--white);color:var(--text);font-size:13px;cursor:pointer;transition:all .2s}
.footer-btn:active{background:var(--primary-light);border-color:var(--primary);color:var(--primary)}
/* ===== Info Bar ===== */
.info-bar{display:flex;align-items:center;gap:8px;padding:10px 12px 0;font-size:12px;color:var(--text2);flex-wrap:wrap}
.info-bar .count{font-weight:600;color:var(--text)}
.info-bar .time{font-family:monospace;background:#f4f4f5;padding:1px 6px;border-radius:4px}
.info-bar .badge-err{background:#fef0f0;color:#f56c6c;padding:1px 6px;border-radius:4px}
/* ===== Loading ===== */
.loading{padding:24px 12px;text-align:center;font-size:13px;color:var(--text2)}
.loading-bar{width:100%;height:3px;background:#e8e8e8;border-radius:2px;overflow:hidden;margin-top:8px}
.loading-bar-inner{height:100%;background:linear-gradient(90deg,var(--primary),#67c23a);border-radius:2px;transition:width .3s ease;width:0%}
/* ===== Tabs ===== */
.tabs{display:flex;gap:4px;padding:8px 12px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tab{flex-shrink:0;padding:5px 12px;border-radius:16px;font-size:12px;color:#606266;background:#f0f2f5;cursor:pointer;white-space:nowrap;transition:all .2s;user-select:none}
.tab:active{transform:scale(.95)}
.tab.active{background:var(--primary-light);color:var(--primary);font-weight:600}
/* ===== Results ===== */
.results{display:flex;flex-direction:column;gap:10px;padding:8px 12px}
.empty{padding:40px 12px;text-align:center;color:var(--text2);font-size:14px}
/* ===== Card ===== */
.card{display:flex;gap:10px;background:var(--white);border-radius:var(--radius);padding:10px;border:1px solid var(--border);transition:border-color .2s}
.card:active{border-color:#c0c4cc}
.card-cover{flex-shrink:0;width:90px;height:120px;border-radius:8px;overflow:hidden;background:var(--bg);position:relative}
.card-cover img{width:100%;height:100%;object-fit:cover}
.card-cover .placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:linear-gradient(135deg,#667eea,#764ba2);color:rgba(255,255,255,.6)}
.card-cover .tag{position:absolute;bottom:3px;left:3px;padding:1px 5px;border-radius:3px;color:#fff;font-size:10px;font-weight:600;backdrop-filter:blur(2px)}
.card-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.card-title{font-size:14px;font-weight:700;color:var(--text);line-height:1.3;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
.card-meta{font-size:11px;color:var(--text2);display:flex;align-items:center;gap:8px}
.card-meta .size{color:#67c23a}
.card-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:2px}
.card-tags span{font-size:10px;padding:1px 6px;border-radius:4px;background:#ecf5ff;color:#409eff;white-space:nowrap}
.card-tags .quality{background:#fef0f0;color:#e74c3c}
.card-actions{margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:6px}
.card-source{font-size:10px;color:var(--text2);background:#f4f4f5;padding:1px 6px;border-radius:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}
.card-btn{padding:4px 10px;border:none;border-radius:6px;background:var(--primary);color:var(--white);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background .2s}
.card-btn:active{background:var(--primary-dark)}
.card-btn:disabled{opacity:.5}
/* ===== Toast ===== */
.toast{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,.75);color:#fff;padding:10px 20px;border-radius:8px;font-size:14px;z-index:200;pointer-events:none;opacity:0;transition:opacity .3s}
.toast.show{opacity:1}
.toast.error{background:rgba(245,108,108,.9)}
/* ===== Overlay / Modal ===== */
.overlay{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;padding:16px;animation:fadeIn .2s}
.modal{background:var(--white);border-radius:14px;width:100%;max-width:420px;max-height:90vh;overflow-y:auto;padding:0;animation:slideUp .25s}
.modal-hdr{padding:14px 16px;border-bottom:1px solid var(--border);font-size:15px;font-weight:700;color:var(--text)}
.modal-body{padding:14px 16px}
.modal-ftr{padding:10px 16px;border-top:1px solid var(--border);display:flex;gap:8px;justify-content:flex-end}
.modal-ftr button{height:36px;padding:0 16px;border:none;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer}
.modal-ftr .btn-close{background:#f4f4f5;color:#606266}
.modal-ftr .btn-disclaimer{background:#fdf6ec;color:#d46b08;margin-right:auto}
.modal-ftr .btn-primary{background:var(--primary);color:var(--white)}
.modal-ftr .btn-primary:active{background:var(--primary-dark)}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes slideUp{from{transform:translateY(40px);opacity:0}to{transform:translateY(0);opacity:1}}
/* ===== Share Modal ===== */
.share-section{display:flex;flex-direction:column;gap:10px}
.share-row{display:flex;gap:8px}
.share-row input{flex:1;height:36px;border:1px solid var(--border);border-radius:6px;padding:0 10px;font-size:13px;outline:none;background:var(--bg);color:var(--text)}
.share-row input:focus{border-color:var(--primary)}
.share-row .copy-btn{height:36px;padding:0 12px;border:none;border-radius:6px;background:var(--primary);color:var(--white);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.share-pwd{display:flex;align-items:center;gap:6px;font-size:13px}
.share-pwd .pwd-tag{padding:2px 8px;background:#fdf6ec;color:#e6a23c;border-radius:4px;font-weight:700}
.share-pwd .pwd-hint{font-size:11px;color:var(--text2)}
.share-tip{padding:8px 10px;background:#fdf6ec;border-radius:6px;font-size:12px;line-height:1.5;color:#d46b08;display:flex;gap:6px;align-items:flex-start}
.share-tip .warn-icon{font-size:18px;line-height:1.5;flex-shrink:0}
.share-tip .tip-text{flex:1;min-width:0}
.share-tip strong{font-weight:700}
.warning-box{background:#fff2f0;border:1px solid #ffccc7;border-radius:8px;padding:8px 10px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.warning-item{margin:0;font-size:12px;line-height:1.8;font-weight:700;white-space:nowrap}
.warning-item:nth-child(odd){color:#cf1322}
.warning-item:nth-child(even){color:#d46b08}
.warning-item:last-child{color:#b71c1c;font-size:13px}
.share-qr{display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px}
.share-qr canvas{border-radius:8px}
.share-qr .qr-label{font-size:12px;font-weight:600;color:var(--primary)}
.share-qr .qr-sub{font-size:11px;color:var(--text2)}
.share-disclaimer{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:10px;padding:8px 10px;background:#fdf6ec;border-radius:6px;font-size:12px;color:#d46b08;flex-wrap:wrap}
/* ===== Login Modal ===== */
.login-form{display:flex;flex-direction:column;gap:12px}
.login-form input{height:40px;border:1px solid var(--border);border-radius:8px;padding:0 12px;font-size:14px;outline:none}
.login-form input:focus{border-color:var(--primary)}
.login-form .login-btn{height:40px;border:none;border-radius:8px;background:var(--primary);color:var(--white);font-size:14px;font-weight:600;cursor:pointer;transition:background .2s}
.login-form .login-btn:active{background:var(--primary-dark)}
.login-form .login-btn:disabled{opacity:.5}
.login-form .login-err{font-size:12px;color:#f56c6c;text-align:center}
/* ===== Progress Steps ===== */
.steps{display:flex;flex-direction:column;gap:10px;padding:8px 0}
.step{display:flex;align-items:flex-start;gap:10px;opacity:.4;transition:opacity .3s}
.step.active{opacity:1}
.step.done{opacity:.7}
.step-dot{flex-shrink:0;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;background:#e4e7ed;color:#909399}
.step.active .step-dot{background:var(--primary);color:#fff;box-shadow:0 0 0 3px rgba(64,158,255,.2)}
.step.done .step-dot{background:#67c23a;color:#fff}
.step-body{flex:1;padding-top:3px;display:flex;align-items:center;gap:8px}
.step-title{font-size:13px;color:var(--text);font-weight:500}
.step-status{font-size:11px;padding:1px 7px;border-radius:10px;white-space:nowrap}
.step-status.doing{background:#ecf5ff;color:var(--primary)}
.step-status.done{background:#f0f9eb;color:#67c23a}
.step-status.wait{background:#f4f4f5;color:#c0c4cc}
.error-alert{padding:12px 16px;background:#fef0f0;border:1px solid #fde2e2;border-radius:8px;display:flex;align-items:center;gap:8px;font-size:14px;color:#f56c6c}
/* ===== User Badge ===== */
.user-badge{font-size:12px;color:var(--primary);font-weight:600;white-space:nowrap}
.login-btn-small{height:30px;padding:0 10px;border:none;border-radius:6px;background:var(--primary-light);color:var(--primary);font-size:12px;font-weight:600;cursor:pointer}
.logout-btn-small{height:30px;padding:0 8px;border:none;border-radius:6px;background:transparent;color:var(--text2);font-size:12px;cursor:pointer}
</style>
</head> </head>
<body> <body>
<div class="app" id="app"> <div class="app" id="app">
@@ -327,592 +148,8 @@
<!-- Toast --> <!-- Toast -->
<div class="toast" id="toast"></div> <div class="toast" id="toast"></div>
<script> <script src="/h5/qrcode.min.js"></script>
// ===== Anime keywords for categorization ===== <script src="/h5/app.js"></script>
const ANIME_KWS=['仙逆','凡人修仙传','斗破苍穹','斗破','盘龙','完美世界','一念永恒','妖神记','星辰变','遮天','神墓','吞噬星空','武动乾坤','大主宰','全职高手','鬼灭之刃','海贼王','火影忍者','死神','龙珠','进击的巨人','咒术回战','一人之下','狐妖小红娘','魔道祖师','天官赐福','时光代理人','大王饶命','斗罗大陆','绝世唐门','不良人','秦时明月','全职法师','牧神记','三体','灵笼','雾山五行','凡人','仙王的日常生活','百妖谱','眷思量','镖人','伍六七','刺客伍六七','葬送的芙莉莲','间谍过家家']
// ===== Quotes =====
const QUOTES=['学而时习之,不亦说乎。','温故而知新,可以为师矣。','三人行,必有我师焉。','学而不思则罔,思而不学则殆。','博学之,审问之,慎思之,明辨之,笃行之。','千里之行,始于足下。','不积跬步,无以至千里。','知之为知之,不知为不知,是知也。','工欲善其事,必先利其器。','玉不琢,不成器;人不学,不知道。','学以致用,知行合一。','学海无涯,勤作舟。','书山有路,勤为径。','宝剑锋从磨砺出,梅花香自苦寒来。','锲而不舍,金石可镂。','业精于勤,荒于嬉。','读书破万卷,下笔如有神。','路漫漫其修远兮,吾将上下而求索。','采菊东篱下,悠然见南山。','海内存知己,天涯若比邻。','长风破浪会有时,直挂云帆济沧海。','会当凌绝顶,一览众山小。','山重水复疑无路,柳暗花明又一村。']
// ===== Home Page =====
function homeSearch(){
const q=document.getElementById('homeSearchInput').value.trim()
if(q)doSearchFromHome(q)
}
function doSearchFromHome(q){
document.getElementById('homePage').style.display='none'
document.getElementById('searchView').style.display='block'
document.getElementById('searchInput').value=q
window.history.replaceState({},'','/h5?q='+encodeURIComponent(q))
doSearch()
}
function renderHomePage(data){
fetch("/api/site-config").then(r=>r.json()).then(cfg=>{
// 显示 Logo优先图片其次文字
var logoEl=document.getElementById("homeLogo");
var headerEl=document.getElementById("headerTitle");
if(cfg.site_logo){
logoEl.innerHTML='<img src="'+cfg.site_logo+'" class="home-logo-img" alt="logo" />';
logoEl.style.display="";
headerEl.innerHTML='<img src="'+cfg.site_logo+'" class="header-logo-img" alt="logo" />';
headerEl.style.display="";
}else if(cfg.site_name){
logoEl.textContent=cfg.site_name;
logoEl.style.display="";
headerEl.textContent=cfg.site_name;
headerEl.style.display="";
}else{
logoEl.textContent="CloudSearch";
logoEl.style.display="";
headerEl.textContent="CloudSearch";
headerEl.style.display="";
}
if(cfg.site_disclaimer){
document.getElementById("footerContent").innerHTML=cfg.site_disclaimer.replace(/\n/g,'<br>');
document.getElementById("siteFooter").style.display="block";
}
}).catch(()=>{})
const categories=data.categories||[]
const fetchedAt=data.fetchedAt||''
// Quote
fetch('https://v1.hitokoto.cn/').then(r=>r.json()).then(d=>{
document.getElementById('homeQuote').textContent='「 '+d.hitokoto+' 」'
document.getElementById('homeQuoteAuthor').textContent='---'+(d.from_who||d.from||'')
}).catch(()=>{
document.getElementById('homeQuote').textContent='「 学而时习之,不亦说乎。 」'
document.getElementById('homeQuoteAuthor').textContent='---孔子'
})
// Store expanded state per category
window.__expanded=window.__expanded||{}
window.__activeTab=window.__activeTab||{}
const el=document.getElementById('homeRankings')
let html=''
for(const cat of categories){
const icons={movie:'🎬',tv:'📺',western_movie:'🎥',western:'🌍',donghua:'🐉',global_anime:'🌐',variety:'🎤',niche:'💎',hotsite:'🏆'}
const icon=icons[cat.category]||'📋'
const key=cat.category
if(!window.__activeTab[key])window.__activeTab[key]='hot'
html+='<div class="rank-block">'
html+='<div class="rank-block-hdr">'+
'<span class="rank-block-title">'+icon+' '+cat.label+'</span>'+
'<div class="rank-block-tabs" id="rtabs-'+key+'">'+
'<span class="rank-tab'+(window.__activeTab[key]==='hot'?' active':'')+'" onclick="switchRankTab(\''+key+'\',\'hot\')">热榜</span>'+
'<span class="rank-tab'+(window.__activeTab[key]==='newest'?' active':'')+'" onclick="switchRankTab(\''+key+'\',\'newest\')">最新</span>'+
'</div>'+
'</div>'
html+='<div class="rank-block-items" id="ritems-'+key+'" data-hot=\''+JSON.stringify({items:cat.hot||[]}).replace(/'/g,"&#39;")+'\' data-newest=\''+JSON.stringify({items:cat.newest||[]}).replace(/'/g,"&#39;")+'\'>'
const items=window.__activeTab[key]==='hot'?(cat.hot||[]):(cat.newest||[])
html+=renderRankItems(items,key,false)
html+='</div>'
// 数据来源
html+='<div class="rank-block-ftr">'+
'<span>'+(cat.category!=='hotsite'?'数据来源TMDB':'本站搜索数据')+'</span>'+
'<span class="ftr-time">'+fetchedAt+'</span>'+
'</div></div>'
}
el.innerHTML=html
}
function renderRankItems(items,key,expanded){
if(!items||items.length===0)return'<div style="padding:10px;text-align:center;color:#c0c4cc;font-size:12px">暂无数据</div>'
const limit=3
const show=expanded?items.length:Math.min(limit,items.length)
let html=items.slice(0,show).map((item,i)=>{
const c=i<3?' rank-idx top3':' rank-idx'
return '<div class="rank-item" onclick="doSearchFromHome(\''+item.keyword.replace(/'/g,"\\'")+'\')">'+
'<span class="'+c+'">'+(i+1)+'</span>'+
'<span class="rank-name">'+item.keyword+'</span>'+
'<span class="rank-cnt">'+(item.rating?'⭐'+item.rating:item.searchCount)+'</span>'+
'</div>'
}).join('')
if(items.length>limit&&!expanded){
html+='<div class="rank-expand" onclick="expandRank(\''+key+'\')">展开全部 ▼</div>'
}
return html
}
function expandRank(key){
const container=document.getElementById('ritems-'+key)
if(!container)return
const tab=window.__activeTab[key]||'hot'
const data=JSON.parse(tab==='hot'?container.dataset.hot:container.dataset.newest)
container.innerHTML=renderRankItems(data.items,key,true)
}
function switchRankTab(category,tab){
window.__activeTab[category]=tab
const tabsContainer=document.getElementById('rtabs-'+category)
if(tabsContainer){
tabsContainer.querySelectorAll('.rank-tab').forEach(t=>t.className='rank-tab')
tabsContainer.querySelector(tab==='hot'?'.rank-tab:first-child':'.rank-tab:last-child').className='rank-tab active'
}
const container=document.getElementById('ritems-'+category)
if(container){
const data=JSON.parse(tab==='hot'?container.dataset.hot:container.dataset.newest)
container.innerHTML=renderRankItems(data.items,category,false)
}
}
let userInfo = null
let allResults = []
let allChannels = []
let activeTab = ''
let currentSaveItem = null
const CLOUD_ICONS = {quark:'☁️',baidu:'🔵',aliyun:'🟠','115':'🟣',tianyi:'🔷','123pan':'🔴',uc:'🟡',xunlei:'🟢',pikpak:'🟤',magnet:'🧲',ed2k:'🔗',others:'📁'}
const CLOUD_LABELS = {quark:'夸克网盘',baidu:'百度网盘',aliyun:'阿里云盘','115':'115网盘',tianyi:'天翼云盘','123pan':'123云盘',uc:'UC网盘',xunlei:'迅雷云盘',pikpak:'PikPak',magnet:'磁力链接',ed2k:'电驴链接',others:'其他'}
const CLOUD_COLORS = {quark:'#07c160',baidu:'#4e6ef2',aliyun:'#ff6a00','115':'#9b59b6',tianyi:'#00a1d6','123pan':'#e74c3c',uc:'#f39c12',xunlei:'#2ecc71',pikpak:'#8e44ad',magnet:'#95a5a6',ed2k:'#7f8c8d',others:'#95a5a6'}
const CLOUD_ORDER = {quark:1,baidu:2,aliyun:3,'115':4,tianyi:5,'123pan':6,uc:7,xunlei:8,pikpak:9,magnet:10,ed2k:11,others:12}
// ===== Fetch helpers =====
function getToken(){return localStorage.getItem('h5_admin_token')}
function apiHeaders(){const h={'Content-Type':'application/json'};const t=getToken();if(t)h['Authorization']='Bearer '+t;return h}
// ===== Toast =====
let toastTimer
function showToast(msg,isError){
const el=document.getElementById('toast')
el.textContent=msg
el.className='toast show'+(isError?' error':'')
clearTimeout(toastTimer)
toastTimer=setTimeout(()=>el.className='toast',2000)
}
// ===== User =====
async function checkLogin(){
try{
const res=await fetch('/api/me',{headers:apiHeaders()})
if(res.ok){
const data=await res.json()
if(data.loggedIn){
userInfo=data
document.getElementById('userArea').innerHTML='<span class="user-badge">'+data.username+'</span><button class="logout-btn-small" onclick="logout()">退出</button>'
}
}
}catch(e){}
}
function logout(){
localStorage.removeItem('h5_admin_token')
userInfo=null
document.getElementById('userArea').innerHTML='<button class="login-btn-small" onclick="showLogin()">登录</button>'
showToast('已退出')
}
function showLogin(){
document.getElementById('loginErr').textContent=''
document.getElementById('loginUser').value=''
document.getElementById('loginPass').value=''
document.getElementById('loginModal').style.display='block'
document.getElementById('overlay').style.display='block'
}
function closeLogin(){
document.getElementById('loginModal').style.display='none'
document.getElementById('overlay').style.display='none'
}
async function handleLogin(){
const user=document.getElementById('loginUser').value.trim()
const pass=document.getElementById('loginPass').value
if(!user||!pass){showToast('请输入用户名和密码',true);return}
const btn=document.getElementById('loginBtn')
btn.disabled=true;btn.textContent='登录中...'
try{
const res=await fetch('/api/admin/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:user,password:pass})})
if(res.ok){
const data=await res.json()
localStorage.setItem('h5_admin_token',data.token)
userInfo={username:user}
document.getElementById('userArea').innerHTML='<span class="user-badge">'+user+'</span><button class="logout-btn-small" onclick="logout()">退出</button>'
closeLogin()
showToast('登录成功')
}else{
const err=await res.json().catch(()=>({}))
document.getElementById('loginErr').textContent=err.error||'登录失败'
}
}catch(e){
document.getElementById('loginErr').textContent='网络错误'
}finally{
btn.disabled=false;btn.textContent='登录'
}
}
// ===== Search =====
function handleKeydown(e){if(e.key==='Enter')doSearch()}
let searchTimer
function doSearch(){
const q=document.getElementById('searchInput').value.trim()
if(!q)return
// Update URL
window.history.replaceState({},'','/h5?q='+encodeURIComponent(q))
// Show loading
document.getElementById('results').innerHTML=''
document.getElementById('tabs').style.display='none'
document.getElementById('infoBar').style.display='none'
document.getElementById('loading').style.display='block'
document.getElementById('loadingText').textContent='🔍 正在搜索中...'
document.getElementById('searchBtn').disabled=true
let progress=0
const bar=document.getElementById('loadingBar')
const progressTimer=setInterval(()=>{
if(progress<60)progress+=1+Math.random()*3
else if(progress<85)progress+=0.5+Math.random()
bar.style.width=progress+'%'
},200)
// Use streaming search for live updates
streamSearch(q,progressTimer,bar)
}
async function streamSearch(q,progressTimer,bar){
const startTime=Date.now()
try{
const response=await fetch('/api/query',{method:'POST',headers:apiHeaders(),body:JSON.stringify({q})})
if(!response.ok)throw new Error('搜索失败 ('+response.status+')')
const reader=response.body.getReader()
const decoder=new TextDecoder()
let buffer=''
let allItems=[]
let channels=[]
let totalCount=0
let filteredCount=0
while(true){
const {done,value}=await reader.read()
if(done)break
buffer+=decoder.decode(value,{stream:true})
const lines=buffer.split('\n')
buffer=lines.pop()||''
for(const line of lines){
if(!line.trim())continue
try{
const msg=JSON.parse(line)
if(msg.type==='stats'){
totalCount=msg.total||0
filteredCount=msg.filtered||0
document.getElementById('loadingText').textContent='🔍 搜索到 '+totalCount+' 条,正在验证...'
}else if(msg.type==='result'){
if(msg.valid&&msg.id){
allItems.push(msg.id)
}
}else if(msg.type==='complete'){
const results=msg.results||[]
channels=msg.channels||[]
clearInterval(progressTimer)
bar.style.width='100%'
setTimeout(()=>renderResults(results,channels,totalCount,filteredCount,Date.now()-startTime),300)
return
}
}catch(e){}
}
}
}catch(e){
clearInterval(progressTimer)
document.getElementById('loading').style.display='none'
document.getElementById('searchBtn').disabled=false
document.getElementById('results').innerHTML='<div class="empty">搜索失败:'+e.message+'</div>'
}
}
// ===== Render =====
function renderResults(results,channels,totalCount,filteredCount,time){
document.getElementById('loading').style.display='none'
document.getElementById('searchBtn').disabled=false
allResults=results
allChannels=channels||[]
// Info bar
if(totalCount>0){
document.getElementById('infoBar').style.display='flex'
document.getElementById('infoCount').textContent='已为您挑选到最符合 '+totalCount+' 条结果'
document.getElementById('infoTime').textContent='⏱ '+time+'ms'
if(filteredCount>0)document.getElementById('infoFiltered').textContent='❌ 失效 '+filteredCount
else document.getElementById('infoFiltered').textContent=''
}else{
document.getElementById('infoBar').style.display='none'
}
// Build tabs
const tabsEl=document.getElementById('tabs')
tabsEl.innerHTML=''
const typeCounts={}
for(const r of results){const ct=r.cloud_type||'others';typeCounts[ct]=(typeCounts[ct]||0)+1}
const sorted=Object.keys(typeCounts).sort((a,b)=>(CLOUD_ORDER[a]||99)-(CLOUD_ORDER[b]||99))
// "全部" tab
const allTab=document.createElement('div')
allTab.className='tab active'
allTab.textContent='📋 全部 ('+results.length+')'
allTab.onclick=()=>{setActiveTab('');renderCardList(results)}
tabsEl.appendChild(allTab)
for(const ct of sorted){
const tab=document.createElement('div')
tab.className='tab'
tab.textContent=(CLOUD_ICONS[ct]||'📁')+' '+(CLOUD_LABELS[ct]||ct)+' ('+typeCounts[ct]+')'
tab.onclick=()=>{setActiveTab(ct);renderCardList(results.filter(r=>(r.cloud_type||'others')===ct))}
tabsEl.appendChild(tab)
}
tabsEl.style.display=results.length>0?'flex':'none'
activeTab=''
// Render cards
renderCardList(results)
}
function setActiveTab(ct){
activeTab=ct
document.querySelectorAll('.tab').forEach((t,i)=>{
const isAll=i===0&&!ct
const active=i>0&&ct&&t.textContent.includes(CLOUD_LABELS[ct])
t.className='tab'+(active||isAll?' active':'')
})
}
function renderCardList(items){
const el=document.getElementById('results')
if(items.length===0){
el.innerHTML='<div class="empty">暂无结果</div>'
return
}
el.innerHTML=items.map((item,idx)=>{
const coverHtml=item.cover
? '<img src="'+escapeHtml(item.cover)+'" alt="" onerror="this.parentElement.innerHTML=\'<div class=placeholder>'+escapeHtml(CLOUD_ICONS[item.cloud_type||'others'])+'</div>\'" loading="lazy" />'
: '<div class="placeholder">'+escapeHtml(CLOUD_ICONS[item.cloud_type||'others'])+'</div>'
const cloudLabel=CLOUD_LABELS[item.cloud_type]||item.cloud_type||''
const cloudColor=CLOUD_COLORS[item.cloud_type]||'#95a5a6'
const tags=extractTags(item.title||'')
const cleanTitle=(item.title||'').replace(/【[^】]+】/g,'').trim()
const relativeTime=formatTime(item.update_time||item.datetime||'')
return '<div class="card" onclick="saveItem('+idx+')">'+
'<div class="card-cover">'+coverHtml+'<span class="tag" style="background:'+cloudColor+'">'+cloudLabel+'</span></div>'+
'<div class="card-body">'+
'<div class="card-title">'+escapeHtml(cleanTitle)+'</div>'+
'<div class="card-meta"><span>🕐 '+relativeTime+'</span>'+(item.file_size?'<span class="size">📦 '+escapeHtml(item.file_size)+'</span>':'')+'</div>'+
(tags.length>0?'<div class="card-tags">'+tags.map(t=>'<span'+(isQualityTag(t)?' class="quality"':'')+'>'+escapeHtml(t)+'</span>').join('')+'</div>':'')+
'<div class="card-actions">'+
'<span class="card-source">'+(item.source?escapeHtml(item.source):'网盘')+'</span>'+
'<button class="card-btn" onclick="event.stopPropagation();saveItem('+idx+')">🔗 获取分享链接</button>'+
'</div>'+
'</div>'+
'</div>'
}).join('')
// Store items for save reference
window.__h5Results=items
}
function escapeHtml(s){if(!s)return '';return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;')}
function extractTags(title){
const tags=[]
// Quality tags
const quality=['4K','1080P','2160P','720P','480P','HDR','HDR10','BluRay','REMUX','HEVC','x264','x265','WEB-DL','WEBRip']
for(const q of quality){if(title.includes(q)&&!tags.includes(q))tags.push(q)}
const kw=['杜比视界','杜比全景声','高码率','内封简繁英字幕','内嵌字幕','中文字幕','中英字幕']
for(const k of kw){if(title.includes(k)&&!tags.includes(k))tags.push(k)}
return tags.slice(0,6)
}
function isQualityTag(t){const q=['4K','1080P','2160P','720P','480P','HDR','HDR10','BluRay','REMUX','HEVC','x264','x265','臻彩','高清','WEB-DL','WEBRip'];return q.includes(t)}
function formatTime(s){
if(!s)return ''
const d=new Date(s)
if(isNaN(d.getTime()))return s.slice(0,10)
const diff=Date.now()-d.getTime()
if(diff<0)return s.slice(0,10)
const mins=Math.floor(diff/60000)
if(mins<60)return mins<=1?'刚刚':mins+' 分钟前'
const hours=Math.floor(mins/60)
if(hours<24)return hours+' 小时前'
const days=Math.floor(hours/24)
if(days<30)return days+' 天前'
return Math.floor(days/30)+' 个月前'
}
// ===== Save / Share =====
function saveItem(idx){
const items=window.__h5Results||[]
currentSaveItem=items[idx]
if(!currentSaveItem)return
document.getElementById('progressSteps').style.display='block'
document.getElementById('shareContent').style.display='none'
document.getElementById('saveError').style.display='none'
document.getElementById('copyBtn2').style.display='none'
const title=(currentSaveItem.title||'').replace(/【[^】]+】/g,'').trim()||'资源'
document.getElementById('shareTitle').textContent=title
// Show modal
document.getElementById('overlay').style.display='block'
document.getElementById('shareModal').style.display='block'
// Reset steps
resetSteps()
advanceStep(1)
// Call save API
doSave()
}
async function doSave(){
try{
const res=await fetch('/api/save',{method:'POST',headers:apiHeaders(),body:JSON.stringify({type:'search',source:currentSaveItem,target_cloud:currentSaveItem.cloud_type||'quark'})})
const data=await res.json()
if(!data.success){
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent=data.message||data.error||'保存失败'
return
}
// Step 2
advanceStep(2)
await sleep(500)
// Step 3
advanceStep(3)
await sleep(300)
if(data.share_url){
advanceStep(4)
await sleep(200)
showShareResult(data)
}else{
advanceStep(4)
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent='生成分享链接失败'
}
}catch(e){
document.getElementById('progressSteps').style.display='none'
document.getElementById('saveError').style.display='flex'
document.getElementById('saveError').textContent=e.message||'保存请求失败'
}
}
function showShareResult(data){
document.getElementById('progressSteps').style.display='none'
document.getElementById('shareContent').style.display='block'
const link=data.share_url
document.getElementById('shareLinkInput').value=link
const diskLabel=CLOUD_LABELS[currentSaveItem.cloud_type]||'夸克网盘'
document.getElementById('qrLabel').textContent=diskLabel+' APP扫码转存'
// Generate QR
const qrContainer=document.getElementById('qrContainer')
qrContainer.innerHTML=''
new QRCode(qrContainer,{text:link,width:140,height:140})
// Password
const pwd=data.share_pwd||data.sharePwd||''
if(pwd){
document.getElementById('sharePwdRow').style.display='flex'
document.getElementById('sharePwdTag').textContent=pwd
}else{
document.getElementById('sharePwdRow').style.display='none'
}
document.getElementById('copyBtn2').style.display='inline-block'
}
function resetSteps(){
for(let i=1;i<=3;i++){
const el=document.getElementById('step'+i)
el.className='step'
el.querySelector('.step-dot').innerHTML='<span>'+i+'</span>'
el.querySelector('.step-status').textContent='等待中'
el.querySelector('.step-status').className='step-status wait'
}
}
function advanceStep(n){
for(let i=1;i<=3;i++){
const el=document.getElementById('step'+i)
if(i<n){
el.className='step done'
el.querySelector('.step-dot').innerHTML='<span class="step-check">✓</span>'
el.querySelector('.step-status').textContent='已完成'
el.querySelector('.step-status').className='step-status done'
}else if(i===n){
el.className='step active'
el.querySelector('.step-dot').innerHTML='<span>'+i+'</span>'
const titles=['正在转存到','正在重命名文件(防和谐)','正在生成分享链接']
el.querySelector('.step-title').textContent=titles[i-1]+'...'
el.querySelector('.step-status').textContent='进行中'
el.querySelector('.step-status').className='step-status doing'
}
}
}
function sleep(ms){return new Promise(r=>setTimeout(r,ms))}
function copyShareLink(){
const input=document.getElementById('shareLinkInput')
if(!input.value)return
if(navigator.clipboard&&navigator.clipboard.writeText){
navigator.clipboard.writeText(input.value).then(()=>showToast('链接已复制')).catch(()=>fallbackCopy(input.value))
}else{
fallbackCopy(input.value)
}
}
function fallbackCopy(text){
const ta=document.createElement('textarea')
ta.value=text;ta.style.position='fixed';ta.style.left='-9999px';document.body.appendChild(ta)
ta.select()
try{document.execCommand('copy');showToast('链接已复制')}catch{showToast('复制失败',true)}
document.body.removeChild(ta)
}
function openDisclaimer(){
window.open('/disclaimer/','_blank')
}
function closeModal(){
document.getElementById('overlay').style.display='none'
document.getElementById('shareModal').style.display='none'
document.getElementById('loginModal').style.display='none'
}
// ===== Init =====
checkLogin()
// Add Enter key handler for home search
document.getElementById('homeSearchInput').addEventListener('keydown',function(e){if(e.key==='Enter')homeSearch()})
// Also add for search view input
document.getElementById('searchInput').addEventListener('keydown',function(e){if(e.key==='Enter')doSearch()})
// Fetch home page data
fetch('/api/rankings/categorized').then(r=>r.json()).then(data=>{
renderHomePage(data)
}).catch(()=>{
document.getElementById('homeQuote').textContent='「 学而时习之,不亦说乎。 」'
document.getElementById('homeQuoteAuthor').textContent='---孔子'
})
// Check URL for query
const params=new URLSearchParams(window.location.search)
const q=params.get('q')
if(q){
document.getElementById('homePage').style.display='none'
document.getElementById('searchView').style.display='block'
document.getElementById('searchInput').value=q
doSearch()
}
</script>
</body>
<!-- Footer --> <!-- Footer -->
<div id="siteFooter" class="site-footer" style="display:none"> <div id="siteFooter" class="site-footer" style="display:none">
<div id="footerContent" class="footer-inner"></div> <div id="footerContent" class="footer-inner"></div>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,179 @@
/* ===== Dark Mode ===== */[data-theme="dark"] body { background:#1a1a1a;color:#e5e5e5 }[data-theme="dark"] .rank-block,[data-theme="dark"] .card,[data-theme="dark"] .modal,[data-theme="dark"] .header { background:#1f1f1f;border-color:#333 }[data-theme="dark"] input,[data-theme="dark"] .home-search-box,[data-theme="dark"] .search-wrap { background:#2a2a2a;color:#e5e5e5;border-color:#333 }[data-theme="dark"] .rank-block-title,[data-theme="dark"] .card-title,[data-theme="dark"] .rank-name,[data-theme="dark"] .modal-hdr { color:#e5e5e5 }[data-theme="dark"] .card-meta,[data-theme="dark"] .rank-cnt,[data-theme="dark"] .info-bar { color:#999 }[data-theme="dark"] .rank-tab,[data-theme="dark"] .tab { background:#333;color:#999 }[data-theme="dark"] .rank-tab.active,[data-theme="dark"] .tab.active { background:#409eff;color:#fff }[data-theme="dark"] .site-footer { background:#1a1a1a;border-color:#333;color:#999 }[data-theme="dark"] .rank-block-ftr { border-color:#333;color:#666 }[data-theme="dark"] .rank-idx { background:#333;color:#999 }[data-theme="dark"] .theme-btn { position:fixed;bottom:20px;right:20px;z-index:99;width:40px;height:40px;border-radius:50%;border:1px solid #555;background:#1f1f1f;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 8px rgba(0,0,0,.3) }
/* ===== Reset & Base ===== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:16px;-webkit-text-size-adjust:100%}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;background:#f5f5f5;color:#303133;min-height:100vh;overflow-x:hidden}
:root{--primary:#409eff;--primary-dark:#337ecc;--primary-light:rgba(64,158,255,0.08);--text:#303133;--text2:#909399;--border:#ebeef5;--bg:#f5f5f5;--white:#fff;--radius:10px;--shadow:0 1px 4px rgba(0,0,0,0.04);--safe-bottom:env(safe-area-inset-bottom,0px)}
a{color:var(--primary);text-decoration:none}
img{display:block;max-width:100%}
/* ===== Home Page ===== */
.home-page{padding-bottom:calc(30px + var(--safe-bottom))}
.home-hero{display:flex;flex-direction:column;align-items:center;padding:36px 16px 20px}
.home-logo{font-size:32px;font-weight:700;color:var(--primary);margin-bottom:20px;text-align:center}
.home-logo-img{max-width:360px;max-height:80px;width:auto;height:auto;object-fit:contain}
.home-search-box{display:flex;width:100%;max-width:500px;border:1px solid var(--border);border-radius:20px;overflow:hidden;background:var(--bg);transition:border-color .2s}
.home-search-box:focus-within{border-color:var(--primary);background:var(--white);box-shadow:0 0 0 3px rgba(64,158,255,.1)}
.home-search-box input{flex:1;height:40px;border:none;padding:0 14px;font-size:14px;outline:none;background:transparent}
.home-search-box button{flex-shrink:0;height:32px;margin:4px;padding:0 22px;border:none;border-radius:999px;background:var(--primary);color:var(--white);font-size:13px;font-weight:600;cursor:pointer}
.home-search-box button:active{background:var(--primary-dark)}
.home-quote{margin-top:12px;font-size:12px;color:#b0b8c4;font-style:italic;text-align:center;max-width:500px;line-height:1.5}
.home-quote-author{font-size:11px;color:#c0c4cc;display:inline-block;margin-top:2px}
/* ===== Home Rankings ===== */
.home-rankings{padding:8px 12px;display:flex;flex-direction:column;gap:10px}
.rank-block{background:var(--white);border-radius:var(--radius);padding:12px;border:1px solid var(--border);box-shadow:var(--shadow)}
.rank-block-hdr{display:flex;align-items:center;justify-content:space-between;padding-bottom:8px;border-bottom:2px solid #f0f0f0;margin-bottom:4px}
.rank-block-title{font-size:14px;font-weight:700;color:var(--text);white-space:nowrap}
.rank-block-tabs{display:flex;gap:2px;background:#f0f2f5;border-radius:5px;padding:2px}
.rank-tab{font-size:11px;padding:2px 9px;border-radius:4px;cursor:pointer;color:#909399;font-weight:500;transition:all .2s;user-select:none}
.rank-tab.active{background:var(--white);color:var(--primary);font-weight:600;box-shadow:0 1px 2px rgba(0,0,0,.06)}
.rank-item{display:flex;align-items:center;gap:7px;padding:5px 6px;border-radius:6px;cursor:pointer;transition:background .15s}
.rank-item:active{background:#f0f5ff}
.rank-idx{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#909399;background:#f0f0f0;flex-shrink:0}
.rank-idx.top3{background:var(--primary);color:var(--white);font-size:12px}
.rank-name{flex:1;min-width:0;font-size:13px;font-weight:500;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rank-cnt{font-size:11px;color:#c0c4cc;white-space:nowrap;flex-shrink:0}
.rank-expand{text-align:center;padding:5px;margin-top:2px;font-size:12px;color:var(--primary);cursor:pointer;border-radius:5px;user-select:none}
.rank-expand:active{background:#ecf5ff}
.rank-block-ftr{margin-top:6px;padding-top:6px;border-top:1px solid #f0f0f0;display:flex;align-items:center;justify-content:space-between;font-size:10px;color:#c0c4cc}
.ftr-time{font-family:monospace;font-size:9px}
/* ===== Layout ===== */
.app{max-width:100%;margin:0 auto;padding-bottom:calc(20px + var(--safe-bottom))}
.header{position:sticky;top:0;z-index:50;background:var(--white);border-bottom:1px solid var(--border);padding:8px 12px}
.header-row{display:flex;align-items:center;gap:10px}
.header-title{font-size:18px;font-weight:700;color:var(--primary);flex-shrink:0}
.header-title-link{text-decoration:none;flex-shrink:0;display:flex;align-items:center}
.header-logo-img{max-width:120px;max-height:28px;width:auto;height:auto;object-fit:contain;display:block}
.header-actions{margin-left:auto;display:flex;gap:6px;align-items:center}
/* ===== Search Bar ===== */
.search-wrap{flex:1;display:flex;border:1px solid var(--border);border-radius:18px;overflow:hidden;background:var(--bg);transition:border-color .2s}
.search-wrap:focus-within{border-color:var(--primary);background:var(--white)}
.search-wrap input{flex:1;height:36px;border:none;padding:0 14px;font-size:14px;outline:none;background:transparent}
.search-wrap button{flex-shrink:0;height:28px;margin:4px;padding:0 18px;border:none;border-radius:999px;background:var(--primary);color:var(--white);font-size:13px;font-weight:600;cursor:pointer;transition:background .2s}
.search-wrap button:active{background:var(--primary-dark)}
.search-wrap button:disabled{opacity:.5}
/* ===== Footer ===== */
.site-footer{margin-top:30px;padding:16px 12px 24px;background:#f9fafb;border-top:1px solid var(--border)}
.footer-inner{max-width:500px;margin:0 auto;font-size:11px;line-height:1.8;color:#909399;text-align:center;white-space:pre-line}
.footer-actions{display:flex;justify-content:center;gap:10px;margin-top:12px;flex-wrap:wrap}
.footer-btn{padding:8px 20px;border:1px solid var(--border);border-radius:8px;background:var(--white);color:var(--text);font-size:13px;cursor:pointer;transition:all .2s}
.footer-btn:active{background:var(--primary-light);border-color:var(--primary);color:var(--primary)}
/* ===== Info Bar ===== */
.info-bar{display:flex;align-items:center;gap:8px;padding:10px 12px 0;font-size:12px;color:var(--text2);flex-wrap:wrap}
.info-bar .count{font-weight:600;color:var(--text)}
.info-bar .time{font-family:monospace;background:#f4f4f5;padding:1px 6px;border-radius:4px}
.info-bar .badge-err{background:#fef0f0;color:#f56c6c;padding:1px 6px;border-radius:4px}
/* ===== Loading ===== */
.loading{padding:24px 12px;text-align:center;font-size:13px;color:var(--text2)}
.loading-bar{width:100%;height:3px;background:#e8e8e8;border-radius:2px;overflow:hidden;margin-top:8px}
.loading-bar-inner{height:100%;background:linear-gradient(90deg,var(--primary),#67c23a);border-radius:2px;transition:width .3s ease;width:0%}
/* ===== Tabs ===== */
.tabs{display:flex;gap:4px;padding:8px 12px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.tabs::-webkit-scrollbar{display:none}
.tab{flex-shrink:0;padding:5px 12px;border-radius:16px;font-size:12px;color:#606266;background:#f0f2f5;cursor:pointer;white-space:nowrap;transition:all .2s;user-select:none}
.tab:active{transform:scale(.95)}
.tab.active{background:var(--primary-light);color:var(--primary);font-weight:600}
/* ===== Results ===== */
.results{display:flex;flex-direction:column;gap:10px;padding:8px 12px}
.empty{padding:40px 12px;text-align:center;color:var(--text2);font-size:14px}
/* ===== Card ===== */
.card{display:flex;gap:10px;background:var(--white);border-radius:var(--radius);padding:10px;border:1px solid var(--border);transition:border-color .2s}
.card:active{border-color:#c0c4cc}
.card-cover{flex-shrink:0;width:90px;height:120px;border-radius:8px;overflow:hidden;background:var(--bg);position:relative}
.card-cover img{width:100%;height:100%;object-fit:cover}
.card-cover .placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:28px;background:linear-gradient(135deg,#667eea,#764ba2);color:rgba(255,255,255,.6)}
.card-cover .tag{position:absolute;bottom:3px;left:3px;padding:1px 5px;border-radius:3px;color:#fff;font-size:10px;font-weight:600;backdrop-filter:blur(2px)}
.card-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.card-title{font-size:14px;font-weight:700;color:var(--text);line-height:1.3;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
.card-meta{font-size:11px;color:var(--text2);display:flex;align-items:center;gap:8px}
.card-meta .size{color:#67c23a}
.card-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:2px}
.card-tags span{font-size:10px;padding:1px 6px;border-radius:4px;background:#ecf5ff;color:#409eff;white-space:nowrap}
.card-tags .quality{background:#fef0f0;color:#e74c3c}
.card-actions{margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:6px}
.card-source{font-size:10px;color:var(--text2);background:#f4f4f5;padding:1px 6px;border-radius:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}
.card-btn{padding:4px 10px;border:none;border-radius:6px;background:var(--primary);color:var(--white);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background .2s}
.card-btn:active{background:var(--primary-dark)}
.card-btn:disabled{opacity:.5}
/* ===== Toast ===== */
.toast{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:rgba(0,0,0,.75);color:#fff;padding:10px 20px;border-radius:8px;font-size:14px;z-index:200;pointer-events:none;opacity:0;transition:opacity .3s}
.toast.show{opacity:1}
.toast.error{background:rgba(245,108,108,.9)}
/* ===== Overlay / Modal ===== */
.overlay{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;padding:16px;animation:fadeIn .2s}
.modal{background:var(--white);border-radius:14px;width:100%;max-width:420px;max-height:90vh;overflow-y:auto;padding:0;animation:slideUp .25s}
.modal-hdr{padding:14px 16px;border-bottom:1px solid var(--border);font-size:15px;font-weight:700;color:var(--text)}
.modal-body{padding:14px 16px}
.modal-ftr{padding:10px 16px;border-top:1px solid var(--border);display:flex;gap:8px;justify-content:flex-end}
.modal-ftr button{height:36px;padding:0 16px;border:none;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer}
.modal-ftr .btn-close{background:#f4f4f5;color:#606266}
.modal-ftr .btn-disclaimer{background:#fdf6ec;color:#d46b08;margin-right:auto}
.modal-ftr .btn-primary{background:var(--primary);color:var(--white)}
.modal-ftr .btn-primary:active{background:var(--primary-dark)}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes slideUp{from{transform:translateY(40px);opacity:0}to{transform:translateY(0);opacity:1}}
/* ===== Share Modal ===== */
.share-section{display:flex;flex-direction:column;gap:10px}
.share-row{display:flex;gap:8px}
.share-row input{flex:1;height:36px;border:1px solid var(--border);border-radius:6px;padding:0 10px;font-size:13px;outline:none;background:var(--bg);color:var(--text)}
.share-row input:focus{border-color:var(--primary)}
.share-row .copy-btn{height:36px;padding:0 12px;border:none;border-radius:6px;background:var(--primary);color:var(--white);font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}
.share-pwd{display:flex;align-items:center;gap:6px;font-size:13px}
.share-pwd .pwd-tag{padding:2px 8px;background:#fdf6ec;color:#e6a23c;border-radius:4px;font-weight:700}
.share-pwd .pwd-hint{font-size:11px;color:var(--text2)}
.share-tip{padding:8px 10px;background:#fdf6ec;border-radius:6px;font-size:12px;line-height:1.5;color:#d46b08;display:flex;gap:6px;align-items:flex-start}
.share-tip .warn-icon{font-size:18px;line-height:1.5;flex-shrink:0}
.share-tip .tip-text{flex:1;min-width:0}
.share-tip strong{font-weight:700}
.warning-box{background:#fff2f0;border:1px solid #ffccc7;border-radius:8px;padding:8px 10px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.warning-item{margin:0;font-size:12px;line-height:1.8;font-weight:700;white-space:nowrap}
.warning-item:nth-child(odd){color:#cf1322}
.warning-item:nth-child(even){color:#d46b08}
.warning-item:last-child{color:#b71c1c;font-size:13px}
.share-qr{display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px}
.share-qr canvas{border-radius:8px}
.share-qr .qr-label{font-size:12px;font-weight:600;color:var(--primary)}
.share-qr .qr-sub{font-size:11px;color:var(--text2)}
.share-disclaimer{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:10px;padding:8px 10px;background:#fdf6ec;border-radius:6px;font-size:12px;color:#d46b08;flex-wrap:wrap}
/* ===== Login Modal ===== */
.login-form{display:flex;flex-direction:column;gap:12px}
.login-form input{height:40px;border:1px solid var(--border);border-radius:8px;padding:0 12px;font-size:14px;outline:none}
.login-form input:focus{border-color:var(--primary)}
.login-form .login-btn{height:40px;border:none;border-radius:8px;background:var(--primary);color:var(--white);font-size:14px;font-weight:600;cursor:pointer;transition:background .2s}
.login-form .login-btn:active{background:var(--primary-dark)}
.login-form .login-btn:disabled{opacity:.5}
.login-form .login-err{font-size:12px;color:#f56c6c;text-align:center}
/* ===== Progress Steps ===== */
.steps{display:flex;flex-direction:column;gap:10px;padding:8px 0}
.step{display:flex;align-items:flex-start;gap:10px;opacity:.4;transition:opacity .3s}
.step.active{opacity:1}
.step.done{opacity:.7}
.step-dot{flex-shrink:0;width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;background:#e4e7ed;color:#909399}
.step.active .step-dot{background:var(--primary);color:#fff;box-shadow:0 0 0 3px rgba(64,158,255,.2)}
.step.done .step-dot{background:#67c23a;color:#fff}
.step-body{flex:1;padding-top:3px;display:flex;align-items:center;gap:8px}
.step-title{font-size:13px;color:var(--text);font-weight:500}
.step-status{font-size:11px;padding:1px 7px;border-radius:10px;white-space:nowrap}
.step-status.doing{background:#ecf5ff;color:var(--primary)}
.step-status.done{background:#f0f9eb;color:#67c23a}
.step-status.wait{background:#f4f4f5;color:#c0c4cc}
.error-alert{padding:12px 16px;background:#fef0f0;border:1px solid #fde2e2;border-radius:8px;display:flex;align-items:center;gap:8px;font-size:14px;color:#f56c6c}
/* ===== User Badge ===== */
.user-badge{font-size:12px;color:var(--primary);font-weight:600;white-space:nowrap}
.login-btn-small{height:30px;padding:0 10px;border:none;border-radius:6px;background:var(--primary-light);color:var(--primary);font-size:12px;font-weight:600;cursor:pointer}
.logout-btn-small{height:30px;padding:0 8px;border:none;border-radius:6px;background:transparent;color:var(--text2);font-size:12px;cursor:pointer}

View File

@@ -21,7 +21,7 @@
} }
})(); })();
</script> </script>
<script type="module" crossorigin src="/assets/index-D_srC3bj.js"></script> <script type="module" crossorigin src="/assets/index-B3brQT6g.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Ekbe64zQ.css"> <link rel="stylesheet" crossorigin href="/assets/index-Ekbe64zQ.css">
</head> </head>
<body> <body>

View File

@@ -298,7 +298,7 @@ function seedSystemConfigs(db: Database.Database): void {
{ key: 'site_disclaimer', value: '本站为非盈利性个人站点所有资源仅供学习、研究使用版权归原作者所有。请于下载后24小时内删除切勿用于商业或非法用途。若侵犯了您的权益请联系我们邮箱3337598077@qq.com我们将及时处理。', description: '网站底部免责声明' }, { key: 'site_disclaimer', value: '本站为非盈利性个人站点所有资源仅供学习、研究使用版权归原作者所有。请于下载后24小时内删除切勿用于商业或非法用途。若侵犯了您的权益请联系我们邮箱3337598077@qq.com我们将及时处理。', description: '网站底部免责声明' },
{ key: 'site_marquee', value: '📢 欢迎使用CloudSearch所有资源仅供学习交流请于下载后24小时内删除', description: '搜索栏下方滚动通知文字(从右往左滚动显示)' }, { key: 'site_marquee', value: '📢 欢迎使用CloudSearch所有资源仅供学习交流请于下载后24小时内删除', description: '搜索栏下方滚动通知文字(从右往左滚动显示)' },
{ key: 'tmdb_api_token', value: '', description: 'TMDB API 读取令牌(用于增强豆瓣内容信息)' }, { key: 'tmdb_api_token', value: '', description: 'TMDB API 读取令牌(用于增强豆瓣内容信息)' },
{ key: 'ip_geo_api_url', value: 'https://cn.apihz.cn/api/ip/chaapi.php?id=10014356&key=ca7ccb3b9ca044dd993c8604bc9afd93&ip={ip}&td=0', description: 'IP 归属地查询接口({ip} 会被替换为实际IP' }, { key: 'ip_geo_api_url', value: '', description: 'IP 归属地查询接口({ip} 会被替换为实际IP,留空则禁用' },
{ key: 'ip_geo_api_key', value: '', description: 'IP 归属地备用 API Key留空使用默认' }, { key: 'ip_geo_api_key', value: '', description: 'IP 归属地备用 API Key留空使用默认' },
{ key: 'title_filter_rules', value: '', description: '搜索结果标题过滤规则(一行一条:纯文本直接移除 / 正则用/包围/' }, { key: 'title_filter_rules', value: '', description: '搜索结果标题过滤规则(一行一条:纯文本直接移除 / 正则用/包围/' },
{ key: 'timezone', value: 'Asia/Shanghai', description: '系统时区(如 Asia/Shanghai、America/New_York、UTC' }, { key: 'timezone', value: 'Asia/Shanghai', description: '系统时区(如 Asia/Shanghai、America/New_York、UTC' },

View File

@@ -125,7 +125,7 @@ export async function testProxyConnection(
proxyUrl: string, proxyUrl: string,
testUrl?: string testUrl?: string
): Promise<{ ok: boolean; latency: number; info: string }> { ): Promise<{ ok: boolean; latency: number; info: string }> {
const target = testUrl || 'https://www.baidu.com'; const target = testUrl || 'http://pansou:80';
const start = Date.now(); const start = Date.now();
try { try {
const res = await proxiedFetch(target, { const res = await proxiedFetch(target, {