1
- import { Notice , Plugin , normalizePath } from "obsidian" ;
1
+ import { Notice , Plugin , TFile , TFolder , normalizePath } from "obsidian" ;
2
2
import { fetchTitleFromUrl } from "./utils/http-utils" ;
3
3
import { formatTitleForMacOS } from "./utils/title-utils" ;
4
4
interface TitleFetcherSettings {
@@ -19,6 +19,20 @@ export default class TitleFetcherPlugin extends Plugin {
19
19
this . renameToUrlTitle ( ) ;
20
20
} ) ;
21
21
22
+ this . registerEvent (
23
+ this . app . workspace . on ( "file-menu" , ( menu , file ) => {
24
+ if ( file instanceof TFolder ) {
25
+ menu . addItem ( ( item ) => {
26
+ item . setTitle ( "Rename notes to URL titles" )
27
+ . setIcon ( "file-code-2" )
28
+ . onClick ( async ( ) => {
29
+ await this . renameFolderNotesToUrlTitle ( file ) ;
30
+ } ) ;
31
+ } ) ;
32
+ }
33
+ } )
34
+ ) ;
35
+
22
36
this . addCommand ( {
23
37
id : "rename-to-url-title" ,
24
38
name : "Rename to URL title" ,
@@ -33,15 +47,38 @@ export default class TitleFetcherPlugin extends Plugin {
33
47
34
48
onunload ( ) { }
35
49
36
- private async renameToUrlTitle ( ) {
37
- const activeFile = this . app . workspace . getActiveFile ( ) ;
38
- if ( ! activeFile ) {
39
- new Notice ( "No file is open" ) ;
40
- return ;
50
+ private async renameFolderNotesToUrlTitle ( folder : TFolder ) {
51
+ const markdownFiles = this . app . vault
52
+ . getMarkdownFiles ( )
53
+ . filter ( ( file ) => file . parent === folder ) ;
54
+
55
+ const BATCH_SIZE = 3 ; // Process 3 files at a time
56
+
57
+ for ( let i = 0 ; i < markdownFiles . length ; i += BATCH_SIZE ) {
58
+ const batch = markdownFiles . slice ( i , i + BATCH_SIZE ) ;
59
+ await Promise . allSettled (
60
+ batch . map ( ( file ) => this . renameToUrlTitle ( file ) )
61
+ ) ;
62
+
63
+ // Optional: small delay between batches to be respectful
64
+ if ( i + BATCH_SIZE < markdownFiles . length ) {
65
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) ) ;
66
+ }
67
+ }
68
+ }
69
+
70
+ private async renameToUrlTitle ( file ?: TFile ) {
71
+ if ( ! file ) {
72
+ const activeFile = this . app . workspace . getActiveFile ( ) ;
73
+ if ( ! activeFile ) {
74
+ new Notice ( "No file is open" ) ;
75
+ return ;
76
+ }
77
+ file = activeFile ;
41
78
}
42
79
43
80
const frontmatter =
44
- this . app . metadataCache . getFileCache ( activeFile ) ?. frontmatter ;
81
+ this . app . metadataCache . getFileCache ( file ) ?. frontmatter ;
45
82
if ( ! frontmatter ) {
46
83
new Notice ( "No frontmatter found in the current file" ) ;
47
84
return ;
@@ -63,18 +100,15 @@ export default class TitleFetcherPlugin extends Plugin {
63
100
const formattedTitle = formatTitleForMacOS ( title ) ;
64
101
65
102
let formattedTitleWithExtension = "" ;
66
- if ( activeFile . parent ) {
103
+ if ( file . parent ) {
67
104
formattedTitleWithExtension = normalizePath (
68
- `${ activeFile . parent . path } /${ formattedTitle } .md`
105
+ `${ file . parent . path } /${ formattedTitle } .md`
69
106
) ;
70
107
} else {
71
108
formattedTitleWithExtension = `${ formattedTitle } .md` ;
72
109
}
73
110
74
- await this . app . vault . rename (
75
- activeFile ,
76
- formattedTitleWithExtension
77
- ) ;
111
+ await this . app . vault . rename ( file , formattedTitleWithExtension ) ;
78
112
new Notice ( `Renamed file to ${ formattedTitleWithExtension } ` ) ;
79
113
} catch ( error ) {
80
114
new Notice ( "Failed to rename file" ) ;
0 commit comments