616 lines
26 KiB
JavaScript
616 lines
26 KiB
JavaScript
// Bing Wallpaper GNOME extension
|
|
// Copyright (C) 2017-2021 Michael Carroll
|
|
// This extension is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
// See the GNU General Public License, version 3 or later for details.
|
|
// Based on GNOME shell extension NASA APOD by Elia Argentieri https://github.com/Elinvention/gnome-shell-extension-nasa-apod
|
|
|
|
const St = imports.gi.St;
|
|
const Main = imports.ui.main;
|
|
const MessageTray = imports.ui.messageTray;
|
|
const Soup = imports.gi.Soup;
|
|
const Lang = imports.lang;
|
|
const Mainloop = imports.mainloop;
|
|
const Gio = imports.gi.Gio;
|
|
const GLib = imports.gi.GLib;
|
|
const Gtk = imports.gi.Gtk;
|
|
const Util = imports.misc.util;
|
|
const PanelMenu = imports.ui.panelMenu;
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
const Clutter = imports.gi.Clutter;
|
|
const Cogl = imports.gi.Cogl;
|
|
const Clipboard = St.Clipboard.get_default();
|
|
const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;
|
|
const UnlockDialog = imports.ui.unlockDialog.UnlockDialog;
|
|
// const Background = imports.ui.background;
|
|
|
|
const ExtensionUtils = imports.misc.extensionUtils;
|
|
const Me = ExtensionUtils.getCurrentExtension();
|
|
const Utils = Me.imports.utils;
|
|
const Blur = Me.imports.blur;
|
|
|
|
const Convenience = Me.imports.convenience;
|
|
const Gettext = imports.gettext.domain('BingWallpaper');
|
|
const _ = Gettext.gettext;
|
|
|
|
const BingImageURL = Utils.BingImageURL;
|
|
const BingURL = "https://www.bing.com";
|
|
const IndicatorName = "BingWallpaperIndicator";
|
|
const TIMEOUT_SECONDS = 24 * 3600; // FIXME: this should use the end data from the json data
|
|
const TIMEOUT_SECONDS_ON_HTTP_ERROR = 1 * 3600; // retry in one hour if there is a http error
|
|
|
|
let validresolutions = [ '800x600' , '1024x768', '1280x720', '1280x768', '1366x768', '1920x1080', '1920x1200', 'UHD'];
|
|
|
|
let autores; // automatically selected resolution
|
|
|
|
let bingWallpaperIndicator=null;
|
|
let blur=null;
|
|
let init_called=false;
|
|
let blur_brightness=0.55;
|
|
let blur_strength=30;
|
|
|
|
// remove this when dropping support for < 3.33, see https://github.com/OttoAllmendinger/
|
|
const getActorCompat = (obj) =>
|
|
Convenience.currentVersionGreaterEqual("3.33") ? obj : obj.actor;
|
|
|
|
function log(msg) {
|
|
if (bingWallpaperIndicator==null || bingWallpaperIndicator._settings.get_boolean('debug-logging'))
|
|
print("BingWallpaper extension: " + msg); // disable to keep the noise down in journal
|
|
}
|
|
|
|
// Utility function
|
|
function dump(object) {
|
|
let output = '';
|
|
for (let property in object) {
|
|
output += property + ': ' + object[property]+'; ';
|
|
}
|
|
log(output);
|
|
}
|
|
|
|
function notifyError(msg) {
|
|
Main.notifyError("BingWallpaper extension error", msg);
|
|
}
|
|
|
|
function doSetBackground(uri, schema) {
|
|
let gsettings = new Gio.Settings({schema: schema});
|
|
let prev = gsettings.get_string('picture-uri');
|
|
uri = 'file://'+ uri;
|
|
gsettings.set_string('picture-uri', uri);
|
|
gsettings.set_string('picture-options', 'zoom');
|
|
Gio.Settings.sync();
|
|
gsettings.apply();
|
|
return (prev != uri); // return true if background uri has changed
|
|
}
|
|
|
|
function friendly_time_diff(time, short = true) {
|
|
// short we want to keep ~4-5 characters
|
|
let timezone = GLib.TimeZone.new_local();
|
|
let now = GLib.DateTime.new_now(timezone).to_unix();
|
|
let seconds = time.to_unix() - now;
|
|
|
|
if (seconds <= 0) {
|
|
return "now";
|
|
}
|
|
else if (seconds < 60) {
|
|
return "< 1 "+(short?"m":_("minutes"));
|
|
}
|
|
else if (seconds < 3600) {
|
|
return Math.round(seconds/60)+" "+(short?"m":_("minutes"));
|
|
}
|
|
else if (seconds > 86400) {
|
|
return Math.round(seconds/86400)+" "+(short?"d":_("days"));
|
|
}
|
|
else {
|
|
return Math.round(seconds/3600)+" "+(short?"h":_("hours"));
|
|
}
|
|
}
|
|
|
|
let httpSession = new Soup.SessionAsync();
|
|
Soup.Session.prototype.add_feature.call(httpSession, new Soup.ProxyResolverDefault());
|
|
|
|
const BingWallpaperIndicator = new Lang.Class({
|
|
Name: IndicatorName,
|
|
Extends: PanelMenu.Button,
|
|
|
|
_init: function() {
|
|
this.parent(0.0, IndicatorName);
|
|
|
|
this.title = "";
|
|
this.explanation = "";
|
|
this.filename = "";
|
|
this.copyright = "";
|
|
this.version = "0.1";
|
|
this._updatePending = false;
|
|
this._timeout = null;
|
|
this.longstartdate = null;
|
|
this.imageURL= ""; // link to image itself
|
|
this.imageinfolink = ""; // link to Bing photo info page
|
|
this.refreshdue = 0;
|
|
this.refreshduetext = "";
|
|
this.thumbnail = null;
|
|
blur = new Blur.Blur();
|
|
blur.blur_strength = 30;
|
|
blur.blur_brightness = 0.55;
|
|
|
|
// take a variety of actions when the gsettings values are modified by prefs
|
|
this._settings = Utils.getSettings();
|
|
this._settings.connect('changed::hide', Lang.bind(this, function() {
|
|
getActorCompat(this).visible = !this._settings.get_boolean('hide');
|
|
}));
|
|
this._setIcon(this._settings.get_string('icon-name'));
|
|
this._settings.connect('changed::icon-name', Lang.bind(this, function() {
|
|
this._setIcon(this._settings.get_string('icon-name'));
|
|
}));
|
|
this._settings.connect('changed::market', Lang.bind(this, function() {
|
|
this._refresh();
|
|
}));
|
|
this._settings.connect('changed::set-background', Lang.bind(this, function() {
|
|
this._setBackground();
|
|
}));
|
|
this._settings.connect('changed::set-lockscreen', Lang.bind(this, function() {
|
|
this._setBackground();
|
|
}));
|
|
this._settings.connect('changed::override-lockscreen-blur', Lang.bind(this, function () {
|
|
blur._switch(this._settings.get_boolean('override-lockscreen-blur'));
|
|
blur.set_blur_strength(this._settings.get_int('lockscreen-blur-strength'));
|
|
blur.set_blur_brightness(this._settings.get_int('lockscreen-blur-brightness'));
|
|
}));
|
|
this._settings.connect('changed::lockscreen-blur-strength', Lang.bind(this, function () {
|
|
blur.set_blur_strength(this._settings.get_int('lockscreen-blur-strength'));
|
|
}));
|
|
this._settings.connect('changed::lockscreen-blur-brightness', Lang.bind(this, function () {
|
|
blur.set_blur_brightness(this._settings.get_int('lockscreen-blur-brightness'));
|
|
}));
|
|
blur._switch(this._settings.get_boolean('override-lockscreen-blur'));
|
|
blur.set_blur_strength(this._settings.get_int('lockscreen-blur-strength'));
|
|
blur.set_blur_brightness(this._settings.get_int('lockscreen-blur-brightness'));
|
|
|
|
getActorCompat(this).visible = !this._settings.get_boolean('hide');
|
|
|
|
this.refreshDueItem = new PopupMenu.PopupMenuItem(_("<No refresh scheduled>"));
|
|
//this.showItem = new PopupMenu.PopupMenuItem(_("Show description"));
|
|
this.titleItem = new PopupMenu.PopupMenuItem(_("Awaiting refresh...")); //FIXME: clean this up
|
|
this.titleItem.label.get_clutter_text().set_line_wrap(true);
|
|
this.titleItem.label.set_style("max-width: 350px;");
|
|
this.explainItem = new PopupMenu.PopupMenuItem(_("Awaiting refresh..."));
|
|
this.explainItem.label.get_clutter_text().set_line_wrap(true);
|
|
this.explainItem.label.set_style("max-width: 350px;");
|
|
this.copyrightItem = new PopupMenu.PopupMenuItem(_("Awaiting refresh..."));
|
|
this.copyrightItem.label.get_clutter_text().set_line_wrap(true);
|
|
this.copyrightItem.label.set_style("max-width: 350px;");
|
|
this.separator = new PopupMenu.PopupSeparatorMenuItem();
|
|
this.clipboardImageItem = new PopupMenu.PopupMenuItem(_("Copy image to clipboard"));
|
|
this.clipboardURLItem = new PopupMenu.PopupMenuItem(_("Copy image URL to clipboard"));
|
|
this.dwallpaperItem = new PopupMenu.PopupMenuItem(_("Set background image"));
|
|
this.swallpaperItem = new PopupMenu.PopupMenuItem(_("Set lock screen image"));
|
|
this.refreshItem = new PopupMenu.PopupMenuItem(_("Refresh Now"));
|
|
this.settingsItem = new PopupMenu.PopupMenuItem(_("Settings"));
|
|
if (Utils.is_x11()) { // causes crashes when XWayland is not available, ref github #82
|
|
this.thumbnailItem = new PopupMenu.PopupBaseMenuItem(); // new Gtk.AspectFrame('Preview',0.5, 0.5, 1.77, false);
|
|
}
|
|
else {
|
|
this.thumbnailItem = new PopupMenu.PopupMenuItem(_("Thumbnail disabled on Wayland"));
|
|
log('X11 not detected, disabling some unsafe features');
|
|
}
|
|
this.menu.addMenuItem(this.refreshItem);
|
|
this.menu.addMenuItem(this.refreshDueItem);
|
|
this.menu.addMenuItem(this.titleItem);
|
|
this.menu.addMenuItem(this.thumbnailItem);
|
|
this.menu.addMenuItem(this.explainItem);
|
|
this.menu.addMenuItem(this.copyrightItem);
|
|
//this.menu.addMenuItem(this.showItem);
|
|
this.menu.addMenuItem(this.separator);
|
|
if (Utils.is_x11()) { // these do not work on Wayland atm
|
|
this.menu.addMenuItem(this.clipboardImageItem);
|
|
this.menu.addMenuItem(this.clipboardURLItem);
|
|
this.clipboardURLItem.connect('activate', Lang.bind(this, this._copyURLToClipboard));
|
|
this.clipboardImageItem.connect('activate', Lang.bind(this, this._copyImageToClipboard));
|
|
}
|
|
|
|
this.menu.addMenuItem(this.dwallpaperItem);
|
|
if (!Convenience.currentVersionGreaterEqual("3.36")) { // lockscreen and desktop wallpaper are the same in GNOME 3.36+
|
|
this.menu.addMenuItem(this.swallpaperItem);
|
|
this.swallpaperItem.connect('activate', Lang.bind(this, this._setBackgroundScreensaver));
|
|
}
|
|
|
|
this.menu.addMenuItem(this.settingsItem);
|
|
this.explainItem.setSensitive(false);
|
|
this.copyrightItem.setSensitive(false);
|
|
this.refreshDueItem.setSensitive(false);
|
|
this.thumbnailItem.setSensitive(false);
|
|
this.titleItem.connect('activate', Lang.bind(this, function() {
|
|
if (this.imageinfolink)
|
|
Util.spawn(["xdg-open", this.imageinfolink]);
|
|
}));
|
|
|
|
this.dwallpaperItem.connect('activate', Lang.bind(this, this._setBackgroundDesktop));
|
|
this.refreshItem.connect('activate', Lang.bind(this, this._refresh));
|
|
this.settingsItem.connect('activate', function() {
|
|
if (ExtensionUtils.openPrefs)
|
|
ExtensionUtils.openPrefs();
|
|
else
|
|
Util.spawn(["gnome-extensions", "prefs", Me.metadata.uuid]); // fall back for older gnome versions
|
|
});
|
|
|
|
getActorCompat(this).connect('button-press-event', Lang.bind(this, function () {
|
|
// Grey out menu items if an update is pending
|
|
this.refreshItem.setSensitive(!this._updatePending);
|
|
if (Utils.is_x11()) {
|
|
this.clipboardImageItem.setSensitive(!this._updatePending && this.imageURL != "");
|
|
this.clipboardURLItem.setSensitive(!this._updatePending && this.imageURL != "");
|
|
}
|
|
this.thumbnailItem.setSensitive(!this._updatePending && this.imageURL != "");
|
|
//this.showItem.setSensitive(!this._updatePending && this.title != "" && this.explanation != "");
|
|
this.dwallpaperItem.setSensitive(!this._updatePending && this.filename != "");
|
|
this.swallpaperItem.setSensitive(!this._updatePending && this.filename != "");
|
|
this.titleItem.setSensitive(!this._updatePending && this.imageinfolink != "");
|
|
this.refreshduetext = _("Next refresh") + ": " + this.refreshdue.format("%X") + " (" + friendly_time_diff(this.refreshdue) + ")";
|
|
this.refreshDueItem.label.set_text(this.refreshduetext); //
|
|
}));
|
|
this._restartTimeout(60); // wait 60 seconds before performing refresh
|
|
},
|
|
|
|
// set indicator icon (tray icon)
|
|
_setIcon: function(icon_name) {
|
|
//log('Icon set to : '+icon_name)
|
|
Utils.validate_icon(this._settings);
|
|
let gicon = Gio.icon_new_for_string(Me.dir.get_child('icons').get_path() + "/" + icon_name + ".svg");
|
|
this.icon = new St.Icon({gicon: gicon, style_class: 'system-status-icon'});
|
|
if (!this.icon.get_parent() && 0) {
|
|
log('New icon set to : '+icon_name);
|
|
getActorCompat(this).add_child(this.icon);
|
|
}
|
|
else {
|
|
log('Replace icon set to : '+icon_name);
|
|
getActorCompat(this).remove_all_children();
|
|
getActorCompat(this).add_child(this.icon);
|
|
}
|
|
},
|
|
|
|
// set backgrounds as requested and set preview image in menu
|
|
_setBackground: function() {
|
|
if (this.filename == "")
|
|
return;
|
|
if (Utils.is_x11()) { // wayland - only if we are sure it's safe to do so, we can't know if xwayland is running
|
|
this.thumbnail = new Thumbnail(this.filename);
|
|
this._setImage();
|
|
}
|
|
|
|
if (this._settings.get_boolean('set-background'))
|
|
this._setBackgroundDesktop();
|
|
|
|
if (this._settings.get_boolean('set-lock-screen'))
|
|
this._setBackgroundScreensaver();
|
|
},
|
|
|
|
_setBackgroundDesktop: function() {
|
|
doSetBackground(this.filename, 'org.gnome.desktop.background');
|
|
},
|
|
|
|
_setBackgroundScreensaver: function() {
|
|
doSetBackground(this.filename, 'org.gnome.desktop.screensaver');
|
|
},
|
|
|
|
_copyURLToClipboard: function() {
|
|
Clipboard.set_text(CLIPBOARD_TYPE, this.imageURL);
|
|
},
|
|
|
|
_copyImageToClipboard: function() {
|
|
Clipboard.setImage(this.thumbnailImage.gtkImage);
|
|
},
|
|
|
|
// sets a timer for next refresh of Bing metadata
|
|
_restartTimeout: function(seconds = null) {
|
|
if (this._timeout)
|
|
Mainloop.source_remove(this._timeout);
|
|
if (seconds == null)
|
|
seconds = TIMEOUT_SECONDS;
|
|
this._timeout = Mainloop.timeout_add_seconds(seconds, Lang.bind(this, this._refresh));
|
|
let timezone = GLib.TimeZone.new_local();
|
|
let localTime = GLib.DateTime.new_now(timezone).add_seconds(seconds);
|
|
this.refreshdue = localTime;
|
|
log('next check in '+seconds+' seconds @ local time '+localTime);
|
|
},
|
|
|
|
// set a timer on when the current image is going to expire
|
|
_restartTimeoutFromLongDate: function (longdate) {
|
|
// longdate is UTC, in the following format
|
|
// 201708041400 YYYYMMDDHHMM
|
|
// 012345678901
|
|
let timezone = GLib.TimeZone.new_utc(); // all bing times are in UTC (+0)
|
|
let refreshDue = GLib.DateTime.new(timezone,
|
|
parseInt(longdate.substr(0,4)), // year
|
|
parseInt(longdate.substr(4,2)), // month
|
|
parseInt(longdate.substr(6,2)), // day
|
|
parseInt(longdate.substr(8,2)), // hour
|
|
parseInt(longdate.substr(10,2)), // mins
|
|
0 ).add_seconds(86400); // seconds
|
|
|
|
let now = GLib.DateTime.new_now(timezone);
|
|
let difference = refreshDue.difference(now)/1000000;
|
|
|
|
log("Next refresh due @ "+refreshDue.format('%F %R %z')+" = "+difference+" seconds from now ("+now.format('%F %R %z')+")");
|
|
|
|
if (difference < 60 || difference > 86400) // something wierd happened
|
|
difference = 3600;
|
|
|
|
difference=difference+300; // 5 minute fudge offset in case of inaccurate local clock
|
|
this._restartTimeout(difference);
|
|
},
|
|
|
|
// convert shortdate format into human friendly format
|
|
_localeDate: function (shortdate) {
|
|
let timezone = GLib.TimeZone.new_local(); // TZ doesn't really matter for this
|
|
let date = GLib.DateTime.new(timezone,
|
|
parseInt(shortdate.substr(0,4)), // year
|
|
parseInt(shortdate.substr(4,2)), // month
|
|
parseInt(shortdate.substr(6,2)), // day
|
|
0, 0, 0 );
|
|
return date.format('%Y-%m-%d'); // ISO 8601 - https://xkcd.com/1179/
|
|
},
|
|
|
|
// set menu text in lieu of a notification/popup
|
|
_setMenuText: function() {
|
|
this.titleItem.label.set_text(this.title);
|
|
this.explainItem.label.set_text(this.explanation);
|
|
this.copyrightItem.label.set_text(this.copyright);
|
|
},
|
|
|
|
// set menu thumbnail
|
|
// "But really, what the extension is doing is a terrible terrible hack, and I'm quite surprised that it worked at all." - Florian Müllner, 2020
|
|
// FIXME: find another way
|
|
_setImage: function () {
|
|
let pixbuf = this.thumbnail.gtkImage.get_pixbuf();
|
|
const { width, height } = pixbuf;
|
|
if (height == 0) {
|
|
return;
|
|
}
|
|
const image = new Clutter.Image();
|
|
const success = image.set_data(
|
|
pixbuf.get_pixels(),
|
|
pixbuf.get_has_alpha() ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888,
|
|
width,
|
|
height,
|
|
pixbuf.get_rowstride()
|
|
);
|
|
if (!success) {
|
|
throw Error("error creating Clutter.Image()");
|
|
}
|
|
|
|
getActorCompat(this.thumbnailItem).hexpand = false;
|
|
getActorCompat(this.thumbnailItem).vexpand = false;
|
|
getActorCompat(this.thumbnailItem).content = image;
|
|
|
|
getActorCompat(this.thumbnailItem).set_size(480, 270);
|
|
this.thumbnailItem.setSensitive(true);
|
|
},
|
|
|
|
// download Bing metadat
|
|
_refresh: function() {
|
|
if (this._updatePending)
|
|
return;
|
|
this._updatePending = true;
|
|
|
|
this._restartTimeout();
|
|
|
|
let market = this._settings.get_string('market');
|
|
log("market: " + market);
|
|
|
|
// create an http message
|
|
let request = Soup.Message.new('GET', BingImageURL+market); // + market
|
|
log("fetching: " + BingImageURL+market);
|
|
|
|
// queue the http request
|
|
httpSession.queue_message(request, Lang.bind(this, function(httpSession, message) {
|
|
if (message.status_code == 200) {
|
|
let data = message.response_body.data;
|
|
log("Recieved "+data.length+" bytes");
|
|
this._parseData(data);
|
|
} else if (message.status_code == 403) {
|
|
log("Access denied: "+message.status_code);
|
|
this._updatePending = false;
|
|
this._restartTimeout(TIMEOUT_SECONDS_ON_HTTP_ERROR);
|
|
} else {
|
|
log("Network error occured: "+message.status_code);
|
|
this._updatePending = false;
|
|
this._restartTimeout(TIMEOUT_SECONDS_ON_HTTP_ERROR);
|
|
}
|
|
}));
|
|
},
|
|
|
|
// process Bing metadata
|
|
_parseData: function(data) {
|
|
let parsed = JSON.parse(data);
|
|
let imagejson = parsed.images[0];
|
|
let datamarket = parsed.market.mkt;
|
|
let prefmarket = this._settings.get_string('market');
|
|
|
|
log('JSON returned (raw):\n' + data);
|
|
|
|
if (imagejson.url != '') {
|
|
this.title = imagejson.copyright.replace(/\s*\(.*?\)\s*/g, "");
|
|
this.explanation = _("Bing Wallpaper of the Day for")+' '+this._localeDate(imagejson.startdate)+' ('+datamarket+')';
|
|
this.copyright = imagejson.copyright.match(/\(([^)]+)\)/)[1].replace('\*\*','');
|
|
if (datamarket != prefmarket) {
|
|
// user requested a market that isn't available in their GeoIP area, so they are forced to use another generic type (probably "en-WW")
|
|
log('Mismatched market data, Req: '+prefmarket +' != Recv: ' + datamarket +')');
|
|
this.copyright = this.copyright + '\n\n WARNING: ' + _("Market not available in your region") + '\n Req: '+prefmarket +' -> Recv: ' + datamarket;
|
|
}
|
|
this.longstartdate = imagejson.fullstartdate;
|
|
this.imageinfolink = imagejson.copyrightlink.replace(/^http:\/\//i, 'https://');
|
|
let resolution = this._settings.get_string('resolution');
|
|
|
|
if (resolution == "auto") {
|
|
log("auto resolution selected ("+autores+")");
|
|
resolution = autores;
|
|
}
|
|
|
|
if (Utils.resolutions.indexOf(resolution) == -1 || imagejson.wp == false ||
|
|
(this._settings.get_string('resolution') == "auto" && autores == "1920x1200") ) {
|
|
// resolution invalid, animated background, or override auto selected 1920x1200 to avoid bing logo unless user wants it
|
|
resolution = "UHD";
|
|
}
|
|
|
|
this.imageURL = BingURL+imagejson.urlbase+"_"+resolution+".jpg"; // generate image url for user's resolution
|
|
|
|
let BingWallpaperDir = this._settings.get_string('download-folder');
|
|
let userPicturesDir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES);
|
|
if (BingWallpaperDir == '') {
|
|
BingWallpaperDir = userPicturesDir + "/BingWallpaper/";
|
|
this._settings.set_string('download-folder', BingWallpaperDir);
|
|
}
|
|
else if (!BingWallpaperDir.endsWith('/')) {
|
|
BingWallpaperDir += '/';
|
|
}
|
|
|
|
log("XDG pictures directory detected as "+userPicturesDir+" saving pictures to "+BingWallpaperDir);
|
|
this.filename = BingWallpaperDir+imagejson.startdate+'-'+this.imageURL.replace(/^.*[\\\/]/, '').replace('th?id=OHR.', '');
|
|
let file = Gio.file_new_for_path(this.filename);
|
|
let file_exists = file.query_exists(null);
|
|
let file_info = file_exists ? file.query_info ('*',Gio.FileQueryInfoFlags.NONE,null): 0;
|
|
|
|
if (!file_exists || file_info.get_size () == 0) { // file doesn't exist or is empty (probably due to a network error)
|
|
let dir = Gio.file_new_for_path(BingWallpaperDir);
|
|
if (!dir.query_exists(null)) {
|
|
dir.make_directory_with_parents(null);
|
|
}
|
|
this._download_image(this.imageURL, file);
|
|
} else {
|
|
log("Image already downloaded");
|
|
let changed = this._setBackground();
|
|
this._updatePending = false;
|
|
}
|
|
|
|
} else {
|
|
this.title = _("No wallpaper available");
|
|
this.explanation = _("No picture for today 😞.");
|
|
this.filename = "";
|
|
this._updatePending = false;
|
|
}
|
|
this._setMenuText();
|
|
this._restartTimeoutFromLongDate(this.longstartdate);
|
|
},
|
|
|
|
// download and process new image
|
|
_download_image: function(url, file) {
|
|
log("Downloading " + url + " to " + file.get_uri());
|
|
|
|
// open the Gfile
|
|
let fstream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
|
|
|
|
// create an http message
|
|
let request = Soup.Message.new('GET', url);
|
|
|
|
// got_headers event
|
|
request.connect('got_headers', Lang.bind(this, function(message){
|
|
log("got_headers, status: "+message.status_code);
|
|
}));
|
|
|
|
// got_chunk event
|
|
request.connect('got_chunk', Lang.bind(this, function(message, chunk){
|
|
//log("got_chuck, status: "+message.status_code);
|
|
if (message.status_code == 200) { // only save the data we want, not content of 301 redirect page
|
|
fstream.write(chunk.get_data(), null);
|
|
}
|
|
else {
|
|
log("got_chuck, status: "+message.status_code);
|
|
}
|
|
}));
|
|
|
|
// queue the http request
|
|
httpSession.queue_message(request, Lang.bind(this, function(httpSession, message) {
|
|
// request completed
|
|
fstream.close(null);
|
|
this._updatePending = false;
|
|
if (message.status_code == 200) {
|
|
log('Download successful');
|
|
this._setBackground();
|
|
this._add_to_previous_queue(this.filename);
|
|
} else {
|
|
log("Couldn't fetch image from " + url);
|
|
file.delete(null);
|
|
}
|
|
}));
|
|
},
|
|
|
|
// add image to persistant list so we can delete it later (in chronological order), delete the oldest image (if user wants this)
|
|
_add_to_previous_queue: function (filename) {
|
|
let rawimagelist = this._settings.get_string('previous');
|
|
let imagelist = rawimagelist.split(',');
|
|
let maxpictures = this._settings.get_int('previous-days');
|
|
let deletepictures = this._settings.get_boolean('delete-previous');
|
|
|
|
log("Raw: "+ rawimagelist+" count: "+imagelist.length);
|
|
log("Settings: delete:"+(deletepictures?"yes":"no")+" max: "+maxpictures);
|
|
|
|
imagelist.push(filename); // add current to end of list
|
|
|
|
while(imagelist.length > maxpictures+1) {
|
|
var to_delete = imagelist.shift(); // get the first (oldest item from the list)
|
|
log("image: "+to_delete);
|
|
if (deletepictures && to_delete != '') {
|
|
var file = Gio.file_new_for_path(to_delete);
|
|
if (file.query_exists(null)) {
|
|
file.delete(null);
|
|
log("deleted file: "+ to_delete);
|
|
}
|
|
}
|
|
}
|
|
|
|
// put it back together and send back to settings
|
|
rawimagelist = imagelist.join();
|
|
this._settings.set_string('previous', rawimagelist);
|
|
log("wrote back this: "+rawimagelist);
|
|
},
|
|
|
|
// open image in default image view
|
|
_open_in_system_viewer: function launchOpen() {
|
|
const context = global.create_app_launch_context(0, -1);
|
|
Gio.AppInfo.launch_default_for_uri(this.filename.get_uri(), context);
|
|
},
|
|
|
|
stop: function () {
|
|
if (this._timeout)
|
|
Mainloop.source_remove(this._timeout);
|
|
this._timeout = undefined;
|
|
this.menu.removeAll();
|
|
}
|
|
});
|
|
|
|
function init(extensionMeta) {
|
|
if (init_called === false) {
|
|
Convenience.initTranslations("BingWallpaper");
|
|
init_called = true;
|
|
}
|
|
else {
|
|
log("WARNING: init() called more than once, ignoring");
|
|
}
|
|
}
|
|
|
|
function enable() {
|
|
bingWallpaperIndicator = new BingWallpaperIndicator();
|
|
Main.panel.addToStatusArea(IndicatorName, bingWallpaperIndicator);
|
|
autores = "UHD"; // remove monitor size checks
|
|
}
|
|
|
|
function disable() {
|
|
if (this._timeout)
|
|
Mainloop.source_remove(this._timeout);
|
|
bingWallpaperIndicator.stop();
|
|
bingWallpaperIndicator.destroy();
|
|
bingWallpaperIndicator = null;
|
|
}
|
|
|
|
// props to Otto Allmendinger
|
|
// see https://github.com/OttoAllmendinger/gnome-shell-screenshot
|
|
class Thumbnail {
|
|
constructor(filePath) {
|
|
if (!filePath) {
|
|
throw new Error(`need argument ${filePath}`);
|
|
}
|
|
this.gtkImage = new Gtk.Image({file: filePath});
|
|
this.srcFile = Gio.File.new_for_path(filePath);
|
|
}
|
|
}
|