Skip to content

migrated to Chrome Manifest V3 - #398

Open
neo37 wants to merge 18 commits into
deathau:mainfrom
neo37:main
Open

migrated to Chrome Manifest V3#398
neo37 wants to merge 18 commits into
deathau:mainfrom
neo37:main

Conversation

@neo37

@neo37 neo37 commented May 28, 2026

Copy link
Copy Markdown

Core problem

The extension was migrated to Chrome Manifest V3, which replaces the background page with a Service Worker. SWs have no document, no
URL.createObjectURL, and in this environment DOMParser was also inaccessible — breaking virtually every key feature.


What was done today

Service Worker compatibility

  • Replaced all URL.createObjectURL / URL.revokeObjectURL calls with data URLs (encodeURIComponent for text, arrayBuffer + btoa for blobs)
  • Replaced the UUID trick via blob URL with crypto.randomUUID()
  • Added self.window = self polyfill before importScripts so Turndown's window check doesn't fail

Turndown / HTML parsing in SW

  • The root cause: TurndownService needs document/DOMParser to parse HTML strings — neither exists in the SW
  • Multiple attempts to patch turndown.js (fallbacks, typeof DOMParser checks) — all failed because DOMParser itself wasn't accessible even as a
    bare global
  • Final solution: inject turndown.js, turndown-plugin-gfm.js, and a new convert-article.js into the tab page via executeScript, parse the HTML
    with new DOMParser() there (page context always has it), and pass the resulting DOM node to TurndownService — bypassing the internal
    htmlParser() entirely
  • Fixed TurndownService.prototype.defaultEscape not existing in the tab isolated world, causing self.escape is not a function and a silent
    fallback to the broken SW path

PDF export

  • Single tab: replaced CDP Page.printToPDF with window.print() — opens the browser print dialog, no black background from dark-mode pages
  • Batch tabs: restored CDP but with printBackground: false — saves directly to Downloads without dialog, no black background

Batch Markdown save ("All → Markdown")

  • Changed forEach (fire-and-forget) to a sequential for...of with await — previously SW went to sleep before all downloads completed, so only
    the first tab was actually saved
  • Added filtering to skip chrome://, chrome-extension://, about: tabs
  • Added saveAs: false for batch mode so Chrome doesn't block downloads after the first dialog

Download filename fix

  • generateValidFileName now applied to title before passing to downloads.download — prevents Invalid filename errors from user-edited titles or
    special characters
  • Object.entries(imageList || {}) — guard against null imageList

Debug logging

  • dbgLog() — persistent ring buffer (200 lines) stored in chrome.storage.local._debugLog
  • "Show debug log" button in popup downloads markdownload-debug.txt to the Downloads folder
  • Key conversion steps are logged (inject start, success/failure, markdown length)

Build User and others added 16 commits May 28, 2026 19:19
…ped folders

New buttons added to popup alongside existing MarkDownload UI:
- Open all links on current page in new tabs (3 s delay between each)
- Save current tab or all tabs as HTML, PNG, PDF, or Markdown
- PDF export uses Chrome DevTools Protocol (Page.printToPDF) — no print dialog
- Screenshots and all downloads handled by background page (no popup-close issues)
- Each batch is saved into page-saver/YYYY-MM-DD_HH-mm/ inside Downloads

All original MarkDownload features by @deathau remain unchanged.
Permissions added: tabs, debugger
…abels, update README with usage guide and authors
- Move Readability/DOMParser processing to content script context (get-article.js)
  to fix 'DOMParser is not defined' error in Chrome MV3 service workers
- Also fix notify() clip handler: use getArticleFromContent (tab-injected) instead
  of getArticleFromDom (which used DOMParser in the SW)
- Remove Readability.js from service-worker.js importScripts (no longer needed in SW)
- Add 'Crawl entire domain' button: recursively opens all same-domain links
  with URL normalization and deduplication, plus a Stop button
- Update README: document primary use case (wiki/docs archiving) and new feature
…lThis, SW-compatible), guard chrome:// URLs in popup
Build User
```
refactor: replace object URLs with data URLs and crypto.randomUUID()
```

