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

:::
## 本次討論事項
- 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)

## 公告轉發整合至機器人
- 抓取公告
```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 網站
- 最新消息

- 天氣預報

- 公車時刻

- 選課評價


- 匿名留言

- 建議回饋

- 實用連結

### Discord Bot
- 最新消息

- 天氣預報

- 公車時刻

- 社群網站

- ChatGPT

- 搜尋課程(依照類別、關鍵字)

- 查看課程餘額

- 查看課程綱要

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