url-atproto
This commit is contained in:
parent
650e8446a0
commit
0b1dbc87ac
@ -25,6 +25,10 @@
|
||||
"name": "timezone",
|
||||
"version": "1.1.0"
|
||||
},
|
||||
{
|
||||
"name": "url-atproto",
|
||||
"version": "1.0.1"
|
||||
},
|
||||
{
|
||||
"name": "url-fediverse",
|
||||
"version": "1.0.4"
|
||||
|
9
url-atproto/plugin.json
Normal file
9
url-atproto/plugin.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"main": "plugin.js",
|
||||
"name": "url-atproto",
|
||||
"description": "AT Protocol (Bluesky) URL",
|
||||
"version": "1.0.1",
|
||||
"tags": ["urlreply", "at-protocol", "bluesky"],
|
||||
"dependencies": ["urlreply"],
|
||||
"npmDependencies": []
|
||||
}
|
175
url-atproto/plugin.ts
Normal file
175
url-atproto/plugin.ts
Normal file
@ -0,0 +1,175 @@
|
||||
import {
|
||||
Plugin,
|
||||
Configurable,
|
||||
EventListener,
|
||||
DependencyLoad,
|
||||
} from '@squeebot/core/lib/plugin';
|
||||
|
||||
import { IMessage } from '@squeebot/core/lib/types';
|
||||
import { httpGET, sanitizeEscapedText } from '@squeebot/core/lib/common';
|
||||
|
||||
interface ATRecordEmbed {
|
||||
$type: string;
|
||||
images: [
|
||||
{
|
||||
alt: string;
|
||||
aspectRatio: {
|
||||
height: number;
|
||||
width: number;
|
||||
};
|
||||
image: {
|
||||
$type: string;
|
||||
ref: {
|
||||
$link: string;
|
||||
};
|
||||
mimeType: string;
|
||||
size: number;
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
interface ATRecord {
|
||||
$type: string;
|
||||
createdAt: string;
|
||||
langs: string[];
|
||||
text: string;
|
||||
embed?: ATRecordEmbed;
|
||||
facets?: unknown[];
|
||||
}
|
||||
|
||||
interface ATEmbed {
|
||||
$type: string;
|
||||
images?: [
|
||||
{
|
||||
thumb: string;
|
||||
fullsize: string;
|
||||
alt: string;
|
||||
aspectRatio: {
|
||||
height: number;
|
||||
width: number;
|
||||
};
|
||||
}
|
||||
];
|
||||
record?: ATRecord;
|
||||
}
|
||||
|
||||
interface ATThread {
|
||||
thread: {
|
||||
$type: 'app.bsky.feed.defs#threadViewPost';
|
||||
post: {
|
||||
uri: string;
|
||||
cid: string;
|
||||
author: {
|
||||
did: string;
|
||||
handle: string;
|
||||
displayName: string;
|
||||
avatar: string;
|
||||
labels: unknown[];
|
||||
createdAt: string;
|
||||
};
|
||||
record: ATRecord;
|
||||
embed?: ATEmbed;
|
||||
replyCount: number;
|
||||
repostCount: number;
|
||||
likeCount: number;
|
||||
quoteCount: number;
|
||||
indexedAt: string;
|
||||
labels: unknown[];
|
||||
};
|
||||
replies: ATThread['thread'][];
|
||||
};
|
||||
}
|
||||
|
||||
@Configurable({})
|
||||
class TwitterURLPlugin extends Plugin {
|
||||
@EventListener('pluginUnload')
|
||||
public unloadEventHandler(plugin: string | Plugin): void {
|
||||
if (plugin === this.name || plugin === this) {
|
||||
this.emit('pluginUnloaded', this);
|
||||
}
|
||||
}
|
||||
|
||||
async handlePost(
|
||||
data: ATThread['thread']['post'],
|
||||
msg: IMessage
|
||||
): Promise<boolean> {
|
||||
const keys = [];
|
||||
const end = sanitizeEscapedText(data.record.text);
|
||||
|
||||
keys.push(['field', 'Bluesky', { color: 'cyan', type: 'title' }]);
|
||||
keys.push([
|
||||
'field',
|
||||
data.likeCount.toString(),
|
||||
{ color: 'red', label: ['♥', 'Likes'], type: 'metric' },
|
||||
]);
|
||||
keys.push([
|
||||
'field',
|
||||
data.repostCount.toString(),
|
||||
{ color: 'green', label: ['↱↲', 'Reposts'], type: 'metric' },
|
||||
]);
|
||||
keys.push(['bold', '@' + data.author.handle + ':']);
|
||||
keys.push(['field', end, { type: 'content' }]);
|
||||
|
||||
if (data.embed?.images?.length) {
|
||||
const amount = data.embed.images.length;
|
||||
keys.push([
|
||||
'field',
|
||||
`[${amount} attachment${amount !== 1 ? 's' : ''}]`,
|
||||
{ color: 'brown' },
|
||||
]);
|
||||
}
|
||||
|
||||
if (data.embed?.record) {
|
||||
keys.push(['field', '[quoted post]', { color: 'brown' }]);
|
||||
}
|
||||
|
||||
msg.resolve(keys);
|
||||
return true;
|
||||
}
|
||||
|
||||
async atprotoGetThread(url: URL, msg: IMessage): Promise<boolean> {
|
||||
const urlString = url.toString();
|
||||
const det = urlString.match(
|
||||
/^(https?):\/\/((?:[\w\d-]+\.)*[\w\d-]+\.\w{2,16})\/(?:profile\/)?@?([\d\w-_.]+)\/(?:post\/)?([\w\d]+[^&#?\s/])/i
|
||||
);
|
||||
if (!det) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const [_, proto, webviewHost, atHost, postId] = det;
|
||||
|
||||
if (proto !== 'https' || webviewHost !== 'bsky.app') {
|
||||
// no other webviews atm
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const postInfo = await httpGET(
|
||||
`https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?depth=1&parentHeight=1&uri=at://${atHost}/app.bsky.feed.post/${postId}`
|
||||
);
|
||||
|
||||
const data = JSON.parse(postInfo) as ATThread;
|
||||
if (data?.thread) {
|
||||
return this.handlePost(data.thread.post, msg);
|
||||
}
|
||||
} catch (e) {
|
||||
msg.resolve('Could not fetch Bluesky post, it may be private.');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@DependencyLoad('urlreply')
|
||||
addURLHandler(urlreply: any): void {
|
||||
urlreply.registerHandler(
|
||||
this.name,
|
||||
'bsky.app/',
|
||||
(url: URL, msg: IMessage) => {
|
||||
return this.atprotoGetThread(url, msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TwitterURLPlugin;
|
9
url-atproto/schema.json
Normal file
9
url-atproto/schema.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://squeebot.lunasqu.ee/pkg/plugins-evert/url-atproto.schema.json",
|
||||
"title": "url-atproto",
|
||||
"description": "url-atproto plugin configuration",
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
Loading…
Reference in New Issue
Block a user