niconico.py-ma 2.1.0.post1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- niconico_py_ma-2.1.0.post1/LICENSE +21 -0
- niconico_py_ma-2.1.0.post1/PKG-INFO +83 -0
- niconico_py_ma-2.1.0.post1/README.md +59 -0
- niconico_py_ma-2.1.0.post1/niconico/__init__.py +6 -0
- niconico_py_ma-2.1.0.post1/niconico/__main__.py +126 -0
- niconico_py_ma-2.1.0.post1/niconico/base/__init__.py +0 -0
- niconico_py_ma-2.1.0.post1/niconico/base/client.py +22 -0
- niconico_py_ma-2.1.0.post1/niconico/channel/__init__.py +35 -0
- niconico_py_ma-2.1.0.post1/niconico/channel/search.py +55 -0
- niconico_py_ma-2.1.0.post1/niconico/decorators.py +30 -0
- niconico_py_ma-2.1.0.post1/niconico/exceptions.py +71 -0
- niconico_py_ma-2.1.0.post1/niconico/niconico.py +215 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/__init__.py +0 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/channel/__init__.py +98 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/channel/search.py +63 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/common.py +37 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/nvapi.py +460 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/user/__init__.py +210 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/user/search.py +28 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/video/__init__.py +174 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/video/ranking.py +12 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/video/search.py +150 -0
- niconico_py_ma-2.1.0.post1/niconico/objects/video/watch.py +679 -0
- niconico_py_ma-2.1.0.post1/niconico/py.typed +0 -0
- niconico_py_ma-2.1.0.post1/niconico/user/__init__.py +569 -0
- niconico_py_ma-2.1.0.post1/niconico/user/search.py +50 -0
- niconico_py_ma-2.1.0.post1/niconico/utils.py +25 -0
- niconico_py_ma-2.1.0.post1/niconico/video/__init__.py +191 -0
- niconico_py_ma-2.1.0.post1/niconico/video/ranking.py +120 -0
- niconico_py_ma-2.1.0.post1/niconico/video/search.py +402 -0
- niconico_py_ma-2.1.0.post1/niconico/video/watch.py +364 -0
- niconico_py_ma-2.1.0.post1/pyproject.toml +59 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Negima1072
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: niconico.py-ma
|
|
3
|
+
Version: 2.1.0.post1
|
|
4
|
+
Summary: API wrapper for NicoNico services (Music Assistant fork)
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Author: Shi-553
|
|
8
|
+
Author-email: 58556078+Shi-553@users.noreply.github.com
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Dist: pydantic (>=2.8.2,<3.0.0)
|
|
20
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
21
|
+
Project-URL: Repository, https://github.com/Shi-553/niconico.py
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
-auto?logo=niconico&logoColor=%23e6e6e6&color=%23252525)
|
|
25
|
+
|
|
26
|
+
[](https://pypi.org/project/niconico.py-ma/)
|
|
27
|
+

|
|
28
|
+

|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
[](https://github.com/Shi-553/niconico.py/actions/workflows/release.yml)
|
|
32
|
+
[](https://github.com/Shi-553/niconico.py/actions/workflows/pypi.yml)
|
|
33
|
+
|
|
34
|
+
# <img src="https://avatars.githubusercontent.com/u/113749892" height="30" /> niconico.py-ma
|
|
35
|
+
|
|
36
|
+
niconico.py-ma is a Python library for retrieving Niconico video content and information, and is compatible with the latest version of Niconico.
|
|
37
|
+
This is a Music Assistant fork with additional features and improvements.
|
|
38
|
+
It allows you to download videos, retrieve information, get comments, and more.
|
|
39
|
+
|
|
40
|
+
## Requirement
|
|
41
|
+
|
|
42
|
+
To use the video download function, you need to install [FFmpeg](https://www.ffmpeg.org/) and set the path.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
You can install it using pip:
|
|
47
|
+
```bash
|
|
48
|
+
pip install niconico.py-ma
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from niconico import NicoNico
|
|
55
|
+
client = NicoNico()
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Examples
|
|
59
|
+
|
|
60
|
+
All examples can be found [here](https://github.com/Shi-553/niconico.py/tree/main/examples).
|
|
61
|
+
|
|
62
|
+
## Original Project
|
|
63
|
+
|
|
64
|
+
This is a fork of [niconico.py](https://github.com/niconicolibs/niconico.py) by Negima1072, enhanced for Music Assistant integration.
|
|
65
|
+
|
|
66
|
+
## Command
|
|
67
|
+
|
|
68
|
+
Console commands are available, see the following commands for usage:
|
|
69
|
+
```bash
|
|
70
|
+
niconico -h
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Contributing
|
|
74
|
+
|
|
75
|
+
All contributions are welcome, but please:
|
|
76
|
+
- Use the `develop` branch.
|
|
77
|
+
- Follow PEP8.
|
|
78
|
+
- Be clear about the meaning and purpose of your issue or PR.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
[MIT License](LICENSE)
|
|
83
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
-auto?logo=niconico&logoColor=%23e6e6e6&color=%23252525)
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/niconico.py-ma/)
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
[](https://github.com/Shi-553/niconico.py/actions/workflows/release.yml)
|
|
9
|
+
[](https://github.com/Shi-553/niconico.py/actions/workflows/pypi.yml)
|
|
10
|
+
|
|
11
|
+
# <img src="https://avatars.githubusercontent.com/u/113749892" height="30" /> niconico.py-ma
|
|
12
|
+
|
|
13
|
+
niconico.py-ma is a Python library for retrieving Niconico video content and information, and is compatible with the latest version of Niconico.
|
|
14
|
+
This is a Music Assistant fork with additional features and improvements.
|
|
15
|
+
It allows you to download videos, retrieve information, get comments, and more.
|
|
16
|
+
|
|
17
|
+
## Requirement
|
|
18
|
+
|
|
19
|
+
To use the video download function, you need to install [FFmpeg](https://www.ffmpeg.org/) and set the path.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
You can install it using pip:
|
|
24
|
+
```bash
|
|
25
|
+
pip install niconico.py-ma
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from niconico import NicoNico
|
|
32
|
+
client = NicoNico()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Examples
|
|
36
|
+
|
|
37
|
+
All examples can be found [here](https://github.com/Shi-553/niconico.py/tree/main/examples).
|
|
38
|
+
|
|
39
|
+
## Original Project
|
|
40
|
+
|
|
41
|
+
This is a fork of [niconico.py](https://github.com/niconicolibs/niconico.py) by Negima1072, enhanced for Music Assistant integration.
|
|
42
|
+
|
|
43
|
+
## Command
|
|
44
|
+
|
|
45
|
+
Console commands are available, see the following commands for usage:
|
|
46
|
+
```bash
|
|
47
|
+
niconico -h
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Contributing
|
|
51
|
+
|
|
52
|
+
All contributions are welcome, but please:
|
|
53
|
+
- Use the `develop` branch.
|
|
54
|
+
- Follow PEP8.
|
|
55
|
+
- Be clear about the meaning and purpose of your issue or PR.
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
[MIT License](LICENSE)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Main module for niconico package."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import logging
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from niconico import NicoNico, __version__
|
|
8
|
+
from niconico.exceptions import LoginFailureError, WatchAPIError
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger("niconico.py")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def command_details(args: argparse.Namespace) -> None:
|
|
14
|
+
"""Show video details."""
|
|
15
|
+
logger.debug("Starting command: details with args: %s", args)
|
|
16
|
+
client = NicoNico()
|
|
17
|
+
video = client.video.get_video(args.id)
|
|
18
|
+
if video is None:
|
|
19
|
+
logger.error("Video not found")
|
|
20
|
+
return
|
|
21
|
+
logger.debug("Video: %s", video)
|
|
22
|
+
if args.output is None:
|
|
23
|
+
logger.info(video.model_dump_json(indent=2, by_alias=True))
|
|
24
|
+
else:
|
|
25
|
+
with args.output.open("w") as f:
|
|
26
|
+
f.write(video.model_dump_json(by_alias=True))
|
|
27
|
+
logger.info("Saved to %s", args.output)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def command_quality(args: argparse.Namespace) -> None:
|
|
31
|
+
"""Show video quality."""
|
|
32
|
+
logger.debug("Starting command: quality with args: %s", args)
|
|
33
|
+
client = NicoNico()
|
|
34
|
+
if args.session is not None:
|
|
35
|
+
try:
|
|
36
|
+
client.login_with_session(args.session)
|
|
37
|
+
logger.debug("Logged in with session")
|
|
38
|
+
except LoginFailureError:
|
|
39
|
+
logger.exception("Login failed")
|
|
40
|
+
logger.debug("is_premium: %s", client.premium)
|
|
41
|
+
try:
|
|
42
|
+
watch_data = client.video.watch.get_watch_data(args.id)
|
|
43
|
+
except WatchAPIError:
|
|
44
|
+
logger.exception("An error has occurred")
|
|
45
|
+
return
|
|
46
|
+
logger.debug("Watch data: %s", watch_data)
|
|
47
|
+
outputs = client.video.watch.get_outputs(watch_data)
|
|
48
|
+
logger.info("Label\tVideo, Audio")
|
|
49
|
+
for output_key, output in outputs.items():
|
|
50
|
+
logger.info("%s:\t%s", output_key, ", ".join(output))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def command_download(args: argparse.Namespace) -> None:
|
|
54
|
+
"""Download video."""
|
|
55
|
+
logger.debug("Starting command: download with args: %s", args)
|
|
56
|
+
client = NicoNico()
|
|
57
|
+
if args.session is not None:
|
|
58
|
+
try:
|
|
59
|
+
client.login_with_session(args.session)
|
|
60
|
+
logger.debug("Logged in with session")
|
|
61
|
+
except LoginFailureError:
|
|
62
|
+
logger.exception("Login failed")
|
|
63
|
+
logger.debug("is_premium: %s", client.premium)
|
|
64
|
+
try:
|
|
65
|
+
watch_data = client.video.watch.get_watch_data(args.id)
|
|
66
|
+
except WatchAPIError:
|
|
67
|
+
logger.exception("An error has occurred")
|
|
68
|
+
return
|
|
69
|
+
logger.debug("Watch data: %s", watch_data)
|
|
70
|
+
outputs = client.video.watch.get_outputs(watch_data, audio_only=args.audio)
|
|
71
|
+
logger.debug("Outputs: %s", outputs)
|
|
72
|
+
if args.quality is not None:
|
|
73
|
+
if args.quality not in outputs:
|
|
74
|
+
logger.error("This quality is not supported")
|
|
75
|
+
return
|
|
76
|
+
quality = args.quality
|
|
77
|
+
logger.debug("Selected quality: %s", quality)
|
|
78
|
+
else:
|
|
79
|
+
quality = next(iter(outputs))
|
|
80
|
+
logger.debug("Selected quality: %s(best)", quality)
|
|
81
|
+
logger.debug("Downloading video...")
|
|
82
|
+
downloaded_path = client.video.watch.download_video(watch_data, quality, args.output, audio_only=args.audio)
|
|
83
|
+
logger.info("Downloaded to %s", downloaded_path)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def main() -> None:
|
|
87
|
+
"""Main function for niconico package."""
|
|
88
|
+
parser = argparse.ArgumentParser(
|
|
89
|
+
description="download video from niconico",
|
|
90
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
91
|
+
)
|
|
92
|
+
parser.add_argument("-v", "--version", action="version", version=f"%(prog)s {__version__}")
|
|
93
|
+
parser.add_argument("--debug", help="enable debug logging", action="store_true")
|
|
94
|
+
|
|
95
|
+
subparsers = parser.add_subparsers(title="commands")
|
|
96
|
+
|
|
97
|
+
parser_details = subparsers.add_parser("details", help="show video details")
|
|
98
|
+
parser_details.add_argument("id", help="video id", type=str)
|
|
99
|
+
parser_details.add_argument("-o", "--output", help="output file (default: stdout)", default=None, type=Path)
|
|
100
|
+
parser_details.set_defaults(func=command_details)
|
|
101
|
+
|
|
102
|
+
parser_quality = subparsers.add_parser("quality", help="show video quality")
|
|
103
|
+
parser_quality.add_argument("id", help="video id", type=str)
|
|
104
|
+
parser_quality.add_argument("-s", "--session", help="user_session cookie", default=None, type=str)
|
|
105
|
+
parser_quality.set_defaults(func=command_quality)
|
|
106
|
+
|
|
107
|
+
parser_download = subparsers.add_parser("download", help="download video")
|
|
108
|
+
parser_download.add_argument("id", help="video id", type=str)
|
|
109
|
+
parser_download.add_argument("-o", "--output", help="output file path", default=".", type=str)
|
|
110
|
+
parser_download.add_argument("-s", "--session", help="user_session cookie", default=None, type=str)
|
|
111
|
+
parser_download.add_argument("-q", "--quality", help="video quality (default: best)", default=None, type=str)
|
|
112
|
+
parser_download.add_argument("-a", "--audio", help="download audio only", action="store_true")
|
|
113
|
+
parser_download.set_defaults(func=command_download)
|
|
114
|
+
|
|
115
|
+
args = parser.parse_args()
|
|
116
|
+
|
|
117
|
+
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO, format="%(message)s")
|
|
118
|
+
|
|
119
|
+
if hasattr(args, "func"):
|
|
120
|
+
args.func(args)
|
|
121
|
+
else:
|
|
122
|
+
parser.print_help()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""This module contains the base client class."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from niconico.niconico import NicoNico
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseClient:
|
|
12
|
+
"""A class that represents a base client."""
|
|
13
|
+
|
|
14
|
+
niconico: NicoNico
|
|
15
|
+
|
|
16
|
+
def __init__(self, niconico: NicoNico) -> None:
|
|
17
|
+
"""Initialize the base client."""
|
|
18
|
+
self.niconico = niconico
|
|
19
|
+
|
|
20
|
+
def log(self, type_: str, message: str) -> None:
|
|
21
|
+
"""Log a message."""
|
|
22
|
+
return getattr(self.niconico.logger, type_)(message)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""This module provides a class that represents a channel client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from niconico.base.client import BaseClient
|
|
10
|
+
from niconico.channel.search import ChannelSearchClient
|
|
11
|
+
from niconico.objects.channel import ChannelData, ChAPIResponse
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from niconico.niconico import NicoNico
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ChannelClient(BaseClient):
|
|
18
|
+
"""A client that represents a channel client."""
|
|
19
|
+
|
|
20
|
+
search: ChannelSearchClient
|
|
21
|
+
|
|
22
|
+
def __init__(self, niconico: NicoNico) -> None:
|
|
23
|
+
"""Initialize the client."""
|
|
24
|
+
super().__init__(niconico)
|
|
25
|
+
self.search = ChannelSearchClient(niconico)
|
|
26
|
+
|
|
27
|
+
def get_channel(self, channel_id: str) -> ChannelData | None:
|
|
28
|
+
"""Get a channel."""
|
|
29
|
+
channel_id = channel_id.replace("ch", "")
|
|
30
|
+
res = self.niconico.get(f"https://public-api.ch.nicovideo.jp/v2/open/channels/{channel_id}")
|
|
31
|
+
if res.status_code == requests.codes.ok:
|
|
32
|
+
res_cls = ChAPIResponse[ChannelData](**res.json())
|
|
33
|
+
if res_cls.data is not None:
|
|
34
|
+
return res_cls.data
|
|
35
|
+
return None
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Module for channel search client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from niconico.base.client import BaseClient
|
|
10
|
+
from niconico.objects.channel.search import ChannelSearchItem, ChSearchAPIResponse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ChannelSearchClient(BaseClient):
|
|
14
|
+
"""Client for channel search."""
|
|
15
|
+
|
|
16
|
+
def search_channels(
|
|
17
|
+
self,
|
|
18
|
+
query: str,
|
|
19
|
+
*,
|
|
20
|
+
search_type: Literal["keyword", "tag"] = "keyword",
|
|
21
|
+
limit: int = 20,
|
|
22
|
+
offset: int = 0,
|
|
23
|
+
order: Literal["desc", "asc"] = "desc",
|
|
24
|
+
sort: Literal["updateTime"] | None = None,
|
|
25
|
+
) -> list[ChannelSearchItem]:
|
|
26
|
+
"""Search channels by query.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
query (str): Query to search.
|
|
30
|
+
search_type (Literal["keyword", "tag"], optional): Search type. Defaults to "keyword".
|
|
31
|
+
limit (int, optional): Limit. Defaults to 20.
|
|
32
|
+
offset (int, optional): Offset. Defaults to 0.
|
|
33
|
+
order (Literal["desc", "asc"], optional): Order. Defaults to "desc".
|
|
34
|
+
sort (Literal["updateTime"], optional): Sort. Default is created time.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
list[ChannelSearchItem]: Channel search item list.
|
|
38
|
+
"""
|
|
39
|
+
query_dict = {
|
|
40
|
+
"query": query,
|
|
41
|
+
"searchType": search_type,
|
|
42
|
+
"limit": str(limit),
|
|
43
|
+
"offset": str(offset),
|
|
44
|
+
"order": order,
|
|
45
|
+
"responseGroup": "detail",
|
|
46
|
+
}
|
|
47
|
+
if sort is not None:
|
|
48
|
+
query_dict["sort"] = sort
|
|
49
|
+
query_str = "&".join(f"{key}={value}" for key, value in query_dict.items())
|
|
50
|
+
res = self.niconico.get(f"https://public-api.ch.nicovideo.jp/v1/open/search/channels?{query_str}")
|
|
51
|
+
if res.status_code == requests.codes.ok:
|
|
52
|
+
res_cls = ChSearchAPIResponse(**res.json())
|
|
53
|
+
if res_cls.data is not None:
|
|
54
|
+
return res_cls.data
|
|
55
|
+
return []
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Decorators for the niconico package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from functools import wraps
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
|
7
|
+
|
|
8
|
+
from niconico.exceptions import LoginRequiredError, PremiumRequiredError
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from niconico.base.client import BaseClient
|
|
12
|
+
|
|
13
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def login_required(*, premium: bool = False) -> Callable[[F], F]:
|
|
17
|
+
"""A decorator that requires a login to be performed."""
|
|
18
|
+
|
|
19
|
+
def decorator(func: F) -> F:
|
|
20
|
+
@wraps(func)
|
|
21
|
+
def wrapper(self: BaseClient, *args: Any, **kwargs: Any) -> F: # noqa: ANN401
|
|
22
|
+
if not self.niconico.logined:
|
|
23
|
+
raise LoginRequiredError(message="Login is required to use this function.")
|
|
24
|
+
if premium and not self.niconico.premium:
|
|
25
|
+
raise PremiumRequiredError(message="Premium account is required to use this function.")
|
|
26
|
+
return func(self, *args, **kwargs)
|
|
27
|
+
|
|
28
|
+
return wrapper # type: ignore # noqa: PGH003
|
|
29
|
+
|
|
30
|
+
return decorator
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""This module contains exceptions for the niconico package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from niconico.objects.video.watch import WatchResponseError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LoginFailureError(Exception):
|
|
12
|
+
"""An exception raised when login fails."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, message: str) -> None:
|
|
15
|
+
"""Initialize the exception."""
|
|
16
|
+
self.message = message
|
|
17
|
+
super().__init__(message)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DownloadError(Exception):
|
|
21
|
+
"""An exception raised when download fails."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, message: str) -> None:
|
|
24
|
+
"""Initialize the exception."""
|
|
25
|
+
self.message = message
|
|
26
|
+
super().__init__(message)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class NicoAPIError(Exception):
|
|
30
|
+
"""An exception raised when an error occurs in the Nico API."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, message: str) -> None:
|
|
33
|
+
"""Initialize the exception."""
|
|
34
|
+
self.message = message
|
|
35
|
+
super().__init__(message)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class LoginRequiredError(Exception):
|
|
39
|
+
"""An exception raised when login is required."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, message: str) -> None:
|
|
42
|
+
"""Initialize the exception."""
|
|
43
|
+
self.message = message
|
|
44
|
+
super().__init__(message)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PremiumRequiredError(Exception):
|
|
48
|
+
"""An exception raised when a premium account is required."""
|
|
49
|
+
|
|
50
|
+
def __init__(self, message: str) -> None:
|
|
51
|
+
"""Initialize the exception."""
|
|
52
|
+
self.message = message
|
|
53
|
+
super().__init__(message)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class WatchAPIError(Exception):
|
|
57
|
+
"""An exception raised when an error occurs in the watch API."""
|
|
58
|
+
|
|
59
|
+
def __init__(self, response: WatchResponseError) -> None:
|
|
60
|
+
"""Initialize the exception."""
|
|
61
|
+
self.response = response
|
|
62
|
+
super().__init__(response.error_code)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class CommentAPIError(Exception):
|
|
66
|
+
"""An exception raised when an error occurs in the comment API."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, message: str | None) -> None:
|
|
69
|
+
"""Initialize the exception."""
|
|
70
|
+
self.message = message
|
|
71
|
+
super().__init__(message)
|