完成(たぶん)

このコミットが含まれているのは:
2024-10-07 22:53:13 +09:00
コミット e4b541ecdc
+135 -19
ファイルの表示
@@ -1,3 +1,7 @@
"""
日次で実行し,ぼざクリ DB を最新に更新する.
"""
from __future__ import annotations from __future__ import annotations
import json import json
@@ -7,7 +11,7 @@ import string
import time import time
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import TypedDict, cast from typing import Any, TypedDict, cast
import mysql.connector import mysql.connector
import requests import requests
@@ -16,15 +20,6 @@ DbNull = (None,)
DbNullType = tuple[None] DbNullType = tuple[None]
class VideoResult (TypedDict):
contentId: str
title: str
tags: list[str]
description: str
viewCounter: int
startTime: str
class VideoSearchParam (TypedDict): class VideoSearchParam (TypedDict):
q: str q: str
targets: str targets: str
@@ -34,8 +29,29 @@ class VideoSearchParam (TypedDict):
jsonFilter: str jsonFilter: str
class VideoResult (TypedDict):
contentId: str
title: str
tags: list[str]
description: str
viewCounter: int
startTime: str
class CommentResult (TypedDict): class CommentResult (TypedDict):
pass id: str
no: int
vposMs: int
body: str
commands: list[str]
userId: str
isPremium: bool
score: int
postedAt: str
nicoruCount: int
nicoruId: Any
source: str
isMyPost: bool
def main ( def main (
@@ -50,10 +66,13 @@ def main (
tag_dao = TagDao (conn) tag_dao = TagDao (conn)
video_tag_dao = VideoTagDao (conn) video_tag_dao = VideoTagDao (conn)
video_history_dao = VideoHistoryDao (conn) video_history_dao = VideoHistoryDao (conn)
comment_dao = CommentDao (conn)
user_dao = UserDao (conn)
api_data = search_nico_by_tags (['伊地知ニジカ', 'ぼざろクリーチャーシリーズ']) api_data = search_nico_by_tags (['伊地知ニジカ', 'ぼざろクリーチャーシリーズ'])
update_tables (video_dao, tag_dao, video_tag_dao, video_history_dao, api_data, now) update_tables (video_dao, tag_dao, video_tag_dao, video_history_dao, comment_dao, user_dao,
api_data, now)
# TODO: 書くこと # TODO: 書くこと
@@ -63,9 +82,12 @@ def update_tables (
tag_dao: TagDao, tag_dao: TagDao,
video_tag_dao: VideoTagDao, video_tag_dao: VideoTagDao,
video_history_dao: VideoHistoryDao, video_history_dao: VideoHistoryDao,
comment_dao: CommentDao,
user_dao: UserDao,
api_data: list[VideoResult], api_data: list[VideoResult],
now: datetime, now: datetime,
) -> None: ) -> None:
video_ids: list[int] = []
for datum in api_data: for datum in api_data:
video = VideoDto (code = datum['contentId'], video = VideoDto (code = datum['contentId'],
title = datum['title'], title = datum['title'],
@@ -73,6 +95,7 @@ def update_tables (
uploaded_at = datetime.fromisoformat (datum['startTime'])) uploaded_at = datetime.fromisoformat (datum['startTime']))
video_dao.upsert (video, False) video_dao.upsert (video, False)
if video.id_ is not None: if video.id_ is not None:
video_ids.append (video.id_)
video_history = VideoHistoryDto (video_id = video.id_, video_history = VideoHistoryDto (video_id = video.id_,
fetched_at = now, fetched_at = now,
views_count = datum['viewCounter']) views_count = datum['viewCounter'])
@@ -99,17 +122,37 @@ def update_tables (
tag_id = tag.id_, tag_id = tag.id_,
tagged_at = now) tagged_at = now)
video_tag_dao.insert (video_tag, False) video_tag_dao.insert (video_tag, False)
# TODO: コメント取得すること for com in fetch_comments (video.code):
user = user_dao.fetch_by_code (com['userId'])
if user is None:
user = UserDto (code = com['userId'])
user_dao.insert (user)
if video.id_ is not None and user.id_ is not None:
comment = CommentDto (video_id = video.id_,
comment_no = com['no'],
user_id = user.id_,
content = com['body'],
posted_at = datetime.fromisoformat (com['postedAt']),
nico_count = com['nicoruCount'],
vpos_ms = com['vposMs'])
comment_dao.upsert (comment, False)
# TODO: 削除処理,存在しなぃ動画リストを取得した上で行ふこと alive_video_ids = [d['contentId'] for d in api_data]
# video_dao.delete (video_ids, now)
# TODO: 書くこと lost_video_ids: list[int] = []
videos = video_dao.fetch_alive ()
for video in videos:
if video.id_ is not None and video.id_ not in alive_video_ids:
lost_video_ids.append (video.id_)
video_dao.delete (lost_video_ids, now)
def fetch_comments ( def fetch_comments (
video_id: str, video_code: str,
) -> list: ) -> list[CommentResult]:
time.sleep (1.2)
headers = { 'X-Frontend-Id': '6', headers = { 'X-Frontend-Id': '6',
'X-Frontend-Version': '0' } 'X-Frontend-Version': '0' }
@@ -119,7 +162,7 @@ def fetch_comments (
+ '_' + '_'
+ str (random.randrange (10 ** 12, 10 ** 13))) + str (random.randrange (10 ** 12, 10 ** 13)))
url = (f"https://www.nicovideo.jp/api/watch/v3_guest/{ video_id }" url = (f"https://www.nicovideo.jp/api/watch/v3_guest/{ video_code }"
+ f"?actionTrackId={ action_track_id }") + f"?actionTrackId={ action_track_id }")
res = requests.post (url, headers = headers, timeout = 60).json () res = requests.post (url, headers = headers, timeout = 60).json ()
@@ -253,6 +296,27 @@ class VideoDao:
videos.append (self._create_dto_from_row (row, with_relation_tables)) videos.append (self._create_dto_from_row (row, with_relation_tables))
return videos return videos
def fetch_alive (
self,
) -> list[VideoDto]:
with self.conn.cursor () as c:
c.execute ("""
SELECT
id,
code,
title,
description,
uploaded_at,
deleted_at
FROM
videos
WHERE
deleted_at IS NULL""")
videos: list[VideoDto] = []
for row in c.fetchall ():
videos.append (self._create_dto_from_row (row, False))
return videos
def upsert ( def upsert (
self, self,
video: VideoDto, video: VideoDto,
@@ -836,6 +900,58 @@ class CommentDto:
nico_count: int = 0 nico_count: int = 0
vpos_ms: int | DbNullType = DbNull vpos_ms: int | DbNullType = DbNull
video: VideoDto | None = None video: VideoDto | None = None
user: UserDto | None = None
class UserDao:
def __init__ (
self,
conn,
):
self.conn = conn
def fetch_by_code (
self,
user_code: str
) -> UserDto | None:
with self.conn.cursor () as c:
c.execute ("""
SELECT
id,
code
FROM
users
WHERE
code = %s""", user_code)
row = c.fetchone ()
if row is None:
return None
return self._create_dto_from_row (row)
def insert (
self,
user: UserDto,
) -> None:
with self.conn.cursor () as c:
c.execute ("""
INSERT INTO
users(code)
VALUES
(%s)""", user.code)
user.id_ = c.lastrowid
def _create_dto_from_row (
self,
row,
) -> UserDto:
return UserDto (id_ = row['id'],
code = row['code'])
@dataclass (slots = True)
class UserDto:
code: str
id_: int | None = None
if __name__ == '__main__': if __name__ == '__main__':