Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
neffo committed Jul 22, 2017
0 parents commit 392831e
Show file tree
Hide file tree
Showing 10 changed files with 2,062 additions and 0 deletions.
675 changes: 675 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# GNOME shell extension Bing Wallpaper Changer

Let this simple GNOME shell extension change your wallpaper every day to
Microsoft Bing's wallpaper (the image you see when you visit Bing.com). It will
also show a notification containing the title and the explanation of the image.

*Disclaimer*: this extension is unofficial and not affiliated with Bing or
Microsoft in any way. Images are protected by copyright. And are licensed only
for use as wallpapers.

This extension is based extensively on the NASA APOD extension by Elinvention
(see https://github.com/Elinvention) and Bing Desktop Wallpaper Changer by
Utkarsh Gupta (see https://github.com/UtkarshGpta).

This is my first attempt at a Gnome extension, so it may have some issues.

## Install

`git clone https://github.com/neffo/bing-wallpaper-gnome-extension.git $HOME/.local/share/gnome-shell/extensions/[email protected]`

or create a zip file by doing this

`git clone https://github.com/neffo/bing-wallpaper-gnome-extension.git`
`cd bing-wallpaper-gnome-extension`
`zip -r ../[email protected] *`

682 changes: 682 additions & 0 deletions Settings.ui

Large diffs are not rendered by default.

309 changes: 309 additions & 0 deletions extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@

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 Util = imports.misc.util;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;


const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Utils = Me.imports.utils;

const BingImageURL = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"; //+ "&mkt="; // optional Bing market (currently ignored)
const BingURL = "https://bing.com";
const IndicatorName = "BingWallpaperIndicator";
const TIMEOUT_SECONDS = 6 * 3600;
const ICON = "bing"

let validresolutions = [ '800x600' , '1024x768', '1280x720', '1280x768', '1366x768', '1920x1080', '1920x1200'];

let bingWallpaperIndicator;


function log(msg) {
print("BingWallpaper extension: " + msg);
}

// Utility function
function dump(object) {
let output = '';
for (let property in object) {
output += property + ': ' + object[property]+'; ';
}
log(output);
}

const LongNotification = new Lang.Class({
Name: 'LongNotification',
Extends: MessageTray.Notification,

createBanner: function() {
// Explanations are usually longer than default
let banner = this.source.createBanner(this);
banner.setExpandedLines(20);
return banner;
}
});

function notify(msg, details, transient) {
// set notifications icon
let source = new MessageTray.Source("BingWallpaper", ICON);
// force expanded notification
source.policy = new MessageTray.NotificationPolicy({ enable: true,
enableSound: true,
showBanners: true,
forceExpanded: true,
showInLockScreen: true,
detailsInLockScreen: true
});
Main.messageTray.add(source);
let notification = new LongNotification(source, msg, details);
notification.setTransient(transient);
// Add action to open Bing website with default browser
notification.addAction("Bing website", Lang.bind(this, function() {
Util.spawn(["xdg-open", BingURL]);
}));
source.notify(notification);
}

function notifyError(msg) {
Main.notifyError("BingWallpaper extension error", msg);
}

function doSetBackground(uri, schema) {
let gsettings = new Gio.Settings({schema: schema});
gsettings.set_string('picture-uri', uri);
Gio.Settings.sync();
gsettings.apply();
}

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.icon = new St.Icon({icon_name: ICON, style_class: 'system-status-icon'});
this.actor.add_child(this.icon);

this.title = "";
this.explanation = "";
this.filename = "";
this.copyright = "";
this.version = "0.1";
this._updatePending = false;
this._timeout = null;

this._settings = Utils.getSettings();
this._settings.connect('changed::hide', Lang.bind(this, function() {
this.actor.visible = !this._settings.get_boolean('hide');
}));

this.showItem = new PopupMenu.PopupMenuItem("Show description");
this.wallpaperItem = new PopupMenu.PopupMenuItem("Set wallpaper");
this.refreshItem = new PopupMenu.PopupMenuItem("Refresh");
this.settingsItem = new PopupMenu.PopupMenuItem("Settings");
this.menu.addMenuItem(this.showItem);
this.menu.addMenuItem(this.wallpaperItem);
this.menu.addMenuItem(this.refreshItem);
this.menu.addMenuItem(this.settingsItem);
this.showItem.connect('activate', Lang.bind(this, this._showDescription));
this.wallpaperItem.connect('activate', Lang.bind(this, this._setBackground));
this.refreshItem.connect('activate', Lang.bind(this, this._refresh));
this.settingsItem.connect('activate', function() {
Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]);
});

