Search

Results include substring matches and semantically similar vals. Learn more
neverstew avatar
finalUrl
@neverstew
Final URL I keep getting tracking links as part of emails. They suck! Use Val Town as a tracking shield - call this val and get redirected to the final URL at the end of the redirection chain without picking up trackers along the way. https://neverstew-finalurl.web.val.run/<tracking_link> Example The Glastonbury registration lookup link. https://neverstew-finalurl.web.val.run/https://scke65qh.r.eu-west-1.awstrack.me/L0/https:%2F%2Fglastonbury.seetickets.com%2Fregistration%2Flookup/2/01020189fe6dd832-f894deea-eab7-4d1d-8c6a-0818e87ac95c-000000/8f6rVLcCc3v6CQNroYC81q9YkaU=335
HTTP
import { fetch } from "https://esm.town/v/std/fetch";
export async function finalUrl(req: Request) {
const url = new URL(req.url).pathname.replace(/^\//, "");
const response = await fetch(url);
iakovos avatar
renderTopStories
@iakovos
An interactive, runnable TypeScript val by iakovos
Script
import { getUrlHostname } from "https://esm.town/v/iakovos/getUrlHostname";
export function renderTopStories(stories: {
id: number;
title: string;
teretzdev avatar
scrapeAndPreviewDelta8Products
@teretzdev
* Scrape product details from Delta8Pro website * @returns Array of product objects with details
HTTP
* @returns Array of product objects with details
export default async function scrapeProducts() {
try {
* @returns Formatted string of product previews
export function previewProducts(products, limit = 5) {
return products.slice(0, limit).map(product => {
* @returns Array of scraped products
export async function runAndPreview() {
const products = await scrapeProducts();
* @returns Filtered array of products
export function filterProductsByCategory(products, category) {
return products.filter(product =>
* @returns Sorted array of products
export function sortProductsByPrice(products, ascending = true) {
return [...products].sort((a, b) => {
vladimyr avatar
keyDidResolver
@vladimyr
An interactive, runnable TypeScript val by vladimyr
Script
import ky from "npm:ky@1.2.0";
function resolveDidKey(did) {
return ky.get(`https://dev.uniresolver.io/1.0/identifiers/${did}`, {
headers: {
accept: "application/ld+json; profile=\"https://w3id.org/did-resolution\"",
}).json();
export function getResolver() {
return { key: resolveDidKey };
browniebroke avatar
btcPriceAlert
@browniebroke
BTC Price Alert This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency. Fork this val to get these notifications on your inbox.
Cron
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
maraiaharc avatar
mybabi
@maraiaharc
@jsxImportSource https://esm.sh/react@18.2.0
HTTP
url: "https://open.spotify.com/track/3AJwUDP919kvQ9QcozQPxg?si=f336236a56094d84",
function App() {
const [selectedSong, setSelectedSong] = useState(null);
</div>
function client() {
createRoot(document.getElementById("root")).render(<App />);
if (typeof document !== "undefined") { client(); }
export default async function server(request: Request): Promise<Response> {
return new Response(
dthyresson avatar
getSpotifyTrackUrl
@dthyresson
getSpotifyTrackUrl Get a Spotify Track Url using the Spotify Web API given an artist and a song title. Track info is cached by the query and also the spotify track id, so your popular queries won't have to fetch from Spotify over and over. Examples import { getSpotifyTrackUrl } from "https://esm.town/v/dthyresson/getSpotifyTrackUrl"; const reni = await getSpotifyTrackUrl("Stone Roses", "Fools Gold"); const ian = await getSpotifyTrackUrl("Joy Division", "Love Will Tear Us Apart"); const kim = await getSpotifyTrackUrl("Pixies", "Velouria"); console.log(reni) console.log(ian) console.log(kim) Info Uses getSpotifyAccessToken which requires you to set environment variables from your Spotify Developers account. SPOTIFY_CLIENT_ID SPOTIFY_CLIENT_SECRET Your access token is cached by getSpotifyAccessToken to avoid fetching over and over.
Script
format?: SpotifyTrackUrlFormat;
export function buildSpotifyTrackKey(artist: string, title: string) {
const key = `${SPOTIFY_TRACK_KEY_PREFIX}_artist:${kebabCase(artist)}_title:${kebabCase(title)}`.toLowerCase();
return key;
export function spotifyTrackUrl(track, format: SpotifyTrackUrlFormat) {
if (!track) return;
return url;
export function spotifyTrackAppLink(track) {
if (!track) return;
return url;
async function cacheTrack(spotifyTrackKey: string, track: any) {
console.debug(`Caching track ${spotifyTrackKey}`);
await blob.setJSON(`${SPOTIFY_TRACK_KEY_PREFIX}_id:${track.id}`, track);
export async function getSpotifyTrackUrl(artist: string, title: string, options?: SpotifyTrackUrlOptions) {
const format = options?.format || "web";
ryanwaits avatar
hexToUtf8
@ryanwaits
An interactive, runnable TypeScript val by ryanwaits
Script
export function hexToUtf8(hex: string) {
if (!hex) {
return;
reosablo avatar
uuidGeneratorStream
@reosablo
generate UUID v4 every 200ms in streaming response. Note that streaming is not available in Val Town as of May 2024.
HTTP
export default async function fetch(req: Request) {
const countParam = new URL(req.url).searchParams.get("count");
if (countParam === null) {
charlypoly avatar
websiteHasChanged
@charlypoly
An interactive, runnable TypeScript val by charlypoly
Script
import { PNG } from "npm:pngjs";
import slugify from "npm:slugify";
export async function hasWebsiteChanged(url: string, threshold = 0.5) {
const slug = slugify(url);
const buffer = await screenshotPage(url);
vladimyr avatar
keyvhqBlob
@vladimyr
// SPDX-License-Identifier: 0BSD
Script
key?: string;
export const blobStore = createStore();
export function createStore<T>(options?: KeyvBlobOptions): Store<T> {
const key = options?.key ?? "keyv";
return new KeyvLow<T>({
vladimyr avatar
extractHeaderComments
@vladimyr
// SPDX-License-Identifier: 0BSD
Script
// SPDX-License-Identifier: 0BSD
export function extractHeaderComments(code: string) {
const comments: string[] = [];
let currChar;
ezomode avatar
btcPriceAlert
@ezomode
BTC Price Alert This val monitors the price of Bitcoin (BTC) and sends an email alert if the price fluctuates significantly. Specifically, it checks the current BTC price against the last recorded price and triggers an email notification if the change exceeds 20%. The email includes the new price, formatted as currency. Fork this val to get these notifications on your inbox.
Cron
import { email } from "https://esm.town/v/std/email?v=9";
import { currency } from "https://esm.town/v/stevekrouse/currency";
export async function btcPriceAlert() {
const lastBtcPrice: number = await blob.getJSON("lastBtcPrice");
let btcPrice = await currency("usd", "btc");
georgemandis avatar
convertEmailToBlogDraft
@georgemandis
Convert Emails to Blog Drafts This val will receive inbound emails and create a new Markdown file in a specified GitHub repository. Create drafts for your static site (or, for the bold, publish directly!) by simply sending an email! Notes This script assumes you're using some kind of static site generator that can read from a GitHub repository. There are many to choose from in this space. I'm partial to 11ty Gmail is doing some heavy-lifting for me here in terms of kindly converting my HTML email to Markdown behind the scenes. It's not a guarantee all email providers do this. If yours does not, you may have to investigate an HTML-to-Markdown conversion step. We'll use the GitHub API via Octokit to create the file. You'll need to create a token and store it an an environmental variable in your Val Town settings. Enjoy! ā€” George https://george.mand.is/2024/09/using-email-and-val-town-to-draft-blog-posts/
Email
import { Octokit } from "https://esm.sh/@octokit/core";
import { email } from "https://esm.town/v/std/email";
export default async function(emailData: Email) {
// Extract email content
const htmlContent = emailData.text;
hrbrmstr avatar
cisaKEVToRSS
@hrbrmstr
CISA KEV To RSS This val.town HTTP endpoint reads the JSON from CISA's Known Exploited Vulnerabilities Catalog and converts it to an RSS feed.
HTTP
const RSS_FEED_URL = "https://hrbrmstr-cisakevtorss.web.val.run"; // Update this to your actual RSS feed URL
function escapeXML(str: string): string {
return str.replace(/&/g, "&amp;")
.replace(/'/g, "&apos;");
function removeInvalidXMLChars(str: string): string {
return str
.replace(/\uFFFD/g, ""); // Remove Unicode Replacement Character
function generateRSS(data: any): string {
const { title, catalogVersion, dateReleased, vulnerabilities } = data;
return rss;
export async function handler(req: Request): Promise<Response> {
try {