---
# System prepended metadata

title: 11/7 Discord Bot 開發(六)

---

# 11/7 Discord Bot 開發(六)

:::info
時間：2023/11/7 19:20 ~ 23:50
地點：線上會議(Discord)
參與：xiaojie4082、wei._.614、StarLeisure、SmingXO

![image.png](https://hackmd.io/_uploads/rJgbZiDXp.png)
:::


## 本次討論事項
- TDX API 政策更改
- 進度管理 Trello
- 公告轉發整合至機器人
- 添加靜宜大學專用道(往市區、海線)
- 製作社群網站嵌入式訊息

## TDX API 政策更改
> 親愛的會員您好：  
>   
> 每會員帳號可擁有3把金鑰存取平臺資料服務，帳號各金鑰使用量將合併計算虛擬點數，存取頻率則依各把金鑰分別控管(113年3月起適用)。  
> 存取頻率，現行依50次/秒/來源端IP控管，將分2階段調整：  
> 階段1：112年12月1日起改一律50次/秒/金鑰  
> 階段2：113年3月起改依各方案存取頻率調整  
> 
> ◆ 一般會員：存取頻率5次/分/1金鑰  
> ◆ 銅級會員：存取頻率5次/秒/1金鑰  
> ◆ 銀級會員：存取頻率10次/秒/1金鑰  
> ◆ 金級會員：存取頻率30次/秒/1金鑰  
> ◆ 白金級會員：存取頻率50次/秒/1金鑰  
> ◆ 專案會員：存取頻率50次/秒/1金鑰  

## 進度管理 Trello
- [Trello 看板](https://trello.com/b/IVcODoWx/discord%EF%BC%8C%E5%9C%A8%E6%A0%A1%E5%9C%92%E6%80%8E%E9%BA%BC%E7%8E%A9%EF%BC%9F%E6%89%93%E9%80%A0%E5%85%A8%E5%8F%B0%E6%9C%80%E5%A4%A7-discord-%E6%A0%A1%E5%9C%92%E7%A4%BE%E7%BE%A4%EF%BC%81)
    ![image.png](https://hackmd.io/_uploads/r1AP-owXp.png)


## 公告轉發整合至機器人
- 抓取公告
    ```python
    import requests
    from bs4 import BeautifulSoup

    def getpu():
        url = 'https://www.pu.edu.tw/p/422-1000-1011.php?Lang=zh-tw'
        response = requests.get(url=url)

        soup = BeautifulSoup(response.text,'html.parser')
        info_items = soup.find_all('div', 'mbox')

        i = 0
        for item in info_items:
            i = i + 1
            if i == 5:
                title = item.find('div', 'mtitle').a.text.strip()
                break
        i = 0
        for link in soup.find_all('a'):
            i = i + 1
            if i == 38:
                href = link.get('href')
                break
        if(href[0] == '/'):
            href = "https://www.pu.edu.tw" + href

        try:
            url = href
            response = requests.get(url=url)
            soup = BeautifulSoup(response.text,'html.parser')
            summary = (soup.find('meta', {'name': 'description'})['content']).strip()
            soup = BeautifulSoup(summary, 'html.parser')
            summary = soup.get_text()
        except:
            summary = ""
        return title, href, summary
    ```
- 發送訊息
    ```python
    @tasks.loop(minutes=3)
    async def new_background_task():
        try:
            title, href, summary = getpu()

            with open(os.getenv("NEWS_SAVE_PATH"), "r") as file:
                file_content = file.read()
            if file_content != title:
                with open(os.getenv("NEWS_SAVE_PATH"), "w") as file:
                    file.write(title)

                    embed=discord.Embed(title=title, url=href, description=summary, color=0xffffff)
                    embed.set_footer(text="資料來源:靜宜大學校首頁/公告總覽")
                    channel = bot.get_channel()
                    await channel.send(embed=embed)

        except Exception as e:
            print(e)
    ```


## 添加靜宜大學專用道(往市區、海線)
- 添加 300~310 公車時刻
- 程式碼
    ```python!
    import requests
    import json
    import time

    app_id = 's1100055-cbdd8708-c9dc-4ce6'
    app_key = '922e9fd0-b137-49d6-bb55-5917b2de073a'

    # 162 靜宜大學(校門), 主顧樓, 聖母堂(終), 聖母堂(起)
    # 301 靜宜大學(校門), 主顧樓, 靜園餐廳(終), 靜園餐廳(起)
    # 368 靜宜大學(校門), 主顧樓, 聖母堂(終), 聖母堂(起)
    # 300、302~310 靜宜大學(專用道) 

    stop_dict = {
        '162': ['TXG20091','TXG20092','TXG20093','TXG20094'], 
        '300': ['TXG13567','TXG21478'],#往市區,往海線
        '301': ['TXG20091','TXG20092','TXG15247','TXG15230'], 
        '302': ['TXG13567','TXG19438'],
        '303': ['TXG13567','TXG19438'],
        '304': ['TXG13567','TXG19438'],
        '305': ['TXG13567','TXG19438'],
        '306': ['TXG13567','TXG19438'],
        '307': ['TXG13567','TXG19438'],
        '308': ['TXG13567','TXG19438'],
        '309': ['TXG13567','TXG19438'],
        '310': ['TXG13567','TXG19438'],
        '368': ['TXG24503','TXG24504','TXG24505','TXG24506']
    } 

    auth_url="https://tdx.transportdata.tw/auth/realms/TDXConnect/protocol/openid-connect/token"

    def EstimateTime():
        class Auth():

            def __init__(self, app_id, app_key):
                self.app_id = app_id
                self.app_key = app_key

            def get_auth_header(self):
                content_type = 'application/x-www-form-urlencoded'
                grant_type = 'client_credentials'

                return{
                    'content-type' : content_type,
                    'grant_type' : grant_type,
                    'client_id' : self.app_id,
                    'client_secret' : self.app_key
                }

        class data():

            def __init__(self, app_id, app_key, auth_response):
                self.app_id = app_id
                self.app_key = app_key
                self.auth_response = auth_response

            def get_data_header(self):
                auth_JSON = json.loads(self.auth_response.text)
                access_token = auth_JSON.get('access_token')

                return{
                    'authorization': 'Bearer '+access_token
                }

        try:
            d = data(app_id, app_key, auth_response)     
        except:
            a = Auth(app_id, app_key)
            auth_response = requests.post(auth_url, a.get_auth_header())
            d = data(app_id, app_key, auth_response)
        EstimateTime = {}
        now = time.mktime(time.localtime())
        print(now)
        for route, uids in stop_dict.items(): 
            EstimateTime[route] = []
            for uid in uids: 
                url = "https://tdx.transportdata.tw/api/basic/v2/Bus/EstimatedTimeOfArrival/City/Taichung/" + route + "?%24filter=StopUID%20eq%20%27" + uid + "%27&%24orderby=StopSequence&%24format=JSON"

                try:
                    data_response = requests.get(url, headers=d.get_data_header())
                    data = json.loads(data_response.text)

                    if data[0]["EstimateTime"] is not None:
                        if data[0]["EstimateTime"]/60 > 3:
                            EstimateTime[route].append(str(int(data[0]["EstimateTime"]/60)) + " 分鐘")
                        else:
                            EstimateTime[route].append("進站中...")
                    else:    
                        target_time = time.strptime(data[0]["NextBusTime"], "%Y-%m-%dT%H:%M:%S%z")
                        target_time = time.mktime(target_time)
                        diff_minute = int(target_time - now) / 60
                        if diff_minute > 3:
                            EstimateTime[route].append(str(int(diff_minute)) + " 分鐘")
                        elif diff_minute > 0:
                            EstimateTime[route].append("進站中...") 
                        else:
                            EstimateTime[route].append("尚未發車")         

                except Exception as e:
                    print(url)
                    EstimateTime[route].append("尚未發車")
        return EstimateTime
    ```
    ```python!
    @tasks.loop(minutes=1)
    async def bus_background_task():
        try:
            Estimate = EstimateTime()
            current_time = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime())
            embed=discord.Embed(title="校園公車站牌資訊", description=
                "校門\n" + 
                ":bus: `162` `" + Estimate["162"][0] + "`\n" +
                ":bus: `301` `" + Estimate["301"][0] + "`\n" +
                ":bus: `368` `" + Estimate["368"][0] + "`\n\n" +

                "主顧樓\n" +
                ":bus: `162` `" + Estimate["162"][1] + "`\n" +
                ":bus: `301` `" + Estimate["301"][1] + "`\n" +
                ":bus: `368` `" + Estimate["368"][1] + "`\n\n" +

                "聖母堂/靜園餐廳\n" +
                ":bus: `162` `" + Estimate["162"][3] + "`\n" +
                ":bus: `301` `" + Estimate["301"][3] + "`\n" +
                ":bus: `368` `" + Estimate["368"][3] + "`\n\n" +

                "靜宜大學(專用道)-往市區\n" +
                ":bus: `300` `" + Estimate["300"][0] + "`\n" +
                ":bus: `302` `" + Estimate["302"][0] + "`\n" +
                ":bus: `303` `" + Estimate["303"][0] + "`\n" +
                ":bus: `304` `" + Estimate["304"][0] + "`\n" +
                ":bus: `305` `" + Estimate["305"][0] + "`\n" +
                ":bus: `306` `" + Estimate["306"][0] + "`\n" +
                ":bus: `307` `" + Estimate["307"][0] + "`\n" +
                ":bus: `308` `" + Estimate["308"][0] + "`\n" +
                ":bus: `309` `" + Estimate["309"][0] + "`\n" +
                ":bus: `310` `" + Estimate["310"][0] + "`\n\n" +

                "靜宜大學(專用道)-往海線\n" +
                ":bus: `300` `" + Estimate["300"][1] + "`\n" +
                ":bus: `302` `" + Estimate["302"][1] + "`\n" +
                ":bus: `303` `" + Estimate["303"][1] + "`\n" +
                ":bus: `304` `" + Estimate["304"][1] + "`\n" +
                ":bus: `305` `" + Estimate["305"][1] + "`\n" +
                ":bus: `306` `" + Estimate["306"][1] + "`\n" +
                ":bus: `307` `" + Estimate["307"][1] + "`\n" +
                ":bus: `308` `" + Estimate["308"][1] + "`\n" +
                ":bus: `309` `" + Estimate["309"][1] + "`\n" +
                ":bus: `310` `" + Estimate["310"][1] + "`\n\n" 

            , color=0xfff700)
            embed.set_footer(text="更新時間：" + current_time + "\n" + "資料來源：https://tdx.transportdata.tw")
            # message = await bot.get_channel().fetch_message()
            # await message.edit(embed=embed)
            channel = bot.get_channel()
            await channel.send(embed=embed)
        except Exception as e:
            print(e)
    ```

## 製作社群網站嵌入式訊息
- 製作工具
    - https://cog-creators.github.io/discord-embed-sandbox/
- 程式碼
    ```python!
        embed=discord.Embed(title="PUHub-你在校園生活中不可或缺的夥伴", url="https://puhub.org/", color=0xffffff)
        embed.set_image(url="https://cdn.discordapp.com/attachments/1006251089898786816/1171441049932156968/image.png")
        button = discord.ui.Button(label="PUHub", url="https://puhub.org/")
        view = discord.ui.View()
        view.add_item(button)
        await ctx.send(embed=embed, view=view)
    ```
## 統整目前進度
### PUHub 網站
- 最新消息
    ![image.png](https://hackmd.io/_uploads/rk1jC0DX6.png)
- 天氣預報
    ![image.png](https://hackmd.io/_uploads/ByAi0RPXp.png)
- 公車時刻
    ![image.png](https://hackmd.io/_uploads/SJ0hRRwQp.png)
- 選課評價
    ![image.png](https://hackmd.io/_uploads/SJX0CAPQ6.png)
    ![image.png](https://hackmd.io/_uploads/B1RRARwX6.png)
- 匿名留言
    ![image.png](https://hackmd.io/_uploads/ryteJ1OQp.png)
- 建議回饋
    ![image.png](https://hackmd.io/_uploads/HJGmy1dXa.png)
- 實用連結
    ![image.png](https://hackmd.io/_uploads/rJfG11dXT.png)


### Discord Bot
- 最新消息
    ![image.png](https://hackmd.io/_uploads/B13waRPQp.png)
- 天氣預報
    ![image.png](https://hackmd.io/_uploads/ryX4aCP76.png)
- 公車時刻
    ![image.png](https://hackmd.io/_uploads/S1eTG6CP7a.png)
- 社群網站
    ![image.png](https://hackmd.io/_uploads/S1zbpCPXT.png)
- ChatGPT
    ![image.png](https://hackmd.io/_uploads/HykQC0PQp.png)
- 搜尋課程(依照類別、關鍵字)
    ![image.png](https://hackmd.io/_uploads/HJYN0Rv7T.png)
- 查看課程餘額
    ![image.png](https://hackmd.io/_uploads/r1HU00wmT.png)
- 查看課程綱要
    ![image.png](https://hackmd.io/_uploads/rkdwCAvXp.png)

## 下次討論事項
- 未定 PUHub 網頁(二)
    - 針對 [10/14 PUHub 網頁(一)](https://hackmd.io/@PU-X-Discord/%E5%B0%88%E6%A1%88%E5%AF%A6%E4%BD%9C/%2FQLlNGZaoTtOV57bwrwzNsw) 進行修改

