diff --git a/docs/TODO.md b/docs/TODO.md index 170e4e1..81aa318 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -12,8 +12,13 @@ ## Page Clipping + Highlight - [x] 계획서 작성 (`docs/CLIPPING_HIGHLIGHT_PLAN.md`) -- [ ] Step 1: 텍스트 선택 캡처(`Selection` + `Range`)와 하이라이트 렌더러 구현 -- [ ] Step 2: 저장소/메시지 채널 추가 (`clipStore`, background relay) -- [ ] Step 3: Popup/History UI에 클립 목록, 재이동(스크롤), 삭제 기능 추가 -- [ ] Step 4: 페이지 재진입 시 하이라이트 복원(anchoring) 및 깨진 앵커 fallback 처리 -- [ ] Step 5: 내보내기/가져오기(JSON)와 기본 회귀 테스트 시나리오 정리 +- [x] Step 1: 텍스트 선택 캡처(`Selection` + `Range`)와 하이라이트 렌더러 구현 +- [x] Step 2: 저장소/메시지 채널 추가 (`clipStore`, background relay) +- [x] Step 3: Popup/History UI에 클립 목록, 재이동(스크롤), 삭제 기능 추가 +- [x] Step 4: 페이지 재진입 시 하이라이트 복원(anchoring) 및 깨진 앵커 fallback 처리 +- [x] Step 5: 내보내기/가져오기(JSON)와 기본 회귀 테스트 시나리오 정리 + +## Obsidian Integration +- [x] Step 1: 현재 페이지 클립 Markdown 내보내기(Obsidian 친화 포맷) +- [x] Step 2: Markdown 클립보드 복사 버튼 추가 +- [x] Step 3: Obsidian URI 스킴(`obsidian://`) 직접 전송 옵션 추가 diff --git a/manifest.config.ts b/manifest.config.ts index c435088..e54713a 100644 --- a/manifest.config.ts +++ b/manifest.config.ts @@ -28,6 +28,15 @@ export default defineManifest({ }, }, options_page: 'src/config/index.html', + commands: { + create_clip_from_selection: { + suggested_key: { + default: 'Ctrl+Shift+Y', + mac: 'Command+Shift+Y', + }, + description: 'Create clip from current text selection', + }, + }, content_scripts: [ { matches: [''], @@ -36,7 +45,7 @@ export default defineManifest({ all_frames: true, }, ], - permissions: ['downloads', 'downloads.shelf', 'notifications', 'storage', 'contextMenus', 'cookies', 'webRequest', 'nativeMessaging'], + permissions: ['downloads', 'downloads.shelf', 'notifications', 'storage', 'contextMenus', 'cookies', 'webRequest', 'nativeMessaging', 'scripting'], host_permissions: [''], web_accessible_resources: [ { diff --git a/package.json b/package.json index bf3b2d3..ba0089d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "gomdown-helper", "private": true, - "version": "0.0.16", + "version": "0.0.64", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/chrome/.vite/manifest.json b/packages/chrome/.vite/manifest.json index d8c8fa2..ac9a476 100644 --- a/packages/chrome/.vite/manifest.json +++ b/packages/chrome/.vite/manifest.json @@ -1,6 +1,6 @@ { "../../../../../../../@crx/manifest": { - "file": "assets/crx-manifest.js-CXu7hmTa.js", + "file": "assets/crx-manifest.js-DFyiZccP.js", "name": "crx-manifest.js", "src": "../../../../../../../@crx/manifest", "isEntry": true @@ -12,26 +12,31 @@ "_settings-CgBxHrrF.js" ] }, + "_clipTypes-C_ha5Ash.js": { + "file": "assets/clipTypes-C_ha5Ash.js", + "name": "clipTypes" + }, "_downloadIntent-Dv31jC2S.js": { "file": "assets/downloadIntent-Dv31jC2S.js", "name": "downloadIntent" }, - "_index.ts-loader-D_eQmgUa.js": { - "file": "assets/index.ts-loader-D_eQmgUa.js", - "src": "_index.ts-loader-D_eQmgUa.js" + "_index.ts-loader-2I0oIARK.js": { + "file": "assets/index.ts-loader-2I0oIARK.js", + "src": "_index.ts-loader-2I0oIARK.js" }, "_settings-CgBxHrrF.js": { "file": "assets/settings-CgBxHrrF.js", "name": "settings" }, "src/background/index.ts": { - "file": "assets/index.ts-U8lbRRO-.js", + "file": "assets/index.ts-BkGMAUD4.js", "name": "index.ts", "src": "src/background/index.ts", "isEntry": true, "imports": [ "_settings-CgBxHrrF.js", - "_downloadIntent-Dv31jC2S.js" + "_downloadIntent-Dv31jC2S.js", + "_clipTypes-C_ha5Ash.js" ] }, "src/config/index.html": { @@ -48,26 +53,28 @@ ] }, "src/content/index.ts": { - "file": "assets/index.ts-w1ilzv93.js", + "file": "assets/index.ts-DQGjv8iX.js", "name": "index.ts", "src": "src/content/index.ts", "isEntry": true, "imports": [ "_settings-CgBxHrrF.js", - "_downloadIntent-Dv31jC2S.js" + "_downloadIntent-Dv31jC2S.js", + "_clipTypes-C_ha5Ash.js" ] }, "src/popup/index.html": { - "file": "assets/index.html-92_ZB8wX.js", + "file": "assets/index.html-ClVBeFHX.js", "name": "index.html", "src": "src/popup/index.html", "isEntry": true, "imports": [ "_client-BzjyOx7y.js", - "_settings-CgBxHrrF.js" + "_settings-CgBxHrrF.js", + "_clipTypes-C_ha5Ash.js" ], "css": [ - "assets/index-CJaGAyoX.css" + "assets/index-xoGXBrzN.css" ] } } \ No newline at end of file diff --git a/packages/chrome/assets/clipTypes-C_ha5Ash.js b/packages/chrome/assets/clipTypes-C_ha5Ash.js new file mode 100644 index 0000000..abf2674 --- /dev/null +++ b/packages/chrome/assets/clipTypes-C_ha5Ash.js @@ -0,0 +1 @@ +function n(r){try{const t=new URL(r);return t.hash="",t.toString()}catch{return String(r||"").trim()}}function e(r){return String(r||"").replace(/\s+/g," ").trim()}export{e as a,n}; diff --git a/packages/chrome/assets/index-CJaGAyoX.css b/packages/chrome/assets/index-xoGXBrzN.css similarity index 63% rename from packages/chrome/assets/index-CJaGAyoX.css rename to packages/chrome/assets/index-xoGXBrzN.css index d8b30c1..91462cd 100644 --- a/packages/chrome/assets/index-CJaGAyoX.css +++ b/packages/chrome/assets/index-xoGXBrzN.css @@ -1 +1 @@ -:root{color-scheme:dark;font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}body{margin:0;background:#151821;color:#e7ebf7;width:360px}.container{padding:14px;display:grid;gap:10px}.top-row{display:flex;align-items:center;justify-content:space-between;gap:8px}h1{margin:0;font-size:14px}.power-toggle{height:28px;min-width:70px;border-radius:999px;padding:0 12px;display:inline-flex;align-items:center;justify-content:center;gap:6px;font-size:11px;font-weight:800;letter-spacing:.04em}.power-toggle.on{background:#204f37;border-color:#2b7a52;color:#c7ffe3}.power-toggle.off{background:#4a2631;border-color:#75404d;color:#ffd6df}.power-dot{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.9}.field{display:grid;gap:6px}label{font-size:12px;color:#aeb6cc}input[type=text],input[type=number]{height:32px;border:1px solid #3e4658;border-radius:6px;padding:0 10px;background:#202532;color:#e7ebf7}.toggle{display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#cdd5ea}button{height:34px;border:1px solid #5562f0;border-radius:8px;background:#5562f0;color:#fff;font-weight:600;cursor:pointer}.media-panel{margin-top:6px;border:1px solid #384255;border-radius:8px;padding:8px;background:#1b202c;display:grid;gap:8px}.media-head{display:flex;align-items:center;justify-content:space-between;font-size:12px}.media-list{display:grid;gap:6px;max-height:150px;overflow:auto}.media-item{display:flex;align-items:center;justify-content:space-between;gap:8px}.media-meta{min-width:0;display:grid;gap:2px}.kind{font-size:11px;color:#8fc0ff}.url{font-size:11px;color:#c6d1e8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:250px}.mini{height:26px;min-width:44px;padding:0 8px;border-radius:6px;font-size:11px}.mini.ghost{background:#2a3140;border-color:#47546c;color:#d4def2}.empty{font-size:11px;color:#96a3bc}.status{font-size:12px;color:#8fe0a6;min-height:14px} +:root{color-scheme:dark;font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}body{margin:0;background:#151821;color:#e7ebf7;width:360px}.container{padding:14px;display:grid;gap:10px}.top-row{display:flex;align-items:center;justify-content:space-between;gap:8px}h1{margin:0;font-size:14px}.power-toggle{height:28px;min-width:70px;border-radius:999px;padding:0 12px;display:inline-flex;align-items:center;justify-content:center;gap:6px;font-size:11px;font-weight:800;letter-spacing:.04em}.power-toggle.on{background:#204f37;border-color:#2b7a52;color:#c7ffe3}.power-toggle.off{background:#4a2631;border-color:#75404d;color:#ffd6df}.power-dot{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.9}.field{display:grid;gap:6px}label{font-size:12px;color:#aeb6cc}input[type=text],input[type=number]{height:32px;border:1px solid #3e4658;border-radius:6px;padding:0 10px;background:#202532;color:#e7ebf7}.toggle{display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#cdd5ea}button{height:34px;border:1px solid #5562f0;border-radius:8px;background:#5562f0;color:#fff;font-weight:600;cursor:pointer}.media-panel{margin-top:6px;border:1px solid #384255;border-radius:8px;padding:8px;background:#1b202c;display:grid;gap:8px}.media-head{display:flex;align-items:center;justify-content:space-between;font-size:12px}.hint{font-size:10px;color:#9eadcb}.media-list{display:grid;gap:6px;max-height:150px;overflow:auto}.media-item{display:flex;align-items:center;justify-content:space-between;gap:8px}.clip-item{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.clip-actions{display:flex;align-items:center;gap:6px}.media-meta{min-width:0;display:grid;gap:2px}.kind{font-size:11px;color:#8fc0ff}.url{font-size:11px;color:#c6d1e8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:250px}.mini{height:26px;min-width:44px;padding:0 8px;border-radius:6px;font-size:11px}.mini.ghost{background:#2a3140;border-color:#47546c;color:#d4def2}.empty{font-size:11px;color:#96a3bc}.status{font-size:12px;color:#8fe0a6;min-height:14px} diff --git a/packages/chrome/assets/index.html-92_ZB8wX.js b/packages/chrome/assets/index.html-92_ZB8wX.js deleted file mode 100644 index 5314395..0000000 --- a/packages/chrome/assets/index.html-92_ZB8wX.js +++ /dev/null @@ -1 +0,0 @@ -import{c as N,j as t,R as r}from"./client-BzjyOx7y.js";import{g as k,b as i,s as m}from"./settings-CgBxHrrF.js";function S(){const[s,d]=r.useState(null),[x,n]=r.useState(""),[l,u]=r.useState([]);r.useEffect(()=>{k().then(d)},[]),r.useEffect(()=>{let e=null;const a=async()=>{const o=await i.runtime.sendMessage({type:"media:list"});o?.ok&&Array.isArray(o.items)&&u(o.items.slice(0,10))};return a(),e=window.setInterval(()=>{a()},2e3),()=>{e!==null&&window.clearInterval(e)}},[]);const c=(e,a)=>{d(o=>o&&{...o,[e]:a})},p=async e=>{if(!s)return;const a={...s,extensionStatus:e};d(a),await m({extensionStatus:e}),n(e?"Extension ON":"Extension OFF"),window.setTimeout(()=>n(""),1200)},g=async()=>{s&&(await m(s),n("Saved"),window.setTimeout(()=>n(""),1200))},h=async()=>{const e=i.runtime.getURL("src/config/index.html");await i.tabs.create({url:e})},j=async()=>{const e=i.runtime.getURL("src/history/index.html");await i.tabs.create({url:e})},v=async()=>{const e=await i.runtime.sendMessage({type:"page:enqueue-ytdlp"});n(e?.ok?"Active tab sent to gdown (yt-dlp)":`Send failed: ${e?.error||"unknown error"}`),window.setTimeout(()=>n(""),1800)},w=async e=>{const a=await i.runtime.sendMessage({type:"media:enqueue",url:e.url,referer:e.referer||"",kind:e.kind,suggestedOut:e.suggestedOut||"",cookie:e.cookie||"",userAgent:e.userAgent||""});n(a?.ok?"Media sent to gdown":`Send failed: ${a?.error||"unknown error"}`),window.setTimeout(()=>n(""),1600)},y=async()=>{await i.runtime.sendMessage({type:"media:clear"}),u([]),n("Captured media cleared"),window.setTimeout(()=>n(""),1200)};return s?t.jsxs("div",{className:"container",children:[t.jsxs("div",{className:"top-row",children:[t.jsx("h1",{children:"Gomdown Helper"}),t.jsxs("button",{className:`power-toggle ${s.extensionStatus?"on":"off"}`,onClick:()=>{p(!s.extensionStatus)},children:[t.jsx("span",{className:"power-dot"}),s.extensionStatus?"ON":"OFF"]})]}),t.jsxs("div",{className:"field",children:[t.jsx("label",{children:"RPC Secret"}),t.jsx("input",{type:"text",value:s.motrixAPIkey,onChange:e=>c("motrixAPIkey",e.target.value),placeholder:"aria2 rpc secret"})]}),t.jsxs("div",{className:"field",children:[t.jsx("label",{children:"RPC Port"}),t.jsx("input",{type:"number",value:s.motrixPort,onChange:e=>c("motrixPort",Number(e.target.value||16800))})]}),t.jsxs("label",{className:"toggle",children:["Use Native Host",t.jsx("input",{type:"checkbox",checked:s.useNativeHost,onChange:e=>c("useNativeHost",e.target.checked)})]}),t.jsxs("label",{className:"toggle",children:["Activate gdown App",t.jsx("input",{type:"checkbox",checked:s.activateAppOnDownload,onChange:e=>c("activateAppOnDownload",e.target.checked)})]}),t.jsx("button",{onClick:g,children:"Save"}),t.jsx("button",{onClick:h,children:"Settings"}),t.jsx("button",{onClick:j,children:"History"}),t.jsx("button",{onClick:()=>{v()},children:"Send Active Tab (yt-dlp)"}),t.jsxs("div",{className:"media-panel",children:[t.jsxs("div",{className:"media-head",children:[t.jsx("strong",{children:"Captured Media"}),t.jsx("button",{className:"mini ghost",onClick:y,children:"Clear"})]}),l.length===0?t.jsx("div",{className:"empty",children:"No media captured yet"}):t.jsx("div",{className:"media-list",children:l.map(e=>t.jsxs("div",{className:"media-item",children:[t.jsxs("div",{className:"media-meta",children:[t.jsx("span",{className:"kind",children:e.kind.toUpperCase()}),e.pageTitle?t.jsx("span",{className:"url",children:e.pageTitle}):null,t.jsx("span",{className:"url",children:e.url})]}),t.jsx("button",{className:"mini",onClick:()=>{w(e)},children:"Add"})]},e.id))})]}),t.jsx("div",{className:"status",children:x})]}):t.jsx("div",{className:"container",children:"Loading..."})}N.createRoot(document.getElementById("root")).render(t.jsx(r.StrictMode,{children:t.jsx(S,{})})); diff --git a/packages/chrome/assets/index.html-ClVBeFHX.js b/packages/chrome/assets/index.html-ClVBeFHX.js new file mode 100644 index 0000000..a9889a2 --- /dev/null +++ b/packages/chrome/assets/index.html-ClVBeFHX.js @@ -0,0 +1 @@ +import{c as U,j as s,R as o}from"./client-BzjyOx7y.js";import{g as E,b as i,s as v}from"./settings-CgBxHrrF.js";import{n as R}from"./clipTypes-C_ha5Ash.js";function F(){const[a,u]=o.useState(null),[j,t]=o.useState(""),[x,h]=o.useState([]),[g,y]=o.useState(null),[N,k]=o.useState(""),[w,l]=o.useState([]);o.useEffect(()=>{E().then(u)},[]),o.useEffect(()=>{let e=null;const n=async()=>{const r=await i.runtime.sendMessage({type:"media:list"});r?.ok&&Array.isArray(r.items)&&h(r.items.slice(0,10))};return n(),e=window.setInterval(()=>{n()},2e3),()=>{e!==null&&window.clearInterval(e)}},[]),o.useEffect(()=>{const e=async()=>{const c=(await i.tabs.query({active:!0,currentWindow:!0}))[0],m=R(String(c?.url||""));if(y(Number.isInteger(c?.id)?c?.id:null),k(m),!m){l([]);return}const p=await i.runtime.sendMessage({type:"clip:list",pageUrl:m});p?.ok&&Array.isArray(p.items)&&l(p.items)};e();const n=window.setInterval(()=>{e()},2500);return()=>{window.clearInterval(n)}},[]);const d=(e,n)=>{u(r=>r&&{...r,[e]:n})},f=async e=>{if(!a)return;const n={...a,extensionStatus:e};u(n),await v({extensionStatus:e}),t(e?"Extension ON":"Extension OFF"),window.setTimeout(()=>t(""),1200)},b=async()=>{a&&(await v(a),t("Saved"),window.setTimeout(()=>t(""),1200))},C=async()=>{const e=i.runtime.getURL("src/config/index.html");await i.tabs.create({url:e})},S=async()=>{const e=i.runtime.getURL("src/history/index.html");await i.tabs.create({url:e})},A=async()=>{const e=await i.runtime.sendMessage({type:"page:enqueue-ytdlp"});t(e?.ok?"Active tab sent to gdown (yt-dlp)":`Send failed: ${e?.error||"unknown error"}`),window.setTimeout(()=>t(""),1800)},T=async e=>{const n=await i.runtime.sendMessage({type:"media:enqueue",url:e.url,referer:e.referer||"",kind:e.kind,suggestedOut:e.suggestedOut||"",cookie:e.cookie||"",userAgent:e.userAgent||""});t(n?.ok?"Media sent to gdown":`Send failed: ${n?.error||"unknown error"}`),window.setTimeout(()=>t(""),1600)},M=async()=>{await i.runtime.sendMessage({type:"media:clear"}),h([]),t("Captured media cleared"),window.setTimeout(()=>t(""),1200)},I=async()=>{if(!Number.isInteger(g)){t("활성 탭을 찾을 수 없습니다."),window.setTimeout(()=>t(""),1600);return}const e=await i.tabs.sendMessage(g,{type:"clip:create-from-selection"});if(!e?.ok){t(`클립 생성 실패: ${e?.error||"선택 텍스트를 확인하세요"}`),window.setTimeout(()=>t(""),2e3);return}t("클립 저장 완료"),window.setTimeout(()=>t(""),1400);const n=await i.runtime.sendMessage({type:"clip:list",pageUrl:N});n?.ok&&Array.isArray(n.items)&&l(n.items)},P=async e=>{const n=await i.runtime.sendMessage({type:"clip:reveal",id:e});t(n?.ok?n.opened?"클립 페이지를 열었습니다":"클립 위치로 이동":`이동 실패: ${n?.error||"unknown error"}`),window.setTimeout(()=>t(""),1700)},O=async e=>{const n=await i.runtime.sendMessage({type:"clip:delete",id:e});if(!n?.ok){t(`삭제 실패: ${n?.error||"unknown error"}`),window.setTimeout(()=>t(""),1600);return}l(r=>r.filter(c=>c.id!==e)),t("클립 삭제 완료"),window.setTimeout(()=>t(""),1200)};return a?s.jsxs("div",{className:"container",children:[s.jsxs("div",{className:"top-row",children:[s.jsx("h1",{children:"Gomdown Helper"}),s.jsxs("button",{className:`power-toggle ${a.extensionStatus?"on":"off"}`,onClick:()=>{f(!a.extensionStatus)},children:[s.jsx("span",{className:"power-dot"}),a.extensionStatus?"ON":"OFF"]})]}),s.jsxs("div",{className:"field",children:[s.jsx("label",{children:"RPC Secret"}),s.jsx("input",{type:"text",value:a.motrixAPIkey,onChange:e=>d("motrixAPIkey",e.target.value),placeholder:"aria2 rpc secret"})]}),s.jsxs("div",{className:"field",children:[s.jsx("label",{children:"RPC Port"}),s.jsx("input",{type:"number",value:a.motrixPort,onChange:e=>d("motrixPort",Number(e.target.value||16800))})]}),s.jsxs("label",{className:"toggle",children:["Use Native Host",s.jsx("input",{type:"checkbox",checked:a.useNativeHost,onChange:e=>d("useNativeHost",e.target.checked)})]}),s.jsxs("label",{className:"toggle",children:["Activate gdown App",s.jsx("input",{type:"checkbox",checked:a.activateAppOnDownload,onChange:e=>d("activateAppOnDownload",e.target.checked)})]}),s.jsx("button",{onClick:b,children:"Save"}),s.jsx("button",{onClick:C,children:"Settings"}),s.jsx("button",{onClick:S,children:"History"}),s.jsx("button",{onClick:()=>{A()},children:"Send Active Tab (yt-dlp)"}),s.jsx("button",{onClick:()=>{I()},children:"Create Clip From Selection"}),s.jsxs("div",{className:"media-panel",children:[s.jsxs("div",{className:"media-head",children:[s.jsx("strong",{children:"Captured Media"}),s.jsx("button",{className:"mini ghost",onClick:M,children:"Clear"})]}),x.length===0?s.jsx("div",{className:"empty",children:"No media captured yet"}):s.jsx("div",{className:"media-list",children:x.map(e=>s.jsxs("div",{className:"media-item",children:[s.jsxs("div",{className:"media-meta",children:[s.jsx("span",{className:"kind",children:e.kind.toUpperCase()}),e.pageTitle?s.jsx("span",{className:"url",children:e.pageTitle}):null,s.jsx("span",{className:"url",children:e.url})]}),s.jsx("button",{className:"mini",onClick:()=>{T(e)},children:"Add"})]},e.id))})]}),s.jsxs("div",{className:"media-panel",children:[s.jsxs("div",{className:"media-head",children:[s.jsx("strong",{children:"Page Clips"}),s.jsx("span",{className:"hint",children:"Alt+Shift+C"})]}),w.length===0?s.jsx("div",{className:"empty",children:"No clips for this page"}):s.jsx("div",{className:"media-list",children:w.map(e=>s.jsxs("div",{className:"clip-item",children:[s.jsxs("div",{className:"media-meta",children:[s.jsx("span",{className:"kind",children:"CLIP"}),s.jsx("span",{className:"url",children:e.quote||e.anchor.exact})]}),s.jsxs("div",{className:"clip-actions",children:[s.jsx("button",{className:"mini",onClick:()=>{P(e.id)},children:"Go"}),s.jsx("button",{className:"mini ghost",onClick:()=>{O(e.id)},children:"Del"})]})]},e.id))})]}),s.jsx("div",{className:"status",children:j})]}):s.jsx("div",{className:"container",children:"Loading..."})}U.createRoot(document.getElementById("root")).render(s.jsx(o.StrictMode,{children:s.jsx(F,{})})); diff --git a/packages/chrome/assets/index.ts-BkGMAUD4.js b/packages/chrome/assets/index.ts-BkGMAUD4.js new file mode 100644 index 0000000..3a4deba --- /dev/null +++ b/packages/chrome/assets/index.ts-BkGMAUD4.js @@ -0,0 +1 @@ +import{b as a,g as m}from"./settings-CgBxHrrF.js";import{n as W,a as oe}from"./downloadIntent-Dv31jC2S.js";import{n as f,a as I}from"./clipTypes-C_ha5Ash.js";const Y="org.gdown.nativehost";async function ie(e){return a.runtime.sendNativeMessage(Y,{action:"addUri",...e})}async function ae(){return a.runtime.sendNativeMessage(Y,{action:"focus"})}const M="history";async function se(){const t=(await a.storage.local.get([M]))[M];return Array.isArray(t)?t:[]}async function ue(e){await a.storage.local.set({[M]:e.slice(0,300)})}async function ce(e){const t=await se(),r=t.findIndex(n=>n.gid===e.gid);r>=0?t[r]=e:t.unshift(e),await ue(t)}function Q(e,t){const r=Array.isArray(e?.responseHeaders)?e.responseHeaders:[],n=t.toLowerCase(),o=r.find(i=>String(i?.name||"").toLowerCase()===n);return String(o?.value||"")}function le(e){const t=e.toLowerCase();return t?t.includes("application/vnd.apple.mpegurl")||t.includes("application/x-mpegurl")||t.includes("audio/mpegurl")?"m3u8":t.includes("video/mp4")?"mp4":t.includes("application/octet-stream")&&t.includes("m3u8")?"m3u8":t.includes("hls")?"hls":"unknown":"unknown"}function de(e){const t=String(e||"").toLowerCase();return t.includes(".m3u8")?"m3u8":t.includes(".m3u")?"m3u":t.includes(".mp4")?"mp4":t.includes("m3u8")?"m3u8":t.includes("hls")?"hls":"unknown"}function X(e,t){const r=le(t);return r!=="unknown"?r:de(e)}function fe(e){if(!e?.url)return!1;const t=String(e?.method||"").toUpperCase();if(t&&t!=="GET")return!1;const r=Number(e?.statusCode||0);if(r>0&&(r<200||r>299))return!1;const n=String(e?.type||"");if(!["xmlhttprequest","media","other","main_frame","sub_frame","fetch"].includes(n))return!1;const o=Q(e,"content-type");return X(e.url,o)!=="unknown"}function pe(e,t=""){const r=Q(e,"content-type"),n=String(e?.url||""),o=X(n,r),i=Number.isInteger(e?.tabId)?Number(e.tabId):-1,s=Date.now();return{id:`${s}:${i}:${o}:${n}`,url:n,kind:o,tabId:i,pageUrl:String(e?.documentUrl||e?.initiator||""),referer:String(t||e?.documentUrl||e?.initiator||""),contentType:r,detectedAt:s}}function $(e){try{const t=new URL(e);return`${t.protocol}//${t.host}${t.pathname}`.toLowerCase()}catch{return String(e||"").toLowerCase()}}const U="media_candidates",me=200;async function V(){const t=(await a.storage.local.get([U]))[U];return Array.isArray(t)?t:[]}async function ge(e){const t=[...e].sort((r,n)=>n.detectedAt-r.detectedAt);await a.storage.local.set({[U]:t.slice(0,me)})}async function we(e,t){const r=await V(),n=r.findIndex(o=>{try{const i=new URL(o.url);return`${i.protocol}//${i.host}${i.pathname}`.toLowerCase()===t}catch{return o.url.toLowerCase()===t}});n>=0?r[n]={...r[n],...e,detectedAt:Date.now()}:r.unshift(e),await ge(r)}async function ye(){await a.storage.local.set({[U]:[]})}const A="clips",he=500;function j(e,t){return Date.parse(t.createdAt||"")-Date.parse(e.createdAt||"")}function F(e){return`${f(e.pageUrl)}::${I(e.quote).toLowerCase()}`}async function b(){const t=(await a.storage.local.get([A]))[A];return Array.isArray(t)?t:[]}async function J(e){const t=[...e].sort(j).slice(0,he);await a.storage.local.set({[A]:t})}async function be(e){const t=f(e);return(await b()).filter(n=>f(n.pageUrl)===t).sort(j)}async function Se(e){return(await b()).find(n=>n.id===e)||null}async function ke(e){const t=await b(),r=Date.now(),n=F(e),o=t.find(i=>{const s=Date.parse(i.createdAt||"");return!Number.isFinite(s)||Math.abs(r-s)>8e3?!1:F(i)===n});return o||(t.unshift(e),await J(t),e)}async function Ue(e){const t=await b(),r=t.filter(n=>n.id!==e);return r.length===t.length?!1:(await J(r),!0)}const x=8e3,xe=7e3,L="gomdown-helper-download-context-menu-option",w=new Map,q=new Map,R=new Map,T=new Map,y=new Map,D=new Map,H=new Map;let O=!1,P=!1,z=!1,g=null;const Z="bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]/best",ve=[{hosts:["youtube.com","www.youtube.com","m.youtube.com","youtu.be"],extractor:"yt-dlp",format:Z}];function v(e){try{const t=new URL(e),r=(t.pathname||"/").replace(/\/+$/,"")||"/";return`${t.protocol}//${t.host}${r}`.toLowerCase()}catch{return String(e||"").toLowerCase()}}function p(e){const t=Date.now();for(const[r,n]of e.entries())n<=t&&e.delete(r)}function ee(e){const t=Date.now()+x;q.set(W(e),t),R.set(v(e),t)}function te(e){!Number.isInteger(e)||(e??-1)<0||D.set(e,Date.now()+x)}function Ce(e){p(q),p(R);const t=W(e);return q.has(t)||R.has(v(e))}function Ie(e){return p(D),!Number.isInteger(e)||(e??-1)<0?!1:D.has(e)}function Me(e){return p(T),T.has(v(e))}function Ae(e){T.set(v(e),Date.now()+xe)}function Le(e){return p(y),!!e&&y.has(e)}function qe(e){e&&y.set(e,Date.now()+x)}function Re(e){p(H);const t=$(e);return H.has(t)}function Te(e){H.set($(e),Date.now()+x)}async function De(){try{await ae()}catch{}}async function C(e){await a.notifications.create(`gomdown-notice-${Date.now()}`,{type:"basic",iconUrl:"/images/icon-large.png",title:"Gomdown Helper",message:e}).catch(()=>null)}async function d(e,t="",r,n,o,i){if(Me(e))return{ok:!1,error:"duplicate transfer suppressed"};const s=await m();if(!s.extensionStatus)return{ok:!1,error:"extension disabled"};if(!s.motrixAPIkey)return{ok:!1,error:"motrixAPIkey is not set"};try{const u=await ie({url:e,rpcPort:s.motrixPort,rpcSecret:s.motrixAPIkey,referer:t,split:64,out:o?.trim()||void 0,cookie:i?.cookie?.trim()||void 0,userAgent:i?.userAgent?.trim()||void 0,authorization:i?.authorization?.trim()||void 0,proxy:i?.proxy?.trim()||void 0,extractor:r==="yt-dlp"?"yt-dlp":void 0,format:r==="yt-dlp"?n||Z:void 0});if(!u?.ok)return{ok:!1,error:u?.error||"native host addUri failed"};s.activateAppOnDownload&&await De(),Ae(e);const c=String(u?.gid||u?.requestId||`pending-${Date.now()}`),l=(()=>{try{return new URL(e).pathname}catch{return""}})().split("/").filter(Boolean).pop()||e;return await ce({gid:c,downloader:"native",startTime:new Date().toISOString(),icon:"/images/32.png",name:decodeURIComponent(l),path:null,status:u?.pending?"queued":"downloading",size:0,downloaded:0}),s.enableNotifications&&await a.notifications.create(`gomdown-transfer-${Date.now()}`,{type:"basic",iconUrl:"/images/icon-large.png",title:"Gomdown Helper",message:"Download sent to gdown"}),{ok:!0}}catch(u){return{ok:!1,error:String(u)}}}function B(e){try{return new URL(e).hostname.toLowerCase()}catch{return""}}function re(e,t="",r=""){const n=[B(e),B(t)].filter(Boolean);for(const i of ve)if(n.some(s=>i.hosts.includes(s)))return{extractor:i.extractor,format:i.format};const o=r.toLowerCase();return o==="m3u8"||o==="m3u"||o==="hls"?{extractor:"yt-dlp",format:"best"}:o==="mp4"?{extractor:"aria2"}:{extractor:"aria2"}}function G(e,t){const r=t.toLowerCase(),n=e.find(o=>String(o?.name||"").toLowerCase()===r);return String(n?.value||"").trim()}async function He(e){if(e.type!=="main_frame"||(e.method||"").toUpperCase()!=="GET"||typeof e.statusCode=="number"&&(e.statusCode<200||e.statusCode>299))return!1;const t=await m();if(!t.extensionStatus||!t.motrixAPIkey)return!1;const r=String(Array.isArray(e?.responseHeaders)&&e.responseHeaders.find(o=>String(o?.name||"").toLowerCase()==="content-length")?.value||""),n=Number(r||0);return t.minFileSize>0&&n>0&&n=0){const ne=await a.tabs.get(u.tabId).catch(()=>null);c=String(ne?.title||"").trim()}const k=Fe(u.url,u.kind,c),l={...u,pageTitle:c||void 0,cookie:i||void 0,userAgent:s||void 0,suggestedOut:k||void 0};await we(l,$(l.url)),Te(l.url),l.tabId>=0&&await a.tabs.sendMessage(l.tabId,{type:"media:captured",kind:l.kind,url:l.url,suggestedOut:l.suggestedOut||""}).catch(()=>null)}function Ne(e){let t=e.trim().replace(/[\\/:*?"<>|]/g,"_").replace(/\s+/g," ").replace(/^\.+/,"").replace(/\.+$/,"");return t.length>180&&(t=t.slice(0,180).trim()),t}function _e(e){try{return new URL(e).pathname.toLowerCase().match(/\.([a-z0-9]{2,6})(?:$|[?#])/)?.[1]||""}catch{return""}}function Fe(e,t,r){const n=Ne(r||""),i=_e(e)||(t==="mp4"||t==="m3u8"||t==="m3u"||t==="hls"?"mp4":"");return n?!i||n.toLowerCase().endsWith(`.${i}`)?n:`${n}.${i}`:""}async function S(){const e=a.downloads;if(!e.setShelfEnabled)return;const t=await m();if(!t.extensionStatus)return;const r=t.useNativeHost?!1:!t.hideChromeBar;await e.setShelfEnabled(r)}function E(){P||(P=!0,a.downloads.onCreated.addListener(async e=>{await S();const t=e,r=t.finalUrl||t.url||"";!Ce(r)&&!Ie(t.tabId)||(await a.downloads.cancel(e.id).catch(()=>null),await a.downloads.erase({id:e.id}).catch(()=>null),await a.downloads.removeFile(e.id).catch(()=>null))}))}function N(){O||(O=!0,a.webRequest.onSendHeaders.addListener(e=>{w.set(e.requestId,e)},{urls:[""]},["requestHeaders","extraHeaders"]),a.webRequest.onErrorOccurred.addListener(e=>{w.delete(e.requestId),y.delete(String(e.requestId))},{urls:[""]}),a.webRequest.onCompleted.addListener(e=>{w.delete(e.requestId),y.delete(String(e.requestId))},{urls:[""]}),a.webRequest.onHeadersReceived.addListener(e=>{$e(e),Ee(e)},{urls:[""]},["responseHeaders"]))}async function K(e,t){console.log("[gomdown-helper] context menu clicked",{menuItemId:e?.menuItemId,linkUrl:e?.linkUrl,srcUrl:e?.srcUrl,frameUrl:e?.frameUrl,pageUrl:e?.pageUrl,tabUrl:t?.url});const r=e?.menuItemId;if(r!=null&&String(r)!==L)return;const n=String(e?.linkUrl||e?.srcUrl||"").trim(),o=String(e?.frameUrl||e?.pageUrl||t?.url||"").trim(),s=String(n||o||"").trim();if(!s||/^(about:|chrome:|chrome-extension:|edge:|brave:)/i.test(s)){await C("다운로드 가능한 URL을 찾지 못했습니다.");return}const u=re(s,String(e?.pageUrl||t?.url||""),""),c=await d(s,String(e?.pageUrl||t?.url||""),u.extractor,u.format);if(!c.ok){await C(`전송 실패: ${c.error||"unknown error"}`);return}await C(u.extractor==="yt-dlp"?"페이지 URL을 yt-dlp로 gdown에 전송했습니다.":"gdown으로 전송했습니다.")}function Oe(){if(typeof chrome>"u"||!chrome.contextMenus?.create){a.contextMenus.create({id:L,title:"Download with Gomdown",visible:!0,contexts:["all"]});return}chrome.contextMenus.create({id:L,title:"Download with Gomdown",contexts:["all"]},()=>{chrome.runtime.lastError})}function _(){z||(typeof chrome<"u"&&chrome.contextMenus?.onClicked?chrome.contextMenus.onClicked.addListener((e,t)=>{K(e,t)}):a.contextMenus.onClicked.addListener((e,t)=>{K(e,t)}),z=!0)}async function Pe(){const e=await m();if(!e.extensionStatus||!e.showContextOption){await a.contextMenus.removeAll().catch(()=>null);return}await a.contextMenus.removeAll().catch(()=>null),Oe()}function h(){return g||(g=Pe().finally(()=>{g=null}),g)}function ze(){try{return crypto.randomUUID()}catch{return`clip-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}}async function Be(e){const t=f(e),n=(await a.tabs.query({})).find(o=>f(String(o.url||""))===t);return Number.isInteger(n?.id)?n?.id:null}a.runtime.onMessage.addListener((e,t)=>{if(e?.type==="capture-link-download"){const r=String(e?.url||"").trim();if(!r)return Promise.resolve({ok:!1,error:"url is empty"});const n=Number(t?.tab?.id);return d(r,String(e?.referer||"")).then(o=>(o.ok&&(ee(r),te(n)),o))}if(e?.type==="media:list")return V().then(r=>({ok:!0,items:r}));if(e?.type==="media:clear")return ye().then(()=>({ok:!0}));if(e?.type==="media:enqueue"){const r=String(e?.url||"").trim(),n=String(e?.kind||"").trim(),o=String(e?.suggestedOut||"").trim(),i=String(e?.referer||"").trim(),s=String(e?.cookie||"").trim(),u=String(e?.userAgent||"").trim();if(!r)return Promise.resolve({ok:!1,error:"url is empty"});const c=re(r,i,n);return d(r,i,c.extractor,c.format,o,{cookie:s,userAgent:u}).then(k=>k)}if(e?.type==="page:enqueue-ytdlp")return a.tabs.query({active:!0,currentWindow:!0}).then(async r=>{const n=r[0],o=String(n?.url||"").trim();return o?d(o,o,"yt-dlp"):{ok:!1,error:"active tab url is empty"}});if(e?.type==="page:enqueue-ytdlp-url"){const r=String(e?.url||"").trim(),n=String(e?.referer||r).trim();return r?d(r,n||r,"yt-dlp"):Promise.resolve({ok:!1,error:"url is empty"})}if(e?.type==="clip:create")return m().then(async r=>{if(!r.extensionStatus)return{ok:!1,error:"extension disabled"};const n=f(String(e?.pageUrl||t?.tab?.url||"")),o=String(e?.pageTitle||t?.tab?.title||"").trim(),i=I(String(e?.quote||e?.anchor?.exact||"")),s=e?.anchor;if(!n)return{ok:!1,error:"pageUrl is empty"};if(!s||!String(s.exact||"").trim())return{ok:!1,error:"anchor is empty"};const u={id:ze(),tabId:Number.isInteger(t?.tab?.id)?Number(t.tab.id):void 0,pageUrl:n,pageTitle:o||n,quote:i||I(String(s.exact||"")),createdAt:new Date().toISOString(),color:"yellow",anchor:s};return{ok:!0,item:await ke(u)}});if(e?.type==="clip:list"){const r=String(e?.pageUrl||"").trim();return r?be(r).then(n=>({ok:!0,items:n})):b().then(n=>({ok:!0,items:n}))}if(e?.type==="clip:delete"){const r=String(e?.id||"").trim();return r?Ue(r).then(n=>({ok:n})):Promise.resolve({ok:!1,error:"id is empty"})}if(e?.type==="clip:reveal"){const r=String(e?.id||"").trim();return r?Se(r).then(async n=>{if(!n)return{ok:!1,error:"clip not found"};const o=Number.isInteger(n.tabId)&&(n.tabId||0)>=0?n.tabId:await Be(n.pageUrl);if(!Number.isInteger(o)||o<0){const i=await a.tabs.create({url:n.pageUrl,active:!0}).catch(()=>null);return Number.isInteger(i?.id)?{ok:!0,opened:!0}:{ok:!1,error:"failed to open clip page"}}return await a.tabs.update(o,{active:!0}).catch(()=>null),await a.tabs.sendMessage(o,{type:"clip:reveal",id:n.id}).catch(()=>null),{ok:!0}}):Promise.resolve({ok:!1,error:"id is empty"})}});a.runtime.onInstalled.addListener(()=>{console.log("[gomdown-helper] onInstalled"),N(),E(),_(),h(),S()});a.runtime.onStartup.addListener(()=>{console.log("[gomdown-helper] onStartup"),N(),E(),_(),h(),S()});a.storage.onChanged.addListener((e,t)=>{t==="sync"&&((e.hideChromeBar||e.useNativeHost||e.extensionStatus)&&(S(),h()),e.showContextOption&&h())});N();E();_();h();S();console.log("[gomdown-helper] service worker initialized"); diff --git a/packages/chrome/assets/index.ts-DQGjv8iX.js b/packages/chrome/assets/index.ts-DQGjv8iX.js new file mode 100644 index 0000000..972e7c3 --- /dev/null +++ b/packages/chrome/assets/index.ts-DQGjv8iX.js @@ -0,0 +1 @@ +import{b as p,g as B}from"./settings-CgBxHrrF.js";import{i as w,n as W}from"./downloadIntent-Dv31jC2S.js";import{n as g,a as q}from"./clipTypes-C_ha5Ash.js";function M(){const e=document.body||document.documentElement;if(!e)return[];const t=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),n=[];let r=0,o=t.nextNode();for(;o;){const i=o,l=(i.nodeValue||"").length;l>0&&(n.push({node:i,start:r,end:r+l}),r+=l),o=t.nextNode()}return n}function H(e){return e.map(t=>t.node.nodeValue||"").join("")}function I(e){const t=document.body||document.documentElement;if(!t)return"";if(e===t)return"/body";const n=[];let r=e.nodeType===Node.TEXT_NODE?e.parentNode:e;for(;r&&r!==t&&r.nodeType===Node.ELEMENT_NODE;){const o=r,i=o.tagName.toLowerCase();let s=1,l=o.previousElementSibling;for(;l;)l.tagName.toLowerCase()===i&&(s+=1),l=l.previousElementSibling;n.unshift(`${i}[${s}]`),r=o.parentElement}return`/body/${n.join("/")}`}function P(e){if(!e)return null;try{return document.evaluate(e,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}catch{return null}}function V(e){const t=e.commonAncestorContainer,n=t.nodeType===Node.ELEMENT_NODE?t:t.parentElement;return!(!n||n.closest("input, textarea, select, button, script, style")||n.closest('[contenteditable="true"]'))}function Y(e,t,n){const r=e.slice(Math.max(0,t-40),t).trim(),o=e.slice(n,Math.min(e.length,n+40)).trim();return{prefix:r,suffix:o}}function Q(e,t){const n=e.startContainer,r=e.endContainer;if(n.nodeType!==Node.TEXT_NODE||r.nodeType!==Node.TEXT_NODE)return null;const o=t.find(s=>s.node===n),i=t.find(s=>s.node===r);return!o||!i?null:{start:o.start+e.startOffset,end:i.start+e.endOffset}}function R(e,t){if(!Number.isFinite(e)||!Number.isFinite(t)||e>=t)return null;const n=M(),r=n.find(s=>e>=s.start&&et>s.start&&t<=s.end);if(!r||!o)return null;const i=document.createRange();return i.setStart(r.node,Math.max(0,Math.min(r.node.length,e-r.start))),i.setEnd(o.node,Math.max(0,Math.min(o.node.length,t-o.start))),i}function j(e){if(!e.xpathStart||!e.xpathEnd)return null;const t=P(e.xpathStart),n=P(e.xpathEnd);if(!t||!n||t.nodeType!==Node.ELEMENT_NODE||n.nodeType!==Node.ELEMENT_NODE)return null;const r=l=>{const b=document.createTreeWalker(l,NodeFilter.SHOW_TEXT).nextNode();return b&&b.nodeType===Node.TEXT_NODE?b:null},o=r(t),i=r(n);if(!o||!i||o.nodeType!==Node.TEXT_NODE||i.nodeType!==Node.TEXT_NODE||!Number.isInteger(e.startOffset)||!Number.isInteger(e.endOffset))return null;const s=document.createRange();return s.setStart(o,Math.min((o.nodeValue||"").length,Math.max(0,e.startOffset||0))),s.setEnd(i,Math.min((i.nodeValue||"").length,Math.max(0,e.endOffset||0))),s}function G(e){const t=String(e.exact||"");if(!t)return null;const n=M(),r=H(n);let o=r.indexOf(t);if(o<0)return null;const i=String(e.prefix||""),s=String(e.suffix||"");if(!i&&!s)return{start:o,end:o+t.length};for(;o>=0;){const l=r.slice(Math.max(0,o-i.length),o).trim(),S=r.slice(o+t.length,o+t.length+s.length).trim();if((!i||l===i)&&(!s||S===s))return{start:o,end:o+t.length};o=r.indexOf(t,o+t.length)}return null}function J(e){if(!e.rangeCount)return null;const t=e.getRangeAt(0);if(t.collapsed||!V(t))return null;const n=e.toString();if(!n.trim())return null;const r=M(),o=Q(t,r),i={exact:n};if(t.startContainer.nodeType===Node.TEXT_NODE&&t.endContainer.nodeType===Node.TEXT_NODE){const s=t.startContainer,l=t.endContainer;i.xpathStart=I(s),i.xpathEnd=I(l),i.startOffset=t.startOffset,i.endOffset=t.endOffset}if(o){i.startTextOffset=o.start,i.endTextOffset=o.end;const s=H(r),l=Y(s,o.start,o.end);l.prefix&&(i.prefix=l.prefix),l.suffix&&(i.suffix=l.suffix)}return{anchor:i,quote:n}}function Z(e){if(Number.isInteger(e.startTextOffset)&&Number.isInteger(e.endTextOffset)){const r=R(e.startTextOffset||0,e.endTextOffset||0);if(r&&!r.collapsed)return r}const t=G(e);if(t){const r=R(t.start,t.end);if(r&&!r.collapsed)return r}const n=j(e);return n&&!n.collapsed?n:null}const ee=8e3,m=new Map;let a=!1,A=null,T=g(window.location.href);function te(){const e=Date.now();for(const[t,n]of m.entries())n<=e&&m.delete(t)}async function x(e,t){if(!a)return!1;const n=W(e,window.location.href);if(!n)return!1;if(te(),m.has(n))return!0;m.set(n,Date.now()+ee);try{if((await p.runtime.sendMessage({type:"capture-link-download",url:n,referer:t||document.referrer||window.location.href}))?.ok)return!0}catch{}return m.delete(n),!1}function L(e){return e?e instanceof HTMLAnchorElement?e:e instanceof Element?e.closest("a[href]"):null:null}function D(e){return!!(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)}async function U(e){if(!a||e.defaultPrevented||D(e))return;const t=L(e.target);if(!t)return;const n=t.href||"";!n||!w(n,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),await x(n,document.referrer||window.location.href))}function X(e){if(!a)return;const t=L(e.target);if(!t)return;const n=t.href||"";!n||!w(n,window.location.href)||D(e)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),x(n,document.referrer||window.location.href))}document.addEventListener("pointerdown",e=>{e.button===0&&X(e)},!0);document.addEventListener("mousedown",e=>{e.button===0&&X(e)},!0);document.addEventListener("click",e=>{e.button===0&&U(e)},!0);document.addEventListener("keydown",e=>{if(!a||e.key!=="Enter"||e.defaultPrevented||D(e))return;const t=L(e.target);if(!t)return;const n=t.href||"";!n||!w(n,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),x(n,document.referrer||window.location.href))},!0);document.addEventListener("keydown",e=>{a&&(e.defaultPrevented||e.altKey&&e.shiftKey&&(e.metaKey||e.ctrlKey||e.key.toLowerCase()==="c"&&(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),$())))},!0);document.addEventListener("auxclick",e=>{e.button===1&&U(e)},!0);function ne(){try{const e=window.open.bind(window);window.open=function(n,r,o){const i=String(n||"").trim();return a&&i&&w(i,window.location.href)?(x(i,window.location.href),null):e(n,r,o)}}catch{}try{const e=HTMLAnchorElement.prototype.click;HTMLAnchorElement.prototype.click=function(){const n=this.href||this.getAttribute("href")||"";if(a&&n&&w(n,window.location.href)){x(n,document.referrer||window.location.href);return}e.call(this)}}catch{}}ne();let y=null,f=null,v=!1,F=null,E=window.location.href;function re(e){try{const t=new URL(e);return t.hostname!=="www.youtube.com"&&t.hostname!=="youtube.com"?!1:t.pathname==="/watch"&&t.searchParams.has("v")}catch{return!1}}function k(e,t="idle"){f&&(f.textContent=e,t==="ok"?f.style.color="#8ff0a4":t==="error"?f.style.color="#ff9b9b":f.style.color="#aeb7d8")}async function oe(){if(!v){v=!0,k("gdown으로 전송 중...");try{const e=await p.runtime.sendMessage({type:"page:enqueue-ytdlp-url",url:window.location.href,referer:window.location.href});e?.ok?k("다운로드 모달로 전송됨","ok"):k(`전송 실패: ${e?.error||"unknown error"}`,"error")}catch(e){k(`전송 실패: ${String(e)}`,"error")}finally{v=!1}}}function C(){y&&(y.remove(),y=null,f=null)}function c(){if(!a){C();return}if(window.top!==window.self)return;if(!re(window.location.href)){C();return}if(y)return;const e=document.createElement("div");e.id="gomdown-youtube-overlay",e.style.position="fixed",e.style.right="20px",e.style.bottom="24px",e.style.zIndex="2147483647",e.style.background="rgba(17, 21, 32, 0.94)",e.style.border="1px solid rgba(133, 148, 195, 0.35)",e.style.borderRadius="12px",e.style.padding="10px",e.style.boxShadow="0 8px 24px rgba(0, 0, 0, 0.28)",e.style.backdropFilter="blur(6px)",e.style.width="220px",e.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.style.color="#e8edff";const t=document.createElement("div");t.textContent="Gdown Helper",t.style.fontSize="12px",t.style.fontWeight="700",t.style.marginBottom="8px";const n=document.createElement("button");n.type="button",n.textContent="이 영상 다운로드",n.style.width="100%",n.style.height="34px",n.style.border="1px solid #5a69f0",n.style.borderRadius="8px",n.style.background="#5a69f0",n.style.color="#ffffff",n.style.fontSize="12px",n.style.fontWeight="700",n.style.cursor="pointer",n.addEventListener("click",()=>{oe()});const r=document.createElement("div");r.textContent="클릭 시 gdown 다운로드 모달로 연결",r.style.fontSize="11px",r.style.marginTop="8px",r.style.lineHeight="1.35",r.style.color="#aeb7d8",e.appendChild(t),e.appendChild(n),e.appendChild(r),document.documentElement.appendChild(e),y=e,f=r}function ie(){F===null&&(F=window.setInterval(()=>{const e=window.location.href;e!==E&&(E=e,c())},800),window.addEventListener("popstate",()=>{E=window.location.href,c()}),document.addEventListener("yt-navigate-finish",()=>{E=window.location.href,c()}))}c();ie();function se(e){return e.color==="yellow","rgba(255, 235, 87, 0.58)"}function N(){const e=Array.from(document.querySelectorAll("span[data-gomdown-clip]"));for(const t of e){const n=t.parentNode;if(n){for(;t.firstChild;)n.insertBefore(t.firstChild,t);n.removeChild(t)}}}function O(e,t="ok"){const n=z();n.textContent=e,n.style.display="block",n.style.borderColor=t==="ok"?"rgba(123, 190, 124, 0.55)":"rgba(200, 113, 113, 0.55)",n.style.color=t==="ok"?"#dffbe4":"#ffe4e4",u!==null&&window.clearTimeout(u),u=window.setTimeout(()=>{n.style.display="none",u=null,n.style.borderColor="rgba(128, 140, 180, 0.42)",n.style.color="#dce4fa"},1800)}function le(e){const t=Z(e.anchor);if(!t||t.collapsed)return!1;const n=document.createElement("span");n.dataset.gomdownClip=e.id,n.style.background=se(e),n.style.padding="0.04em 0.03em",n.style.borderRadius="0.12em",n.style.boxDecorationBreak="clone",n.style.setProperty("-webkit-box-decoration-break","clone"),n.style.cursor="pointer",n.title=e.quote||"clip",n.addEventListener("click",r=>{(r.altKey||r.metaKey||r.ctrlKey)&&(r.stopPropagation(),r.preventDefault())});try{const r=t.extractContents();return n.appendChild(r),t.insertNode(n),!0}catch{return!1}}function _(e){const t=document.querySelector(`span[data-gomdown-clip="${CSS.escape(e)}"]`);return t?(t.scrollIntoView({behavior:"smooth",block:"center",inline:"nearest"}),t.animate([{boxShadow:"0 0 0 0 rgba(255, 250, 164, 0.2)"},{boxShadow:"0 0 0 8px rgba(255, 250, 164, 0.65)"},{boxShadow:"0 0 0 0 rgba(255, 250, 164, 0.2)"}],{duration:760,easing:"ease-out"}),!0):!1}async function d(e=!1){if(!a)return;const t=g(window.location.href),n=await p.runtime.sendMessage({type:"clip:list",pageUrl:t});if(!n?.ok||!Array.isArray(n.items))return;N();const r=[...n.items].sort((i,s)=>{const l=Number(i.anchor.startTextOffset||0);return Number(s.anchor.startTextOffset||0)-l});let o=0;for(const i of r)le(i)&&(o+=1);e&&O(`클립 복원: ${o}/${r.length}`,o>0?"ok":"error")}async function $(){if(!a)return{ok:!1,error:"extension disabled"};const e=window.getSelection();if(!e)return{ok:!1,error:"selection unavailable"};const t=J(e);if(!t)return O("선택된 텍스트가 없습니다.","error"),{ok:!1,error:"empty selection"};const n=await p.runtime.sendMessage({type:"clip:create",pageUrl:g(window.location.href),pageTitle:document.title||window.location.href,quote:q(t.quote),anchor:t.anchor});return!n?.ok||!n.item?(O(`클립 저장 실패: ${n?.error||"unknown error"}`,"error"),{ok:!1,error:n?.error||"create failed"}):(N(),await d(),O("클립 저장 완료 (Alt+Shift+C)","ok"),{ok:!0})}function ae(){A===null&&(A=window.setInterval(()=>{const e=g(window.location.href);e!==T&&(T=e,d())},900),window.addEventListener("popstate",()=>{const e=g(window.location.href);e!==T&&(T=e,d())}))}ae();let h=null,u=null;function K(){h&&(h.style.display="none",u!==null&&(window.clearTimeout(u),u=null))}function z(){if(h)return h;const e=document.createElement("div");return e.id="gomdown-media-toast",e.style.position="fixed",e.style.left="18px",e.style.bottom="18px",e.style.zIndex="2147483647",e.style.maxWidth="360px",e.style.padding="10px 12px",e.style.borderRadius="10px",e.style.border="1px solid rgba(128, 140, 180, 0.42)",e.style.background="rgba(18, 21, 31, 0.95)",e.style.color="#dce4fa",e.style.fontSize="12px",e.style.lineHeight="1.35",e.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.style.boxShadow="0 10px 24px rgba(0, 0, 0, 0.28)",e.style.display="none",document.documentElement.appendChild(e),h=e,e}function ue(e){if(!a)return;const t=z(),n=String(e?.kind||"media").toUpperCase(),r=String(e?.suggestedOut||"").trim(),o=String(e?.url||"").trim().slice(0,96);t.textContent=r?`캡처됨 [${n}] ${r}`:`캡처됨 [${n}] ${o}${o.length>=96?"…":""}`,t.style.display="block",u!==null&&window.clearTimeout(u),u=window.setTimeout(()=>{t.style.display="none",u=null},2200)}p.runtime.onMessage.addListener(e=>{if(e?.type==="clip:create-from-selection")return $();if(e?.type==="media:captured"){ue({kind:e?.kind,url:e?.url,suggestedOut:e?.suggestedOut});return}if(e?.type==="clip:reveal"){const t=String(e?.id||"").trim();return t?(_(t)||d(!0).then(()=>{_(t)}),{ok:!0}):void 0}});async function fe(){try{a=!!(await B()).extensionStatus}catch{a=!1}a?(c(),await d()):(C(),K(),N())}fe();p.storage.onChanged.addListener((e,t)=>{if(t==="sync"&&e.extensionStatus){if(a=!!e.extensionStatus.newValue,!a){C(),K(),N();return}c(),d()}}); diff --git a/packages/chrome/assets/index.ts-U8lbRRO-.js b/packages/chrome/assets/index.ts-U8lbRRO-.js deleted file mode 100644 index 551edde..0000000 --- a/packages/chrome/assets/index.ts-U8lbRRO-.js +++ /dev/null @@ -1 +0,0 @@ -import{b as i,g as h}from"./settings-CgBxHrrF.js";import{n as P,a as j}from"./downloadIntent-Dv31jC2S.js";const z="org.gdown.nativehost";async function J(e){return i.runtime.sendNativeMessage(z,{action:"addUri",...e})}async function Z(){return i.runtime.sendNativeMessage(z,{action:"focus"})}const C="history";async function ee(){const t=(await i.storage.local.get([C]))[C];return Array.isArray(t)?t:[]}async function te(e){await i.storage.local.set({[C]:e.slice(0,300)})}async function ne(e){const t=await ee(),n=t.findIndex(r=>r.gid===e.gid);n>=0?t[n]=e:t.unshift(e),await te(t)}function G(e,t){const n=Array.isArray(e?.responseHeaders)?e.responseHeaders:[],r=t.toLowerCase(),o=n.find(s=>String(s?.name||"").toLowerCase()===r);return String(o?.value||"")}function re(e){const t=e.toLowerCase();return t?t.includes("application/vnd.apple.mpegurl")||t.includes("application/x-mpegurl")||t.includes("audio/mpegurl")?"m3u8":t.includes("video/mp4")?"mp4":t.includes("application/octet-stream")&&t.includes("m3u8")?"m3u8":t.includes("hls")?"hls":"unknown":"unknown"}function oe(e){const t=String(e||"").toLowerCase();return t.includes(".m3u8")?"m3u8":t.includes(".m3u")?"m3u":t.includes(".mp4")?"mp4":t.includes("m3u8")?"m3u8":t.includes("hls")?"hls":"unknown"}function B(e,t){const n=re(t);return n!=="unknown"?n:oe(e)}function ie(e){if(!e?.url)return!1;const t=String(e?.method||"").toUpperCase();if(t&&t!=="GET")return!1;const n=Number(e?.statusCode||0);if(n>0&&(n<200||n>299))return!1;const r=String(e?.type||"");if(!["xmlhttprequest","media","other","main_frame","sub_frame","fetch"].includes(r))return!1;const o=G(e,"content-type");return B(e.url,o)!=="unknown"}function se(e,t=""){const n=G(e,"content-type"),r=String(e?.url||""),o=B(r,n),s=Number.isInteger(e?.tabId)?Number(e.tabId):-1,a=Date.now();return{id:`${a}:${s}:${o}:${r}`,url:r,kind:o,tabId:s,pageUrl:String(e?.documentUrl||e?.initiator||""),referer:String(t||e?.documentUrl||e?.initiator||""),contentType:n,detectedAt:a}}function q(e){try{const t=new URL(e);return`${t.protocol}//${t.host}${t.pathname}`.toLowerCase()}catch{return String(e||"").toLowerCase()}}const b="media_candidates",ae=200;async function W(){const t=(await i.storage.local.get([b]))[b];return Array.isArray(t)?t:[]}async function ue(e){const t=[...e].sort((n,r)=>r.detectedAt-n.detectedAt);await i.storage.local.set({[b]:t.slice(0,ae)})}async function ce(e,t){const n=await W(),r=n.findIndex(o=>{try{const s=new URL(o.url);return`${s.protocol}//${s.host}${s.pathname}`.toLowerCase()===t}catch{return o.url.toLowerCase()===t}});r>=0?n[r]={...n[r],...e,detectedAt:Date.now()}:n.unshift(e),await ue(n)}async function le(){await i.storage.local.set({[b]:[]})}const k=8e3,de=7e3,U="gomdown-helper-download-context-menu-option",m=new Map,M=new Map,I=new Map,L=new Map,w=new Map,R=new Map,A=new Map;let $=!1,E=!1,_=!1,p=null;const K="bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]/best",fe=[{hosts:["youtube.com","www.youtube.com","m.youtube.com","youtu.be"],extractor:"yt-dlp",format:K}];function x(e){try{const t=new URL(e),n=(t.pathname||"/").replace(/\/+$/,"")||"/";return`${t.protocol}//${t.host}${n}`.toLowerCase()}catch{return String(e||"").toLowerCase()}}function f(e){const t=Date.now();for(const[n,r]of e.entries())r<=t&&e.delete(n)}function Y(e){const t=Date.now()+k;M.set(P(e),t),I.set(x(e),t)}function Q(e){!Number.isInteger(e)||(e??-1)<0||R.set(e,Date.now()+k)}function pe(e){f(M),f(I);const t=P(e);return M.has(t)||I.has(x(e))}function me(e){return f(R),!Number.isInteger(e)||(e??-1)<0?!1:R.has(e)}function we(e){return f(L),L.has(x(e))}function ge(e){L.set(x(e),Date.now()+de)}function he(e){return f(w),!!e&&w.has(e)}function ye(e){e&&w.set(e,Date.now()+k)}function Se(e){f(A);const t=q(e);return A.has(t)}function be(e){A.set(q(e),Date.now()+k)}async function ke(){try{await Z()}catch{}}async function v(e){await i.notifications.create(`gomdown-notice-${Date.now()}`,{type:"basic",iconUrl:"/images/icon-large.png",title:"Gomdown Helper",message:e}).catch(()=>null)}async function d(e,t="",n,r,o,s){if(we(e))return{ok:!1,error:"duplicate transfer suppressed"};const a=await h();if(!a.extensionStatus)return{ok:!1,error:"extension disabled"};if(!a.motrixAPIkey)return{ok:!1,error:"motrixAPIkey is not set"};try{const u=await J({url:e,rpcPort:a.motrixPort,rpcSecret:a.motrixAPIkey,referer:t,split:64,out:o?.trim()||void 0,cookie:s?.cookie?.trim()||void 0,userAgent:s?.userAgent?.trim()||void 0,authorization:s?.authorization?.trim()||void 0,proxy:s?.proxy?.trim()||void 0,extractor:n==="yt-dlp"?"yt-dlp":void 0,format:n==="yt-dlp"?r||K:void 0});if(!u?.ok)return{ok:!1,error:u?.error||"native host addUri failed"};a.activateAppOnDownload&&await ke(),ge(e);const c=String(u?.gid||u?.requestId||`pending-${Date.now()}`),l=(()=>{try{return new URL(e).pathname}catch{return""}})().split("/").filter(Boolean).pop()||e;return await ne({gid:c,downloader:"native",startTime:new Date().toISOString(),icon:"/images/32.png",name:decodeURIComponent(l),path:null,status:u?.pending?"queued":"downloading",size:0,downloaded:0}),a.enableNotifications&&await i.notifications.create(`gomdown-transfer-${Date.now()}`,{type:"basic",iconUrl:"/images/icon-large.png",title:"Gomdown Helper",message:"Download sent to gdown"}),{ok:!0}}catch(u){return{ok:!1,error:String(u)}}}function F(e){try{return new URL(e).hostname.toLowerCase()}catch{return""}}function V(e,t="",n=""){const r=[F(e),F(t)].filter(Boolean);for(const s of fe)if(r.some(a=>s.hosts.includes(a)))return{extractor:s.extractor,format:s.format};const o=n.toLowerCase();return o==="m3u8"||o==="m3u"||o==="hls"?{extractor:"yt-dlp",format:"best"}:o==="mp4"?{extractor:"aria2"}:{extractor:"aria2"}}function O(e,t){const n=t.toLowerCase(),r=e.find(o=>String(o?.name||"").toLowerCase()===n);return String(r?.value||"").trim()}async function xe(e){if(e.type!=="main_frame"||(e.method||"").toUpperCase()!=="GET"||typeof e.statusCode=="number"&&(e.statusCode<200||e.statusCode>299))return!1;const t=await h();if(!t.extensionStatus||!t.motrixAPIkey)return!1;const n=String(Array.isArray(e?.responseHeaders)&&e.responseHeaders.find(o=>String(o?.name||"").toLowerCase()==="content-length")?.value||""),r=Number(n||0);return t.minFileSize>0&&r>0&&r=0){const X=await i.tabs.get(u.tabId).catch(()=>null);c=String(X?.title||"").trim()}const S=Ie(u.url,u.kind,c),l={...u,pageTitle:c||void 0,cookie:s||void 0,userAgent:a||void 0,suggestedOut:S||void 0};await ce(l,q(l.url)),be(l.url),l.tabId>=0&&await i.tabs.sendMessage(l.tabId,{type:"media:captured",kind:l.kind,url:l.url,suggestedOut:l.suggestedOut||""}).catch(()=>null)}function Ue(e){let t=e.trim().replace(/[\\/:*?"<>|]/g,"_").replace(/\s+/g," ").replace(/^\.+/,"").replace(/\.+$/,"");return t.length>180&&(t=t.slice(0,180).trim()),t}function Me(e){try{return new URL(e).pathname.toLowerCase().match(/\.([a-z0-9]{2,6})(?:$|[?#])/)?.[1]||""}catch{return""}}function Ie(e,t,n){const r=Ue(n||""),s=Me(e)||(t==="mp4"||t==="m3u8"||t==="m3u"||t==="hls"?"mp4":"");return r?!s||r.toLowerCase().endsWith(`.${s}`)?r:`${r}.${s}`:""}async function y(){const e=i.downloads;if(!e.setShelfEnabled)return;const t=await h();if(!t.extensionStatus)return;const n=t.useNativeHost?!1:!t.hideChromeBar;await e.setShelfEnabled(n)}function H(){E||(E=!0,i.downloads.onCreated.addListener(async e=>{await y();const t=e,n=t.finalUrl||t.url||"";!pe(n)&&!me(t.tabId)||(await i.downloads.cancel(e.id).catch(()=>null),await i.downloads.erase({id:e.id}).catch(()=>null),await i.downloads.removeFile(e.id).catch(()=>null))}))}function T(){$||($=!0,i.webRequest.onSendHeaders.addListener(e=>{m.set(e.requestId,e)},{urls:[""]},["requestHeaders","extraHeaders"]),i.webRequest.onErrorOccurred.addListener(e=>{m.delete(e.requestId),w.delete(String(e.requestId))},{urls:[""]}),i.webRequest.onCompleted.addListener(e=>{m.delete(e.requestId),w.delete(String(e.requestId))},{urls:[""]}),i.webRequest.onHeadersReceived.addListener(e=>{ve(e),Ce(e)},{urls:[""]},["responseHeaders"]))}async function N(e,t){console.log("[gomdown-helper] context menu clicked",{menuItemId:e?.menuItemId,linkUrl:e?.linkUrl,srcUrl:e?.srcUrl,frameUrl:e?.frameUrl,pageUrl:e?.pageUrl,tabUrl:t?.url});const n=e?.menuItemId;if(n!=null&&String(n)!==U)return;const r=String(e?.linkUrl||e?.srcUrl||"").trim(),o=String(e?.frameUrl||e?.pageUrl||t?.url||"").trim(),a=String(r||o||"").trim();if(!a||/^(about:|chrome:|chrome-extension:|edge:|brave:)/i.test(a)){await v("다운로드 가능한 URL을 찾지 못했습니다.");return}const u=V(a,String(e?.pageUrl||t?.url||""),""),c=await d(a,String(e?.pageUrl||t?.url||""),u.extractor,u.format);if(!c.ok){await v(`전송 실패: ${c.error||"unknown error"}`);return}await v(u.extractor==="yt-dlp"?"페이지 URL을 yt-dlp로 gdown에 전송했습니다.":"gdown으로 전송했습니다.")}function Le(){if(typeof chrome>"u"||!chrome.contextMenus?.create){i.contextMenus.create({id:U,title:"Download with Gomdown",visible:!0,contexts:["all"]});return}chrome.contextMenus.create({id:U,title:"Download with Gomdown",contexts:["all"]},()=>{chrome.runtime.lastError})}function D(){_||(typeof chrome<"u"&&chrome.contextMenus?.onClicked?chrome.contextMenus.onClicked.addListener((e,t)=>{N(e,t)}):i.contextMenus.onClicked.addListener((e,t)=>{N(e,t)}),_=!0)}async function Re(){const e=await h();if(!e.extensionStatus||!e.showContextOption){await i.contextMenus.removeAll().catch(()=>null);return}await i.contextMenus.removeAll().catch(()=>null),Le()}function g(){return p||(p=Re().finally(()=>{p=null}),p)}i.runtime.onMessage.addListener((e,t)=>{if(e?.type==="capture-link-download"){const n=String(e?.url||"").trim();if(!n)return Promise.resolve({ok:!1,error:"url is empty"});const r=Number(t?.tab?.id);return d(n,String(e?.referer||"")).then(o=>(o.ok&&(Y(n),Q(r)),o))}if(e?.type==="media:list")return W().then(n=>({ok:!0,items:n}));if(e?.type==="media:clear")return le().then(()=>({ok:!0}));if(e?.type==="media:enqueue"){const n=String(e?.url||"").trim(),r=String(e?.kind||"").trim(),o=String(e?.suggestedOut||"").trim(),s=String(e?.referer||"").trim(),a=String(e?.cookie||"").trim(),u=String(e?.userAgent||"").trim();if(!n)return Promise.resolve({ok:!1,error:"url is empty"});const c=V(n,s,r);return d(n,s,c.extractor,c.format,o,{cookie:a,userAgent:u}).then(S=>S)}if(e?.type==="page:enqueue-ytdlp")return i.tabs.query({active:!0,currentWindow:!0}).then(async n=>{const r=n[0],o=String(r?.url||"").trim();return o?d(o,o,"yt-dlp"):{ok:!1,error:"active tab url is empty"}});if(e?.type==="page:enqueue-ytdlp-url"){const n=String(e?.url||"").trim(),r=String(e?.referer||n).trim();return n?d(n,r||n,"yt-dlp"):Promise.resolve({ok:!1,error:"url is empty"})}});i.runtime.onInstalled.addListener(()=>{console.log("[gomdown-helper] onInstalled"),T(),H(),D(),g(),y()});i.runtime.onStartup.addListener(()=>{console.log("[gomdown-helper] onStartup"),T(),H(),D(),g(),y()});i.storage.onChanged.addListener((e,t)=>{t==="sync"&&((e.hideChromeBar||e.useNativeHost||e.extensionStatus)&&(y(),g()),e.showContextOption&&g())});T();H();D();g();y();console.log("[gomdown-helper] service worker initialized"); diff --git a/packages/edge/assets/index.ts-loader-DMyyuf2n.js b/packages/chrome/assets/index.ts-loader-2I0oIARK.js similarity index 82% rename from packages/edge/assets/index.ts-loader-DMyyuf2n.js rename to packages/chrome/assets/index.ts-loader-2I0oIARK.js index 6401162..75b1302 100644 --- a/packages/edge/assets/index.ts-loader-DMyyuf2n.js +++ b/packages/chrome/assets/index.ts-loader-2I0oIARK.js @@ -5,7 +5,7 @@ (async () => { const { onExecute } = await import( /* @vite-ignore */ - chrome.runtime.getURL("assets/index.ts-BGLNJwsP.js") + chrome.runtime.getURL("assets/index.ts-DQGjv8iX.js") ); onExecute?.({ perf: { injectTime, loadTime: performance.now() - injectTime } }); })().catch(console.error); diff --git a/packages/chrome/assets/index.ts-w1ilzv93.js b/packages/chrome/assets/index.ts-w1ilzv93.js deleted file mode 100644 index 09cfe85..0000000 --- a/packages/chrome/assets/index.ts-w1ilzv93.js +++ /dev/null @@ -1 +0,0 @@ -import{b as m,g as L}from"./settings-CgBxHrrF.js";import{i as c,n as T}from"./downloadIntent-Dv31jC2S.js";const I=8e3,a=new Map;let o=!1;function M(){const e=Date.now();for(const[n,t]of a.entries())t<=e&&a.delete(n)}async function f(e,n){if(!o)return!1;const t=T(e,window.location.href);if(!t)return!1;if(M(),a.has(t))return!0;a.set(t,Date.now()+I);try{if((await m.runtime.sendMessage({type:"capture-link-download",url:t,referer:n||document.referrer||window.location.href}))?.ok)return!0}catch{}return a.delete(t),!1}function x(e){return e?e instanceof HTMLAnchorElement?e:e instanceof Element?e.closest("a[href]"):null:null}function k(e){return!!(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)}async function S(e){if(!o||e.defaultPrevented||k(e))return;const n=x(e.target);if(!n)return;const t=n.href||"";!t||!c(t,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),await f(t,document.referrer||window.location.href))}function C(e){if(!o)return;const n=x(e.target);if(!n)return;const t=n.href||"";!t||!c(t,window.location.href)||k(e)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),f(t,document.referrer||window.location.href))}document.addEventListener("pointerdown",e=>{e.button===0&&C(e)},!0);document.addEventListener("mousedown",e=>{e.button===0&&C(e)},!0);document.addEventListener("click",e=>{e.button===0&&S(e)},!0);document.addEventListener("keydown",e=>{if(!o||e.key!=="Enter"||e.defaultPrevented||k(e))return;const n=x(e.target);if(!n)return;const t=n.href||"";!t||!c(t,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),f(t,document.referrer||window.location.href))},!0);document.addEventListener("auxclick",e=>{e.button===1&&S(e)},!0);function P(){try{const e=window.open.bind(window);window.open=function(t,r,p){const g=String(t||"").trim();return o&&g&&c(g,window.location.href)?(f(g,window.location.href),null):e(t,r,p)}}catch{}try{const e=HTMLAnchorElement.prototype.click;HTMLAnchorElement.prototype.click=function(){const t=this.href||this.getAttribute("href")||"";if(o&&t&&c(t,window.location.href)){f(t,document.referrer||window.location.href);return}e.call(this)}}catch{}}P();let u=null,i=null,b=!1,E=null,y=window.location.href;function O(e){try{const n=new URL(e);return n.hostname!=="www.youtube.com"&&n.hostname!=="youtube.com"?!1:n.pathname==="/watch"&&n.searchParams.has("v")}catch{return!1}}function w(e,n="idle"){i&&(i.textContent=e,n==="ok"?i.style.color="#8ff0a4":n==="error"?i.style.color="#ff9b9b":i.style.color="#aeb7d8")}async function A(){if(!b){b=!0,w("gdown으로 전송 중...");try{const e=await m.runtime.sendMessage({type:"page:enqueue-ytdlp-url",url:window.location.href,referer:window.location.href});e?.ok?w("다운로드 모달로 전송됨","ok"):w(`전송 실패: ${e?.error||"unknown error"}`,"error")}catch(e){w(`전송 실패: ${String(e)}`,"error")}finally{b=!1}}}function h(){u&&(u.remove(),u=null,i=null)}function s(){if(!o){h();return}if(window.top!==window.self)return;if(!O(window.location.href)){h();return}if(u)return;const e=document.createElement("div");e.id="gomdown-youtube-overlay",e.style.position="fixed",e.style.right="20px",e.style.bottom="24px",e.style.zIndex="2147483647",e.style.background="rgba(17, 21, 32, 0.94)",e.style.border="1px solid rgba(133, 148, 195, 0.35)",e.style.borderRadius="12px",e.style.padding="10px",e.style.boxShadow="0 8px 24px rgba(0, 0, 0, 0.28)",e.style.backdropFilter="blur(6px)",e.style.width="220px",e.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.style.color="#e8edff";const n=document.createElement("div");n.textContent="Gdown Helper",n.style.fontSize="12px",n.style.fontWeight="700",n.style.marginBottom="8px";const t=document.createElement("button");t.type="button",t.textContent="이 영상 다운로드",t.style.width="100%",t.style.height="34px",t.style.border="1px solid #5a69f0",t.style.borderRadius="8px",t.style.background="#5a69f0",t.style.color="#ffffff",t.style.fontSize="12px",t.style.fontWeight="700",t.style.cursor="pointer",t.addEventListener("click",()=>{A()});const r=document.createElement("div");r.textContent="클릭 시 gdown 다운로드 모달로 연결",r.style.fontSize="11px",r.style.marginTop="8px",r.style.lineHeight="1.35",r.style.color="#aeb7d8",e.appendChild(n),e.appendChild(t),e.appendChild(r),document.documentElement.appendChild(e),u=e,i=r}function U(){E===null&&(E=window.setInterval(()=>{const e=window.location.href;e!==y&&(y=e,s())},800),window.addEventListener("popstate",()=>{y=window.location.href,s()}),document.addEventListener("yt-navigate-finish",()=>{y=window.location.href,s()}))}s();U();let d=null,l=null;function v(){d&&(d.style.display="none",l!==null&&(window.clearTimeout(l),l=null))}function R(){if(d)return d;const e=document.createElement("div");return e.id="gomdown-media-toast",e.style.position="fixed",e.style.left="18px",e.style.bottom="18px",e.style.zIndex="2147483647",e.style.maxWidth="360px",e.style.padding="10px 12px",e.style.borderRadius="10px",e.style.border="1px solid rgba(128, 140, 180, 0.42)",e.style.background="rgba(18, 21, 31, 0.95)",e.style.color="#dce4fa",e.style.fontSize="12px",e.style.lineHeight="1.35",e.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.style.boxShadow="0 10px 24px rgba(0, 0, 0, 0.28)",e.style.display="none",document.documentElement.appendChild(e),d=e,e}function z(e){if(!o)return;const n=R(),t=String(e?.kind||"media").toUpperCase(),r=String(e?.suggestedOut||"").trim(),p=String(e?.url||"").trim().slice(0,96);n.textContent=r?`캡처됨 [${t}] ${r}`:`캡처됨 [${t}] ${p}${p.length>=96?"…":""}`,n.style.display="block",l!==null&&window.clearTimeout(l),l=window.setTimeout(()=>{n.style.display="none",l=null},2200)}m.runtime.onMessage.addListener(e=>{e?.type==="media:captured"&&z({kind:e?.kind,url:e?.url,suggestedOut:e?.suggestedOut})});async function F(){try{o=!!(await L()).extensionStatus}catch{o=!1}o?s():(h(),v())}F();m.storage.onChanged.addListener((e,n)=>{if(n==="sync"&&e.extensionStatus){if(o=!!e.extensionStatus.newValue,!o){h(),v();return}s()}}); diff --git a/packages/chrome/manifest.json b/packages/chrome/manifest.json index f00ab3f..be34734 100644 --- a/packages/chrome/manifest.json +++ b/packages/chrome/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "Gomdown Helper", "description": "Send browser downloads to gdown", - "version": "0.0.16", + "version": "0.0.19", "default_locale": "en", "icons": { "16": "images/16.png", @@ -28,7 +28,7 @@ "content_scripts": [ { "js": [ - "assets/index.ts-loader-D_eQmgUa.js" + "assets/index.ts-loader-2I0oIARK.js" ], "matches": [ "" @@ -59,7 +59,8 @@ "images/*", "assets/settings-CgBxHrrF.js", "assets/downloadIntent-Dv31jC2S.js", - "assets/index.ts-w1ilzv93.js" + "assets/clipTypes-C_ha5Ash.js", + "assets/index.ts-DQGjv8iX.js" ], "use_dynamic_url": false } diff --git a/packages/chrome/service-worker-loader.js b/packages/chrome/service-worker-loader.js index 7f12106..8e8da38 100644 --- a/packages/chrome/service-worker-loader.js +++ b/packages/chrome/service-worker-loader.js @@ -1 +1 @@ -import './assets/index.ts-U8lbRRO-.js'; +import './assets/index.ts-BkGMAUD4.js'; diff --git a/packages/chrome/src/popup/index.html b/packages/chrome/src/popup/index.html index b80a3e8..15763c0 100644 --- a/packages/chrome/src/popup/index.html +++ b/packages/chrome/src/popup/index.html @@ -4,10 +4,11 @@ Gomdown Helper - + - + +
diff --git a/packages/edge/.vite/manifest.json b/packages/edge/.vite/manifest.json index ff13401..77a45b6 100644 --- a/packages/edge/.vite/manifest.json +++ b/packages/edge/.vite/manifest.json @@ -1,83 +1,80 @@ { - "../../../../../@crx/manifest": { - "file": "assets/crx-manifest.js-DthtiGNU.js", + "../../../../../../../@crx/manifest": { + "file": "assets/crx-manifest.js-5UhKLF3w.js", "name": "crx-manifest.js", - "src": "../../../../../@crx/manifest", + "src": "../../../../../../../@crx/manifest", "isEntry": true }, - "_browser-polyfill-CZ_dLIqp.js": { - "file": "assets/browser-polyfill-CZ_dLIqp.js", - "name": "browser-polyfill" - }, - "_client-CBvt1tWS.js": { - "file": "assets/client-CBvt1tWS.js", + "_client-DnQyoB4h.js": { + "file": "assets/client-DnQyoB4h.js", "name": "client", "imports": [ - "_browser-polyfill-CZ_dLIqp.js" + "_settings-mco8QK8Y.js" ] }, + "_clipTypes-C_ha5Ash.js": { + "file": "assets/clipTypes-C_ha5Ash.js", + "name": "clipTypes" + }, "_downloadIntent-Dv31jC2S.js": { "file": "assets/downloadIntent-Dv31jC2S.js", "name": "downloadIntent" }, - "_index.ts-loader-DMyyuf2n.js": { - "file": "assets/index.ts-loader-DMyyuf2n.js", - "src": "_index.ts-loader-DMyyuf2n.js" + "_index.ts-loader-DWDY2bjZ.js": { + "file": "assets/index.ts-loader-DWDY2bjZ.js", + "src": "_index.ts-loader-DWDY2bjZ.js" }, - "_settings-Bo6W9Drl.js": { - "file": "assets/settings-Bo6W9Drl.js", - "name": "settings", - "imports": [ - "_browser-polyfill-CZ_dLIqp.js" - ] + "_settings-mco8QK8Y.js": { + "file": "assets/settings-mco8QK8Y.js", + "name": "settings" }, "src/background/index.ts": { - "file": "assets/index.ts-BnPsJZXz.js", + "file": "assets/index.ts-D64R0PS1.js", "name": "index.ts", "src": "src/background/index.ts", "isEntry": true, "imports": [ - "_browser-polyfill-CZ_dLIqp.js", + "_settings-mco8QK8Y.js", "_downloadIntent-Dv31jC2S.js", - "_settings-Bo6W9Drl.js" + "_clipTypes-C_ha5Ash.js" ] }, "src/config/index.html": { - "file": "assets/index.html-B0Kfv8fq.js", + "file": "assets/index.html-CYipkEaD.js", "name": "index.html", "src": "src/config/index.html", "isEntry": true, "imports": [ - "_client-CBvt1tWS.js", - "_settings-Bo6W9Drl.js", - "_browser-polyfill-CZ_dLIqp.js" + "_client-DnQyoB4h.js", + "_settings-mco8QK8Y.js" ], "css": [ "assets/index-B2D5FcJM.css" ] }, "src/content/index.ts": { - "file": "assets/index.ts-BGLNJwsP.js", + "file": "assets/index.ts-DMIsnBNX.js", "name": "index.ts", "src": "src/content/index.ts", "isEntry": true, "imports": [ - "_browser-polyfill-CZ_dLIqp.js", - "_downloadIntent-Dv31jC2S.js" + "_settings-mco8QK8Y.js", + "_downloadIntent-Dv31jC2S.js", + "_clipTypes-C_ha5Ash.js" ] }, "src/popup/index.html": { - "file": "assets/index.html-D-JbSuV5.js", + "file": "assets/index.html-yhgSfkXU.js", "name": "index.html", "src": "src/popup/index.html", "isEntry": true, "imports": [ - "_client-CBvt1tWS.js", - "_browser-polyfill-CZ_dLIqp.js", - "_settings-Bo6W9Drl.js" + "_client-DnQyoB4h.js", + "_settings-mco8QK8Y.js", + "_clipTypes-C_ha5Ash.js" ], "css": [ - "assets/index-BZvbrf4l.css" + "assets/index-CV3UOEJM.css" ] } } \ No newline at end of file diff --git a/packages/edge/assets/client-CBvt1tWS.js b/packages/edge/assets/client-DnQyoB4h.js similarity index 87% rename from packages/edge/assets/client-CBvt1tWS.js rename to packages/edge/assets/client-DnQyoB4h.js index 5765dc3..1f59e2a 100644 --- a/packages/edge/assets/client-CBvt1tWS.js +++ b/packages/edge/assets/client-DnQyoB4h.js @@ -1,4 +1,4 @@ -import{g as zc}from"./browser-polyfill-CZ_dLIqp.js";(function(){const H=document.createElement("link").relList;if(H&&H.supports&&H.supports("modulepreload"))return;for(const V of document.querySelectorAll('link[rel="modulepreload"]'))Ne(V);new MutationObserver(V=>{for(const Y of V)if(Y.type==="childList")for(const fe of Y.addedNodes)fe.tagName==="LINK"&&fe.rel==="modulepreload"&&Ne(fe)}).observe(document,{childList:!0,subtree:!0});function m(V){const Y={};return V.integrity&&(Y.integrity=V.integrity),V.referrerPolicy&&(Y.referrerPolicy=V.referrerPolicy),V.crossOrigin==="use-credentials"?Y.credentials="include":V.crossOrigin==="anonymous"?Y.credentials="omit":Y.credentials="same-origin",Y}function Ne(V){if(V.ep)return;V.ep=!0;const Y=m(V);fetch(V.href,Y)}})();var Eo={exports:{}},hr={},_o={exports:{}},D={};var Ea;function Lc(){if(Ea)return D;Ea=1;var R=Symbol.for("react.element"),H=Symbol.for("react.portal"),m=Symbol.for("react.fragment"),Ne=Symbol.for("react.strict_mode"),V=Symbol.for("react.profiler"),Y=Symbol.for("react.provider"),fe=Symbol.for("react.context"),ce=Symbol.for("react.forward_ref"),W=Symbol.for("react.suspense"),_e=Symbol.for("react.memo"),ye=Symbol.for("react.lazy"),ee=Symbol.iterator;function Z(f){return f===null||typeof f!="object"?null:(f=ee&&f[ee]||f["@@iterator"],typeof f=="function"?f:null)}var He={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},We=Object.assign,J={};function Q(f,h,O){this.props=f,this.context=h,this.refs=J,this.updater=O||He}Q.prototype.isReactComponent={},Q.prototype.setState=function(f,h){if(typeof f!="object"&&typeof f!="function"&&f!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,f,h,"setState")},Q.prototype.forceUpdate=function(f){this.updater.enqueueForceUpdate(this,f,"forceUpdate")};function vt(){}vt.prototype=Q.prototype;function it(f,h,O){this.props=f,this.context=h,this.refs=J,this.updater=O||He}var Je=it.prototype=new vt;Je.constructor=it,We(Je,Q.prototype),Je.isPureReactComponent=!0;var ge=Array.isArray,qe=Object.prototype.hasOwnProperty,Ce={current:null},ze={key:!0,ref:!0,__self:!0,__source:!0};function Qe(f,h,O){var M,F={},j=null,$=null;if(h!=null)for(M in h.ref!==void 0&&($=h.ref),h.key!==void 0&&(j=""+h.key),h)qe.call(h,M)&&!ze.hasOwnProperty(M)&&(F[M]=h[M]);var A=arguments.length-2;if(A===1)F.children=O;else if(1>>1,h=S[f];if(0>>1;fV(F,_))jV($,F)?(S[f]=$,S[j]=_,f=j):(S[f]=F,S[M]=_,f=M);else if(jV($,_))S[f]=$,S[j]=_,f=j;else break e}}return L}function V(S,L){var _=S.sortIndex-L.sortIndex;return _!==0?_:S.id-L.id}if(typeof performance=="object"&&typeof performance.now=="function"){var Y=performance;R.unstable_now=function(){return Y.now()}}else{var fe=Date,ce=fe.now();R.unstable_now=function(){return fe.now()-ce}}var W=[],_e=[],ye=1,ee=null,Z=3,He=!1,We=!1,J=!1,Q=typeof setTimeout=="function"?setTimeout:null,vt=typeof clearTimeout=="function"?clearTimeout:null,it=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function Je(S){for(var L=m(_e);L!==null;){if(L.callback===null)Ne(_e);else if(L.startTime<=S)Ne(_e),L.sortIndex=L.expirationTime,H(W,L);else break;L=m(_e)}}function ge(S){if(J=!1,Je(S),!We)if(m(W)!==null)We=!0,Le(qe);else{var L=m(_e);L!==null&&re(ge,L.startTime-S)}}function qe(S,L){We=!1,J&&(J=!1,vt(Qe),Qe=-1),He=!0;var _=Z;try{for(Je(L),ee=m(W);ee!==null&&(!(ee.expirationTime>L)||S&&!$t());){var f=ee.callback;if(typeof f=="function"){ee.callback=null,Z=ee.priorityLevel;var h=f(ee.expirationTime<=L);L=R.unstable_now(),typeof h=="function"?ee.callback=h:ee===m(W)&&Ne(W),Je(L)}else Ne(W);ee=m(W)}if(ee!==null)var O=!0;else{var M=m(_e);M!==null&&re(ge,M.startTime-L),O=!1}return O}finally{ee=null,Z=_,He=!1}}var Ce=!1,ze=null,Qe=-1,xt=5,ht=-1;function $t(){return!(R.unstable_now()-htS||125f?(S.sortIndex=_,H(_e,S),m(W)===null&&S===m(_e)&&(J?(vt(Qe),Qe=-1):J=!0,re(ge,_-f))):(S.sortIndex=h,H(W,S),We||He||(We=!0,Le(qe))),S},R.unstable_shouldYield=$t,R.unstable_wrapCallback=function(S){var L=Z;return function(){var _=Z;Z=L;try{return S.apply(this,arguments)}finally{Z=_}}}})(Po)),Po}var Na;function Mc(){return Na||(Na=1,xo.exports=Dc()),xo.exports}var za;function Ic(){if(za)return Ie;za=1;var R=No(),H=Mc();function m(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),W=Object.prototype.hasOwnProperty,_e=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,ye={},ee={};function Z(e){return W.call(ee,e)?!0:W.call(ye,e)?!1:_e.test(e)?ee[e]=!0:(ye[e]=!0,!1)}function He(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function We(e,t,n,r){if(t===null||typeof t>"u"||He(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function J(e,t,n,r,l,u,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=u,this.removeEmptyString=o}var Q={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Q[e]=new J(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Q[t]=new J(t,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){Q[e]=new J(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Q[e]=new J(e,2,!1,e,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Q[e]=new J(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){Q[e]=new J(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){Q[e]=new J(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){Q[e]=new J(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){Q[e]=new J(e,5,!1,e.toLowerCase(),null,!1,!1)});var vt=/[\-:]([a-z])/g;function it(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(vt,it);Q[t]=new J(t,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(vt,it);Q[t]=new J(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(vt,it);Q[t]=new J(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){Q[e]=new J(e,1,!1,e.toLowerCase(),null,!1,!1)}),Q.xlinkHref=new J("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){Q[e]=new J(e,1,!1,e.toLowerCase(),null,!0,!0)});function Je(e,t,n,r){var l=Q.hasOwnProperty(t)?Q[t]:null;(l!==null?l.type!==0:r||!(2{for(const Y of V)if(Y.type==="childList")for(const fe of Y.addedNodes)fe.tagName==="LINK"&&fe.rel==="modulepreload"&&Ne(fe)}).observe(document,{childList:!0,subtree:!0});function m(V){const Y={};return V.integrity&&(Y.integrity=V.integrity),V.referrerPolicy&&(Y.referrerPolicy=V.referrerPolicy),V.crossOrigin==="use-credentials"?Y.credentials="include":V.crossOrigin==="anonymous"?Y.credentials="omit":Y.credentials="same-origin",Y}function Ne(V){if(V.ep)return;V.ep=!0;const Y=m(V);fetch(V.href,Y)}})();var Eo={exports:{}},hr={},_o={exports:{}},D={};var Ea;function Lc(){if(Ea)return D;Ea=1;var R=Symbol.for("react.element"),H=Symbol.for("react.portal"),m=Symbol.for("react.fragment"),Ne=Symbol.for("react.strict_mode"),V=Symbol.for("react.profiler"),Y=Symbol.for("react.provider"),fe=Symbol.for("react.context"),ce=Symbol.for("react.forward_ref"),W=Symbol.for("react.suspense"),_e=Symbol.for("react.memo"),ye=Symbol.for("react.lazy"),ee=Symbol.iterator;function Z(f){return f===null||typeof f!="object"?null:(f=ee&&f[ee]||f["@@iterator"],typeof f=="function"?f:null)}var He={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},We=Object.assign,J={};function Q(f,h,O){this.props=f,this.context=h,this.refs=J,this.updater=O||He}Q.prototype.isReactComponent={},Q.prototype.setState=function(f,h){if(typeof f!="object"&&typeof f!="function"&&f!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,f,h,"setState")},Q.prototype.forceUpdate=function(f){this.updater.enqueueForceUpdate(this,f,"forceUpdate")};function vt(){}vt.prototype=Q.prototype;function it(f,h,O){this.props=f,this.context=h,this.refs=J,this.updater=O||He}var Je=it.prototype=new vt;Je.constructor=it,We(Je,Q.prototype),Je.isPureReactComponent=!0;var ge=Array.isArray,qe=Object.prototype.hasOwnProperty,Ce={current:null},ze={key:!0,ref:!0,__self:!0,__source:!0};function Qe(f,h,O){var M,F={},j=null,$=null;if(h!=null)for(M in h.ref!==void 0&&($=h.ref),h.key!==void 0&&(j=""+h.key),h)qe.call(h,M)&&!ze.hasOwnProperty(M)&&(F[M]=h[M]);var A=arguments.length-2;if(A===1)F.children=O;else if(1>>1,h=S[f];if(0>>1;fV(F,_))jV($,F)?(S[f]=$,S[j]=_,f=j):(S[f]=F,S[M]=_,f=M);else if(jV($,_))S[f]=$,S[j]=_,f=j;else break e}}return L}function V(S,L){var _=S.sortIndex-L.sortIndex;return _!==0?_:S.id-L.id}if(typeof performance=="object"&&typeof performance.now=="function"){var Y=performance;R.unstable_now=function(){return Y.now()}}else{var fe=Date,ce=fe.now();R.unstable_now=function(){return fe.now()-ce}}var W=[],_e=[],ye=1,ee=null,Z=3,He=!1,We=!1,J=!1,Q=typeof setTimeout=="function"?setTimeout:null,vt=typeof clearTimeout=="function"?clearTimeout:null,it=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function Je(S){for(var L=m(_e);L!==null;){if(L.callback===null)Ne(_e);else if(L.startTime<=S)Ne(_e),L.sortIndex=L.expirationTime,H(W,L);else break;L=m(_e)}}function ge(S){if(J=!1,Je(S),!We)if(m(W)!==null)We=!0,Le(qe);else{var L=m(_e);L!==null&&re(ge,L.startTime-S)}}function qe(S,L){We=!1,J&&(J=!1,vt(Qe),Qe=-1),He=!0;var _=Z;try{for(Je(L),ee=m(W);ee!==null&&(!(ee.expirationTime>L)||S&&!$t());){var f=ee.callback;if(typeof f=="function"){ee.callback=null,Z=ee.priorityLevel;var h=f(ee.expirationTime<=L);L=R.unstable_now(),typeof h=="function"?ee.callback=h:ee===m(W)&&Ne(W),Je(L)}else Ne(W);ee=m(W)}if(ee!==null)var O=!0;else{var M=m(_e);M!==null&&re(ge,M.startTime-L),O=!1}return O}finally{ee=null,Z=_,He=!1}}var Ce=!1,ze=null,Qe=-1,xt=5,ht=-1;function $t(){return!(R.unstable_now()-htS||125f?(S.sortIndex=_,H(_e,S),m(W)===null&&S===m(_e)&&(J?(vt(Qe),Qe=-1):J=!0,re(ge,_-f))):(S.sortIndex=h,H(W,S),We||He||(We=!0,Le(qe))),S},R.unstable_shouldYield=$t,R.unstable_wrapCallback=function(S){var L=Z;return function(){var _=Z;Z=L;try{return S.apply(this,arguments)}finally{Z=_}}}})(Po)),Po}var Na;function Mc(){return Na||(Na=1,xo.exports=Dc()),xo.exports}var za;function Ic(){if(za)return Ie;za=1;var R=No(),H=Mc();function m(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),W=Object.prototype.hasOwnProperty,_e=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,ye={},ee={};function Z(e){return W.call(ee,e)?!0:W.call(ye,e)?!1:_e.test(e)?ee[e]=!0:(ye[e]=!0,!1)}function He(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function We(e,t,n,r){if(t===null||typeof t>"u"||He(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function J(e,t,n,r,l,u,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=u,this.removeEmptyString=o}var Q={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Q[e]=new J(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Q[t]=new J(t,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){Q[e]=new J(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Q[e]=new J(e,2,!1,e,null,!1,!1)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Q[e]=new J(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){Q[e]=new J(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){Q[e]=new J(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){Q[e]=new J(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){Q[e]=new J(e,5,!1,e.toLowerCase(),null,!1,!1)});var vt=/[\-:]([a-z])/g;function it(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(vt,it);Q[t]=new J(t,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(vt,it);Q[t]=new J(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(vt,it);Q[t]=new J(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){Q[e]=new J(e,1,!1,e.toLowerCase(),null,!1,!1)}),Q.xlinkHref=new J("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){Q[e]=new J(e,1,!1,e.toLowerCase(),null,!0,!0)});function Je(e,t,n,r){var l=Q.hasOwnProperty(t)?Q[t]:null;(l!==null?l.type!==0:r||!(2i||l[o]!==u[i]){var s=` diff --git a/packages/edge/assets/clipTypes-C_ha5Ash.js b/packages/edge/assets/clipTypes-C_ha5Ash.js new file mode 100644 index 0000000..abf2674 --- /dev/null +++ b/packages/edge/assets/clipTypes-C_ha5Ash.js @@ -0,0 +1 @@ +function n(r){try{const t=new URL(r);return t.hash="",t.toString()}catch{return String(r||"").trim()}}function e(r){return String(r||"").replace(/\s+/g," ").trim()}export{e as a,n}; diff --git a/packages/edge/assets/index-BZvbrf4l.css b/packages/edge/assets/index-BZvbrf4l.css deleted file mode 100644 index cf647e0..0000000 --- a/packages/edge/assets/index-BZvbrf4l.css +++ /dev/null @@ -1 +0,0 @@ -:root{color-scheme:dark;font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}body{margin:0;background:#151821;color:#e7ebf7;width:360px}.container{padding:14px;display:grid;gap:10px}h1{margin:0;font-size:14px}.field{display:grid;gap:6px}label{font-size:12px;color:#aeb6cc}input[type=text],input[type=number]{height:32px;border:1px solid #3e4658;border-radius:6px;padding:0 10px;background:#202532;color:#e7ebf7}.toggle{display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#cdd5ea}button{height:34px;border:1px solid #5562f0;border-radius:8px;background:#5562f0;color:#fff;font-weight:600;cursor:pointer}.status{font-size:12px;color:#8fe0a6;min-height:14px} diff --git a/packages/edge/assets/index-CV3UOEJM.css b/packages/edge/assets/index-CV3UOEJM.css new file mode 100644 index 0000000..8d79b0e --- /dev/null +++ b/packages/edge/assets/index-CV3UOEJM.css @@ -0,0 +1 @@ +:root{color-scheme:dark;font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}body{margin:0;background:#151821;color:#e7ebf7;width:360px}.container{padding:14px 14px 108px;display:grid;gap:10px}.top-row{display:flex;align-items:center;justify-content:space-between;gap:8px}h1{margin:0;font-size:14px}.power-toggle{height:28px;min-width:70px;border-radius:999px;padding:0 12px;display:inline-flex;align-items:center;justify-content:center;gap:6px;font-size:11px;font-weight:800;letter-spacing:.04em}.power-toggle.on{background:#204f37;border-color:#2b7a52;color:#c7ffe3}.power-toggle.off{background:#4a2631;border-color:#75404d;color:#ffd6df}.power-dot{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.9}.field{display:grid;gap:6px}label{font-size:12px;color:#aeb6cc}input[type=text],input[type=number]{height:32px;border:1px solid #3e4658;border-radius:6px;padding:0 10px;background:#202532;color:#e7ebf7}.toggle{display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#cdd5ea}button{height:34px;border:1px solid #5562f0;border-radius:8px;background:#5562f0;color:#fff;font-weight:600;cursor:pointer}.media-panel{margin-top:6px;border:1px solid #384255;border-radius:8px;padding:8px;background:#1b202c;display:grid;gap:8px}.media-head{display:flex;align-items:center;justify-content:space-between;font-size:12px}.hint{font-size:10px;color:#9eadcb}.page-clips-head{display:grid;gap:8px}.page-clips-title-row{display:flex;align-items:center;justify-content:space-between}.page-clips-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}.page-action-btn{width:100%;min-width:0;padding:0 8px}.page-action-btn-wide{grid-column:1 / -1}.media-list{display:grid;gap:6px;max-height:150px;overflow:auto}.media-item{display:flex;align-items:center;justify-content:space-between;gap:8px}.clip-item{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.clip-actions{display:flex;align-items:center;gap:6px}.media-meta{min-width:0;display:grid;gap:2px}.kind{font-size:11px;color:#8fc0ff}.broken-badge{font-size:10px;color:#ffb0b0;border:1px solid rgba(186,94,94,.6);background:#752c2c73;border-radius:999px;padding:1px 6px;width:fit-content}.url{font-size:11px;color:#c6d1e8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:250px}.mini{height:26px;min-width:44px;padding:0 8px;border-radius:6px;font-size:11px}.mini.ghost{background:#2a3140;border-color:#47546c;color:#d4def2}.empty{font-size:11px;color:#96a3bc}.status{font-size:12px;color:#8fe0a6;min-height:14px}.action-dock{position:fixed;left:0;right:0;bottom:0;width:360px;padding:8px 10px 10px;box-sizing:border-box;background:#0d111bf5;border-top:1px solid #30384b;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px}.action-btn{height:42px;border-radius:9px;border:1px solid #43506d;background:#242c3d;color:#dbe5ff;display:grid;grid-template-rows:18px auto;place-items:center;padding:3px 4px}.action-btn svg{width:15px;height:15px}.action-btn span{font-size:10px;line-height:1} diff --git a/packages/edge/assets/index.html-B0Kfv8fq.js b/packages/edge/assets/index.html-B0Kfv8fq.js deleted file mode 100644 index 7816542..0000000 --- a/packages/edge/assets/index.html-B0Kfv8fq.js +++ /dev/null @@ -1,3 +0,0 @@ -import{c as p,j as e,R as a}from"./client-CBvt1tWS.js";import{g as j,s as m}from"./settings-Bo6W9Drl.js";import"./browser-polyfill-CZ_dLIqp.js";function u(){const[t,i]=a.useState(null),[l,r]=a.useState(""),[h,d]=a.useState("");a.useEffect(()=>{j().then(s=>{i(s),r((s.blacklist||[]).join(` -`))})},[]);const n=(s,c)=>{i(o=>o&&{...o,[s]:c})},x=async()=>{if(!t)return;const s={...t,minFileSize:Number(t.minFileSize||0),motrixPort:Number(t.motrixPort||16800),blacklist:l.split(` -`).map(c=>c.trim()).filter(Boolean)};await m(s),i(s),d("Saved"),window.setTimeout(()=>d(""),1500)};return t?e.jsxs("div",{className:"wrap",children:[e.jsx("h1",{children:"Gomdown Helper Settings"}),e.jsxs("div",{className:"grid",children:[e.jsxs("section",{className:"card",children:[e.jsx("label",{children:"RPC Secret"}),e.jsx("input",{value:t.motrixAPIkey,onChange:s=>n("motrixAPIkey",s.target.value)}),e.jsx("label",{children:"RPC Port"}),e.jsx("input",{type:"number",value:t.motrixPort,onChange:s=>n("motrixPort",Number(s.target.value||16800))}),e.jsx("label",{children:"Min file size (MB)"}),e.jsx("input",{type:"number",value:t.minFileSize,onChange:s=>n("minFileSize",Number(s.target.value||0))}),e.jsx("label",{children:"Blacklist (one per line)"}),e.jsx("textarea",{rows:8,value:l,onChange:s=>r(s.target.value)})]}),e.jsxs("section",{className:"card",children:[e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Extension enabled"}),e.jsx("input",{type:"checkbox",checked:t.extensionStatus,onChange:s=>n("extensionStatus",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Enable notifications"}),e.jsx("input",{type:"checkbox",checked:t.enableNotifications,onChange:s=>n("enableNotifications",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Use native host"}),e.jsx("input",{type:"checkbox",checked:t.useNativeHost,onChange:s=>n("useNativeHost",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Activate app on download"}),e.jsx("input",{type:"checkbox",checked:t.activateAppOnDownload,onChange:s=>n("activateAppOnDownload",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Hide browser download shelf"}),e.jsx("input",{type:"checkbox",checked:t.hideChromeBar,onChange:s=>n("hideChromeBar",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Show context menu option"}),e.jsx("input",{type:"checkbox",checked:t.showContextOption,onChange:s=>n("showContextOption",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Download fallback"}),e.jsx("input",{type:"checkbox",checked:t.downloadFallback,onChange:s=>n("downloadFallback",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Dark mode"}),e.jsx("input",{type:"checkbox",checked:t.darkMode,onChange:s=>n("darkMode",s.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Show only aria downloads"}),e.jsx("input",{type:"checkbox",checked:t.showOnlyAria,onChange:s=>n("showOnlyAria",s.target.checked)})]})]})]}),e.jsxs("div",{className:"actions",children:[e.jsx("button",{onClick:x,children:"Save"}),e.jsx("button",{className:"ghost",onClick:()=>window.close(),children:"Close"})]}),e.jsx("div",{children:h})]}):e.jsx("div",{className:"wrap",children:"Loading..."})}p.createRoot(document.getElementById("root")).render(e.jsx(a.StrictMode,{children:e.jsx(u,{})})); diff --git a/packages/edge/assets/index.html-CYipkEaD.js b/packages/edge/assets/index.html-CYipkEaD.js new file mode 100644 index 0000000..8129af7 --- /dev/null +++ b/packages/edge/assets/index.html-CYipkEaD.js @@ -0,0 +1,3 @@ +import{c as u,j as e,R as t}from"./client-DnQyoB4h.js";import{g as p,s as j}from"./settings-mco8QK8Y.js";function m(){const[n,i]=t.useState(null),[l,r]=t.useState(""),[h,d]=t.useState("");t.useEffect(()=>{p().then(a=>{i(a),r((a.blacklist||[]).join(` +`))})},[]);const s=(a,o)=>{i(c=>c&&{...c,[a]:o})},x=async()=>{if(!n)return;const a={...n,minFileSize:Number(n.minFileSize||0),motrixPort:Number(n.motrixPort||16800),blacklist:l.split(` +`).map(o=>o.trim()).filter(Boolean)};await j(a),i(a),d("Saved"),window.setTimeout(()=>d(""),1500)};return n?e.jsxs("div",{className:"wrap",children:[e.jsx("h1",{children:"Gomdown Helper Settings"}),e.jsxs("div",{className:"grid",children:[e.jsxs("section",{className:"card",children:[e.jsx("label",{children:"RPC Secret"}),e.jsx("input",{value:n.motrixAPIkey,onChange:a=>s("motrixAPIkey",a.target.value)}),e.jsx("label",{children:"RPC Port"}),e.jsx("input",{type:"number",value:n.motrixPort,onChange:a=>s("motrixPort",Number(a.target.value||16800))}),e.jsx("label",{children:"Min file size (MB)"}),e.jsx("input",{type:"number",value:n.minFileSize,onChange:a=>s("minFileSize",Number(a.target.value||0))}),e.jsx("label",{children:"Blacklist (one per line)"}),e.jsx("textarea",{rows:8,value:l,onChange:a=>r(a.target.value)}),e.jsx("label",{children:"Obsidian Vault"}),e.jsx("input",{value:n.obsidianVault,onChange:a=>s("obsidianVault",a.target.value),placeholder:"Exact vault name (blank = last used vault or default vault)"}),e.jsx("label",{children:"Obsidian Folder"}),e.jsx("input",{value:n.obsidianFolder,onChange:a=>s("obsidianFolder",a.target.value),placeholder:"Gomdown/Clips"})]}),e.jsxs("section",{className:"card",children:[e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Extension enabled"}),e.jsx("input",{type:"checkbox",checked:n.extensionStatus,onChange:a=>s("extensionStatus",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Enable notifications"}),e.jsx("input",{type:"checkbox",checked:n.enableNotifications,onChange:a=>s("enableNotifications",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Use native host"}),e.jsx("input",{type:"checkbox",checked:n.useNativeHost,onChange:a=>s("useNativeHost",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Activate app on download"}),e.jsx("input",{type:"checkbox",checked:n.activateAppOnDownload,onChange:a=>s("activateAppOnDownload",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Hide browser download shelf"}),e.jsx("input",{type:"checkbox",checked:n.hideChromeBar,onChange:a=>s("hideChromeBar",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Show context menu option"}),e.jsx("input",{type:"checkbox",checked:n.showContextOption,onChange:a=>s("showContextOption",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Download fallback"}),e.jsx("input",{type:"checkbox",checked:n.downloadFallback,onChange:a=>s("downloadFallback",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Dark mode"}),e.jsx("input",{type:"checkbox",checked:n.darkMode,onChange:a=>s("darkMode",a.target.checked)})]}),e.jsxs("div",{className:"row",children:[e.jsx("span",{children:"Show only aria downloads"}),e.jsx("input",{type:"checkbox",checked:n.showOnlyAria,onChange:a=>s("showOnlyAria",a.target.checked)})]})]})]}),e.jsxs("div",{className:"actions",children:[e.jsx("button",{onClick:x,children:"Save"}),e.jsx("button",{className:"ghost",onClick:()=>window.close(),children:"Close"})]}),e.jsx("div",{children:h})]}):e.jsx("div",{className:"wrap",children:"Loading..."})}u.createRoot(document.getElementById("root")).render(e.jsx(t.StrictMode,{children:e.jsx(m,{})})); diff --git a/packages/edge/assets/index.html-D-JbSuV5.js b/packages/edge/assets/index.html-D-JbSuV5.js deleted file mode 100644 index 8725296..0000000 --- a/packages/edge/assets/index.html-D-JbSuV5.js +++ /dev/null @@ -1 +0,0 @@ -import{c as g,j as e,R as c}from"./client-CBvt1tWS.js";import{b as a}from"./browser-polyfill-CZ_dLIqp.js";import{g as m,s as p}from"./settings-Bo6W9Drl.js";function j(){const[s,o]=c.useState(null),[l,r]=c.useState("");c.useEffect(()=>{m().then(o)},[]);const n=(t,h)=>{o(i=>i&&{...i,[t]:h})},d=async()=>{s&&(await p(s),r("Saved"),window.setTimeout(()=>r(""),1200))},u=async()=>{const t=a.runtime.getURL("src/config/index.html");await a.tabs.create({url:t})},x=async()=>{const t=a.runtime.getURL("src/history/index.html");await a.tabs.create({url:t})};return s?e.jsxs("div",{className:"container",children:[e.jsx("h1",{children:"Gomdown Helper"}),e.jsxs("div",{className:"field",children:[e.jsx("label",{children:"RPC Secret"}),e.jsx("input",{type:"text",value:s.motrixAPIkey,onChange:t=>n("motrixAPIkey",t.target.value),placeholder:"aria2 rpc secret"})]}),e.jsxs("div",{className:"field",children:[e.jsx("label",{children:"RPC Port"}),e.jsx("input",{type:"number",value:s.motrixPort,onChange:t=>n("motrixPort",Number(t.target.value||16800))})]}),e.jsxs("label",{className:"toggle",children:["Extension Enabled",e.jsx("input",{type:"checkbox",checked:s.extensionStatus,onChange:t=>n("extensionStatus",t.target.checked)})]}),e.jsxs("label",{className:"toggle",children:["Use Native Host",e.jsx("input",{type:"checkbox",checked:s.useNativeHost,onChange:t=>n("useNativeHost",t.target.checked)})]}),e.jsxs("label",{className:"toggle",children:["Activate gdown App",e.jsx("input",{type:"checkbox",checked:s.activateAppOnDownload,onChange:t=>n("activateAppOnDownload",t.target.checked)})]}),e.jsx("button",{onClick:d,children:"Save"}),e.jsx("button",{onClick:u,children:"Settings"}),e.jsx("button",{onClick:x,children:"History"}),e.jsx("div",{className:"status",children:l})]}):e.jsx("div",{className:"container",children:"Loading..."})}g.createRoot(document.getElementById("root")).render(e.jsx(c.StrictMode,{children:e.jsx(j,{})})); diff --git a/packages/edge/assets/index.html-yhgSfkXU.js b/packages/edge/assets/index.html-yhgSfkXU.js new file mode 100644 index 0000000..8423b40 --- /dev/null +++ b/packages/edge/assets/index.html-yhgSfkXU.js @@ -0,0 +1,41 @@ +import{c as z,j as e,R as b}from"./client-DnQyoB4h.js";import{g as J,b as d,s as D}from"./settings-mco8QK8Y.js";import{n as M}from"./clipTypes-C_ha5Ash.js";function B(...i){console.log("[gomdown-helper][clip][popup]",...i)}function G(i){return String(i).replace(/\s*[|\-–—]\s*(qiita|medium|youtube|x|twitter|tistory|velog|github)\s*$/i,"").replace(/\s*[-–—|]\s*(edge|chrome|firefox)\s*$/i,"").replace(/\[[^\]]{1,30}\]\s*$/g,"").trim().replace(/[\\/:*?"<>|]/g,"_").replace(/[(){}[\]]/g,"").replace(/\s+/g," ").replace(/[._-]{2,}/g,"-").replace(/^[._\-\s]+|[._\-\s]+$/g,"").slice(0,80)||"clips"}function V(i,x=""){if(!i.trim())return"";const f=new DOMParser().parseFromString(`
${i}
`,"text/html").body.firstElementChild;if(!f)return"";const N=r=>{const s=String(r||"").trim();if(!s)return"";if(!x)return s;try{return new URL(s,x).toString()}catch{return s}},C=r=>String(r||"").replace(/\s+/g," ").trim(),E=r=>{const s=[r.getAttribute("src"),r.getAttribute("data-src"),r.getAttribute("data-original"),r.getAttribute("data-url"),r.currentSrc];for(const o of s){const l=N(String(o||"").trim());if(l)return l}return""},u=r=>r.replace(/\|/g,"\\|").replace(/\n+/g," ").replace(/\s+/g," ").trim(),H=r=>{const s=Array.from(r.querySelectorAll("tr"));if(s.length===0)return"";const o=s.map(j=>Array.from(j.querySelectorAll("th,td")).map(v=>{const P=Array.from(v.childNodes).map(O=>O instanceof HTMLElement&&["pre","ul","ol","table"].includes(O.tagName.toLowerCase())?C(y(O)):g(O)).join("");return u(P)})).filter(j=>j.length>0);if(o.length===0)return"";const l=o.reduce((j,v)=>Math.max(j,v.length),0),p=o.map(j=>{const v=[...j];for(;v.length0:!1,A=S?p[0]:p[0].map((j,v)=>`col${v+1}`),w=S?p.slice(1):p,T=`| ${A.join(" | ")} |`,U=`| ${A.map(()=>"---").join(" | ")} |`,q=w.map(j=>`| ${j.join(" | ")} |`);return[T,U,...q].join(` +`)},g=r=>{if(r.nodeType===Node.TEXT_NODE)return(r.nodeValue||"").replace(/\s+/g," ");if(!(r instanceof HTMLElement))return"";const s=r.tagName.toLowerCase();if(s==="br")return` +`;if(s==="strong"||s==="b")return`**${Array.from(r.childNodes).map(g).join("")}**`;if(s==="em"||s==="i")return`*${Array.from(r.childNodes).map(g).join("")}*`;if(s==="img"){const o=E(r),l=String(r.getAttribute("alt")||"").trim(),p=C(r.getAttribute("title")||""),h=p?` "${p.replace(/"/g,'\\"')}"`:"";return o?`![${l}](${o}${h})`:""}if(s==="a"){const o=N(r.getAttribute("href")||""),l=Array.from(r.childNodes).map(g).join("").trim()||o;return o?`[${l}](${o})`:l}if(s==="code"){if(r.parentElement?.tagName.toLowerCase()==="pre")return r.textContent||"";const o=Array.from(r.childNodes).map(g).join("").replace(/\n+/g," ").trim();return o?`\`${o}\``:""}return Array.from(r.childNodes).map(g).join("")},y=r=>{if(r.nodeType===Node.TEXT_NODE)return(r.nodeValue||"").replace(/\s+/g," ").trim();if(!(r instanceof HTMLElement))return"";const s=r.tagName.toLowerCase();if(s==="pre"){const o=r.querySelector("code"),l=(o?.textContent||r.textContent||"").replace(/\r\n/g,` +`).replace(/\n+$/,""),S=String(o?.className||"").match(/language-([a-z0-9_-]+)/i)?.[1]||"";return l?`\`\`\`${S} +${l} +\`\`\` + +`:""}if(s==="img"){const o=E(r),l=String(r.getAttribute("alt")||"").trim(),p=C(r.getAttribute("title")||""),h=p?` "${p.replace(/"/g,'\\"')}"`:"";return o?`![${l}](${o}${h}) + +`:""}if(s==="figure"){const o=r.querySelector("img"),l=C(r.querySelector("figcaption")?.textContent||"");if(o instanceof HTMLElement){const h=y(o).trim();if(h&&l)return`${h} +*${l}* + +`;if(h)return`${h} + +`}const p=C(Array.from(r.childNodes).map(g).join(""));return p?`${p} + +`:""}if(s==="ul"||s==="ol"){const o=Array.from(r.children).map((l,p)=>{if(!(l instanceof HTMLElement)||l.tagName.toLowerCase()!=="li")return"";const h=Array.from(l.childNodes).map(w=>w instanceof HTMLElement&&(w.tagName.toLowerCase()==="ul"||w.tagName.toLowerCase()==="ol")?"":g(w)).join("").trim(),S=s==="ol"?`${p+1}. `:"- ",A=Array.from(l.children).filter(w=>w.tagName&&["ul","ol"].includes(w.tagName.toLowerCase())).map(w=>y(w).trimEnd().split(` +`).map(T=>T&&` ${T}`).join(` +`)).filter(Boolean).join(` +`);return`${S}${h}${A?` +${A}`:""}`}).filter(Boolean).join(` +`);return o?`${o} + +`:""}if(s==="table"){const o=H(r);return o?`${o} + +`:""}if(s==="p"||s==="div"||s==="section"||s==="article"||s==="blockquote"){const o=Array.from(r.childNodes).map(l=>l instanceof HTMLElement&&["pre","ul","ol","img","table","figure"].includes(l.tagName.toLowerCase())?` +${y(l)}`:g(l)).join("").trim();return o?s==="blockquote"?`${o.split(` +`).map(l=>l?`> ${l}`:">").join(` +`)} + +`:`${o} + +`:""}return s==="code"?"":`${Array.from(r.childNodes).map(y).join("")}`};return y(f).replace(/\n{3,}/g,` + +`).trim()}function W(i,x){if(i.length===0)return"";const n=[`# ${i[0]?.pageTitle||x||"Untitled"}`,`- source: ${x}`,`- exportedAt: ${new Date().toISOString()}`,`- clips: ${i.length}`,"","---",""];for(let f=0;f4e3?`${n.slice(0,4e3)} +...(truncated)`:n,N=f.split(` +`).map(u=>u.trimEnd()).filter((u,H,g)=>!(u===""&&g[H-1]==="")),E=/(^|\n)\|.*\|\n\|[-:| ]+\||(^|\n)```|!\[[^\]]*\]\(|(^|\n)(- |\d+\. )/.test(f)?f:N.length===0?"> ":N.map(u=>`> ${u}`).join(` +`);return[`### ${x+1}. Clip`,E,"",`- created: ${i.createdAt}`,`- status: ${i.resolveStatus||"ok"}`].join(` +`)}function I({kind:i}){return i==="save"?e.jsxs("svg",{viewBox:"0 0 24 24","aria-hidden":"true",children:[e.jsx("path",{d:"M4 4h13l3 3v13H4z",fill:"none",stroke:"currentColor",strokeWidth:"1.8"}),e.jsx("path",{d:"M8 4h8v5H8zM8 14h8v6H8z",fill:"none",stroke:"currentColor",strokeWidth:"1.8"})]}):i==="settings"?e.jsxs("svg",{viewBox:"0 0 24 24","aria-hidden":"true",children:[e.jsx("path",{d:"M12 3l2 1 2-1 2 3-1 2 1 2 2 1v2l-2 1-1 2 1 2-2 3-2-1-2 1-2-1-2 1-2-3 1-2-1-2-2-1v-2l2-1 1-2-1-2 2-3 2 1z",fill:"none",stroke:"currentColor",strokeWidth:"1.4"}),e.jsx("circle",{cx:"12",cy:"12",r:"3",fill:"none",stroke:"currentColor",strokeWidth:"1.8"})]}):i==="history"?e.jsxs("svg",{viewBox:"0 0 24 24","aria-hidden":"true",children:[e.jsx("path",{d:"M5 12a7 7 0 1 0 2-5",fill:"none",stroke:"currentColor",strokeWidth:"1.8"}),e.jsx("path",{d:"M5 4v4h4M12 8v5l3 2",fill:"none",stroke:"currentColor",strokeWidth:"1.8"})]}):i==="send"?e.jsx("svg",{viewBox:"0 0 24 24","aria-hidden":"true",children:e.jsx("path",{d:"M3 12h14M13 6l6 6-6 6",fill:"none",stroke:"currentColor",strokeWidth:"1.8"})}):e.jsxs("svg",{viewBox:"0 0 24 24","aria-hidden":"true",children:[e.jsx("path",{d:"M4 5h16v12H8l-4 3z",fill:"none",stroke:"currentColor",strokeWidth:"1.8"}),e.jsx("path",{d:"M8 9h8M8 12h6",fill:"none",stroke:"currentColor",strokeWidth:"1.8"})]})}function K(){const[i,x]=b.useState(null),[L,n]=b.useState(""),[f,N]=b.useState([]),[C,E]=b.useState(null),[u,H]=b.useState(""),[g,y]=b.useState([]),r=b.useRef(null);b.useEffect(()=>{J().then(x)},[]),b.useEffect(()=>{let t=null;const a=async()=>{const c=await d.runtime.sendMessage({type:"media:list"});c?.ok&&Array.isArray(c.items)&&N(c.items.slice(0,10))};return a(),t=window.setInterval(()=>{a()},2e3),()=>{t!==null&&window.clearInterval(t)}},[]),b.useEffect(()=>{const t=async()=>{const m=(await d.tabs.query({active:!0,currentWindow:!0}))[0],k=M(String(m?.url||""));if(E(Number.isInteger(m?.id)?m?.id:null),H(k),!k){y([]);return}const $=await d.runtime.sendMessage({type:"clip:list",pageUrl:k});$?.ok&&Array.isArray($.items)&&y($.items)};t();const a=window.setInterval(()=>{t()},2500);return()=>{window.clearInterval(a)}},[]);const s=(t,a)=>{x(c=>c&&{...c,[t]:a})},o=async t=>{if(!i)return;const a={...i,extensionStatus:t};x(a),await D({extensionStatus:t}),n(t?"Extension ON":"Extension OFF"),window.setTimeout(()=>n(""),1200)},l=async()=>{i&&(await D(i),n("Saved"),window.setTimeout(()=>n(""),1200))},p=async()=>{const t=d.runtime.getURL("src/config/index.html");await d.tabs.create({url:t})},h=async()=>{const t=d.runtime.getURL("src/history/index.html");await d.tabs.create({url:t})},S=async()=>{const t=await d.runtime.sendMessage({type:"page:enqueue-ytdlp"});n(t?.ok?"Active tab sent to gdown (yt-dlp)":`Send failed: ${t?.error||"unknown error"}`),window.setTimeout(()=>n(""),1800)},A=async t=>{const a=await d.runtime.sendMessage({type:"media:enqueue",url:t.url,referer:t.referer||"",kind:t.kind,suggestedOut:t.suggestedOut||"",cookie:t.cookie||"",userAgent:t.userAgent||""});n(a?.ok?"Media sent to gdown":`Send failed: ${a?.error||"unknown error"}`),window.setTimeout(()=>n(""),1600)},w=async()=>{await d.runtime.sendMessage({type:"media:clear"}),N([]),n("Captured media cleared"),window.setTimeout(()=>n(""),1200)},T=async()=>{B("onCreateClipFromSelection:clicked",{activeTabId:C,activePageUrl:u});const t=await d.runtime.sendMessage({type:"clip:create-active-tab"});if(B("onCreateClipFromSelection:result",t),!t?.ok){n(`클립 생성 실패: ${t?.error||"active tab unavailable"}`),window.setTimeout(()=>n(""),2e3);return}n("클립 저장 완료"),window.setTimeout(()=>n(""),1400);const a=await d.runtime.sendMessage({type:"clip:list",pageUrl:u});a?.ok&&Array.isArray(a.items)&&y(a.items)},U=async t=>{const a=await d.runtime.sendMessage({type:"clip:reveal",id:t});n(a?.ok?a.opened?"클립 페이지를 열었습니다":"클립 위치로 이동":`이동 실패: ${a?.error||"unknown error"}`),window.setTimeout(()=>n(""),1700)},q=async t=>{const a=await d.runtime.sendMessage({type:"clip:delete",id:t});if(!a?.ok){n(`삭제 실패: ${a?.error||"unknown error"}`),window.setTimeout(()=>n(""),1600);return}y(c=>c.filter(m=>m.id!==t)),n("클립 삭제 완료"),window.setTimeout(()=>n(""),1200)},j=async()=>{const t=await d.runtime.sendMessage({type:"clip:export"});if(!t?.ok||!Array.isArray(t.items)){n(`내보내기 실패: ${t?.error||"unknown error"}`),window.setTimeout(()=>n(""),1800);return}const a={exportedAt:new Date().toISOString(),version:1,count:t.items.length,clips:t.items},m=`gomdown-clips-${new Date().toISOString().replace(/[:.]/g,"-")}.json`,k=await d.runtime.sendMessage({type:"file:download-text",filename:m,mime:"application/json;charset=utf-8",content:JSON.stringify(a,null,2)});if(!k?.ok){n(`내보내기 실패: ${k?.error||"download error"}`),window.setTimeout(()=>n(""),1800);return}n(`클립 ${t.items.length}개 내보내기 완료`),window.setTimeout(()=>n(""),1500)},v=()=>{r.current?.click()},P=async()=>{const t=g.filter(k=>M(k.pageUrl)===M(u));if(t.length===0){n("내보낼 클립이 없습니다."),window.setTimeout(()=>n(""),1500);return}const a=t[0]?.pageTitle||u||"Untitled",c=W(t,u),m=await d.runtime.sendMessage({type:"file:download-text",filename:`${G(a)}-clips.md`,mime:"text/markdown;charset=utf-8",content:c});if(!m?.ok){n(`Markdown 내보내기 실패: ${m?.error||"download error"}`),window.setTimeout(()=>n(""),1900);return}n(`Markdown 내보내기 완료 (${t.length}개)`),window.setTimeout(()=>n(""),1700)},O=async()=>{const t=g.filter(c=>M(c.pageUrl)===M(u));if(t.length===0){n("복사할 클립이 없습니다."),window.setTimeout(()=>n(""),1500);return}const a=W(t,u);try{await navigator.clipboard.writeText(a),n(`Markdown 복사 완료 (${t.length}개)`),window.setTimeout(()=>n(""),1700)}catch(c){n(`복사 실패: ${String(c)}`),window.setTimeout(()=>n(""),1700)}},F=async()=>{const t=g.filter(c=>M(c.pageUrl)===M(u));if(t.length===0){n("보낼 클립이 없습니다."),window.setTimeout(()=>n(""),1500);return}const a=t[0]?.pageTitle||u||"Untitled";try{const c=await d.runtime.sendMessage({type:"clip:send-obsidian-current-page",pageUrl:u,pageTitle:a});if(!c?.ok||!c?.uri){n(`Obsidian 전송 실패: ${c?.error||"unknown error"}`),window.setTimeout(()=>n(""),2200);return}window.open(String(c.uri),"_blank"),n("Obsidian 새 노트 전송 시도 완료")}catch(c){n(`Obsidian 전송 실패: ${String(c)}`);try{const m=await d.runtime.sendMessage({type:"clip:send-obsidian-current-page",pageUrl:u,pageTitle:a});m?.ok&&m.uri&&(window.location.href=String(m.uri),n("Obsidian 새 노트 전송 시도 완료"))}catch{}}finally{window.setTimeout(()=>n(""),1900)}},_=async t=>{const a=t.target.files?.[0];if(t.target.value="",!!a)try{const c=await a.text(),m=JSON.parse(c),k=Array.isArray(m)?m:Array.isArray(m?.clips)?m.clips:[];if(!Array.isArray(k)){n("가져오기 실패: JSON 형식이 올바르지 않습니다."),window.setTimeout(()=>n(""),1900);return}const $=await d.runtime.sendMessage({type:"clip:import",items:k});if(!$?.ok){n(`가져오기 실패: ${$?.error||"unknown error"}`),window.setTimeout(()=>n(""),1900);return}n(`가져오기 완료: ${$.imported||0}/${$.total||k.length}`),window.setTimeout(()=>n(""),1900);const R=await d.runtime.sendMessage({type:"clip:list",pageUrl:u});R?.ok&&Array.isArray(R.items)&&y(R.items)}catch(c){n(`가져오기 실패: ${String(c)}`),window.setTimeout(()=>n(""),1900)}};return i?e.jsxs("div",{className:"container",children:[e.jsxs("div",{className:"top-row",children:[e.jsx("h1",{children:"Gomdown Helper"}),e.jsxs("button",{className:`power-toggle ${i.extensionStatus?"on":"off"}`,onClick:()=>{o(!i.extensionStatus)},children:[e.jsx("span",{className:"power-dot"}),i.extensionStatus?"ON":"OFF"]})]}),e.jsxs("div",{className:"field",children:[e.jsx("label",{children:"RPC Secret"}),e.jsx("input",{type:"text",value:i.motrixAPIkey,onChange:t=>s("motrixAPIkey",t.target.value),placeholder:"aria2 rpc secret"})]}),e.jsxs("div",{className:"field",children:[e.jsx("label",{children:"RPC Port"}),e.jsx("input",{type:"number",value:i.motrixPort,onChange:t=>s("motrixPort",Number(t.target.value||16800))})]}),e.jsxs("label",{className:"toggle",children:["Use Native Host",e.jsx("input",{type:"checkbox",checked:i.useNativeHost,onChange:t=>s("useNativeHost",t.target.checked)})]}),e.jsxs("label",{className:"toggle",children:["Activate gdown App",e.jsx("input",{type:"checkbox",checked:i.activateAppOnDownload,onChange:t=>s("activateAppOnDownload",t.target.checked)})]}),e.jsxs("div",{className:"media-panel",children:[e.jsxs("div",{className:"media-head",children:[e.jsx("strong",{children:"Captured Media"}),e.jsx("button",{className:"mini ghost",onClick:w,children:"Clear"})]}),f.length===0?e.jsx("div",{className:"empty",children:"No media captured yet"}):e.jsx("div",{className:"media-list",children:f.map(t=>e.jsxs("div",{className:"media-item",children:[e.jsxs("div",{className:"media-meta",children:[e.jsx("span",{className:"kind",children:t.kind.toUpperCase()}),t.pageTitle?e.jsx("span",{className:"url",children:t.pageTitle}):null,e.jsx("span",{className:"url",children:t.url})]}),e.jsx("button",{className:"mini",onClick:()=>{A(t)},children:"Add"})]},t.id))})]}),e.jsxs("div",{className:"media-panel",children:[e.jsxs("div",{className:"page-clips-head",children:[e.jsxs("div",{className:"page-clips-title-row",children:[e.jsx("strong",{children:"Page Clips"}),e.jsx("span",{className:"hint",children:"Alt+Shift+C"})]}),e.jsxs("div",{className:"page-clips-actions",children:[e.jsx("button",{className:"mini ghost page-action-btn",onClick:()=>{F()},children:"Obsidian"}),e.jsx("button",{className:"mini ghost page-action-btn",onClick:()=>{O()},children:"Copy MD"}),e.jsx("button",{className:"mini ghost page-action-btn",onClick:()=>{P()},children:"MD"}),e.jsx("button",{className:"mini ghost page-action-btn",onClick:()=>{j()},children:"Export"}),e.jsx("button",{className:"mini ghost page-action-btn page-action-btn-wide",onClick:v,children:"Import"})]})]}),e.jsx("input",{ref:r,type:"file",accept:"application/json,.json",style:{display:"none"},onChange:_}),g.length===0?e.jsx("div",{className:"empty",children:"No clips for this page"}):e.jsx("div",{className:"media-list",children:g.map(t=>e.jsxs("div",{className:"clip-item",children:[e.jsxs("div",{className:"media-meta",children:[t.resolveStatus==="broken"?e.jsx("span",{className:"broken-badge",children:"BROKEN"}):null,e.jsx("span",{className:"url",children:t.quote||t.anchor.exact})]}),e.jsxs("div",{className:"clip-actions",children:[e.jsx("button",{className:"mini",onClick:()=>{U(t.id)},children:"Go"}),e.jsx("button",{className:"mini ghost",onClick:()=>{q(t.id)},children:"Del"})]})]},t.id))})]}),e.jsx("div",{className:"status",children:L}),e.jsxs("div",{className:"action-dock",children:[e.jsxs("button",{className:"action-btn",onClick:l,title:"Save",children:[e.jsx(I,{kind:"save"}),e.jsx("span",{children:"Save"})]}),e.jsxs("button",{className:"action-btn",onClick:p,title:"Settings",children:[e.jsx(I,{kind:"settings"}),e.jsx("span",{children:"Settings"})]}),e.jsxs("button",{className:"action-btn",onClick:h,title:"History",children:[e.jsx(I,{kind:"history"}),e.jsx("span",{children:"History"})]}),e.jsxs("button",{className:"action-btn",onClick:()=>{S()},title:"Send Active",children:[e.jsx(I,{kind:"send"}),e.jsx("span",{children:"Send"})]}),e.jsxs("button",{className:"action-btn",onClick:()=>{T()},title:"Capture Selection",children:[e.jsx(I,{kind:"clip"}),e.jsx("span",{children:"Capture"})]})]})]}):e.jsx("div",{className:"container",children:"Loading..."})}z.createRoot(document.getElementById("root")).render(e.jsx(b.StrictMode,{children:e.jsx(K,{})})); diff --git a/packages/edge/assets/index.ts-BGLNJwsP.js b/packages/edge/assets/index.ts-BGLNJwsP.js deleted file mode 100644 index 04f2aec..0000000 --- a/packages/edge/assets/index.ts-BGLNJwsP.js +++ /dev/null @@ -1 +0,0 @@ -import{b as w}from"./browser-polyfill-CZ_dLIqp.js";import{i as o,n as h}from"./downloadIntent-Dv31jC2S.js";const p=8e3,e=new Map;function m(){const r=Date.now();for(const[n,t]of e.entries())t<=r&&e.delete(n)}async function i(r,n){const t=h(r,window.location.href);if(!t)return!1;if(m(),e.has(t))return!0;e.set(t,Date.now()+p);try{if((await w.runtime.sendMessage({type:"capture-link-download",url:t,referer:n||document.referrer||window.location.href}))?.ok)return!0}catch{}return e.delete(t),!1}function u(r){return r?r instanceof HTMLAnchorElement?r:r instanceof Element?r.closest("a[href]"):null:null}function a(r){return!!(r.metaKey||r.ctrlKey||r.shiftKey||r.altKey)}async function d(r){if(r.defaultPrevented||a(r))return;const n=u(r.target);if(!n)return;const t=n.href||"";!t||!o(t,window.location.href)||(r.preventDefault(),r.stopImmediatePropagation(),r.stopPropagation(),await i(t,document.referrer||window.location.href))}function l(r){const n=u(r.target);if(!n)return;const t=n.href||"";!t||!o(t,window.location.href)||a(r)||(r.preventDefault(),r.stopImmediatePropagation(),r.stopPropagation(),i(t,document.referrer||window.location.href))}document.addEventListener("pointerdown",r=>{r.button===0&&l(r)},!0);document.addEventListener("mousedown",r=>{r.button===0&&l(r)},!0);document.addEventListener("click",r=>{r.button===0&&d(r)},!0);document.addEventListener("keydown",r=>{if(r.key!=="Enter"||r.defaultPrevented||a(r))return;const n=u(r.target);if(!n)return;const t=n.href||"";!t||!o(t,window.location.href)||(r.preventDefault(),r.stopImmediatePropagation(),r.stopPropagation(),i(t,document.referrer||window.location.href))},!0);document.addEventListener("auxclick",r=>{r.button===1&&d(r)},!0);function g(){try{const r=window.open.bind(window);window.open=function(t,f,s){const c=String(t||"").trim();return c&&o(c,window.location.href)?(i(c,window.location.href),null):r(t,f,s)}}catch{}try{const r=HTMLAnchorElement.prototype.click;HTMLAnchorElement.prototype.click=function(){const t=this.href||this.getAttribute("href")||"";if(t&&o(t,window.location.href)){i(t,document.referrer||window.location.href);return}r.call(this)}}catch{}}g(); diff --git a/packages/edge/assets/index.ts-BnPsJZXz.js b/packages/edge/assets/index.ts-BnPsJZXz.js deleted file mode 100644 index b18e2ea..0000000 --- a/packages/edge/assets/index.ts-BnPsJZXz.js +++ /dev/null @@ -1 +0,0 @@ -import{b as r}from"./browser-polyfill-CZ_dLIqp.js";import{n as v,a as k}from"./downloadIntent-Dv31jC2S.js";import{g as d}from"./settings-Bo6W9Drl.js";const C="org.gdown.nativehost";async function L(e){return r.runtime.sendNativeMessage(C,{action:"addUri",...e})}async function I(){return r.runtime.sendNativeMessage(C,{action:"focus"})}const p="history";async function H(){const t=(await r.storage.local.get([p]))[p];return Array.isArray(t)?t:[]}async function M(e){await r.storage.local.set({[p]:e.slice(0,300)})}async function T(e){const t=await H(),n=t.findIndex(o=>o.gid===e.gid);n>=0?t[n]=e:t.unshift(e),await M(t)}const y=8e3,A=7e3,D="gomdown-helper-download-context-menu-option",c=new Map,w=new Map,g=new Map,m=new Map,a=new Map,h=new Map;function l(e){try{const t=new URL(e),n=(t.pathname||"/").replace(/\/+$/,"")||"/";return`${t.protocol}//${t.host}${n}`.toLowerCase()}catch{return String(e||"").toLowerCase()}}function i(e){const t=Date.now();for(const[n,o]of e.entries())o<=t&&e.delete(n)}function R(e){const t=Date.now()+y;w.set(v(e),t),g.set(l(e),t)}function q(e){!Number.isInteger(e)||(e??-1)<0||h.set(e,Date.now()+y)}function N(e){i(w),i(g);const t=v(e);return w.has(t)||g.has(l(e))}function _(e){return i(h),!Number.isInteger(e)||(e??-1)<0?!1:h.has(e)}function E(e){return i(m),m.has(l(e))}function F(e){m.set(l(e),Date.now()+A)}function O(e){return i(a),!!e&&a.has(e)}function P(e){e&&a.set(e,Date.now()+y)}async function $(){try{await I()}catch{}}async function S(e,t=""){if(E(e))return{ok:!1,error:"duplicate transfer suppressed"};const n=await d();if(!n.extensionStatus)return{ok:!1,error:"extension disabled"};if(!n.motrixAPIkey)return{ok:!1,error:"motrixAPIkey is not set"};try{const o=await L({url:e,rpcPort:n.motrixPort,rpcSecret:n.motrixAPIkey,referer:t,split:64});if(!o?.ok)return{ok:!1,error:o?.error||"native host addUri failed"};n.activateAppOnDownload&&await $(),F(e);const s=String(o?.gid||o?.requestId||`pending-${Date.now()}`),U=(()=>{try{return new URL(e).pathname}catch{return""}})().split("/").filter(Boolean).pop()||e;return await T({gid:s,downloader:"native",startTime:new Date().toISOString(),icon:"/images/32.png",name:decodeURIComponent(U),path:null,status:o?.pending?"queued":"downloading",size:0,downloaded:0}),n.enableNotifications&&await r.notifications.create(`gomdown-transfer-${Date.now()}`,{type:"basic",iconUrl:"/images/icon-large.png",title:"Gomdown Helper",message:"Download sent to gdown"}),{ok:!0}}catch(o){return{ok:!1,error:String(o)}}}async function z(e){if(e.type!=="main_frame"||(e.method||"").toUpperCase()!=="GET"||typeof e.statusCode=="number"&&(e.statusCode<200||e.statusCode>299))return!1;const t=await d();if(!t.extensionStatus||!t.motrixAPIkey)return!1;const n=String(Array.isArray(e?.responseHeaders)&&e.responseHeaders.find(s=>String(s?.name||"").toLowerCase()==="content-length")?.value||""),o=Number(n||0);return t.minFileSize>0&&o>0&&o{await u();const t=e,n=t.finalUrl||t.url||"";!N(n)&&!_(t.tabId)||(await r.downloads.cancel(e.id).catch(()=>null),await r.downloads.erase({id:e.id}).catch(()=>null),await r.downloads.removeFile(e.id).catch(()=>null))})}function x(){r.webRequest.onSendHeaders.addListener(e=>{c.set(e.requestId,e)},{urls:[""]},["requestHeaders","extraHeaders"]),r.webRequest.onErrorOccurred.addListener(e=>{c.delete(e.requestId),a.delete(String(e.requestId))},{urls:[""]}),r.webRequest.onCompleted.addListener(e=>{c.delete(e.requestId),a.delete(String(e.requestId))},{urls:[""]}),r.webRequest.onHeadersReceived.addListener(e=>{G(e)},{urls:[""]},["responseHeaders"])}function f(){r.contextMenus.removeAll().then(async()=>{const e=await d();e.showContextOption&&r.contextMenus.create({id:D,title:"Download with Gomdown",visible:e.showContextOption,contexts:["all"]})}),r.contextMenus.onClicked.addListener(async e=>{const t=e.linkUrl||e.srcUrl||e.pageUrl;t&&await S(t)})}r.runtime.onMessage.addListener((e,t)=>{if(e?.type!=="capture-link-download")return;const n=String(e?.url||"").trim();if(!n)return Promise.resolve({ok:!1,error:"url is empty"});const o=Number(t?.tab?.id);return S(n,String(e?.referer||"")).then(s=>(s.ok&&(R(n),q(o)),s))});r.runtime.onInstalled.addListener(()=>{x(),b(),f(),u()});r.runtime.onStartup.addListener(()=>{x(),b(),f(),u()});r.storage.onChanged.addListener((e,t)=>{t==="sync"&&((e.hideChromeBar||e.useNativeHost||e.extensionStatus)&&u(),e.showContextOption&&f())});x();b();f();u(); diff --git a/packages/edge/assets/index.ts-D64R0PS1.js b/packages/edge/assets/index.ts-D64R0PS1.js new file mode 100644 index 0000000..d194271 --- /dev/null +++ b/packages/edge/assets/index.ts-D64R0PS1.js @@ -0,0 +1,7 @@ +import{b as c,g as k}from"./settings-mco8QK8Y.js";import{n as mt,a as $t}from"./downloadIntent-Dv31jC2S.js";import{n as x,a as qt}from"./clipTypes-C_ha5Ash.js";const yt="org.gdown.nativehost";async function At(t){return c.runtime.sendNativeMessage(yt,{action:"addUri",...t})}async function Ot(){return c.runtime.sendNativeMessage(yt,{action:"focus"})}const G="history";async function Nt(){const e=(await c.storage.local.get([G]))[G];return Array.isArray(e)?e:[]}async function Rt(t){await c.storage.local.set({[G]:t.slice(0,300)})}async function Et(t){const e=await Nt(),n=e.findIndex(r=>r.gid===t.gid);n>=0?e[n]=t:e.unshift(t),await Rt(e)}function ht(t,e){const n=Array.isArray(t?.responseHeaders)?t.responseHeaders:[],r=e.toLowerCase(),o=n.find(i=>String(i?.name||"").toLowerCase()===r);return String(o?.value||"")}function Lt(t){const e=t.toLowerCase();return e?e.includes("application/vnd.apple.mpegurl")||e.includes("application/x-mpegurl")||e.includes("audio/mpegurl")?"m3u8":e.includes("video/mp4")?"mp4":e.includes("application/octet-stream")&&e.includes("m3u8")?"m3u8":e.includes("hls")?"hls":"unknown":"unknown"}function Dt(t){const e=String(t||"").toLowerCase();return e.includes(".m3u8")?"m3u8":e.includes(".m3u")?"m3u":e.includes(".mp4")?"mp4":e.includes("m3u8")?"m3u8":e.includes("hls")?"hls":"unknown"}function wt(t,e){const n=Lt(e);return n!=="unknown"?n:Dt(t)}function Ht(t){if(!t?.url)return!1;const e=String(t?.method||"").toUpperCase();if(e&&e!=="GET")return!1;const n=Number(t?.statusCode||0);if(n>0&&(n<200||n>299))return!1;const r=String(t?.type||"");if(!["xmlhttprequest","media","other","main_frame","sub_frame","fetch"].includes(r))return!1;const o=ht(t,"content-type");return wt(t.url,o)!=="unknown"}function Bt(t,e=""){const n=ht(t,"content-type"),r=String(t?.url||""),o=wt(r,n),i=Number.isInteger(t?.tabId)?Number(t.tabId):-1,a=Date.now();return{id:`${a}:${i}:${o}:${r}`,url:r,kind:o,tabId:i,pageUrl:String(t?.documentUrl||t?.initiator||""),referer:String(e||t?.documentUrl||t?.initiator||""),contentType:n,detectedAt:a}}function rt(t){try{const e=new URL(t);return`${e.protocol}//${e.host}${e.pathname}`.toLowerCase()}catch{return String(t||"").toLowerCase()}}const F="media_candidates",_t=200;async function St(){const e=(await c.storage.local.get([F]))[F];return Array.isArray(e)?e:[]}async function Ft(t){const e=[...t].sort((n,r)=>r.detectedAt-n.detectedAt);await c.storage.local.set({[F]:e.slice(0,_t)})}async function Pt(t,e){const n=await St(),r=n.findIndex(o=>{try{const i=new URL(o.url);return`${i.protocol}//${i.host}${i.pathname}`.toLowerCase()===e}catch{return o.url.toLowerCase()===e}});r>=0?n[r]={...n[r],...t,detectedAt:Date.now()}:n.unshift(t),await Ft(n)}async function zt(){await c.storage.local.set({[F]:[]})}const V="clips",jt=500;function xt(t,e){return Date.parse(e.createdAt||"")-Date.parse(t.createdAt||"")}function q(t){return`${x(t.pageUrl)}::${qt(t.quote).toLowerCase()}`}async function b(){const e=(await c.storage.local.get([V]))[V];return Array.isArray(e)?e:[]}async function O(t){const e=[...t].sort(xt).slice(0,jt);await c.storage.local.set({[V]:e})}async function ot(t){const e=x(t);return(await b()).filter(r=>x(r.pageUrl)===e).sort(xt)}async function Wt(t){return(await b()).find(r=>r.id===t)||null}async function bt(t){const e=await b(),n=q(t),r=e.find(a=>q(a)===n);if(r){const a=e.findIndex(s=>s.id===r.id);return a>=0?(e[a]={...e[a],tabId:t.tabId??e[a].tabId,pageTitle:t.pageTitle||e[a].pageTitle,anchor:t.anchor||e[a].anchor,resolveStatus:t.resolveStatus??e[a].resolveStatus,resolveUpdatedAt:t.resolveUpdatedAt??e[a].resolveUpdatedAt},await O(e),e[a]):r}const o=Date.now(),i=e.find(a=>{const s=Date.parse(a.createdAt||"");return!Number.isFinite(s)||Math.abs(o-s)>8e3?!1:q(a)===n});return i||(e.unshift(t),await O(e),t)}async function Gt(t){const e=await b(),n=e.filter(r=>r.id!==t);return n.length===e.length?!1:(await O(n),!0)}async function B(t,e){const n=await b(),r=n.findIndex(a=>a.id===t);if(r<0)return null;const o=n[r];if(o.resolveStatus===e)return o;const i={...o,resolveStatus:e,resolveUpdatedAt:new Date().toISOString()};return n[r]=i,await O(n),i}function Vt(t){if(!t||typeof t!="object")return null;const e=x(String(t.pageUrl||"")),n=String(t.quote||t?.anchor?.exact||"").trim(),r=String(t?.anchor?.exact||n).trim();if(!e||!n||!r)return null;const o=String(t.createdAt||new Date().toISOString());return{id:String(t.id||`clip-${Date.now()}-${Math.random().toString(36).slice(2,8)}`),tabId:Number.isInteger(t.tabId)?Number(t.tabId):void 0,pageUrl:e,pageTitle:String(t.pageTitle||e),quote:n,quoteHtml:t.quoteHtml?String(t.quoteHtml):void 0,createdAt:o,color:"yellow",resolveStatus:t.resolveStatus==="broken"?"broken":t.resolveStatus==="ok"?"ok":void 0,resolveUpdatedAt:t.resolveUpdatedAt?String(t.resolveUpdatedAt):void 0,anchor:{exact:r,prefix:t?.anchor?.prefix?String(t.anchor.prefix):void 0,suffix:t?.anchor?.suffix?String(t.anchor.suffix):void 0,xpathStart:t?.anchor?.xpathStart?String(t.anchor.xpathStart):void 0,xpathEnd:t?.anchor?.xpathEnd?String(t.anchor.xpathEnd):void 0,startOffset:Number.isInteger(t?.anchor?.startOffset)?Number(t.anchor.startOffset):void 0,endOffset:Number.isInteger(t?.anchor?.endOffset)?Number(t.anchor.endOffset):void 0,startTextOffset:Number.isInteger(t?.anchor?.startTextOffset)?Number(t.anchor.startTextOffset):void 0,endTextOffset:Number.isInteger(t?.anchor?.endTextOffset)?Number(t.anchor.endTextOffset):void 0}}}async function Xt(t){const e=Array.isArray(t)?t.map(Vt).filter(Boolean):[];if(e.length===0)return{imported:0,total:0};const r=[...await b()];let o=0;for(const i of e){const a=r.findIndex(f=>f.id===i.id);if(a>=0){r[a]={...r[a],...i},o+=1;continue}const s=q(i),u=r.findIndex(f=>q(f)===s);if(u>=0){r[u]={...r[u],...i,id:r[u].id},o+=1;continue}r.unshift(i),o+=1}return await O(r),{imported:o,total:e.length}}const P=8e3,Yt=7e3,X="gomdown-helper-download-context-menu-option",Y="obsidianLastVault",A=new Map,K=new Map,J=new Map,Q=new Map,N=new Map,Z=new Map,tt=new Map;let ct=!1,lt=!1,ut=!1,$=null;const kt="bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]/best",Kt=[{hosts:["youtube.com","www.youtube.com","m.youtube.com","youtu.be"],extractor:"yt-dlp",format:kt}];function w(...t){console.log("[gomdown-helper][clip][bg]",...t)}function z(t){try{const e=new URL(t),n=(e.pathname||"/").replace(/\/+$/,"")||"/";return`${e.protocol}//${e.host}${n}`.toLowerCase()}catch{return String(t||"").toLowerCase()}}function I(t){const e=Date.now();for(const[n,r]of t.entries())r<=e&&t.delete(n)}function vt(t){const e=Date.now()+P;K.set(mt(t),e),J.set(z(t),e)}function Ct(t){!Number.isInteger(t)||(t??-1)<0||Z.set(t,Date.now()+P)}function Jt(t){I(K),I(J);const e=mt(t);return K.has(e)||J.has(z(t))}function Qt(t){return I(Z),!Number.isInteger(t)||(t??-1)<0?!1:Z.has(t)}function Zt(t){return I(Q),Q.has(z(t))}function te(t){Q.set(z(t),Date.now()+Yt)}function ee(t){return I(N),!!t&&N.has(t)}function ne(t){t&&N.set(t,Date.now()+P)}function re(t){I(tt);const e=rt(t);return tt.has(e)}function oe(t){tt.set(rt(t),Date.now()+P)}async function ie(){try{await Ot()}catch{}}async function _(t){await c.notifications.create(`gomdown-notice-${Date.now()}`,{type:"basic",iconUrl:"/images/icon-large.png",title:"Gomdown Helper",message:t}).catch(()=>null)}async function C(t,e="",n,r,o,i){if(Zt(t))return{ok:!1,error:"duplicate transfer suppressed"};const a=await k();if(!a.extensionStatus)return{ok:!1,error:"extension disabled"};if(!a.motrixAPIkey)return{ok:!1,error:"motrixAPIkey is not set"};try{const s=await At({url:t,rpcPort:a.motrixPort,rpcSecret:a.motrixAPIkey,referer:e,split:64,out:o?.trim()||void 0,cookie:i?.cookie?.trim()||void 0,userAgent:i?.userAgent?.trim()||void 0,authorization:i?.authorization?.trim()||void 0,proxy:i?.proxy?.trim()||void 0,extractor:n==="yt-dlp"?"yt-dlp":void 0,format:n==="yt-dlp"?r||kt:void 0});if(!s?.ok)return{ok:!1,error:s?.error||"native host addUri failed"};a.activateAppOnDownload&&await ie(),te(t);const u=String(s?.gid||s?.requestId||`pending-${Date.now()}`),d=(()=>{try{return new URL(t).pathname}catch{return""}})().split("/").filter(Boolean).pop()||t;return await Et({gid:u,downloader:"native",startTime:new Date().toISOString(),icon:"/images/32.png",name:decodeURIComponent(d),path:null,status:s?.pending?"queued":"downloading",size:0,downloaded:0}),a.enableNotifications&&await c.notifications.create(`gomdown-transfer-${Date.now()}`,{type:"basic",iconUrl:"/images/icon-large.png",title:"Gomdown Helper",message:"Download sent to gdown"}),{ok:!0}}catch(s){return{ok:!1,error:String(s)}}}function dt(t){try{return new URL(t).hostname.toLowerCase()}catch{return""}}function It(t,e="",n=""){const r=[dt(t),dt(e)].filter(Boolean);for(const i of Kt)if(r.some(a=>i.hosts.includes(a)))return{extractor:i.extractor,format:i.format};const o=n.toLowerCase();return o==="m3u8"||o==="m3u"||o==="hls"?{extractor:"yt-dlp",format:"best"}:o==="mp4"?{extractor:"aria2"}:{extractor:"aria2"}}function ft(t,e){const n=e.toLowerCase(),r=t.find(o=>String(o?.name||"").toLowerCase()===n);return String(r?.value||"").trim()}async function ae(t){if(t.type!=="main_frame"||(t.method||"").toUpperCase()!=="GET"||typeof t.statusCode=="number"&&(t.statusCode<200||t.statusCode>299))return!1;const e=await k();if(!e.extensionStatus||!e.motrixAPIkey)return!1;const n=String(Array.isArray(t?.responseHeaders)&&t.responseHeaders.find(o=>String(o?.name||"").toLowerCase()==="content-length")?.value||""),r=Number(n||0);return e.minFileSize>0&&r>0&&r=0){const m=await c.tabs.get(s.tabId).catch(()=>null);u=String(m?.title||"").trim()}const f=de(s.url,s.kind,u),d={...s,pageTitle:u||void 0,cookie:i||void 0,userAgent:a||void 0,suggestedOut:f||void 0};await Pt(d,rt(d.url)),oe(d.url),d.tabId>=0&&await c.tabs.sendMessage(d.tabId,{type:"media:captured",kind:d.kind,url:d.url,suggestedOut:d.suggestedOut||""}).catch(()=>null)}function le(t){let e=t.trim().replace(/[\\/:*?"<>|]/g,"_").replace(/\s+/g," ").replace(/^\.+/,"").replace(/\.+$/,"");return e.length>180&&(e=e.slice(0,180).trim()),e}function ue(t){try{return new URL(t).pathname.toLowerCase().match(/\.([a-z0-9]{2,6})(?:$|[?#])/)?.[1]||""}catch{return""}}function de(t,e,n){const r=le(n||""),i=ue(t)||(e==="mp4"||e==="m3u8"||e==="m3u"||e==="hls"?"mp4":"");return r?!i||r.toLowerCase().endsWith(`.${i}`)?r:`${r}.${i}`:""}async function E(){const t=c.downloads;if(!t.setShelfEnabled)return;const e=await k();if(!e.extensionStatus)return;const n=e.useNativeHost?!1:!e.hideChromeBar;await t.setShelfEnabled(n)}function it(){lt||(lt=!0,c.downloads.onCreated.addListener(async t=>{await E();const e=t,n=e.finalUrl||e.url||"";!Jt(n)&&!Qt(e.tabId)||(await c.downloads.cancel(t.id).catch(()=>null),await c.downloads.erase({id:t.id}).catch(()=>null),await c.downloads.removeFile(t.id).catch(()=>null))}))}function at(){ct||(ct=!0,c.webRequest.onSendHeaders.addListener(t=>{A.set(t.requestId,t)},{urls:[""]},["requestHeaders","extraHeaders"]),c.webRequest.onErrorOccurred.addListener(t=>{A.delete(t.requestId),N.delete(String(t.requestId))},{urls:[""]}),c.webRequest.onCompleted.addListener(t=>{A.delete(t.requestId),N.delete(String(t.requestId))},{urls:[""]}),c.webRequest.onHeadersReceived.addListener(t=>{se(t),ce(t)},{urls:[""]},["responseHeaders"]))}async function pt(t,e){console.log("[gomdown-helper] context menu clicked",{menuItemId:t?.menuItemId,linkUrl:t?.linkUrl,srcUrl:t?.srcUrl,frameUrl:t?.frameUrl,pageUrl:t?.pageUrl,tabUrl:e?.url});const n=t?.menuItemId;if(n!=null&&String(n)!==X)return;const r=String(t?.linkUrl||t?.srcUrl||"").trim(),o=String(t?.frameUrl||t?.pageUrl||e?.url||"").trim(),a=String(r||o||"").trim();if(!a||/^(about:|chrome:|chrome-extension:|edge:|brave:)/i.test(a)){await _("다운로드 가능한 URL을 찾지 못했습니다.");return}const s=It(a,String(t?.pageUrl||e?.url||""),""),u=await C(a,String(t?.pageUrl||e?.url||""),s.extractor,s.format);if(!u.ok){await _(`전송 실패: ${u.error||"unknown error"}`);return}await _(s.extractor==="yt-dlp"?"페이지 URL을 yt-dlp로 gdown에 전송했습니다.":"gdown으로 전송했습니다.")}function fe(){if(typeof chrome>"u"||!chrome.contextMenus?.create){c.contextMenus.create({id:X,title:"Download with Gomdown",visible:!0,contexts:["all"]});return}chrome.contextMenus.create({id:X,title:"Download with Gomdown",contexts:["all"]},()=>{chrome.runtime.lastError})}function st(){ut||(typeof chrome<"u"&&chrome.contextMenus?.onClicked?chrome.contextMenus.onClicked.addListener((t,e)=>{pt(t,e)}):c.contextMenus.onClicked.addListener((t,e)=>{pt(t,e)}),ut=!0)}async function pe(){const t=await k();if(!t.extensionStatus||!t.showContextOption){await c.contextMenus.removeAll().catch(()=>null);return}await c.contextMenus.removeAll().catch(()=>null),fe()}function R(){return $||($=pe().finally(()=>{$=null}),$)}async function Ut(){w("requestCreateClipOnActiveTab:start");const e=(await c.tabs.query({active:!0,currentWindow:!0}))[0],n=Number(e?.id);if(w("active tab",{tabId:n,url:String(e?.url||""),title:String(e?.title||"")}),!Number.isInteger(n)||n<0)return w("requestCreateClipOnActiveTab:fail","active tab is unavailable"),{ok:!1,error:"active tab is unavailable"};const r=async()=>await c.tabs.sendMessage(n,{type:"clip:create-from-selection"});try{let o;try{o=await r()}catch(i){throw w("first sendMessage failed, using scripting fallback",String(i)),i}return w("content response",o),o?.ok?{ok:!0}:(w("requestCreateClipOnActiveTab:fail",o?.error||"failed to create clip in active tab"),{ok:!1,error:o?.error||"failed to create clip in active tab"})}catch(o){w("requestCreateClipOnActiveTab:exception",String(o));const i=await be(n,{url:String(e?.url||""),title:String(e?.title||"")}).catch(a=>(w("scripting fallback exception",String(a)),{ok:!1,error:String(a)}));return i.ok?{ok:!0}:{ok:!1,error:i.error||"content script is not ready on active tab"}}}async function ge(t){try{return!!(await c.scripting.executeScript({target:{tabId:t},func:()=>{const n="gomdown-inline-actionbar-fallback",r=document.getElementById(n);if(r)return r.style.display="flex",{ok:!0};const o=document.createElement("div");o.id=n,o.style.position="fixed",o.style.left="50%",o.style.bottom="14px",o.style.transform="translateX(-50%)",o.style.zIndex="2147483647",o.style.display="flex",o.style.gap="8px",o.style.padding="10px",o.style.background="rgba(15, 20, 31, 0.94)",o.style.border="1px solid rgba(97, 112, 155, 0.52)",o.style.borderRadius="12px",o.style.boxShadow="0 12px 24px rgba(0, 0, 0, 0.3)",o.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif";const i=document.createElement("div");i.textContent="Gomdown Quick Action",i.style.fontSize="11px",i.style.color="#c9d4f2",i.style.display="flex",i.style.alignItems="center",i.style.padding="0 2px";const a=(l,p=!1)=>{const y=document.createElement("button");return y.type="button",y.textContent=l,y.style.height="32px",y.style.padding="0 12px",y.style.borderRadius="8px",y.style.border=p?"1px solid #5c6cf3":"1px solid #4b5873",y.style.background=p?"#5c6cf3":"#2a3346",y.style.color="#e8edff",y.style.fontSize="12px",y.style.fontWeight="700",y.style.cursor="pointer",y},s=a("클립 저장",!0),u=a("현재 페이지"),f=a("MD"),d=a("JSON"),m=a("Obsidian"),h=a("닫기"),g=document.createElement("div");return g.style.display="none",g.style.gap="6px",g.style.alignItems="center",g.style.flexWrap="wrap",g.appendChild(f),g.appendChild(d),g.appendChild(m),s.onclick=()=>{try{chrome.runtime.sendMessage({type:"clip:create-active-tab"},l=>{const p=!!l?.ok;i.textContent=p?"클립 저장 완료":`실패: ${String(l?.error||"unknown error")}`,i.style.color=p?"#8ff0a4":"#ffaaaa",p&&(g.style.display="flex")})}catch(l){i.textContent=`실패: ${String(l)}`,i.style.color="#ffaaaa"}},u.onclick=()=>{try{chrome.runtime.sendMessage({type:"page:enqueue-ytdlp-url",url:window.location.href,referer:window.location.href},l=>{const p=!!l?.ok;i.textContent=p?"현재 페이지 전송 완료":`실패: ${String(l?.error||"unknown error")}`,i.style.color=p?"#8ff0a4":"#ffaaaa"})}catch(l){i.textContent=`실패: ${String(l)}`,i.style.color="#ffaaaa"}},f.onclick=()=>{try{chrome.runtime.sendMessage({type:"clip:export-current-page-md",pageUrl:window.location.href,pageTitle:document.title||window.location.href},l=>{const p=!!l?.ok;i.textContent=p?"MD 내보내기 완료":`실패: ${String(l?.error||"unknown error")}`,i.style.color=p?"#8ff0a4":"#ffaaaa"})}catch(l){i.textContent=`실패: ${String(l)}`,i.style.color="#ffaaaa"}},d.onclick=()=>{try{chrome.runtime.sendMessage({type:"clip:export-current-page-json",pageUrl:window.location.href,pageTitle:document.title||window.location.href},l=>{const p=!!l?.ok;i.textContent=p?"JSON 내보내기 완료":`실패: ${String(l?.error||"unknown error")}`,i.style.color=p?"#8ff0a4":"#ffaaaa"})}catch(l){i.textContent=`실패: ${String(l)}`,i.style.color="#ffaaaa"}},m.onclick=()=>{try{chrome.runtime.sendMessage({type:"clip:send-obsidian-current-page",pageUrl:window.location.href,pageTitle:document.title||window.location.href},l=>{if(!!(l?.ok&&l?.uri)){try{window.open(String(l.uri),"_blank")}catch{window.location.href=String(l.uri)}i.textContent="Obsidian 전송 시도 완료",i.style.color="#8ff0a4";return}i.textContent=`실패: ${String(l?.error||"unknown error")}`,i.style.color="#ffaaaa"})}catch(l){i.textContent=`실패: ${String(l)}`,i.style.color="#ffaaaa"}},h.onclick=()=>{o.remove()},o.appendChild(s),o.appendChild(u),o.appendChild(h),o.appendChild(g),o.appendChild(i),document.documentElement.appendChild(o),window.setTimeout(()=>{o.remove()},9e3),{ok:!0}}}))?.[0]?.result?.ok}catch{return!1}}function Tt(){try{return crypto.randomUUID()}catch{return`clip-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}}function me(t,e){const n=String(t.quote||t.anchor?.exact||"").replace(/\r\n/g,` +`).trim(),o=(n.length>4e3?`${n.slice(0,4e3)} +...(truncated)`:n).split(` +`).map(a=>a.trimEnd()).filter((a,s,u)=>!(a===""&&u[s-1]==="")),i=o.length===0?"> ":o.map(a=>`> ${a}`).join(` +`);return[`### ${e+1}. Clip`,i,"",`- created: ${t.createdAt}`,`- status: ${t.resolveStatus||"ok"}`].join(` +`)}function Mt(t,e,n=""){const o=[`# ${n||t[0]?.pageTitle||e||"Untitled"}`,`- source: ${e}`,`- exportedAt: ${new Date().toISOString()}`,`- clips: ${t.length}`,"","---",""];for(let i=0;i|]/g,"_").replace(/[(){}[\]]/g,"").replace(/\s+/g," ").replace(/[._-]{2,}/g,"-").replace(/^[._\-\s]+|[._\-\s]+$/g,"").slice(0,90)||"clips"}function ye(t,e){let n=String(t||"").trim(),r=String(e||"").trim();if(n.includes("/")||n.includes("\\")){const o=n.split(/[\\/]+/).filter(Boolean);n=o[o.length-1]||""}return(/^myvault$/i.test(n)||/^example$/i.test(n))&&(n=""),r=r.replace(/^\/+|\/+$/g,""),{vault:n,folder:r}}async function he(){try{const t=await c.storage.local.get(Y);return String(t?.[Y]||"").trim()}catch{return""}}async function we(t){const e=String(t||"").trim();if(e)try{await c.storage.local.set({[Y]:e})}catch{}}async function nt(t,e,n){if(!t.trim())return{ok:!1,error:"filename is empty"};const r=`data:${e},${encodeURIComponent(n)}`;try{return{ok:!0,downloadId:await c.downloads.download({url:r,filename:t.trim(),saveAs:!0})}}catch(o){return{ok:!1,error:String(o)}}}async function gt(t,e,n){const r=x(String(t||"").trim());if(!r)return{ok:!1,error:"pageUrl is empty"};const o=await ot(r);if(o.length===0)return{ok:!1,error:"no clips for current page"};const i=String(e||o[0]?.pageTitle||r).trim();if(n==="md"){const f=Mt(o,r,i),d=`${et(i)}-clips.md`,m=await nt(d,"text/markdown;charset=utf-8",f);return{ok:m.ok,error:m.error,count:o.length,downloadId:m.downloadId}}const a={exportedAt:new Date().toISOString(),version:1,count:o.length,clips:o},s=`${et(i)}-clips.json`,u=await nt(s,"application/json;charset=utf-8",JSON.stringify(a,null,2));return{ok:u.ok,error:u.error,count:o.length,downloadId:u.downloadId}}async function Se(t,e){const n=x(String(t||"").trim());if(!n)return{ok:!1,error:"pageUrl is empty"};const r=await ot(n);if(r.length===0)return{ok:!1,error:"no clips for current page"};const o=await k(),i=ye(o.obsidianVault,o.obsidianFolder);i.vault&&await we(i.vault);const a=i.vault||await he(),s=String(e||r[0]?.pageTitle||n).trim(),u=Mt(r,n,s),f=i.folder,d=`${et(s)}-${new Date().toISOString().slice(0,19).replace(/[:T]/g,"-")}`,m=f?`${f}/${d}`:d,h=`file=${encodeURIComponent(m)}&content=${encodeURIComponent(u)}`;return{ok:!0,uri:a?`obsidian://new?vault=${encodeURIComponent(a)}&${h}`:`obsidian://new?${h}`,count:r.length}}async function xe(t,e){try{return!!(await c.scripting.executeScript({target:{tabId:t},args:[e.quote||e.anchor?.exact||"",e.anchor?.prefix||"",e.anchor?.suffix||""],func:(r,o,i)=>{const a=String(r||"").trim();if(!a)return{ok:!1,error:"quote is empty"};const s=String(o||"").trim(),u=String(i||"").trim(),f=document.body?.innerText||document.documentElement?.innerText||"";if(!f)return{ok:!1,error:"document text is empty"};let d=f.indexOf(a),m=-1;for(;d>=0;){const M=s?f.slice(Math.max(0,d-s.length),d).trim():"",W=u?f.slice(d+a.length,d+a.length+u.length).trim():"";if((!s||M===s)&&(!u||W===u)){m=d;break}d=f.indexOf(a,d+Math.max(1,Math.floor(a.length/2)))}if(m<0)return{ok:!1,error:"quote not found in page text"};const h=document.createTreeWalker(document.body||document.documentElement,NodeFilter.SHOW_TEXT);let g=0,l=null,p=null,y=0,L=0;const U=m,v=m+a.length;let D=h.nextNode();for(;D;){if(D.nodeType===Node.TEXT_NODE){const M=D,W=M.nodeValue||"",H=g+W.length;!l&&U>=g&&U<=H&&(l=M,y=Math.max(0,U-g)),!p&&v>=g&&v<=H&&(p=M,L=Math.max(0,v-g)),g=H}D=h.nextNode()}if(!l||!p)return{ok:!1,error:"failed to map quote to text nodes"};const j=document.createRange();j.setStart(l,Math.min(l.length,y)),j.setEnd(p,Math.min(p.length,L));const T=j.getBoundingClientRect(),S=document.createElement("span");return S.style.position="absolute",S.style.left=`${window.scrollX+T.left-2}px`,S.style.top=`${window.scrollY+T.top-2}px`,S.style.width=`${Math.max(8,T.width+4)}px`,S.style.height=`${Math.max(14,T.height+4)}px`,S.style.pointerEvents="none",S.style.borderRadius="6px",S.style.background="rgba(255, 240, 130, 0.42)",S.style.border="1px solid rgba(230, 190, 70, 0.72)",S.style.zIndex="2147483647",document.documentElement.appendChild(S),window.scrollTo({top:Math.max(0,window.scrollY+T.top-window.innerHeight*.35),behavior:"smooth"}),window.setTimeout(()=>S.remove(),1800),{ok:!0}}}))?.[0]?.result?.ok}catch{return!1}}async function be(t,e){w("createClipFromSelectionByScriptingFallback:start",{tabId:t});const r=(await c.scripting.executeScript({target:{tabId:t},func:()=>{const d=window.getSelection();if(!d||d.rangeCount===0)return{ok:!1,error:"empty selection"};const m=String(d.toString()||"").trim();if(!m)return{ok:!1,error:"empty selection"};const h=d.getRangeAt(0),g=h.startContainer,l=h.endContainer,p=g.nodeType===Node.TEXT_NODE?String(g.nodeValue||""):"",y=l.nodeType===Node.TEXT_NODE?String(l.nodeValue||""):"",L=p?p.slice(Math.max(0,h.startOffset-24),h.startOffset).trim():"",U=y?y.slice(h.endOffset,Math.min(y.length,h.endOffset+24)).trim():"";return{ok:!0,quote:m,quoteHtml:(()=>{try{const v=document.createElement("div");return v.appendChild(h.cloneContents()),v.innerHTML.trim()}catch{return""}})(),pageUrl:String(location.href||"").split("#")[0],pageTitle:String(document.title||""),anchor:{exact:m,prefix:L||void 0,suffix:U||void 0}}}}))?.[0]?.result;if(!r?.ok){const d=r?.error||"selection capture fallback failed";return w("createClipFromSelectionByScriptingFallback:fail",d),{ok:!1,error:d}}const o=x(String(r.pageUrl||e?.url||"")),i=String(r.pageTitle||e?.title||o).trim(),a=String(r.quote||r.anchor?.exact||"").trim(),s=r.anchor||{exact:a};if(!o||!a||!String(s?.exact||"").trim())return{ok:!1,error:"invalid clip payload from fallback"};const u={id:Tt(),tabId:t,pageUrl:o,pageTitle:i||o,quote:a,quoteHtml:String(r.quoteHtml||"").trim()||void 0,createdAt:new Date().toISOString(),color:"yellow",anchor:s},f=await bt(u);return w("createClipFromSelectionByScriptingFallback:ok",{id:f.id,pageUrl:f.pageUrl}),{ok:!0,item:f}}async function ke(t){const e=x(t),r=(await c.tabs.query({})).find(o=>x(String(o.url||""))===e);return Number.isInteger(r?.id)?r?.id:null}c.runtime.onMessage.addListener((t,e)=>{if(t?.type?.startsWith?.("clip:")&&w("runtime.onMessage",t?.type,{senderTabId:Number(e?.tab?.id),senderUrl:String(e?.tab?.url||"")}),t?.type==="capture-link-download"){const n=String(t?.url||"").trim();if(!n)return Promise.resolve({ok:!1,error:"url is empty"});const r=Number(e?.tab?.id);return C(n,String(t?.referer||"")).then(o=>(o.ok&&(vt(n),Ct(r)),o))}if(t?.type==="media:list")return St().then(n=>({ok:!0,items:n}));if(t?.type==="media:clear")return zt().then(()=>({ok:!0}));if(t?.type==="media:enqueue"){const n=String(t?.url||"").trim(),r=String(t?.kind||"").trim(),o=String(t?.suggestedOut||"").trim(),i=String(t?.referer||"").trim(),a=String(t?.cookie||"").trim(),s=String(t?.userAgent||"").trim();if(!n)return Promise.resolve({ok:!1,error:"url is empty"});const u=It(n,i,r);return C(n,i,u.extractor,u.format,o,{cookie:a,userAgent:s}).then(f=>f)}if(t?.type==="page:enqueue-ytdlp")return c.tabs.query({active:!0,currentWindow:!0}).then(async n=>{const r=n[0],o=String(r?.url||"").trim();return o?C(o,o,"yt-dlp"):{ok:!1,error:"active tab url is empty"}});if(t?.type==="page:enqueue-ytdlp-url"){const n=String(t?.url||"").trim(),r=String(t?.referer||n).trim();return n?C(n,r||n,"yt-dlp"):Promise.resolve({ok:!1,error:"url is empty"})}if(t?.type==="file:download-text"){const n=String(t?.filename||"").trim(),r=String(t?.mime||"text/plain;charset=utf-8").trim(),o=String(t?.content||"");return nt(n,r,o)}if(t?.type==="clip:export-current-page-md")return gt(String(t?.pageUrl||""),String(t?.pageTitle||""),"md");if(t?.type==="clip:export-current-page-json")return gt(String(t?.pageUrl||""),String(t?.pageTitle||""),"json");if(t?.type==="clip:send-obsidian-current-page")return Se(String(t?.pageUrl||""),String(t?.pageTitle||""));if(t?.type==="clip:create")return k().then(async n=>{if(!n.extensionStatus)return{ok:!1,error:"extension disabled"};const r=x(String(t?.pageUrl||e?.tab?.url||"")),o=String(t?.pageTitle||e?.tab?.title||"").trim(),i=String(t?.quote||t?.anchor?.exact||"").trim(),a=String(t?.quoteHtml||"").trim(),s=t?.anchor;if(!r)return{ok:!1,error:"pageUrl is empty"};if(!s||!String(s.exact||"").trim())return{ok:!1,error:"anchor is empty"};const u={id:Tt(),tabId:Number.isInteger(e?.tab?.id)?Number(e.tab.id):void 0,pageUrl:r,pageTitle:o||r,quote:i||String(s.exact||"").trim(),quoteHtml:a||void 0,createdAt:new Date().toISOString(),color:"yellow",anchor:s};return{ok:!0,item:await bt(u)}});if(t?.type==="clip:list"){const n=String(t?.pageUrl||"").trim();return n?ot(n).then(r=>({ok:!0,items:r})):b().then(r=>({ok:!0,items:r}))}if(t?.type==="clip:export")return b().then(n=>({ok:!0,items:n}));if(t?.type==="clip:import"){const n=Array.isArray(t?.items)?t.items:[];return Xt(n).then(r=>({ok:!0,...r}))}if(t?.type==="clip:delete"){const n=String(t?.id||"").trim();return n?Gt(n).then(r=>({ok:r})):Promise.resolve({ok:!1,error:"id is empty"})}if(t?.type==="clip:create-active-tab")return Ut();if(t?.type==="clip:resolve-status"){const n=String(t?.id||"").trim(),r=String(t?.status||"").trim();return n?r!=="ok"&&r!=="broken"?Promise.resolve({ok:!1,error:"invalid status"}):B(n,r).then(o=>({ok:!!o,item:o})):Promise.resolve({ok:!1,error:"id is empty"})}if(t?.type==="clip:reveal"){const n=String(t?.id||"").trim();return n?Wt(n).then(async r=>{if(!r)return{ok:!1,error:"clip not found"};const o=Number.isInteger(r.tabId)&&(r.tabId||0)>=0?r.tabId:await ke(r.pageUrl);if(!Number.isInteger(o)||o<0){const a=await c.tabs.create({url:r.pageUrl,active:!0}).catch(()=>null);return Number.isInteger(a?.id)?{ok:!0,opened:!0}:{ok:!1,error:"failed to open clip page"}}return await c.tabs.update(o,{active:!0}).catch(()=>null),(await c.tabs.sendMessage(o,{type:"clip:reveal",id:r.id}).catch(()=>null))?.ok?(await B(r.id,"ok"),{ok:!0}):await xe(o,r)?(await B(r.id,"ok"),{ok:!0,fallback:"scripting"}):(await B(r.id,"broken"),{ok:!1,error:"clip anchor not found in current dom"})}):Promise.resolve({ok:!1,error:"id is empty"})}});c.commands.onCommand.addListener(t=>{w("commands.onCommand",t),t==="create_clip_from_selection"&&(async()=>{const e=await c.tabs.query({active:!0,currentWindow:!0}),n=Number(e[0]?.id);if(Number.isInteger(n)&&n>=0&&(await c.tabs.sendMessage(n,{type:"clip:show-action-bar"}).then(a=>!!a?.ok).catch(()=>!1)||await ge(n)))return;const r=await Ut();r.ok||(w("commands.onCommand:fail",r),await _(`클립 생성 실패: ${r.error||"unknown error"}`))})()});c.runtime.onInstalled.addListener(()=>{console.log("[gomdown-helper] onInstalled"),at(),it(),st(),R(),E()});c.runtime.onStartup.addListener(()=>{console.log("[gomdown-helper] onStartup"),at(),it(),st(),R(),E()});c.storage.onChanged.addListener((t,e)=>{e==="sync"&&((t.hideChromeBar||t.useNativeHost||t.extensionStatus)&&(E(),R()),t.showContextOption&&R())});at();it();st();R();E();console.log("[gomdown-helper] service worker initialized"); diff --git a/packages/edge/assets/index.ts-DMIsnBNX.js b/packages/edge/assets/index.ts-DMIsnBNX.js new file mode 100644 index 0000000..134f019 --- /dev/null +++ b/packages/edge/assets/index.ts-DMIsnBNX.js @@ -0,0 +1 @@ +import{b as d,g as se}from"./settings-mco8QK8Y.js";import{i as N,n as ae}from"./downloadIntent-Dv31jC2S.js";import{n as M}from"./clipTypes-C_ha5Ash.js";function _(){const e=document.body||document.documentElement;if(!e)return[];const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),t=[];let r=0,o=n.nextNode();for(;o;){const l=o,s=(l.nodeValue||"").length;s>0&&(t.push({node:l,start:r,end:r+s}),r+=s),o=n.nextNode()}return t}function G(e){return e.map(n=>n.node.nodeValue||"").join("")}function X(e){const n=document.body||document.documentElement;if(!n)return"";if(e===n)return"/body";const t=[];let r=e.nodeType===Node.TEXT_NODE?e.parentNode:e;for(;r&&r!==n&&r.nodeType===Node.ELEMENT_NODE;){const o=r,l=o.tagName.toLowerCase();let i=1,s=o.previousElementSibling;for(;s;)s.tagName.toLowerCase()===l&&(i+=1),s=s.previousElementSibling;t.unshift(`${l}[${i}]`),r=o.parentElement}return`/body/${t.join("/")}`}function Y(e){if(!e)return null;try{return document.evaluate(e,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}catch{return null}}function ce(e){const n=e.commonAncestorContainer,t=n.nodeType===Node.ELEMENT_NODE?n:n.parentElement;return!(!t||t.closest("input, textarea, select, button, script, style")||t.closest('[contenteditable="true"]'))}function ue(e,n,t){const r=e.slice(Math.max(0,n-40),n).trim(),o=e.slice(t,Math.min(e.length,t+40)).trim();return{prefix:r,suffix:o}}function de(e,n){const t=e.startContainer,r=e.endContainer;if(t.nodeType!==Node.TEXT_NODE||r.nodeType!==Node.TEXT_NODE)return null;const o=n.find(i=>i.node===t),l=n.find(i=>i.node===r);return!o||!l?null:{start:o.start+e.startOffset,end:l.start+e.endOffset}}function Q(e,n){if(!Number.isFinite(e)||!Number.isFinite(n)||e>=n)return null;const t=_(),r=t.find(i=>e>=i.start&&en>i.start&&n<=i.end);if(!r||!o)return null;const l=document.createRange();return l.setStart(r.node,Math.max(0,Math.min(r.node.length,e-r.start))),l.setEnd(o.node,Math.max(0,Math.min(o.node.length,n-o.start))),l}function fe(e){if(!e.xpathStart||!e.xpathEnd)return null;const n=Y(e.xpathStart),t=Y(e.xpathEnd);if(!n||!t||n.nodeType!==Node.ELEMENT_NODE||t.nodeType!==Node.ELEMENT_NODE)return null;const r=s=>{const a=document.createTreeWalker(s,NodeFilter.SHOW_TEXT).nextNode();return a&&a.nodeType===Node.TEXT_NODE?a:null},o=r(n),l=r(t);if(!o||!l||o.nodeType!==Node.TEXT_NODE||l.nodeType!==Node.TEXT_NODE||!Number.isInteger(e.startOffset)||!Number.isInteger(e.endOffset))return null;const i=document.createRange();return i.setStart(o,Math.min((o.nodeValue||"").length,Math.max(0,e.startOffset||0))),i.setEnd(l,Math.min((l.nodeValue||"").length,Math.max(0,e.endOffset||0))),i}function pe(e){const n=String(e.exact||"");if(!n)return null;const t=_(),r=G(t);let o=r.indexOf(n);if(o<0)return null;const l=String(e.prefix||""),i=String(e.suffix||"");if(!l&&!i)return{start:o,end:o+n.length};for(;o>=0;){const s=r.slice(Math.max(0,o-l.length),o).trim(),p=r.slice(o+n.length,o+n.length+i.length).trim();if((!l||s===l)&&(!i||p===i))return{start:o,end:o+n.length};o=r.indexOf(n,o+n.length)}return null}function ye(e){if(!e.rangeCount)return null;const n=e.getRangeAt(0);if(n.collapsed||!ce(n))return null;const t=e.toString();if(!t.trim())return null;const r=_(),o=de(n,r),l={exact:t};if(n.startContainer.nodeType===Node.TEXT_NODE&&n.endContainer.nodeType===Node.TEXT_NODE){const i=n.startContainer,s=n.endContainer;l.xpathStart=X(i),l.xpathEnd=X(s),l.startOffset=n.startOffset,l.endOffset=n.endOffset}if(o){l.startTextOffset=o.start,l.endTextOffset=o.end;const i=G(r),s=ue(i,o.start,o.end);s.prefix&&(l.prefix=s.prefix),s.suffix&&(l.suffix=s.suffix)}return{anchor:l,quote:t}}function me(e){if(Number.isInteger(e.startTextOffset)&&Number.isInteger(e.endTextOffset)){const r=Q(e.startTextOffset||0,e.endTextOffset||0);if(r&&!r.collapsed)return r}const n=pe(e);if(n){const r=Q(n.start,n.end);if(r&&!r.collapsed)return r}const t=fe(e);return t&&!t.collapsed?t:null}const he=8e3,k=new Map;let c=!1,V=null,I=M(window.location.href),U=0;function m(...e){console.log("[gomdown-helper][clip][content]",...e)}function ge(){const e=Date.now();for(const[n,t]of k.entries())t<=e&&k.delete(n)}async function v(e,n){if(!c)return!1;const t=ae(e,window.location.href);if(!t)return!1;if(ge(),k.has(t))return!0;k.set(t,Date.now()+he);try{if((await d.runtime.sendMessage({type:"capture-link-download",url:t,referer:n||document.referrer||window.location.href}))?.ok)return!0}catch{}return k.delete(t),!1}function q(e){return e?e instanceof HTMLAnchorElement?e:e instanceof Element?e.closest("a[href]"):null:null}function W(e){return!!(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)}function we(e){if(!e)return!1;const n=e instanceof Element?e:e instanceof Node?e.parentElement:null;return n?!!(n.closest("input, textarea, select")||n.closest('[contenteditable="true"]')):!1}function xe(e){const n=String(e.code||""),t=e.altKey&&e.shiftKey&&!e.ctrlKey&&!e.metaKey&&n==="KeyC",r=e.altKey&&!e.shiftKey&&!e.ctrlKey&&!e.metaKey&&n==="KeyC",o=e.ctrlKey&&e.shiftKey&&!e.altKey&&!e.metaKey&&n==="KeyY",l=e.metaKey&&e.shiftKey&&!e.altKey&&!e.ctrlKey&&n==="KeyY";return t||r||o||l}function be(e){try{if(!e.rangeCount)return"";const t=e.getRangeAt(0).cloneContents(),r=document.createElement("div");return r.appendChild(t),r.innerHTML.trim()}catch{return""}}async function Z(e){if(!c||e.defaultPrevented||W(e))return;const n=q(e.target);if(!n)return;const t=n.href||"";!t||!N(t,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),await v(t,document.referrer||window.location.href))}function ee(e){if(!c)return;const n=q(e.target);if(!n)return;const t=n.href||"";!t||!N(t,window.location.href)||W(e)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),v(t,document.referrer||window.location.href))}document.addEventListener("pointerdown",e=>{e.button===0&&ee(e)},!0);document.addEventListener("mousedown",e=>{e.button===0&&ee(e)},!0);document.addEventListener("click",e=>{e.button===0&&Z(e)},!0);document.addEventListener("keydown",e=>{if(!c||e.key!=="Enter"||e.defaultPrevented||W(e))return;const n=q(e.target);if(!n)return;const t=n.href||"";!t||!N(t,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),v(t,document.referrer||window.location.href))},!0);document.addEventListener("keydown",e=>{if(xe(e)&&(m("hotkey detected",{code:e.code,key:e.key,alt:e.altKey,shift:e.shiftKey,ctrl:e.ctrlKey,meta:e.metaKey,defaultPrevented:e.defaultPrevented,href:window.location.href}),!we(e.target))){if(!c){T("확장이 OFF 상태입니다.","error"),m("hotkey blocked: extension disabled");return}e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),D()}},!0);document.addEventListener("auxclick",e=>{e.button===1&&Z(e)},!0);function ke(){try{const e=window.open.bind(window);window.open=function(t,r,o){const l=String(t||"").trim();return c&&l&&N(l,window.location.href)?(v(l,window.location.href),null):e(t,r,o)}}catch{}try{const e=HTMLAnchorElement.prototype.click;HTMLAnchorElement.prototype.click=function(){const t=this.href||this.getAttribute("href")||"";if(c&&t&&N(t,window.location.href)){v(t,document.referrer||window.location.href);return}e.call(this)}}catch{}}ke();let E=null,h=null,H=!1,j=null,P=window.location.href,C=null,g=null,S=null,w=null;function Ee(e){try{const n=new URL(e);return n.hostname!=="www.youtube.com"&&n.hostname!=="youtube.com"?!1:n.pathname==="/watch"&&n.searchParams.has("v")}catch{return!1}}function K(e,n="idle"){h&&(h.textContent=e,n==="ok"?h.style.color="#8ff0a4":n==="error"?h.style.color="#ff9b9b":h.style.color="#aeb7d8")}async function Ce(){if(!H){H=!0,K("gdown으로 전송 중...");try{const e=await d.runtime.sendMessage({type:"page:enqueue-ytdlp-url",url:window.location.href,referer:window.location.href});e?.ok?K("다운로드 모달로 전송됨","ok"):K(`전송 실패: ${e?.error||"unknown error"}`,"error")}catch(e){K(`전송 실패: ${String(e)}`,"error")}finally{H=!1}}}function F(){E&&(E.remove(),E=null,h=null)}function x(){if(!c){F();return}if(window.top!==window.self)return;if(!Ee(window.location.href)){F();return}if(E)return;const e=document.createElement("div");e.id="gomdown-youtube-overlay",e.style.position="fixed",e.style.right="20px",e.style.bottom="24px",e.style.zIndex="2147483647",e.style.background="rgba(17, 21, 32, 0.94)",e.style.border="1px solid rgba(133, 148, 195, 0.35)",e.style.borderRadius="12px",e.style.padding="10px",e.style.boxShadow="0 8px 24px rgba(0, 0, 0, 0.28)",e.style.backdropFilter="blur(6px)",e.style.width="220px",e.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.style.color="#e8edff";const n=document.createElement("div");n.textContent="Gdown Helper",n.style.fontSize="12px",n.style.fontWeight="700",n.style.marginBottom="8px";const t=document.createElement("button");t.type="button",t.textContent="이 영상 다운로드",t.style.width="100%",t.style.height="34px",t.style.border="1px solid #5a69f0",t.style.borderRadius="8px",t.style.background="#5a69f0",t.style.color="#ffffff",t.style.fontSize="12px",t.style.fontWeight="700",t.style.cursor="pointer",t.addEventListener("click",()=>{Ce()});const r=document.createElement("div");r.textContent="클릭 시 gdown 다운로드 모달로 연결",r.style.fontSize="11px",r.style.marginTop="8px",r.style.lineHeight="1.35",r.style.color="#aeb7d8",e.appendChild(n),e.appendChild(t),e.appendChild(r),document.documentElement.appendChild(e),E=e,h=r}function Se(){j===null&&(j=window.setInterval(()=>{const e=window.location.href;e!==P&&(P=e,x())},800),window.addEventListener("popstate",()=>{P=window.location.href,x()}),document.addEventListener("yt-navigate-finish",()=>{P=window.location.href,x()}))}x();Se();function Te(){const e=window.getSelection(),t=(e&&e.rangeCount>0?e.getRangeAt(0):null)?.commonAncestorContainer||document.activeElement||null,r=t instanceof Element?t:t?.parentElement||null;if(!r)return"";const o=r.closest("a[href]");return String(o?.href||"").trim()}function u(e,n="idle"){g&&(g.textContent=e,n==="ok"?g.style.color="#92f0ad":n==="error"?g.style.color="#ffaaaa":g.style.color="#aeb7d8")}async function te(){u("현재 페이지 전송 중...");try{const e=await d.runtime.sendMessage({type:"page:enqueue-ytdlp-url",url:window.location.href,referer:window.location.href});if(!e?.ok){u(`실패: ${e?.error||"unknown error"}`,"error");return}u("현재 페이지 전송 완료","ok")}catch(e){u(`실패: ${String(e)}`,"error")}}async function ne(){const e=Te();if(e){u("선택 링크 전송 중...");try{const t=await d.runtime.sendMessage({type:"page:enqueue-ytdlp-url",url:e,referer:window.location.href});if(t?.ok){u("선택 링크 전송 완료","ok");return}u(`실패: ${t?.error||"unknown error"}`,"error");return}catch(t){u(`실패: ${String(t)}`,"error")}}if((await D()).ok){u("선택 텍스트 클립 저장","ok");return}u("선택 링크/텍스트가 없습니다.","error")}function z(){C&&(C.remove(),C=null,g=null)}function R(){S&&(S.style.display="none",w!==null&&(window.clearTimeout(w),w=null))}function Oe(){if(c){if(!S){const e=document.createElement("div");e.id="gomdown-quick-action-bar",e.style.position="fixed",e.style.left="50%",e.style.bottom="16px",e.style.transform="translateX(-50%)",e.style.zIndex="2147483647",e.style.display="flex",e.style.gap="8px",e.style.padding="10px",e.style.background="rgba(15, 19, 29, 0.94)",e.style.border="1px solid rgba(101, 116, 158, 0.48)",e.style.borderRadius="12px",e.style.boxShadow="0 12px 24px rgba(0, 0, 0, 0.28)",e.style.backdropFilter="blur(6px)";const n=(i,s,p=!1)=>{const a=document.createElement("button");return a.type="button",a.textContent=i,a.style.height="32px",a.style.padding="0 12px",a.style.borderRadius="8px",a.style.border=p?"1px solid #5968f2":"1px solid #4a556f",a.style.background=p?"#5968f2":"#273041",a.style.color="#e8edff",a.style.fontSize="12px",a.style.fontWeight="700",a.style.cursor="pointer",a.addEventListener("click",s),a},t=document.createElement("div");t.style.display="none",t.style.gap="6px",t.style.alignItems="center",t.style.flexWrap="wrap";const r=n("MD",()=>{d.runtime.sendMessage({type:"clip:export-current-page-md",pageUrl:window.location.href,pageTitle:document.title||window.location.href}).then(i=>{u(i?.ok?"MD 내보내기 완료":`실패: ${i?.error||"unknown error"}`,i?.ok?"ok":"error")}).catch(i=>{u(`실패: ${String(i)}`,"error")})}),o=n("JSON",()=>{d.runtime.sendMessage({type:"clip:export-current-page-json",pageUrl:window.location.href,pageTitle:document.title||window.location.href}).then(i=>{u(i?.ok?"JSON 내보내기 완료":`실패: ${i?.error||"unknown error"}`,i?.ok?"ok":"error")}).catch(i=>{u(`실패: ${String(i)}`,"error")})}),l=n("Obsidian",()=>{d.runtime.sendMessage({type:"clip:send-obsidian-current-page",pageUrl:window.location.href,pageTitle:document.title||window.location.href}).then(i=>{if(!i?.ok||!i?.uri){u(`실패: ${i?.error||"unknown error"}`,"error");return}try{window.open(String(i.uri),"_blank")}catch{window.location.href=String(i.uri)}u("Obsidian 전송 시도 완료","ok")}).catch(i=>{u(`실패: ${String(i)}`,"error")})});t.appendChild(r),t.appendChild(o),t.appendChild(l),e.appendChild(n("현재 페이지",()=>{te()})),e.appendChild(n("선택 항목",()=>{ne()},!0)),e.appendChild(n("클립 저장",()=>{D().then(i=>{i.ok&&(t.style.display="flex")})})),e.appendChild(n("닫기",()=>{R()})),e.appendChild(t),document.documentElement.appendChild(e),S=e}S.style.display="flex",w!==null&&window.clearTimeout(w),w=window.setTimeout(()=>{R()},8e3)}}function re(){if(!c){z(),R();return}if(window.top!==window.self||C)return;const e=document.createElement("div");e.id="gomdown-quick-panel",e.style.position="fixed",e.style.right="14px",e.style.top="42%",e.style.transform="translateY(-42%)",e.style.width="188px",e.style.zIndex="2147483647",e.style.padding="10px",e.style.borderRadius="12px",e.style.background="rgba(16, 20, 30, 0.94)",e.style.border="1px solid rgba(110, 125, 168, 0.42)",e.style.boxShadow="0 12px 24px rgba(0, 0, 0, 0.28)",e.style.backdropFilter="blur(6px)",e.style.display="grid",e.style.gap="7px",e.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif";const n=document.createElement("div");n.textContent="Gdown Quick",n.style.fontSize="12px",n.style.fontWeight="700",n.style.color="#e8edff";const t=document.createElement("button");t.type="button",t.textContent="현재 페이지",t.style.height="30px",t.style.border="1px solid #5766ef",t.style.borderRadius="8px",t.style.background="#5766ef",t.style.color="#ffffff",t.style.fontSize="12px",t.style.fontWeight="700",t.style.cursor="pointer",t.addEventListener("click",()=>{te()});const r=document.createElement("button");r.type="button",r.textContent="선택 항목",r.style.height="30px",r.style.border="1px solid #4d566f",r.style.borderRadius="8px",r.style.background="#2a3040",r.style.color="#dce5ff",r.style.fontSize="12px",r.style.fontWeight="700",r.style.cursor="pointer",r.addEventListener("click",()=>{ne()});const o=document.createElement("div");o.textContent="현재 페이지/선택 항목 빠른 처리",o.style.fontSize="11px",o.style.lineHeight="1.35",o.style.color="#aeb7d8",e.appendChild(n),e.appendChild(t),e.appendChild(r),e.appendChild(o),document.documentElement.appendChild(e),C=e,g=o}function Ne(e){return e.color==="yellow","rgba(255, 235, 87, 0.58)"}function A(){const e=Array.from(document.querySelectorAll("span[data-gomdown-clip]"));for(const n of e){const t=n.parentNode;if(t){for(;n.firstChild;)t.insertBefore(n.firstChild,n);t.removeChild(n)}}}function T(e,n="ok"){const t=ie();t.textContent=e,t.style.display="block",t.style.borderColor=n==="ok"?"rgba(123, 190, 124, 0.55)":"rgba(200, 113, 113, 0.55)",t.style.color=n==="ok"?"#dffbe4":"#ffe4e4",f!==null&&window.clearTimeout(f),f=window.setTimeout(()=>{t.style.display="none",f=null,t.style.borderColor="rgba(128, 140, 180, 0.42)",t.style.color="#dce4fa"},1800)}function Me(e){const n=me(e.anchor);if(!n||n.collapsed)return!1;const t=document.createElement("span");t.dataset.gomdownClip=e.id,t.style.background=Ne(e),t.style.padding="0.04em 0.03em",t.style.borderRadius="0.12em",t.style.boxDecorationBreak="clone",t.style.setProperty("-webkit-box-decoration-break","clone"),t.style.cursor="pointer",t.title=e.quote||"clip",t.addEventListener("click",r=>{(r.altKey||r.metaKey||r.ctrlKey)&&(r.stopPropagation(),r.preventDefault())});try{const r=n.extractContents();return t.appendChild(r),n.insertNode(t),!0}catch{return!1}}async function ve(e,n){await d.runtime.sendMessage({type:"clip:resolve-status",id:e,status:n}).catch(()=>null)}function J(e){const n=document.querySelector(`span[data-gomdown-clip="${CSS.escape(e)}"]`);return n?(n.scrollIntoView({behavior:"smooth",block:"center",inline:"nearest"}),n.animate([{boxShadow:"0 0 0 0 rgba(255, 250, 164, 0.2)"},{boxShadow:"0 0 0 8px rgba(255, 250, 164, 0.65)"},{boxShadow:"0 0 0 0 rgba(255, 250, 164, 0.2)"}],{duration:760,easing:"ease-out"}),!0):!1}async function Re(e){return J(e)?!0:(await b(!0),J(e))}async function b(e=!1){if(!c)return;const n=++U,t=M(window.location.href),r=[0,700,1900];let o=0,l=0;for(let i=0;i0&&(await new Promise(y=>window.setTimeout(y,s)),n!==U))return;const p=await d.runtime.sendMessage({type:"clip:list",pageUrl:t});if(!p?.ok||!Array.isArray(p.items))return;A();const a=[...p.items].sort((y,L)=>{const le=Number(y.anchor.startTextOffset||0);return Number(L.anchor.startTextOffset||0)-le});let $=0;const B=[];for(const y of a)Me(y)?$+=1:B.push(y.id);if(o=$,l=a.length,B.length===0||i===r.length-1){const y=new Set(B);await Promise.all(a.map(L=>ve(L.id,y.has(L.id)?"broken":"ok")));break}}e&&T(`클립 복원: ${o}/${l}`,o>0?"ok":"error")}async function D(){if(!c)return{ok:!1,error:"extension disabled"};const e=window.getSelection();if(m("createClipFromCurrentSelection:start",{hasSelection:!!e,selectedTextLength:Number(e?.toString()?.length||0),href:window.location.href}),!e)return{ok:!1,error:"selection unavailable"};const n=ye(e);if(!n)return T("선택된 텍스트가 없습니다.","error"),m("createClipFromCurrentSelection:fail","empty selection"),{ok:!1,error:"empty selection"};const t=await d.runtime.sendMessage({type:"clip:create",pageUrl:M(window.location.href),pageTitle:document.title||window.location.href,quote:String(n.quote||"").trim(),quoteHtml:be(e),anchor:n.anchor});return!t?.ok||!t.item?(T(`클립 저장 실패: ${t?.error||"unknown error"}`,"error"),m("createClipFromCurrentSelection:fail",t?.error||"create failed"),{ok:!1,error:t?.error||"create failed"}):(A(),await b(),T("클립 저장 완료 (Alt+Shift+C)","ok"),m("createClipFromCurrentSelection:ok",{id:t.item.id,pageUrl:t.item.pageUrl}),{ok:!0})}function Le(){V===null&&(V=window.setInterval(()=>{const e=M(window.location.href);e!==I&&(I=e,b())},900),window.addEventListener("popstate",()=>{const e=M(window.location.href);e!==I&&(I=e,b())}))}Le();let O=null,f=null;function oe(){O&&(O.style.display="none",f!==null&&(window.clearTimeout(f),f=null))}function ie(){if(O)return O;const e=document.createElement("div");return e.id="gomdown-media-toast",e.style.position="fixed",e.style.left="18px",e.style.bottom="18px",e.style.zIndex="2147483647",e.style.maxWidth="360px",e.style.padding="10px 12px",e.style.borderRadius="10px",e.style.border="1px solid rgba(128, 140, 180, 0.42)",e.style.background="rgba(18, 21, 31, 0.95)",e.style.color="#dce4fa",e.style.fontSize="12px",e.style.lineHeight="1.35",e.style.fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.style.boxShadow="0 10px 24px rgba(0, 0, 0, 0.28)",e.style.display="none",document.documentElement.appendChild(e),O=e,e}function Ie(e){if(!c)return;const n=ie(),t=String(e?.kind||"media").toUpperCase(),r=String(e?.suggestedOut||"").trim(),o=String(e?.url||"").trim().slice(0,96);n.textContent=r?`캡처됨 [${t}] ${r}`:`캡처됨 [${t}] ${o}${o.length>=96?"…":""}`,n.style.display="block",f!==null&&window.clearTimeout(f),f=window.setTimeout(()=>{n.style.display="none",f=null},2200)}d.runtime.onMessage.addListener(e=>{if(e?.type==="clip:ping")return m("runtime.onMessage clip:ping"),{ok:!0};if(e?.type==="clip:create-from-selection")return m("runtime.onMessage clip:create-from-selection"),D();if(e?.type==="clip:show-action-bar")return Oe(),{ok:!0};if(e?.type==="media:captured"){Ie({kind:e?.kind,url:e?.url,suggestedOut:e?.suggestedOut});return}if(e?.type==="clip:reveal"){const n=String(e?.id||"").trim();return n?Re(n).then(t=>({ok:t})):void 0}});async function Pe(){try{c=!!(await se()).extensionStatus}catch{c=!1}c?(x(),re(),await b()):(F(),z(),R(),oe(),A())}Pe();d.storage.onChanged.addListener((e,n)=>{if(n==="sync"&&e.extensionStatus){if(c=!!e.extensionStatus.newValue,!c){F(),z(),R(),oe(),A();return}x(),re(),b()}}); diff --git a/packages/chrome/assets/index.ts-loader-D_eQmgUa.js b/packages/edge/assets/index.ts-loader-DWDY2bjZ.js similarity index 82% rename from packages/chrome/assets/index.ts-loader-D_eQmgUa.js rename to packages/edge/assets/index.ts-loader-DWDY2bjZ.js index 8486299..5b2b27d 100644 --- a/packages/chrome/assets/index.ts-loader-D_eQmgUa.js +++ b/packages/edge/assets/index.ts-loader-DWDY2bjZ.js @@ -5,7 +5,7 @@ (async () => { const { onExecute } = await import( /* @vite-ignore */ - chrome.runtime.getURL("assets/index.ts-w1ilzv93.js") + chrome.runtime.getURL("assets/index.ts-DMIsnBNX.js") ); onExecute?.({ perf: { injectTime, loadTime: performance.now() - injectTime } }); })().catch(console.error); diff --git a/packages/edge/assets/settings-Bo6W9Drl.js b/packages/edge/assets/settings-Bo6W9Drl.js deleted file mode 100644 index cbfb728..0000000 --- a/packages/edge/assets/settings-Bo6W9Drl.js +++ /dev/null @@ -1 +0,0 @@ -import{b as e}from"./browser-polyfill-CZ_dLIqp.js";const t={extensionStatus:!0,useNativeHost:!0,activateAppOnDownload:!0,enableNotifications:!0,hideChromeBar:!0,showContextOption:!0,downloadFallback:!1,darkMode:!1,showOnlyAria:!1,minFileSize:0,blacklist:[],motrixPort:16800,motrixAPIkey:""};async function n(){const o=await e.storage.sync.get(Object.keys(t));return{extensionStatus:!!(o.extensionStatus??t.extensionStatus),useNativeHost:!!(o.useNativeHost??t.useNativeHost),activateAppOnDownload:!!(o.activateAppOnDownload??t.activateAppOnDownload),enableNotifications:!!(o.enableNotifications??t.enableNotifications),hideChromeBar:!!(o.hideChromeBar??t.hideChromeBar),showContextOption:!!(o.showContextOption??t.showContextOption),downloadFallback:!!(o.downloadFallback??t.downloadFallback),darkMode:!!(o.darkMode??t.darkMode),showOnlyAria:!!(o.showOnlyAria??t.showOnlyAria),minFileSize:Number(o.minFileSize??t.minFileSize),blacklist:Array.isArray(o.blacklist)?o.blacklist.map(a=>String(a)):t.blacklist,motrixPort:Number(o.motrixPort??t.motrixPort),motrixAPIkey:String(o.motrixAPIkey??t.motrixAPIkey)}}async function s(o){await e.storage.sync.set(o)}export{n as g,s}; diff --git a/packages/edge/assets/browser-polyfill-CZ_dLIqp.js b/packages/edge/assets/settings-mco8QK8Y.js similarity index 51% rename from packages/edge/assets/browser-polyfill-CZ_dLIqp.js rename to packages/edge/assets/settings-mco8QK8Y.js index 377b743..bb0f1ad 100644 --- a/packages/edge/assets/browser-polyfill-CZ_dLIqp.js +++ b/packages/edge/assets/settings-mco8QK8Y.js @@ -1 +1 @@ -function j(l){return l&&l.__esModule&&Object.prototype.hasOwnProperty.call(l,"default")?l.default:l}var h={exports:{}},O=h.exports,R;function q(){return R||(R=1,(function(l,D){(function(w,p){p(l)})(typeof globalThis<"u"?globalThis:typeof self<"u"?self:O,function(w){if(!(globalThis.chrome&&globalThis.chrome.runtime&&globalThis.chrome.runtime.id))throw new Error("This script should only be loaded in a browser extension.");if(globalThis.browser&&globalThis.browser.runtime&&globalThis.browser.runtime.id)w.exports=globalThis.browser;else{const p="The message port closed before a response was received.",N=c=>{const k={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2,singleCallbackArg:!1}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0},elements:{createSidebarPane:{minArgs:1,maxArgs:1}}}},downloads:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},setEnabled:{minArgs:2,maxArgs:2},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},goBack:{minArgs:0,maxArgs:1},goForward:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},topSites:{get:{minArgs:0,maxArgs:0}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(Object.keys(k).length===0)throw new Error("api-metadata.json has not been included in browser-polyfill");class v extends WeakMap{constructor(r,g=void 0){super(g),this.createItem=r}get(r){return this.has(r)||this.set(r,this.createItem(r)),super.get(r)}}const $=e=>e&&typeof e=="object"&&typeof e.then=="function",E=(e,r)=>(...g)=>{c.runtime.lastError?e.reject(new Error(c.runtime.lastError.message)):r.singleCallbackArg||g.length<=1&&r.singleCallbackArg!==!1?e.resolve(g[0]):e.resolve(g)},f=e=>e==1?"argument":"arguments",F=(e,r)=>function(n,...a){if(a.lengthr.maxArgs)throw new Error(`Expected at most ${r.maxArgs} ${f(r.maxArgs)} for ${e}(), got ${a.length}`);return new Promise((t,i)=>{if(r.fallbackToNoCallback)try{n[e](...a,E({resolve:t,reject:i},r))}catch(s){console.warn(`${e} API method doesn't seem to support the callback parameter, falling back to call it without a callback: `,s),n[e](...a),r.fallbackToNoCallback=!1,r.noCallback=!0,t()}else r.noCallback?(n[e](...a),t()):n[e](...a,E({resolve:t,reject:i},r))})},P=(e,r,g)=>new Proxy(r,{apply(n,a,t){return g.call(a,e,...t)}});let d=Function.call.bind(Object.prototype.hasOwnProperty);const b=(e,r={},g={})=>{let n=Object.create(null),a={has(i,s){return s in e||s in n},get(i,s,A){if(s in n)return n[s];if(!(s in e))return;let m=e[s];if(typeof m=="function")if(typeof r[s]=="function")m=P(e,e[s],r[s]);else if(d(g,s)){let x=F(s,g[s]);m=P(e,e[s],x)}else m=m.bind(e);else if(typeof m=="object"&&m!==null&&(d(r,s)||d(g,s)))m=b(m,r[s],g[s]);else if(d(g,"*"))m=b(m,r[s],g["*"]);else return Object.defineProperty(n,s,{configurable:!0,enumerable:!0,get(){return e[s]},set(x){e[s]=x}}),m;return n[s]=m,m},set(i,s,A,m){return s in n?n[s]=A:e[s]=A,!0},defineProperty(i,s,A){return Reflect.defineProperty(n,s,A)},deleteProperty(i,s){return Reflect.deleteProperty(n,s)}},t=Object.create(e);return new Proxy(t,a)},y=e=>({addListener(r,g,...n){r.addListener(e.get(g),...n)},hasListener(r,g){return r.hasListener(e.get(g))},removeListener(r,g){r.removeListener(e.get(g))}}),_=new v(e=>typeof e!="function"?e:function(g){const n=b(g,{},{getContent:{minArgs:0,maxArgs:0}});e(n)}),S=new v(e=>typeof e!="function"?e:function(g,n,a){let t=!1,i,s=new Promise(u=>{i=function(o){t=!0,u(o)}}),A;try{A=e(g,n,i)}catch(u){A=Promise.reject(u)}const m=A!==!0&&$(A);if(A!==!0&&!m&&!t)return!1;const x=u=>{u.then(o=>{a(o)},o=>{let C;o&&(o instanceof Error||typeof o.message=="string")?C=o.message:C="An unexpected error occurred",a({__mozWebExtensionPolyfillReject__:!0,message:C})}).catch(o=>{console.error("Failed to send onMessage rejected reply",o)})};return x(m?A:s),!0}),B=({reject:e,resolve:r},g)=>{c.runtime.lastError?c.runtime.lastError.message===p?r():e(new Error(c.runtime.lastError.message)):g&&g.__mozWebExtensionPolyfillReject__?e(new Error(g.message)):r(g)},M=(e,r,g,...n)=>{if(n.lengthr.maxArgs)throw new Error(`Expected at most ${r.maxArgs} ${f(r.maxArgs)} for ${e}(), got ${n.length}`);return new Promise((a,t)=>{const i=B.bind(null,{resolve:a,reject:t});n.push(i),g.sendMessage(...n)})},L={devtools:{network:{onRequestFinished:y(_)}},runtime:{onMessage:y(S),onMessageExternal:y(S),sendMessage:M.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:M.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}},T={clear:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}};return k.privacy={network:{"*":T},services:{"*":T},websites:{"*":T}},b(c,L,k)};w.exports=N(chrome)}})})(h)),h.exports}var W=q();const U=j(W);export{U as b,j as g}; +function q(g){return g&&g.__esModule&&Object.prototype.hasOwnProperty.call(g,"default")?g.default:g}var w={exports:{}},I=w.exports,M;function W(){return M||(M=1,(function(g,S){(function(p,k){k(g)})(typeof globalThis<"u"?globalThis:typeof self<"u"?self:I,function(p){if(!(globalThis.chrome&&globalThis.chrome.runtime&&globalThis.chrome.runtime.id))throw new Error("This script should only be loaded in a browser extension.");if(globalThis.browser&&globalThis.browser.runtime&&globalThis.browser.runtime.id)p.exports=globalThis.browser;else{const k="The message port closed before a response was received.",R=x=>{const y={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2,singleCallbackArg:!1}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0},elements:{createSidebarPane:{minArgs:1,maxArgs:1}}}},downloads:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},setEnabled:{minArgs:2,maxArgs:2},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},goBack:{minArgs:0,maxArgs:1},goForward:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},topSites:{get:{minArgs:0,maxArgs:0}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(Object.keys(y).length===0)throw new Error("api-metadata.json has not been included in browser-polyfill");class P extends WeakMap{constructor(r,n=void 0){super(n),this.createItem=r}get(r){return this.has(r)||this.set(r,this.createItem(r)),super.get(r)}}const $=e=>e&&typeof e=="object"&&typeof e.then=="function",E=(e,r)=>(...n)=>{x.runtime.lastError?e.reject(new Error(x.runtime.lastError.message)):r.singleCallbackArg||n.length<=1&&r.singleCallbackArg!==!1?e.resolve(n[0]):e.resolve(n)},b=e=>e==1?"argument":"arguments",L=(e,r)=>function(a,...i){if(i.lengthr.maxArgs)throw new Error(`Expected at most ${r.maxArgs} ${b(r.maxArgs)} for ${e}(), got ${i.length}`);return new Promise((m,A)=>{if(r.fallbackToNoCallback)try{a[e](...i,E({resolve:m,reject:A},r))}catch(s){console.warn(`${e} API method doesn't seem to support the callback parameter, falling back to call it without a callback: `,s),a[e](...i),r.fallbackToNoCallback=!1,r.noCallback=!0,m()}else r.noCallback?(a[e](...i),m()):a[e](...i,E({resolve:m,reject:A},r))})},F=(e,r,n)=>new Proxy(r,{apply(a,i,m){return n.call(i,e,...m)}});let f=Function.call.bind(Object.prototype.hasOwnProperty);const h=(e,r={},n={})=>{let a=Object.create(null),i={has(A,s){return s in e||s in a},get(A,s,l){if(s in a)return a[s];if(!(s in e))return;let t=e[s];if(typeof t=="function")if(typeof r[s]=="function")t=F(e,e[s],r[s]);else if(f(n,s)){let u=L(s,n[s]);t=F(e,e[s],u)}else t=t.bind(e);else if(typeof t=="object"&&t!==null&&(f(r,s)||f(n,s)))t=h(t,r[s],n[s]);else if(f(n,"*"))t=h(t,r[s],n["*"]);else return Object.defineProperty(a,s,{configurable:!0,enumerable:!0,get(){return e[s]},set(u){e[s]=u}}),t;return a[s]=t,t},set(A,s,l,t){return s in a?a[s]=l:e[s]=l,!0},defineProperty(A,s,l){return Reflect.defineProperty(a,s,l)},deleteProperty(A,s){return Reflect.deleteProperty(a,s)}},m=Object.create(e);return new Proxy(m,i)},C=e=>({addListener(r,n,...a){r.addListener(e.get(n),...a)},hasListener(r,n){return r.hasListener(e.get(n))},removeListener(r,n){r.removeListener(e.get(n))}}),_=new P(e=>typeof e!="function"?e:function(n){const a=h(n,{},{getContent:{minArgs:0,maxArgs:0}});e(a)}),N=new P(e=>typeof e!="function"?e:function(n,a,i){let m=!1,A,s=new Promise(d=>{A=function(c){m=!0,d(c)}}),l;try{l=e(n,a,A)}catch(d){l=Promise.reject(d)}const t=l!==!0&&$(l);if(l!==!0&&!t&&!m)return!1;const u=d=>{d.then(c=>{i(c)},c=>{let T;c&&(c instanceof Error||typeof c.message=="string")?T=c.message:T="An unexpected error occurred",i({__mozWebExtensionPolyfillReject__:!0,message:T})}).catch(c=>{console.error("Failed to send onMessage rejected reply",c)})};return u(t?l:s),!0}),j=({reject:e,resolve:r},n)=>{x.runtime.lastError?x.runtime.lastError.message===k?r():e(new Error(x.runtime.lastError.message)):n&&n.__mozWebExtensionPolyfillReject__?e(new Error(n.message)):r(n)},B=(e,r,n,...a)=>{if(a.lengthr.maxArgs)throw new Error(`Expected at most ${r.maxArgs} ${b(r.maxArgs)} for ${e}(), got ${a.length}`);return new Promise((i,m)=>{const A=j.bind(null,{resolve:i,reject:m});a.push(A),n.sendMessage(...a)})},D={devtools:{network:{onRequestFinished:C(_)}},runtime:{onMessage:C(N),onMessageExternal:C(N),sendMessage:B.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:B.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}},v={clear:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}};return y.privacy={network:{"*":v},services:{"*":v},websites:{"*":v}},h(x,D,y)};p.exports=R(chrome)}})})(w)),w.exports}var U=W();const O=q(U),o={extensionStatus:!0,useNativeHost:!0,activateAppOnDownload:!0,enableNotifications:!0,hideChromeBar:!0,showContextOption:!0,downloadFallback:!1,darkMode:!1,showOnlyAria:!1,minFileSize:0,blacklist:[],motrixPort:16800,motrixAPIkey:"",obsidianVault:"",obsidianFolder:"Gomdown/Clips"};async function z(){const g=await O.storage.sync.get(Object.keys(o));return{extensionStatus:!!(g.extensionStatus??o.extensionStatus),useNativeHost:!!(g.useNativeHost??o.useNativeHost),activateAppOnDownload:!!(g.activateAppOnDownload??o.activateAppOnDownload),enableNotifications:!!(g.enableNotifications??o.enableNotifications),hideChromeBar:!!(g.hideChromeBar??o.hideChromeBar),showContextOption:!!(g.showContextOption??o.showContextOption),downloadFallback:!!(g.downloadFallback??o.downloadFallback),darkMode:!!(g.darkMode??o.darkMode),showOnlyAria:!!(g.showOnlyAria??o.showOnlyAria),minFileSize:Number(g.minFileSize??o.minFileSize),blacklist:Array.isArray(g.blacklist)?g.blacklist.map(S=>String(S)):o.blacklist,motrixPort:Number(g.motrixPort??o.motrixPort),motrixAPIkey:String(g.motrixAPIkey??o.motrixAPIkey),obsidianVault:String(g.obsidianVault??o.obsidianVault),obsidianFolder:String(g.obsidianFolder??o.obsidianFolder)}}async function H(g){await O.storage.sync.set(g)}export{q as a,O as b,z as g,H as s}; diff --git a/packages/edge/images/128.png b/packages/edge/images/128.png index eaae62a..d547e24 100644 Binary files a/packages/edge/images/128.png and b/packages/edge/images/128.png differ diff --git a/packages/edge/images/16.png b/packages/edge/images/16.png index 504fccd..34dbc5c 100644 Binary files a/packages/edge/images/16.png and b/packages/edge/images/16.png differ diff --git a/packages/edge/images/32.png b/packages/edge/images/32.png index d77f929..3214db3 100644 Binary files a/packages/edge/images/32.png and b/packages/edge/images/32.png differ diff --git a/packages/edge/images/48.png b/packages/edge/images/48.png index eb9f4b6..a72d4f5 100644 Binary files a/packages/edge/images/48.png and b/packages/edge/images/48.png differ diff --git a/packages/edge/images/dwld.png b/packages/edge/images/dwld.png index 029ced1..3214db3 100644 Binary files a/packages/edge/images/dwld.png and b/packages/edge/images/dwld.png differ diff --git a/packages/edge/images/icon-large.png b/packages/edge/images/icon-large.png index 42ee5bb..dcf91f0 100644 Binary files a/packages/edge/images/icon-large.png and b/packages/edge/images/icon-large.png differ diff --git a/packages/edge/images/pomeranian-bw.svg b/packages/edge/images/pomeranian-bw.svg new file mode 100644 index 0000000..2355b21 --- /dev/null +++ b/packages/edge/images/pomeranian-bw.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/edge/manifest.json b/packages/edge/manifest.json index 4ddb1be..d9597ab 100644 --- a/packages/edge/manifest.json +++ b/packages/edge/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "Gomdown Helper", "description": "Send browser downloads to gdown", - "version": "0.0.1", + "version": "0.0.64", "default_locale": "en", "icons": { "16": "images/16.png", @@ -25,10 +25,19 @@ } }, "options_page": "src/config/index.html", + "commands": { + "create_clip_from_selection": { + "suggested_key": { + "default": "Ctrl+Shift+Y", + "mac": "Command+Shift+Y" + }, + "description": "Create clip from current text selection" + } + }, "content_scripts": [ { "js": [ - "assets/index.ts-loader-DMyyuf2n.js" + "assets/index.ts-loader-DWDY2bjZ.js" ], "matches": [ "" @@ -45,7 +54,8 @@ "contextMenus", "cookies", "webRequest", - "nativeMessaging" + "nativeMessaging", + "scripting" ], "host_permissions": [ "" @@ -57,9 +67,10 @@ ], "resources": [ "images/*", - "assets/browser-polyfill-CZ_dLIqp.js", + "assets/settings-mco8QK8Y.js", "assets/downloadIntent-Dv31jC2S.js", - "assets/index.ts-BGLNJwsP.js" + "assets/clipTypes-C_ha5Ash.js", + "assets/index.ts-DMIsnBNX.js" ], "use_dynamic_url": false } diff --git a/packages/edge/service-worker-loader.js b/packages/edge/service-worker-loader.js index a13829b..1b18b99 100644 --- a/packages/edge/service-worker-loader.js +++ b/packages/edge/service-worker-loader.js @@ -1 +1 @@ -import './assets/index.ts-BnPsJZXz.js'; +import './assets/index.ts-D64R0PS1.js'; diff --git a/packages/edge/src/config/index.html b/packages/edge/src/config/index.html index f9377f9..51314f5 100644 --- a/packages/edge/src/config/index.html +++ b/packages/edge/src/config/index.html @@ -4,10 +4,9 @@ Gomdown Helper Settings - - - - + + + diff --git a/packages/edge/src/popup/index.html b/packages/edge/src/popup/index.html index 34e6292..3c5a99e 100644 --- a/packages/edge/src/popup/index.html +++ b/packages/edge/src/popup/index.html @@ -4,11 +4,11 @@ Gomdown Helper - - - - - + + + + +
diff --git a/src/background/index.ts b/src/background/index.ts index 8f217bb..380023a 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -5,10 +5,13 @@ import { getSettings } from '../lib/settings' import { upsertHistory } from '../lib/history' import { makeMediaCandidate, mediaFingerprint, shouldCaptureMediaResponse } from '../lib/mediaCapture' import { clearMediaCandidates, listMediaCandidates, upsertMediaCandidate } from '../lib/mediaStore' +import { deleteClip, getClipById, importClips, insertClip, listClips, listClipsByUrl, updateClipResolveStatus } from '../lib/clipStore' +import { normalizePageUrl, normalizeQuote, type ClipItem } from '../lib/clipTypes' const REQUEST_TTL_MS = 8000 const TRANSFER_DEDUPE_TTL_MS = 7000 const contextMenuId = 'gomdown-helper-download-context-menu-option' +const OBSIDIAN_LAST_VAULT_KEY = 'obsidianLastVault' const pendingRequests = new Map() const capturedUrls = new Map() @@ -35,6 +38,10 @@ const SITE_STRATEGIES: Array<{ }, ] +function clipLog(...args: unknown[]): void { + console.log('[gomdown-helper][clip][bg]', ...args) +} + function urlFingerprint(raw: string): string { try { const u = new URL(raw) @@ -493,7 +500,598 @@ function createMenuItem(): Promise { return contextMenuUpdateInFlight } +async function requestCreateClipOnActiveTab(): Promise<{ ok: boolean; error?: string }> { + clipLog('requestCreateClipOnActiveTab:start') + const tabs = await browser.tabs.query({ active: true, currentWindow: true }) + const tab = tabs[0] + const tabId = Number(tab?.id) + clipLog('active tab', { + tabId, + url: String(tab?.url || ''), + title: String(tab?.title || ''), + }) + if (!Number.isInteger(tabId) || tabId < 0) { + clipLog('requestCreateClipOnActiveTab:fail', 'active tab is unavailable') + return { ok: false, error: 'active tab is unavailable' } + } + + const sendClipCreateMessage = async (): Promise<{ ok?: boolean; error?: string } | undefined> => { + return (await browser.tabs.sendMessage(tabId, { + type: 'clip:create-from-selection', + })) as { ok?: boolean; error?: string } | undefined + } + + try { + let result: { ok?: boolean; error?: string } | undefined + try { + result = await sendClipCreateMessage() + } catch (firstError) { + clipLog('first sendMessage failed, using scripting fallback', String(firstError)) + throw firstError + } + clipLog('content response', result) + if (result?.ok) return { ok: true } + clipLog('requestCreateClipOnActiveTab:fail', result?.error || 'failed to create clip in active tab') + return { ok: false, error: result?.error || 'failed to create clip in active tab' } + } catch (error) { + clipLog('requestCreateClipOnActiveTab:exception', String(error)) + const scripted = await createClipFromSelectionByScriptingFallback(tabId, { + url: String(tab?.url || ''), + title: String(tab?.title || ''), + }).catch((fallbackError) => { + clipLog('scripting fallback exception', String(fallbackError)) + return { ok: false, error: String(fallbackError) } + }) + if (scripted.ok) return { ok: true } + return { ok: false, error: scripted.error || 'content script is not ready on active tab' } + } +} + +async function showInlineActionBarByScripting(tabId: number): Promise { + try { + const result = await browser.scripting.executeScript({ + target: { tabId }, + func: () => { + const rootId = 'gomdown-inline-actionbar-fallback' + const existing = document.getElementById(rootId) + if (existing) { + existing.style.display = 'flex' + return { ok: true } + } + + const root = document.createElement('div') + root.id = rootId + root.style.position = 'fixed' + root.style.left = '50%' + root.style.bottom = '14px' + root.style.transform = 'translateX(-50%)' + root.style.zIndex = '2147483647' + root.style.display = 'flex' + root.style.gap = '8px' + root.style.padding = '10px' + root.style.background = 'rgba(15, 20, 31, 0.94)' + root.style.border = '1px solid rgba(97, 112, 155, 0.52)' + root.style.borderRadius = '12px' + root.style.boxShadow = '0 12px 24px rgba(0, 0, 0, 0.3)' + root.style.fontFamily = 'ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif' + + const status = document.createElement('div') + status.textContent = 'Gomdown Quick Action' + status.style.fontSize = '11px' + status.style.color = '#c9d4f2' + status.style.display = 'flex' + status.style.alignItems = 'center' + status.style.padding = '0 2px' + + const mk = (label: string, primary = false): HTMLButtonElement => { + const btn = document.createElement('button') + btn.type = 'button' + btn.textContent = label + btn.style.height = '32px' + btn.style.padding = '0 12px' + btn.style.borderRadius = '8px' + btn.style.border = primary ? '1px solid #5c6cf3' : '1px solid #4b5873' + btn.style.background = primary ? '#5c6cf3' : '#2a3346' + btn.style.color = '#e8edff' + btn.style.fontSize = '12px' + btn.style.fontWeight = '700' + btn.style.cursor = 'pointer' + return btn + } + + const clipBtn = mk('클립 저장', true) + const pageBtn = mk('현재 페이지') + const mdBtn = mk('MD') + const jsonBtn = mk('JSON') + const obsidianBtn = mk('Obsidian') + const closeBtn = mk('닫기') + const extras = document.createElement('div') + extras.style.display = 'none' + extras.style.gap = '6px' + extras.style.alignItems = 'center' + extras.style.flexWrap = 'wrap' + extras.appendChild(mdBtn) + extras.appendChild(jsonBtn) + extras.appendChild(obsidianBtn) + + clipBtn.onclick = () => { + try { + chrome.runtime.sendMessage({ type: 'clip:create-active-tab' }, (response) => { + const ok = Boolean(response?.ok) + status.textContent = ok ? '클립 저장 완료' : `실패: ${String(response?.error || 'unknown error')}` + status.style.color = ok ? '#8ff0a4' : '#ffaaaa' + if (ok) extras.style.display = 'flex' + }) + } catch (error) { + status.textContent = `실패: ${String(error)}` + status.style.color = '#ffaaaa' + } + } + + pageBtn.onclick = () => { + try { + chrome.runtime.sendMessage( + { + type: 'page:enqueue-ytdlp-url', + url: window.location.href, + referer: window.location.href, + }, + (response) => { + const ok = Boolean(response?.ok) + status.textContent = ok ? '현재 페이지 전송 완료' : `실패: ${String(response?.error || 'unknown error')}` + status.style.color = ok ? '#8ff0a4' : '#ffaaaa' + } + ) + } catch (error) { + status.textContent = `실패: ${String(error)}` + status.style.color = '#ffaaaa' + } + } + + mdBtn.onclick = () => { + try { + chrome.runtime.sendMessage( + { + type: 'clip:export-current-page-md', + pageUrl: window.location.href, + pageTitle: document.title || window.location.href, + }, + (response) => { + const ok = Boolean(response?.ok) + status.textContent = ok ? 'MD 내보내기 완료' : `실패: ${String(response?.error || 'unknown error')}` + status.style.color = ok ? '#8ff0a4' : '#ffaaaa' + } + ) + } catch (error) { + status.textContent = `실패: ${String(error)}` + status.style.color = '#ffaaaa' + } + } + + jsonBtn.onclick = () => { + try { + chrome.runtime.sendMessage( + { + type: 'clip:export-current-page-json', + pageUrl: window.location.href, + pageTitle: document.title || window.location.href, + }, + (response) => { + const ok = Boolean(response?.ok) + status.textContent = ok ? 'JSON 내보내기 완료' : `실패: ${String(response?.error || 'unknown error')}` + status.style.color = ok ? '#8ff0a4' : '#ffaaaa' + } + ) + } catch (error) { + status.textContent = `실패: ${String(error)}` + status.style.color = '#ffaaaa' + } + } + + obsidianBtn.onclick = () => { + try { + chrome.runtime.sendMessage( + { + type: 'clip:send-obsidian-current-page', + pageUrl: window.location.href, + pageTitle: document.title || window.location.href, + }, + (response) => { + const ok = Boolean(response?.ok && response?.uri) + if (ok) { + try { + window.open(String(response.uri), '_blank') + } catch { + window.location.href = String(response.uri) + } + status.textContent = 'Obsidian 전송 시도 완료' + status.style.color = '#8ff0a4' + return + } + status.textContent = `실패: ${String(response?.error || 'unknown error')}` + status.style.color = '#ffaaaa' + } + ) + } catch (error) { + status.textContent = `실패: ${String(error)}` + status.style.color = '#ffaaaa' + } + } + + closeBtn.onclick = () => { + root.remove() + } + + root.appendChild(clipBtn) + root.appendChild(pageBtn) + root.appendChild(closeBtn) + root.appendChild(extras) + root.appendChild(status) + document.documentElement.appendChild(root) + window.setTimeout(() => { + root.remove() + }, 9000) + return { ok: true } + }, + }) + return Boolean((result?.[0]?.result as { ok?: boolean } | undefined)?.ok) + } catch { + return false + } +} + +function makeClipId(): string { + try { + return crypto.randomUUID() + } catch { + return `clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` + } +} + +function clipToMarkdownBlock(item: ClipItem, index: number): string { + const quoteRaw = String(item.quote || item.anchor?.exact || '').replace(/\r\n/g, '\n').trim() + const quote = quoteRaw.length > 4000 ? `${quoteRaw.slice(0, 4000)}\n...(truncated)` : quoteRaw + const lines = quote + .split('\n') + .map((line) => line.trimEnd()) + .filter((line, idx, arr) => !(line === '' && arr[idx - 1] === '')) + const block = lines.length === 0 ? '> ' : lines.map((line) => `> ${line}`).join('\n') + return [ + `### ${index + 1}. Clip`, + block, + '', + `- created: ${item.createdAt}`, + `- status: ${item.resolveStatus || 'ok'}`, + ].join('\n') +} + +function buildPageMarkdown(items: ClipItem[], pageUrl: string, pageTitle = ''): string { + const title = pageTitle || items[0]?.pageTitle || pageUrl || 'Untitled' + const lines: string[] = [ + `# ${title}`, + `- source: ${pageUrl}`, + `- exportedAt: ${new Date().toISOString()}`, + `- clips: ${items.length}`, + '', + '---', + '', + ] + for (let i = 0; i < items.length; i += 1) { + lines.push(clipToMarkdownBlock(items[i], i)) + lines.push('') + } + return lines.join('\n') +} + +function safeFileName(raw: string): string { + const title = String(raw || '') + .replace(/\s*[|\-–—]\s*(qiita|medium|youtube|x|twitter|tistory|velog|github)\s*$/i, '') + .replace(/\s*[-–—|]\s*(edge|chrome|firefox)\s*$/i, '') + .replace(/\[[^\]]{1,30}\]\s*$/g, '') + return title + .trim() + .replace(/[\\/:*?"<>|]/g, '_') + .replace(/[(){}[\]]/g, '') + .replace(/\s+/g, ' ') + .replace(/[._-]{2,}/g, '-') + .replace(/^[._\-\s]+|[._\-\s]+$/g, '') + .slice(0, 90) || 'clips' +} + +function normalizeObsidianTarget(vaultRaw: string, folderRaw: string): { vault: string; folder: string } { + let vault = String(vaultRaw || '').trim() + let folder = String(folderRaw || '').trim() + + // If user entered a filesystem path, use its basename as vault name. + if (vault.includes('/') || vault.includes('\\')) { + const parts = vault.split(/[\\/]+/).filter(Boolean) + vault = parts[parts.length - 1] || '' + } + + // Ignore common placeholder values so we can fall back to default vault. + if (/^myvault$/i.test(vault) || /^example$/i.test(vault)) { + vault = '' + } + + folder = folder.replace(/^\/+|\/+$/g, '') + return { vault, folder } +} + +async function readLastObsidianVault(): Promise { + try { + const raw = await browser.storage.local.get(OBSIDIAN_LAST_VAULT_KEY) + const value = String(raw?.[OBSIDIAN_LAST_VAULT_KEY] || '').trim() + return value + } catch { + return '' + } +} + +async function writeLastObsidianVault(vaultRaw: string): Promise { + const vault = String(vaultRaw || '').trim() + if (!vault) return + try { + await browser.storage.local.set({ + [OBSIDIAN_LAST_VAULT_KEY]: vault, + }) + } catch { + // ignored + } +} + +async function downloadTextFile(filename: string, mime: string, content: string): Promise<{ ok: boolean; error?: string; downloadId?: number }> { + if (!filename.trim()) return { ok: false, error: 'filename is empty' } + const url = `data:${mime},${encodeURIComponent(content)}` + try { + const downloadId = await browser.downloads.download({ + url, + filename: filename.trim(), + saveAs: true, + }) + return { ok: true, downloadId } + } catch (error) { + return { ok: false, error: String(error) } + } +} + +async function exportCurrentPageClipsAs( + pageUrlRaw: string, + pageTitleRaw: string, + kind: 'md' | 'json' +): Promise<{ ok: boolean; error?: string; count?: number; downloadId?: number }> { + const pageUrl = normalizePageUrl(String(pageUrlRaw || '').trim()) + if (!pageUrl) return { ok: false, error: 'pageUrl is empty' } + const items = await listClipsByUrl(pageUrl) + if (items.length === 0) return { ok: false, error: 'no clips for current page' } + + const pageTitle = String(pageTitleRaw || items[0]?.pageTitle || pageUrl).trim() + if (kind === 'md') { + const markdown = buildPageMarkdown(items, pageUrl, pageTitle) + const filename = `${safeFileName(pageTitle)}-clips.md` + const saved = await downloadTextFile(filename, 'text/markdown;charset=utf-8', markdown) + return { ok: saved.ok, error: saved.error, count: items.length, downloadId: saved.downloadId } + } + + const payload = { + exportedAt: new Date().toISOString(), + version: 1, + count: items.length, + clips: items, + } + const filename = `${safeFileName(pageTitle)}-clips.json` + const saved = await downloadTextFile(filename, 'application/json;charset=utf-8', JSON.stringify(payload, null, 2)) + return { ok: saved.ok, error: saved.error, count: items.length, downloadId: saved.downloadId } +} + +async function buildObsidianUriForCurrentPage(pageUrlRaw: string, pageTitleRaw: string): Promise<{ ok: boolean; error?: string; uri?: string; count?: number }> { + const pageUrl = normalizePageUrl(String(pageUrlRaw || '').trim()) + if (!pageUrl) return { ok: false, error: 'pageUrl is empty' } + const items = await listClipsByUrl(pageUrl) + if (items.length === 0) return { ok: false, error: 'no clips for current page' } + const settings = await getSettings() + const normalizedTarget = normalizeObsidianTarget(settings.obsidianVault, settings.obsidianFolder) + if (normalizedTarget.vault) { + await writeLastObsidianVault(normalizedTarget.vault) + } + const vault = normalizedTarget.vault || (await readLastObsidianVault()) + const pageTitle = String(pageTitleRaw || items[0]?.pageTitle || pageUrl).trim() + const markdown = buildPageMarkdown(items, pageUrl, pageTitle) + const folder = normalizedTarget.folder + const noteBase = `${safeFileName(pageTitle)}-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-')}` + const filePath = folder ? `${folder}/${noteBase}` : noteBase + const query = + `file=${encodeURIComponent(filePath)}` + + `&content=${encodeURIComponent(markdown)}` + const uri = vault + ? `obsidian://new?vault=${encodeURIComponent(vault)}&${query}` + : `obsidian://new?${query}` + return { ok: true, uri, count: items.length } +} + +async function revealClipByScriptingFallback(tabId: number, item: ClipItem): Promise { + try { + const result = await browser.scripting.executeScript({ + target: { tabId }, + args: [item.quote || item.anchor?.exact || '', item.anchor?.prefix || '', item.anchor?.suffix || ''], + func: (quoteRaw: string, prefixRaw: string, suffixRaw: string) => { + const quote = String(quoteRaw || '').trim() + if (!quote) return { ok: false, error: 'quote is empty' } + const prefix = String(prefixRaw || '').trim() + const suffix = String(suffixRaw || '').trim() + const full = document.body?.innerText || document.documentElement?.innerText || '' + if (!full) return { ok: false, error: 'document text is empty' } + + let idx = full.indexOf(quote) + let matchedIndex = -1 + while (idx >= 0) { + const left = prefix ? full.slice(Math.max(0, idx - prefix.length), idx).trim() : '' + const right = suffix ? full.slice(idx + quote.length, idx + quote.length + suffix.length).trim() : '' + const prefixOk = !prefix || left === prefix + const suffixOk = !suffix || right === suffix + if (prefixOk && suffixOk) { + matchedIndex = idx + break + } + idx = full.indexOf(quote, idx + Math.max(1, Math.floor(quote.length / 2))) + } + if (matchedIndex < 0) return { ok: false, error: 'quote not found in page text' } + + const walker = document.createTreeWalker(document.body || document.documentElement, NodeFilter.SHOW_TEXT) + let cursor = 0 + let startNode: Text | null = null + let endNode: Text | null = null + let startOffset = 0 + let endOffset = 0 + const targetStart = matchedIndex + const targetEnd = matchedIndex + quote.length + let current = walker.nextNode() + while (current) { + if (current.nodeType === Node.TEXT_NODE) { + const text = current as Text + const value = text.nodeValue || '' + const next = cursor + value.length + if (!startNode && targetStart >= cursor && targetStart <= next) { + startNode = text + startOffset = Math.max(0, targetStart - cursor) + } + if (!endNode && targetEnd >= cursor && targetEnd <= next) { + endNode = text + endOffset = Math.max(0, targetEnd - cursor) + } + cursor = next + } + current = walker.nextNode() + } + if (!startNode || !endNode) return { ok: false, error: 'failed to map quote to text nodes' } + + const range = document.createRange() + range.setStart(startNode, Math.min(startNode.length, startOffset)) + range.setEnd(endNode, Math.min(endNode.length, endOffset)) + const rect = range.getBoundingClientRect() + const marker = document.createElement('span') + marker.style.position = 'absolute' + marker.style.left = `${window.scrollX + rect.left - 2}px` + marker.style.top = `${window.scrollY + rect.top - 2}px` + marker.style.width = `${Math.max(8, rect.width + 4)}px` + marker.style.height = `${Math.max(14, rect.height + 4)}px` + marker.style.pointerEvents = 'none' + marker.style.borderRadius = '6px' + marker.style.background = 'rgba(255, 240, 130, 0.42)' + marker.style.border = '1px solid rgba(230, 190, 70, 0.72)' + marker.style.zIndex = '2147483647' + document.documentElement.appendChild(marker) + window.scrollTo({ + top: Math.max(0, window.scrollY + rect.top - window.innerHeight * 0.35), + behavior: 'smooth', + }) + window.setTimeout(() => marker.remove(), 1800) + return { ok: true } + }, + }) + return Boolean((result?.[0]?.result as { ok?: boolean } | undefined)?.ok) + } catch { + return false + } +} + +async function createClipFromSelectionByScriptingFallback( + tabId: number, + fallbackTab?: { url?: string; title?: string } +): Promise<{ ok: boolean; item?: ClipItem; error?: string }> { + clipLog('createClipFromSelectionByScriptingFallback:start', { tabId }) + const injected = await browser.scripting.executeScript({ + target: { tabId }, + func: () => { + const selection = window.getSelection() + if (!selection || selection.rangeCount === 0) return { ok: false, error: 'empty selection' } + const quote = String(selection.toString() || '').trim() + if (!quote) return { ok: false, error: 'empty selection' } + const range = selection.getRangeAt(0) + const startNode = range.startContainer + const endNode = range.endContainer + const startText = startNode.nodeType === Node.TEXT_NODE ? String((startNode as Text).nodeValue || '') : '' + const endText = endNode.nodeType === Node.TEXT_NODE ? String((endNode as Text).nodeValue || '') : '' + const prefix = startText ? startText.slice(Math.max(0, range.startOffset - 24), range.startOffset).trim() : '' + const suffix = endText ? endText.slice(range.endOffset, Math.min(endText.length, range.endOffset + 24)).trim() : '' + return { + ok: true, + quote, + quoteHtml: (() => { + try { + const div = document.createElement('div') + div.appendChild(range.cloneContents()) + return div.innerHTML.trim() + } catch { + return '' + } + })(), + pageUrl: String(location.href || '').split('#')[0], + pageTitle: String(document.title || ''), + anchor: { + exact: quote, + prefix: prefix || undefined, + suffix: suffix || undefined, + }, + } + }, + }) + + const payload = injected?.[0]?.result as + | { + ok?: boolean + error?: string + quote?: string + quoteHtml?: string + pageUrl?: string + pageTitle?: string + anchor?: ClipItem['anchor'] + } + | undefined + if (!payload?.ok) { + const error = payload?.error || 'selection capture fallback failed' + clipLog('createClipFromSelectionByScriptingFallback:fail', error) + return { ok: false, error } + } + + const pageUrl = normalizePageUrl(String(payload.pageUrl || fallbackTab?.url || '')) + const pageTitle = String(payload.pageTitle || fallbackTab?.title || pageUrl).trim() + const quote = String(payload.quote || payload.anchor?.exact || '').trim() + const anchor = (payload.anchor || { exact: quote }) as ClipItem['anchor'] + if (!pageUrl || !quote || !String(anchor?.exact || '').trim()) { + return { ok: false, error: 'invalid clip payload from fallback' } + } + + const created: ClipItem = { + id: makeClipId(), + tabId, + pageUrl, + pageTitle: pageTitle || pageUrl, + quote, + quoteHtml: String(payload.quoteHtml || '').trim() || undefined, + createdAt: new Date().toISOString(), + color: 'yellow', + anchor, + } + const item = await insertClip(created) + clipLog('createClipFromSelectionByScriptingFallback:ok', { id: item.id, pageUrl: item.pageUrl }) + return { ok: true, item } +} + +async function findExistingTabIdByUrl(url: string): Promise { + const target = normalizePageUrl(url) + const tabs = await browser.tabs.query({}) + const hit = tabs.find((tab) => normalizePageUrl(String(tab.url || '')) === target) + return Number.isInteger(hit?.id) ? (hit?.id as number) : null +} + browser.runtime.onMessage.addListener((message: any, sender: any) => { + if (message?.type?.startsWith?.('clip:')) { + clipLog('runtime.onMessage', message?.type, { + senderTabId: Number(sender?.tab?.id), + senderUrl: String(sender?.tab?.url || ''), + }) + } + if (message?.type === 'capture-link-download') { const url = String(message?.url || '').trim() if (!url) return Promise.resolve({ ok: false, error: 'url is empty' }) @@ -549,9 +1147,145 @@ browser.runtime.onMessage.addListener((message: any, sender: any) => { return transferUrlToGdown(url, referer || url, 'yt-dlp') } + if (message?.type === 'file:download-text') { + const filename = String(message?.filename || '').trim() + const mime = String(message?.mime || 'text/plain;charset=utf-8').trim() + const content = String(message?.content || '') + return downloadTextFile(filename, mime, content) + } + + if (message?.type === 'clip:export-current-page-md') { + return exportCurrentPageClipsAs(String(message?.pageUrl || ''), String(message?.pageTitle || ''), 'md') + } + + if (message?.type === 'clip:export-current-page-json') { + return exportCurrentPageClipsAs(String(message?.pageUrl || ''), String(message?.pageTitle || ''), 'json') + } + + if (message?.type === 'clip:send-obsidian-current-page') { + return buildObsidianUriForCurrentPage(String(message?.pageUrl || ''), String(message?.pageTitle || '')) + } + + if (message?.type === 'clip:create') { + return getSettings().then(async (settings) => { + if (!settings.extensionStatus) return { ok: false, error: 'extension disabled' } + const pageUrl = normalizePageUrl(String(message?.pageUrl || sender?.tab?.url || '')) + const pageTitle = String(message?.pageTitle || sender?.tab?.title || '').trim() + const quote = String(message?.quote || message?.anchor?.exact || '').trim() + const quoteHtml = String(message?.quoteHtml || '').trim() + const anchor = message?.anchor as ClipItem['anchor'] + if (!pageUrl) return { ok: false, error: 'pageUrl is empty' } + if (!anchor || !String(anchor.exact || '').trim()) return { ok: false, error: 'anchor is empty' } + + const created: ClipItem = { + id: makeClipId(), + tabId: Number.isInteger(sender?.tab?.id) ? Number(sender.tab.id) : undefined, + pageUrl, + pageTitle: pageTitle || pageUrl, + quote: quote || String(anchor.exact || '').trim(), + quoteHtml: quoteHtml || undefined, + createdAt: new Date().toISOString(), + color: 'yellow', + anchor, + } + const item = await insertClip(created) + return { ok: true, item } + }) + } + + if (message?.type === 'clip:list') { + const pageUrl = String(message?.pageUrl || '').trim() + if (pageUrl) { + return listClipsByUrl(pageUrl).then((items) => ({ ok: true, items })) + } + return listClips().then((items) => ({ ok: true, items })) + } + + if (message?.type === 'clip:export') { + return listClips().then((items) => ({ ok: true, items })) + } + + if (message?.type === 'clip:import') { + const items = Array.isArray(message?.items) ? message.items : [] + return importClips(items).then((result) => ({ ok: true, ...result })) + } + + if (message?.type === 'clip:delete') { + const id = String(message?.id || '').trim() + if (!id) return Promise.resolve({ ok: false, error: 'id is empty' }) + return deleteClip(id).then((deleted) => ({ ok: deleted })) + } + + if (message?.type === 'clip:create-active-tab') { + return requestCreateClipOnActiveTab() + } + + if (message?.type === 'clip:resolve-status') { + const id = String(message?.id || '').trim() + const status = String(message?.status || '').trim() + if (!id) return Promise.resolve({ ok: false, error: 'id is empty' }) + if (status !== 'ok' && status !== 'broken') return Promise.resolve({ ok: false, error: 'invalid status' }) + return updateClipResolveStatus(id, status).then((item) => ({ ok: !!item, item })) + } + + if (message?.type === 'clip:reveal') { + const id = String(message?.id || '').trim() + if (!id) return Promise.resolve({ ok: false, error: 'id is empty' }) + return getClipById(id).then(async (item) => { + if (!item) return { ok: false, error: 'clip not found' } + const tabId = Number.isInteger(item.tabId) && (item.tabId || 0) >= 0 ? (item.tabId as number) : await findExistingTabIdByUrl(item.pageUrl) + if (!Number.isInteger(tabId) || (tabId as number) < 0) { + const created = await browser.tabs.create({ url: item.pageUrl, active: true }).catch(() => null) + if (!Number.isInteger(created?.id)) return { ok: false, error: 'failed to open clip page' } + return { ok: true, opened: true } + } + await browser.tabs.update(tabId as number, { active: true }).catch(() => null) + const revealResult = (await browser.tabs + .sendMessage(tabId as number, { + type: 'clip:reveal', + id: item.id, + }) + .catch(() => null)) as { ok?: boolean } | null + if (!revealResult?.ok) { + const fallbackOk = await revealClipByScriptingFallback(tabId as number, item) + if (fallbackOk) { + await updateClipResolveStatus(item.id, 'ok') + return { ok: true, fallback: 'scripting' } + } + await updateClipResolveStatus(item.id, 'broken') + return { ok: false, error: 'clip anchor not found in current dom' } + } + await updateClipResolveStatus(item.id, 'ok') + return { ok: true } + }) + } + return undefined }) +browser.commands.onCommand.addListener((command) => { + clipLog('commands.onCommand', command) + if (command !== 'create_clip_from_selection') return + void (async () => { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }) + const tabId = Number(tabs[0]?.id) + if (Number.isInteger(tabId) && tabId >= 0) { + const shown = await browser.tabs + .sendMessage(tabId, { type: 'clip:show-action-bar' }) + .then((v) => Boolean((v as any)?.ok)) + .catch(() => false) + if (shown) return + const injectedShown = await showInlineActionBarByScripting(tabId) + if (injectedShown) return + } + + const result = await requestCreateClipOnActiveTab() + if (result.ok) return + clipLog('commands.onCommand:fail', result) + await notify(`클립 생성 실패: ${result.error || 'unknown error'}`) + })() +}) + browser.runtime.onInstalled.addListener(() => { console.log('[gomdown-helper] onInstalled') setupWebRequestInterceptor() diff --git a/src/config/main.tsx b/src/config/main.tsx index 11f361a..b274d5d 100644 --- a/src/config/main.tsx +++ b/src/config/main.tsx @@ -63,6 +63,16 @@ function SettingsPage(): JSX.Element {