// ==UserScript== // @name 加载日记 // @namespace resource-diary // @version 8.0.6 // @description 网页资源捕获工具、查看网页源代码 // @author DeepSeek // @match *://*/* // @license MIT // @icon https://static.vecteezy.com/system/resources/thumbnails/010/796/909/small/multiple-files-icon-with-outline-style-vector.jpg // @grant GM_download // @grant GM_addStyle // @grant unsafeWindow // ==/UserScript== (function(){ 'use strict'; if(!/^https?:$/.test(location.protocol))return; if(window.top!==window.self)return; if(window.ResourceDiary)return; const processedElements=new WeakSet(); const processedUrls=new Set(); const CONFIG=Object.freeze({ MAX_RESOURCES:600, MAX_URL_CACHE:2500, UPDATE_DELAY:120, BATCH_SIZE:60, DEBOUNCE_TIME:100, LAZY_LOAD_OFFSET:'120px', SCAN_INTERVAL:3000, ITEM_HEIGHT:80, FETCH_TIMEOUT:30000 }); const DANGEROUS_PROTOCOLS=new Set([ 'javascript:','data:text/html','data:text/javascript', 'vbscript:','mocha:','livescript:','about:','blob:javascript', 'file:','ftp:','telnet:','ssh:' ]); const ALLOWED_MIMES=new Set([ 'image/','audio/','video/','application/json', 'application/xml','text/plain','text/css','text/javascript', 'application/javascript','application/octet-stream' ]); const EXT_TO_TYPE=Object.freeze({ mp4:'mp4',webm:'webm',ogg:'ogg',ogv:'ogv',mov:'mov', avi:'avi',mkv:'mkv',flv:'flv',m3u8:'m3u8',mpd:'mpd', mp3:'mp3',wav:'wav',flac:'flac',aac:'aac',m4a:'m4a', wma:'wma',oga:'oga',weba:'weba',opus:'opus', jpg:'jpg',jpeg:'jpg',png:'png',gif:'gif',webp:'webp', svg:'svg',ico:'ico',bmp:'bmp',avif:'avif',jxl:'jxl', css:'stylesheet',js:'script',mjs:'script',json:'json', woff:'font',woff2:'font',ttf:'font',otf:'font',eot:'font' }); const MIME_TO_TYPE=Object.freeze({ 'video/mp4':'mp4','video/webm':'webm','video/ogg':'ogg', 'video/quicktime':'mov','video/x-matroska':'mkv', 'audio/mpeg':'mp3','audio/wav':'wav','audio/flac':'flac', 'audio/aac':'aac','audio/ogg':'oga','audio/webm':'weba', 'audio/opus':'opus', 'image/jpeg':'jpg','image/png':'png','image/gif':'gif', 'image/webp':'webp','image/svg+xml':'svg','image/avif':'avif', 'text/css':'stylesheet', 'application/javascript':'script','text/javascript':'script', 'application/json':'json','application/xml':'xml' }); const TYPE_COLORS=Object.freeze({ jpg:'#f43f5e',jpeg:'#f43f5e',png:'#a855f7',gif:'#f97316', webp:'#06b6d4',svg:'#f59e0b',ico:'#78716c',bmp:'#6b7280', avif:'#22c55e',jxl:'#3b82f6',image:'#6366f1', mp4:'#ef4444',webm:'#3b82f6',ogg:'#f59e0b',ogv:'#f59e0b', mov:'#8b5cf6',avi:'#78716c',mkv:'#6b7280',flv:'#e84c6a', m3u8:'#22c55e',mpd:'#06b6d4', mp3:'#5b7fff',wav:'#34a853',flac:'#fbbc05',aac:'#ea4335', m4a:'#9334e6',wma:'#5f6368',oga:'#ff6d01',weba:'#4285f4', opus:'#8b5cf6',audio:'#5b7fff', script:'#f59e0b',stylesheet:'#34a853',json:'#4285f4', xml:'#9aa0a6',font:'#9aa0a6', XHR:'#ea4335',fetch:'#ff6d01',datauri:'#6b7280',other:'#6366f1' }); const Icons={ box:``, file:``, image:``, video:``, audio:``, script:``, stylesheet:``, json:``, xml:``, font:``, wifi:``, download:``, play:``, pause:``, copy:``, close:``, folder:``, folderOpen:``, music:``, film:``, link:``, code:``, waveform:`` }; const OriginalAPIs={ xhrOpen:XMLHttpRequest.prototype.open, xhrSend:XMLHttpRequest.prototype.send, fetch:window.fetch, pushState:history.pushState, replaceState:history.replaceState }; const SecurityUtils={ urlCache:new Map(), maxCacheSize:1000, isSafeUrl(url){ if(!url||typeof url!=='string')return false; const cached=this.urlCache.get(url); if(cached!==undefined)return cached; if(this.urlCache.size>this.maxCacheSize){ const entries=Array.from(this.urlCache.entries()).slice(-500); this.urlCache.clear(); entries.forEach(([k,v])=>this.urlCache.set(k,v)); } const lower=url.toLowerCase().trim(); for(const p of DANGEROUS_PROTOCOLS){ if(lower.startsWith(p)){this.urlCache.set(url,false);return false;} } if(lower.startsWith('data:')){ const mime=lower.split(',')[0].split(':')[1]?.split(';')[0]||''; const safe=Array.from(ALLOWED_MIMES).some(m=>mime.startsWith(m)); this.urlCache.set(url,safe);return safe; } if(lower.startsWith('blob:')){ try{const o=new URL(url);const safe=o.origin===location.origin;this.urlCache.set(url,safe);return safe;} catch{this.urlCache.set(url,false);return false;} } this.urlCache.set(url,true);return true; }, sanitizeAttr(v){return String(v).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,''').trim().slice(0,1000);}, sanitizeFilename(f){return f.replace(/[<>:"/\\|?*\x00-\x1f]/g,'_').slice(0,255)||'download';}, createElement(tag,attrs={},children=[]){ const el=document.createElement(tag); for(const [k,v] of Object.entries(attrs)){ if(v==null)continue; if(k.startsWith('on')||k==='innerHTML')continue; if((k==='href'||k==='src'||k==='action')&&!this.isSafeUrl(v))continue; if(k==='style'&&typeof v==='object')Object.assign(el.style,v); else if(k==='textContent')el.textContent=v; else if(k==='className')el.className=v; else if(k==='dataset')Object.assign(el.dataset,v); else el.setAttribute(k,this.sanitizeAttr(v)); } const frag=document.createDocumentFragment(); for(const c of children){ if(typeof c==='string')frag.appendChild(document.createTextNode(c)); else if(c instanceof Node)frag.appendChild(c); } if(frag.childNodes.length)el.appendChild(frag); return el; } }; const RD={ resources:[], filteredResources:[], currentFilter:'all', isInitialized:false, isPanelOpen:false, isDestroyed:false, _xhrDataMap:new WeakMap(), _rafId:null, _lastUpdate:0, _refreshTimer:null, _statsDirty:true, _resourceObserver:null, _listeners:[], _bodyCheckInterval:null, _host:null, _shadowRoot:null, _elements:{}, getDisplayType(url,contentType='',initiatorType=''){ if(!SecurityUtils.isSafeUrl(url))return 'other'; if(url.startsWith('blob:')){ const m=contentType||''; if(m.includes('video'))return 'mp4'; if(m.includes('audio'))return 'mp3'; if(m.includes('image'))return 'image'; return 'other'; } if(url.startsWith('data:')){ const m=url.split(',')[0].split(':')[1]?.split(';')[0]||''; if(m.includes('image')){ if(m.includes('svg'))return 'svg'; if(m.includes('gif'))return 'gif'; if(m.includes('png'))return 'png'; if(m.includes('webp'))return 'webp'; if(m.includes('avif'))return 'avif'; return m.includes('jpeg')||m.includes('jpg')?'jpg':'image'; } if(m.includes('video'))return 'mp4'; if(m.includes('audio'))return 'mp3'; return 'datauri'; } if(contentType){ const mt=contentType.split(';')[0].toLowerCase(); if(MIME_TO_TYPE[mt])return MIME_TO_TYPE[mt]; if(mt.includes('video'))return 'mp4'; if(mt.includes('audio'))return 'mp3'; if(mt.includes('image'))return 'image'; if(mt.includes('script'))return 'script'; if(mt.includes('css'))return 'stylesheet'; if(mt.includes('font'))return 'font'; } try{ const u=new URL(url);const ext=u.pathname.split('.').pop()?.toLowerCase()||''; if(EXT_TO_TYPE[ext])return EXT_TO_TYPE[ext]; }catch{} if(initiatorType==='xmlhttprequest')return 'XHR'; if(initiatorType==='fetch')return 'fetch'; return 'other'; }, getFilterType(displayType){ const t=displayType.toLowerCase(); if(['mp4','webm','ogg','ogv','mov','avi','mkv','flv','m3u8','mpd', 'mp3','wav','flac','aac','m4a','wma','oga','weba','opus','audio'].includes(t))return 'media'; if(['jpg','jpeg','png','gif','webp','svg','ico','bmp','avif','jxl','image'].includes(t))return 'image'; return 'other'; }, getPreviewUrl(r){ if(!SecurityUtils.isSafeUrl(r.url))return ''; if(r.filterType==='image')return r.url; if(r.url.startsWith('data:')&&r.filterType==='image')return r.url; if(r.url.startsWith('blob:')&&r.filterType==='image')return r.url; return ''; }, formatUrl(url){ if(!SecurityUtils.isSafeUrl(url))return '[不安全URL已阻止]'; if(url.startsWith('data:')){const m=url.split(',')[0];return SecurityUtils.sanitizeAttr(m)+',...';} if(url.startsWith('blob:')){try{const u=new URL(url);return 'blob:...'+u.pathname.slice(-20);}catch{return 'blob:...';}} return SecurityUtils.sanitizeAttr(url); }, getTypeIcon(displayType){ const t=displayType.toLowerCase(); if(['mp4','webm','ogg','ogv','mov','avi','mkv','flv','m3u8','mpd'].includes(t))return Icons.video; if(['mp3','wav','flac','aac','m4a','wma','oga','weba','opus','audio'].includes(t))return Icons.audio; if(['jpg','jpeg','png','gif','webp','svg','ico','bmp','avif','jxl','image'].includes(t))return Icons.image; if(['script','js','mjs'].includes(t))return Icons.script; if(['stylesheet','css'].includes(t))return Icons.stylesheet; if(['json'].includes(t))return Icons.json; if(['xml'].includes(t))return Icons.xml; if(['font','woff','woff2','ttf','otf','eot'].includes(t))return Icons.font; if(['xhr'].includes(t))return Icons.wifi; if(['fetch'].includes(t))return Icons.download; if(['datauri'].includes(t))return Icons.link; return Icons.file; }, async copyToClipboard(text){ if(!text||typeof text!=='string'){this.showToast('无效的复制内容');return;} try{ if(navigator.clipboard?.writeText)await navigator.clipboard.writeText(text); else{ const ta=SecurityUtils.createElement('textarea',{value:text,style:{position:'fixed',left:'-9999px',opacity:'0'}}); document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta); } this.showToast('已复制'); }catch{this.showToast('复制失败,手动复制');prompt('手动复制',text);} }, async downloadResource(url,filename){ if(!SecurityUtils.isSafeUrl(url)){this.showToast('不安全的下载地址');return;} this.showToast('开始下载...'); try{ if(typeof GM_download==='function'&&GM_download.toString().includes('native code')){ const name=filename||this.extractFilename(url); GM_download({url,name,onload:()=>this.showToast('下载完成'),onerror:()=>{this.fallbackDownload(url,filename);}}); }else await this.fallbackDownload(url,filename); }catch{this.fallbackDownload(url,filename);} }, fallbackDownload(url,filename){ return new Promise((resolve,reject)=>{ try{ const a=document.createElement('a');a.href=url;a.download=filename||this.extractFilename(url);a.style.display='none';document.body.appendChild(a); let same=false;try{same=new URL(url,location.href).origin===location.origin;}catch{} if(url.startsWith('data:')||url.startsWith('blob:')||same){a.click();this.showToast('下载已开始');setTimeout(()=>{if(a.parentNode)document.body.removeChild(a);},100);resolve();} else{document.body.removeChild(a);this.fetchAndDownload(url,filename).then(resolve).catch(reject);} }catch(err){reject(err);} }); }, async fetchAndDownload(url,filename){ const ctrl=new AbortController();const tid=setTimeout(()=>ctrl.abort(),CONFIG.FETCH_TIMEOUT); try{ const resp=await fetch(url,{credentials:'omit',signal:ctrl.signal}); clearTimeout(tid); if(!resp.ok)throw new Error('Fetch failed'); const blob=await resp.blob();const blobUrl=URL.createObjectURL(blob); const a=document.createElement('a');a.href=blobUrl;a.download=filename||this.extractFilename(url);a.click(); setTimeout(()=>URL.revokeObjectURL(blobUrl),1000);this.showToast('下载完成'); }catch(err){ if(err.name==='AbortError')this.showToast('下载超时'); else{window.open(url,'_blank','noopener,noreferrer');this.showToast('已在新标签页打开');} } }, extractFilename(url){ try{ if(url.startsWith('data:')){const ext=url.match(/data:image\/(\w+)/)?.[1]||'bin';return `datauri_${Date.now()}.${ext}`;} if(url.startsWith('blob:'))return `blob_${Date.now()}.bin`; const u=new URL(url,location.href);const path=decodeURIComponent(u.pathname);const name=path.split('/').pop()||'download'; return SecurityUtils.sanitizeFilename(name); }catch{return `download_${Date.now()}`;} }, showToast(msg){ if(!this._shadowRoot)return; const old=this._shadowRoot.getElementById('rd-toast');if(old)old.remove(); const el=SecurityUtils.createElement('div',{id:'rd-toast',style:{position:'fixed',top:'50%',left:'50%',transform:'translate3d(-50%,-50%,0) scale(0.96)',background:'rgba(20,20,22,0.72)',color:'#f5f5f7',padding:'14px 32px',borderRadius:'24px',fontSize:'15px',fontWeight:'500',zIndex:'2147483647',pointerEvents:'none',opacity:'0',transition:'all 0.4s cubic-bezier(0.34,1.56,0.64,1)',backdropFilter:'blur(32px) saturate(220%)',webkitBackdropFilter:'blur(32px) saturate(220%)',willChange:'opacity,transform',boxShadow:'0 12px 48px rgba(0,0,0,0.16), inset 0 0.5px 0 rgba(255,255,255,0.08)',border:'0.5px solid rgba(255,255,255,0.06)'}}); el.textContent=msg;this._shadowRoot.appendChild(el);requestAnimationFrame(()=>{el.style.opacity='1';el.style.transform='translate3d(-50%,-50%,0) scale(1)';}); setTimeout(()=>{el.style.opacity='0';el.style.transform='translate3d(-50%,-50%,0) scale(0.96)';setTimeout(()=>{if(el.parentNode)el.remove();},400);},2000); }, init(){if(this.isInitialized||this.isDestroyed)return;this._waitForBodyAndInit();}, _waitForBodyAndInit(){ if(document.body){this._delayedInit();return;} let attempts=0;const max=50;if(this._bodyCheckInterval)clearInterval(this._bodyCheckInterval); this._bodyCheckInterval=setInterval(()=>{ attempts++; if(document.body){clearInterval(this._bodyCheckInterval);this._bodyCheckInterval=null;this._delayedInit();} else if(attempts>=max){clearInterval(this._bodyCheckInterval);this._bodyCheckInterval=null;const obs=new MutationObserver((_,o)=>{if(document.body){o.disconnect();this._delayedInit();}});obs.observe(document.documentElement,{childList:true,subtree:true});} },100); }, _delayedInit(){ const fn=()=>{try{this._performInit();}catch(e){console.error('ResourceDiary init error:',e);this.isInitialized=false;setTimeout(()=>this._waitForBodyAndInit(),1000);}}; if(typeof requestIdleCallback!=='undefined')requestIdleCallback(fn,{timeout:2000});else setTimeout(fn,0); }, _performInit(){ if(this.isInitialized||this.isDestroyed)return; this.setupUI(); this.setupResourceCapture(); this.setupResourceObserver(); this.setupSPASupport(); this.setupKeyboardShortcuts(); setTimeout(()=>this.scanExistingResources(),500); this.setupPeriodicScan(); this.isInitialized=true; }, setupPeriodicScan(){ if(this._refreshTimer)clearInterval(this._refreshTimer); this._refreshTimer=setInterval(()=>{if(!this.isPanelOpen)return;this.scanExistingResources();},CONFIG.SCAN_INTERVAL); }, rebuildUI(){ const wasOpen=this.isPanelOpen; const scrollTop=this._elements.list?.scrollTop||0; this.destroyUI(); this.setupUI(); this.updateFilterButtons(); this.scrollFilterToActive(); if(this._elements.list)this._elements.list.scrollTop=scrollTop; if(wasOpen){this._elements.panel?.classList.add('active');this.isPanelOpen=true;this.renderList();} }, destroyUI(){ if(this._host&&this._host.parentNode)this._host.parentNode.removeChild(this._host); this._host=null;this._shadowRoot=null;this._elements={}; }, updateFilterButtons(){ if(!this._shadowRoot)return; this._shadowRoot.querySelectorAll('.rd-filter').forEach(b=>b.classList.toggle('active',b.dataset.filter===this.currentFilter)); }, scrollFilterToActive(){ if(!this._shadowRoot)return; requestAnimationFrame(()=>{ const act=this._shadowRoot.querySelector('.rd-filter.active');const c=this._shadowRoot.querySelector('.rd-filters-scroll'); if(act&&c){const left=act.offsetLeft-(c.clientWidth/2)+(act.clientWidth/2);c.scrollTo({left:Math.max(0,left),behavior:'smooth'});} }); }, setupUI(){ if(this._host)this.destroyUI(); this._host=document.createElement('div'); this._host.style.cssText='position:fixed;top:0;left:0;width:0;height:0;overflow:visible;pointer-events:none;z-index:2147483647;'; this._shadowRoot=this._host.attachShadow({mode:'open'}); this.injectStyles(); this.createUI(); document.body.appendChild(this._host); this.bindEvents(); }, injectStyles(){ if(!this._shadowRoot)return; const style=document.createElement('style'); style.textContent=` :host{all:initial;display:block;position:fixed;top:0;left:0;width:0;height:0;overflow:visible;pointer-events:none;z-index:2147483647;font-family:-apple-system,BlinkMacSystemFont,'HarmonyOS Sans','SF Pro Display','PingFang SC','Helvetica Neue',sans-serif; --rd-bg:rgba(255,255,255,0.62); --rd-bg2:rgba(245,245,247,0.72); --rd-bg3:rgba(235,235,240,0.68); --rd-border:rgba(0,0,0,0.04); --rd-text:#1c1c1e; --rd-text2:#6c6c70; --rd-accent:#5b7fff; --rd-accent-glow:rgba(91,127,255,0.25); --rd-accent-hover:#4a6fe6; --rd-shadow:0 12px 64px rgba(0,0,0,0.06),0 4px 16px rgba(0,0,0,0.02); --rd-shadow-hover:0 20px 80px rgba(0,0,0,0.08),0 8px 24px rgba(0,0,0,0.03); --rd-glow:0 0 60px rgba(91,127,255,0.08); } :host *{box-sizing:border-box;pointer-events:auto;} .rd-container{pointer-events:auto;width:0;height:0;overflow:visible;position:relative;} #rd-fab{position:fixed;bottom:120px;right:20px;width:54px;height:54px;border-radius:50%;background:var(--rd-bg);backdrop-filter:blur(40px) saturate(240%);-webkit-backdrop-filter:blur(40px) saturate(240%);border:0.5px solid rgba(255,255,255,0.3);box-shadow:0 8px 32px rgba(0,0,0,0.06),inset 0 0.5px 0 rgba(255,255,255,0.5);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all 0.4s cubic-bezier(0.34,1.56,0.64,1);user-select:none;will-change:transform,box-shadow;transform:translateZ(0);color:var(--rd-text);pointer-events:auto;} #rd-fab:hover{transform:scale(1.06) translateZ(0);box-shadow:0 12px 40px rgba(0,0,0,0.08),inset 0 0.5px 0 rgba(255,255,255,0.6);} #rd-fab:active{transform:scale(0.90) translateZ(0);} #rd-fab svg{width:30px;height:30px;stroke:currentColor;stroke-width:1.6;} #rd-panel{position:fixed;bottom:0;left:0;right:0;top:20px;transform:translateY(calc(100% + 20px));transition:transform 0.6s cubic-bezier(0.32,0.94,0.6,1);width:100%;height:calc(100vh - 20px);background:var(--rd-bg);backdrop-filter:blur(56px) saturate(240%);-webkit-backdrop-filter:blur(56px) saturate(240%);border-radius:32px 32px 0 0;box-shadow:var(--rd-shadow);display:flex;flex-direction:column;overflow:hidden;will-change:transform;contain:layout paint;pointer-events:auto;border:0.5px solid rgba(255,255,255,0.15);border-bottom:none;} #rd-panel.active{transform:translateY(0);box-shadow:var(--rd-shadow-hover),var(--rd-glow);} .rd-header{padding:18px;display:flex;align-items:center;flex-shrink:0;gap:16px;min-width:0;border-bottom:0.5px solid var(--rd-border);} .rd-header h3{margin:0;font-size:22px;font-weight:600;color:var(--rd-text);display:flex;align-items:center;gap:10px;white-space:nowrap;flex-shrink:0;letter-spacing:-0.02em;} .rd-header h3 svg{width:24px;height:24px;stroke:currentColor;stroke-width:1.6;} .rd-controls{display:flex;gap:6px;flex-shrink:0;margin-left:auto;} .rd-icon-btn{width:38px;height:38px;border:none;background:rgba(255,255,255,0.4);color:var(--rd-text);border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;transition:all 0.3s cubic-bezier(0.34,1.56,0.64,1);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 1px 4px rgba(0,0,0,0.02);will-change:transform,background;transform:translateZ(0);pointer-events:auto;border:0.5px solid rgba(255,255,255,0.2);} .rd-icon-btn:hover{background:rgba(255,255,255,0.6);transform:scale(1.04) translateZ(0);box-shadow:0 4px 16px rgba(0,0,0,0.04);} .rd-icon-btn:active{transform:scale(0.90) translateZ(0);} .rd-icon-btn svg{width:18px;height:18px;stroke:currentColor;stroke-width:1.8;} .rd-toolbar{padding:10px 18px 12px 18px;flex-shrink:0;} .rd-filters-scroll{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;transform:translateZ(0);padding:2px 0;} .rd-filters-scroll::-webkit-scrollbar{display:none;} .rd-filters{display:flex;gap:10px;padding:2px 0;} .rd-filter{padding:8px 18px;background:rgba(255,255,255,0.4);border-radius:9999px;cursor:pointer;font-size:13px;font-weight:500;color:var(--rd-text2);transition:all 0.3s cubic-bezier(0.34,1.56,0.64,1);border:0.5px solid rgba(255,255,255,0.2);display:inline-flex;align-items:center;gap:6px;white-space:nowrap;will-change:transform,background,box-shadow,color;transform:translateZ(0);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 1px 4px rgba(0,0,0,0.02);pointer-events:auto;} .rd-filter:hover{color:var(--rd-text);background:rgba(255,255,255,0.6);transform:translateY(-1px) translateZ(0);box-shadow:0 4px 16px rgba(0,0,0,0.04);} .rd-filter.active{background:var(--rd-accent);color:#fff;box-shadow:0 8px 32px var(--rd-accent-glow),inset 0 0.5px 0 rgba(255,255,255,0.2);transform:translateY(0) translateZ(0);} .rd-filter svg{width:16px;height:16px;display:inline-block;flex-shrink:0;stroke:currentColor;stroke-width:1.8;} .rd-filter-count{font-size:11px;font-weight:600;margin-left:1px;opacity:0.6;} .rd-filter.active .rd-filter-count{opacity:1;} .rd-list{flex:1;overflow-y:auto;padding:6px 18px 18px 18px;scroll-behavior:smooth;-webkit-overflow-scrolling:touch;contain:layout;will-change:scroll-position;} .rd-list::-webkit-scrollbar{width:4px;} .rd-list::-webkit-scrollbar-track{background:transparent;} .rd-list::-webkit-scrollbar-thumb{background:var(--rd-border);border-radius:8px;} .rd-list{scrollbar-width:thin;scrollbar-color:var(--rd-border) transparent;} .rd-list-content{display:flex;flex-direction:column;gap:12px;contain:layout;padding-bottom:6px;} .rd-entry{display:flex;gap:14px;padding:12px 16px;background:rgba(255,255,255,0.45);border-radius:20px;transition:all 0.4s cubic-bezier(0.34,1.56,0.64,1);cursor:pointer;align-items:center;min-height:64px;will-change:transform,box-shadow,border-color;transform:translateZ(0);contain:layout;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:0.5px solid rgba(255,255,255,0.2);box-shadow:0 2px 8px rgba(0,0,0,0.02);pointer-events:auto;} .rd-entry:hover{transform:translateX(4px) translateZ(0);box-shadow:0 8px 32px rgba(0,0,0,0.04),0 2px 8px rgba(0,0,0,0.02);border-color:rgba(91,127,255,0.2);background:rgba(255,255,255,0.55);} .rd-entry:active{transform:scale(0.98) translateZ(0);} .rd-entry-thumb-wrapper{width:48px;height:48px;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,0.5);border-radius:16px;overflow:hidden;align-self:center;contain:strict;box-shadow:inset 0 1px 4px rgba(0,0,0,0.03);border:0.5px solid rgba(255,255,255,0.2);} .rd-entry-thumb{width:100%;height:100%;object-fit:cover;will-change:transform;border-radius:16px;} .rd-entry-fallback{display:flex;align-items:center;justify-content:center;color:var(--rd-text2);} .rd-entry-fallback svg{width:26px;height:26px;stroke:currentColor;stroke-width:1.6;} .rd-entry-content{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:4px;padding:0;contain:layout;} .rd-entry-header{display:flex;align-items:center;gap:10px;height:24px;} .rd-entry-type{color:#fff;padding:0 12px;border-radius:32px;font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;height:20px;line-height:20px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;will-change:transform;transform:translateZ(0);box-shadow:0 2px 12px rgba(0,0,0,0.06);} ${Object.entries(TYPE_COLORS).map(([t,c])=>`.rd-entry-type.${t}{background:${c}!important;}`).join('')} .rd-entry-actions{display:flex;gap:2px;margin-left:auto;align-items:center;} .rd-action-btn{cursor:pointer;width:32px;height:32px;border-radius:50%;background:rgba(255,255,255,0.2);transition:all 0.25s cubic-bezier(0.34,1.56,0.64,1);border:0.5px solid rgba(255,255,255,0.1);display:flex;align-items:center;justify-content:center;padding:0;color:var(--rd-text2);will-change:transform,background,color,box-shadow;transform:translateZ(0);pointer-events:auto;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);} .rd-action-btn:hover{background:rgba(255,255,255,0.5);transform:scale(1.08) translateZ(0);color:var(--rd-text);box-shadow:0 4px 16px rgba(0,0,0,0.04);} .rd-action-btn:active{transform:scale(0.88) translateZ(0);} .rd-action-btn svg{width:16px;height:16px;stroke:currentColor;stroke-width:1.8;pointer-events:none;} .rd-download-btn{color:var(--rd-accent);} .rd-download-btn:hover{color:var(--rd-accent-hover);background:rgba(91,127,255,0.08);} .rd-play-btn{color:#ff3b30;} .rd-play-btn:hover{background:rgba(255,59,48,0.08);color:#e0352b;} .rd-copy-btn{color:var(--rd-text2);} .rd-copy-btn:hover{background:rgba(0,0,0,0.04);color:var(--rd-text);} .rd-entry-url{word-break:break-all;color:var(--rd-text2);font-family:'SF Mono',Monaco,'HarmonyOS Sans Mono',Consolas,monospace;font-size:10px;line-height:1.5;max-height:3em;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;contain:layout;opacity:0.5;transition:opacity 0.3s;} .rd-entry:hover .rd-entry-url{opacity:0.8;} .rd-empty{text-align:center;color:var(--rd-text2);padding:60px 20px;font-size:15px;display:flex;flex-direction:column;align-items:center;gap:20px;contain:layout;opacity:0.5;} .rd-empty svg{width:64px;height:64px;stroke:currentColor;stroke-width:1.2;opacity:0.3;} #rd-inline-player,#rd-img-preview,#rd-text-preview,#rd-source-preview{position:fixed;z-index:2147483647;will-change:transform,opacity;transform:translate3d(-50%,-50%,0);backdrop-filter:blur(56px) saturate(240%);-webkit-backdrop-filter:blur(56px) saturate(240%);pointer-events:auto;animation:rdFadeIn 0.5s cubic-bezier(0.34,1.56,0.64,1);border:0.5px solid rgba(255,255,255,0.12);border-radius:32px;} @keyframes rdFadeIn{0%{opacity:0;transform:translate3d(-50%,-50%,0) scale(0.94);}100%{opacity:1;transform:translate3d(-50%,-50%,0) scale(1);}} #rd-inline-player{top:50%;left:50%;width:92%;max-width:780px;height:82vh;max-height:82vh;background:rgba(255,255,255,0.68);overflow:hidden;box-shadow:0 40px 100px rgba(0,0,0,0.12),0 8px 32px rgba(0,0,0,0.04);display:flex;flex-direction:column;contain:layout paint;} #rd-player-header{display:flex;align-items:center;justify-content:space-between;padding:18px;background:transparent;flex-shrink:0;height:auto;contain:layout;} #rd-player-title{color:var(--rd-text);font-size:17px;font-weight:600;display:flex;align-items:center;gap:10px;letter-spacing:-0.01em;} #rd-player-title svg{width:22px;height:22px;stroke:currentColor;stroke-width:1.6;} #rd-media-wrapper{flex:1;display:flex;align-items:center;justify-content:center;background:transparent;overflow:hidden;min-height:0;position:relative;width:100%;contain:layout paint;padding:4px 18px 18px 18px;} #rd-video{width:100%;height:100%;max-width:100%;max-height:100%;object-fit:contain;display:block;will-change:transform;border-radius:16px;box-shadow:0 8px 32px rgba(0,0,0,0.04);} .rd-custom-audio{width:100%;padding:24px 28px;display:flex;flex-direction:column;gap:16px;background:rgba(255,255,255,0.4);border-radius:20px;margin:8px 0;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:0.5px solid rgba(255,255,255,0.15);} .rd-audio-info{display:flex;align-items:center;gap:12px;color:var(--rd-text);font-size:13px;font-weight:500;word-break:break-all;} .rd-audio-info svg{width:28px;height:28px;stroke:currentColor;stroke-width:1.6;flex-shrink:0;opacity:0.7;} .rd-audio-filename{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} .rd-audio-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap;} .rd-play-pause-btn{width:44px;height:44px;border-radius:50%;background:var(--rd-accent);border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#fff;transition:all 0.3s cubic-bezier(0.34,1.56,0.64,1);flex-shrink:0;box-shadow:0 8px 32px var(--rd-accent-glow);pointer-events:auto;} .rd-play-pause-btn:hover{transform:scale(1.05);box-shadow:0 12px 48px var(--rd-accent-glow);} .rd-play-pause-btn:active{transform:scale(0.88);} .rd-progress-container{flex:1;position:relative;height:32px;display:flex;align-items:center;cursor:pointer;pointer-events:auto;} .rd-progress-bg{width:100%;height:3px;background:rgba(0,0,0,0.06);border-radius:6px;position:relative;overflow:hidden;} .rd-progress-filled{position:absolute;left:0;top:0;height:100%;width:0;background:var(--rd-accent);border-radius:6px;pointer-events:none;transition:width 0.08s;} .rd-progress-thumb{position:absolute;top:50%;width:14px;height:14px;background:var(--rd-accent);border-radius:50%;transform:translate(-50%,-50%);pointer-events:none;box-shadow:0 2px 16px var(--rd-accent-glow);transition:box-shadow 0.2s,transform 0.2s;border:2px solid rgba(255,255,255,0.3);} .rd-progress-container:hover .rd-progress-thumb{transform:translate(-50%,-50%) scale(1.1);box-shadow:0 4px 24px var(--rd-accent-glow);} .rd-time{font-size:12px;font-family:'SF Mono',Monaco,'HarmonyOS Sans Mono',Consolas,monospace;color:var(--rd-text2);display:flex;gap:4px;flex-shrink:0;font-weight:500;} #rd-img-preview{top:50%;left:50%;width:92%;max-width:780px;height:82vh;max-height:82vh;background:rgba(255,255,255,0.68);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 40px 100px rgba(0,0,0,0.12),0 8px 32px rgba(0,0,0,0.04);} #rd-img-preview-header{display:flex;align-items:center;justify-content:space-between;padding:18px;background:transparent;height:auto;flex-shrink:0;contain:layout;} #rd-img-preview-title{color:var(--rd-text);font-size:17px;font-weight:600;display:flex;align-items:center;gap:10px;} #rd-img-preview-title svg{width:22px;height:22px;stroke:currentColor;stroke-width:1.6;} #rd-img-preview-content{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:18px;background:transparent;cursor:zoom-out;contain:layout paint;} #rd-preview-img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;border-radius:16px;cursor:default;will-change:transform;box-shadow:0 8px 40px rgba(0,0,0,0.04);} #rd-text-preview,#rd-source-preview{top:50%;left:50%;width:92%;max-width:780px;height:82vh;background:rgba(255,255,255,0.68);box-shadow:0 40px 100px rgba(0,0,0,0.12),0 8px 32px rgba(0,0,0,0.04);display:flex;flex-direction:column;overflow:hidden;} #rd-text-preview-header,#rd-source-preview-header{display:flex;align-items:center;justify-content:space-between;padding:18px;background:transparent;height:auto;contain:layout;flex-shrink:0;} #rd-text-preview-title,#rd-source-preview-title{font-weight:600;color:var(--rd-text);font-size:17px;display:flex;align-items:center;gap:10px;} #rd-text-preview-title svg,#rd-source-preview-title svg{width:22px;height:22px;stroke:currentColor;stroke-width:1.6;} #rd-text-preview-scroll,#rd-source-preview-scroll{flex:1;overflow:auto;padding:18px;background:transparent;-webkit-overflow-scrolling:touch;} #rd-text-preview-scroll::-webkit-scrollbar,#rd-source-preview-scroll::-webkit-scrollbar{width:4px;} #rd-text-preview-scroll::-webkit-scrollbar-track,#rd-source-preview-scroll::-webkit-scrollbar-track{background:transparent;} #rd-text-preview-scroll::-webkit-scrollbar-thumb,#rd-source-preview-scroll::-webkit-scrollbar-thumb{background:var(--rd-border);border-radius:8px;} #rd-text-preview-content,#rd-source-preview-content{margin:0;padding:0;font-family:'SF Mono',Monaco,'HarmonyOS Sans Mono',Consolas,monospace;font-size:13px;line-height:1.8;color:var(--rd-text);white-space:pre-wrap;word-break:break-all;background:transparent;border:none;outline:none;} .rd-iframe-container{flex:1;position:relative;background:transparent;overflow:hidden;contain:layout paint;border-radius:0 0 32px 32px;} .rd-iframe-container iframe{width:100%;height:100%;border:none;background:transparent;} *{outline:none!important;-webkit-tap-highlight-color:transparent!important;} @media (prefers-color-scheme: dark){ :host{ --rd-bg:rgba(28,28,30,0.78); --rd-bg2:rgba(44,44,46,0.82); --rd-bg3:rgba(58,58,60,0.78); --rd-border:rgba(255,255,255,0.05); --rd-text:#f5f5f7; --rd-text2:#98989e; --rd-accent:#5b7fff; --rd-accent-glow:rgba(91,127,255,0.3); --rd-accent-hover:#7a96ff; --rd-shadow:0 12px 64px rgba(0,0,0,0.2),0 4px 16px rgba(0,0,0,0.08); --rd-shadow-hover:0 20px 80px rgba(0,0,0,0.24),0 8px 24px rgba(0,0,0,0.1); --rd-glow:0 0 60px rgba(91,127,255,0.06); } #rd-fab{background:rgba(28,28,30,0.7);border-color:rgba(255,255,255,0.06);} #rd-panel{background:rgba(28,28,30,0.78);border-color:rgba(255,255,255,0.05);} .rd-header h3{color:#f5f5f7;} .rd-icon-btn{background:rgba(255,255,255,0.05);border-color:rgba(255,255,255,0.04);color:#f5f5f7;} .rd-icon-btn:hover{background:rgba(255,255,255,0.1);} .rd-filter{background:rgba(255,255,255,0.04);border-color:rgba(255,255,255,0.04);color:var(--rd-text2);} .rd-filter:hover{background:rgba(255,255,255,0.08);color:#f5f5f7;} .rd-filter.active{background:var(--rd-accent);color:#fff;} .rd-entry{background:rgba(255,255,255,0.04);border-color:rgba(255,255,255,0.04);} .rd-entry:hover{background:rgba(255,255,255,0.08);border-color:rgba(91,127,255,0.15);} .rd-entry-thumb-wrapper{background:rgba(255,255,255,0.04);border-color:rgba(255,255,255,0.04);} .rd-action-btn{background:rgba(255,255,255,0.04);border-color:rgba(255,255,255,0.03);} .rd-action-btn:hover{background:rgba(255,255,255,0.08);} .rd-custom-audio{background:rgba(255,255,255,0.04);border-color:rgba(255,255,255,0.04);} .rd-progress-bg{background:rgba(255,255,255,0.06);} #rd-inline-player,#rd-img-preview,#rd-text-preview,#rd-source-preview{background:rgba(28,28,30,0.82);border-color:rgba(255,255,255,0.04);} .rd-entry-url{color:#98989e;} .rd-entry-type{box-shadow:0 2px 12px rgba(0,0,0,0.15);} } `; this._shadowRoot.appendChild(style); }, getFilterIcon(type){const map={all:Icons.folder,media:Icons.waveform,image:Icons.image,other:Icons.file};return map[type]||Icons.file;}, getFilterName(type){const names={all:'全部',media:'媒体',image:'图片',other:'其他'};return names[type]||type;}, createUI(){ if(!this._shadowRoot)return; const c=document.createElement('div');c.className='rd-container'; c.innerHTML=`
${Icons.box}

