温泉追加とリファクタリング
このコミットが含まれているのは:
バイナリファイルは表示されません.
|
変更後 幅: | 高さ: | サイズ: 221 KiB |
@@ -1,8 +1,13 @@
|
|||||||
|
"""
|
||||||
|
Bluesky のニジカがいろいろする.
|
||||||
|
(近々機能ごとにファイル分けて systemd でイベント管理する予定)
|
||||||
|
"""
|
||||||
|
|
||||||
import io
|
import io
|
||||||
import json
|
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from atproto import Client, models
|
from atproto import Client, models
|
||||||
@@ -22,7 +27,7 @@ def check_notifications (
|
|||||||
for notification in (client.app.bsky.notification.list_notifications ()
|
for notification in (client.app.bsky.notification.list_notifications ()
|
||||||
.notifications):
|
.notifications):
|
||||||
if not notification.is_read:
|
if not notification.is_read:
|
||||||
if notification.reason in ['mention', 'reply']:
|
if notification.reason in ['mention', 'reply', 'quote']:
|
||||||
uris += [notification.uri]
|
uris += [notification.uri]
|
||||||
elif notification.reason == 'follow':
|
elif notification.reason == 'follow':
|
||||||
client.follow (notification.author.did)
|
client.follow (notification.author.did)
|
||||||
@@ -62,6 +67,7 @@ def main (
|
|||||||
|
|
||||||
last_posted_at = datetime.now () - timedelta (hours = 6)
|
last_posted_at = datetime.now () - timedelta (hours = 6)
|
||||||
has_got_snack_time = False
|
has_got_snack_time = False
|
||||||
|
has_taken_hot_spring = False
|
||||||
watched_videos = []
|
watched_videos = []
|
||||||
while True:
|
while True:
|
||||||
now = datetime.now ()
|
now = datetime.now ()
|
||||||
@@ -111,7 +117,7 @@ def main (
|
|||||||
external = models.AppBskyEmbedExternal.External (
|
external = models.AppBskyEmbedExternal.External (
|
||||||
title = title,
|
title = title,
|
||||||
description = description,
|
description = description,
|
||||||
thumb = upload.blob,
|
thumb = thumb,
|
||||||
uri = uri))
|
uri = uri))
|
||||||
client.post (Talk.main (f"""
|
client.post (Talk.main (f"""
|
||||||
ニコニコに『{ datum['title'] }』という動画がアップされました。
|
ニコニコに『{ datum['title'] }』という動画がアップされました。
|
||||||
@@ -122,6 +128,7 @@ def main (
|
|||||||
```
|
```
|
||||||
このことについて、みんなに告知するとともに、ニジカちゃんの感想を教えてください。 """),
|
このことについて、みんなに告知するとともに、ニジカちゃんの感想を教えてください。 """),
|
||||||
embed = embed_external)
|
embed = embed_external)
|
||||||
|
last_posted_at = now
|
||||||
|
|
||||||
if now.hour == 14 and has_got_snack_time:
|
if now.hour == 14 and has_got_snack_time:
|
||||||
has_got_snack_time = False
|
has_got_snack_time = False
|
||||||
@@ -142,16 +149,40 @@ def main (
|
|||||||
'下部に「おやつタイムだ!!!!」という'
|
'下部に「おやつタイムだ!!!!」という'
|
||||||
'日本語のテキストが表示されている。'),
|
'日本語のテキストが表示されている。'),
|
||||||
image = client.com.atproto.repo.upload_blob (f).blob)
|
image = client.com.atproto.repo.upload_blob (f).blob)
|
||||||
|
|
||||||
client.post (Talk.main ('おやつタイムだ!!!!'),
|
client.post (Talk.main ('おやつタイムだ!!!!'),
|
||||||
embed = models.app.bsky.embed.images.Main (
|
embed = models.app.bsky.embed.images.Main (
|
||||||
images = [image]))
|
images = [image]))
|
||||||
last_posted_at = now
|
last_posted_at = now
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
has_got_snack_time = True
|
has_got_snack_time = True
|
||||||
|
|
||||||
|
if now.hour == 20 and has_got_snack_time:
|
||||||
|
has_taken_hot_spring = False
|
||||||
|
|
||||||
|
if now.hour == 21 and not has_taken_hot_spring:
|
||||||
|
try:
|
||||||
|
with open ('./assets/hot-spring.jpg', 'rb') as f:
|
||||||
|
image = models.AppBskyEmbedImages.Image (
|
||||||
|
alt = ('左に喜多ちゃん、右にわさび県産滋賀県が'
|
||||||
|
'V字に並んでいる。'
|
||||||
|
'喜多ちゃんは右手でピースサインをして'
|
||||||
|
'片目をウインクしている。'
|
||||||
|
'わさび県産滋賀県はただ茫然と'
|
||||||
|
'立ち尽くしている。'
|
||||||
|
'背景には'
|
||||||
|
'血と空の色をした放射線状の模様が広がり、'
|
||||||
|
'下部に「温泉に入ろう!!!」という'
|
||||||
|
'日本語のテキストが表示されている。'),
|
||||||
|
image = client.com.atproto.repo.upload_blob (f).blob)
|
||||||
|
client.post (Talk.main ('温泉に入ろう!!!'),
|
||||||
|
embed = models.app.bsky.embed.images.Main (
|
||||||
|
images = [image]))
|
||||||
|
last_posted_at = now
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
has_taken_hot_spring = True
|
||||||
|
|
||||||
if now - last_posted_at >= timedelta (hours = 6):
|
if now - last_posted_at >= timedelta (hours = 6):
|
||||||
client.post (Talk.main ('今どうしてる?'))
|
client.post (Talk.main ('今どうしてる?'))
|
||||||
last_posted_at = now
|
last_posted_at = now
|
||||||
@@ -161,7 +192,7 @@ def main (
|
|||||||
|
|
||||||
def get_embed_info (
|
def get_embed_info (
|
||||||
url: str
|
url: str
|
||||||
) -> (str, str, str):
|
) -> tuple[str, str, str]:
|
||||||
title: str = ''
|
title: str = ''
|
||||||
description: str = ''
|
description: str = ''
|
||||||
thumbnail: str = ''
|
thumbnail: str = ''
|
||||||
@@ -181,12 +212,18 @@ def get_embed_info (
|
|||||||
title = tmp.text
|
title = tmp.text
|
||||||
|
|
||||||
tmp = soup.find ('meta', attrs = { 'name': 'description' })
|
tmp = soup.find ('meta', attrs = { 'name': 'description' })
|
||||||
if tmp is not None:
|
if tmp is not None and hasattr (tmp, 'get'):
|
||||||
description = tmp.get ('content')
|
try:
|
||||||
|
description = cast (str, tmp.get ('content'))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
tmp = soup.find ('meta', attrs = { 'name': 'thumbnail' })
|
tmp = soup.find ('meta', attrs = { 'name': 'thumbnail' })
|
||||||
if tmp is not None:
|
if tmp is not None and hasattr (tmp, 'get'):
|
||||||
thumbnail = tmp.get ('content')
|
try:
|
||||||
|
thumbnail = cast (str, tmp.get ('content'))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
return (title, description, thumbnail)
|
return (title, description, thumbnail)
|
||||||
|
|
||||||
|
|||||||
@@ -16,48 +16,9 @@ class VideoInfo (TypedDict):
|
|||||||
description: str
|
description: str
|
||||||
|
|
||||||
|
|
||||||
def get_nico_deerjika (
|
|
||||||
) -> list:
|
|
||||||
URL = ('https://snapshot.search.nicovideo.jp/api/v2/snapshot/video'
|
|
||||||
'/contents/search')
|
|
||||||
|
|
||||||
now = datetime.now ()
|
|
||||||
base = now - timedelta (hours = 24)
|
|
||||||
|
|
||||||
params = { 'q': '伊地知ニジカ OR ぼざろクリーチャーシリーズ',
|
|
||||||
'targets': 'tags',
|
|
||||||
'_sort': '-startTime',
|
|
||||||
'fields': 'contentId,title,description,tags,startTime',
|
|
||||||
'_limit': 20,
|
|
||||||
'jsonFilter': json.dumps ({ 'type': 'or',
|
|
||||||
'filters': [{
|
|
||||||
'type': 'range',
|
|
||||||
'field': 'startTime',
|
|
||||||
'from': ('%04d-%02d-%02dT05:00:00+09:00'
|
|
||||||
% (base.year, base.month, base.day,
|
|
||||||
base.hour, base.minute)),
|
|
||||||
'to': ('%04d-%02d-%02dT05:00:00+09:00'
|
|
||||||
% (now.year, now.month, now.day)),
|
|
||||||
'include_lower': True }] }) }
|
|
||||||
|
|
||||||
try:
|
|
||||||
res = requests.get (URL, params = params, timeout = 60).json ()
|
|
||||||
except Timeout:
|
|
||||||
return []
|
|
||||||
|
|
||||||
data = []
|
|
||||||
for datum in res['data']:
|
|
||||||
datum['tags'] = datum['tags'].split ()
|
|
||||||
data.append (datum)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def get_latest_deerjika (
|
def get_latest_deerjika (
|
||||||
) -> VideoInfo | None:
|
) -> VideoInfo | None:
|
||||||
tag = '伊地知ニジカ'
|
tag = '伊地知ニジカ OR ぼざろクリーチャーシリーズ'
|
||||||
url = f"https://www.nicovideo.jp/tag/{ tag }"
|
url = f"https://www.nicovideo.jp/tag/{ tag }"
|
||||||
|
|
||||||
params = { 'sort': 'f',
|
params = { 'sort': 'f',
|
||||||
|
|||||||
新しい課題から参照
ユーザをブロックする