Avatar

@burningion

4 public vals
Joined April 2, 2024

Update Tidbyt workouts

Updates a Tidbyt with workout information:

Tidbyt_Workouts_Backup_2.00_06_13_08.Still001.png

For more information, watch the YouTube video or reach out to me on Twitter!

Usage

  1. Fork this val.
  2. Update the byDay variable to get your workout information for each day of the current and previous week.
  3. If you want to use a rule different than "Don't skip twice", you can fork and update the weekWorkoutIcons val.
Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { createTidbytWorkoutsImage } from "https://esm.town/v/andreterron/createTidbytWorkoutsImage";
import { setTidbytImage } from "https://esm.town/v/andreterron/setTidbytImage";
import { weekWorkoutIcons } from "https://esm.town/v/andreterron/weekWorkoutIcons";
import { workedOutByDay } from "https://esm.town/v/andreterron/workedOutByDay";
import { blob } from "https://esm.town/v/std/blob?v=11";
export let updateTidbytWorkout = async (force: boolean = false) => {
const timezone = "America/Los_Angeles";
// byDay is a Record<"YYYY-MM-DD", truthy | falsy> that
// stores which days you worked out. Recommended to get
// the current and previous week of data.
// e.g.: {"2023-11-15": true, "2023-11-13": true}
const byDay = await workedOutByDay(timezone);
// icons is an Array with one icon type for each of the 7 days
// e.g.: ["done", "skipped", "done", "done", "today", "future", "future"]
const icons = weekWorkoutIcons(byDay, timezone);
// Don't update the image if it didn't change
let iconsCache: string[] | undefined;
try {
iconsCache = await blob.getJSON("tidbytWorkoutCache");
} catch (e) {
console.error(e);
}
await blob.setJSON("tidbytWorkoutCache", icons);
if (!force && iconsCache && iconsCache.every((v, i) => v === icons[i])) {
console.log("No changes detected, skipping updating tidbyt app");
return;
}
// img is the resulting jimp image
const img = await createTidbytWorkoutsImage(icons);
// Send the image to Tidbyt
await setTidbytImage({
image: (await img.getBufferAsync(img.getMIME())).toString("base64"),
});
};

Kysely on val.town

Uses @easrng/kyselyVtDialect as a Kysely Dialect and @easrng/kyselyVtTypes for type autogeneration.

Readme
1
2
3
4
5
6
7
8
9
10
11
import type { DB } from "https://easrng-kyselyvttypes.web.val.run/?tables=contacts";
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@0.27.3";
// ^ pinned version because val.town's editor doesn't
// load version ranges.
const db = new Kysely<DB>({
dialect: new VtDialect(),
});
const rows = await db.selectFrom("contacts").selectAll().execute();
// ^ { contact_id: number; email: string; first_name: string; ... }[]
console.log(rows);

Val Shot

Generate val source code screenshot using sourcecodeshots.com

⚠️ This service is offered for personal use under a reasonable usage policy as stated here: https://sourcecodeshots.com/docs

📣 Special thanks to @pomdtr for their help and contributions!

Usage

https://vladimyr-valshot.web.val.run/v/<author>/<val>

Example

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// SPDX-License-Identifier: 0BSD
import { fetchVal } from "https://esm.town/v/vladimyr/fetchVal";
import { serveReadme } from "https://esm.town/v/vladimyr/serveReadme";
import { toHonoHandler } from "https://esm.town/v/vladimyr/toHonoHandler";
import { Hono } from "npm:hono";
import ky from "npm:ky";
const router = new Hono();
// router.get("/", toHonoHandler(serveReadme(import.meta.url)));
router.get("/", async (c) => {
// const { author, name } = c.req.param();
const query = c.req.query();
const res = await fetch(
"https://raw.githubusercontent.com/burningion/dab-and-tpose-controlled-lights/master/src/dab-tpose-controller.py",
);
const code = await res.text();
const imageURL = await createScreenshot(code, query.theme);
return c.redirect(imageURL.href);
});
export default router.fetch;
export async function createScreenshot(code: string, theme: string = "dark-plus"): Promise<URL> {
const apiUrl = "https://sourcecodeshots.com/api/image/permalink";
const { url } = await ky.post(apiUrl, {
json: {
code,
settings: { language: "python", theme },
},
}).json();
return new URL(url);
}

AQI Alerts

Get email alerts when AQI is unhealthy near you.

Set up

  1. Click Fork
  2. Change location (Line 4) to describe your location. It accepts fairly flexible English descriptions which it turns into locations via nominatim's geocoder API.
  3. Click Run

Background

This val uses nominatim's geocoder to get your lat, lon, and air quality data from OpenAQ. It uses EPA's NowCast AQI Index calculation and severity levels. Learn more: https://www.val.town/v/stevekrouse.easyAQI

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { email } from "https://esm.town/v/std/email?v=9";
import { easyAQI } from "https://esm.town/v/stevekrouse/easyAQI";
export async function aqi(interval: Interval) {
const location = "Brooklyn Navy Yard, Brooklyn"; // <-- change to place, city, or zip code
const data = await easyAQI({ location });
if (!interval.lastRunAt) {
email({
text:
`You will now get Air Quality alerts for ${location} if it's unhealthy. It is now ${data.aqi} which is ${data.severity}.`,
subject: `AQI Alerts for ${location} setup!`,
});
}
if (data.severity.includes("Unhealthy")) {
email({
text: "Air Quality: " + data.severity,
subject: `AQI in ${location} is ${data.aqi}`,
});
}
}
Next