${Icons.box} 资源日记

${['all','media','image','other'].map(f=>``).join('')}
`; this._shadowRoot.appendChild(c); this._elements={floatingBtn:this._shadowRoot.getElementById('rd-fab'),panel:this._shadowRoot.getElementById('rd-panel'),list:this._shadowRoot.getElementById('rd-list'),listContent:this._shadowRoot.querySelector('.rd-list-content'),closeBtn:this._shadowRoot.getElementById('rd-close'),viewSourceBtn:this._shadowRoot.getElementById('rd-view-source')}; }, bindEvents(){ if(!this._shadowRoot)return; const root=this._shadowRoot; root.addEventListener('click',e=>{ const t=e.target.closest?e.target.closest(e.target.tagName==='svg'?'svg':'*'):e.target; if(t.closest('#rd-close')){this.hidePanel();return;} if(t.closest('#rd-view-source')){this.viewSource();return;} const filter=t.closest('.rd-filter');if(filter){this.setFilter(filter.dataset.filter);return;} const action=t.closest('.rd-action-btn');if(action){e.stopPropagation();const url=action.dataset.url;if(!url||!SecurityUtils.isSafeUrl(url))return;if(action.classList.contains('rd-download-btn'))this.downloadResource(url);else if(action.classList.contains('rd-play-btn'))this.playMedia(url);else if(action.classList.contains('rd-copy-btn'))this.copyToClipboard(url);return;} const thumb=t.closest('.rd-entry-thumb-wrapper');if(thumb){e.stopPropagation();const url=thumb.dataset.url;if(url&&SecurityUtils.isSafeUrl(url))this.previewImage(url);return;} const entry=t.closest('.rd-entry');if(entry&&!t.closest('.rd-entry-actions')){const url=entry.dataset.url;const displayType=entry.dataset.displayType;const filterType=this.getFilterType(displayType);if(!url||!SecurityUtils.isSafeUrl(url))return;if(filterType==='media')this.playMedia(url);else if(filterType==='image')this.previewImage(url);else this.previewTextContent(url);} }); const fab=this._elements.floatingBtn;if(fab)fab.addEventListener('click',e=>{e.stopPropagation();this.togglePanel();}); const list=this._elements.list;if(list){let sx=0,sy=0,sw=false,st=0;list.addEventListener('touchstart',e=>{sx=e.changedTouches[0].screenX;sy=e.changedTouches[0].screenY;st=Date.now();sw=false;},{passive:true});list.addEventListener('touchmove',e=>{if(!sx)return;const x=e.changedTouches[0].screenX,y=e.changedTouches[0].screenY;const dx=Math.abs(sx-x),dy=Math.abs(sy-y);if(dx>dy&&dx>10)sw=true;},{passive:true});list.addEventListener('touchend',e=>{if(!sw)return;const dx=sx-e.changedTouches[0].screenX;const dt=Date.now()-st;if(Math.abs(dx)>50&&dt<300){const filters=['all','media','image','other'];const ci=filters.indexOf(this.currentFilter);const ni=dx>0?Math.min(ci+1,filters.length-1):Math.max(ci-1,0);if(ni!==ci){this.setFilter(filters[ni]);setTimeout(()=>this.scrollFilterToActive(),50);}}sx=0;sw=false;},{passive:true});} }, setupKeyboardShortcuts(){ const handler=e=>{ if(e.key==='Escape'){ if(this._shadowRoot){this._shadowRoot.getElementById('rd-inline-player')?.remove();this._shadowRoot.getElementById('rd-img-preview')?.remove();this._shadowRoot.getElementById('rd-text-preview')?.remove();this._shadowRoot.getElementById('rd-source-preview')?.remove();} if(this.isPanelOpen)this.hidePanel(); } }; document.addEventListener('keydown',handler); this._listeners.push(()=>document.removeEventListener('keydown',handler)); }, setFilter(filter){this.currentFilter=filter;this.updateFilterButtons();this.scrollFilterToActive();this.scheduleUpdate();}, togglePanel(){ const p=this._elements.panel;if(!p)return; if(p.classList.contains('active')){this.hidePanel();}else{p.classList.add('active');this.isPanelOpen=true;this.manualRefresh();this.scheduleUpdate();this.scrollFilterToActive();} }, hidePanel(){ const p=this._elements.panel;if(p)p.classList.remove('active');this.isPanelOpen=false; if(this._shadowRoot){setTimeout(()=>{this._shadowRoot.getElementById('rd-inline-player')?.remove();this._shadowRoot.getElementById('rd-img-preview')?.remove();this._shadowRoot.getElementById('rd-text-preview')?.remove();this._shadowRoot.getElementById('rd-source-preview')?.remove();},300);} }, previewImage(url){ if(!SecurityUtils.isSafeUrl(url)){this.showToast('不安全的图片地址');return;} if(!this._shadowRoot)return; this._shadowRoot.getElementById('rd-img-preview')?.remove(); const preview=SecurityUtils.createElement('div',{id:'rd-img-preview',style:{borderRadius:'32px'}}); const header=SecurityUtils.createElement('div',{id:'rd-img-preview-header'}); const title=SecurityUtils.createElement('span',{id:'rd-img-preview-title'});title.innerHTML=Icons.image+' 图片预览'; const close=SecurityUtils.createElement('button',{className:'rd-icon-btn',id:'rd-close-preview',title:'关闭'});close.innerHTML=Icons.close; header.appendChild(title);header.appendChild(close); const content=SecurityUtils.createElement('div',{id:'rd-img-preview-content'}); const img=document.createElement('img');img.id='rd-preview-img';img.src=url;img.alt='预览'; content.appendChild(img); preview.appendChild(header);preview.appendChild(content); const closeHandler=()=>preview.remove(); close.addEventListener('click',closeHandler); preview.addEventListener('click',e=>{if(e.target===preview||e.target.id==='rd-img-preview-content'||e.target.id==='rd-img-preview-header')closeHandler();}); this._shadowRoot.appendChild(preview); }, async previewTextContent(url){ if(!SecurityUtils.isSafeUrl(url)){this.showToast('不安全的资源地址');return;} if(!this._shadowRoot)return; this.showToast('加载中...'); const ctrl=new AbortController();const tid=setTimeout(()=>ctrl.abort(),CONFIG.FETCH_TIMEOUT); try{ const resp=await fetch(url,{credentials:'omit',signal:ctrl.signal,headers:{'Accept':'text/plain,text/html,application/json'}}); clearTimeout(tid); const ct=resp.headers.get('content-type')||''; if(!/text\/|json|xml|javascript/.test(ct)){this.showIframePreview(url);return;} const text=await resp.text();const display=text.length>50000?text.slice(0,50000)+'\n\n... (内容过长已截断)':text; this._shadowRoot.getElementById('rd-text-preview')?.remove(); const preview=SecurityUtils.createElement('div',{id:'rd-text-preview',style:{borderRadius:'32px'}}); const header=SecurityUtils.createElement('div',{id:'rd-text-preview-header'}); const title=SecurityUtils.createElement('span',{id:'rd-text-preview-title'});title.innerHTML=Icons.file+' 内容预览'; const close=SecurityUtils.createElement('button',{className:'rd-icon-btn',id:'rd-text-preview-close',title:'关闭'});close.innerHTML=Icons.close; header.appendChild(title);header.appendChild(close); preview.appendChild(header); const scroll=SecurityUtils.createElement('div',{id:'rd-text-preview-scroll'}); const pre=document.createElement('pre');pre.id='rd-text-preview-content';pre.textContent=display; scroll.appendChild(pre);preview.appendChild(scroll); const handler=()=>preview.remove(); close.addEventListener('click',handler); preview.addEventListener('click',e=>{if(e.target===preview||e.target.id==='rd-text-preview-scroll')handler();}); this._shadowRoot.appendChild(preview); }catch(e){this.showIframePreview(url);} }, showIframePreview(url){ if(!this._shadowRoot)return; this._shadowRoot.getElementById('rd-text-preview')?.remove(); const preview=SecurityUtils.createElement('div',{id:'rd-text-preview',style:{display:'flex',flexDirection:'column',borderRadius:'32px'}}); const header=SecurityUtils.createElement('div',{id:'rd-text-preview-header'}); const title=SecurityUtils.createElement('span',{id:'rd-text-preview-title'});title.innerHTML=Icons.file+' 内容预览'; const controls=SecurityUtils.createElement('div',{style:{display:'flex',gap:'8px',alignItems:'center'}}); const open=SecurityUtils.createElement('button',{className:'rd-icon-btn',title:'新窗口打开'});open.innerHTML=Icons.link; const close=SecurityUtils.createElement('button',{className:'rd-icon-btn',id:'rd-text-preview-close',title:'关闭'});close.innerHTML=Icons.close; controls.appendChild(open);controls.appendChild(close); header.appendChild(title);header.appendChild(controls); const container=SecurityUtils.createElement('div',{className:'rd-iframe-container'}); const iframe=SecurityUtils.createElement('iframe',{src:url,sandbox:'allow-same-origin allow-scripts allow-popups allow-downloads'}); container.appendChild(iframe); preview.appendChild(header);preview.appendChild(container); const handler=()=>preview.remove(); close.addEventListener('click',handler); open.addEventListener('click',()=>{window.open(url,'_blank','noopener,noreferrer');}); preview.addEventListener('click',e=>{if(e.target===preview||e.target.className==='rd-iframe-container')handler();}); this._shadowRoot.appendChild(preview); }, viewSource(){ if(!this._shadowRoot)return; const src='\n'+document.documentElement.outerHTML; this._shadowRoot.getElementById('rd-source-preview')?.remove(); const preview=SecurityUtils.createElement('div',{id:'rd-source-preview',style:{borderRadius:'32px'}}); const header=SecurityUtils.createElement('div',{id:'rd-source-preview-header'}); const title=SecurityUtils.createElement('span',{id:'rd-source-preview-title'});title.innerHTML=Icons.code+' 网页源代码'; const controls=SecurityUtils.createElement('div',{style:{display:'flex',gap:'8px',alignItems:'center'}}); const copy=SecurityUtils.createElement('button',{className:'rd-icon-btn',id:'rd-source-copy',title:'复制'});copy.innerHTML=Icons.copy; const close=SecurityUtils.createElement('button',{className:'rd-icon-btn',id:'rd-source-close',title:'关闭'});close.innerHTML=Icons.close; controls.appendChild(copy);controls.appendChild(close); header.appendChild(title);header.appendChild(controls); preview.appendChild(header); const scroll=SecurityUtils.createElement('div',{id:'rd-source-preview-scroll'}); const pre=document.createElement('pre');pre.id='rd-source-preview-content';pre.textContent=src; scroll.appendChild(pre);preview.appendChild(scroll); const handler=()=>preview.remove(); close.addEventListener('click',handler); copy.addEventListener('click',()=>{this.copyToClipboard(src);}); preview.addEventListener('click',e=>{if(e.target===preview||e.target.id==='rd-source-preview-scroll')handler();}); this._shadowRoot.appendChild(preview); }, setupSPASupport(){ let lastUrl=location.href; const check=()=>{ if(location.href!==lastUrl){lastUrl=location.href;this.resources=[];this.filteredResources=[];processedUrls.clear();this._statsDirty=true;this.scheduleUpdate();setTimeout(()=>{this.scanExistingResources();if(!this._host||!this._host.parentNode)this.setupUI();},500);} }; const origPush=OriginalAPIs.pushState;const origReplace=OriginalAPIs.replaceState; history.pushState=function(...args){origPush.apply(this,args);setTimeout(check,50);}; history.replaceState=function(...args){origReplace.apply(this,args);setTimeout(check,50);}; const pop=()=>setTimeout(check,50);const hash=check; window.addEventListener('popstate',pop);window.addEventListener('hashchange',hash); this._listeners.push(()=>{window.removeEventListener('popstate',pop);window.removeEventListener('hashchange',hash);}); }, scanExistingResources(){ const processImages=()=>{const imgs=document.querySelectorAll('img[src], img[srcset]');for(let i=0;i{const videos=document.querySelectorAll('video[src], video source[src], video[data-src]');const audios=document.querySelectorAll('audio[src], audio source[src], audio[data-src]');[...videos,...audios].slice(0,CONFIG.BATCH_SIZE).forEach(el=>{if(el.src)this.tryAddMediaUrl(el.src,el.tagName.toLowerCase());if(el.dataset?.src)this.tryAddMediaUrl(el.dataset.src,el.tagName.toLowerCase());});}; const processShadowDOM=()=>{document.querySelectorAll('*').forEach(el=>{if(el.shadowRoot){el.shadowRoot.querySelectorAll('video[src], video source[src]').forEach(v=>{if(v.src)this.tryAddMediaUrl(v.src,'video');if(v.dataset?.src)this.tryAddMediaUrl(v.dataset.src,'video');});}});}; const processIframes=()=>{document.querySelectorAll('iframe').forEach(iframe=>{try{const doc=iframe.contentDocument||iframe.contentWindow?.document;if(doc){doc.querySelectorAll('video[src], video source[src]').forEach(v=>{if(v.src)this.tryAddMediaUrl(v.src,'video');});}}catch(e){}});}; const processBgImages=()=>{const els=document.querySelectorAll('body, body *');let idx=0;const batch=()=>{const end=Math.min(idx+CONFIG.BATCH_SIZE,els.length);for(;idx{const u=m.replace(/url\(["']?/,'').replace(/["']?\)$/,'');if(u.startsWith('data:'))this.tryAddDataUri(u,'css-bg');});}const blobMatches=bg.match(/url\(["']?(blob:[^"')]+)["']?\)/g);if(blobMatches){blobMatches.forEach(m=>{const u=m.replace(/url\(["']?/,'').replace(/["']?\)$/,'');if(u.startsWith('blob:'))this.tryAddBlobUrl(u,'css-bg','image');});}}}catch(e){}}if(idxrequestIdleCallback(processBgImages),1000);}else{setTimeout(processImages,1);setTimeout(processMedia,100);setTimeout(processShadowDOM,200);setTimeout(processIframes,300);setTimeout(processBgImages,1000);} }, captureImageElement(img){ if(processedElements.has(img))return;processedElements.add(img); const src=img.currentSrc||img.src;if(src){if(src.startsWith('data:'))this.tryAddDataUri(src,'img');else if(src.startsWith('blob:'))this.tryAddBlobUrl(src,'img','image');else this.tryAddImageUrl(src);} if(img.srcset){img.srcset.split(',').forEach(s=>{const u=s.trim().split(' ')[0];if(u){if(u.startsWith('data:'))this.tryAddDataUri(u,'srcset');else if(u.startsWith('blob:'))this.tryAddBlobUrl(u,'srcset','image');else this.tryAddImageUrl(u);}});} }, tryAddMediaUrl(url,tagName){ if(!url)return;if(processedUrls.has(url))return; const isAudio=tagName==='audio';const ext=url.split('.').pop()?.split('?')[0].toLowerCase()||''; const audioExts=new Set(['mp3','wav','flac','aac','m4a','wma','oga','weba','opus']); const videoExts=new Set(['mp4','webm','ogg','ogv','mov','avi','mkv','flv','m3u8','mpd']); let displayType; if(isAudio||audioExts.has(ext))displayType=EXT_TO_TYPE[ext]||'mp3'; else if(videoExts.has(ext))displayType=EXT_TO_TYPE[ext]||'mp4'; else return; processedUrls.add(url);this.addResource({url,displayType,filterType:'media',status:200}); }, tryAddBlobUrl(url,source,suggestedType){ if(!SecurityUtils.isSafeUrl(url))return;if(processedUrls.has(url))return;processedUrls.add(url); let displayType=suggestedType||this.getDisplayType(url,''); const filterType=this.getFilterType(displayType); this.addResource({url,displayType,filterType,status:200,size:0,method:'BLOB',source}); }, tryAddImageUrl(url){ if(!url||processedUrls.has(url))return;const ext=url.split('.').pop()?.split('?')[0].toLowerCase()||''; if(new Set(['jpg','jpeg','png','gif','webp','svg','ico','bmp','avif','jxl']).has(ext)){ processedUrls.add(url);this.addResource({url,displayType:EXT_TO_TYPE[ext]||'image',filterType:'image',status:200}); } }, tryAddDataUri(url,source){ if(!SecurityUtils.isSafeUrl(url))return;if(processedUrls.has(url))return;processedUrls.add(url); const displayType=this.getDisplayType(url,'');const filterType=this.getFilterType(displayType); this.addResource({url,displayType,filterType,status:200,size:url.length,method:'DATA',source}); }, setupResourceObserver(){ if(this._resourceObserver)this._resourceObserver.disconnect(); this._resourceObserver=new MutationObserver(mutations=>{ for(const m of mutations){ for(const node of m.addedNodes){ if(node.nodeType!==1)continue; if(node.tagName==='IMG')this.captureImageElement(node); else if(node.tagName==='VIDEO'||node.tagName==='AUDIO')this.captureMediaElement(node); else if(node.tagName==='IFRAME'){setTimeout(()=>{try{const doc=node.contentDocument||node.contentWindow?.document;if(doc){doc.querySelectorAll('video[src], video source[src]').forEach(v=>{if(v.src)this.tryAddMediaUrl(v.src,'video');});}}catch(e){}},1000);} else if(node.querySelectorAll){ node.querySelectorAll('img[src], img[srcset]').forEach(img=>this.captureImageElement(img)); node.querySelectorAll('video, audio').forEach(el=>this.captureMediaElement(el)); node.querySelectorAll('*').forEach(el=>{if(el.shadowRoot){el.shadowRoot.querySelectorAll('video[src], video source[src]').forEach(v=>{if(v.src)this.tryAddMediaUrl(v.src,'video');});}}); } } if(m.type==='attributes'&&(m.target.tagName==='VIDEO'||m.target.tagName==='AUDIO')){ const ns=m.target.src||m.target.dataset?.src;if(ns)this.tryAddMediaUrl(ns,m.target.tagName.toLowerCase()); } } }); this._resourceObserver.observe(document.body,{childList:true,subtree:true,attributes:true,attributeFilter:['src','data-src']}); }, captureMediaElement(el){ if(processedElements.has(el))return;processedElements.add(el); const observers=[]; const processSources=()=>{ const src=el.currentSrc||el.src||el.dataset?.src;if(src)this.tryAddMediaUrl(src,el.tagName.toLowerCase()); el.querySelectorAll('source').forEach(source=>{ const s=source.src||source.dataset?.src;if(!s||processedUrls.has(s))return; const type=source.type||'';const ext=s.split('.').pop()?.split('?')[0].toLowerCase()||''; const audioExts=new Set(['mp3','wav','flac','aac','m4a','wma','oga','weba','opus']); const videoExts=new Set(['mp4','webm','ogg','ogv','mov','avi','mkv','flv','m3u8','mpd']); let displayType; if(type.includes('audio')||audioExts.has(ext))displayType=EXT_TO_TYPE[ext]||'mp3'; else if(type.includes('video')||videoExts.has(ext))displayType=EXT_TO_TYPE[ext]||'mp4'; else return; processedUrls.add(s);this.addResource({url:s,displayType,filterType:'media',status:200}); }); }; processSources(); const loadHandler=()=>processSources(); el.addEventListener('loadstart',loadHandler,{once:true}); el.addEventListener('loadedmetadata',loadHandler,{once:true}); const attrObs=new MutationObserver(muts=>{muts.forEach(m=>{if(m.attributeName==='src'||m.attributeName==='data-src'){const ns=el.src||el.dataset?.src;if(ns)this.tryAddMediaUrl(ns,el.tagName.toLowerCase());}});}); attrObs.observe(el,{attributes:true,attributeFilter:['src','data-src']}); observers.push(attrObs); if('IntersectionObserver' in window){const io=new IntersectionObserver(entries=>{entries.forEach(e=>{if(e.isIntersecting)processSources();});},{rootMargin:CONFIG.LAZY_LOAD_OFFSET});io.observe(el);observers.push(io);} const cleanObs=new MutationObserver(muts=>{muts.forEach(m=>{m.removedNodes.forEach(node=>{if(node===el||(node.contains&&node.contains(el))){observers.forEach(o=>o.disconnect());cleanObs.disconnect();}});});}); if(document.body)cleanObs.observe(document.body,{childList:true,subtree:true}); }, setupResourceCapture(){ const processEntry=(entry)=>{ if(!entry.name)return;const url=entry.name;if(!SecurityUtils.isSafeUrl(url))return;if(processedUrls.has(url))return; const displayType=this.getDisplayType(url,entry.responseContentType,entry.initiatorType); const filterType=this.getFilterType(displayType); if(filterType==='other'&&(url.includes('.m3u8')||url.includes('.mpd')||url.includes('manifest')||entry.responseContentType?.includes('mpegurl'))){ const ext=url.includes('.m3u8')?'m3u8':url.includes('.mpd')?'mpd':'mp4'; processedUrls.add(url);this.addResource({url,displayType:ext,filterType:'media',status:entry.responseStatus||200,size:entry.transferSize||entry.encodedBodySize||0,duration:entry.duration||0,cached:entry.transferSize===0&&entry.encodedBodySize>0});return; } if(filterType==='other'&&!entry.responseContentType?.includes('video')&&!entry.responseContentType?.includes('audio'))return; processedUrls.add(url);let size=entry.transferSize||entry.encodedBodySize||0;if((url.startsWith('data:')||url.startsWith('blob:'))&&size===0)size=url.length; this.addResource({url,displayType,filterType,status:entry.responseStatus||200,size,duration:entry.duration||0,cached:entry.transferSize===0&&entry.encodedBodySize>0}); }; performance.getEntriesByType('resource').forEach(processEntry); try{const obs=new PerformanceObserver(list=>{list.getEntries().forEach(processEntry);});obs.observe({type:'resource',buffered:true});this._listeners.push(()=>obs.disconnect());}catch(e){} const bufHandler=()=>{performance.clearResourceTimings();};performance.addEventListener('resourcetimingbufferfull',bufHandler);this._listeners.push(()=>performance.removeEventListener('resourcetimingbufferfull',bufHandler)); const self=this; XMLHttpRequest.prototype.open=function(method,url){const data={method,url:String(url),startTime:performance.now()};self._xhrDataMap.set(this,data);return OriginalAPIs.xhrOpen.apply(this,arguments);}; XMLHttpRequest.prototype.send=function(){const xhr=this;const data=self._xhrDataMap.get(xhr);if(!data)return OriginalAPIs.xhrSend.apply(this,arguments);const loadHandler=()=>{try{if(self.isDestroyed)return;const rurl=xhr.responseURL||data.url;if(!SecurityUtils.isSafeUrl(rurl))return;if(processedUrls.has(rurl))return;const displayType=self.getDisplayType(rurl,xhr.getResponseHeader('content-type'),'xmlhttprequest');const filterType=self.getFilterType(displayType);processedUrls.add(rurl);self.addResource({url:rurl,displayType,filterType,status:xhr.status,size:xhr.responseText?.length||0,duration:performance.now()-data.startTime,method:data.method});}catch(e){}self._xhrDataMap.delete(xhr);};xhr.addEventListener('load',loadHandler,{once:true});return OriginalAPIs.xhrSend.apply(this,arguments);}; window.fetch=async (input,init)=>{if(self.isDestroyed)return OriginalAPIs.fetch(input,init);const url=typeof input==='string'?input:input?.url||input;if(!url||!SecurityUtils.isSafeUrl(url))return OriginalAPIs.fetch(input,init);const method=init?.method||'GET';const start=performance.now();const resp=await OriginalAPIs.fetch(input,init);Promise.resolve().then(async ()=>{try{if(!resp.ok||resp.type==='opaque')return;if(processedUrls.has(url))return;const clone=resp.clone();const displayType=self.getDisplayType(url,clone.headers.get('content-type'),'fetch');const filterType=self.getFilterType(displayType);processedUrls.add(url);let size=0;try{const blob=await clone.blob();size=blob.size;}catch(e){size=parseInt(clone.headers.get('content-length'))||0;}self.addResource({url,displayType,filterType,status:clone.status,size,duration:performance.now()-start,method});}catch(e){}});return resp;}; }, addResource(resource){ if(!SecurityUtils.isSafeUrl(resource.url))return; const id=`${Date.now()}_${Math.random().toString(36).slice(2)}_${Math.random().toString(36).slice(2)}`; this.resources.unshift({id,url:resource.url,displayType:resource.displayType||'other',filterType:resource.filterType||'other',status:resource.status||0,size:resource.size||0,duration:resource.duration||0,method:resource.method||'GET',timestamp:new Date().toLocaleTimeString('zh-CN'),cached:resource.cached||false}); if(this.resources.length>CONFIG.MAX_RESOURCES){const removed=this.resources.splice(CONFIG.MAX_RESOURCES);removed.forEach(r=>processedUrls.delete(r.url));} if(processedUrls.size>CONFIG.MAX_URL_CACHE){const recent=this.resources.slice(0,Math.floor(CONFIG.MAX_URL_CACHE/2));processedUrls.clear();recent.forEach(r=>processedUrls.add(r.url));} this._statsDirty=true;this.scheduleUpdate(); }, scheduleUpdate(){ if(this._rafId)return; const now=performance.now();const elapsed=now-this._lastUpdate; if(elapsed{this._rafId=null;if(performance.now()-this._lastUpdate>=CONFIG.UPDATE_DELAY)this._doUpdate();else this.scheduleUpdate();});} else this._doUpdate(); }, _doUpdate(){this._lastUpdate=performance.now();this.filterResources();this.renderList();this.updateStats();}, filterResources(){this.filteredResources=this.resources.filter(r=>this.currentFilter==='all'||r.filterType===this.currentFilter);}, renderList(){ const list=this._elements.list;if(!list)return;const scrollTop=list.scrollTop;const content=this._elements.listContent;if(!content)return; content.innerHTML=''; if(this.filteredResources.length===0){content.innerHTML=`
${Icons.folderOpen}
暂无资源
`;return;} const frag=document.createDocumentFragment();this.filteredResources.forEach(r=>frag.appendChild(this.createEntryElement(r)));content.appendChild(frag); if(scrollTop>0){requestAnimationFrame(()=>{list.scrollTop=scrollTop;});} }, createEntryElement(r){ const preview=this.getPreviewUrl(r);const dispUrl=this.formatUrl(r.url);const icon=this.getTypeIcon(r.displayType);const isMedia=r.filterType==='media';const isImage=r.filterType==='image';const isDataUri=r.displayType==='datauri'; const entry=document.createElement('div');entry.className='rd-entry';entry.dataset.url=r.url;entry.dataset.displayType=r.displayType;entry.title=isMedia?'点击播放':(isImage||isDataUri)?'点击查看图片':'点击查看内容'; const thumb=document.createElement('div');thumb.className='rd-entry-thumb-wrapper';thumb.dataset.url=r.url; if((isImage||isDataUri)&&preview){const img=document.createElement('img');img.className='rd-entry-thumb';img.src=preview;img.loading='lazy';img.decoding='async';img.onerror=function(){this.style.display='none';this.nextElementSibling.style.display='flex';};thumb.appendChild(img);} const fallback=document.createElement('div');fallback.className='rd-entry-fallback';fallback.style.display=(isImage||isDataUri)&&preview?'none':'flex';fallback.innerHTML=icon;thumb.appendChild(fallback); const content=document.createElement('div');content.className='rd-entry-content'; const header=document.createElement('div');header.className='rd-entry-header'; const typeSpan=document.createElement('span');typeSpan.className=`rd-entry-type ${r.displayType}`;typeSpan.textContent=r.displayType; const actions=document.createElement('div');actions.className='rd-entry-actions'; if(isMedia){const play=document.createElement('button');play.className='rd-action-btn rd-play-btn';play.dataset.url=r.url;play.title='播放';play.innerHTML=Icons.play;actions.appendChild(play);} const copy=document.createElement('button');copy.className='rd-action-btn rd-copy-btn';copy.dataset.url=r.url;copy.title='复制';copy.innerHTML=Icons.copy; const download=document.createElement('button');download.className='rd-action-btn rd-download-btn';download.dataset.url=r.url;download.title='下载';download.innerHTML=Icons.download; actions.appendChild(copy);actions.appendChild(download); header.appendChild(typeSpan);header.appendChild(actions); const urlDiv=document.createElement('div');urlDiv.className='rd-entry-url';urlDiv.textContent=dispUrl; content.appendChild(header);content.appendChild(urlDiv); entry.appendChild(thumb);entry.appendChild(content); return entry; }, updateStats(){ if(!this._statsDirty)return;this._statsDirty=false;const stats={all:0,media:0,image:0,other:0}; for(const r of this.resources){stats.all++;stats[r.filterType]++;} if(this._shadowRoot){this._shadowRoot.querySelectorAll('.rd-filter-count').forEach(el=>{const t=el.dataset.count;if(stats.hasOwnProperty(t))el.textContent=stats[t];});} }, extractRealMediaUrl(url){ try{if(url.match(/^https?:\/\/[^\s&]+$/))return url;const u=new URL(url,location.href);const params=u.searchParams;const candidates=['url','src','link','file','play','video','audio','stream','source','v','u'];for(const p of candidates){const val=params.get(p);if(val){const dec=decodeURIComponent(val);if(dec.startsWith('http'))return dec;}}if(url.includes('play')||url.includes('player')||url.includes('embed')){const m=url.match(/https?:\/\/[^\s&"']+\.(m3u8|mp4|webm|mkv|flv|mp3|aac)/i);if(m)return m[0];}return url;}catch(e){return url;} }, _createAudioPlayerUI(url,mime,originalUrl){ const wrap=document.createElement('div');wrap.className='rd-custom-audio'; let fname='音频';try{const u=new URL(url,location.href);const parts=decodeURIComponent(u.pathname).split('/');const last=parts.pop();if(last&&last.includes('.'))fname=last;else fname='音频流';}catch(e){fname='音频';} const info=document.createElement('div');info.className='rd-audio-info';info.innerHTML=`${Icons.music}${SecurityUtils.sanitizeAttr(fname)}`; const ctrl=document.createElement('div');ctrl.className='rd-audio-controls'; const pp=document.createElement('button');pp.className='rd-play-pause-btn';pp.innerHTML=Icons.play; const prog=document.createElement('div');prog.className='rd-progress-container'; const bg=document.createElement('div');bg.className='rd-progress-bg'; const fill=document.createElement('div');fill.className='rd-progress-filled'; const thumb=document.createElement('div');thumb.className='rd-progress-thumb'; prog.appendChild(bg);prog.appendChild(fill);prog.appendChild(thumb); const time=document.createElement('div');time.className='rd-time';time.innerHTML='0:00/0:00'; ctrl.appendChild(pp);ctrl.appendChild(prog);ctrl.appendChild(time); wrap.appendChild(info);wrap.appendChild(ctrl); const audio=document.createElement('audio');audio.preload='auto';audio.style.position='absolute';audio.style.width='0';audio.style.height='0';audio.style.opacity='0';audio.style.pointerEvents='none'; const src=document.createElement('source');src.src=url;src.type=mime;audio.appendChild(src);audio.appendChild(document.createTextNode('不支持该格式')); let dragging=false;let anim=null; const fmt=s=>{if(isNaN(s))return '0:00';const m=Math.floor(s/60);const sec=Math.floor(s%60);return `${m}:${sec.toString().padStart(2,'0')}`;}; const update=()=>{if(!audio.duration||isNaN(audio.duration))return;const p=(audio.currentTime/audio.duration)*100;fill.style.width=`${p}%`;const rect=prog.getBoundingClientRect();thumb.style.left=`${(p/100)*rect.width}px`;const cur=time.querySelector('.rd-current-time');if(cur)cur.textContent=fmt(audio.currentTime);}; const setFromEvent=(cx)=>{const rect=prog.getBoundingClientRect();let x=cx-rect.left;x=Math.max(0,Math.min(x,rect.width));const p=(x/rect.width)*100;const nt=(p/100)*audio.duration;if(!isNaN(nt)){audio.currentTime=nt;update();}}; audio.addEventListener('timeupdate',()=>{if(!dragging)update();}); audio.addEventListener('loadedmetadata',()=>{const tot=time.querySelector('.rd-total-time');if(tot)tot.textContent=fmt(audio.duration);update();}); audio.addEventListener('ended',()=>{pp.innerHTML=Icons.play;}); pp.addEventListener('click',e=>{e.stopPropagation();if(audio.paused){audio.play().catch(()=>ResourceDiary.showToast('播放失败'));pp.innerHTML=Icons.pause;}else{audio.pause();pp.innerHTML=Icons.play;}}); prog.addEventListener('click',e=>{if(!audio.duration||isNaN(audio.duration))return;setFromEvent(e.clientX);}); const onMove=e=>{if(!dragging)return;setFromEvent(e.clientX);};const onUp=()=>{dragging=false;document.removeEventListener('mousemove',onMove);document.removeEventListener('mouseup',onUp);document.removeEventListener('touchmove',onTouchMove);document.removeEventListener('touchend',onTouchEnd);update();}; const onTouchMove=e=>{if(!dragging)return;e.preventDefault();setFromEvent(e.touches[0].clientX);};const onTouchEnd=e=>{onUp();}; prog.addEventListener('mousedown',e=>{e.preventDefault();if(!audio.duration||isNaN(audio.duration))return;dragging=true;setFromEvent(e.clientX);document.addEventListener('mousemove',onMove);document.addEventListener('mouseup',onUp);}); prog.addEventListener('touchstart',e=>{e.preventDefault();if(!audio.duration||isNaN(audio.duration))return;dragging=true;setFromEvent(e.touches[0].clientX);document.addEventListener('touchmove',onTouchMove,{passive:false});document.addEventListener('touchend',onTouchEnd);}); audio.play().then(()=>pp.innerHTML=Icons.pause).catch(()=>pp.innerHTML=Icons.play); wrap.appendChild(audio); const cleanup=()=>{audio.pause();audio.removeEventListener('timeupdate',update);audio.removeEventListener('loadedmetadata',update);audio.removeEventListener('ended',()=>{});if(anim)cancelAnimationFrame(anim);audio.src='';audio.load();}; return {element:wrap,cleanup}; }, playMedia(url){ if(!SecurityUtils.isSafeUrl(url)){this.showToast('不安全的媒体地址');return;} if(!this._shadowRoot)return; const realUrl=this.extractRealMediaUrl(url); this._shadowRoot.getElementById('rd-inline-player')?.remove(); const isAudio=/\.(mp3|wav|flac|aac|ogg|m4a|weba|oga|opus)$/i.test(realUrl); const mime=this.getMimeType(realUrl); const player=SecurityUtils.createElement('div',{id:'rd-inline-player',style:{borderRadius:'32px'}}); const header=SecurityUtils.createElement('div',{id:'rd-player-header'}); const title=SecurityUtils.createElement('span',{id:'rd-player-title'});title.innerHTML=(isAudio?Icons.music:Icons.film)+(isAudio?' 音频播放器':' 媒体播放器'); const close=SecurityUtils.createElement('button',{className:'rd-icon-btn',id:'rd-close-player',title:'关闭'});close.innerHTML=Icons.close; header.appendChild(title);header.appendChild(close);player.appendChild(header); const wrap=SecurityUtils.createElement('div',{id:'rd-media-wrapper'}); let customCleanup=null; if(isAudio){ const {element,cleanup}=this._createAudioPlayerUI(realUrl,mime,url);wrap.appendChild(element);customCleanup=cleanup; }else{ const video=document.createElement('video');video.id='rd-video';video.controls=true;video.autoplay=true;video.playsInline=true; const src=document.createElement('source');src.src=realUrl;src.type=mime;video.appendChild(src);video.appendChild(document.createTextNode('不支持该格式')); wrap.appendChild(video); const adjust=()=>{const c=wrap;if(!c||!video)return;const cw=c.clientWidth,ch=c.clientHeight;const vr=video.videoWidth/video.videoHeight,cr=cw/ch;if(vr>cr){video.style.width='100%';video.style.height='auto';}else{video.style.width='auto';video.style.height='100%;';}}; video.addEventListener('loadedmetadata',adjust,{once:true});video.addEventListener('canplay',adjust,{once:true}); const resizeHandler=()=>{if(this._shadowRoot?.getElementById('rd-inline-player'))adjust();else window.removeEventListener('resize',resizeHandler);}; window.addEventListener('resize',resizeHandler,{passive:true});this._listeners.push(()=>window.removeEventListener('resize',resizeHandler)); } player.appendChild(wrap); const handler=()=>{if(customCleanup)customCleanup();player.remove();}; close.addEventListener('click',handler); this._shadowRoot.appendChild(player); }, getMimeType(url){try{const u=new URL(url,location.href);const ext=u.pathname.split('.').pop()?.toLowerCase()||'';const map={mp4:'video/mp4',webm:'video/webm',ogg:'video/ogg',ogv:'video/ogg',mov:'video/quicktime',avi:'video/x-msvideo',mkv:'video/x-matroska',flv:'video/x-flv',m3u8:'application/x-mpegURL',mpd:'application/dash+xml',mp3:'audio/mpeg',wav:'audio/wav',flac:'audio/flac',aac:'audio/aac',m4a:'audio/mp4',wma:'audio/x-ms-wma',oga:'audio/ogg',weba:'audio/webm',opus:'audio/opus'};return map[ext]||'video/mp4';}catch(e){return'video/mp4';}}, manualRefresh(){ const entries=performance.getEntriesByType('resource');const processed=new Set(); entries.forEach(entry=>{ if(!entry.name||processed.has(entry.name))return;processed.add(entry.name); const url=entry.name;if(!SecurityUtils.isSafeUrl(url))return;if(processedUrls.has(url))return; const status=entry.responseStatus||200;if(status>=400)return; const displayType=this.getDisplayType(url,entry.responseContentType||'',entry.initiatorType); const filterType=this.getFilterType(displayType);processedUrls.add(url); let size=entry.transferSize||entry.encodedBodySize||0;if((url.startsWith('data:')||url.startsWith('blob:'))&&size===0)size=url.length; this.addResource({url,displayType,filterType,status,size,duration:entry.duration||0,cached:entry.transferSize===0&&entry.encodedBodySize>0}); }); }, destroy(){ this.isDestroyed=true; if(this._bodyCheckInterval){clearInterval(this._bodyCheckInterval);this._bodyCheckInterval=null;} if(this._refreshTimer){clearInterval(this._refreshTimer);this._refreshTimer=null;} if(this._rafId){cancelAnimationFrame(this._rafId);this._rafId=null;} if(this._resourceObserver){this._resourceObserver.disconnect();this._resourceObserver=null;} this._listeners.forEach(c=>c());this._listeners=[]; XMLHttpRequest.prototype.open=OriginalAPIs.xhrOpen; XMLHttpRequest.prototype.send=OriginalAPIs.xhrSend; window.fetch=OriginalAPIs.fetch; history.pushState=OriginalAPIs.pushState; history.replaceState=OriginalAPIs.replaceState; this.destroyUI();this.resources=[];this.filteredResources=[];processedUrls.clear();delete window.ResourceDiary;this.isInitialized=false; } }; RD.init(); window.ResourceDiary=RD; window.addEventListener('beforeunload',()=>{if(window.ResourceDiary)window.ResourceDiary.destroy();},{once:true}); })();