Misskey → Twitter 크로스포스팅 (With an Image)

#NodeJS

중간에 노드 서버가 하나 있어야 하긴 합니다.

미스키에서 노트를 하면, 웹훅을 통해 그 노트 정보를 중간 서버에 전송하고, 그 서버에서 데이터를 적당히 가공해서 트위터로 보내 주는 거거든요.

기존 크로스포스터를 안 쓰는 이유는

  1. 원본 미스키로의 url 또는 자기 서비스 해시태그가 달려 있음
  2. 파일을 첨부할 수 없음

그래서, 직접 만드는 김에 파일 첨부 기능도 제작했습니다.

미스키 노트에 파일이 첨부되어 있으면 웹훅으로 들어오는 요청에서 URL을 읽을 수 있습니다. 그걸 바탕으로 파일을 업로드 할거예요.

그런데 Misskey는 WebP 위주로 파일을 올려버리고, 트위터는 WebP를 제외하고 파일을 첨부합니다. 그래서 이것도 한번 png로의 변환 과정을 거쳐야 해요.

const { TwitterApi } = require('twitter-api-v2');
const axios = require('axios');
const sharp = require('sharp');

//....

app.post('/misskey', (req, res) => {
    let misEvent = req.body
    const twitterClient = new TwitterApi({ 
        appKey: '', 
        appSecret: '',
        accessToken: '',
        accessSecret: '',
    })
    console.log(misEvent)
    if (misEvent.body.note.files.length == 0 && misEvent.body.note.text) {
        async function myfunction() {
            (async () => {
        
                try {
                    const tweet = await twitterClient.v2.tweet(misEvent.body.note.text.substring(0, 140));
                    console.log('Tweet posted successfully:', tweet);
                    res.json({ok: true})
        
                } catch (error) {
                    console.error('Error posting tweet:', error);
                    res.json({ok: true})
                }
            })();
        
            console.log('Inside of myfunction');
        }

        myfunction()
    } else if (misEvent.body.note.files.length > 0 && misEvent.body.note.text) {
        var url = misEvent.body.note.files[0].url
        
        async function myfunction2() {
            (async () => {

                try {
                    const downStream = await axios({
                        method: 'GET',
                        responseType: 'arraybuffer',
                        url: url,
                      }).catch(function (error) {
                        res.send({error:error});
                      });
                      const img = await sharp(downStream.data).toFormat('png').toBuffer(); // webp → png
                      const mediaId = await twitterClient.v1.uploadMedia(img, { mimeType: 'png'}); 
                      
                      const tweet = await twitterClient.v2.tweet({text: misEvent.body.note.text.substring(0, 140), media: { media_ids: [mediaId] }});
                      console.log('Tweet posted successfully:', tweet);
    
                } catch (error) {
                    console.error('Error posting tweet:', error);
                }
        
            })();
        
            console.log('Inside of myfunction');
        }

        myfunction2()

        res.json({ok: true})
    } else { //Text값이 없는 노트(리노트 같은 거)일 때...
        res.json({ok: true})
    }
})