1
- import { FrontMatterCache , Notice , Plugin , TFile } from 'obsidian' ;
1
+ import { Notice , Plugin , TFile , TFolder } from 'obsidian' ;
2
2
import { DEFAULT_SETTINGS , MediaDbPluginSettings , MediaDbSettingTab } from './settings/Settings' ;
3
3
import { APIManager } from './api/APIManager' ;
4
4
import { MediaTypeModel } from './models/MediaTypeModel' ;
5
- import { replaceIllegalFileNameCharactersInString } from './utils/Utils' ;
5
+ import { dateTimeToString , markdownTable , replaceIllegalFileNameCharactersInString } from './utils/Utils' ;
6
6
import { OMDbAPI } from './api/apis/OMDbAPI' ;
7
7
import { MediaDbAdvancedSearchModal } from './modals/MediaDbAdvancedSearchModal' ;
8
8
import { MediaDbSearchResultModal } from './modals/MediaDbSearchResultModal' ;
@@ -14,6 +14,7 @@ import {MediaTypeManager} from './utils/MediaTypeManager';
14
14
import { SteamAPI } from './api/apis/SteamAPI' ;
15
15
import { ModelPropertyMapper } from './settings/ModelPropertyMapper' ;
16
16
import { YAMLConverter } from './utils/YAMLConverter' ;
17
+ import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal' ;
17
18
18
19
export default class MediaDbPlugin extends Plugin {
19
20
settings : MediaDbPluginSettings ;
@@ -30,6 +31,16 @@ export default class MediaDbPlugin extends Plugin {
30
31
) ;
31
32
ribbonIconEl . addClass ( 'obsidian-media-db-plugin-ribbon-class' ) ;
32
33
34
+ this . registerEvent ( this . app . workspace . on ( 'file-menu' , ( menu , file ) => {
35
+ if ( file instanceof TFolder ) {
36
+ menu . addItem ( item => {
37
+ item . setTitle ( 'Create Media DB entries from folder' )
38
+ . setIcon ( 'database' )
39
+ . onClick ( ( ) => this . createEntriesFromFolder ( file as TFolder ) ) ;
40
+ } ) ;
41
+ }
42
+ } ) ) ;
43
+
33
44
// register command to open search modal
34
45
this . addCommand ( {
35
46
id : 'open-media-db-search-modal' ,
@@ -74,16 +85,23 @@ export default class MediaDbPlugin extends Plugin {
74
85
this . modelPropertyMapper = new ModelPropertyMapper ( this . settings ) ;
75
86
}
76
87
77
- async createMediaDbNote ( modal : ( ) => Promise < MediaTypeModel > ) : Promise < void > {
88
+ async createMediaDbNote ( modal : ( ) => Promise < MediaTypeModel [ ] > ) : Promise < void > {
89
+ let models : MediaTypeModel [ ] = [ ] ;
78
90
try {
79
- let data : MediaTypeModel = await modal ( ) ;
80
- data = await this . apiManager . queryDetailedInfo ( data ) ;
81
-
82
- await this . createMediaDbNoteFromModel ( data ) ;
91
+ models = await modal ( ) ;
83
92
} catch ( e ) {
84
93
console . warn ( e ) ;
85
94
new Notice ( e . toString ( ) ) ;
86
95
}
96
+
97
+ for ( const model of models ) {
98
+ try {
99
+ await this . createMediaDbNoteFromModel ( await this . apiManager . queryDetailedInfo ( model ) ) ;
100
+ } catch ( e ) {
101
+ console . warn ( e ) ;
102
+ new Notice ( e . toString ( ) ) ;
103
+ }
104
+ }
87
105
}
88
106
89
107
async createMediaDbNoteFromModel ( mediaTypeModel : MediaTypeModel ) : Promise < void > {
@@ -126,44 +144,23 @@ export default class MediaDbPlugin extends Plugin {
126
144
}
127
145
}
128
146
129
- async openMediaDbAdvancedSearchModal ( ) : Promise < MediaTypeModel > {
130
- return new Promise ( ( ( resolve , reject ) => {
131
- new MediaDbAdvancedSearchModal ( this . app , this , ( err , results ) => {
132
- if ( err ) return reject ( err ) ;
133
- new MediaDbSearchResultModal ( this . app , this , results , ( err2 , res ) => {
134
- if ( err2 ) return reject ( err2 ) ;
135
- resolve ( res ) ;
136
- } ) . open ( ) ;
137
- } ) . open ( ) ;
138
- } ) ) ;
139
- }
140
-
141
- async openMediaDbIdSearchModal ( ) : Promise < MediaTypeModel > {
142
- return new Promise ( ( ( resolve , reject ) => {
143
- new MediaDbIdSearchModal ( this . app , this , ( err , res ) => {
144
- if ( err ) return reject ( err ) ;
145
- resolve ( res ) ;
146
- } ) . open ( ) ;
147
- } ) ) ;
148
- }
149
-
150
147
async updateActiveNote ( ) {
151
148
const activeFile : TFile = this . app . workspace . getActiveFile ( ) ;
152
149
if ( ! activeFile ) {
153
150
throw new Error ( 'MDB | there is no active note' ) ;
154
151
}
155
152
156
153
let metadata : any = this . app . metadataCache . getFileCache ( activeFile ) . frontmatter ;
154
+ metadata = JSON . parse ( JSON . stringify ( metadata ) ) ; // deep copy
157
155
delete metadata . position ; // remove unnecessary data from the FrontMatterCache
158
156
metadata = this . modelPropertyMapper . convertObjectBack ( metadata ) ;
159
157
160
- console . log ( metadata )
158
+ console . log ( metadata ) ;
161
159
162
160
if ( ! metadata ?. type || ! metadata ?. dataSource || ! metadata ?. id ) {
163
161
throw new Error ( 'MDB | active note is not a Media DB entry or is missing metadata' ) ;
164
162
}
165
163
166
-
167
164
let oldMediaTypeModel = this . mediaTypeManager . createMediaTypeModelFromMediaType ( metadata , metadata . type ) ;
168
165
169
166
let newMediaTypeModel = await this . apiManager . queryDetailedInfoById ( metadata . id , metadata . dataSource ) ;
@@ -178,6 +175,94 @@ export default class MediaDbPlugin extends Plugin {
178
175
await this . createMediaDbNoteFromModel ( newMediaTypeModel ) ;
179
176
}
180
177
178
+ async createEntriesFromFolder ( folder : TFolder ) {
179
+ const erroredFiles : { filePath : string , error : string } [ ] = [ ] ;
180
+
181
+ const { selectedAPI, titleFieldName} = await new Promise ( ( resolve , reject ) => {
182
+ new MediaDbFolderImportModal ( this . app , this , ( ( selectedAPI , titleFieldName ) => {
183
+ resolve ( { selectedAPI, titleFieldName} ) ;
184
+ } ) ) . open ( ) ;
185
+ } ) ;
186
+
187
+ const selectedAPIs = { } ;
188
+ for ( const api of this . apiManager . apis ) {
189
+ // @ts -ignore
190
+ selectedAPIs [ api . apiName ] = api . apiName === selectedAPI ;
191
+ }
192
+
193
+ for ( const child of folder . children ) {
194
+ if ( child instanceof TFile ) {
195
+ const file = child as TFile ;
196
+ let metadata : any = this . app . metadataCache . getFileCache ( file ) . frontmatter ;
197
+
198
+ let title = metadata [ titleFieldName ] ;
199
+ if ( ! title ) {
200
+ erroredFiles . push ( { filePath : file . path , error : `metadata field \'${ titleFieldName } \' not found or empty` } ) ;
201
+ continue ;
202
+ }
203
+
204
+ let results : MediaTypeModel [ ] = [ ] ;
205
+ try {
206
+ results = await this . apiManager . query ( title , selectedAPIs ) ;
207
+ } catch ( e ) {
208
+ erroredFiles . push ( { filePath : file . path , error : e . toString ( ) } ) ;
209
+ continue ;
210
+ }
211
+ if ( ! results || results . length === 0 ) {
212
+ erroredFiles . push ( { filePath : file . path , error : `no search results` } ) ;
213
+ continue ;
214
+ }
215
+
216
+ let selectedResults : MediaTypeModel [ ] = await new Promise ( ( resolve , reject ) => {
217
+ const searchResultModal = new MediaDbSearchResultModal ( this . app , this , results , ( err , res ) => {
218
+ if ( err ) return reject ( err ) ;
219
+ resolve ( res ) ;
220
+ } ) ;
221
+ searchResultModal . title = `Results for \'${ title } \'` ;
222
+ searchResultModal . open ( ) ;
223
+ } ) ;
224
+
225
+ await this . createMediaDbNote ( async ( ) => selectedResults ) ;
226
+ }
227
+ }
228
+
229
+ if ( erroredFiles . length > 0 ) {
230
+ const title = `bulk import error report ${ dateTimeToString ( new Date ( ) ) } ` ;
231
+ const filePath = `${ this . settings . folder . replace ( / \/ $ / , '' ) } /${ title } .md` ;
232
+
233
+ const table = [ [ 'file' , 'error' ] ] . concat ( erroredFiles . map ( x => [ x . filePath , x . error ] ) ) ;
234
+ // console.log(table)
235
+ let fileContent = `# ${ title } \n\n${ markdownTable ( table ) } ` ;
236
+
237
+ const targetFile = await this . app . vault . create ( filePath , fileContent ) ;
238
+ }
239
+ }
240
+
241
+ async openMediaDbAdvancedSearchModal ( ) : Promise < MediaTypeModel [ ] > {
242
+ return new Promise ( ( ( resolve , reject ) => {
243
+ new MediaDbAdvancedSearchModal ( this . app , this , ( err , results ) => {
244
+ if ( err ) {
245
+ return reject ( err ) ;
246
+ }
247
+ new MediaDbSearchResultModal ( this . app , this , results , ( err2 , res ) => {
248
+ if ( err2 ) {
249
+ return reject ( err2 ) ;
250
+ }
251
+ resolve ( res ) ;
252
+ } ) . open ( ) ;
253
+ } ) . open ( ) ;
254
+ } ) ) ;
255
+ }
256
+
257
+ async openMediaDbIdSearchModal ( ) : Promise < MediaTypeModel > {
258
+ return new Promise ( ( ( resolve , reject ) => {
259
+ new MediaDbIdSearchModal ( this . app , this , ( err , res ) => {
260
+ if ( err ) return reject ( err ) ;
261
+ resolve ( res ) ;
262
+ } ) . open ( ) ;
263
+ } ) ) ;
264
+ }
265
+
181
266
async loadSettings ( ) {
182
267
this . settings = Object . assign ( { } , DEFAULT_SETTINGS , await this . loadData ( ) ) ;
183
268
}
0 commit comments