Skip to content

Commit

Permalink
Merge pull request #55 from niconicolibs/develop
Browse files Browse the repository at this point in the history
release: v2.0.4
  • Loading branch information
Negima1072 committed Aug 17, 2024
2 parents 96b0b88 + db4c0ae commit 83301fa
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 19 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
niconico.py is a Python library for retrieving Niconico video content and information, and is compatible with the latest version of Niconico.
It allows you to download videos, retrieve information, get comments, and more.

## Requirement

To use the video download function, you need to install [FFmpeg](https://www.ffmpeg.org/) and set the path.

## Installation

You can install it using pip:
Expand Down
2 changes: 1 addition & 1 deletion niconico/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
from niconico.niconico import NicoNico

__all__ = ("NicoNico",)
__version__ = "2.0.3"
__version__ = "2.0.4"
2 changes: 1 addition & 1 deletion niconico/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def main() -> None:

parser_download = subparsers.add_parser("download", help="download video")
parser_download.add_argument("id", help="video id", type=str)
parser_download.add_argument("-o", "--output", help="output file (default: stdout)", default=".", type=Path)
parser_download.add_argument("-o", "--output", help="output file path", default=".", type=str)
parser_download.add_argument("-s", "--session", help="user_session cookie", default=None, type=str)
parser_download.add_argument("-q", "--quality", help="video quality (default: best)", default=None, type=str)
parser_download.set_defaults(func=command_download)
Expand Down
50 changes: 34 additions & 16 deletions niconico/video/watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,44 +129,55 @@ def get_storyboard_url(self, watch_data: WatchData) -> str | None:
return None

@login_required(premium=True)
def download_storyboards(self, watch_data: WatchData, path: str) -> None:
def download_storyboards(self, watch_data: WatchData, output_path: str) -> str:
"""Download the storyboards of a video.
Args:
watch_data: The watch data of the video.
path: The folder path to save the storyboards.
output_path: The folder path to save the storyboards.
Returns:
str: The path of the downloaded storyboards.
"""
storyboard_url = self.get_storyboard_url(watch_data)
if storyboard_url is None:
raise NicoAPIError(message="Failed to get the storyboards URL.")
output_path = output_path % {
"id": watch_data.video.id_,
"title": watch_data.video.title,
"owner": watch_data.owner.nickname,
"owner_id": str(watch_data.owner.id_),
"timestamp": str(int(time.time())),
}
res = self.niconico.get(storyboard_url)
if res.status_code == requests.codes.ok:
res_cls = StoryboardResponse(**res.json())
if not Path(path).is_dir():
Path(path).mkdir(parents=True)
if Path(f"{path}/storyboard.json").exists():
if not Path(output_path).is_dir():
Path(output_path).mkdir(parents=True)
if Path(f"{output_path}/storyboard.json").exists():
raise DownloadError(message="The storyboard.json file already exists.")
with Path(f"{path}/storyboard.json").open(mode="w") as f:
with Path(f"{output_path}/storyboard.json").open(mode="w") as f:
f.write(res.text)
for image in res_cls.images:
image_res = self.niconico.get(re.sub(r"(?<=/)[^/]+(?=\?)", image.url, storyboard_url))
if image_res.status_code == requests.codes.ok:
if Path(f"{path}/{image.url}.jpg").exists():
if Path(f"{output_path}/{image.url}.jpg").exists():
raise DownloadError(message=f"The storyboard image already exists: {image.url}")
with Path(f"{path}/{image.url}.jpg").open(mode="wb") as f:
with Path(f"{output_path}/{image.url}.jpg").open(mode="wb") as f:
f.write(image_res.content)
else:
raise DownloadError(message=f"Failed to download the storyboard image: {image.url}")
else:
raise DownloadError(message="Failed to download the storyboards.")
return output_path

def download_video(self, watch_data: WatchData, output_label: str, path: str) -> str:
def download_video(self, watch_data: WatchData, output_label: str, output_path: str = "%(title)s.%(ext)s") -> str:
"""Download a video.
Args:
watch_data: The watch data of the video.
output_label: The output label of the video.
path: The folder path to save the video.
output_path: The path to save the video.
Returns:
str: The path of the downloaded video.
Expand All @@ -177,10 +188,17 @@ def download_video(self, watch_data: WatchData, output_label: str, path: str) ->
hls_content_url = self.get_hls_content_url(watch_data, [outputs[output_label]])
if hls_content_url is None:
raise NicoAPIError(message="Failed to get the HLS content URL.")
name = f"{watch_data.video.id_}_{watch_data.video.title}.mp4"
if not Path(path).is_dir():
Path(path).mkdir(parents=True)
if (Path(path) / name).exists():
output_path = output_path % {
"id": watch_data.video.id_,
"title": watch_data.video.title,
"owner": watch_data.owner.nickname,
"owner_id": str(watch_data.owner.id_),
"timestamp": str(int(time.time())),
"ext": "mp4",
}
if not Path(output_path).parent.exists():
Path(output_path).parent.mkdir(parents=True)
if Path(output_path).exists():
raise DownloadError(message="The video file already exists.")
cookies = {
"domand_bid": self.niconico.session.cookies.get("domand_bid"),
Expand All @@ -196,15 +214,15 @@ def download_video(self, watch_data: WatchData, output_label: str, path: str) ->
f"'{hls_content_url}'",
"-c",
"copy",
f"'{(Path(path) / name).as_posix()}'",
f"'{output_path}'",
],
)
try:
with subprocess.Popen(commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True) as p: # noqa: S602
p.wait()
except subprocess.CalledProcessError as e:
raise DownloadError(message="Failed to download the video.") from e
return (Path(path) / name).as_posix()
return output_path

def get_comments(self, watch_data: WatchData, *, when: int | None = None) -> NvCommentAPIData | None:
"""Get the comments of a video.
Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "niconico.py"
version = "2.0.3"
version = "2.0.4"
description = "API wrapper for NicoNico services"
authors = ["Negima1072 <ngm1072@gmail.com>"]
license = "MIT"
Expand Down Expand Up @@ -40,6 +40,10 @@ target-version = "py38"
"ANN101",
"ANN102"
]
"examples/*.py" = [
"INP001",
"T201"
]

[tool.ruff.lint.pylint]
max-args = 15
Expand Down

0 comments on commit 83301fa

Please sign in to comment.