2023-02-21 17:50:53 +08:00
|
|
|
from .exceptions import *
|
2023-03-04 13:53:05 +08:00
|
|
|
from bilibili_api import video, sync
|
2023-02-21 17:50:53 +08:00
|
|
|
from httpx import stream
|
|
|
|
from os import PathLike
|
2023-02-20 17:20:29 +08:00
|
|
|
|
2023-03-04 13:53:05 +08:00
|
|
|
HEADERS = {
|
|
|
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0",
|
|
|
|
"Referer": "https://www.bilibili.com",
|
|
|
|
}
|
|
|
|
|
2023-02-20 17:20:29 +08:00
|
|
|
|
|
|
|
class Video:
|
|
|
|
def __init__(self, video_number: str):
|
2023-02-21 17:50:53 +08:00
|
|
|
self.title = None
|
|
|
|
self.received_bytes = 0
|
|
|
|
self.length = 0
|
2023-02-20 19:56:09 +08:00
|
|
|
video_number = video_number.strip()
|
2023-02-20 17:20:29 +08:00
|
|
|
if len(video_number) <= 2:
|
|
|
|
raise InvalidVideoNumberException(
|
|
|
|
f"The video number {video_number} is too short!"
|
|
|
|
)
|
|
|
|
if video_number[:2].upper() == "AV":
|
|
|
|
if not video_number[2:].isnumeric():
|
|
|
|
raise InvalidVideoNumberException(
|
|
|
|
f"Invalid AV video number {video_number}!"
|
|
|
|
)
|
|
|
|
else:
|
2023-02-21 17:50:53 +08:00
|
|
|
self.number = "AV" + video_number[2:]
|
2023-02-23 21:44:10 +08:00
|
|
|
self.v = video.Video(aid=int(video_number[2:]))
|
|
|
|
return
|
2023-02-20 17:20:29 +08:00
|
|
|
if video_number[:2].upper() != "BV":
|
|
|
|
raise InvalidVideoNumberException(f"Invalid video number {video_number}!")
|
|
|
|
else:
|
2023-02-21 17:50:53 +08:00
|
|
|
self.number = "BV" + video_number[2:]
|
|
|
|
self.v = video.Video(bvid=self.number)
|
2023-02-20 17:20:29 +08:00
|
|
|
|
|
|
|
def get_info(self):
|
|
|
|
try:
|
|
|
|
info = sync(self.v.get_info())
|
|
|
|
except:
|
|
|
|
raise BiliBiliAPIException("Error happens with bilibili-api-python.")
|
|
|
|
self.title = info["title"]
|
|
|
|
|
|
|
|
def get_url(self):
|
|
|
|
try:
|
|
|
|
download_url_data = sync(self.v.get_download_url(0))
|
|
|
|
detecter = video.VideoDownloadURLDataDetecter(data=download_url_data)
|
|
|
|
streams = detecter.detect_best_streams()
|
|
|
|
except:
|
|
|
|
raise BiliBiliAPIException("Error happens with bilibili-api-python.")
|
|
|
|
if detecter.check_flv_stream() == True:
|
|
|
|
raise BadVideoException(
|
|
|
|
f"This video ({self.title})) is only available in flv format."
|
|
|
|
)
|
2023-02-21 17:50:53 +08:00
|
|
|
return streams[1].url
|
2023-02-20 17:20:29 +08:00
|
|
|
|
2023-02-21 17:50:53 +08:00
|
|
|
def download(self, file: int | str | bytes | PathLike):
|
|
|
|
with stream("GET", self.get_url(), headers=HEADERS) as r:
|
2023-02-20 17:20:29 +08:00
|
|
|
self.length = int(r.headers["content-length"])
|
|
|
|
self.received_bytes = 0
|
2023-02-20 19:24:48 +08:00
|
|
|
with open(file, "wb") as f:
|
2023-02-20 17:20:29 +08:00
|
|
|
for chunk in r.iter_bytes(1024):
|
|
|
|
if not chunk:
|
|
|
|
break
|
|
|
|
self.received_bytes += len(chunk)
|
|
|
|
f.write(chunk)
|