[PHP] 從 Slack 無痛轉移 Discord 的做法

本篇文章更新時間:2022/01/25
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣新台幣 贊助支持。


Slack 免費版有十萬則訊息的上限,討論到一定量後只會保留「前」十萬則。作為專案討論工具是都還好,就是近期因為加入幣圈各種項目使用了 Discord 後感覺也很適合公司轉移過來,就來想辦法換工具啦~

粉絲頁上筆記 用 Discord 取代 Slack 當公司專案討論的工具,我覺得有幾點是關鍵

至於要「無痛」,也是要求有一點開發底就是!不然自己一個一個建立,對於經營好幾年的公司來說,絕對不輕鬆。

Slack 頻道匯出

就 Slack 這邊來說,開立的頻道要能帶過來 Discord,我個人懶得去申請使用 API,直接開啟瀏覽器版本的 Slack,然後使用開發者模式,捕捉載入 Slack 頻道回傳的那隻 API,可以搜尋關鍵字「channel」(超過 100 筆會分兩個請求),撈到的 JSON 格式存好檔案再寫 Discord Bot 來寫入。

Discord 機器人

這邊機器人會做的事初期比較算是「輔助工具」。程式碼先放下面:

<?php

include '../vendor/autoload.php';

use Discord\Discord;
use Discord\Parts\Channel\Channel;
use Discord\WebSockets\Event;
use Discord\WebSockets\Intents;
$discord = new Discord([
    'token'          => 'BOT_TOKEN',
    'intents'        => Intents::getDefaultIntents() | Intents::GUILD_MEMBERS,
    'loadAllMembers' => true,
]);

$discord->on('ready', function ($discord) {
    echo "Bot is ready!", PHP_EOL;

    // Listen for messages.
    $discord->on(Event::MESSAGE_CREATE, function ($message, $discord) {
        echo "{$message->author->username}: {$message->content}", PHP_EOL;
        if ($message->content == '!resetP' && !$message->author->bot) {
            $guild = $discord->guilds['88888'];
            $roles = $guild->roles;
            // 重設所有頻道權限
            $channels = $guild->channels;
            foreach ($channels as $cid => $channel) {
                foreach ($roles as $rid => $role) {
                    // 載入當前伺服器裡設定角色的所有權限,用角色的 scope 來規範頻道。如有變動角色權限設定,可以重跑一次來套用全部頻道,不然頻道的設定會是各自奔走的狀態
                    $permissions = json_decode(json_encode($roles[$rid]->permissions), true);
                    $allow       = [];
                    $deny        = [];
                    foreach ($permissions as $pkey => $bool) {
                        if ($pkey != 'bitwise') {
                            if ($bool) {
                                $allow[] = $pkey;
                            } else {
                                $deny[] = $pkey;
                            }
                        }
                    }
                    // @everyone 所有人不開放觀看頻道
                    if ($rid == '88888') {
                        $allow = [];
                        $deny  = ['view_channel'];
                    }
                    // 唯一開放所有人可以參與「33333」這個公共頻道
                    if ($rid == '88888' && $cid == '33333') {
                        $allow = ['view_channel'];
                        $deny  = [];
                    }
                    $guild->channels[$cid]->setPermissions($roles[$rid], $allow, $deny)->done(function () {
                        // echo $channel->name . " 設定 " . $roles[$rid]->name . " 權限完成!" . PHP_EOL;
                    });
                }
            }
        }
        if ($message->content == '!init' && !$message->author->bot) {
            $guild = $discord->guilds['88888'];

            $chs = [];//載入要匯入的頻道清單
            foreach ($chs as $key => $ch) {
                $newchannel = $guild->channels->create([
                    'name'                  => $ch['name'],
                    'type'                  => Channel::TYPE_TEXT,
                    'topic'                 => '頻道描述 - 建立時間:' . date('Y-m-d', $ch['time']),
                    'nsfw'                  => false,
                    'permission_overwrites' => [0 => array('id' => '88888', 'type' => 0, 'deny' => 1024, 'allow' => 0)],//預設權限為私人頻道
                ]);
                $guild->channels->save($newchannel)->done(function ($channel) {
                    echo '建立新頻道 - ID: ' . $channel->id . ' => ' . $channel->name . PHP_EOL;
                });
            }
            // Reply with "pong"
            $message->reply('pong');

        }
        if ($message->content == '!removeCH' && !$message->author->bot) {
            $guild    = $discord->guilds['88888'];
            $channels = $guild->channels;
            foreach ($channels as $cid => $channel) {
                // 除了 00000, 11111 這兩個範例頻道外,其他都刪除
                if ($cid != '00000' && $cid != '11111') {
                    $guild->channels->delete($cid)->done(function ($channel) {
                        echo 'Deleted channel: ' . $channel->name . PHP_EOL;
                    });
                }
            }
        }
        if ($message->content == '!getMembersID' && !$message->author->bot) {
            $guild   = $discord->guilds['88888'];
            $members = $guild->members;
            $str     = '';
            //列出使用者的編號與名稱,日後對應 tag 人時要用
            foreach ($members as $mid => $member) {
                $str .= $mid . '->' . $member->username . PHP_EOL;
            }
            $message->reply($str);
        }
    });

    $discord->on(Event::MESSAGE_REACTION_ADD, function ($reaction, $discord) {
        $reaction->channel->sendMessage($reaction->member->user->username . '新增了一個表情!');
        // 語音群
        // $reaction->channel->moveMember($reaction->member->user)->done(function () {
        //     echo "加進群了" . PHP_EOL;
        // });
    });
    $discord->on(Event::MESSAGE_REACTION_REMOVE, function ($reaction, $discord) {
        $reaction->channel->sendMessage($reaction->member->user->username . '移除了一個表情!');
    });
    $discord->on(Event::CHANNEL_CREATE, function ($channel, $discord) {
        var_dump($channel);
    });
});

