From b6b8c71350dfdfbbf1447ce42a89606dc4fff1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Deme?= Date: Mon, 18 Oct 2021 03:03:00 +0200 Subject: [PATCH] initial version - v0.1.0 --- README.md | 62 +++++----------- main.ts | 194 ++++++++++++++++++++++++++++++++------------------ manifest.json | 12 ++-- styles.css | 4 -- versions.json | 3 +- 5 files changed, 148 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index 9e4fe9c..04add08 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,29 @@ -## Obsidian Sample Plugin +# Obsidian Link Archive -This is a sample plugin for Obsidian (https://obsidian.md). +This plugin archives links in your note so they're available to you even if the original site goes down or gets removed. -This project uses Typescript to provide type checking and documentation. -The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does. +## How it works -**Note:** The Obsidian API is still in early alpha and is subject to change at any time! +Upon pressing the "Archive Links" button in the ribbon/left sidebar, the plugin: -This sample plugin demonstrates some of the basic functionality the plugin API can do. -- Changes the default font color to red using `styles.css`. -- Adds a ribbon icon, which shows a Notice when clicked. -- Adds a command "Open Sample Modal" which opens a Modal. -- Adds a plugin setting tab to the settings page. -- Registers a global click event and output 'click' to the console. -- Registers a global interval which logs 'setInterval' to the console. +1. looks up every external link in the current note, +2. sumbits each of them to https://archive.org, +3. as soon as they are saved, it embeds an `(Archived)` link after the regular link in your note. -### First time developing plugins? +The plugin will attempt not to recreate archive links for already-archived links (and the archive links themselves) - but this relies on not modifying the formatting of the archive links. -Quick starting guide for new plugin devs: +## Installation -- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it). -- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder. -- Install NodeJS, then run `npm i` in the command line under your repo folder. -- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`. -- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`. -- Reload Obsidian to load the new version of your plugin. -- Enable plugin in settings window. -- For updates to the Obsidian API run `npm update` in the command line under your repo folder. +In Obsidian, navigate to **Settings > Community Plugins**, turn off **Safe mode** if you haven't yet, then press the **Browse** button - you should be able to find it in the list there. -### Releasing new releases +Alternatively, clone/download this repository, and copy its contents to you vault's `.obsidian/plugins/obsidian-link-archive` folder and then enable it under **Settings > Community Plugins** (the note about disabling above applies here as well). +## Changelog -- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release. -- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible. -- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases -- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. -- Publish the release. +**v0.1.0** -### Adding your plugin to the community plugin list +Initial release. -- Publish an initial version. -- Make sure you have a `README.md` file in the root of your repo. -- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin. +## Future plans -### How to use - -- Clone this repo. -- `npm i` or `yarn` to install dependencies -- `npm run dev` to start compilation in watch mode. - -### Manually installing the plugin - -- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`. - -### API Documentation - -See https://github.com/obsidianmd/obsidian-api +- Support for other archive providers +- Custom formatting for archive links \ No newline at end of file diff --git a/main.ts b/main.ts index 36e175e..34e314b 100644 --- a/main.ts +++ b/main.ts @@ -1,60 +1,111 @@ -import { App, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian'; +import { Console } from 'console'; +import { App, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, request, Setting } from 'obsidian'; +import { Url } from 'url'; + +export const enum ArchiveOptions { + wayback, + archiveis, + both +} -interface MyPluginSettings { - mySetting: string; +interface LinkArchivePluginSettings { + archiveOption: ArchiveOptions; } -const DEFAULT_SETTINGS: MyPluginSettings = { - mySetting: 'default' +const DEFAULT_SETTINGS: LinkArchivePluginSettings = { + archiveOption: ArchiveOptions.archiveis } -export default class MyPlugin extends Plugin { - settings: MyPluginSettings; +const urlRegex =/(\b(https?|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; + +const waybackUrl = 'https://web.archive.org/web/'; +const waybackSaveUrl = 'https://web.archive.org/save/'; + +const archiveText = '[(Archived)]'; + +export default class ObsidianLinkArchivePlugin extends Plugin { + settings: LinkArchivePluginSettings; async onload() { - console.log('loading plugin'); + console.log('Loading Link Archive plugin...'); await this.loadSettings(); - this.addRibbonIcon('dice', 'Sample Plugin', () => { - new Notice('This is a notice!'); - }); + this.addRibbonIcon('restore-file-glyph', 'Archive Links', async () => { + + // test save + //new Notice('Archive option: ' + this.settings.archiveOption.toString()); - this.addStatusBarItem().setText('Status Bar Text'); - - this.addCommand({ - id: 'open-sample-modal', - name: 'Open Sample Modal', - // callback: () => { - // console.log('Simple Callback'); - // }, - checkCallback: (checking: boolean) => { - let leaf = this.app.workspace.activeLeaf; - if (leaf) { - if (!checking) { - new SampleModal(this.app).open(); - } - return true; - } - return false; - } - }); + const view = this.app.workspace.getActiveViewOfType(MarkdownView); - this.addSettingTab(new SampleSettingTab(this.app, this)); + if(view) { + const viewData = view.getViewData(); - this.registerCodeMirror((cm: CodeMirror.Editor) => { - console.log('codemirror', cm); - }); + let reverseArray: Array<[string, number]> = []; + + let linkArray; + while ((linkArray = urlRegex.exec(viewData)) !== null) { + console.log(`Found ${linkArray[0]}. Next starts at ${urlRegex.lastIndex}.`); + + if(linkArray[0].startsWith(waybackUrl)) continue; + + if(viewData.substring(urlRegex.lastIndex, urlRegex.lastIndex + 14).contains(archiveText)) continue; + + reverseArray.unshift([linkArray[0], urlRegex.lastIndex]); + } + + console.log(reverseArray); - this.registerDomEvent(document, 'click', (evt: MouseEvent) => { - console.log('click', evt); + if(reverseArray.length == 0) { + new Notice('No (new) links to archive.'); + return; + } + + new Notice(`Preparing to archive ${reverseArray.length} link(s), this might take a while - please be patient...`, 10 * 1000); + + for (const tuple of reverseArray) { + let currentLink = tuple[0]; + let saveLink = `${waybackSaveUrl}${currentLink}`; + let archiveLink = ` ${archiveText}(${waybackUrl}${currentLink})`; + let offset = view.editor.offsetToPos(tuple[1]); + let message = `Successfully archived ${currentLink}!`; + + await request({ + url: saveLink + }); + + view.editor.replaceRange(archiveLink, offset); + console.log(message); + new Notice(message); + } + + // reverseArray.forEach(async function (tuple) { + // let currentLink = tuple[0]; + // let saveLink = `${waybackSaveUrl}${currentLink}`; + // let archiveLink = ` ${archiveText}(${waybackUrl}${currentLink})`; + // let offset = view.editor.offsetToPos(tuple[1]); + // let message = `Successfully archived ${currentLink}!`; + + // request({ + // url: saveLink + // }).then(function(pageRes) { + // view.editor.replaceRange(archiveLink, offset); + // console.log(message); + // new Notice(message); + // }); + // }); + + new Notice('Link archiving done!'); + } else { + new Notice('Link archiving only works if you have a note open.'); + } }); - this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000)); + this.addSettingTab(new LinkArchiveSettingTab(this.app, this)); } onunload() { - console.log('unloading plugin'); + console.log('Unloading Link Archive plugin...'); } async loadSettings() { @@ -66,47 +117,50 @@ export default class MyPlugin extends Plugin { } } -class SampleModal extends Modal { - constructor(app: App) { - super(app); - } - - onOpen() { - let {contentEl} = this; - contentEl.setText('Woah!'); - } - - onClose() { - let {contentEl} = this; - contentEl.empty(); - } -} - -class SampleSettingTab extends PluginSettingTab { - plugin: MyPlugin; +class LinkArchiveSettingTab extends PluginSettingTab { + plugin: ObsidianLinkArchivePlugin; - constructor(app: App, plugin: MyPlugin) { + constructor(app: App, plugin: ObsidianLinkArchivePlugin) { super(app, plugin); this.plugin = plugin; } display(): void { + const plugin: ObsidianLinkArchivePlugin = (this as any).plugin; + let {containerEl} = this; containerEl.empty(); - containerEl.createEl('h2', {text: 'Settings for my awesome plugin.'}); - - new Setting(containerEl) - .setName('Setting #1') - .setDesc('It\'s a secret') - .addText(text => text - .setPlaceholder('Enter your secret') - .setValue(this.plugin.settings.mySetting) - .onChange(async (value) => { - console.log('Secret: ' + value); - this.plugin.settings.mySetting = value; - await this.plugin.saveSettings(); - })); + // containerEl.createEl('h2', {text: 'Archive Settings'}); + + // new Setting(containerEl) + // .setName('Archive Provider') + // .setDesc('Choose a provider for the link archive') + // .addDropdown((dropdown) => { + // const options: Record = { + // 0: "Internet Archive", + // 1: "archive.is", + // 2: "Both" + // }; + + // dropdown + // .addOptions(options) + // .setValue(plugin.settings.archiveOption.toString()) + // .onChange(async (value) => { + // console.log('Archive option: ' + value); + // plugin.settings.archiveOption = +value; + // await plugin.saveSettings(); + // this.display(); + // }) + // }); + + containerEl.createEl('h2', {text: 'About Link Archive'}); + + containerEl.createEl('p', {text: 'This plugin archives links in your note so they\'re available to you even if the original site goes down or gets removed.'}); + + containerEl.createEl('a', {text: 'Open GitHub repository', href: 'https://github.com/tomzorz/obsidian-link-archive'}); + + // TODO github support and ko-fi } } diff --git a/manifest.json b/manifest.json index 4ca4889..5f8425f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { - "id": "obsidian-sample-plugin", - "name": "Sample Plugin", - "version": "1.0.1", + "id": "obsidian-link-archive", + "name": "Link Archive", + "version": "0.1.0", "minAppVersion": "0.9.12", - "description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.", - "author": "Obsidian", - "authorUrl": "https://obsidian.md/about", + "description": "This plugin archives links in your note so they're available to you even if the original site goes down or gets removed.", + "author": "Tamás Deme - @tomzorz_", + "authorUrl": "https://tomzorz.me", "isDesktopOnly": false } diff --git a/styles.css b/styles.css index cfd0fd7..e69de29 100644 --- a/styles.css +++ b/styles.css @@ -1,4 +0,0 @@ -/* Sets all the text color to red! */ -body { - color: red; -} diff --git a/versions.json b/versions.json index ba14785..934b633 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,3 @@ { - "1.0.1": "0.9.12", - "1.0.0": "0.9.7" + "0.1.0": "0.9.12" }