2023-09-06 01:07:05 +00:00
// @ts-check
2023-10-07 10:39:49 +00:00
console . log ( "This could take up to 30 seconds. Please be patient." )
2023-09-06 01:07:05 +00:00
const assert = require ( "assert" ) . strict
const fs = require ( "fs" )
const sqlite = require ( "better-sqlite3" )
const HeatSync = require ( "heatsync" )
2023-10-07 10:39:49 +00:00
const args = require ( "minimist" ) ( process . argv . slice ( 2 ) , { string : [ "emoji-guild" ] } )
2023-09-06 01:07:05 +00:00
const config = require ( "../config" )
const passthrough = require ( "../passthrough" )
const db = new sqlite ( "db/ooye.db" )
2023-10-02 01:00:14 +00:00
const migrate = require ( "../db/migrate" )
2023-09-06 01:07:05 +00:00
const sync = new HeatSync ( { watchFS : false } )
2023-10-07 08:57:09 +00:00
Object . assign ( passthrough , { sync , config , db } )
const orm = sync . require ( "../db/orm" )
passthrough . from = orm . from
passthrough . select = orm . select
const DiscordClient = require ( "../d2m/discord-client" )
const discord = new DiscordClient ( config . discordToken , "no" )
passthrough . discord = discord
2023-09-06 01:07:05 +00:00
const api = require ( "../matrix/api" )
const file = require ( "../matrix/file" )
const reg = require ( "../matrix/read-registration" )
const utils = require ( "../m2d/converters/utils" )
2023-10-07 10:39:49 +00:00
function die ( message ) {
console . error ( message )
process . exit ( 1 )
}
async function uploadAutoEmoji ( guild , name , filename ) {
let emoji = guild . emojis . find ( e => e . name === name )
if ( ! emoji ) {
console . log ( ` Uploading ${ name } ... ` )
const data = fs . readFileSync ( filename , null )
emoji = await discord . snow . guildAssets . createEmoji ( guild . id , { name , image : "data:image/png;base64," + data . toString ( "base64" ) } )
} else {
console . log ( ` Reusing ${ name } ... ` )
}
db . prepare ( "REPLACE INTO auto_emoji (name, emoji_id, guild_id) VALUES (?, ?, ?)" ) . run ( emoji . name , emoji . id , guild . id )
return emoji
}
2023-09-06 01:07:05 +00:00
; ( async ( ) => {
const mxid = ` @ ${ reg . sender _localpart } : ${ reg . ooye . server _name } `
// ensure registration is correctly set...
2024-03-23 05:39:37 +00:00
assert ( reg . sender _localpart . startsWith ( reg . ooye . namespace _prefix ) , "appservice's localpart must be in the namespace it controls" )
assert ( utils . eventSenderIsFromDiscord ( mxid ) , "appservice's mxid must be in the namespace it controls" )
assert ( reg . ooye . server _origin . match ( /^https?:\/\// ) , "server origin must start with http or https" )
assert . notEqual ( reg . ooye . server _origin . slice ( - 1 ) , "/" , "server origin must not end in slash" )
const botID = Buffer . from ( config . discordToken . split ( "." ) [ 0 ] , "base64" ) . toString ( )
assert ( botID . match ( /^[0-9]{10,}$/ ) , "discord token must follow the correct format" )
2024-08-28 00:51:28 +00:00
assert . match ( reg . url , /^https?:/ , "url must start with http:// or https://" )
2023-10-07 08:57:09 +00:00
console . log ( "✅ Configuration looks good..." )
2023-09-06 01:07:05 +00:00
2023-09-12 07:23:23 +00:00
// database ddl...
2023-10-02 01:00:14 +00:00
await migrate . migrate ( db )
2023-09-12 07:23:23 +00:00
2023-10-07 08:57:09 +00:00
// add initial rows to database, like adding the bot to sim...
2024-03-23 05:39:37 +00:00
db . prepare ( "INSERT OR IGNORE INTO sim (user_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)" ) . run ( botID , reg . sender _localpart . slice ( reg . ooye . namespace _prefix . length ) , reg . sender _localpart , mxid )
2023-10-07 08:57:09 +00:00
console . log ( "✅ Database is ready..." )
2023-10-07 10:39:49 +00:00
2023-10-16 03:47:42 +00:00
// ensure appservice bot user is registered...
try {
await api . register ( reg . sender _localpart )
} catch ( e ) {
2024-01-20 04:03:03 +00:00
if ( e . errcode === "M_USER_IN_USE" || e . data ? . error === "Internal server error" ) {
// "Internal server error" is the only OK error because older versions of Synapse say this if you try to register the same username twice.
} else {
throw e
}
2023-10-16 03:47:42 +00:00
}
// upload initial images...
const avatarUrl = await file . uploadDiscordFileToMxc ( "https://cadence.moe/friends/out_of_your_element.png" )
console . log ( "✅ Matrix appservice login works..." )
2023-10-07 10:39:49 +00:00
// upload the L1 L2 emojis to some guild
const emojis = db . prepare ( "SELECT name FROM auto_emoji WHERE name = 'L1' OR name = 'L2'" ) . pluck ( ) . all ( )
if ( emojis . length !== 2 ) {
// If an argument was supplied, always use that one
let guild = null
if ( args [ "emoji-guild" ] ) {
if ( typeof args [ "emoji-guild" ] === "string" ) {
guild = await discord . snow . guild . getGuild ( args [ "emoji-guild" ] )
}
if ( ! guild ) return die ( ` Error: You asked emojis to be uploaded to guild ID ${ args [ "emoji-guild" ] } , but the bot isn't in that guild. ` )
}
// Otherwise, check if we have already registered an auto emoji guild
if ( ! guild ) {
const guildID = passthrough . select ( "auto_emoji" , "guild_id" , { name : "_" } ) . pluck ( ) . get ( )
if ( guildID ) {
guild = await discord . snow . guild . getGuild ( guildID , false )
}
}
// Otherwise, check if we should create a new guild
if ( ! guild ) {
const guilds = await discord . snow . user . getGuilds ( { limit : 11 , with _counts : false } )
if ( guilds . length < 10 ) {
console . log ( " Creating a guild for emojis..." )
guild = await discord . snow . guild . createGuild ( { name : "OOYE Emojis" } )
}
}
// Otherwise, it's the user's problem
if ( ! guild ) {
return die ( ` Error: The bot needs to upload some emojis. Please say where to upload them to. Run seed.js again with --emoji-guild=GUILD_ID ` )
}
// Upload those emojis to the chosen location
db . prepare ( "REPLACE INTO auto_emoji (name, emoji_id, guild_id) VALUES ('_', '_', ?)" ) . run ( guild . id )
await uploadAutoEmoji ( guild , "L1" , "docs/img/L1.png" )
await uploadAutoEmoji ( guild , "L2" , "docs/img/L2.png" )
}
console . log ( "✅ Emojis are ready..." )
2023-10-07 08:57:09 +00:00
// set profile data on discord...
const avatarImageBuffer = await fetch ( "https://cadence.moe/friends/out_of_your_element.png" ) . then ( res => res . arrayBuffer ( ) )
await discord . snow . user . updateSelf ( { avatar : "data:image/png;base64," + Buffer . from ( avatarImageBuffer ) . toString ( "base64" ) } )
await discord . snow . requestHandler . request ( ` /applications/@me ` , { } , "patch" , "json" , { description : "Powered by **Out Of Your Element**\nhttps://gitdab.com/cadence/out-of-your-element" } )
console . log ( "✅ Discord profile updated..." )
2023-09-06 01:07:05 +00:00
// set profile data on homeserver...
await api . profileSetDisplayname ( mxid , "Out Of Your Element" )
await api . profileSetAvatarUrl ( mxid , avatarUrl )
2023-10-07 08:57:09 +00:00
console . log ( "✅ Matrix profile updated..." )
2023-09-06 01:07:05 +00:00
2023-10-07 08:57:09 +00:00
console . log ( "Good to go. I hope you enjoy Out Of Your Element." )
process . exit ( )
2023-09-06 01:07:05 +00:00
} ) ( )