diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index b8bfb97..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-[*.mts]
-indent_size = 4
-indent_style = tab
\ No newline at end of file
diff --git a/analyze/analysis.mts b/analyze/analysis.mts
index 3942798..7aac025 100755
--- a/analyze/analysis.mts
+++ b/analyze/analysis.mts
@@ -1,4 +1,7 @@
#!/usr/bin/env zx
+
+import { floorToStep } from "../utils.mts";
+
///
export interface AnalysisConfig {
@@ -32,10 +35,10 @@ export class ImageAnalysisData {
}
}
-export const defaultConfig: AnalysisConfig = {
- imageDir: `${os.homedir()}/Pictures`,
- lightnessStep: 10,
- chromaStep: 1,
+export const defaultConfig: AnalysisConfig = {
+ imageDir: `${os.homedir()}/Pictures`,
+ lightnessStep: 10,
+ chromaStep: 1,
hueStep: 90,
preAnalysisCommands: []
}
@@ -131,6 +134,3 @@ export async function analyzeImages(imageDir: string, analysisOutput: ImageAnaly
}
}
-function floorToStep(num: number, step: number) {
- return Math.floor(num / step) * step
-}
\ No newline at end of file
diff --git a/apply/application.mts b/apply/application.mts
index e4462f3..c166a06 100644
--- a/apply/application.mts
+++ b/apply/application.mts
@@ -1,51 +1,107 @@
#!/usr/bin/env zx
+
+import { ImageAnalysisData } from "../analyze/analysis.mts"
+import _ from "npm:underscore"
+
///
export interface ApplicationConfig {
- latitude: number,
- longitude: number,
- weatherModel: string,
- applyWallpaperCommand: string
+ latitude: number
+ longitude: number
+ weatherModel: string
+ lightnessRange: { start: number; end: number }
+ chromaRange: { start: number; end: number }
+ hueRange: { start: number; end: number }
+ applyWallpaperCommand: string
}
-export const defaultConfig: ApplicationConfig = {
+export const defaultConfig: ApplicationConfig = {
latitude: 0,
- longitude: 0,
- weatherModel: "best_match",
- applyWallpaperCommand: "hyprctl hyprpaper wallpaper , %s"
+ longitude: 0,
+ weatherModel: "best_match",
+ lightnessRange: {
+ start: 0,
+ end: 100,
+ },
+ chromaRange: {
+ start: 0,
+ end: 100,
+ },
+ hueRange: {
+ start: 0,
+ end: 360,
+ },
+ applyWallpaperCommand: "hyprctl hyprpaper wallpaper , %s",
+}
+
+export async function getOpenMeteoData(
+ latitude: number,
+ longitude: number,
+ weatherModel: string = "best_match",
+) {
+ const openMeteoResponse = await fetch(
+ "https://api.open-meteo.com/v1/forecast",
+ {
+ method: "POST",
+ body: new URLSearchParams({
+ latitude: latitude.toString(),
+ longitude: longitude.toString(),
+ models: weatherModel,
+ current: "cloud_cover",
+ minutely_15: "shortwave_radiation_instant",
+ }),
+ },
+ )
+
+ if (!openMeteoResponse.ok) {
+ throw new Error(
+ `Open-Meteo sent back an error: ${openMeteoResponse.status}`,
+ )
+ }
+
+ const openMeteoData = await openMeteoResponse.json()
+
+ const cloudCover: string = openMeteoData.current.cloud_cover
+
+ let index = 0
+ openMeteoData.minutely_15.time.forEach((time: string) => {
+ if (Date.parse(time) > Date.now()) {
+ // if the data point has a time greater than right now, subtract one to find the one just before the current
+ // time
+ index = openMeteoData.minutely_15.time.indexOf(time) - 1
+ }
+ })
+ const shortwaveRadiation: string = openMeteoData.minutely_15.shortwave_radiation_instant[index]
+
+ return {
+ cloudCover,
+ shortwaveRadiation,
+ }
}
-export async function getOpenMeteoData(latitude: number, longitude: number, weatherModel: string = "best_match") {
- const openMeteoResponse = await fetch("https://api.open-meteo.com/v1/forecast", {
- method: "POST",
- body: new URLSearchParams({
- latitude: latitude.toString(),
- longitude: longitude.toString(),
- models: weatherModel,
- current: "cloud_cover",
- minutely_15: "shortwave_radiation_instant"
- })
- })
-
- if (!openMeteoResponse.ok) {
- throw new Error(`Open-Meteo sent back an error: ${openMeteoResponse.status}`)
- }
-
- const openMeteoData = await openMeteoResponse.json()
-
- const cloudCover = openMeteoData.current.cloud_cover
-
- let index = 0
- openMeteoData.minutely_15.time.forEach((time: string) => {
- if (Date.parse(time) > Date.now()) {
- // if the data point has a time greater than right now, subtract one to find the one just before the current
- // time
- index = openMeteoData.minutely_15.time.indexOf(time) - 1
- }
- })
- const shortwaveRadiation = openMeteoData.minutely_15.shortwave_radiation_instant[index];
-
- return {
- cloudCover, shortwaveRadiation
- }
-}
\ No newline at end of file
+export function findMatchingImages(
+ imagesData: ImageAnalysisData,
+ hueValue: number,
+ chromaValue: number,
+ lightnessValue: number,
+) {
+ let result = []
+ let i = 0
+ const chromaIndex = imagesData.chromaData.indexOf(
+ imagesData.chromaData.find((data) => data.chroma === chromaValue)!,
+ )
+ const lightnessIndex = imagesData.lightnessData.indexOf(
+ imagesData.lightnessData.find((data) => data.lightness === lightnessValue)!,
+ )
+
+ do {
+ const matches = [
+ imagesData.chromaData[chromaIndex + i].paths || imagesData.chromaData[chromaIndex - i].paths,
+ imagesData.lightnessData[lightnessIndex + i].paths || imagesData.lightnessData[lightnessIndex - i].paths,
+ ]
+ console.log(matches)
+ result = matches.reduce((a, b) => a.filter((c) => b.includes(c)))
+
+ i++
+ } while (result.length === 0)
+}
diff --git a/apply/index.mts b/apply/index.mts
index f9d0614..2c8cd2b 100644
--- a/apply/index.mts
+++ b/apply/index.mts
@@ -1,23 +1,86 @@
#!/usr/bin/env zx
///
-import { configDir, loadConfig } from "../utils.mts";
-import { ApplicationConfig, defaultConfig, getOpenMeteoData } from "./application.mts";
-import * as SunCalc from "npm:suncalc"
+import { AnalysisConfig, defaultConfig as analysisDefaultConfig, ImageAnalysisData } from "../analyze/analysis.mts"
+import { cacheDir, configDir, floorToStep, loadConfig, map } from "../utils.mts"
+import { ApplicationConfig, defaultConfig, findMatchingImages, getOpenMeteoData } from "./application.mts"
+import * as SunCalc from "npm:suncalc"
const pathToConfig = `${configDir}/apply-config.json`
+const pathToAnalysisConfig = `${configDir}/analyze-config.json`
+const pathToCache = `${cacheDir}/analysis.json`
-console.debug(`Trying to load config from ${pathToConfig}...`)
-const config = await loadConfig(pathToConfig, defaultConfig) as ApplicationConfig
+console.debug(`Trying to load application config from ${pathToConfig}...`)
+const config = await loadConfig(
+ pathToConfig,
+ defaultConfig,
+) as ApplicationConfig
if (config == undefined) {
- throw new Error("Couldn't initialize config!")
+ throw new Error("Couldn't initialize config!")
+}
+
+// we also need the analysis config to load the steps
+console.debug(`Trying to load analysis config from ${pathToAnalysisConfig}...`)
+const analysisConfig = await loadConfig(
+ pathToAnalysisConfig,
+ analysisDefaultConfig,
+) as AnalysisConfig
+if (analysisConfig == undefined) {
+ throw new Error("Couldn't initialize config!")
}
console.debug(`Config: \n${JSON.stringify(config, null, 4)}`)
-const openMeteoData = await getOpenMeteoData(config.latitude, config.longitude, config.weatherModel)
-const sunCalcData = SunCalc.getPosition(new Date(), config.latitude, config.longitude)
+const openMeteoData = await getOpenMeteoData(
+ config.latitude,
+ config.longitude,
+ config.weatherModel,
+)
+const sunCalcData = SunCalc.getPosition(
+ new Date(),
+ config.latitude,
+ config.longitude,
+)
+
console.info(`Current cloud cover percentage is ${openMeteoData.cloudCover}%!`)
-console.info(`Current shortwave radiation is ${openMeteoData.shortwaveRadiation} W/m²!`)
+console.info(
+ `Current shortwave radiation is ${openMeteoData.shortwaveRadiation} W/m²!`,
+)
console.info(`Current sun altitude is ${sunCalcData.altitude}°!`)
+// const hueValue = clamp()
+const chromaValue = floorToStep(
+ map(
+ Number(openMeteoData.cloudCover),
+ 0,
+ 100,
+ config.chromaRange.end,
+ config.chromaRange.start,
+ ),
+ analysisConfig.chromaStep,
+)
+
+const lightnessValue = floorToStep(
+ map(
+ Number(openMeteoData.shortwaveRadiation),
+ 0,
+ 1000,
+ config.lightnessRange.start,
+ config.lightnessRange.end,
+ ),
+ analysisConfig.lightnessStep,
+)
+
+console.info(`Got chroma value ${chromaValue}!`)
+console.info(`Got lightness value ${lightnessValue}!`)
+
+console.debug(`Trying to open cache file ${pathToCache}...`)
+const cacheFile = await fs.promises.readFile(`${pathToCache}`, {
+ encoding: "utf8",
+})
+const imagesData = JSON.parse(cacheFile) as ImageAnalysisData
+console.debug(`Opened cache file ${pathToCache}!`)
+
+
+
+findMatchingImages(imagesData, 0, chromaValue, lightnessValue)
\ No newline at end of file
diff --git a/deno.json b/deno.json
index d4ba7f1..3a6e8a8 100644
--- a/deno.json
+++ b/deno.json
@@ -7,5 +7,6 @@
"@std/assert": "jsr:@std/assert@1",
"suncalc": "npm:suncalc@^2.0.0",
"zx": "npm:zx@^8.8.5"
- }
+ },
+ "fmt": { "semiColons": false, "indentWidth": 4, "useTabs": true, "lineWidth": 120 }
}
diff --git a/utils.mts b/utils.mts
index 28f488a..ac02769 100644
--- a/utils.mts
+++ b/utils.mts
@@ -1,35 +1,60 @@
-export const configDir = process.env.XDG_CONFIG_HOME ? `${process.env.XDG_CONFIG_HOME}/rainwall` : `${os.homedir()}/.config/rainwall`
-export const cacheDir = process.env.XDG_CACHE_HOME ? `${process.env.XDG_CACHE_HOME}/rainwall` : `${os.homedir()}/.cache/rainwall`
-if (!fs.statSync(configDir)){
- fs.mkdirSync(configDir);
+export const configDir = process.env.XDG_CONFIG_HOME
+ ? `${process.env.XDG_CONFIG_HOME}/rainwall`
+ : `${os.homedir()}/.config/rainwall`
+export const cacheDir = process.env.XDG_CACHE_HOME
+ ? `${process.env.XDG_CACHE_HOME}/rainwall`
+ : `${os.homedir()}/.cache/rainwall`
+
+if (!fs.statSync(configDir)) {
+ fs.mkdirSync(configDir)
}
-if (!fs.statSync(cacheDir)){
- fs.mkdirSync(cacheDir);
+if (!fs.statSync(cacheDir)) {
+ fs.mkdirSync(cacheDir)
}
export async function loadConfig(pathToConfig: string, defaultConfig: object) {
- let config: object | undefined
- try {
- const stringConfig = await fs.promises.readFile(`${pathToConfig}`, { encoding: 'utf8' })
- if (stringConfig == undefined) {
- console.warn(`Current config blank, generating a new one... you may need to stop this process and edit the config file.`)
- config = defaultConfig
- writeDefaultConfig(pathToConfig, defaultConfig)
- } else {
- config = JSON.parse(stringConfig)
- }
- } catch (err) {
- console.warn(`Got ${(err as Error).message} when trying to load config, generating a new one... you may need to stop this process and edit the config file.`)
- config = defaultConfig
- writeDefaultConfig(pathToConfig, defaultConfig)
- }
- console.info(`Loaded config from ${pathToConfig}!`)
- return config
+ let config: object | undefined
+ try {
+ const stringConfig = await fs.promises.readFile(`${pathToConfig}`, {
+ encoding: "utf8"
+ })
+ if (stringConfig == undefined) {
+ console.warn(
+ `Current config blank, generating a new one... you may need to stop this process and edit the config file.`
+ )
+ config = defaultConfig
+ writeDefaultConfig(pathToConfig, defaultConfig)
+ } else {
+ config = JSON.parse(stringConfig)
+ }
+ } catch (err) {
+ console.warn(
+ `Got ${
+ (err as Error).message
+ } when trying to load config, generating a new one... you may need to stop this process and edit the config file.`
+ )
+ config = defaultConfig
+ writeDefaultConfig(pathToConfig, defaultConfig)
+ }
+ console.info(`Loaded config from ${pathToConfig}!`)
+ return config
}
async function writeDefaultConfig(path: string, data: object) {
- await fs.writeFile(`${path}`, JSON.stringify(data, null, 4))
- console.info(`Generated default config at ${path}!`)
+ await fs.writeFile(`${path}`, JSON.stringify(data, null, 4))
+ console.info(`Generated default config at ${path}!`)
+}
+
+export function floorToStep(num: number, step: number) {
+ return Math.floor(num / step) * step
+}
+
+export function clamp(number: number, min: number, max: number) {
+ return Math.max(min, Math.min(number, max))
+}
+
+export function map(number: number, min: number, max: number, newMin: number, newMax: number) {
+ return (((number - min) / (max - min)) * (newMax - newMin)) + newMin
}
\ No newline at end of file