Skip to content

Instantly share code, notes, and snippets.

@qubbit
Last active May 26, 2018 02:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qubbit/23c230e406ddb8553f58fb25b764e48c to your computer and use it in GitHub Desktop.
Save qubbit/23c230e406ddb8553f58fb25b764e48c to your computer and use it in GitHub Desktop.
Periodically download images and set them as wallpaper from Unsplash
using Microsoft.Win32;
using System;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
// A program that will periodically download an image from Unsplash and
// change your Windows desktop background to the downloaded image
// Compilation: csc /out:unsplash.exe /t:winexe .\Program.cs /nologo /o
// After compilation, drop the executable in a folder and run it with command line args:
// time = minutes (how often to change the background image)
// category = search terms to find your desired type of wallpaper
// fit = wallpaper fit, one of fill, fit, span, tile, center, stretch
// Example:
// unsplash.exe time=60 category=nature,scenary fit=stretch
// This will change the wallpaper every hour from category of nature and scenary
namespace Unsplash {
// Very simple logger implementation with a lock!
public class FileLogger {
protected readonly object locker = new object();
const string LOG_FILE_PATH = "application.log";
const bool ALSO_LOG_TO_STDOUT = true;
public void Log(string message) {
lock (locker) {
using (var streamWriter = new StreamWriter(LOG_FILE_PATH, append: true)) {
var line = string.Format("{0} \t {1}", DateTime.Now.ToString("MM/d/yyyy hh:mm:ss tt zzzz"), message);
streamWriter.WriteLine(line);
if (ALSO_LOG_TO_STDOUT) Console.WriteLine(line);
}
}
}
}
class Program {
const string IMAGE_DIR_NAME = "Unsplash";
const string SEARCH_URL_TEMPLATE = "http://source.unsplash.com/{0}x{1}/?{2}";
static string url;
static FileLogger logger = new FileLogger();
static uint timerCallCount = 0;
public static string imageDownloadDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, IMAGE_DIR_NAME);
static dynamic ParseCommandLine(string[] args) {
var typeDictionary = new Dictionary<string, Type>() {
{ "time", typeof(int)},
{ "category", typeof(string)},
{ "fit", typeof(Wallpaper.Style)}
};
dynamic o = new ExpandoObject();
var options = (IDictionary<string, object>)o;
foreach (var x in args) {
var segments = x.Split('=');
var key = segments[0];
var value = segments[1];
var converter = TypeDescriptor.GetConverter(typeDictionary[key]);
var result = converter.ConvertFrom(value);
options.Add(key, result);
}
return o;
}
static dynamic options;
static void Main(string[] args) {
SetAppBasePath();
logger.Log("Application started");
if (args.Length < 3) args = new string[] { "time=15", "category=cities", "fit=stretch" };
options = ParseCommandLine(args);
var screenBounds = Screen.AllScreens.Where(x => x.Primary).First().Bounds;
logger.Log("Primary screen bounds: " + screenBounds.ToString());
url = string.Format(SEARCH_URL_TEMPLATE, screenBounds.Width, screenBounds.Height, options.category);
int intervalMilliseconds = options.time * 60 * 1000;
new System.Threading.Timer(Tick, null, 0, intervalMilliseconds);
while (true) System.Threading.Thread.Sleep(1000);
}
private static void SetAppBasePath() {
if (!Directory.Exists(imageDownloadDir)) { Directory.CreateDirectory(imageDownloadDir); }
Directory.SetCurrentDirectory(imageDownloadDir);
}
private static void Tick(object state) {
string imageFileName = ImageDownloader.Download(url);
var logMessage = string.Format("Tick count: {0}. Setting wallpaper to {1}", ++timerCallCount, imageFileName);
logger.Log(logMessage);
Wallpaper.Set(imageFileName, options.fit);
}
}
class ImageDownloader {
private static string Extension(string mimeType) {
switch (mimeType) {
case "image/jpeg":
return ".jpg";
case "image/png":
return ".png";
default:
return "";
}
}
public static string Download(string url) {
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var request = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)request.GetResponse();
var responseUri = response.ResponseUri;
string imageFileName = Program.imageDownloadDir + "\\" + new FileInfo(response.ResponseUri.LocalPath).Name + Extension(response.ContentType);
using (Stream receiveStream = response.GetResponseStream()) {
using (Stream outputStream = File.OpenWrite(imageFileName)) {
byte[] buffer = new byte[4096];
int bytesRead;
do {
bytesRead = receiveStream.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
}
return imageFileName;
}
}
}
public sealed class Wallpaper {
const int SPI_SETDESKWALLPAPER = 20;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDWININICHANGE = 0x02;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
public enum Style : int {
Fill, Fit, Span, Tile, Center, Stretch
}
private static Dictionary<Style, Tuple<string, string>> wallpaperStyles = new Dictionary<Style, Tuple<string, string>> {
{ Style.Fill, new Tuple<string, string>("10", "0") },
{ Style.Fit, new Tuple<string, string>("6", "0") },
{ Style.Span, new Tuple<string, string>("22", "0") },
{ Style.Stretch, new Tuple<string, string>("2", "0") },
{ Style.Tile, new Tuple<string, string>("0", "1") },
{ Style.Center, new Tuple<string, string>("0", "0") }
};
public static void Set(string filename, Style style) {
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true);
var reg = wallpaperStyles[style];
key.SetValue("WallpaperStyle", reg.Item1);
key.SetValue("TileWallpaper", reg.Item1);
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, filename, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment