From 54501c9390d7e2197f5274528b35c14cb81e11c1 Mon Sep 17 00:00:00 2001 From: luxick Date: Mon, 18 May 2020 19:58:10 +0200 Subject: [PATCH] Separate providers module. --- .gitignore | 10 +++++ randopix.nimble | 2 +- src/fileAccess.nim | 33 --------------- src/providers.nim | 73 +++++++++++++++++++++++++++++++++ src/randopix.nim | 100 ++++++++++++++------------------------------- 5 files changed, 114 insertions(+), 104 deletions(-) delete mode 100644 src/fileAccess.nim create mode 100644 src/providers.nim diff --git a/.gitignore b/.gitignore index b497ff1..5b73554 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,12 @@ +# Ignore all +* + +# Unignore all with extensions +!*.* + +# Unignore all dirs +!*/ + +### Above combination will ignore all files without extension ### bin/ .vscode/ \ No newline at end of file diff --git a/randopix.nimble b/randopix.nimble index af77cc6..7767e98 100644 --- a/randopix.nimble +++ b/randopix.nimble @@ -9,7 +9,7 @@ srcDir = "src" bin = @["randopix"] # Dependencies -requires "nim >= 1.0.0", "gintro <= 0.5.5", "argparse >=0.10.1" +requires "nim >= 1.0.0", "gintro >= 0.5.5", "argparse >=0.10.1" task debug, "Compile debug version": exec "nim c -d:debug --debugger:native --out:bin/randopix src/randopix.nim" diff --git a/src/fileAccess.nim b/src/fileAccess.nim deleted file mode 100644 index 223fdd2..0000000 --- a/src/fileAccess.nim +++ /dev/null @@ -1,33 +0,0 @@ -import os, sets, random - -const - supportedExts = @[".png", ".jpg", ".jpeg"] - -type - FileProvider* = ref object - exts: HashSet[string] - path*: string - files*: seq[string] - -proc load*(fp: FileProvider) = - ## Reload the file list - if fp.path == "": - return - - for file in walkDirRec(fp.path): - let split = splitFile(file) - if fp.exts.contains(split.ext): - fp.files.add(file) - - randomize() - shuffle(fp.files) - -proc next*(fp: FileProvider): string = - if fp.files.len < 1: - fp.load - result = fp.files[0] - fp.files.delete(0) - -proc newFileProvider*(path: string): FileProvider = - result = FileProvider(path: path, exts: supportedExts.toHashSet) - result.load \ No newline at end of file diff --git a/src/providers.nim b/src/providers.nim new file mode 100644 index 0000000..3668227 --- /dev/null +++ b/src/providers.nim @@ -0,0 +1,73 @@ +import os, sets, random, httpClient, json +import gintro/[gdkpixbuf] + +const + supportedExts = @[".png", ".jpg", ".jpeg"] + foxesUrl = "https://randomfox.ca/floof/" + +type + ProviderKind* {.pure.} = enum + Foxes = "foxes" ## Some nice foxes + Inspiro = "inspiro" ## Inspiring nonsense + File = "file" ## Images from a local path + + ImageProvider* = ref object + case kind: ProviderKind + of ProviderKind.Foxes, ProviderKind.Inspiro: + url: string + of ProviderKind.File: + exts: HashSet[string] + path*: string + files*: seq[string] + +var client = newHttpClient() ## For loading images from the web + +proc downloadFox(ip: ImageProvider): Pixbuf = + ## Download image from the fox API + let urlData = client.getContent(ip.url) + let info = parseJson(urlData) + let imageData = client.getContent(info["image"].getStr) + let loader = newPixbufLoader() + discard loader.write(imageData) + loader.getPixbuf() + +proc reloadFileList(ip: ImageProvider) = + ## Reload the file list + if ip.path == "": + return + + for file in walkDirRec(ip.path): + let split = splitFile(file) + if ip.exts.contains(split.ext): + ip.files.add(file) + + randomize() + shuffle(ip.files) + +proc next*(ip: ImageProvider): Pixbuf = + ## Return a new image from the chosen image source + case ip.kind + of ProviderKind.Foxes, ProviderKind.Inspiro: + return ip.downloadFox + of ProviderKind.File: + if ip.files.len < 1: + ip.reloadFileList + result = ip.files[0].newPixbufFromFile + ip.files.delete(0) + +proc newFileProvider(path: string): ImageProvider = + result = ImageProvider(kind: ProviderKind.File, path: path, exts: supportedExts.toHashSet) + result.reloadFileList + +proc newFoxProvider(): ImageProvider = ImageProvider(kind: ProviderKind.Foxes, url: foxesUrl) + +proc newImageProvider*(kind: ProviderKind, filePath: string = ""): ImageProvider = + ## Create a new `ImageProvider` for the API chosen with thge `kind` parameter + case kind + of ProviderKind.Foxes: + newFoxProvider() + of ProviderKind.Inspiro: + # TODO + newFoxProvider() + of ProviderKind.File: + newFileProvider(filePath) \ No newline at end of file diff --git a/src/randopix.nim b/src/randopix.nim index c529732..45b6d3a 100644 --- a/src/randopix.nim +++ b/src/randopix.nim @@ -1,31 +1,22 @@ -import httpClient, json, os, options, strformat +import os, options, strformat import gintro/[gtk, glib, gobject, gio, gdkpixbuf] import gintro/gdk except Window import argparse except run -import fileAccess +import providers const css = slurp("app.css") version = "0.1" - floofUrl = "https://randomfox.ca/floof/" type - Mode {.pure.} = enum - Foxes = "foxes" ## Some nice foxes - Inspiro = "inspiro" ## Inspiring nonsense - File = "file" ## Images from a local path - Args = object fullscreen: bool ## Applicaion is show in fullscreen mode verbose: bool ## More debug information in notification label - mode: Option[Mode] ## The chosen image source - path: string ## File mode only: the path to the images timeout: int ## Milliseconds between image refreshes var - client = newHttpClient() ## For loading images from the web - fileProvider: FileProvider ## Gets images from the chosen source - args: Args ## The parsed command line args + imageProvider: ImageProvider ## Gets images from the chosen source + args: Args ## The parsed command line args # Widgets window: ApplicationWindow imageWidget: Image @@ -44,79 +35,46 @@ proc notify(label: Label, message: string = "") = else: label.show -proc newArgs(): Args = +proc newArgs(): Option[Args] = let p = newParser("randopix"): help(fmt"Version {version} - Display random images from different sources") - option("-m", "--mode", help="The image source mode.", choices=enumToStrings(Mode)) + option("-m", "--mode", help="The image source mode.", choices=enumToStrings(ProviderKind)) option("-p", "--path", help="Path to a directory with images ('file' mode only)") option("-t", "--timeout", help="Seconds before the image is refreshed", default="300") flag("-w", "--windowed", help="Do not start in fullscreen mode") flag("-v", "--verbose", help="Show more information") - let opts = p.parse(commandLineParams()) - var mode: Option[Mode] - if (opts.mode == ""): - echo p.help - return try: - mode = some(parseEnum[Mode](opts.mode)) - except ValueError: - echo fmt"Invaild mode: {opts.mode}" + let opts = p.parse(commandLineParams()) + let mode = some(parseEnum[ProviderKind](opts.mode)) + imageProvider = newImageProvider(mode.get, opts.path) + ## Timeout is given in seconds as an argument + var timeout = 3000 + try: + timeout = opts.timeout.parseInt * 1000 + except ValueError: + raise newException(UsageError, fmt"Invalid timeout value: {opts.timeout}") + + return some(Args( + fullscreen: not opts.windowed, + verbose: opts.verbose, + timeout: timeout)) + except UsageError: + echo getCurrentExceptionMsg() echo p.help - return - - if (mode.get == Mode.File): - fileProvider = newFileProvider(opts.path) - - ## Timeout is given in seconds as an argument - var timeout = 3000 - try: - timeout = opts.timeout.parseInt * 1000 - except ValueError: - echo "Invalid timeout: ", opts.timeout - - Args( - fullscreen: not opts.windowed, - verbose: opts.verbose, - mode: mode, - path: opts.path, - timeout: timeout) - -proc downloadFox(): Pixbuf = - let urlData = client.getContent(floofUrl) - let info = parseJson(urlData) - let imageData = client.getContent(info["image"].getStr) - let loader = newPixbufLoader() - discard loader.write(imageData) - loader.getPixbuf() - -proc getLocalImage(): Pixbuf = - ## let the file provider serve another image - fileProvider.next.newPixbufFromFile - -proc tryGetImage(): Option[Pixbuf] = - ## Get the raw image from an image provider - ## The kind of image is based on the command line args - if args.mode.isSome: - case args.mode.get - of Mode.Foxes: - result = some(downloadFox()) - of Mode.Inspiro: - echo "Not Implemented" - of Mode.File: - result = some(getLocalImage()) proc updateImage(): bool = ## Updates the UI with a new image # Loading new image try: if (args.verbose): echo "Refreshing..." - let data = tryGetImage(); + # TODO better error signalling from providers.nim + let data = some(imageProvider.next) if data.isNone: label.notify "No image to display..." return false; - ## Resize image to best fit the window + ## Resize image to best fit the window var pixbuf = data.get() var wWidth, wHeight, width, height: int window.getSize(wWidth, wHeight) @@ -186,9 +144,11 @@ proc connectSignals(app: Application) = proc appActivate(app: Application) = # Parse arguments from the command line - args = newArgs() - # No mode was given, exit and display the help text - if (args.mode.isNone): return + let parsed = newArgs() + if parsed.isNone: + return + else: + args = parsed.get window = newApplicationWindow(app) window.title = "randopix"