Avatar

@axelav

5 public vals
Joined February 1, 2023
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { fetchJSON } from "https://esm.town/v/axelav/fetchJSON";
import process from "node:process";
export async function home(req: express.Request, res: express.Response) {
interface Artist {
name: string;
join: string;
}
interface RecordLabel {
name: string;
}
interface DiscogsRelease {
artists: Artist[];
title: string;
year: number;
genres: string[];
styles: string[];
labels: RecordLabel[];
master_id?: string;
main_release?: string;
uri: string;
id: string;
}
const params = req.params;
console.log(params, req);
const token = process.env.DISCOGS_API_TOKEN;
const toLowerCaseAndSort = (list: string[]) =>
list.map((t) => t.toLowerCase()).sort();
const unique = (x: string, idx: number, self: string[]) =>
self.indexOf(x) === idx;
const getLabel = (list: RecordLabel[]) => {
const noLabelText = "Not On Label";
if (!list || !list.length) {
return noLabelText;
}
const first = list[0]?.name;
// Use generic not on label text; strip parentheticals eg. "Not On Label (Self-released)"
if (first.match(noLabelText)) {
return noLabelText;
}
// Trim any parenthetical marks from label name
return first.trim().replace(/\s\(\d+\)/g, "");
};
const addSpaceAfterJoin = (artist: Artist) => {
const join = artist.join;
if (join) {
return join.replace(/(\/)/g, "$1 ");
}
return "";
};
const formatArtist = (artist: Artist) => {
// Remove any parenthetical marks from artist name
const name = artist.name.trim().replace(/\s\(\d+\)/g, "");
const join = addSpaceAfterJoin(artist);
// This isn't perfect. Some joins needs spaces before and after, some after, etc...
return `${name}${join}`;
};
const formatRelease = (release: DiscogsRelease) => {
const {
artists = [],
title,
year,
genres = [],
styles = [],
labels = [],
} = release;
return {
artist: artists.reduce((acc, x) => `${acc}${formatArtist(x)}`, ""),
title,
year,
label: getLabel(labels),
tags: [
...toLowerCaseAndSort(genres),
...toLowerCaseAndSort(styles),
].filter(unique),
url: release.uri,
};
};
const getSearchResults = async (
query: string,
isMaster = true
): Promise<{
results: DiscogsRelease[];
}> =>
fetchJSON(
`https://api.discogs.com/database/search?token=${token}&q=${query}${
isMaster ? "&type=master" : ""
}`
);
const getMasterRelease = async (id: string): Promise<DiscogsRelease> =>
fetchJSON(
`https://api.discogs.com/masters/${id}?token=${token}`
);
const getMainRelease = async (id: string): Promise<DiscogsRelease> =>
fetchJSON(
`https://api.discogs.com/releases/${id}?token=${token}`
);
if (params.q) {
const now = new Date().toISOString();
const subject = `val town: @axelav.discogs -> ${params.q}`;
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
import { fetch } from "https://esm.town/v/std/fetch";
export let // View this in a web browser!
// https://api3.val.town/express/async%20(req,%20res)%20=%3Eres.send(@healeycodes.hnTopStories)
const hnTopStories = (async () => {
let valTownFetchLimit = 100;
const topStories: Number[] = await fetch(
"https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty"
).then((res) => res.json());
valTownFetchLimit--;
const topStoriesData: Promise<{
title: string;
url: string;
}>[] = topStories.slice(0, valTownFetchLimit).map(async (id) => {
return await fetch(
`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`
).then((res) => res.json());
});
return `
<ul>
${(await Promise.all(topStoriesData))
.map((story) => {
return `<li><a href="${story.url}">${story.title}</a></li>`;
})
.join("\n")}
</ul>
`;
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { fetch } from "https://esm.town/v/std/fetch";
export let sendNotification = async (params: { channel: string, message: string }) => {
if (!params) {
return "Channel and message are required. Usage: @axelav.sendNotification('val town testing', 'Hello')";
}
const { channel, message } = params;
try {
const response = await fetch(`https://ntfy.sh/${channel}`, {
method: "POST",
body: message,
});
return { status: "success", ...response };
} catch (err) {
return {
status: "failed",
...err,
};
}
};
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { fetchJSON } from "https://esm.town/v/axelav/fetchJSON";
import process from "node:process";
export async function discogs(
request: express.Request,
response: express.Response
) {
console.log("Request!", request);
interface Artist {
name: string;
join: string;
}
interface RecordLabel {
name: string;
}
interface DiscogsRelease {
artists: Artist[];
title: string;
year: number;
genres: string[];
styles: string[];
labels: RecordLabel[];
master_id?: string;
main_release?: string;
uri: string;
id: string;
}
const token = process.env.DISCOGS_API_TOKEN;
const toLowerCaseAndSort = (list: string[]) =>
list.map((t) => t.toLowerCase()).sort();
const unique = (x: string, idx: number, self: string[]) =>
self.indexOf(x) === idx;
const getLabel = (list: RecordLabel[]) => {
const noLabelText = "Not On Label";
if (!list || !list.length) {
return noLabelText;
}
const first = list[0]?.name;
// Use generic not on label text; strip parentheticals eg. "Not On Label (Self-released)"
if (first.match(noLabelText)) {
return noLabelText;
}
// Trim any parenthetical marks from label name
return first.trim().replace(/\s\(\d+\)/g, "");
};
const addSpaceAfterJoin = (artist: Artist) => {
const join = artist.join;
if (join) {
return join.replace(/(\/)/g, "$1 ");
}
return "";
};
const formatArtist = (artist: Artist) => {
// Remove any parenthetical marks from artist name
const name = artist.name.trim().replace(/\s\(\d+\)/g, "");
const join = addSpaceAfterJoin(artist);
// This isn't perfect. Some joins needs spaces before and after, some after, etc...
return `${name}${join}`;
};
const formatRelease = (release: DiscogsRelease) => {
const {
artists = [],
title,
year,
genres = [],
styles = [],
labels = [],
} = release;
return {
artist: artists.reduce((acc, x) => `${acc}${formatArtist(x)}`, ""),
title,
year,
label: getLabel(labels),
tags: [
...toLowerCaseAndSort(genres),
...toLowerCaseAndSort(styles),
].filter(unique),
url: release.uri,
};
};
const getSearchResults = async (
query: string,
isMaster = true
): Promise<{
results: DiscogsRelease[];
}> =>
fetchJSON(
`https://api.discogs.com/database/search?token=${token}&q=${query}${
isMaster ? "&type=master" : ""
}`
);
const getMasterRelease = async (id: string): Promise<DiscogsRelease> =>
fetchJSON(
`https://api.discogs.com/masters/${id}?token=${token}`
);
const getMainRelease = async (id: string): Promise<DiscogsRelease> =>
fetchJSON(
`https://api.discogs.com/releases/${id}?token=${token}`
);
const params = request.params;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export let aqi = async () => {
let res = await fetchJSON(
"https://api.openaq.org/v2/latest?" +
new URLSearchParams({
limit: "10",
page: "1",
coordinates: "40.666758,-73.967150",
offset: "0",
sort: "desc",
radius: "100000",
order_by: "lastUpdated",
dumpRaw: "false",
})
);
const pm25 = res.results[0].measurements.find(
(m) => m.parameter === "pm25"
).value;
if (pm25 > 50) console.email(null, `AQI is ${pm25}, close your windows!`);
return pm25;
};
Next