Skip to content

Commit ee0645c

Browse files
committed
For each type of template it's possible to set a title template
CLOSES #22
1 parent 9181b9b commit ee0645c

File tree

9 files changed

+292
-202
lines changed

9 files changed

+292
-202
lines changed

src/helpers/fileutils.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { normalizePath } from 'obsidian';
2+
import path from 'path';
3+
4+
export function isValidUrl(url: string): boolean {
5+
try {
6+
new URL(url);
7+
} catch (e) {
8+
return false;
9+
}
10+
return true;
11+
}
12+
13+
export function getBaseUrl(url?: string, prefix?: string): string {
14+
const dir = '/';
15+
const urlAsArray = url.split(dir);
16+
const doubleSlashIndex = url.indexOf('://');
17+
if (doubleSlashIndex !== -1 && doubleSlashIndex === url.indexOf(dir) - 1) {
18+
urlAsArray.length = 3;
19+
let url = urlAsArray.join(dir);
20+
if (prefix !== undefined) url = url.replace(/http:\/\/|https:\/\//, prefix);
21+
return url;
22+
} else {
23+
const pointIndex = url.indexOf('.');
24+
if (pointIndex !== -1 && pointIndex !== 0) {
25+
return (prefix !== undefined ? prefix : 'https://') + urlAsArray[0];
26+
}
27+
}
28+
}
29+
30+
export function normalizeFilename(fileName: string): string {
31+
const illegalSymbols = [':', '#', '/', '\\', '|', '?', '*', '<', '>', '"'];
32+
if (illegalSymbols.some((el) => fileName.contains(el))) {
33+
illegalSymbols.forEach((ilSymbol) => {
34+
fileName = fileName.replace(ilSymbol, '');
35+
});
36+
37+
return fileName;
38+
} else {
39+
return fileName;
40+
}
41+
}
42+
43+
export function pathJoin(dir: string, subpath: string): string {
44+
const result = path.join(dir, subpath);
45+
// it seems that obsidian do not understand paths with backslashes in Windows, so turn them into forward slashes
46+
return normalizePath(result.replace(/\\/g, '/'));
47+
}

src/helpers/index.ts

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,4 @@
1-
import { normalizePath } from 'obsidian';
2-
import path from 'path';
3-
4-
export function isValidUrl(url: string): boolean {
5-
try {
6-
new URL(url);
7-
} catch (e) {
8-
return false;
9-
}
10-
return true;
11-
}
12-
13-
export function getBaseUrl(url?: string, prefix?: string): string {
14-
const dir = '/';
15-
const urlAsArray = url.split(dir);
16-
const doubleSlashIndex = url.indexOf('://');
17-
if (doubleSlashIndex !== -1 && doubleSlashIndex === url.indexOf(dir) - 1) {
18-
urlAsArray.length = 3;
19-
let url = urlAsArray.join(dir);
20-
if (prefix !== undefined) url = url.replace(/http:\/\/|https:\/\//, prefix);
21-
return url;
22-
} else {
23-
const pointIndex = url.indexOf('.');
24-
if (pointIndex !== -1 && pointIndex !== 0) {
25-
return (prefix !== undefined ? prefix : 'https://') + urlAsArray[0];
26-
}
27-
}
28-
}
29-
30-
export function normalizeFilename(fileName: string): string {
31-
const illegalSymbols = [':', '#', '/', '\\', '|', '?', '*', '<', '>', '"'];
32-
if (illegalSymbols.some((el) => fileName.contains(el))) {
33-
illegalSymbols.forEach((ilSymbol) => {
34-
fileName = fileName.replace(ilSymbol, '');
35-
});
36-
37-
return fileName;
38-
} else {
39-
return fileName;
40-
}
41-
}
42-
43-
export function pathJoin(dir: string, subpath: string): string {
44-
const result = path.join(dir, subpath);
45-
// it seems that obsidian do not understand paths with backslashes in Windows, so turn them into forward slashes
46-
return normalizePath(result.replace(/\\/g, '/'));
47-
}
48-
491
export { downloadImage } from './downloadImage';
502
export { checkAndCreateFolder } from './checkAndCreateFolder';
51-
export { replaceImages } from './replaceImages';
3+
export { replaceImages } from './replaceImages';
4+
export { getBaseUrl, isValidUrl, normalizeFilename, pathJoin } from './fileutils';

src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { addIcon, normalizePath, Notice, Plugin } from 'obsidian';
22
import { checkAndCreateFolder, normalizeFilename } from './helpers';
3-
import { DEFAULT_SETTINGS, ReadItLaterSettings, ReadItLaterSettingsTab } from './settings';
3+
import { DEFAULT_SETTINGS, ReadItLaterSettings } from './settings';
44
import YoutubeParser from './parsers/YoutubeParser';
55
import TwitterParser from './parsers/TwitterParser';
66
import { Parser } from './parsers/Parser';
77
import WebsiteParser from './parsers/WebsiteParser';
88
import TextSnippetParser from './parsers/TextSnippetParser';
9+
import { ReadItLaterSettingsTab } from './views/settings-tab';
910

1011
export default class ReadItLaterPlugin extends Plugin {
1112
settings: ReadItLaterSettings;

src/parsers/TextSnippetParser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class TextSnippetParser extends Parser {
1313
}
1414

1515
async prepareNote(text: string): Promise<Note> {
16-
const fileName = `Notice ${this.getFormattedDateForFilename()}.md`;
16+
const fileName = `${this.getFormattedDateForFilename()}.md`;
1717
const content = this.settings.textSnippetNote.replace(/%content%/g, text);
1818
return new Note(fileName, content);
1919
}

src/parsers/TwitterParser.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ class TwitterParser extends Parser {
3232
.replace(/%tweetURL%/g, response.url)
3333
.replace(/%tweetContent%/g, content);
3434

35-
const fileName = `Tweet from ${tweetAuthorName} (${this.getFormattedDateForFilename()}).md`;
35+
const fileNameTemplate = this.settings.twitterNoteTitle
36+
.replace(/%tweetAuthorName%/g, tweetAuthorName)
37+
.replace(/%date%/g, this.getFormattedDateForFilename());
38+
39+
const fileName = `${fileNameTemplate}.md`;
3640

3741
return new Note(fileName, processedContent);
3842
}

src/parsers/WebsiteParser.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ class WebsiteParser extends Parser {
5353
.replace(/%articleTitle%/g, title)
5454
.replace(/%articleURL%/g, url)
5555
.replace(/%articleContent%/g, content);
56+
57+
const fileNameTemplate = this.settings.parseableArticleNoteTitle
58+
.replace(/%title%/g, title);
5659

57-
const fileName = `${title}.md`;
60+
const fileName = `${fileNameTemplate}.md`;
5861
return new Note(fileName, processedContent);
5962
}
6063

@@ -63,7 +66,9 @@ class WebsiteParser extends Parser {
6366

6467
const content = this.settings.notParsableArticleNote.replace('%articleURL%', url);
6568

66-
const fileName = `Article (${this.getFormattedDateForFilename()}).md`;
69+
const fileNameTemplate = this.settings.notParsableArticleNote
70+
.replace(/%date%/g, this.getFormattedDateForFilename());
71+
const fileName = `${fileNameTemplate}.md`;
6772
return new Note(fileName, content);
6873
}
6974
}

src/parsers/YoutubeParser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class YoutubeParser extends Parser {
2626
.replace(/%videoId%/g, videoId)
2727
.replace(/%videoPlayer%/g, videoPlayer);
2828

29-
const fileName = `Youtube - ${videoTitle}.md`;
29+
const fileNameTemplate = this.settings.youtubeNoteTitle.replace(/%title%/g, videoTitle);
30+
const fileName = `${fileNameTemplate}.md`;
3031
return new Note(fileName, content);
3132
}
3233
}

src/settings.ts

Lines changed: 11 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import { App, PluginSettingTab, Setting } from 'obsidian';
2-
import ReadItLaterPlugin from './main';
3-
41
export interface ReadItLaterSettings {
52
inboxDir: string;
63
assetsDir: string;
74
openNewNote: boolean;
5+
youtubeNoteTitle: string;
86
youtubeNote: string;
7+
twitterNoteTitle: string;
98
twitterNote: string;
9+
parseableArticleNoteTitle: string;
1010
parsableArticleNote: string;
11+
notParseableArticleNoteTitle: string;
1112
notParsableArticleNote: string;
13+
textSnippetNoteTitle: string;
1214
textSnippetNote: string;
1315
downloadImages: boolean;
1416
}
@@ -17,153 +19,15 @@ export const DEFAULT_SETTINGS: ReadItLaterSettings = {
1719
inboxDir: 'ReadItLater Inbox',
1820
assetsDir: 'ReadItLater Inbox/assets',
1921
openNewNote: false,
22+
youtubeNoteTitle: 'Youtube - %title%',
2023
youtubeNote: `[[ReadItLater]] [[Youtube]]\n\n# [%videoTitle%](%videoURL%)\n\n%videoPlayer%`,
24+
twitterNoteTitle: 'Tweet from %tweetAuthorName% (%date%)',
2125
twitterNote: `[[ReadItLater]] [[Tweet]]\n\n# [%tweetAuthorName%](%tweetURL%)\n\n%tweetContent%`,
26+
parseableArticleNoteTitle: '%title%',
2227
parsableArticleNote: `[[ReadItLater]] [[Article]]\n\n# [%articleTitle%](%articleURL%)\n\n%articleContent%`,
28+
notParseableArticleNoteTitle: 'Article %date%',
2329
notParsableArticleNote: `[[ReadItLater]] [[Article]]\n\n[%articleURL%](%articleURL%)`,
30+
textSnippetNoteTitle: 'Notice %date%',
2431
textSnippetNote: `[[ReadItLater]] [[Textsnippet]]\n\n%content%`,
2532
downloadImages: true,
26-
};
27-
28-
export class ReadItLaterSettingsTab extends PluginSettingTab {
29-
plugin: ReadItLaterPlugin;
30-
31-
constructor(app: App, plugin: ReadItLaterPlugin) {
32-
super(app, plugin);
33-
this.plugin = plugin;
34-
}
35-
36-
display(): void {
37-
const { containerEl } = this;
38-
39-
containerEl.empty();
40-
41-
containerEl.createEl('h2', { text: 'Settings for the ReadItLater plugin.' });
42-
43-
new Setting(containerEl)
44-
.setName('Inbox dir')
45-
.setDesc(
46-
'Enter valid folder name. For nested folders use this format: Folder A/Folder B. If no folder is enetred, new note will be created in vault root.',
47-
)
48-
.addText((text) =>
49-
text
50-
.setPlaceholder('Defaults to root')
51-
.setValue(this.plugin.settings.inboxDir || DEFAULT_SETTINGS.inboxDir)
52-
.onChange(async (value) => {
53-
this.plugin.settings.inboxDir = value;
54-
await this.plugin.saveSettings();
55-
}),
56-
);
57-
58-
new Setting(containerEl)
59-
.setName('Open new note')
60-
.setDesc('If enabled, new note will open in current workspace')
61-
.addToggle((toggle) =>
62-
toggle
63-
.setValue(this.plugin.settings.openNewNote || DEFAULT_SETTINGS.openNewNote)
64-
.onChange(async (value) => {
65-
this.plugin.settings.openNewNote = value;
66-
await this.plugin.saveSettings();
67-
}),
68-
);
69-
70-
new Setting(containerEl)
71-
.setName('Download images')
72-
.setDesc('If this is true, the used images are downloaded to the defined folder')
73-
.addToggle((toggle) =>
74-
toggle
75-
.setValue(this.plugin.settings.downloadImages || DEFAULT_SETTINGS.downloadImages)
76-
.onChange(async (value) => {
77-
this.plugin.settings.downloadImages = value;
78-
assetDirSetting.setDisabled(!value);
79-
await this.plugin.saveSettings();
80-
}),
81-
);
82-
83-
const assetDirSetting = new Setting(containerEl)
84-
.setName('Assets dir')
85-
.setDesc(
86-
'Enter valid folder name. For nested folders use this format: Folder A/Folder B. If no folder is enetred, new note will be created in vault root.',
87-
)
88-
.addText((text) =>
89-
text
90-
.setPlaceholder('Defaults to root')
91-
.setValue(this.plugin.settings.assetsDir || DEFAULT_SETTINGS.inboxDir + '/assets')
92-
.setDisabled(!this.plugin.settings.downloadImages)
93-
.onChange(async (value) => {
94-
this.plugin.settings.assetsDir = value;
95-
await this.plugin.saveSettings();
96-
}),
97-
);
98-
99-
new Setting(containerEl)
100-
.setName('Youtube note template')
101-
.setDesc('Available variables: %videoTitle%, %videoURL%, %videoId%, %videoPlayer%')
102-
.addTextArea((textarea) => {
103-
textarea
104-
.setValue(this.plugin.settings.youtubeNote || DEFAULT_SETTINGS.youtubeNote)
105-
.onChange(async (value) => {
106-
this.plugin.settings.youtubeNote = value;
107-
await this.plugin.saveSettings();
108-
});
109-
textarea.inputEl.rows = 10;
110-
textarea.inputEl.cols = 25;
111-
});
112-
113-
new Setting(containerEl)
114-
.setName('Twitter note template')
115-
.setDesc('Available variables: %tweetAuthorName%, %tweetURL%, %tweetContent%')
116-
.addTextArea((textarea) => {
117-
textarea
118-
.setValue(this.plugin.settings.twitterNote || DEFAULT_SETTINGS.twitterNote)
119-
.onChange(async (value) => {
120-
this.plugin.settings.twitterNote = value;
121-
await this.plugin.saveSettings();
122-
});
123-
textarea.inputEl.rows = 10;
124-
textarea.inputEl.cols = 25;
125-
});
126-
127-
new Setting(containerEl)
128-
.setName('Parsable article note template')
129-
.setDesc('Available variables: %articleTitle%, %articleURL%, %articleContent%')
130-
.addTextArea((textarea) => {
131-
textarea
132-
.setValue(this.plugin.settings.parsableArticleNote || DEFAULT_SETTINGS.parsableArticleNote)
133-
.onChange(async (value) => {
134-
this.plugin.settings.parsableArticleNote = value;
135-
await this.plugin.saveSettings();
136-
});
137-
textarea.inputEl.rows = 10;
138-
textarea.inputEl.cols = 25;
139-
});
140-
141-
new Setting(containerEl)
142-
.setName('Not parsable article note template')
143-
.setDesc('Available variables: %articleURL%')
144-
.addTextArea((textarea) => {
145-
textarea
146-
.setValue(this.plugin.settings.notParsableArticleNote || DEFAULT_SETTINGS.notParsableArticleNote)
147-
.onChange(async (value) => {
148-
this.plugin.settings.notParsableArticleNote = value;
149-
await this.plugin.saveSettings();
150-
});
151-
textarea.inputEl.rows = 10;
152-
textarea.inputEl.cols = 25;
153-
});
154-
155-
new Setting(containerEl)
156-
.setName('Text snippet note template')
157-
.setDesc('Available variables: %content%')
158-
.addTextArea((textarea) => {
159-
textarea
160-
.setValue(this.plugin.settings.textSnippetNote || DEFAULT_SETTINGS.textSnippetNote)
161-
.onChange(async (value) => {
162-
this.plugin.settings.textSnippetNote = value;
163-
await this.plugin.saveSettings();
164-
});
165-
textarea.inputEl.rows = 10;
166-
textarea.inputEl.cols = 25;
167-
});
168-
}
169-
}
33+
};

0 commit comments

Comments
 (0)