import { Adapter , App , Bot , Schema , segment , Session } from 'koishi' ; import { DiscordBot } from './bot' ; import * as DC from './types' ; interface PrivilegedIntents { members ? : boolean ; } export interface AdapterConfig extends Adapter . WebSocketClient . Config , App . Config . Request { intents ? : PrivilegedIntents ; } export const AdapterConfig = Schema . intersect ( [ Schema . object ( { intents : Schema . object ( { members : Schema . boolean ( ) , } ) , } ) , App . Config . Request , Adapter . WebSocketClient . Config , ] ) ; export const adaptUser = ( user ) : Bot . User => ( { userId : user . id , avatar : `https://cdn.discordapp.com/avatars/${ user . id }/${ user . avatar }.png` , username : user . username , discriminator : user . discriminator , isBot : user . bot || false , } ) ; export function adaptGroup ( data ) { return { guildId : data . id , guildName : data . name , } ; } export function adaptChannel ( data ) { return { channelId : data . id , channelName : data . name , } ; } export const adaptAuthor = ( author ) : Bot . Author => ( { ... adaptUser ( author ) , nickname : author . username , } ) ; export function adaptMessage ( bot , meta , session = { } ) { if ( meta . author ) { session . author = adaptAuthor ( meta . author ) ; session . userId = meta . author . id ; } if ( meta . member ?. nick ) { session . author . nickname = meta . member ?. nick ; } session . content = '' ; if ( meta . content ) { session . content = meta . content . replace ( /<@[!&](.+?)>/ , ( _ , id ) => { if ( meta . mention_roles . includes ( id ) ) { return segment ( 'at' , { role : id } ) ; } else { const user = meta . mentions ?. find ( u => u . id === id ) ; return segment . at ( id , { name : user ?. username } ) ; } } ) . replace ( /<:(.*):(.+?)>/ , ( _ , name , id ) => segment ( 'face' , { id : id , name } ) ) . replace ( /<a:(.*):(.+?)>/ , ( _ , name , id ) => segment ( 'face' , { id : id , name , animated : true } ) ) . replace ( /@everyone/ , ( ) => segment ( 'at' , { type : 'all' } ) ) . replace ( /@here/ , ( ) => segment ( 'at' , { type : 'here' } ) ) . replace ( /<#(.+?)>/ , ( _ , id ) => { const channel = meta . mention_channels ?. find ( c => c . id === id ) ; return segment . sharp ( id , { name : channel ?. name } ) ; } ) ; } if ( meta . attachments ?. length ) { session . content += meta . attachments . map ( v => { if ( v . height && v . width && v . content_type ?. startsWith ( 'image/' ) ) { return segment ( 'image' , { url : v . url , proxy_url : v . proxy_url , file : v . filename , } ) ; } else if ( v . height && v . width && v . content_type ?. startsWith ( 'video/' ) ) { return segment ( 'video' , { url : v . url , proxy_url : v . proxy_url , file : v . filename , } ) ; } else if ( v . content_type ?. startsWith ( 'audio/' ) ) { return segment ( 'record' , { url : v . url , proxy_url : v . proxy_url , file : v . filename , } ) ; } else { return segment ( 'file' , { url : v . url , proxy_url : v . proxy_url , file : v . filename , } ) ; } } ) . join ( '' ) ; } for ( const embed of meta . embeds ) { if ( embed . image ) { session . content += segment ( 'image' , { url : embed . image . url , proxy_url : embed . image . proxy_url } ) ; } if ( embed . thumbnail ) { session . content += segment ( 'image' , { url : embed . thumbnail . url , proxy_url : embed . thumbnail . proxy_url } ) ; } if ( embed . video ) { session . content += segment ( 'video' , { url : embed . video . url , proxy_url : embed . video . proxy_url } ) ; } } return session as Bot . Message ; } function adaptMessageSession ( bot , meta , session = { } ) { adaptMessage ( bot , meta , session ) ; session . messageId = meta . id ; session . timestamp = new Date ( meta . timestamp ) . valueOf ( ) || Date . now ( ) ; if ( meta . message_reference ) { const { message_id , channel_id } = meta . message_reference ; session . content = segment ( 'quote' , { id : message_id , channelId : channel_id } ) + session . content ; } return session ; } function prepareMessageSession ( session , data ) { session . guildId = data . guild_id ; session . subtype = data . guild_id ? 'group' : 'private' ; session . channelId = data . channel_id ; } function prepareReactionSession ( session , data ) { session . userId = data . user_id ; session . messageId = data . message_id ; session . guildId = data . guild_id ; session . channelId = data . channel_id ; session . subtype = data . guild_id ? 'group' : 'private' ; if ( ! data . emoji ) return ; const { id , name } = data . emoji ; session . content = id ? `${ name }:${ id }` : name ; } export async function adaptSession ( bot , input ) { const session = { selfId : bot . selfId , } ; if ( input . t === 'MESSAGE_CREATE' ) { session . type = 'message' ; prepareMessageSession ( session , input . d ) ; adaptMessageSession ( bot , input . d , session ) ; if ( session . userId === bot . selfId ) return ; } else if ( input . t === 'MESSAGE_UPDATE' ) { session . type = 'message-updated' ; prepareMessageSession ( session , input . d ) ; const msg = await bot . internal . getChannelMessage ( input . d . channel_id , input . d . id ) ; adaptMessageSession ( bot , msg , session ) ; if ( session . userId === bot . selfId ) return ; } else if ( input . t === 'MESSAGE_DELETE' ) { session . type = 'message-deleted' ; session . messageId = input . d . id ; prepareMessageSession ( session , input . d ) ; } else if ( input . t === 'MESSAGE_REACTION_ADD' ) { session . type = 'reaction-added' ; prepareReactionSession ( session , input . d ) ; } else if ( input . t === 'MESSAGE_REACTION_REMOVE' ) { session . type = 'reaction-deleted' ; session . subtype = 'one' ; prepareReactionSession ( session , input . d ) ; } else if ( input . t === 'MESSAGE_REACTION_REMOVE_ALL' ) { session . type = 'reaction-deleted' ; session . subtype = 'all' ; prepareReactionSession ( session , input . d ) ; } else if ( input . t === 'MESSAGE_REACTION_REMOVE_EMOJI' ) { session . type = 'reaction-deleted' ; session . subtype = 'emoji' ; prepareReactionSession ( session , input . d ) ; } else { return ; } return new Session ( bot , session ) ; }