|
@@ -0,0 +1,153 @@ |
|
|
|
|
|
import json |
|
|
|
|
|
import os |
|
|
|
|
|
import random |
|
|
|
|
|
import string |
|
|
|
|
|
import time |
|
|
|
|
|
from dataclasses import dataclass |
|
|
|
|
|
from datetime import datetime |
|
|
|
|
|
|
|
|
|
|
|
import mysql.connector |
|
|
|
|
|
import requests |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main ( |
|
|
|
|
|
) -> None: |
|
|
|
|
|
conn = mysql.connector.connect (host = os.environ['MYSQL_HOST'], |
|
|
|
|
|
user = os.environ['MYSQL_USER'], |
|
|
|
|
|
password = os.environ['MYSQL_PASS']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fetch_comments ( |
|
|
|
|
|
video_id: str, |
|
|
|
|
|
) -> list: |
|
|
|
|
|
headers = { 'X-Frontend-Id': '6', |
|
|
|
|
|
'X-Frontend-Version': '0' } |
|
|
|
|
|
|
|
|
|
|
|
action_track_id = ( |
|
|
|
|
|
''.join (random.choice (string.ascii_letters + string.digits) |
|
|
|
|
|
for _ in range (10)) |
|
|
|
|
|
+ '_' |
|
|
|
|
|
+ str (random.randrange (10 ** 12, 10 ** 13))) |
|
|
|
|
|
|
|
|
|
|
|
url = (f"https://www.nicovideo.jp/api/watch/v3_guest/{ video_id }" |
|
|
|
|
|
+ f"?actionTrackId={ action_track_id }") |
|
|
|
|
|
|
|
|
|
|
|
res = requests.post (url, headers = headers, timeout = 60).json () |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
nv_comment = res['data']['comment']['nvComment'] |
|
|
|
|
|
except (NameError, AttributeError): |
|
|
|
|
|
return [] |
|
|
|
|
|
if nv_comment is None: |
|
|
|
|
|
return [] |
|
|
|
|
|
|
|
|
|
|
|
headers = { 'X-Frontend-Id': '6', |
|
|
|
|
|
'X-Frontend-Version': '0', |
|
|
|
|
|
'Content-Type': 'application/json' } |
|
|
|
|
|
|
|
|
|
|
|
params = { 'params': nv_comment['params'], |
|
|
|
|
|
'additionals': { }, |
|
|
|
|
|
'threadKey': nv_comment['threadKey'] } |
|
|
|
|
|
|
|
|
|
|
|
url = nv_comment['server'] + '/v1/threads' |
|
|
|
|
|
|
|
|
|
|
|
res = (requests.post (url, json.dumps (params), |
|
|
|
|
|
headers = headers, |
|
|
|
|
|
timeout = 60) |
|
|
|
|
|
.json ()) |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
return res['data']['threads'][1]['comments'] |
|
|
|
|
|
except (NameError, AttributeError): |
|
|
|
|
|
return [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def search_nico_by_tag ( |
|
|
|
|
|
tag: str, |
|
|
|
|
|
) -> list[dict]: |
|
|
|
|
|
return search_nico_by_tags ([tag]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def search_nico_by_tags ( |
|
|
|
|
|
tags: list[str], |
|
|
|
|
|
) -> list[dict]: |
|
|
|
|
|
url = ('https://snapshot.search.nicovideo.jp' |
|
|
|
|
|
+ '/api/v2/snapshot/video/contents/search') |
|
|
|
|
|
|
|
|
|
|
|
query_filter = json.dumps ({ 'type': 'or', |
|
|
|
|
|
'filters': [ |
|
|
|
|
|
{ 'type': 'range', |
|
|
|
|
|
'field': 'startTime', |
|
|
|
|
|
'from': f"{year}-{start}T00:00:00+09:00", |
|
|
|
|
|
'to': f"{year}-{end}T23:59:59+09:00", |
|
|
|
|
|
'include_lower': True }] }) |
|
|
|
|
|
|
|
|
|
|
|
params: dict[str, int | str] |
|
|
|
|
|
params = { 'q': ' OR '.join (tags), |
|
|
|
|
|
'targets': 'tagsExact', |
|
|
|
|
|
'_sort': '-viewCounter', |
|
|
|
|
|
'fields': 'contentId,title,tags,viewCounter,startTime', |
|
|
|
|
|
'_limit': 100, |
|
|
|
|
|
'jsonFilter': query_filter } |
|
|
|
|
|
|
|
|
|
|
|
res = requests.get (url, params = params, timeout = 60).json () |
|
|
|
|
|
|
|
|
|
|
|
return res['data'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VideoDao: |
|
|
|
|
|
def __init__ ( |
|
|
|
|
|
self, |
|
|
|
|
|
conn |
|
|
|
|
|
): |
|
|
|
|
|
self.conn = conn |
|
|
|
|
|
|
|
|
|
|
|
def fetch_all ( |
|
|
|
|
|
with_relation_tables: bool = True, |
|
|
|
|
|
) -> list[VideoDto]: |
|
|
|
|
|
with self.conn.cursor () as c: |
|
|
|
|
|
c.execute (""" |
|
|
|
|
|
SELECT |
|
|
|
|
|
id, |
|
|
|
|
|
code, |
|
|
|
|
|
title, |
|
|
|
|
|
description, |
|
|
|
|
|
uploaded_at, |
|
|
|
|
|
deleted_at |
|
|
|
|
|
FROM |
|
|
|
|
|
videos""") |
|
|
|
|
|
for video in c.fetchall (): |
|
|
|
|
|
if with_relation_tables: |
|
|
|
|
|
video_tags = VideoTagDao (conn).fetch_all (False) |
|
|
|
|
|
comments = CommentDao (conn).fetch_all (False) |
|
|
|
|
|
video_histories = VideoHistoryDao (conn).fetch_all (False) |
|
|
|
|
|
else: |
|
|
|
|
|
video_tags = None |
|
|
|
|
|
comments = None |
|
|
|
|
|
video_histories = None |
|
|
|
|
|
return VideoDto (id_ = video['id'], |
|
|
|
|
|
code = video['code'], |
|
|
|
|
|
title = video['title'], |
|
|
|
|
|
description = video['description'], |
|
|
|
|
|
uploaded_at = video['uploaded_at'], |
|
|
|
|
|
deleted_at = video['deleted_at'], |
|
|
|
|
|
video_tags = video_tags, |
|
|
|
|
|
comments = comments, |
|
|
|
|
|
video_histories = video_histories) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass (slots = True) |
|
|
|
|
|
class VideoDto: |
|
|
|
|
|
id_: int |
|
|
|
|
|
code: str |
|
|
|
|
|
title: str |
|
|
|
|
|
description: str |
|
|
|
|
|
uploaded_at: datetime |
|
|
|
|
|
deleted_at: datetime | None |
|
|
|
|
|
video_tags: VideoTagDto | None |
|
|
|
|
|
comments: CommentDto | None |
|
|
|
|
|
video_histories: VideoHistoryDto | None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
|
|
main () |