[Code Review Request] Unsplash image downloader

Hadn’t written any C# in what feels like years. No error handling, no third-party libs. Is there anyway I can make it better? I want to keep it in a single file because I want people to be able to use it from PowerShell. Feedback appreciated.

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 = "https://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 PanelDesktop", true); var reg = wallpaperStyles[style]; key.SetValue("WallpaperStyle", reg.Item1); key.SetValue("TileWallpaper", reg.Item1); SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, filename, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); } } } 

submitted by /u/barshat
[link] [comments]

Leave a Reply