mirror of
https://github.com/Ellpeck/ObsidianJustSharePlease.git
synced 2024-05-30 14:23:37 +02:00
Compare commits
6 commits
0fa6dff2d6
...
6c781d560c
Author | SHA1 | Date | |
---|---|---|---|
Ell | 6c781d560c | ||
Ell | 07995d2a9a | ||
Ell | 0bb5ae69b0 | ||
Ell | b22540c772 | ||
Ell | 7067957899 | ||
Ell | 0679f3add8 |
|
@ -28,7 +28,7 @@ When sharing a note, its content as well as additional metadata created by the b
|
|||
Due to the fact that note links are generated randomly, it is reasonably difficult for attackers to guess note links and access notes that they're not supposed to. That being said, all notes are still publicly available the same way that YouTube videos set to "Unlisted" are still publicly available: harder to access, but not impossible; not truly private.
|
||||
|
||||
Before being uploaded, notes go through minor preprocessing as part of the plugin, including
|
||||
- stripping frontmatter (optionally, this can be changed in the plugin settinsg),
|
||||
- stripping frontmatter (optionally, this can be changed in the plugin settings),
|
||||
- converting all attachments to `base64` encoding and embedding them in the shared note as HTML.
|
||||
|
||||
Currently, links to other notes are included in your share, but don't actually lead anywhere, and sharing linked notes is not supported yet.
|
||||
|
@ -68,7 +68,7 @@ Lastly, to get your server connected to the plugin, head to its settings and cha
|
|||
## About This Site
|
||||
The official Just Share Please site, [jsp.ellpeck.de](https://jsp.ellpeck.de), is run by Ellpeck, the creator of the plugin. It is hosted on a server in Germany, and connections to and from it are secured using SSL encryption, partly through LetsEncrypt and partly through Cloudflare SSL.
|
||||
|
||||
If you have lost access to your shares due to your settingds file being deleted or due to other reasons, and you want your shares to be deleted, please contact Ell at [me@ellpeck.de](mailto:me@ellpeck.de) or through his [Discord server](https://ellpeck.de/discord).
|
||||
If you have lost access to your shares due to your settings file being deleted or due to other reasons, and you want your shares to be deleted, please contact Ell at [me@ellpeck.de](mailto:me@ellpeck.de) or through his [Discord server](https://ellpeck.de/discord).
|
||||
|
||||
Additionally, the site's source can be found [on GitHub](https://github.com/Ellpeck/ObsidianJustSharePlease/tree/main/server), and for information on privacy and ownership, see the [imprint](https://ellpeck.de/impressum/) and [privacy policy](https://ellpeck.de/privacy/). Ellpeck Games is not responsible for content published through Just Share Please.
|
||||
|
||||
|
|
70
src/main.ts
70
src/main.ts
|
@ -25,7 +25,7 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
|
||||
this.registerEvent(this.app.workspace.on("file-menu", async (m, f) => {
|
||||
if (f instanceof TFile && f.extension == "md") {
|
||||
let shared = this.getSharedItem(f);
|
||||
let shared = this.getSharedItem(f.path);
|
||||
if (!shared) {
|
||||
m.addItem(i => {
|
||||
i.setTitle("Share to JSP");
|
||||
|
@ -51,12 +51,40 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
}));
|
||||
this.registerEvent(this.app.vault.on("rename", (f, p) => {
|
||||
if (f instanceof TFile) {
|
||||
let shared = this.getSharedItem(p);
|
||||
if (shared) {
|
||||
shared.path = f.path;
|
||||
this.refreshAllViews();
|
||||
}
|
||||
}
|
||||
}));
|
||||
this.registerEvent(this.app.vault.on("delete", f => {
|
||||
if (f instanceof TFile) {
|
||||
let shared = this.getSharedItem(f.path);
|
||||
if (shared) {
|
||||
if (this.settings.unshareDeletedFiles) {
|
||||
this.deleteFile(shared, false);
|
||||
} else {
|
||||
this.refreshAllViews();
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
this.registerEvent(this.app.vault.on("modify", f => {
|
||||
if (this.settings.autoUpdateShares && f instanceof TFile) {
|
||||
let shared = this.getSharedItem(f.path);
|
||||
if (shared)
|
||||
this.updateFile(shared, f, false);
|
||||
}
|
||||
}));
|
||||
|
||||
this.addCommand({
|
||||
id: "share",
|
||||
name: "Share current file to JSP",
|
||||
editorCheckCallback: (checking, _, ctx) => {
|
||||
if (!this.getSharedItem(ctx.file)) {
|
||||
if (!this.getSharedItem(ctx.file.path)) {
|
||||
if (!checking)
|
||||
this.shareFile(ctx.file);
|
||||
return true;
|
||||
|
@ -68,7 +96,7 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
id: "copy",
|
||||
name: "Copy current file's JSP link",
|
||||
editorCheckCallback: (checking, _, ctx) => {
|
||||
let shared = this.getSharedItem(ctx.file);
|
||||
let shared = this.getSharedItem(ctx.file.path);
|
||||
if (shared) {
|
||||
if (!checking)
|
||||
this.copyShareLink(shared);
|
||||
|
@ -81,7 +109,7 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
id: "update",
|
||||
name: "Update current file in JSP",
|
||||
editorCheckCallback: (checking, _, ctx) => {
|
||||
let shared = this.getSharedItem(ctx.file);
|
||||
let shared = this.getSharedItem(ctx.file.path);
|
||||
if (shared) {
|
||||
if (!checking)
|
||||
this.updateFile(shared, ctx.file);
|
||||
|
@ -94,7 +122,7 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
id: "delete",
|
||||
name: "Delete current file from JSP",
|
||||
editorCheckCallback: (checking, _, ctx) => {
|
||||
let shared = this.getSharedItem(ctx.file);
|
||||
let shared = this.getSharedItem(ctx.file.path);
|
||||
if (shared) {
|
||||
if (!checking)
|
||||
this.deleteFile(shared);
|
||||
|
@ -114,8 +142,8 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
getSharedItem(file: TFile): SharedItem {
|
||||
return this.settings.shared.find(f => f.path == file.path);
|
||||
getSharedItem(path: string): SharedItem {
|
||||
return this.settings.shared.find(f => f.path == path);
|
||||
}
|
||||
|
||||
async shareFile(file: TFile): Promise<SharedItem> {
|
||||
|
@ -128,13 +156,12 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
let shared = response.json as SharedItem;
|
||||
shared.path = file.path;
|
||||
|
||||
await this.copyShareLink(shared, false);
|
||||
new Notice(`Successfully shared ${file.basename} and copied link to clipboard`);
|
||||
|
||||
this.settings.shared.push(shared);
|
||||
await this.saveSettings();
|
||||
this.refreshAllViews();
|
||||
|
||||
await this.copyShareLink(shared, false);
|
||||
new Notice(`Successfully shared ${file.basename} and copied link to clipboard`);
|
||||
return shared;
|
||||
} catch (e) {
|
||||
new Notice(createFragment(f => {
|
||||
|
@ -153,21 +180,20 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
headers: {"Password": item.password},
|
||||
body: JSON.stringify({content: await this.preProcessMarkdown(file)})
|
||||
});
|
||||
new Notice(`Successfully updated ${file.basename} on JSP`);
|
||||
if (notice)
|
||||
new Notice(`Successfully updated ${file.basename} on JSP`);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (notice) {
|
||||
new Notice(createFragment(f => {
|
||||
f.createSpan({text: `There was an error updating ${file.basename}: `});
|
||||
f.createEl("code", {text: e});
|
||||
}), 10000);
|
||||
}
|
||||
new Notice(createFragment(f => {
|
||||
f.createSpan({text: `There was an error updating ${file.basename}: `});
|
||||
f.createEl("code", {text: e});
|
||||
}), 10000);
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async deleteFile(item: SharedItem): Promise<boolean> {
|
||||
async deleteFile(item: SharedItem, notice = true): Promise<boolean> {
|
||||
let name = basename(item.path, extname(item.path));
|
||||
try {
|
||||
await requestUrl({
|
||||
|
@ -175,12 +201,13 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
method: "DELETE",
|
||||
headers: {"Password": item.password}
|
||||
});
|
||||
new Notice(`Successfully deleted ${name} from JSP`);
|
||||
|
||||
this.settings.shared.remove(item);
|
||||
await this.saveSettings();
|
||||
this.refreshAllViews();
|
||||
|
||||
if (notice)
|
||||
new Notice(`Successfully deleted ${name} from JSP`);
|
||||
return true;
|
||||
} catch (e) {
|
||||
new Notice(createFragment(f => {
|
||||
|
@ -204,6 +231,10 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
if (this.settings.stripFrontmatter)
|
||||
text = text.replace(/^---\s*\n.*?\n---\s*\n(.*)$/s, "$1");
|
||||
|
||||
// include note name
|
||||
if (this.settings.includeNoteName)
|
||||
text = `# ${file.basename}\n\n${text}`;
|
||||
|
||||
// embed attachments directly
|
||||
let attachments = /!\[(.*)]\((.+)\)|!\[\[(.+)]]/g;
|
||||
let match: RegExpExecArray;
|
||||
|
@ -226,7 +257,6 @@ export default class JustSharePleasePlugin extends Plugin {
|
|||
return text;
|
||||
}
|
||||
|
||||
// TODO refresh when a file is moved or deleted in Obsidian
|
||||
refreshAllViews(): void {
|
||||
for (let leaf of this.app.workspace.getLeavesOfType(JSPView.type)) {
|
||||
if (leaf.view instanceof JSPView)
|
||||
|
|
|
@ -14,7 +14,6 @@ export class JSPSettingsTab extends PluginSettingTab {
|
|||
display(): void {
|
||||
this.containerEl.empty();
|
||||
this.containerEl.createEl("h2", {text: "Just Share Please Settings"});
|
||||
|
||||
new Setting(this.containerEl)
|
||||
.setName("Just Share Please Server")
|
||||
.setDesc(createFragment(f => {
|
||||
|
@ -31,7 +30,6 @@ export class JSPSettingsTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(this.containerEl)
|
||||
.setName("Strip Frontmatter")
|
||||
.setDesc("Whether document frontmatter (also known as properties) should be removed from the uploaded share.")
|
||||
|
@ -42,6 +40,36 @@ export class JSPSettingsTab extends PluginSettingTab {
|
|||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(this.containerEl)
|
||||
.setName("Include Note Name")
|
||||
.setDesc("Whether the name of the shared note should be included in the share as a heading.")
|
||||
.addToggle(t => {
|
||||
t.setValue(this.plugin.settings.includeNoteName);
|
||||
t.onChange(async v => {
|
||||
this.plugin.settings.includeNoteName = v;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(this.containerEl)
|
||||
.setName("Unshare Deleted Files")
|
||||
.setDesc("Whether shares of files should be removed automatically when they are deleted. Only supported when deleting from within Obsidian.")
|
||||
.addToggle(t => {
|
||||
t.setValue(this.plugin.settings.unshareDeletedFiles);
|
||||
t.onChange(async v => {
|
||||
this.plugin.settings.unshareDeletedFiles = v;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(this.containerEl)
|
||||
.setName("Automatically Update Shares")
|
||||
.setDesc("Whether a file's share should automatically be updated when the file is changed from within Obsidian.")
|
||||
.addToggle(t => {
|
||||
t.setValue(this.plugin.settings.autoUpdateShares);
|
||||
t.onChange(async v => {
|
||||
this.plugin.settings.autoUpdateShares = v;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
this.containerEl.createEl("hr");
|
||||
this.containerEl.createEl("p", {text: "If you like this plugin and want to support its development, you can do so through my website by clicking this fancy image!"});
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
export const defaultSettings: JSPSettings = {
|
||||
url: "https://jsp.ellpeck.de",
|
||||
shared: [],
|
||||
stripFrontmatter: true
|
||||
stripFrontmatter: true,
|
||||
includeNoteName: true,
|
||||
unshareDeletedFiles: true,
|
||||
autoUpdateShares: false
|
||||
};
|
||||
|
||||
// TODO add a setting for auto-refreshing uploads when saving
|
||||
// TODO add a setting for auto-removing JSP shares when the original file is deleted
|
||||
export interface JSPSettings {
|
||||
|
||||
url: string;
|
||||
shared: SharedItem[];
|
||||
stripFrontmatter: boolean;
|
||||
includeNoteName: boolean;
|
||||
unshareDeletedFiles: boolean;
|
||||
autoUpdateShares: boolean;
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,7 +22,6 @@ export interface SharedItem {
|
|||
|
||||
id: string;
|
||||
password: string;
|
||||
// TODO auto-update path when file is moved
|
||||
path: string;
|
||||
|
||||
}
|
||||
|
|
52
src/view.ts
52
src/view.ts
|
@ -16,34 +16,40 @@ export class JSPView extends ItemView {
|
|||
public refresh(): void {
|
||||
this.contentEl.empty();
|
||||
let content = this.contentEl.createDiv({cls: "just-share-please-view"});
|
||||
for (let shared of this.plugin.settings.shared) {
|
||||
let file = this.plugin.app.vault.getAbstractFileByPath(shared.path) as TFile;
|
||||
let div = content.createDiv({cls: "just-share-please-shared-item"});
|
||||
div.createSpan({cls: "just-share-please-shared-name", text: basename(shared.path, extname(shared.path))});
|
||||
new ButtonComponent(div)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Copy JSP link")
|
||||
.setIcon("link")
|
||||
.onClick(async () => this.plugin.copyShareLink(shared));
|
||||
if (file) {
|
||||
if (this.plugin.settings.shared.length > 0) {
|
||||
for (let shared of this.plugin.settings.shared) {
|
||||
let file = this.plugin.app.vault.getAbstractFileByPath(shared.path) as TFile;
|
||||
let div = content.createDiv({cls: "just-share-please-shared-item"});
|
||||
div.createSpan({cls: "just-share-please-shared-name", text: basename(shared.path, extname(shared.path))});
|
||||
new ButtonComponent(div)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Open in Obsidian")
|
||||
.setIcon("edit")
|
||||
.onClick(async () => {
|
||||
// TODO open in obsidian
|
||||
});
|
||||
.setTooltip("Copy JSP link")
|
||||
.setIcon("link")
|
||||
.onClick(async () => this.plugin.copyShareLink(shared));
|
||||
if (file) {
|
||||
new ButtonComponent(div)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Open in Obsidian")
|
||||
.setIcon("edit")
|
||||
.onClick(async e => {
|
||||
let leaf = this.app.workspace.getLeaf(e.ctrlKey);
|
||||
await leaf.openFile(file);
|
||||
this.app.workspace.setActiveLeaf(leaf, {focus: true});
|
||||
});
|
||||
new ButtonComponent(div)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Update in JSP")
|
||||
.setIcon("share")
|
||||
.onClick(async () => this.plugin.updateFile(shared, file));
|
||||
}
|
||||
new ButtonComponent(div)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Update in JSP")
|
||||
.setIcon("share")
|
||||
.onClick(async () => this.plugin.updateFile(shared, file));
|
||||
.setTooltip("Delete from JSP")
|
||||
.setIcon("trash")
|
||||
.onClick(async () => this.plugin.deleteFile(shared));
|
||||
}
|
||||
new ButtonComponent(div)
|
||||
.setClass("clickable-icon")
|
||||
.setTooltip("Delete from JSP")
|
||||
.setIcon("trash")
|
||||
.onClick(async () => this.plugin.deleteFile(shared));
|
||||
} else {
|
||||
content.createSpan({text: "You have not shared any items yet."});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
{
|
||||
"url": "https://jsp.ellpeck.de",
|
||||
"url": "http://localhost:8080",
|
||||
"shared": [
|
||||
{
|
||||
"id": "3c781ebc",
|
||||
"password": "7eae9eea1f7503f6f236b242d45657e6",
|
||||
"id": "234df7b7",
|
||||
"password": "0ef1504bfe83cd9ca812434caa7aacf4",
|
||||
"path": "Cool Test Note.md"
|
||||
},
|
||||
{
|
||||
"id": "d47f7765",
|
||||
"password": "513115b756d9ddebd3afd6efe4c248c6",
|
||||
"path": "Even cooler note.md"
|
||||
}
|
||||
],
|
||||
"stripFrontmatter": true
|
||||
"stripFrontmatter": true,
|
||||
"includeNoteName": true,
|
||||
"unshareDeletedFiles": false,
|
||||
"autoUpdateShares": false
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
test: yes
|
||||
---
|
||||
# Cool Test Note
|
||||
|
||||
This is a cool test note, my friends!
|
||||
|
||||
|
@ -25,6 +24,8 @@ $.ajax({
|
|||
|
||||
cool!!
|
||||
|
||||
blah blah i added and removed this
|
||||
|
||||
The following is $x^2 = 7$, but more complicated!
|
||||
$$
|
||||
x^2 + \sum_{i = 1}^{10000} x^2 \cdot 0 = 7
|
||||
|
|
Loading…
Reference in a new issue