Skip to content
This repository was archived by the owner on Sep 1, 2024. It is now read-only.

Commit 5a881e7

Browse files
committed
feat: add custom attachment types support
re #43
1 parent 2310cc4 commit 5a881e7

10 files changed

+230
-25
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# [2.2.0](https://github.com/JYC333/obsidian-attachment-name-formatting/compare/2.1.10...2.2.0) (2024-08-13)
2+
3+
4+
### Features
5+
6+
* add custom attachment types support ([9f2e76a](https://github.com/JYC333/obsidian-attachment-name-formatting/commit/9f2e76a464d2606bfbf9dd69c6ea66927f03315d)), closes [#43](https://github.com/JYC333/obsidian-attachment-name-formatting/issues/43)
7+
* add using notename as a subfolder ([2310cc4](https://github.com/JYC333/obsidian-attachment-name-formatting/commit/2310cc42c1c6a9cfcc5b70ff092b0757f22e12c1)), closes [#40](https://github.com/JYC333/obsidian-attachment-name-formatting/issues/40) [#44](https://github.com/JYC333/obsidian-attachment-name-formatting/issues/44)
8+
9+
10+
111
## [2.1.10](https://github.com/JYC333/obsidian-attachment-name-formatting/compare/2.1.9...2.1.10) (2024-08-12)
212

313

README.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# This plugin will soon be archived and will no longer be maintained. I plan to wait for a while after the update to see if any issues arise. Personally, I've switched to using [Trilium](https://github.com/TriliumNext/Notes) as I found managing attachments and syncing notes manually with Obsidian a bit tedious. That said, Obsidian is still an excellent tool, and I have no criticisms of it. Thank you for using this plugin—I hope it has been helpful to you.
2+
13
## Obsidian Attachment Name Formatting
24

35
This plugin will format all attachments in the format: "noteName attachmentFormat indexNumber.xxx"
@@ -29,9 +31,10 @@ When using "Copy" mode, it will take a bit longer time than usual renaming time,
2931
#### Core Function
3032

3133
- Format attachments in active file, such as "noteName image 1.png". Format time and absolute note path hash can add into attachment name, such as "noteName image 1 20220101000000.png", "noteName image 1 6666cd76.png". Defualt setting is not adding time and path hash. You can also exclude the noteName in the attachment noteName, but the time suffix will be added automatically.
32-
- Format attachmnets in selected folder
33-
- Format attachments with customize subfolder for each attachment type
34+
- Format attachmnets in selected folder (support recursively)
35+
- Format attachments with customize subfolder for each attachment type, and can add note name as another level subfolder
3436
- Attachment name can be customized for each type of attachment, you can use any character that allowed in a note name
37+
- Attachment type not supported officially can be added in the setting
3538
- Connector (the character between noteName, attachmentFormat, indexNumber, time and pathHash) can be customized, you can use any character that allowed in a note name. You can also customized different connectors seperately or even don't use connector.
3639
- Add new attachment -> will rename the attachment based on type and index
3740
- Change order -> will rename attachments with new order
@@ -44,22 +47,24 @@ When using "Copy" mode, it will take a bit longer time than usual renaming time,
4447

4548
### Supported attachment format
4649

47-
1. Image files: png, webp, jpg, jpeg, gif, bmp, svg
50+
1. Image files: png, webp, jpg, jpeg, gif, bmp, svg, avif
4851
2. Audio files: mp3, wav, m4a, ogg, 3gp, flac
4952
3. Video files: mp4, webp, ogv, mov, mkv
5053
4. PDF files: pdf
5154

5255
`webm` file type will be regard as vedieo even if it can be audio.
5356

57+
Customized attachment format can be added in the setting.
58+
5459
### Known Issues
5560

5661
- When delete an attachment which is already renamed, it will not rename and will occupy the indexNmuber for this note. But will be renamed to tmp_xxx if there is a conflict later.
5762
- When there are two attachments have same name but in different paths, the function will not work correctly. Try to not change the setting "Files & Links -> Default location for new attachments".
5863

5964
### Roadmap
6065

61-
- When deleting attachment in a file, rename it with "noteName attachmentFormat unuse 1.xxx".
62-
- When deleting an attachment that no other file using this attachment, delete it from vault. (Could be disable)
66+
~~- When deleting attachment in a file, rename it with "noteName attachmentFormat unuse 1.xxx".
67+
- When deleting an attachment that no other file using this attachment, delete it from vault. (Could be disable)~~
6368

6469
### Development Setup
6570

manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-attachment-name-formatting",
33
"name": "Attachment Name Formatting",
4-
"version": "2.1.10",
4+
"version": "2.2.0",
55
"minAppVersion": "0.12.0",
66
"description": "Obsidian plugin for formatting attachments name (filename attachmentType indexNumber.xxx)",
77
"author": "JYC333",

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-attachment-name-formattion",
3-
"version": "2.1.10",
3+
"version": "2.2.0",
44
"description": "Obsidian plugin for formatting attachments name (filename attachmentType indexNumber.xxx)",
55
"main": "main.js",
66
"scripts": {

src/constants.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const DEFAULT_SETTINGS: ANFSettings = {
1313
multipleConnectors: ["_", "_", "_", "_"],
1414
multipleConnectorsEnabled: [true, true, true, true],
1515
enableImage: true,
16-
imageExtensions: [true, true, true, true, true, true, true], // same amout with image extensions
16+
imageExtensions: [true, true, true, true, true, true, true, true], // same amout with image extensions
1717
image: "image",
1818
enableAudio: true,
1919
audioExtensions: [true, true, true, true, true, true], // same amout with audio extensions
@@ -24,6 +24,8 @@ export const DEFAULT_SETTINGS: ANFSettings = {
2424
enablePdf: true,
2525
pdfExtensions: [true], // same amout with pdf extensions
2626
pdf: "pdf",
27+
customExtensions: {},
28+
enableCustom: false,
2729
oneInMany: "Default",
2830
enableAuto: true,
2931
enableTime: false,

src/main.ts

+45-13
Original file line numberDiff line numberDiff line change
@@ -321,22 +321,52 @@ export default class AttachmentNameFormatting extends Plugin {
321321
// Create a list of attachments, classified by types
322322
const attachmentList: AttachmentList = {};
323323
for (const item of attachments.embeds) {
324+
let extensionAll;
325+
// Check whether the custom extensions are enabled
326+
if (this.settings.enableCustom) {
327+
extensionAll = Object.assign(
328+
{},
329+
extensions,
330+
this.settings.customExtensions
331+
);
332+
} else {
333+
extensionAll = Object.assign({}, extensions);
334+
}
335+
324336
for (const [fileType, fileExtensions] of Object.entries(
325-
extensions
337+
extensionAll
326338
)) {
327-
const attachmentEnable = ("enable" +
328-
fileType.slice(0, 1).toUpperCase() +
329-
fileType.slice(1)) as keyof ANFSettings;
330-
const extensionEnable = (fileType +
331-
"Extensions") as keyof ANFSettings;
332339
const attachmentExtension = item.link.split(".").pop();
333-
const attachmentExtensionInd =
334-
extensions[fileType].indexOf(attachmentExtension);
340+
341+
// Check whether official attachment is enabled
342+
let isAttachmentEnable;
343+
if (Object.keys(extensions).contains(fileType)) {
344+
const attachmentEnable = ("enable" +
345+
fileType.slice(0, 1).toUpperCase() +
346+
fileType.slice(1)) as keyof ANFSettings;
347+
const extensionEnable = (fileType +
348+
"Extensions") as keyof ANFSettings;
349+
const attachmentExtensionInd =
350+
extensions[fileType].indexOf(attachmentExtension);
351+
isAttachmentEnable =
352+
this.settings[attachmentEnable] &&
353+
// @ts-ignore
354+
this.settings[extensionEnable][
355+
attachmentExtensionInd
356+
];
357+
} else {
358+
isAttachmentEnable = true;
359+
}
360+
361+
// Get all custom extensions
362+
const customExtentions = [].concat(
363+
...Object.values(this.settings.customExtensions)
364+
);
365+
335366
if (
336-
fileExtensions.contains(attachmentExtension) &&
337-
this.settings[attachmentEnable] &&
338-
// @ts-ignore
339-
this.settings[extensionEnable][attachmentExtensionInd]
367+
(fileExtensions.contains(attachmentExtension) ||
368+
customExtentions.contains(attachmentExtension)) &&
369+
isAttachmentEnable
340370
) {
341371
if (!attachmentList.hasOwnProperty(fileType)) {
342372
attachmentList[fileType] = [];
@@ -464,7 +494,9 @@ export default class AttachmentNameFormatting extends Plugin {
464494

465495
const baseNameComponent = [
466496
file.basename,
467-
this.settings[fileType as keyof ANFSettings],
497+
Object.keys(this.settings).includes(fileType)
498+
? this.settings[fileType as keyof ANFSettings]
499+
: fileType,
468500
num,
469501
];
470502

src/modals.ts

+132-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ export class MultiConnectorModal extends Modal {
195195
}
196196
}
197197

198-
export class SuboldersModal extends Modal {
198+
export class SubfoldersModal extends Modal {
199199
plugin: AttachmentNameFormatting;
200200

201201
constructor(app: App, plugin: AttachmentNameFormatting) {
@@ -291,6 +291,137 @@ export class AttachmentExtensionModal extends Modal {
291291
}
292292
}
293293

294+
export class CustomAttachmentExtensionModal extends Modal {
295+
plugin: AttachmentNameFormatting;
296+
297+
constructor(app: App, plugin: AttachmentNameFormatting) {
298+
super(app);
299+
this.plugin = plugin;
300+
}
301+
302+
onOpen() {
303+
const { contentEl } = this;
304+
contentEl.createEl("h2", {
305+
text: `Add/Remove custom attachment extenstions.`,
306+
});
307+
contentEl.createEl("p", {
308+
text: "Please separate the extension with comma, for example: zip,rar.",
309+
});
310+
311+
for (const extension of Object.keys(
312+
this.plugin.settings.customExtensions
313+
)) {
314+
new Setting(contentEl)
315+
.setName(extension)
316+
.addText((text) => {
317+
text.setValue(
318+
this.plugin.settings.customExtensions[extension].join(
319+
","
320+
)
321+
).onChange(async (value) => {
322+
this.plugin.settings.customExtensions[extension] =
323+
value.split(",");
324+
await this.plugin.saveSettings();
325+
});
326+
})
327+
.addExtraButton((extraButton) => {
328+
extraButton.setIcon("x-circle").onClick(() => {
329+
delete this.plugin.settings.customExtensions[extension];
330+
331+
this.plugin.saveSettings();
332+
this.close();
333+
this.open();
334+
});
335+
});
336+
}
337+
338+
new Setting(contentEl).addButton((button) => {
339+
button.setButtonText("Add").onClick(async () => {
340+
new CustomAttachmentNameModal(this.app, this.plugin).open();
341+
this.close();
342+
});
343+
});
344+
}
345+
346+
onClose() {
347+
const { contentEl } = this;
348+
contentEl.empty();
349+
}
350+
}
351+
352+
class CustomAttachmentNameModal extends Modal {
353+
plugin: AttachmentNameFormatting;
354+
text: string;
355+
356+
constructor(app: App, plugin: AttachmentNameFormatting) {
357+
super(app);
358+
this.plugin = plugin;
359+
}
360+
361+
onOpen() {
362+
const { contentEl } = this;
363+
contentEl.createEl("h1", {
364+
text: "Add custom attachment type",
365+
});
366+
contentEl.createEl("p", {
367+
text: 'Please enter the custom attachment type name, for example "custom".',
368+
});
369+
contentEl.createEl("p", {
370+
text: "The name will be used as the format name for this type of attachment.",
371+
});
372+
contentEl.createEl("p", {
373+
text: "Note: the name should not be empty or already exists.",
374+
});
375+
376+
new Setting(contentEl)
377+
.addText((text) => {
378+
text.setPlaceholder("custom").onChange(async (value) => {
379+
this.text = value;
380+
});
381+
})
382+
.addButton((button) =>
383+
button
384+
.setButtonText("OK")
385+
.setCta()
386+
.onClick(() => {
387+
if (
388+
this.plugin.settings.customExtensions.hasOwnProperty(
389+
this.text
390+
)
391+
) {
392+
new WarningModal(
393+
this.app,
394+
"Custom extension type already exists, please change."
395+
).open();
396+
} else if (
397+
this.text === undefined ||
398+
this.text === ""
399+
) {
400+
new WarningModal(
401+
this.app,
402+
"Custom extension type can not be empty."
403+
).open();
404+
} else {
405+
this.plugin.settings.customExtensions[
406+
this.text.toString()
407+
] = [];
408+
this.plugin.saveSettings();
409+
new CustomAttachmentExtensionModal(
410+
app,
411+
this.plugin
412+
).open();
413+
this.close();
414+
}
415+
})
416+
);
417+
}
418+
419+
onClose() {
420+
const { contentEl } = this;
421+
contentEl.empty();
422+
}
423+
}
424+
294425
export class WarningModal extends Modal {
295426
text: string;
296427

src/settings.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import AttachmentNameFormatting from "./main";
44
import {
55
ExcludedFoldersModal,
66
MultiConnectorModal,
7-
SuboldersModal,
7+
SubfoldersModal,
88
AttachmentExtensionModal,
9+
CustomAttachmentExtensionModal,
910
WarningModal,
1011
} from "./modals";
1112
import { ANFSettings } from "./types";
@@ -128,6 +129,9 @@ export class ANFSettingTab extends PluginSettingTab {
128129
}
129130

130131
for (const item of ATTACHMENT_TYPE) {
132+
if (item === "custom") {
133+
continue;
134+
}
131135
const attachmentType = item as keyof ANFSettings;
132136
const typeSetting = new Setting(containerEl)
133137
.setName(`Format for ${attachmentType}`)
@@ -189,6 +193,24 @@ export class ANFSettingTab extends PluginSettingTab {
189193
});
190194
}
191195

196+
new Setting(containerEl)
197+
.setName(`Format for custom attachment types`)
198+
.setDesc(`Set the format for custom attachment types.`)
199+
.addExtraButton((button) => {
200+
button.onClick(() => {
201+
new CustomAttachmentExtensionModal(app, this.plugin).open();
202+
});
203+
})
204+
.addToggle((toggle) => {
205+
toggle
206+
.setValue(this.plugin.settings.enableCustom)
207+
.onChange(async (value) => {
208+
this.plugin.settings.enableCustom = value;
209+
await this.plugin.saveSettings();
210+
this.display();
211+
});
212+
});
213+
192214
new Setting(containerEl)
193215
.setName("Handle same attachment used in different notes")
194216
.setDesc(
@@ -316,7 +338,7 @@ export class ANFSettingTab extends PluginSettingTab {
316338
)
317339
.addExtraButton((extraButton) => {
318340
extraButton.onClick(() => {
319-
new SuboldersModal(app, this.plugin).open();
341+
new SubfoldersModal(app, this.plugin).open();
320342
});
321343
});
322344

src/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export interface ANFSettings {
1919
enablePdf: boolean;
2020
pdfExtensions: boolean[];
2121
pdf: string;
22+
customExtensions: Record<string, string[]>;
23+
enableCustom: boolean;
2224
oneInMany: string;
2325
enableAuto: boolean;
2426
enableTime: boolean;

versions.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@
3131
"2.1.7": "0.12.0",
3232
"2.1.8": "0.12.0",
3333
"2.1.9": "0.12.0",
34-
"2.1.10": "0.12.0"
34+
"2.1.10": "0.12.0",
35+
"2.2.0": "0.12.0"
3536
}

0 commit comments

Comments
 (0)