diff --git a/src/app.js b/src/app.js index 7df9c3e5..1f2b2a3d 100644 --- a/src/app.js +++ b/src/app.js @@ -38,8 +38,7 @@ class ClapperApp extends AppBase { super.vfunc_open(files, hint); - this._openFiles(files); - this.activate(); + this._openFilesAsync(files).then(() => this.activate()).catch(debug); } _onWindowMap(window) diff --git a/src/appBase.js b/src/appBase.js index 565beffd..8ad55da4 100644 --- a/src/appBase.js +++ b/src/appBase.js @@ -1,5 +1,6 @@ const { Gio, GLib, GObject, Gtk } = imports.gi; const Debug = imports.src.debug; +const FileOps = imports.src.fileOps; const Menu = imports.src.menu; const Misc = imports.src.misc; @@ -59,9 +60,18 @@ class ClapperAppBase extends Gtk.Application ); } - _openFiles(files) + async _openFilesAsync(files) { - const [playlist, subs] = Misc.parsePlaylistFiles(files); + const urisArr = []; + + for(let file of files) { + /* If file is not a dir its URI will be returned in an array */ + const uris = await FileOps.getDirFilesUrisPromise(file).catch(debug); + if(uris && uris.length) + urisArr.push(...uris); + } + + const [playlist, subs] = Misc.parsePlaylistFiles(urisArr); const { player } = this.active_window.get_child(); if(playlist && playlist.length) diff --git a/src/dialogs.js b/src/dialogs.js index 8b378a93..c1f7b654 100644 --- a/src/dialogs.js +++ b/src/dialogs.js @@ -62,7 +62,7 @@ class ClapperFileChooser extends Gtk.FileChooserNative if(isHandlesOpen) application.open(filesArray, ""); else - application._openFiles(filesArray); + application._openFilesAsync(filesArray); } this.unref(); diff --git a/src/fileOps.js b/src/fileOps.js index e5cc839e..af4d4617 100644 --- a/src/fileOps.js +++ b/src/fileOps.js @@ -12,6 +12,11 @@ const LocalFilePrototype = Gio.File.new_for_path('/').constructor.prototype; Gio._promisify(LocalFilePrototype, 'load_bytes_async', 'load_bytes_finish'); Gio._promisify(LocalFilePrototype, 'make_directory_async', 'make_directory_finish'); Gio._promisify(LocalFilePrototype, 'replace_contents_bytes_async', 'replace_contents_finish'); +Gio._promisify(LocalFilePrototype, 'query_info_async', 'query_info_finish'); +Gio._promisify(LocalFilePrototype, 'enumerate_children_async', 'enumerate_children_finish'); + +Gio._promisify(Gio.FileEnumerator.prototype, 'close_async', 'close_finish'); +Gio._promisify(Gio.FileEnumerator.prototype, 'next_files_async', 'next_files_finish'); function createCacheDirPromise() { @@ -126,3 +131,91 @@ function getFileContentsPromise(place, subdirName, fileName) .catch(err => reject(err)); }); } + +function _getDirUrisPromise(dir, isDeep) +{ + return new Promise(async (resolve, reject) => { + const enumerator = await dir.enumerate_children_async( + 'standard::name,standard::type', + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_DEFAULT, + null + ).catch(debug); + + if(!enumerator) + return reject(new Error('could not create file enumerator')); + + const dirPath = dir.get_path(); + const arr = []; + + debug(`enumerating files in dir: ${dirPath}`); + + while(true) { + const infos = await enumerator.next_files_async( + 1, + GLib.PRIORITY_DEFAULT, + null + ).catch(debug); + + if(!infos || !infos.length) + break; + + const fileUri = dir.get_uri() + '/' + infos[0].get_name(); + + if(infos[0].get_file_type() !== Gio.FileType.DIRECTORY) { + arr.push(fileUri); + continue; + } + if(!isDeep) + continue; + + const subDir = Misc.getFileFromLocalUri(fileUri); + const subDirUris = await _getDirUrisPromise(subDir, isDeep).catch(debug); + + if(subDirUris && subDirUris.length) + arr.push(...subDirUris); + } + + const isClosed = await enumerator.close_async( + GLib.PRIORITY_DEFAULT, + null + ).catch(debug); + + if(isClosed) + debug(`closed enumerator for dir: ${dirPath}`); + else + debug(new Error(`could not close file enumerator for dir: ${dirPath}`)); + + resolve(arr); + }); +} + +/* Either GioFile or URI for dir arg */ +function getDirFilesUrisPromise(dir, isDeep) +{ + return new Promise(async (resolve, reject) => { + if(!dir.get_path) + dir = Misc.getFileFromLocalUri(dir); + if(!dir) + return reject(new Error('invalid directory')); + + const fileInfo = await dir.query_info_async( + 'standard::type', + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_DEFAULT, + null + ).catch(debug); + + if(!fileInfo) + return reject(new Error('no file type info')); + + if(fileInfo.get_file_type() !== Gio.FileType.DIRECTORY) + return resolve([dir.get_uri()]); + + const arr = await _getDirUrisPromise(dir, isDeep).catch(debug); + if(!arr || !arr.length) + return reject(new Error('enumerated files list is empty')); + + resolve(arr.sort()); + }); +}