Various AT Protocol integrations with obsidian
at main 156 lines 4.1 kB view raw
1import { Notice, Plugin, WorkspaceLeaf } from "obsidian"; 2import { DEFAULT_SETTINGS, AtProtoSettings, SettingTab } from "./settings"; 3import { BookmarksView, VIEW_TYPE_ATMOSPHERE_BOOKMARKS } from "./views/bookmarks"; 4import { publishFileAsDocument } from "./commands/publishDocument"; 5import { StandardFeedView, VIEW_ATMOSPHERE_STANDARD_FEED } from "views/standardfeed"; 6import { ATClient } from "lib/client"; 7import { Clipper } from "lib/clipper"; 8import { registerIcons } from "./icons"; 9 10export default class AtmospherePlugin extends Plugin { 11 settings: AtProtoSettings = DEFAULT_SETTINGS; 12 client: ATClient; 13 clipper: Clipper; 14 15 async onload() { 16 registerIcons(); 17 await this.loadSettings(); 18 this.client = new ATClient(); 19 this.clipper = new Clipper(this); 20 21 this.registerObsidianProtocolHandler('atmosphere-oauth', (params) => { 22 try { 23 const urlParams = new URLSearchParams(); 24 for (const [key, value] of Object.entries(params)) { 25 if (value) { 26 urlParams.set(key, String(value)); 27 } 28 } 29 this.client.handleOAuthCallback(urlParams); 30 new Notice('Authentication completed! Processing...'); 31 } catch (error) { 32 console.error('Error handling OAuth callback:', error); 33 new Notice('Authentication error. Please try again.'); 34 } 35 }); 36 37 this.registerView(VIEW_TYPE_ATMOSPHERE_BOOKMARKS, (leaf) => { 38 return new BookmarksView(leaf, this); 39 }); 40 41 this.registerView(VIEW_ATMOSPHERE_STANDARD_FEED, (leaf) => { 42 return new StandardFeedView(leaf, this); 43 }); 44 45 this.addRibbonIcon("layers", "Atmosphere bookmarks", () => { 46 void this.activateView(VIEW_TYPE_ATMOSPHERE_BOOKMARKS); 47 }); 48 49 this.addRibbonIcon("rss", "Atmosphere feed", () => { 50 void this.activateView(VIEW_ATMOSPHERE_STANDARD_FEED); 51 }); 52 53 this.addCommand({ 54 id: "open-bookmarks", 55 name: "Open bookmarks", 56 callback: () => { void this.activateView(VIEW_TYPE_ATMOSPHERE_BOOKMARKS); }, 57 }); 58 59 this.addCommand({ 60 id: "open-feed", 61 name: "Open feed", 62 callback: () => { void this.activateView(VIEW_ATMOSPHERE_STANDARD_FEED); }, 63 }); 64 65 this.addCommand({ 66 id: "publish-note", 67 name: "Publish note", 68 editorCheckCallback: (checking: boolean,) => { 69 const file = this.app.workspace.getActiveFile(); 70 71 if (file) { 72 if (!checking) { 73 void publishFileAsDocument(this) 74 } 75 76 return true 77 } 78 79 return false; 80 }, 81 }); 82 83 this.addSettingTab(new SettingTab(this.app, this)); 84 } 85 86 async checkAuth() { 87 if (this.client.loggedIn) { 88 return true; 89 } 90 if (this.settings.did) { 91 try { 92 await this.client.restoreSession(this.settings.did); 93 return true 94 } catch (e) { 95 console.error("Failed to restore session:", e); 96 this.settings.did = undefined; 97 await this.saveSettings(); 98 new Notice("Session expired. Please login by opening settings"); 99 return false; 100 } 101 } 102 new Notice("Please log in by opening settings"); 103 return false; 104 } 105 106 async activateView(v: string) { 107 if (!await this.checkAuth()) { 108 return; 109 } 110 111 const { workspace } = this.app; 112 113 let leaf: WorkspaceLeaf | null = null; 114 const leaves = workspace.getLeavesOfType(v); 115 116 if (leaves.length > 0) { 117 // A leaf with our view already exists, use that 118 leaf = leaves[0] as WorkspaceLeaf; 119 void workspace.revealLeaf(leaf); 120 return; 121 } 122 123 // Our view could not be found in the workspace, create a new leaf 124 leaf = workspace.getMostRecentLeaf() 125 await leaf?.setViewState({ type: v, active: true }); 126 127 // "Reveal" the leaf in case it is in a collapsed sidebar 128 if (leaf) { 129 void workspace.revealLeaf(leaf); 130 } 131 } 132 133 async loadSettings() { 134 const saved = await this.loadData() as Partial<AtProtoSettings>; 135 this.settings = Object.assign({}, DEFAULT_SETTINGS, saved, { 136 bookmarks: { 137 ...DEFAULT_SETTINGS.bookmarks, 138 ...saved?.bookmarks, 139 enabledSources: { 140 ...DEFAULT_SETTINGS.bookmarks.enabledSources, 141 ...saved?.bookmarks?.enabledSources, 142 }, 143 }, 144 publish: { 145 ...DEFAULT_SETTINGS.publish, 146 ...saved?.publish, 147 }, 148 }); 149 } 150 151 async saveSettings() { 152 await this.saveData(this.settings); 153 } 154 155 onunload() { } 156}