diff --git a/randomwallpaper@iflow.space/extension.js b/randomwallpaper@iflow.space/extension.js index 295bb14..c50ea9e 100644 --- a/randomwallpaper@iflow.space/extension.js +++ b/randomwallpaper@iflow.space/extension.js @@ -6,6 +6,8 @@ const Shell = imports.gi.Shell; const Self = imports.misc.extensionUtils.getCurrentExtension(); const WallpaperController = Self.imports.wallpaperController; +const LoggerModule = Self.imports.logger; + // UI Imports const Main = imports.ui.main; const St = imports.gi.St; @@ -33,9 +35,11 @@ let panelEntry; let RandomWallpaperEntry = new Lang.Class({ Extends: PanelMenu.Button, Name: "RandomWallpaperEntry", + logger: null, _init: function(menuAlignment, nameText) { this.parent(menuAlignment, nameText); + this.logger = new LoggerModule.Logger('RWG3', 'RandomWallpaperEntry'); // Panelmenu Icon this.statusIcon = new CustomElements.StatusElement(); @@ -110,15 +114,16 @@ let RandomWallpaperEntry = new Lang.Class({ setHistoryList: function() { this.historySection.removeAll(); - let history = this.history = wallpaperController.getHistory(); + let historyController = wallpaperController.getHistoryController(); + let history = historyController.history; if (history.length <= 1) { this.clearHistoryList(); return; - }; + } - for (var i = 1; i < history.length; i++) { - let historyid = history[i]; + for (let i = 1; i < history.length; i++) { + let historyid = history[i].id; let tmp = new CustomElements.HistoryElement(historyid, i); tmp.actor.connect('key-focus-in', onEnter); @@ -128,7 +133,7 @@ let RandomWallpaperEntry = new Lang.Class({ tmp.connect('activate', onSelect); this.historySection.addMenuItem(tmp); - }; + } function onLeave(actor) { wallpaperController.resetWallpaper(); diff --git a/randomwallpaper@iflow.space/history.js b/randomwallpaper@iflow.space/history.js new file mode 100644 index 0000000..ff89eb8 --- /dev/null +++ b/randomwallpaper@iflow.space/history.js @@ -0,0 +1,154 @@ +const Lang = imports.lang; +const Mainloop = imports.gi.GLib; + +// Filesystem +const Gio = imports.gi.Gio; + +const Self = imports.misc.extensionUtils.getCurrentExtension(); +const Prefs = Self.imports.settings; + +const LoggerModule = Self.imports.logger; + +let HistoryEntry = new Lang.Class({ + Name: "HistoryEntry", + timestamp: null, + id: null, + path: null, + src: null, + + _init: function(historyId, path, src) { + this.timestamp = new Date().getTime(); + this.id = historyId; + this.path = path; + this.src = src; + }, +}); + +let HistoryController = new Lang.Class({ + Name: "HistoryController", + _settings: null, + _wallpaperlocation: null, + + logger: null, + size: 10, + history: [], + + _init: function(wallpaperlocation) { + this.logger = new LoggerModule.Logger('RWG3', 'HistoryController'); + + this._settings = new Prefs.Settings(); + this._wallpaperlocation = wallpaperlocation; + + this.load(); + }, + + insert: function(historyElement) { + this.history.unshift(historyElement); + this._deleteOldPictures(); + this.save(); + }, + + /** + * Set the given id to to the first history element (the current one) + * @param id + * @returns {boolean} + */ + promoteToActive: function(id) { + let element = this.get(id); + if (element === null) { + return false; + } + + element.timestamp = new Date().getTime(); + this.history = this.history.sort((elem1, elem2) => { return elem1.timestamp < elem2.timestamp }); + this.save(); + + return true; + }, + + /** + * Returns the corresponding HistoryEntry or null + * @param id + * @returns {*} + */ + get: function(id) { + for (let elem of this.history) { + if (elem.id == id) { + return elem; + } + } + + return null; + }, + + /** + * Load the history from the gschema + */ + load: function() { + this.size = this._settings.get('history-length', 'int'); + let stringHistory = this._settings.get('history', 'strv'); + this.history = stringHistory.map(elem => { + return JSON.parse(elem) + }); + }, + + /** + * Save the history to the gschema + */ + save: function() { + let stringHistory = this.history.map(elem => { return JSON.stringify(elem) }); + this._settings.set('history', 'strv', stringHistory); + }, + + /** + * Clear the history and delete all photos except the current one. + * @returns {boolean} + */ + clear() { + let firstHistoryElement = this.history[0]; + + if (firstHistoryElement) + this.history = [firstHistoryElement]; + + let directory = Gio.file_new_for_path(this._wallpaperlocation); + let enumerator = directory.enumerate_children('', Gio.FileQueryInfoFlags.NONE, null); + + let fileinfo; + let deleteFile; + + do { + + fileinfo = enumerator.next_file(null); + + if (!fileinfo) { + break; + } + + let id = fileinfo.get_name(); + + // ignore hidden files and first element + if (id[0] != '.' && id != firstHistoryElement.id) { + deleteFile = Gio.file_new_for_path(this._wallpaperlocation + id); + deleteFile.delete(null); + } + + } while(fileinfo); + + this.save(); + return true; + }, + + /** + * Delete all pictures that have no slot in the history. + * @private + */ + _deleteOldPictures: function() { + this.size = this._settings.get('history-length', 'int'); + let deleteFile; + while(this.history.length > this.size) { + deleteFile = Gio.file_new_for_path(this.history.pop().path); + deleteFile.delete(null); + } + }, + +}); \ No newline at end of file diff --git a/randomwallpaper@iflow.space/logger.js b/randomwallpaper@iflow.space/logger.js index 61b2356..d0a4fc0 100644 --- a/randomwallpaper@iflow.space/logger.js +++ b/randomwallpaper@iflow.space/logger.js @@ -22,7 +22,7 @@ let Logger = new Lang.Class({ this._log("INFO", message); }, - warning: function (message) { + warn: function (message) { this._log("WARNING", message); }, diff --git a/randomwallpaper@iflow.space/sourceAdapter.js b/randomwallpaper@iflow.space/sourceAdapter.js index 6dfcc07..66512c4 100644 --- a/randomwallpaper@iflow.space/sourceAdapter.js +++ b/randomwallpaper@iflow.space/sourceAdapter.js @@ -9,8 +9,8 @@ const LoggerModule = Self.imports.logger; let BaseAdapter = new Lang.Class({ Name: "BaseAdapter", + logger: null, - logge: null, _init: function () { this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter'); @@ -18,6 +18,12 @@ let BaseAdapter = new Lang.Class({ requestRandomImage: function () { this.logger.error("requestRandomImage not implemented") + }, + + fileName: function(uri) + { + let base = new String(uri).substring(uri.lastIndexOf('/') + 1); + return base; } }); @@ -34,9 +40,7 @@ let DesktopperAdapter = new Lang.Class({ let parser = new Json.Parser(); - var _this = this; - - session.queue_message(message, function (session, message) { + session.queue_message(message, (session, message) => { parser.load_from_data(message.response_body.data, -1); let data = parser.get_root().get_object(); @@ -73,7 +77,7 @@ let WallheavenAdapter = new Lang.Class({ let options = this.options; let optionsString = ""; - for (var key in options) { + for (let key in options) { if (options.hasOwnProperty(key)) { if (Array.isArray(options[key])) { optionsString += key + "=" + options[key].join() + "&"; @@ -89,9 +93,7 @@ let WallheavenAdapter = new Lang.Class({ let message = Soup.Message.new('GET', url); - var _this = this; - - session.queue_message(message, function (session, message) { + session.queue_message(message, (session, message) => { let body = message.response_body.data; let urlArray = body.match(new RegExp(/http[s]*:\/\/alpha.wallhaven.cc\/wallpaper\/[0-9]+/g)); @@ -101,11 +103,11 @@ let WallheavenAdapter = new Lang.Class({ }); // get a random entry from the array - var url = uniqueUrlArray[Math.floor(Math.random() * uniqueUrlArray.length)]; + let url = uniqueUrlArray[Math.floor(Math.random() * uniqueUrlArray.length)]; message = Soup.Message.new('GET', url); - session.queue_message(message, function () { + session.queue_message(message, () => { let body = message.response_body.data; let imageUrl = body.match(new RegExp(/\/\/wallpapers.wallhaven.cc\/wallpapers\/full\/.*?"/))[0]; imageUrl = imageUrl.slice(0, -1); diff --git a/randomwallpaper@iflow.space/wallpaperController.js b/randomwallpaper@iflow.space/wallpaperController.js index 0025fc8..b359461 100644 --- a/randomwallpaper@iflow.space/wallpaperController.js +++ b/randomwallpaper@iflow.space/wallpaperController.js @@ -14,6 +14,7 @@ const SourceAdapter = Self.imports.sourceAdapter; const Convenience = Self.imports.convenience; const Prefs = Self.imports.settings; const Timer = Self.imports.timer; +const HistoryModule = Self.imports.history; const LoggerModule = Self.imports.logger; @@ -24,9 +25,8 @@ let WallpaperController = new Lang.Class({ wallpaperlocation: '', currentWallpaper: '', - historySize: 10, - history: [], - imageSourceAdapter: undefined, + _historyController: null, + imageSourceAdapter: null, _timer: null, _autoFetch : { @@ -44,6 +44,7 @@ let WallpaperController = new Lang.Class({ this.wallpaperlocation = this.extensionMeta.path + '/wallpapers/'; this._timer = new Timer.AFTimer(); + this._historyController = new HistoryModule.HistoryController(this.wallpaperlocation); this._settings = new Prefs.Settings(); this._settings.observe('history-length', this._updateHistory.bind(this)); @@ -54,7 +55,6 @@ let WallpaperController = new Lang.Class({ this._updateHistory(); this._updateAutoFetching(); - this.history = this._loadHistory(); this.currentWallpaper = this._getCurrentWallpaper(); this._desktopperAdapter = new SourceAdapter.DesktopperAdapter(); @@ -64,7 +64,7 @@ let WallpaperController = new Lang.Class({ }, _updateHistory: function() { - this.historySize = this._settings.get('history-length', 'int'); + this._historyController.load(); }, _updateAutoFetching: function() { @@ -108,20 +108,16 @@ let WallpaperController = new Lang.Class({ the written file as parameter. */ _fetchFile: function(uri, callback){ + //extract the name from the url and let date = new Date(); - let inputbuffer; - - //extract the name from the desktopper url and add timestamp prefix - let name = date.getTime() + uri.substr(uri.lastIndexOf('.')); + let name = date.getTime()+'_'+this.imageSourceAdapter.fileName(uri); // timestamp ensures uniqueness let output_file = Gio.file_new_for_path(this.wallpaperlocation + String(name)); let output_stream = output_file.create(0, null); let input_file = Gio.file_new_for_uri(uri); - let _this = this; - - input_file.load_contents_async(null, function(file, result){ + input_file.load_contents_async(null, (file, result) => { let contents = file.load_contents_finish(result)[1]; output_stream.write(contents, null); @@ -132,38 +128,8 @@ let WallpaperController = new Lang.Class({ }); }, - /* - Set a new timestamp as name for the given file - and adapt the history - */ - _setNewFileName: function(historyid) { - let date = new Date(); - let file = Gio.file_new_for_path(this.wallpaperlocation + historyid); - let name = date.getTime() + historyid.substr(historyid.lastIndexOf('.')); - let newFile = Gio.file_new_for_path(this.wallpaperlocation + name); - - for (var i = 0; i < this.history.length; i++) { - if(this.history[i] == historyid) { - file.move(newFile, Gio.FileCopyFlags.NONE, null, function(){ - }); - - // TODO: error handling, what if move fails? - - this.history[i] = name; - - this.history.sort(); - this.history.reverse(); - - return name; - } - } - - return false; - }, - _setBackground: function(path, callback){ let background_setting = new Gio.Settings({schema: "org.gnome.desktop.background"}); - this.deleteOldPictures(); /* inspired from: @@ -192,69 +158,36 @@ let WallpaperController = new Lang.Class({ return background_setting.get_string("picture-uri").replace(/^(file:\/\/)/, ""); }, - _loadHistory: function () { - let directory = Gio.file_new_for_path(this.wallpaperlocation); - let enumerator = directory.enumerate_children('', Gio.FileQueryInfoFlags.NONE, null); + setWallpaper: function(historyId) { + let historyElement = this._historyController.get(historyId); - let fileinfo; - let history = []; - - do { - fileinfo = enumerator.next_file(null); - - if (!fileinfo) { - break; - } - - let name = fileinfo.get_name(); - - // ignore hidden files - if (name[0] != '.') { - history.push(fileinfo.get_name()); - } - - } while(fileinfo); - - history.sort(); - history.reverse(); - - return history; - }, - - deleteOldPictures: function() { - this.historySize = this._settings.get('history-length', 'int'); - let deleteFile; - while(this.history.length > this.historySize) { - deleteFile = Gio.file_new_for_path(this.wallpaperlocation + this.history.pop()); - deleteFile.delete(null); + if(this._historyController.promoteToActive(historyElement.id)) { + this._setBackground(historyElement.path); + this.currentWallpaper = this._getCurrentWallpaper(); + } else { + this.logger.warn("The history id ("+historyElement.id+") could not be found.") + // TODO: Error handling history id not found. } }, - setWallpaper: function(historyEntry, keepName) { - if (!keepName) { - historyEntry = this._setNewFileName(historyEntry); - } - this._setBackground(this.wallpaperlocation + historyEntry); - this.currentWallpaper = this._getCurrentWallpaper(); - }, - fetchNewWallpaper: function(callback) { this._startLoadingHooks.forEach((element) => { element(); }); this._timer.begin(); // reset timer - let _this = this; this._requestRandomImageFromAdapter((imageUrl) => { - this.logger.debug("Requesting image: "+imageUrl); + this.logger.info("Requesting image: "+imageUrl); - _this._fetchFile(imageUrl, (historyid, path) => { - // insert file into history - _this.history.unshift(historyid); + this._fetchFile(imageUrl, (historyid, path) => { + let historyElement = new HistoryModule.HistoryEntry(historyid, path, imageUrl); + + this._setBackground(path, () => { + // insert file into history + this._historyController.insert(historyElement); - _this._setBackground(_this.wallpaperlocation + historyid, function(){ // call callback if given - _this._stopLoadingHooks.forEach((element) => { + this._stopLoadingHooks.forEach((element) => { element(null); }); if (callback) { @@ -270,16 +203,15 @@ let WallpaperController = new Lang.Class({ return; } - let _this = this; delay = delay || 200; - this.timeout = Mainloop.timeout_add(Mainloop.PRIORITY_DEFAULT, delay, function(){ - _this.timeout = null; - if (_this._resetWallpaper) { - _this._setBackground(_this.currentWallpaper); - _this._resetWallpaper = false; + this.timeout = Mainloop.timeout_add(Mainloop.PRIORITY_DEFAULT, delay, () => { + this.timeout = null; + if (this._resetWallpaper) { + this._setBackground(this.currentWallpaper); + this._resetWallpaper = false; } else { - _this._setBackground(_this.wallpaperlocation + _this.previewId); + this._setBackground(this.wallpaperlocation + this.previewId); } return false; }); @@ -297,41 +229,12 @@ let WallpaperController = new Lang.Class({ this._backgroundTimout(); }, - getHistory: function() { - return this.history; + getHistoryController: function() { + return this._historyController; }, deleteHistory: function() { - let firstHistoryElement = this.history[0]; - - if (firstHistoryElement) - this.history = [firstHistoryElement]; - - let directory = Gio.file_new_for_path(this.wallpaperlocation); - let enumerator = directory.enumerate_children('', Gio.FileQueryInfoFlags.NONE, null); - - let fileinfo; - let deleteFile; - - do { - - fileinfo = enumerator.next_file(null); - - if (!fileinfo) { - break; - }; - - let name = fileinfo.get_name(); - - // ignore hidden files and first element - if (name[0] != '.' && name != firstHistoryElement) { - deleteFile = Gio.file_new_for_path(this.wallpaperlocation + name); - deleteFile.delete(null); - }; - - } while(fileinfo); - - return true; + this._historyController.clear(); }, menuShowHook: function() {