$discord->run();

這隻 Bot 是使用 DiscordPHP 建立, Wiki 文件還算清楚,但目前最完整的應該還是 NodeJS 版本

各種語言框架可以參考這邊 比較表

建立 Discord Bot 之前要先去建立 Discord App,然後都建立完後要把 Bot 邀請進伺服器的方法如下:

https://discordapp.com/oauth2/authorize?&client_id=CLIENT_ID&scope=bot&permissions=PERMISSIONS_INTEGER 分別帶入上述連結參數去瀏覽授權。

上方程式碼主要都是建立「特殊關鍵字」來讓 Bot 判斷要執行動作,像是輸入 !init 後,機器人 Bot 就會開始處理從 Slack 撈到的頻道資料,改建立在 Discord 這邊。

其他功能重置權限、刪除頻道還有一些事件捕捉的範例就不贅述了,能運用的場景很多,像是可以判斷使用者點了一個表情符號,就視為認同這個伺服器的規範,進而授權給使用者更多解鎖的權限等。

Discord Channel Webhook

這個設計我一開始還真的轉不過來,也跟我知道大多的設計不同。 Discord Webhook 不是一個幫你把資料 push 到某一個外部資源的方法,他是提供你一個 Webhook 網址,讓你把資料帶進去頻道的功能 (整個反了!?)XD

建立 Discord App 的時候也會存入一個 INTERACTIONS ENDPOINT URL,這設計我也有看還沒有懂。也不是上述的 Webhook 概念,目前只是作為驗證 App 有效與否用。

但總而言之,你可以使用 Discord 給你的 Webhook URL 來把資料 POST 傳值進去頻道,那代表整合的方式就更多元與方便了。

這部分我就是將公司會使用的 Trello 專案管理工具對應的事件傳回 Discord 對應頻道來整合。

首先就是去建立 Trello App,取得 API Key & API Token 後可以使用網友開發的 Trello Webhook 介面化管理工具 選擇對應你的 Boards/Lists/Cards 來把 Discord 事件串上。

不過因為 Discord Webhook 傳入的格式與 Trello Webhook 的格式不同,會需要一個中介來處理轉發,不介意用別人服務的話可以套 Skyhook 這工具,介意的話,或是有更深入客製需求的話,自己寫過一隻 wrapper 來也不難。

Discord Webhook 傳入的格式與玩法可以參考文件:Webhook Resource

令我覺得這個 Webhook 厲害的是他還有「客製化欄位」的概念,也就是傳入進去的一則訊息,可以不只是訊息,還可以像「資訊卡」一般呈現。 tag 人也是可以辦到的: <#123123>(標註頻道連結)、<@123123>(標註使用者),123123是對應編號)


Share:

作者: Chun

資訊愛好人士。主張「人人都該為了偷懶而進步」。期許自己成為斜槓到變進度條 100% 的年輕人。[///////////____34%_________]

參與討論

4 則留言

  1. 大大有機會的話能分享Discord最好的私人訊息備份法嗎
    目前備份都是先請求資料後透過官方給的壓縮檔下載
    但開啟後一堆副檔名,格式感覺也跟在DC上看到的差很多
    不像line可以完整恢復QQ

    1. 我還真沒想過要備份 Discord 的訊息耶XD

      私人訊息的部分大概就是只能開著 bot 來把每一個對話給用資料庫存起來了

  2. 謝謝您回覆哈哈
    其實是想把DC帳號刪了
    但是還想留著對話看,
    爬文也找不到更好的備份恢復法
    看來有這需求的人很少

    1. 你這需求真的是有矛盾了XD
      「備份回覆」應該是不太可能會有,因為 DC 設計的概念就是讓你可以跟別人交流,這個交流不是單向你保存一份、對方保存一份,而是 DC 主機幫雙方同時保存。
      還原這件事等於你要在一個獨立的環境下恢復你的身份以及與你對話的另一個身份,對 DC 來說,如果與你對話的身份已經不存在了,那要創造過一個身份單獨給你也不太對,可能往「匯出
      對話」這方向找,然後找方法重現能觀看就好了~

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

文章
Filter

Filter Search Results