|
- from __future__ import annotations
-
- import json
- import random
- import string
- import time
- from typing import Any, TypedDict
-
- import requests
- from bs4 import BeautifulSoup
- from requests.exceptions import Timeout
-
-
- def fetch_video_info (
- video_code: str,
- ) -> VideoInfo | None:
- bs = _create_bs_from_url (f"https://www.nicovideo.jp/watch/{ video_code }")
- if bs is None:
- return None
-
- try:
- title_tag = bs.find ('title')
- if title_tag is None:
- return None
- title = '-'.join (title_tag.text.split ('-')[:(-1)]).strip ()
-
- tags_str: str = bs.find ('meta', attrs = { 'name': 'keywords' }).get ('content') # type: ignore
- tags = tags_str.split (',')
-
- description = bs.find ('meta', attrs = { 'name': 'description' }).get ('content') # type: ignore
- except (AttributeError, TypeError):
- return None
-
- return { 'contentId': video_code,
- 'title': title,
- 'tags': tags,
- 'description': str (description) }
-
-
- def fetch_comments (
- video_code: str,
- ) -> list[Comment]:
- time.sleep (1.2)
-
- 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_code }"
- + f"?actionTrackId={ action_track_id }")
-
- res = requests.post (url, headers = headers, timeout = 60).json ()
-
- try:
- nv_comment = res['data']['comment']['nvComment']
- except KeyError:
- 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 (IndexError, KeyError):
- return []
-
-
- def fetch_embed_info (
- url: str,
- ) -> tuple[str, str, str]:
- title: str = ''
- description: str = ''
- thumbnail: str = ''
-
- bs = _create_bs_from_url (url)
- if bs is None:
- return ('', '', '')
-
- tmp = bs.find ('title')
- if tmp is not None:
- title = tmp.text
-
- tmp = bs.find ('meta', attrs = { 'name': 'description' })
- if tmp is not None and hasattr (tmp, 'get'):
- try:
- description = str (tmp.get ('content'))
- except Exception:
- pass
-
- tmp = bs.find ('meta', attrs = { 'name': 'thumbnail' })
- if tmp is not None and hasattr (tmp, 'get'):
- try:
- thumbnail = str (tmp.get ('content'))
- except Exception:
- pass
-
- return (title, description, thumbnail)
-
-
- def fetch_latest_video (
- tags: list[str],
- ) -> VideoInfo | None:
- tag = ' OR '.join (tags)
- url = f"https://www.nicovideo.jp/tag/{ tag }"
-
- params = { 'sort': 'f',
- 'order': 'd' }
-
- video_info = { }
-
- bs = _create_bs_from_url (url, params)
- if bs is None:
- return None
-
- try:
- video = (bs.find_all ('ul', class_ = 'videoListInner')[1]
- .find ('li', class_ = 'item'))
-
- video_info['contentId'] = video['data-video-id']
- except Exception:
- return None
-
- return fetch_video_info (video_info['contentId'])
-
-
- def _create_bs_from_url (
- url: str,
- params: dict | None = None,
- ) -> BeautifulSoup | None:
- if params is None:
- params = { }
-
- try:
- req = requests.get (url, params = params, timeout = 60)
- except Timeout:
- return None
-
- if req.status_code != 200:
- return None
-
- req.encoding = req.apparent_encoding
-
- return BeautifulSoup (req.text, 'html.parser')
-
-
- class VideoInfo (TypedDict):
- contentId: str
- title: str
- tags: list[str]
- description: str
-
-
- class Comment (TypedDict):
- 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
|