diff --git a/frameos/src/apps/apps.nim b/frameos/src/apps/apps.nim
index fdf8c5f9..5b93c4f6 100644
--- a/frameos/src/apps/apps.nim
+++ b/frameos/src/apps/apps.nim
@@ -20,6 +20,7 @@ import apps/data/resizeImage/app_loader as data_resizeImage_loader
import apps/data/rotateImage/app_loader as data_rotateImage_loader
import apps/data/rstpSnapshot/app_loader as data_rstpSnapshot_loader
import apps/data/unsplash/app_loader as data_unsplash_loader
+import apps/data/wikicommons/app_loader as data_wikicommons_loader
import apps/data/xmlToJson/app_loader as data_xmlToJson_loader
import apps/logic/breakIfRendering/app_loader as logic_breakIfRendering_loader
import apps/logic/ifElse/app_loader as logic_ifElse_loader
@@ -56,6 +57,7 @@ proc initApp*(keyword: string, node: DiagramNode, scene: FrameScene): AppRoot =
of "data/rotateImage": data_rotateImage_loader.init(node, scene)
of "data/rstpSnapshot": data_rstpSnapshot_loader.init(node, scene)
of "data/unsplash": data_unsplash_loader.init(node, scene)
+ of "data/wikicommons": data_wikicommons_loader.init(node, scene)
of "data/xmlToJson": data_xmlToJson_loader.init(node, scene)
of "logic/breakIfRendering": logic_breakIfRendering_loader.init(node, scene)
of "logic/ifElse": logic_ifElse_loader.init(node, scene)
@@ -93,6 +95,7 @@ proc setAppField*(keyword: string, app: AppRoot, field: string, value: Value) =
of "data/rotateImage": data_rotateImage_loader.setField(app, field, value)
of "data/rstpSnapshot": data_rstpSnapshot_loader.setField(app, field, value)
of "data/unsplash": data_unsplash_loader.setField(app, field, value)
+ of "data/wikicommons": data_wikicommons_loader.setField(app, field, value)
of "data/xmlToJson": data_xmlToJson_loader.setField(app, field, value)
of "logic/breakIfRendering": logic_breakIfRendering_loader.setField(app, field, value)
of "logic/ifElse": logic_ifElse_loader.setField(app, field, value)
@@ -145,6 +148,7 @@ proc getApp*(keyword: string, app: AppRoot, context: ExecutionContext): Value =
of "data/rotateImage": data_rotateImage_loader.get(app, context)
of "data/rstpSnapshot": data_rstpSnapshot_loader.get(app, context)
of "data/unsplash": data_unsplash_loader.get(app, context)
+ of "data/wikicommons": data_wikicommons_loader.get(app, context)
of "data/xmlToJson": data_xmlToJson_loader.get(app, context)
of "render/calendar": render_calendar_loader.get(app, context)
of "render/color": render_color_loader.get(app, context)
diff --git a/frameos/src/apps/data/wikicommons/app.nim b/frameos/src/apps/data/wikicommons/app.nim
new file mode 100644
index 00000000..9419b976
--- /dev/null
+++ b/frameos/src/apps/data/wikicommons/app.nim
@@ -0,0 +1,168 @@
+import pixie
+import strformat
+import strutils
+import httpclient
+import frameos/apps
+import frameos/types
+import frameos/utils/image
+import nre
+import times
+import random
+
+type
+ AppConfig* = object
+ mode*: string
+ submode*: string
+ saveAssets*: string
+
+ App* = ref object of AppRoot
+ appConfig*: AppConfig
+
+proc init*(self: App) =
+ randomize()
+ self.appConfig.mode = self.appConfig.mode.strip()
+ self.appConfig.submode = self.appConfig.submode.strip()
+
+proc error*(self: App, context: ExecutionContext, message: string): Image =
+ self.logError(message)
+ result = renderError(if context.hasImage: context.image.width else: self.frameConfig.renderWidth(),
+ if context.hasImage: context.image.height else: self.frameConfig.renderHeight(), message)
+
+proc getImageUrlFromFilePage(client: HttpClient, fileUrl: string): string =
+ # Fetch the file page and extract the original file URL
+ let response = client.request(fileUrl, httpMethod = HttpGet)
+ if response.code != Http200:
+ raise newException(CatchableError, &"Error fetching file page: {response.status}")
+
+ let body = response.body
+ # Look for Original file
+ let m = body.match(re"""]*>Original file""")
+ if m.isSome:
+ let href = m.get.captures[0]
+ result = if href.startsWith("http"): href else: "https:" & href
+ else:
+ raise newException(CatchableError, "Could not find original file link")
+
+proc getPotdInfo(client: HttpClient, year: int, month: int, day: int): tuple[url: string, description: string] =
+ let url = &"https://commons.wikimedia.org/wiki/Template:Potd/{year}-{month:02d}"
+ let response = client.request(url, httpMethod = HttpGet)
+ if response.code != Http200:
+ raise newException(CatchableError, &"Error fetching POTD template: {response.status}")
+
+ let body = response.body
+ # Find the div with id="day"
+ let divPattern = &"id=\"{day}\""
+ let divStart = body.find(divPattern)
+ if divStart == -1:
+ raise newException(CatchableError, &"No POTD for {year}-{month:02d}-{day:02d}")
+
+ # Find the end of the div, assuming it's the next
+ let divEnd = body.find("", divStart)
+ if divEnd == -1:
+ raise newException(CatchableError, "Malformed HTML")
+
+ let divContent = body[divStart..divEnd]
+
+ # Extract href
+ let mHref = divContent.match(re"""""")
+ if mHref.isNone:
+ raise newException(CatchableError, "No image link found")
+ let href = mHref.get.captures[0]
+ let fileUrl = "https://commons.wikimedia.org" & href
+
+ # Extract description
+ let mDesc = divContent.match(re"""