├── .envrc ├── src ├── vite-env.d.ts ├── popup.ts ├── background.ts ├── popup.html ├── popup.css └── manifest.json ├── public ├── icon │ ├── 128.png │ ├── 16.png │ ├── 256.png │ ├── 32.png │ ├── 48.png │ ├── 512.png │ └── 96.png └── icon.svg ├── updates.json ├── .gitignore ├── tsconfig.json ├── vite.config.ts ├── package.json ├── flake.lock ├── .github └── FUNDING.yml ├── flake.nix ├── LICENSE └── README.md /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /public/icon/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhumantsar/slurp-extension/HEAD/public/icon/128.png -------------------------------------------------------------------------------- /public/icon/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhumantsar/slurp-extension/HEAD/public/icon/16.png -------------------------------------------------------------------------------- /public/icon/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhumantsar/slurp-extension/HEAD/public/icon/256.png -------------------------------------------------------------------------------- /public/icon/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhumantsar/slurp-extension/HEAD/public/icon/32.png -------------------------------------------------------------------------------- /public/icon/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhumantsar/slurp-extension/HEAD/public/icon/48.png -------------------------------------------------------------------------------- /public/icon/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhumantsar/slurp-extension/HEAD/public/icon/512.png -------------------------------------------------------------------------------- /public/icon/96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inhumantsar/slurp-extension/HEAD/public/icon/96.png -------------------------------------------------------------------------------- /src/popup.ts: -------------------------------------------------------------------------------- 1 | import browser from "webextension-polyfill"; 2 | 3 | console.log("Hello from the popup!", { id: browser.runtime.id }); 4 | -------------------------------------------------------------------------------- /src/background.ts: -------------------------------------------------------------------------------- 1 | import browser from "webextension-polyfill"; 2 | 3 | const slurp = (url: string) => { 4 | const slurpUrl = `obsidian://slurp?url=${url}`; 5 | browser.tabs.create({ url: slurpUrl }); 6 | }; 7 | 8 | browser.action.onClicked.addListener((tab) => { 9 | if (tab.url && tab.url.startsWith("http")) slurp(tab.url); 10 | }); -------------------------------------------------------------------------------- /updates.json: -------------------------------------------------------------------------------- 1 | { 2 | "addons": { 3 | "{fd6b045c-f3ea-4fd1-9967-cfc7f7c366d2}": { 4 | "updates": [ 5 | { 6 | "version": "1.0.0", 7 | "update_link": "https://addons.mozilla.org/firefox/downloads/file/4262151/709cda0d800c4eacbd85-1.0.0.xpi" 8 | } 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # Config files 27 | .webextrc 28 | .webextrc.* 29 | 30 | *.zip 31 | .direnv/ -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /src/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Popup 10 | 11 | 12 | 13 |

vite-plugin-web-extension

14 |

Template: vanilla-ts

15 | 16 | 17 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import webExtension, { readJsonFile } from "vite-plugin-web-extension"; 3 | 4 | function generateManifest() { 5 | const manifest = readJsonFile("src/manifest.json"); 6 | const pkg = readJsonFile("package.json"); 7 | return { 8 | name: pkg.name, 9 | description: pkg.description, 10 | version: pkg.version, 11 | ...manifest, 12 | }; 13 | } 14 | 15 | export default defineConfig({ 16 | plugins: [ 17 | webExtension({ 18 | manifest: generateManifest, 19 | watchFilePaths: ["package.json", "manifest.json"], 20 | browser: process.env.TARGET || "chrome" 21 | }), 22 | ], 23 | }); 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slurp-extension", 3 | "private": true, 4 | "version": "1.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "compile": "tsc --noEmit", 8 | "dev": "vite", 9 | "build-firefox": "cross-env TARGET=firefox vite build && cd dist && zip -r ../firefox.zip ./*", 10 | "build-chrome": "cross-env TARGET=chrome vite build && cd dist && zip -r ../chrome.zip ./*" 11 | }, 12 | "devDependencies": { 13 | "@types/webextension-polyfill": "^0.10.0", 14 | "cross-env": "^7.0.3", 15 | "typescript": "^5.3.2", 16 | "vite": "^5.0.0", 17 | "vite-plugin-web-extension": "^4.0.0", 18 | "webextension-polyfill": "^0.10.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1712439257, 6 | "narHash": "sha256-aSpiNepFOMk9932HOax0XwNxbA38GOUVOiXfUVPOrck=", 7 | "owner": "nixos", 8 | "repo": "nixpkgs", 9 | "rev": "ff0dbd94265ac470dda06a657d5fe49de93b4599", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nixos", 14 | "ref": "nixos-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs" 22 | } 23 | } 24 | }, 25 | "root": "root", 26 | "version": 7 27 | } 28 | -------------------------------------------------------------------------------- /src/popup.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 300px; 3 | height: 400px; 4 | padding: 0; 5 | margin: 0; 6 | } 7 | 8 | body { 9 | display: flex; 10 | flex-direction: column; 11 | gap: 16px; 12 | align-items: center; 13 | justify-content: center; 14 | background-color: rgb(36, 36, 36); 15 | } 16 | 17 | img { 18 | width: 200px; 19 | height: 200px; 20 | } 21 | 22 | h1 { 23 | font-size: 18px; 24 | color: white; 25 | font-weight: bold; 26 | margin: 0; 27 | } 28 | 29 | p { 30 | color: white; 31 | opacity: 0.7; 32 | margin: 0; 33 | } 34 | 35 | 36 | code { 37 | font-size: 12px; 38 | padding: 2px 4px; 39 | background-color: #ffffff24; 40 | border-radius: 2px; 41 | } 42 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: inhumantsar 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A Nix-flake-based Node.js development environment"; 3 | 4 | inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; 5 | 6 | outputs = { self, nixpkgs }: 7 | let 8 | overlays = [ 9 | (final: prev: rec { 10 | nodejs = prev.nodejs_latest; 11 | pnpm = prev.nodePackages.pnpm; 12 | yarn = (prev.yarn.override { inherit nodejs; }); 13 | }) 14 | ]; 15 | supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 16 | forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f { 17 | pkgs = import nixpkgs { inherit overlays system; }; 18 | }); 19 | in 20 | { 21 | devShells = forEachSupportedSystem ({ pkgs }: { 22 | default = pkgs.mkShell { 23 | packages = with pkgs; [ node2nix nodejs pnpm yarn ]; 24 | }; 25 | }); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "{{chrome}}.manifest_version": 3, 3 | "{{firefox}}.manifest_version": 2, 4 | "icons": { 5 | "16": "icon/16.png", 6 | "32": "icon/32.png", 7 | "48": "icon/48.png", 8 | "96": "icon/96.png", 9 | "128": "icon/128.png" 10 | }, 11 | "permissions": ["tabs"], 12 | "{{chrome}}.action": { 13 | "default_title": "Slurp in Obsidian" 14 | }, 15 | "{{firefox}}.browser_action": { 16 | "default_title": "Slurp in Obsidian" 17 | }, 18 | "background": { 19 | "{{chrome}}.service_worker": "src/background.ts", 20 | "{{firefox}}.scripts": ["src/background.ts"] 21 | }, 22 | "browser_specific_settings": { 23 | "gecko_android": { 24 | "update_url": "https://raw.githubusercontent.com/inhumantsar/slurp-extension/main/updates.json" 25 | }, 26 | "gecko": { 27 | "update_url": "https://raw.githubusercontent.com/inhumantsar/slurp-extension/main/updates.json" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Shaun Martin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /public/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 50 | 56 | 61 | 69 | 76 | 83 | 87 | 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slurp Browser Extension 2 | 3 | Provides convenient a one-click method for sending pages to Slurp, the plugin for Obsidian that makes it easy to save web pages as clean, easy-to-read Markdown. 4 | 5 | ## How does it work? 6 | 7 | When you click the Slurp extension button, it will grab the URL from your active tab and invoke Obsidian using its custom URI. For example, if you're looking at an article on Medium that you would like to save and click the button, it will open a new browser tab and point it at a url like `obsidian://slurp?url=https://medium.com/...`. From there, Obsidian will pass that URL to the Slurp plugin. Slurp will then read the page, strip it of irrelevant elements like ads and navbars, then convert it to Markdown and save it to your vault. 8 | 9 | If you don't already have Slurp for Obsidian, [check it out](https://github.com/inhumantsar/slurp). 10 | 11 | ## Installation 12 | 13 | While the Slurp for Obsidian plugin is in the pre-release phase, the extension must be installed manually. Simply download the appropriate package below and open it with your web browser: 14 | 15 | * [Firefox](https://addons.mozilla.org/firefox/downloads/file/4262151/709cda0d800c4eacbd85-1.0.0.xpi) 16 | * Chrome (Soon™️) 17 | 18 | ## Roadmap 19 | 20 | - [ ] Edit content, metadata, and tags prior to slurping 21 | - [ ] View, search, and revisit the original source for slurped pages 22 | - [ ] Get quick access to related slurped pages right in your web browser 23 | 24 | ## Privacy 25 | 26 | No data is sent to any third-parties at any point. The URL is passed directly to your local Obsidian installation and all processing is handled locally. 27 | 28 | ## Development 29 | 30 | This was built with the [Vite Web Extension plugin](https://vite-plugin-web-extension.aklinker1.io/) and NPM. The easiest way to get going while ensuring dependency isolation is to use the included `direnv` configuration. 31 | 32 | ### Requirements 33 | 34 | * Ubuntu and Ubuntu on WSL2 are supported, though it should work on any OS with NodeJS installed. 35 | * NodeJS v21 and NPM v10 -- if you do not already have these, then `direnv` is recommended. See below. 36 | * A modern web browser which supports Manifest v2 or Manifest v3, tested on Chrome v123 and Firefox v124 37 | * [Optional] [direnv](https://direnv.net/) 38 | 39 | ### Clone 40 | 41 | ``` 42 | git clone https://github.com/inhumantsar/slurp-extension 43 | ``` 44 | 45 | ### direnv (optional) 46 | 47 | There is a `direnv` config which can be used to quickly configure a completely isolated local environment. Setting it up requires a few extra steps though. 48 | 49 | 1. Install the [Nix package manager](https://nixos.org/download/#nix-install-linux) 50 | 2. Ensure `flakes` and `nix-command` are enabled, eg: `mkdir -p ~/.local/nix && echo "experimental-features = nix-command flakes" >> nix.conf` 51 | 2. Install `direnv`, adjusting or removing `bin_path` as needed: `curl -sfL https://direnv.net/install.sh | bin_path=~/.local/bin bash` 52 | * [Official installation guide](https://direnv.net/docs/installation.html) 53 | * Note that the official Ubuntu packages are out-of-date and as such, they are *not* recommended. 54 | 3. `direnv` will instruct you to add a line to your `.bashrc`, once that's done, run `direnv allow` from the repository root directory. 55 | 56 | ### Building 57 | 58 | ``` 59 | npm install # not required if using direnv 60 | npm run build-chrome # firefox users can run `build-firefox` instead 61 | ``` 62 | 63 | This will use Vite to package the extension and create a zip file in the repository's root directory containing the extension files. 64 | 65 | ## License 66 | 67 | [MIT](./LICENSE) --------------------------------------------------------------------------------