diff --git a/.gitmodules b/.gitmodules index 1fd27f6..3c5684e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = ai url = https://git.miteruzo.com/miteruzo/nizika_broadcast branch = main +[submodule "db"] + path = db + url = https://git.miteruzo.com/miteruzo/nizika_nico diff --git a/db b/db new file mode 160000 index 0000000..6a5e6df --- /dev/null +++ b/db @@ -0,0 +1 @@ +Subproject commit 6a5e6dfadec664a653c697bc5463c943302d2ec2 diff --git a/main.py b/main.py index 8d8029a..ca5d5a2 100644 --- a/main.py +++ b/main.py @@ -4,9 +4,12 @@ Bluesky のニジカがいろいろする. """ import io +import random import sys import time -from datetime import datetime, timedelta +from datetime import date, datetime +from datetime import time as dt_time +from datetime import timedelta from typing import cast import requests @@ -67,6 +70,12 @@ def main ( client.login (account.USER_ID, account.PASSWORD) + kiriban_list: list[tuple[int, nico.VideoInfo]] = nico.get_kiriban_list () + got_kiriban_at: date = datetime.now ().date () - timedelta (days = datetime.now ().hour < 15) + kiriban_interval: timedelta = ((get_kiriban_dt_to_update () - datetime.now ()) + / len (kiriban_list)) + next_kiriban_at = datetime.now () + last_posted_at = datetime.now () - timedelta (hours = 6) has_got_snack_time = False has_taken_hot_spring = False @@ -99,6 +108,27 @@ def main ( parent = records[0]['strong_ref'], root = records[-1]['strong_ref'])) + if kiriban_list and datetime.now () >= next_kiriban_at: + (views_count, video_code) = ( + kiriban_list.pop (random.randint (0, len (kiriban_list) - 1))) + embed_external = models.AppBskyEmbedExternal.Main ( + external = models.AppBskyEmbedExternal.External ( + title = title, + description = description, + thumb = thumb, + uri = uri)) + client.post (Talk.main (f""" +ニコニコの『{ datum['title'] }』という動画が{ views_count }再生を突破しました。 +つけられたタグは「{ '」、「'.join (datum['tags']) }」です。 +概要には次のように書かれています: +```html +{ datum['description'] } +``` +このことについて、ニジカちゃんからのお祝いメッセージを下さい。"""), + embed = embed_external) + next_kiriban_at += kiriban_interval + last_posted_at = now + latest_deerjika = nico.get_latest_deerjika () if latest_deerjika is not None: for datum in [e for e in [latest_deerjika] @@ -135,29 +165,37 @@ def main ( if now.hour == 14 and has_got_snack_time: has_got_snack_time = False - if now.hour == 15 and not has_got_snack_time: - try: - with open ('./assets/snack-time.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_got_snack_time = True + if now.hour == 15: + if got_kiriban_at < datetime.now ().date (): + kiriban_list = nico.get_kiriban_list () + got_kiriban_at = datetime.now ().date () + kiriban_interval = ((get_kiriban_dt_to_update () - datetime.now ()) + / len (kiriban_list)) + next_kiriban_at = datetime.now () + + if not has_got_snack_time: + try: + with open ('./assets/snack-time.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_got_snack_time = True if now.hour == 20 and has_taken_hot_spring: has_taken_hot_spring = False @@ -192,7 +230,6 @@ def main ( time.sleep (60) - def get_embed_info ( url: str ) -> tuple[str, str, str]: @@ -231,5 +268,15 @@ def get_embed_info ( return (title, description, thumbnail) +def get_kiriban_dt_to_update ( +) -> datetime: + now = datetime.now () + today = now.date () + dt = datetime.combine (today, dt_time (15, 0)) + if dt <= now: + dt += timedelta (days = 1) + return dt + + if __name__ == '__main__': main (*sys.argv[1:]) diff --git a/nico.py b/nico.py index 1154a43..79bdbc4 100644 --- a/nico.py +++ b/nico.py @@ -2,12 +2,18 @@ ニコニコのニジカ動画取得モヂュール """ -from typing import TypedDict +from typing import TypedDict, cast import requests from bs4 import BeautifulSoup from requests.exceptions import Timeout +KIRIBAN_VIEWS_COUNTS = { *range (100, 1_000, 100), + *range (1_000, 10_000, 1_000), + *range (10_000, 1_000_001, 10_000), + 194, 245, 510, 114_514, 1_940, 2_450, 5_100, 24_500, + 51_000, 2_424 } + class VideoInfo (TypedDict): contentId: str @@ -44,16 +50,19 @@ def get_latest_deerjika ( return None try: - video_info['title'] = '-'.join (bs.find ('title').text.split ('-')[:(-1)])[:(-1)] + title = bs.find ('title') + if title is None: + return None + video_info['title'] = '-'.join (title.text.split ('-')[:(-1)])[:(-1)] - tags = bs.find ('meta', attrs = { 'name': 'keywords' }).get ('content') + tags: str = bs.find ('meta', attrs = { 'name': 'keywords' }).get ('content') # type: ignore video_info['tags'] = tags.split (',') - video_info['description'] = bs.find ('meta', attrs = { 'name': 'description' }).get ('content') + video_info['description'] = bs.find ('meta', attrs = { 'name': 'description' }).get ('content') # type: ignore except Exception: return None - return video_info + return cast (VideoInfo, video_info) def get_bs_from_url ( @@ -87,3 +96,10 @@ def get_bs_from_url ( req.encoding = req.apparent_encoding return BeautifulSoup (req.text, 'html.parser') + + +def get_kiriban_list ( +) -> list[tuple[int, VideoInfo]]: + kiriban_list: list[tuple[int, VideoInfo]] = [] + +