Skip to content

Commit 3878181

Browse files
authored
Merge pull request #10 from hker9527/feat-9
feat: Auto-generate Twitter embeds
2 parents 60865fa + bdf3934 commit 3878181

File tree

4 files changed

+98
-1
lines changed

4 files changed

+98
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ yarn start
3939
|[saucenao](https://saucenao.com/)|Reverse image search|
4040
|[exchangerate.host](https://exchangerate.host/)|Currency conversion|
4141
|[Google Safebrowsing](https://safebrowsing.google.com/)|Detect malicious URLs|
42+
|[VXTwitter](https://github.com/dylanpdx/BetterTwitFix)|Generate embeds from Twitter links|

src/modules/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { StealthModule } from "@type/StealthModule";
22
import { moebooru } from "./moebooru";
33
import { pixiv } from "./pixiv";
44
import { scam } from "./scam";
5+
import { twitter } from "./twitter";
56

67
export const modules: StealthModule[] = [
78
moebooru,
89
pixiv,
9-
scam
10+
scam,
11+
twitter
1012
]

src/modules/twitter.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { StealthModule } from "@type/StealthModule";
2+
import { ZAPIVXTwitter } from "@type/api/VXTwitter";
3+
import { APIEmbed } from "discord.js";
4+
5+
export const twitter: StealthModule = {
6+
name: "twitter",
7+
event: "messageCreate",
8+
pattern: /https?:\/\/(?:www\.)?twitter\.com\/(?:#!\/)?(\w+)\/status\/(\d+)/,
9+
action: async (obj) => {
10+
const statusId = obj.matches!.pop();
11+
const response = await (await fetch(`https://api.vxtwitter.com/i/status/${statusId}`)).text();
12+
13+
try {
14+
const json = JSON.parse(response);
15+
if (ZAPIVXTwitter.check(json)) {
16+
await obj.message.suppressEmbeds();
17+
return {
18+
type: "send",
19+
result: {
20+
embeds: ([
21+
{
22+
author: {
23+
name: `${json.user_name} (@${json.user_screen_name})`,
24+
icon_url: "https://cdn-icons-png.flaticon.com/512/179/179342.png",
25+
url: `https://twitter.com/${json.user_screen_name}`
26+
},
27+
color: 0x1DA1F2,
28+
// Remove https://t.co/... links
29+
description: json.text.replace(/https:\/\/t\.co\/\w+/g, ""),
30+
timestamp: new Date(json.date_epoch * 1000).toISOString(),
31+
image: {
32+
url: json.mediaURLs[0]
33+
},
34+
url: json.tweetURL
35+
}
36+
] as APIEmbed[]).concat(json.mediaURLs.splice(1).map((url: string) => ({
37+
image: {
38+
url
39+
},
40+
url: json.tweetURL
41+
})))
42+
}
43+
};
44+
}
45+
return false;
46+
} catch (e) {
47+
return false;
48+
}
49+
}
50+
};

src/types/api/VXTwitter.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { z } from "zod";
2+
import { Zod } from "@type/Zod";
3+
4+
const SizeSchema = z.object({
5+
height: z.number(),
6+
width: z.number()
7+
});
8+
9+
const BaseMediaSchema = z.object({
10+
altText: z.string().nullable(),
11+
size: SizeSchema,
12+
thumbnail_url: z.string(),
13+
url: z.string()
14+
});
15+
16+
const ImageMediaSchema = BaseMediaSchema.extend({
17+
type: z.literal("image")
18+
});
19+
20+
const VideoMediaSchema = BaseMediaSchema.extend({
21+
duration_millis: z.number(),
22+
type: z.literal("video")
23+
});
24+
25+
const VXTwitterSchema = z.object({
26+
conversationID: z.string(),
27+
date: z.string(),
28+
date_epoch: z.number(),
29+
hashtags: z.array(z.string()),
30+
likes: z.number(),
31+
mediaURLs: z.array(z.string()),
32+
media_extended: z.array(z.union([ImageMediaSchema, VideoMediaSchema])),
33+
replies: z.number(),
34+
retweets: z.number(),
35+
text: z.string(),
36+
tweetID: z.string(),
37+
tweetURL: z.string(),
38+
user_name: z.string(),
39+
user_screen_name: z.string()
40+
});
41+
42+
export const ZAPIVXTwitter = new Zod(VXTwitterSchema);
43+
44+
export type APIVXTwitter = z.infer<typeof VXTwitterSchema>;

0 commit comments

Comments
 (0)