A Safari Web Extension that adds "Add to playlist" rows to YouTube's video ⋮ menu, saving each video as a bookmark in a chosen DEVONthink group.
- One shared codebase for macOS Safari (v1 focus) and iOS/iPadOS (later).
- On macOS: saves silently via AppleScript into DEVONthink (no app switch).
- On iOS (and as a macOS fallback): saves via the
x-devonthink://URL scheme. - Configurable playlists (each = one DEVONthink group) + optional hiding of YouTube's native "Save to Watch later" item.
Work in progress. The DEVONthink save layer is verified on macOS — both the
AppleScript path and the x-devonthink:// URL scheme create bookmarks correctly.
The Safari packaging + in-browser flow is not yet built/tested (requires
Xcode; see below). YouTube DOM selectors will likely need tuning against the live
site.
extension/ ← the web-extension source (author here)
manifest.json
background/service-worker.js
content/inject.js, inject.css
options/options.html, options.js, options.css
lib/store.js, devonthink.js
native/
SafariWebExtensionHandler.swift ← paste into the generated Xcode target
The web-extension source lives in extension/. Wrap it in an Xcode app + Safari
extension target with Apple's converter:
cd "/Users/andyjohansson/Dev/YouTube Playlist"
xcrun safari-web-extension-converter extension/ \
--project-location ./xcode \
--app-name "YouTube Playlist Saver" \
--bundle-identifier com.example.YouTubePlaylistSaver \
--macos-only # drop this later to also generate the iOS targetThen in the generated Xcode project:
- Native handler — replace the generated
SafariWebExtensionHandler.swift(in the extension target) withnative/SafariWebExtensionHandler.swift. - Entitlement — in the extension target's
.entitlements, add:com.apple.security.automation.apple-events=YES. - Info.plist — in the extension target, add
NSAppleEventsUsageDescription= "Saves YouTube bookmarks to DEVONthink." - Bundle id — set
NATIVE_APP_IDinextension/background/service-worker.jsto match the container app's bundle identifier used above. - Build & run the app target (⌘R).
- Safari → Settings → Advanced → check Show features for web developers.
- Safari → Develop → Allow Unsigned Extensions (needed each Safari launch for local, unsigned dev builds).
- Safari → Settings → Extensions → enable YouTube Playlist Saver and, when prompted, allow it to access youtube.com.
- On the first save, macOS prompts to let the extension control DEVONthink — allow it. (If denied/blocked, saves fall back to the URL scheme automatically.)
Open the extension's options page (Safari → Settings → Extensions → YouTube Playlist Saver → Preferences, or via the extension action):
- In DEVONthink, right-click a group → Copy Item Link
(
x-devonthink-item://<UUID>). - In options, enter a name and paste the link → Add playlist. Leave the link empty to save into DEVONthink's global inbox.
- Optionally toggle Hide "Save to Watch later" (off by default).
- Add a playlist pointing at a real DEVONthink group.
- On youtube.com, open a video's ⋮ menu → a "Spellistor" section with your playlist row appears at the top. Click it.
- Confirm a bookmark to the correct video URL lands in that DEVONthink group.
- Silent (native) path = no app switch.
- Fallback path = a brief flash to DEVONthink via the URL scheme.
- Toggle Hide "Save to Watch later" → confirm the native item hides/returns.
- Repeat from a feed thumbnail and from a
/watchpage.
- YouTube DOM: the ⋮ popup is a shared, reused element; selectors in
content/inject.js(ytd-menu-popup-renderer,#items, the video-container tags) may need tuning as YouTube changes markup. Fallback idea if it gets too brittle: inject a button into the thumbnail hover overlay instead. - Watch-later hiding matches by localized label text
(
WATCH_LATER_LABELSininject.js); add locales there if needed. - Sandboxed Apple Events: if the extension sandbox blocks AppleScript, the
JS falls back to the
x-devonthink://URL scheme (functional, brief app switch).
- iOS target + code signing (paid Apple Developer account for stable installs).
- Obsidian
.mdappend as an alternate playlist target type. - Native handler enumerating DEVONthink groups so the options page offers a dropdown instead of pasting item links.