From 58c7906cb8ac7878f03e451c7639043429634ff0 Mon Sep 17 00:00:00 2001 From: projectdx Date: Sun, 1 Mar 2026 22:28:23 +0900 Subject: [PATCH] feat: improve clip UX, markdown export, and obsidian flow --- docs/TODO.md | 15 +- manifest.config.ts | 11 +- package.json | 2 +- packages/chrome/.vite/manifest.json | 29 +- packages/chrome/assets/clipTypes-C_ha5Ash.js | 1 + ...{index-CJaGAyoX.css => index-xoGXBrzN.css} | 2 +- packages/chrome/assets/index.html-92_ZB8wX.js | 1 - packages/chrome/assets/index.html-ClVBeFHX.js | 1 + packages/chrome/assets/index.ts-BkGMAUD4.js | 1 + packages/chrome/assets/index.ts-DQGjv8iX.js | 1 + packages/chrome/assets/index.ts-U8lbRRO-.js | 1 - .../assets/index.ts-loader-2I0oIARK.js} | 2 +- packages/chrome/assets/index.ts-w1ilzv93.js | 1 - packages/chrome/manifest.json | 7 +- packages/chrome/service-worker-loader.js | 2 +- packages/chrome/src/popup/index.html | 5 +- packages/edge/.vite/manifest.json | 65 +- ...{client-CBvt1tWS.js => client-DnQyoB4h.js} | 2 +- packages/edge/assets/clipTypes-C_ha5Ash.js | 1 + packages/edge/assets/index-BZvbrf4l.css | 1 - packages/edge/assets/index-CV3UOEJM.css | 1 + packages/edge/assets/index.html-B0Kfv8fq.js | 3 - packages/edge/assets/index.html-CYipkEaD.js | 3 + packages/edge/assets/index.html-D-JbSuV5.js | 1 - packages/edge/assets/index.html-yhgSfkXU.js | 41 + packages/edge/assets/index.ts-BGLNJwsP.js | 1 - packages/edge/assets/index.ts-BnPsJZXz.js | 1 - packages/edge/assets/index.ts-D64R0PS1.js | 7 + packages/edge/assets/index.ts-DMIsnBNX.js | 1 + .../assets/index.ts-loader-DWDY2bjZ.js} | 2 +- packages/edge/assets/settings-Bo6W9Drl.js | 1 - ...yfill-CZ_dLIqp.js => settings-mco8QK8Y.js} | 2 +- packages/edge/images/128.png | Bin 11155 -> 7223 bytes packages/edge/images/16.png | Bin 597 -> 613 bytes packages/edge/images/32.png | Bin 1511 -> 1536 bytes packages/edge/images/48.png | Bin 2908 -> 2508 bytes packages/edge/images/dwld.png | Bin 553 -> 1536 bytes packages/edge/images/icon-large.png | Bin 29630 -> 15429 bytes packages/edge/images/pomeranian-bw.svg | 17 + packages/edge/manifest.json | 21 +- packages/edge/service-worker-loader.js | 2 +- packages/edge/src/config/index.html | 7 +- packages/edge/src/popup/index.html | 10 +- src/background/index.ts | 734 ++++++++++++++++++ src/config/main.tsx | 10 + src/content/index.ts | 583 ++++++++++++++ src/lib/clipAnchor.ts | 206 +++++ src/lib/clipStore.ts | 158 ++++ src/lib/clipTypes.ts | 41 + src/lib/settings.ts | 6 + src/popup/main.tsx | 593 +++++++++++++- src/popup/styles.css | 93 +++ tsconfig.tsbuildinfo | 2 +- 53 files changed, 2603 insertions(+), 95 deletions(-) create mode 100644 packages/chrome/assets/clipTypes-C_ha5Ash.js rename packages/chrome/assets/{index-CJaGAyoX.css => index-xoGXBrzN.css} (63%) delete mode 100644 packages/chrome/assets/index.html-92_ZB8wX.js create mode 100644 packages/chrome/assets/index.html-ClVBeFHX.js create mode 100644 packages/chrome/assets/index.ts-BkGMAUD4.js create mode 100644 packages/chrome/assets/index.ts-DQGjv8iX.js delete mode 100644 packages/chrome/assets/index.ts-U8lbRRO-.js rename packages/{edge/assets/index.ts-loader-DMyyuf2n.js => chrome/assets/index.ts-loader-2I0oIARK.js} (82%) delete mode 100644 packages/chrome/assets/index.ts-w1ilzv93.js rename packages/edge/assets/{client-CBvt1tWS.js => client-DnQyoB4h.js} (87%) create mode 100644 packages/edge/assets/clipTypes-C_ha5Ash.js delete mode 100644 packages/edge/assets/index-BZvbrf4l.css create mode 100644 packages/edge/assets/index-CV3UOEJM.css delete mode 100644 packages/edge/assets/index.html-B0Kfv8fq.js create mode 100644 packages/edge/assets/index.html-CYipkEaD.js delete mode 100644 packages/edge/assets/index.html-D-JbSuV5.js create mode 100644 packages/edge/assets/index.html-yhgSfkXU.js delete mode 100644 packages/edge/assets/index.ts-BGLNJwsP.js delete mode 100644 packages/edge/assets/index.ts-BnPsJZXz.js create mode 100644 packages/edge/assets/index.ts-D64R0PS1.js create mode 100644 packages/edge/assets/index.ts-DMIsnBNX.js rename packages/{chrome/assets/index.ts-loader-D_eQmgUa.js => edge/assets/index.ts-loader-DWDY2bjZ.js} (82%) delete mode 100644 packages/edge/assets/settings-Bo6W9Drl.js rename packages/edge/assets/{browser-polyfill-CZ_dLIqp.js => settings-mco8QK8Y.js} (51%) create mode 100644 packages/edge/images/pomeranian-bw.svg create mode 100644 src/lib/clipAnchor.ts create mode 100644 src/lib/clipStore.ts create mode 100644 src/lib/clipTypes.ts 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 eaae62a6bc20cb59acee3be32337d50fa6364864..d547e24d647759a97a5247ebc3a6c0db0c246f9d 100644 GIT binary patch literal 7223 zcmX9@2RxMjAAdOGh^$LSvPbrwnK@)-W@n{PM#@S!Wn_;wc z_A8?y`x6AwZ#`62H1JB@PV+WE7@c%Bjo~Tc1U-w@ia^8Pt58L&;YFg*6oMW2aTzyR zl+%ep7#GZy zRDl|Gh(O9dMhas36a&e9ArYvLV1Y;>BaG5CKI@i(H0l!i?_QYWA8ynq9CD>v*cm4Z z1LaqzYu+fDffds#h$3~hUXs~3L4o9!kQvU=Qeg@;sUCq91yYxD(qQKolrC|)iNmX> zE5w&92`9nF-`C b-ymL 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 literal 11155 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 b&P4tI#&q`?>H_;s00000NkvXXu0mjfWCtCw delta 573 zcmV-D0>b^}1l0tPBYy%MNklz>L z6cwd9)0C!W7Jm>ChPx+OP9`|+-HfNaNLheDFe;<>11yO_kpF<*nPevE8uZ&j9g5bS~s$#s>}v_AAg?~-$2;9gNAduLn(du=(CJn zJL|3Qquw|MCTCln)YX*R02>mNcl}Z7oBzK3wdp+UGr7>Vp1K-$s*QgR9UK}Qc{%&G zfP@&tL=iU)>tYu%NSIh9?mrOHgLDXZwK@lBQI3B7G5P%Uz)#{DAO?%3Vj1mh(A45! zTdn69@HS$_C*x!K^388OCOuGEdVsWcY^}=GQ=MK`MnKj!toivH)<44$bO2V_00000 LNkvXXu0mjf#`qDI diff --git a/packages/edge/images/32.png b/packages/edge/images/32.png index d77f9296979dad7b47bfcfc0fff186d16c98b426..3214db3c882eb79e0d72309e59548137c4863329 100644 GIT binary patch delta 1519 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 diff --git a/packages/edge/images/48.png b/packages/edge/images/48.png index eb9f4b6f0c30a530414393e2f89db7b061651df9..a72d4f5b364b4cc1cd54ffdcc6e1162af2b59612 100644 GIT binary patch delta 2499 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 A!vFvP diff --git a/packages/edge/images/dwld.png b/packages/edge/images/dwld.png index 029ced1acab200fd71ef1cc66cedf1e436147907..3214db3c882eb79e0d72309e59548137c4863329 100644 GIT binary patch literal 1536 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 literal 29630 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 FV1jEcL)icT 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 {