Separate providers module.

This commit is contained in:
2020-05-18 19:58:10 +02:00
parent 4c1335378d
commit 54501c9390
5 changed files with 114 additions and 104 deletions

10
.gitignore vendored
View File

@@ -1,2 +1,12 @@
# Ignore all
*
# Unignore all with extensions
!*.*
# Unignore all dirs
!*/
### Above combination will ignore all files without extension ###
bin/
.vscode/

View File

@@ -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"

View File

@@ -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

73
src/providers.nim Normal file
View File

@@ -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)

View File

@@ -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"