this.actor.connect('button-press-event', Lang.bind(this, function () {
// Grey out menu items if an update is pending
this.refreshItem.setSensitive(!this._updatePending);
this.showItem.setSensitive(!this._updatePending && this.title != "" && this.explanation != "");
this.wallpaperItem.setSensitive(!this._updatePending && this.filename != "");
}));

this._refresh();
},

_setBackground: function() {
if (this.filename == "")
return;
if (this._settings.get_boolean('set-background'))
doSetBackground(this.filename, 'org.gnome.desktop.background');
if (this._settings.get_boolean('set-lock-screen'))
doSetBackground(this.filename, 'org.gnome.desktop.screensaver');
},

_restartTimeout: function() {
if (this._timeout)
Mainloop.source_remove(this._timeout);
this._timeout = Mainloop.timeout_add_seconds(TIMEOUT_SECONDS, Lang.bind(this, this._refresh));
},

_showDescription: function() {
if (this.title == "" && this.explanation == "") {
this._refresh();
} else {
let message = this.explanation;
if (this.copyright != "")
message += "\n**" + this.copyright + "**"
notify(this.title, message, this._settings.get_boolean('transient'));
}
},

_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

// 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;
this._parseData(data);
} else if (message.status_code == 403) {
notifyError("Error 403: No access");
this._updatePending = false;
} else {
notifyError("Network error");
this._updatePending = false;
}
}));
},

_parseData: function(data) {
let parsed = JSON.parse(data);
let imagejson = parsed['images'][0];

if (imagejson['wp'] == true) {
this.title = imagejson['copyright'].replace(/\s*\(.*?\)\s*/g, "");
this.explanation = "Bing Wallpaper of the Day for ("+imagejson['fullstartdate']+")";
this.copyright = imagejson['copyright'].match(/\(([^)]+)\)/)[1].replace('\*\*','');;
//let url = ('hdurl' in parsed) ? parsed['hdurl'] : parsed['url'];
let resolution = this._settings.get_string('resolution');

if (validresolutions.indexOf(resolution) == -1)
resolution = "1920x1200";

let url = BingURL+imagejson['url'].replace('1920x1080','1920x1200');

log("Bing new wallpaper: "+url);
log("Bing new wallpaper description: "+this.title);

let BingWallpaperDir = this._settings.get_string('download-folder');
if (BingWallpaperDir == "")
BingWallpaperDir = GLib.get_home_dir() + "/Pictures/BingWallpaper/";
else if (!BingWallpaperDir.endsWith('/'))
BingWallpaperDir += '/';
this.filename = BingWallpaperDir + imagejson['startdate'] + '-BingWallpaper-'+ resolution + '.jpg';

let file = Gio.file_new_for_path(this.filename);
if (!file.query_exists(null)) {
let dir = Gio.file_new_for_path(BingWallpaperDir);
if (!dir.query_exists(null)) {
dir.make_directory_with_parents(null);
}
this._download_image(url, file);
} else {
log("Image already downloaded");
this._setBackground();
this._updatePending = false;
}
} else {
this.title = "No wallpaper available";
this.explanation = "No picture for today 😞.";
this.filename = "";
this._updatePending = false;
if (this._settings.get_boolean('notify'))
this._showDescription();
}
},

_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);

// variables for the progress bar
let total_size;
let bytes_so_far = 0;

// 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")
total_size = message.response_headers.get_content_length()
}));

// got_chunk event
request.connect('got_chunk', Lang.bind(this, function(message, chunk){
bytes_so_far += chunk.length;

if(total_size) {
let fraction = bytes_so_far / total_size;
let percent = Math.floor(fraction * 100);
log("Download "+percent+"% done ("+bytes_so_far+" / "+total_size+" bytes)");
}
fstream.write(chunk.get_data(), null, chunk.length);
}));

// 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();
if (this._settings.get_boolean('notify'))
this._showDescription();
} else {
notifyError("Couldn't fetch image from " + url);
file.delete(null);
}
}));
},

stop: function () {
if (this._timeout)
Mainloop.source_remove(this._timeout);
this._timeout = undefined;
this.menu.removeAll();
}
});

function init(extensionMeta) {
let theme = imports.gi.Gtk.IconTheme.get_default();
theme.append_search_path(extensionMeta.path + "/icons");
}

function enable() {
bingWallpaperIndicator = new BingWallpaperIndicator();
Main.panel.addToStatusArea(IndicatorName, bingWallpaperIndicator);
}

function disable() {
BingWallpaperIndicator.stop();
BingWallpaperIndicator.destroy();
}
Loading

0 comments on commit 392831e

Please sign in to comment.