diff --git a/docs/CLIPPING_HIGHLIGHT_PLAN.md b/docs/CLIPPING_HIGHLIGHT_PLAN.md new file mode 100644 index 0000000..3698eab --- /dev/null +++ b/docs/CLIPPING_HIGHLIGHT_PLAN.md @@ -0,0 +1,115 @@ +# Page Clipping + Highlight Implementation Plan + +## Goal +- 사용자가 특정 페이지에서 선택한 텍스트를 클리핑(저장)한다. +- 저장된 클립은 원문 위치에 하이라이트로 다시 표시된다. +- 팝업에서 클립 목록을 보고 해당 위치로 다시 이동할 수 있다. + +## Scope (v1) +1. 지원 대상 +- 텍스트 기반 웹페이지 (`contenteditable` 제외, 일반 DOM 문서 우선) +- 탭 단위 클립 저장/조회 + +2. 포함 기능 +- 선택 텍스트 캡처 +- 하이라이트 주입/복원 +- 클립 목록 조회/삭제 +- 클릭 시 원문 위치로 스크롤 + +3. 제외 기능(후속) +- PDF/캔버스/이미지 OCR 하이라이트 +- 협업 공유/서버 동기화 +- 다중 색상 태깅, 폴더 분류 + +## Data Model (Draft) +```ts +type ClipItem = { + id: string + tabId?: number + pageUrl: string + pageTitle: string + quote: string + createdAt: string + color: 'yellow' + anchor: { + textStart: string + textEnd: string + exact: string + prefix?: string + suffix?: string + xpathStart?: string + xpathEnd?: string + startOffset?: number + endOffset?: number + } +} +``` + +## Architecture +1. Content Script +- 사용자 선택(`window.getSelection`)에서 `Range` 추출 +- `anchor` 생성(텍스트 인용 + DOM 포지션) +- background에 `clip:create` 메시지 전송 +- `clip:apply` 이벤트 수신 시 하이라이트 렌더링 + +2. Background (Service Worker) +- `clip:create`, `clip:list`, `clip:delete`, `clip:reveal` 메시지 처리 +- `storage.local` 기반 영속화 +- 탭 활성화/페이지 완료 시 `clip:sync` 트리거 + +3. Popup/History UI +- 현재 탭 URL 기준 클립 목록 요청 +- 항목별 `위치로 이동`, `삭제` 버튼 +- 상태 메시지(저장 성공/실패) 표시 + +## Step-by-Step +1. Step 1: Selection Capture + Overlay +- `src/lib/clipAnchor.ts` 생성 +- `Range -> anchor` 변환 유틸 구현 +- `src/content/index.ts`에 단축키/우클릭 기반 캡처 진입점 추가 +- `span[data-gomdown-clip]` 하이라이트 렌더링/해제 로직 구현 + +2. Step 2: Store + Message Channel +- `src/lib/clipStore.ts` 생성 (`list/upsert/delete/byUrl`) +- background message router에 `clip:*` 타입 추가 +- dedupe(`pageUrl + exact + createdAt window`) 정책 추가 + +3. Step 3: Popup UI +- `src/popup/main.tsx`에 "Clips" 섹션 추가 +- 현재 탭 URL 클립 조회 + 목록 렌더링 +- `Reveal/Delete` 액션과 오류 상태 처리 + +4. Step 4: Re-anchoring +- 페이지 로드 시 `clip:list` 후 순차 복원 +- 우선순위: +- `exact + prefix/suffix` 텍스트 매칭 +- 실패 시 `xpath + offset` 복구 +- 둘 다 실패 시 `broken anchor`로 표시 + +5. Step 5: Export/Import + QA +- JSON export/import 메시지 추가 +- 샘플 페이지(뉴스, 블로그, SPA) 수동 테스트 +- 회귀 체크리스트 문서화 + +## QA Checklist +- 같은 페이지 새로고침 후 하이라이트가 유지된다. +- SPA 라우팅(YouTube/블로그) 후에도 복원 시도가 동작한다. +- 원문 DOM이 일부 바뀐 경우, 텍스트 매칭 fallback이 동작한다. +- 클립 삭제 시 화면/저장소에서 모두 제거된다. +- 확장 비활성화 상태에서 캡처가 차단된다. + +## Risk & Mitigation +1. DOM 변형으로 앵커 붕괴 +- 텍스트 인용 앵커 + XPath 이중 저장 + +2. 성능 저하(클립 다수) +- URL 단위 lazy apply, viewport 근처 우선 렌더 + +3. 사이트 충돌(CSS/스크립트) +- 고유 data-attribute와 최소 침습 스타일 사용 + +## Definition of Done +- 사용자는 텍스트 선택 후 1회 액션으로 클립 저장 가능 +- 같은 URL 재방문 시 하이라이트 자동 복원 +- 팝업에서 클립 조회/이동/삭제 가능 +- 크롬 기준 수동 시나리오 10개 중 9개 이상 성공 diff --git a/docs/TODO.md b/docs/TODO.md index 0efa4c4..170e4e1 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -9,3 +9,11 @@ - [ ] Step 2: content script 보조 탐지 - [ ] Step 3: 노이즈 필터/품질 그룹핑 - [ ] Step 4: 고급 분석/진단 UI + +## 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)와 기본 회귀 테스트 시나리오 정리 diff --git a/packages/chrome/.vite/manifest.json b/packages/chrome/.vite/manifest.json index e14a1c7..d8c8fa2 100644 --- a/packages/chrome/.vite/manifest.json +++ b/packages/chrome/.vite/manifest.json @@ -1,83 +1,73 @@ { - "../../../../../@crx/manifest": { - "file": "assets/crx-manifest.js-mSo6-ym3.js", + "../../../../../../../@crx/manifest": { + "file": "assets/crx-manifest.js-CXu7hmTa.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-BzjyOx7y.js": { + "file": "assets/client-BzjyOx7y.js", "name": "client", "imports": [ - "_browser-polyfill-CZ_dLIqp.js" + "_settings-CgBxHrrF.js" ] }, "_downloadIntent-Dv31jC2S.js": { "file": "assets/downloadIntent-Dv31jC2S.js", "name": "downloadIntent" }, - "_index.ts-loader-Bju9eGS_.js": { - "file": "assets/index.ts-loader-Bju9eGS_.js", - "src": "_index.ts-loader-Bju9eGS_.js" + "_index.ts-loader-D_eQmgUa.js": { + "file": "assets/index.ts-loader-D_eQmgUa.js", + "src": "_index.ts-loader-D_eQmgUa.js" }, - "_settings-Bo6W9Drl.js": { - "file": "assets/settings-Bo6W9Drl.js", - "name": "settings", - "imports": [ - "_browser-polyfill-CZ_dLIqp.js" - ] + "_settings-CgBxHrrF.js": { + "file": "assets/settings-CgBxHrrF.js", + "name": "settings" }, "src/background/index.ts": { - "file": "assets/index.ts-BljhweV3.js", + "file": "assets/index.ts-U8lbRRO-.js", "name": "index.ts", "src": "src/background/index.ts", "isEntry": true, "imports": [ - "_browser-polyfill-CZ_dLIqp.js", - "_downloadIntent-Dv31jC2S.js", - "_settings-Bo6W9Drl.js" + "_settings-CgBxHrrF.js", + "_downloadIntent-Dv31jC2S.js" ] }, "src/config/index.html": { - "file": "assets/index.html-B0Kfv8fq.js", + "file": "assets/index.html-B7fMyQPm.js", "name": "index.html", "src": "src/config/index.html", "isEntry": true, "imports": [ - "_client-CBvt1tWS.js", - "_settings-Bo6W9Drl.js", - "_browser-polyfill-CZ_dLIqp.js" + "_client-BzjyOx7y.js", + "_settings-CgBxHrrF.js" ], "css": [ "assets/index-B2D5FcJM.css" ] }, "src/content/index.ts": { - "file": "assets/index.ts-C6ePCen1.js", + "file": "assets/index.ts-w1ilzv93.js", "name": "index.ts", "src": "src/content/index.ts", "isEntry": true, "imports": [ - "_browser-polyfill-CZ_dLIqp.js", + "_settings-CgBxHrrF.js", "_downloadIntent-Dv31jC2S.js" ] }, "src/popup/index.html": { - "file": "assets/index.html-BLzIyLM-.js", + "file": "assets/index.html-92_ZB8wX.js", "name": "index.html", "src": "src/popup/index.html", "isEntry": true, "imports": [ - "_client-CBvt1tWS.js", - "_browser-polyfill-CZ_dLIqp.js", - "_settings-Bo6W9Drl.js" + "_client-BzjyOx7y.js", + "_settings-CgBxHrrF.js" ], "css": [ - "assets/index-D6aWDpYY.css" + "assets/index-CJaGAyoX.css" ] } } \ No newline at end of file diff --git a/packages/chrome/assets/client-CBvt1tWS.js b/packages/chrome/assets/client-BzjyOx7y.js similarity index 87% rename from packages/chrome/assets/client-CBvt1tWS.js rename to packages/chrome/assets/client-BzjyOx7y.js index 5765dc3..f0a3fbf 100644 --- a/packages/chrome/assets/client-CBvt1tWS.js +++ b/packages/chrome/assets/client-BzjyOx7y.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/chrome/assets/index-CJaGAyoX.css b/packages/chrome/assets/index-CJaGAyoX.css new file mode 100644 index 0000000..d8b30c1 --- /dev/null +++ b/packages/chrome/assets/index-CJaGAyoX.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;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} diff --git a/packages/chrome/assets/index-D6aWDpYY.css b/packages/chrome/assets/index-D6aWDpYY.css deleted file mode 100644 index 9e31168..0000000 --- a/packages/chrome/assets/index-D6aWDpYY.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}.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} diff --git a/packages/chrome/assets/index.html-92_ZB8wX.js b/packages/chrome/assets/index.html-92_ZB8wX.js new file mode 100644 index 0000000..5314395 --- /dev/null +++ b/packages/chrome/assets/index.html-92_ZB8wX.js @@ -0,0 +1 @@ +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-B0Kfv8fq.js b/packages/chrome/assets/index.html-B7fMyQPm.js similarity index 89% rename from packages/chrome/assets/index.html-B0Kfv8fq.js rename to packages/chrome/assets/index.html-B7fMyQPm.js index 7816542..df44250 100644 --- a/packages/chrome/assets/index.html-B0Kfv8fq.js +++ b/packages/chrome/assets/index.html-B7fMyQPm.js @@ -1,3 +1,3 @@ -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(` +import{c as j,j as e,R as a}from"./client-BzjyOx7y.js";import{g as p,s as m}from"./settings-CgBxHrrF.js";function u(){const[t,i]=a.useState(null),[l,r]=a.useState(""),[h,d]=a.useState("");a.useEffect(()=>{p().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,{})})); +`).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..."})}j.createRoot(document.getElementById("root")).render(e.jsx(a.StrictMode,{children:e.jsx(u,{})})); diff --git a/packages/chrome/assets/index.html-BLzIyLM-.js b/packages/chrome/assets/index.html-BLzIyLM-.js deleted file mode 100644 index 87126ce..0000000 --- a/packages/chrome/assets/index.html-BLzIyLM-.js +++ /dev/null @@ -1 +0,0 @@ -import{c as k,j as t,R as r}from"./client-CBvt1tWS.js";import{b as i}from"./browser-polyfill-CZ_dLIqp.js";import{g as N,s as m}from"./settings-Bo6W9Drl.js";function b(){const[s,d]=r.useState(null),[x,n]=r.useState(""),[l,u]=r.useState([]);r.useEffect(()=>{N().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})},h=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))},p=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.jsx("h1",{children:"Gomdown Helper"}),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:["Extension Enabled",t.jsx("input",{type:"checkbox",checked:s.extensionStatus,onChange:e=>{h(e.target.checked)}})]}),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:p,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..."})}k.createRoot(document.getElementById("root")).render(t.jsx(r.StrictMode,{children:t.jsx(b,{})})); diff --git a/packages/chrome/assets/index.ts-BljhweV3.js b/packages/chrome/assets/index.ts-BljhweV3.js deleted file mode 100644 index 9311254..0000000 --- a/packages/chrome/assets/index.ts-BljhweV3.js +++ /dev/null @@ -1 +0,0 @@ -import{b as i}from"./browser-polyfill-CZ_dLIqp.js";import{n as P,a as j}from"./downloadIntent-Dv31jC2S.js";import{g as h}from"./settings-Bo6W9Drl.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/chrome/assets/index.ts-C6ePCen1.js b/packages/chrome/assets/index.ts-C6ePCen1.js deleted file mode 100644 index 2ee71d0..0000000 --- a/packages/chrome/assets/index.ts-C6ePCen1.js +++ /dev/null @@ -1 +0,0 @@ -import{b as m}from"./browser-polyfill-CZ_dLIqp.js";import{i as s,n as C}from"./downloadIntent-Dv31jC2S.js";const S=8e3,i=new Map;function v(){const e=Date.now();for(const[n,t]of i.entries())t<=e&&i.delete(n)}async function a(e,n){const t=C(e,window.location.href);if(!t)return!1;if(v(),i.has(t))return!0;i.set(t,Date.now()+S);try{if((await m.runtime.sendMessage({type:"capture-link-download",url:t,referer:n||document.referrer||window.location.href}))?.ok)return!0}catch{}return i.delete(t),!1}function g(e){return e?e instanceof HTMLAnchorElement?e:e instanceof Element?e.closest("a[href]"):null:null}function b(e){return!!(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)}async function k(e){if(e.defaultPrevented||b(e))return;const n=g(e.target);if(!n)return;const t=n.href||"";!t||!s(t,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),await a(t,document.referrer||window.location.href))}function E(e){const n=g(e.target);if(!n)return;const t=n.href||"";!t||!s(t,window.location.href)||b(e)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),a(t,document.referrer||window.location.href))}document.addEventListener("pointerdown",e=>{e.button===0&&E(e)},!0);document.addEventListener("mousedown",e=>{e.button===0&&E(e)},!0);document.addEventListener("click",e=>{e.button===0&&k(e)},!0);document.addEventListener("keydown",e=>{if(e.key!=="Enter"||e.defaultPrevented||b(e))return;const n=g(e.target);if(!n)return;const t=n.href||"";!t||!s(t,window.location.href)||(e.preventDefault(),e.stopImmediatePropagation(),e.stopPropagation(),a(t,document.referrer||window.location.href))},!0);document.addEventListener("auxclick",e=>{e.button===1&&k(e)},!0);function L(){try{const e=window.open.bind(window);window.open=function(t,o,u){const y=String(t||"").trim();return y&&s(y,window.location.href)?(a(y,window.location.href),null):e(t,o,u)}}catch{}try{const e=HTMLAnchorElement.prototype.click;HTMLAnchorElement.prototype.click=function(){const t=this.href||this.getAttribute("href")||"";if(t&&s(t,window.location.href)){a(t,document.referrer||window.location.href);return}e.call(this)}}catch{}}L();let l=null,r=null,w=!1,x=null,d=window.location.href;function T(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 c(e,n="idle"){r&&(r.textContent=e,n==="ok"?r.style.color="#8ff0a4":n==="error"?r.style.color="#ff9b9b":r.style.color="#aeb7d8")}async function I(){if(!w){w=!0,c("gdown으로 전송 중...");try{const e=await m.runtime.sendMessage({type:"page:enqueue-ytdlp-url",url:window.location.href,referer:window.location.href});e?.ok?c("다운로드 모달로 전송됨","ok"):c(`전송 실패: ${e?.error||"unknown error"}`,"error")}catch(e){c(`전송 실패: ${String(e)}`,"error")}finally{w=!1}}}function M(){l&&(l.remove(),l=null,r=null)}function p(){if(window.top!==window.self)return;if(!T(window.location.href)){M();return}if(l)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",()=>{I()});const o=document.createElement("div");o.textContent="클릭 시 gdown 다운로드 모달로 연결",o.style.fontSize="11px",o.style.marginTop="8px",o.style.lineHeight="1.35",o.style.color="#aeb7d8",e.appendChild(n),e.appendChild(t),e.appendChild(o),document.documentElement.appendChild(e),l=e,r=o}function P(){x===null&&(x=window.setInterval(()=>{const e=window.location.href;e!==d&&(d=e,p())},800),window.addEventListener("popstate",()=>{d=window.location.href,p()}),document.addEventListener("yt-navigate-finish",()=>{d=window.location.href,p()}))}p();P();let h=null,f=null;function O(){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 A(e){const n=O(),t=String(e?.kind||"media").toUpperCase(),o=String(e?.suggestedOut||"").trim(),u=String(e?.url||"").trim().slice(0,96);n.textContent=o?`캡처됨 [${t}] ${o}`:`캡처됨 [${t}] ${u}${u.length>=96?"…":""}`,n.style.display="block",f!==null&&window.clearTimeout(f),f=window.setTimeout(()=>{n.style.display="none",f=null},2200)}m.runtime.onMessage.addListener(e=>{e?.type==="media:captured"&&A({kind:e?.kind,url:e?.url,suggestedOut:e?.suggestedOut})}); diff --git a/packages/chrome/assets/index.ts-U8lbRRO-.js b/packages/chrome/assets/index.ts-U8lbRRO-.js new file mode 100644 index 0000000..551edde --- /dev/null +++ b/packages/chrome/assets/index.ts-U8lbRRO-.js @@ -0,0 +1 @@ +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/chrome/assets/index.ts-loader-Bju9eGS_.js b/packages/chrome/assets/index.ts-loader-D_eQmgUa.js similarity index 82% rename from packages/chrome/assets/index.ts-loader-Bju9eGS_.js rename to packages/chrome/assets/index.ts-loader-D_eQmgUa.js index 08be718..8486299 100644 --- a/packages/chrome/assets/index.ts-loader-Bju9eGS_.js +++ b/packages/chrome/assets/index.ts-loader-D_eQmgUa.js @@ -5,7 +5,7 @@ (async () => { const { onExecute } = await import( /* @vite-ignore */ - chrome.runtime.getURL("assets/index.ts-C6ePCen1.js") + chrome.runtime.getURL("assets/index.ts-w1ilzv93.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 new file mode 100644 index 0000000..09cfe85 --- /dev/null +++ b/packages/chrome/assets/index.ts-w1ilzv93.js @@ -0,0 +1 @@ +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/assets/settings-Bo6W9Drl.js b/packages/chrome/assets/settings-Bo6W9Drl.js deleted file mode 100644 index cbfb728..0000000 --- a/packages/chrome/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/chrome/assets/browser-polyfill-CZ_dLIqp.js b/packages/chrome/assets/settings-CgBxHrrF.js similarity index 53% rename from packages/chrome/assets/browser-polyfill-CZ_dLIqp.js rename to packages/chrome/assets/settings-CgBxHrrF.js index 377b743..076059a 100644 --- a/packages/chrome/assets/browser-polyfill-CZ_dLIqp.js +++ b/packages/chrome/assets/settings-CgBxHrrF.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(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var w={exports:{}},I=w.exports,O;function W(){return O||(O=1,(function(t,P){(function(p,k){k(t)})(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 S 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)},f=e=>e==1?"argument":"arguments",L=(e,r)=>function(g,...i){if(i.lengthr.maxArgs)throw new Error(`Expected at most ${r.maxArgs} ${f(r.maxArgs)} for ${e}(), got ${i.length}`);return new Promise((m,A)=>{if(r.fallbackToNoCallback)try{g[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),g[e](...i),r.fallbackToNoCallback=!1,r.noCallback=!0,m()}else r.noCallback?(g[e](...i),m()):g[e](...i,E({resolve:m,reject:A},r))})},N=(e,r,n)=>new Proxy(r,{apply(g,i,m){return n.call(i,e,...m)}});let b=Function.call.bind(Object.prototype.hasOwnProperty);const h=(e,r={},n={})=>{let g=Object.create(null),i={has(A,s){return s in e||s in g},get(A,s,l){if(s in g)return g[s];if(!(s in e))return;let a=e[s];if(typeof a=="function")if(typeof r[s]=="function")a=N(e,e[s],r[s]);else if(b(n,s)){let u=L(s,n[s]);a=N(e,e[s],u)}else a=a.bind(e);else if(typeof a=="object"&&a!==null&&(b(r,s)||b(n,s)))a=h(a,r[s],n[s]);else if(b(n,"*"))a=h(a,r[s],n["*"]);else return Object.defineProperty(g,s,{configurable:!0,enumerable:!0,get(){return e[s]},set(u){e[s]=u}}),a;return g[s]=a,a},set(A,s,l,a){return s in g?g[s]=l:e[s]=l,!0},defineProperty(A,s,l){return Reflect.defineProperty(g,s,l)},deleteProperty(A,s){return Reflect.deleteProperty(g,s)}},m=Object.create(e);return new Proxy(m,i)},C=e=>({addListener(r,n,...g){r.addListener(e.get(n),...g)},hasListener(r,n){return r.hasListener(e.get(n))},removeListener(r,n){r.removeListener(e.get(n))}}),_=new S(e=>typeof e!="function"?e:function(n){const g=h(n,{},{getContent:{minArgs:0,maxArgs:0}});e(g)}),B=new S(e=>typeof e!="function"?e:function(n,g,i){let m=!1,A,s=new Promise(d=>{A=function(c){m=!0,d(c)}}),l;try{l=e(n,g,A)}catch(d){l=Promise.reject(d)}const a=l!==!0&&$(l);if(l!==!0&&!a&&!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(a?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)},M=(e,r,n,...g)=>{if(g.lengthr.maxArgs)throw new Error(`Expected at most ${r.maxArgs} ${f(r.maxArgs)} for ${e}(), got ${g.length}`);return new Promise((i,m)=>{const A=j.bind(null,{resolve:i,reject:m});g.push(A),n.sendMessage(...g)})},D={devtools:{network:{onRequestFinished:C(_)}},runtime:{onMessage:C(B),onMessageExternal:C(B),sendMessage:M.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:M.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 F=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:""};async function z(){const t=await F.storage.sync.get(Object.keys(o));return{extensionStatus:!!(t.extensionStatus??o.extensionStatus),useNativeHost:!!(t.useNativeHost??o.useNativeHost),activateAppOnDownload:!!(t.activateAppOnDownload??o.activateAppOnDownload),enableNotifications:!!(t.enableNotifications??o.enableNotifications),hideChromeBar:!!(t.hideChromeBar??o.hideChromeBar),showContextOption:!!(t.showContextOption??o.showContextOption),downloadFallback:!!(t.downloadFallback??o.downloadFallback),darkMode:!!(t.darkMode??o.darkMode),showOnlyAria:!!(t.showOnlyAria??o.showOnlyAria),minFileSize:Number(t.minFileSize??o.minFileSize),blacklist:Array.isArray(t.blacklist)?t.blacklist.map(P=>String(P)):o.blacklist,motrixPort:Number(t.motrixPort??o.motrixPort),motrixAPIkey:String(t.motrixAPIkey??o.motrixAPIkey)}}async function H(t){await F.storage.sync.set(t)}export{q as a,F as b,z as g,H as s}; diff --git a/packages/chrome/manifest.json b/packages/chrome/manifest.json index 4aeff20..f00ab3f 100644 --- a/packages/chrome/manifest.json +++ b/packages/chrome/manifest.json @@ -28,7 +28,7 @@ "content_scripts": [ { "js": [ - "assets/index.ts-loader-Bju9eGS_.js" + "assets/index.ts-loader-D_eQmgUa.js" ], "matches": [ "" @@ -57,9 +57,9 @@ ], "resources": [ "images/*", - "assets/browser-polyfill-CZ_dLIqp.js", + "assets/settings-CgBxHrrF.js", "assets/downloadIntent-Dv31jC2S.js", - "assets/index.ts-C6ePCen1.js" + "assets/index.ts-w1ilzv93.js" ], "use_dynamic_url": false } diff --git a/packages/chrome/service-worker-loader.js b/packages/chrome/service-worker-loader.js index f7c4242..7f12106 100644 --- a/packages/chrome/service-worker-loader.js +++ b/packages/chrome/service-worker-loader.js @@ -1 +1 @@ -import './assets/index.ts-BljhweV3.js'; +import './assets/index.ts-U8lbRRO-.js'; diff --git a/packages/chrome/src/config/index.html b/packages/chrome/src/config/index.html index f9377f9..53a3ae7 100644 --- a/packages/chrome/src/config/index.html +++ b/packages/chrome/src/config/index.html @@ -4,10 +4,9 @@ Gomdown Helper Settings - - - - + + + diff --git a/packages/chrome/src/popup/index.html b/packages/chrome/src/popup/index.html index 091206d..b80a3e8 100644 --- a/packages/chrome/src/popup/index.html +++ b/packages/chrome/src/popup/index.html @@ -4,11 +4,10 @@ Gomdown Helper - - - - - + + + +
diff --git a/packages/gomdown-helper.v0.0.16.chrome.zip b/packages/gomdown-helper.v0.0.16.chrome.zip index 97ce5b8..aa0a7c2 100644 Binary files a/packages/gomdown-helper.v0.0.16.chrome.zip and b/packages/gomdown-helper.v0.0.16.chrome.zip differ diff --git a/src/content/index.ts b/src/content/index.ts index 011a271..5fa6252 100644 --- a/src/content/index.ts +++ b/src/content/index.ts @@ -1,8 +1,10 @@ import browser from 'webextension-polyfill' import { isLikelyDownloadUrl, normalizeUrl } from '../lib/downloadIntent' +import { getSettings } from '../lib/settings' const CAPTURE_TTL_MS = 8000 const captureInFlight = new Map() +let extensionEnabled = false function pruneCaptureInFlight(): void { const now = Date.now() @@ -12,6 +14,7 @@ function pruneCaptureInFlight(): void { } async function sendCapture(url: string, referer: string): Promise { + if (!extensionEnabled) return false const normalized = normalizeUrl(url, window.location.href) if (!normalized) return false @@ -46,6 +49,7 @@ function shouldIgnoreHotkey(event: MouseEvent | KeyboardEvent): boolean { } async function interceptAnchorEvent(event: MouseEvent): Promise { + if (!extensionEnabled) return if (event.defaultPrevented) return if (shouldIgnoreHotkey(event)) return @@ -61,6 +65,7 @@ async function interceptAnchorEvent(event: MouseEvent): Promise { } function interceptMouseLike(event: MouseEvent): void { + if (!extensionEnabled) return const anchor = findAnchor(event.target) if (!anchor) return const href = anchor.href || '' @@ -89,6 +94,7 @@ document.addEventListener('click', (event: MouseEvent) => { }, true) document.addEventListener('keydown', (event: KeyboardEvent) => { + if (!extensionEnabled) return if (event.key !== 'Enter') return if (event.defaultPrevented) return if (shouldIgnoreHotkey(event)) return @@ -114,7 +120,7 @@ function installProgrammaticInterceptors(): void { const originalOpen = window.open.bind(window) window.open = function gomdownInterceptOpen(url?: string | URL, target?: string, features?: string): Window | null { const raw = String(url || '').trim() - if (raw && isLikelyDownloadUrl(raw, window.location.href)) { + if (extensionEnabled && raw && isLikelyDownloadUrl(raw, window.location.href)) { void sendCapture(raw, window.location.href) return null } @@ -128,7 +134,7 @@ function installProgrammaticInterceptors(): void { const originalAnchorClick = HTMLAnchorElement.prototype.click HTMLAnchorElement.prototype.click = function gomdownInterceptAnchorClick(): void { const href = this.href || this.getAttribute('href') || '' - if (href && isLikelyDownloadUrl(href, window.location.href)) { + if (extensionEnabled && href && isLikelyDownloadUrl(href, window.location.href)) { void sendCapture(href, document.referrer || window.location.href) return } @@ -196,6 +202,10 @@ function removeYoutubeOverlay(): void { } function ensureYoutubeOverlay(): void { + if (!extensionEnabled) { + removeYoutubeOverlay() + return + } if (window.top !== window.self) return if (!isYoutubeWatchPage(window.location.href)) { removeYoutubeOverlay() @@ -283,6 +293,15 @@ watchYoutubeRouteChanges() let mediaToastRoot: HTMLDivElement | null = null let mediaToastTimer: number | null = null +function hideMediaCapturedToast(): void { + if (!mediaToastRoot) return + mediaToastRoot.style.display = 'none' + if (mediaToastTimer !== null) { + window.clearTimeout(mediaToastTimer) + mediaToastTimer = null + } +} + function ensureMediaToastRoot(): HTMLDivElement { if (mediaToastRoot) return mediaToastRoot const root = document.createElement('div') @@ -308,6 +327,7 @@ function ensureMediaToastRoot(): HTMLDivElement { } function showMediaCapturedToast(payload: { kind?: string; url?: string; suggestedOut?: string }): void { + if (!extensionEnabled) return const root = ensureMediaToastRoot() const kind = String(payload?.kind || 'media').toUpperCase() const out = String(payload?.suggestedOut || '').trim() @@ -332,3 +352,33 @@ browser.runtime.onMessage.addListener((message: any) => { }) } }) + +async function syncExtensionEnabled(): Promise { + try { + const settings = await getSettings() + extensionEnabled = Boolean(settings.extensionStatus) + } catch { + extensionEnabled = false + } + + if (!extensionEnabled) { + removeYoutubeOverlay() + hideMediaCapturedToast() + } else { + ensureYoutubeOverlay() + } +} + +void syncExtensionEnabled() + +browser.storage.onChanged.addListener((changes, areaName) => { + if (areaName !== 'sync') return + if (!changes.extensionStatus) return + extensionEnabled = Boolean(changes.extensionStatus.newValue) + if (!extensionEnabled) { + removeYoutubeOverlay() + hideMediaCapturedToast() + return + } + ensureYoutubeOverlay() +}) diff --git a/src/popup/main.tsx b/src/popup/main.tsx index 1e2a58e..affe060 100644 --- a/src/popup/main.tsx +++ b/src/popup/main.tsx @@ -111,7 +111,18 @@ function App(): JSX.Element { return (
-

Gomdown Helper

+
+

Gomdown Helper

+ +
@@ -132,17 +143,6 @@ function App(): JSX.Element { />
- -