- `414,1048`: `URL.createObjectURL(blob)` → data URLs (`btoa` / `encodeURIComponent`)
- `493`: remove `URL.revokeObjectURL()` (no longer needed)
- `691`: `URL.createObjectURL(new Blob([]))` → `crypto.randomUUID()`
- `710`: `document.createElement` → `dom.createElement` (DOMParser document)
…lenames

- Service worker lacks `window`, causing turndown to use slow fallback via `document.implementation`
- Added `self.window = self` before imports to enable native DOMParser
- Sanitize title with `generateValidFileName()`, fallback to untitled if empty
  turndown.js — fallback
…т быть undefined, хотя глобальная DOMParser доступна. Теперь во всех трёх

  местах (canParseHTMLNatively, HTMLParser, fallback parseFromString) используется цепочка: root.DOMParser || (typeof DOMParser !== undefined ?
   DOMParser : null)
…rse the HTML string. Well run the conversion via executeScript directly in + fix pdf
…e(...) contains raw unicode characters instead of \uXXXX - Chrome cant do them
… logging

  - Run Turndown conversion via executeScript in the tab context (where
    document/DOMParser are always available) instead of the service worker,
    which has no HTML parser. TurndownService now receives a pre-parsed DOM
    node, bypassing its internal htmlParser() entirely.

  - Fix TurndownService.prototype.defaultEscape not being set in the tab
    isolated world (it was only set in the SW via background.js), causing
    "self.escape is not a function" and silent fallback to broken SW path.

  - Fix batch "All → Markdown": force saveAs=false so Chrome does not block
    downloads after the first save dialog; all tabs now save automatically.

  - Fix PDF export: single tab opens print dialog (no black background);
    batch uses CDP Page.printToPDF with printBackground=false to avoid
    dark-mode black pages and save directly to downloads.

  - Add persistent debug log ring buffer (dbgLog → chrome.storage.local)
    with "Show debug log" button in popup that downloads markdownload-debug.txt.
nsureScripts → getArticle → convertToMarkdown → download
@neo37

neo37 commented May 28, 2026

Copy link
Copy Markdown
Author

i just found the branch that was there with v3...

neo37

This comment was marked as spam.

@neo37

neo37 commented May 28, 2026

Copy link
Copy Markdown
Author

new buttons: save all
if u press new btn "open all links" - after ypu can press " save all of them "

@neo37
neo37 force-pushed the main branch 3 times, most recently from dea06c7 to 3a0910a Compare May 28, 2026 20:42
Build User and others added 2 commits May 28, 2026 23:43
@neo37

neo37 commented May 29, 2026

Copy link
Copy Markdown
Author

maan

Y-T04KA added a commit to Y-T04KA/markdownload that referenced this pull request Jul 21, 2026
Scopes the migration to the existing feature set, adopting the
service-worker-can't-parse-HTML workaround from upstream PR deathau#398
(inject Turndown/Readability into the tab context) while dropping
that PR's unrelated Page Saver feature and debugger permission.
Y-T04KA added a commit to Y-T04KA/markdownload that referenced this pull request Jul 21, 2026
convertArticleToMarkdown now injects turndown.js + turndown-plugin-gfm.js
+ convert-article.js into the tab and runs the conversion there,
instead of the service worker (which has no DOMParser for Turndown's
internal HTML-string parsing to use). The old SW-side turndown()
wrapper and its private helpers are deleted rather than kept as dead
fallback code, since every call site now has a tabId.

Also fixes a bug inherited from the reference implementation this
migration is based on (upstream PR deathau#398): the 'copy markdown link'
context menu item called the SW-side turndown() on a synthesized
<a> tag, which would still fail with no DOMParser. Since the input
is already known plain text + URL, it now builds the markdown link
directly instead.

The popup-triggered clip-to-preview flow (notify's "clip" handler)
should now work end-to-end. Context-menu/keyboard-shortcut-triggered
actions (download, copy-*) still don't work — they call ensureScripts,
which still uses the removed browser.tabs.executeScript API. Fixed in
the next task.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant