#1 型定義が未完成だが,動作は問題ないと思ãはれるため本番に移す.

このコミットが含まれているのは:
2024-11-06 03:57:57 +09:00
コミット d1b1bf2a14
6個のファイルの変更140行の追加32行の削除
+49
ファイルの表示
@@ -0,0 +1,49 @@
from datetime import datetime
from atproto import models
class Client:
app: AppNamespace
def get_current_time_iso (self) -> datetime: ...
def get_post_thread (
self,
uri: str,
parent_height: int | None = None
) -> Response: ...
def follow (self, did: str) -> None: ...
class AppNamespace:
bsky: AppBskyNamespace
class AppBskyNamespace:
notification: AppBskyNotificationNamespace
class AppBskyNotificationNamespace:
def list_notifications (self) -> Response: ...
def update_seen (self, seen: dict[str, datetime]) -> None: ...
class Response:
notifications: list[Notification]
thread: (ThreadViewPost
| models.AppBskyFeedDefs.NotFoundPost
| models.AppBskyFeedDefs.BlockedPost)
class Notification:
is_read: bool
reason: str
uri: str
author: ProfileView
class ProfileView:
did: str
ファイルの表示
シンボリックリンク
+1
ファイルの表示
@@ -0,0 +1 @@
db/eloquent.pyi
+15 -6
ファイルの表示
@@ -70,8 +70,8 @@ def main (
client.login (account.USER_ID, account.PASSWORD) 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) got_kiriban_at: date = datetime.now ().date () - timedelta (days = datetime.now ().hour < 15)
kiriban_list: list[tuple[int, nico.VideoInfo]] = nico.get_kiriban_list (got_kiriban_at)
kiriban_interval: timedelta = ((get_kiriban_dt_to_update () - datetime.now ()) kiriban_interval: timedelta = ((get_kiriban_dt_to_update () - datetime.now ())
/ len (kiriban_list)) / len (kiriban_list))
next_kiriban_at = datetime.now () next_kiriban_at = datetime.now ()
@@ -109,8 +109,17 @@ def main (
root = records[-1]['strong_ref'])) root = records[-1]['strong_ref']))
if kiriban_list and datetime.now () >= next_kiriban_at: if kiriban_list and datetime.now () >= next_kiriban_at:
(views_count, video_code) = ( (views_count, video_info) = (
kiriban_list.pop (random.randint (0, len (kiriban_list) - 1))) kiriban_list.pop (random.randint (0, len (kiriban_list) - 1)))
uri = f"https://www.nicovideo.jp/watch/{ video_info['contentId'] }"
(title, description, thumbnail) = get_embed_info (uri)
try:
upload = client.com.atproto.repo.upload_blob (
io.BytesIO (requests.get (thumbnail,
timeout = 60).content))
thumb = upload.blob
except Timeout:
thumb = None
embed_external = models.AppBskyEmbedExternal.Main ( embed_external = models.AppBskyEmbedExternal.Main (
external = models.AppBskyEmbedExternal.External ( external = models.AppBskyEmbedExternal.External (
title = title, title = title,
@@ -118,11 +127,11 @@ def main (
thumb = thumb, thumb = thumb,
uri = uri)) uri = uri))
client.post (Talk.main (f""" client.post (Talk.main (f"""
ニコニコの『{ datum['title'] }』という動画が{ views_count }再生を突破しました。 ニコニコの『{ video_info['title'] }』という動画が{ views_count }再生を突破しました。
つけられたタグは「{ '」、「'.join (datum['tags']) }」です。 つけられたタグは「{ '」、「'.join (video_info['tags']) }」です。
概要には次のように書かれています: 概要には次のように書かれています:
```html ```html
{ datum['description'] } { video_info['description'] }
``` ```
このことについて、ニジカちゃんからのお祝いメッセージを下さい。"""), このことについて、ニジカちゃんからのお祝いメッセージを下さい。"""),
embed = embed_external) embed = embed_external)
@@ -167,7 +176,7 @@ def main (
if now.hour == 15: if now.hour == 15:
if got_kiriban_at < datetime.now ().date (): if got_kiriban_at < datetime.now ().date ():
kiriban_list = nico.get_kiriban_list () kiriban_list = nico.get_kiriban_list (datetime.now ().date ())
got_kiriban_at = datetime.now ().date () got_kiriban_at = datetime.now ().date ()
kiriban_interval = ((get_kiriban_dt_to_update () - datetime.now ()) kiriban_interval = ((get_kiriban_dt_to_update () - datetime.now ())
/ len (kiriban_list)) / len (kiriban_list))
+74 -25
ファイルの表示
@@ -2,19 +2,32 @@
ニコニコのニジカ動画取得モヂュール ニコニコのニジカ動画取得モヂュール
""" """
import os
from datetime import date, timedelta
from typing import TypedDict, cast from typing import TypedDict, cast
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from requests.exceptions import Timeout from requests.exceptions import Timeout
from eloquent import DatabaseManager, Model
from db.models import Video from db.models import Tag, Video, VideoHistory, VideoTag
KIRIBAN_VIEWS_COUNTS = { *range (100, 1_000, 100), CONFIG: dict[str, DbConfig] = { 'mysql': { 'driver': 'mysql',
*range (1_000, 10_000, 1_000), 'host': 'localhost',
*range (10_000, 1_000_001, 10_000), 'database': 'nizika_nico',
194, 245, 510, 114_514, 1_940, 2_450, 5_100, 24_500, 'user': os.environ['MYSQL_USER'],
51_000, 2_424 } 'password': os.environ['MYSQL_PASS'],
'prefix': '' } }
DB = DatabaseManager (CONFIG)
Model.set_connection_resolver (DB)
KIRIBAN_VIEWS_COUNTS: set[int] = { *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): class VideoInfo (TypedDict):
@@ -46,25 +59,7 @@ def get_latest_deerjika (
except Exception: except Exception:
return None return None
bs = get_bs_from_url ('https://www.nicovideo.jp/watch/' return get_video_info (video_info['contentId'])
+ video_info['contentId'])
if bs is None:
return None
try:
title = bs.find ('title')
if title is None:
return None
video_info['title'] = '-'.join (title.text.split ('-')[:(-1)])[:(-1)]
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') # type: ignore
except Exception:
return None
return cast (VideoInfo, video_info)
def get_bs_from_url ( def get_bs_from_url (
@@ -100,8 +95,62 @@ def get_bs_from_url (
return BeautifulSoup (req.text, 'html.parser') return BeautifulSoup (req.text, 'html.parser')
def get_video_info (
video_code: str,
) -> VideoInfo | None:
video_info: dict[str, str | list[str]] = { 'contentId': video_code }
bs = get_bs_from_url (f"https://www.nicovideo.jp/watch/{ video_code }")
if bs is None:
return None
try:
title = bs.find ('title')
if title is None:
return None
video_info['title'] = '-'.join (title.text.split ('-')[:(-1)])[:(-1)]
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') # type: ignore
except Exception:
return None
return cast (VideoInfo, video_info)
def get_kiriban_list ( def get_kiriban_list (
base_date: date,
) -> list[tuple[int, VideoInfo]]: ) -> list[tuple[int, VideoInfo]]:
kiriban_list: list[tuple[int, VideoInfo]] = [] kiriban_list: list[tuple[int, VideoInfo]] = []
latest_fetched_at = cast (date, VideoHistory.max ('fetched_at'))
previous_fetched_at = cast (date, (VideoHistory
.where ('fetched_at', '<', latest_fetched_at)
.max ('fetched_at')))
for kiriban_views_count in KIRIBAN_VIEWS_COUNTS:
targets = ({ vh.video.code for vh in (VideoHistory
.where ('fetched_at', latest_fetched_at)
.where ('views_count', '>=', kiriban_views_count)
.get ()) }
- { vh.video.code for vh in (VideoHistory
.where ('fetched_at', previous_fetched_at)
.where ('views_count', '>=', kiriban_views_count)
.get ()) })
for code in targets:
video_info = get_video_info (code)
if video_info is not None:
kiriban_list.append ((kiriban_views_count, video_info))
return kiriban_list
class DbConfig (TypedDict):
driver: str
host: str
database: str
user: str
password: str
prefix: str
サブモジュール nizika_nico が更新されました: 67b76e6dd4...b2f5f81ca8