mirror of https://github.com/yutto-dev/yutto
parent
2ec883d218
commit
1a629f7803
|
@ -26,25 +26,27 @@ class BilibiliId(NamedTuple):
|
|||
class AvId(BilibiliId, metaclass=ABCMeta):
|
||||
"""AId 与 BvId 的统一,大多数 API 只需要其中一种即可正常工作
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
# 初始化
|
||||
# 这两个 Id 事实上是完全一样的,指向同一个资源
|
||||
# 因此我们只获取其一即可,在能够获取 BvId 的情况下建议使用 BvId
|
||||
aid = AId("808982399")
|
||||
bvid = BvId("BV1f34y1k7D5")
|
||||
### Examples
|
||||
|
||||
# 使用
|
||||
# 由于 B 站大多数需要 aid/bvid 的接口都是只提供其一即可,
|
||||
# 因此我们可以直接这样通过格式化的方式来产生一个合法的接口链接
|
||||
api = "https://api.bilibili.com/x/player/pagelist?aid={aid}&bvid={bvid}&jsonp=jsonp"
|
||||
api = api.format(aid=aid.value, bvid="")
|
||||
api = api.format(aid="", bvid=bvid.value)
|
||||
``` python
|
||||
# 初始化
|
||||
# 这两个 Id 事实上是完全一样的,指向同一个资源
|
||||
# 因此我们只获取其一即可,在能够获取 BvId 的情况下建议使用 BvId
|
||||
aid = AId("808982399")
|
||||
bvid = BvId("BV1f34y1k7D5")
|
||||
|
||||
# 为了方便,继承了 AvId 的 AId 和 BvId 都可以通过 to_dict 方法简化这一步
|
||||
api = api.format(**aid.to_dict())
|
||||
api = api.format(**bvid.to_dict())
|
||||
# 这样就完全屏蔽了 aid 和 bvid 的差异了
|
||||
# 使用
|
||||
# 由于 B 站大多数需要 aid/bvid 的接口都是只提供其一即可,
|
||||
# 因此我们可以直接这样通过格式化的方式来产生一个合法的接口链接
|
||||
api = "https://api.bilibili.com/x/player/pagelist?aid={aid}&bvid={bvid}&jsonp=jsonp"
|
||||
api = api.format(aid=aid.value, bvid="")
|
||||
api = api.format(aid="", bvid=bvid.value)
|
||||
|
||||
# 为了方便,继承了 AvId 的 AId 和 BvId 都可以通过 to_dict 方法简化这一步
|
||||
api = api.format(**aid.to_dict())
|
||||
api = api.format(**bvid.to_dict())
|
||||
# 这样就完全屏蔽了 aid 和 bvid 的差异了
|
||||
```
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
|
|
|
@ -25,13 +25,15 @@ def slice_blocks(
|
|||
) -> list[tuple[int, Optional[int]]]:
|
||||
"""生成分块后的 (start, size) 序列
|
||||
|
||||
Args:
|
||||
start (int): 总起始位置
|
||||
total_size (Optional[int]): 需要分块的总大小
|
||||
block_size (Optional[int], optional): 每块的大小. Defaults to None.
|
||||
### Args
|
||||
|
||||
Returns:
|
||||
list[tuple[int, Optional[int]]]: 分块大小序列,使用元组组织,格式为 (start, size)
|
||||
- start (int): 总起始位置
|
||||
- total_size (Optional[int]): 需要分块的总大小
|
||||
- block_size (Optional[int], optional): 每块的大小. Defaults to None.
|
||||
|
||||
### Returns
|
||||
|
||||
- list[tuple[int, Optional[int]]]: 分块大小序列,使用元组组织,格式为 (start, size)
|
||||
"""
|
||||
if total_size is None:
|
||||
return [(0, None)]
|
||||
|
|
|
@ -8,8 +8,9 @@ from typing import Optional
|
|||
def get_terminal_size() -> tuple[int, int]:
|
||||
"""获取 Console 的宽高
|
||||
|
||||
Refs:
|
||||
https://github.com/willmcgugan/rich/blob/e5246436cd75de32f3436cc88d6e4fdebe13bd8d/rich/console.py#L918-L951
|
||||
### Refs
|
||||
|
||||
- https://github.com/willmcgugan/rich/blob/e5246436cd75de32f3436cc88d6e4fdebe13bd8d/rich/console.py#L918-L951
|
||||
"""
|
||||
|
||||
width: Optional[int] = None
|
||||
|
|
|
@ -16,8 +16,9 @@ T = TypeVar("T")
|
|||
class MaxRetry:
|
||||
"""重试装饰器,为请求方法提供一定的重试次数
|
||||
|
||||
Args:
|
||||
max_retry (int): 额外重试次数(如重试次数为 2,则最多尝试 3 次)
|
||||
### Args
|
||||
|
||||
- max_retry (int): 额外重试次数(如重试次数为 2,则最多尝试 3 次)
|
||||
"""
|
||||
|
||||
def __init__(self, max_retry: int = 2):
|
||||
|
|
|
@ -19,24 +19,26 @@ class BufferChunk:
|
|||
class AsyncFileBuffer(aobject):
|
||||
"""异步文件缓冲区
|
||||
|
||||
Args:
|
||||
file_path (str): 所需存储文件位置
|
||||
overwrite (bool): 是否直接覆盖原文件
|
||||
### Args
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
- file_path (str): 所需存储文件位置
|
||||
- overwrite (bool): 是否直接覆盖原文件
|
||||
|
||||
async def afunc():
|
||||
buffer = await AsyncFileBuffer("/path/to/file", True)
|
||||
for i, chunk in enumerate([b'0', b'1', b'2', b'3', b'4']):
|
||||
await buffer.write(chunk, i)
|
||||
await buffer.close()
|
||||
### Examples:
|
||||
|
||||
# 或者使用 async with(注意后面要有 await,因为 AsyncFileBuffer 的初始化是异步的)
|
||||
``` python
|
||||
async def afunc():
|
||||
buffer = await AsyncFileBuffer("/path/to/file", True)
|
||||
for i, chunk in enumerate([b'0', b'1', b'2', b'3', b'4']):
|
||||
await buffer.write(chunk, i)
|
||||
await buffer.close()
|
||||
|
||||
async with await AsyncFileBuffer("/path/to/file", True) as buffer:
|
||||
for i, chunk in enumerate([b'0', b'1', b'2', b'3', b'4']):
|
||||
await buffer.write(chunk, i)
|
||||
# 或者使用 async with(注意后面要有 await,因为 AsyncFileBuffer 的初始化是异步的)
|
||||
|
||||
async with await AsyncFileBuffer("/path/to/file", True) as buffer:
|
||||
for i, chunk in enumerate([b'0', b'1', b'2', b'3', b'4']):
|
||||
await buffer.write(chunk, i)
|
||||
```
|
||||
"""
|
||||
|
||||
# pyright: reportIncompatibleMethodOverride=false
|
||||
|
|
|
@ -4,18 +4,20 @@ from typing import Any
|
|||
class aobject(object):
|
||||
"""Inheriting this class allows you to define an async __ainit__.
|
||||
|
||||
Refs:
|
||||
https://stackoverflow.com/questions/33128325/how-to-set-class-attribute-with-await-in-init
|
||||
### Refs
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
- https://stackoverflow.com/questions/33128325/how-to-set-class-attribute-with-await-in-init
|
||||
|
||||
class MyClass(aobject):
|
||||
# pyright: reportIncompatibleMethodOverride=false
|
||||
async def __ainit__(self):
|
||||
...
|
||||
### Examples
|
||||
|
||||
await MyClass()
|
||||
``` python
|
||||
class MyClass(aobject):
|
||||
# pyright: reportIncompatibleMethodOverride=false
|
||||
async def __ainit__(self):
|
||||
...
|
||||
|
||||
await MyClass()
|
||||
```
|
||||
"""
|
||||
|
||||
async def __new__(cls, *args: Any, **kwargs: Any):
|
||||
|
|
|
@ -9,20 +9,22 @@ T = TypeVar("T")
|
|||
def as_sync(async_func: Callable[..., Coroutine[Any, Any, T]]) -> Callable[..., T]:
|
||||
"""将异步函数变成同步函数,避免在调用时需要显式使用 asyncio.run
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
### Examples
|
||||
|
||||
# 不使用 sync
|
||||
async def itoa(a: int) -> str:
|
||||
return str(a)
|
||||
``` python
|
||||
|
||||
s: str = asyncio.run(itoa(1))
|
||||
# 不使用 sync
|
||||
async def itoa(a: int) -> str:
|
||||
return str(a)
|
||||
|
||||
# 使用 sync
|
||||
@as_sync
|
||||
async def itoa(a: int) -> str:
|
||||
return str(a)
|
||||
s: str = itoa(1)
|
||||
s: str = asyncio.run(itoa(1))
|
||||
|
||||
# 使用 sync
|
||||
@as_sync
|
||||
async def itoa(a: int) -> str:
|
||||
return str(a)
|
||||
s: str = itoa(1)
|
||||
```
|
||||
"""
|
||||
|
||||
@wraps(async_func)
|
||||
|
|
|
@ -6,12 +6,13 @@ T = TypeVar("T")
|
|||
def filter_none_value(l: Iterable[Optional[T]]) -> Iterable[T]:
|
||||
"""移除列表(迭代器)中的 None
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
### Examples
|
||||
|
||||
l1 = [1, 2, 3, None, 5, None, 7]
|
||||
l2 = filter_none_value(l1)
|
||||
assert l2 == [1, 2, 3, 5, 7]
|
||||
``` python
|
||||
l1 = [1, 2, 3, None, 5, None, 7]
|
||||
l2 = filter_none_value(l1)
|
||||
assert l2 == [1, 2, 3, 5, 7]
|
||||
```
|
||||
"""
|
||||
result: Iterable[T] = []
|
||||
for item in l:
|
||||
|
|
|
@ -2,14 +2,20 @@
|
|||
class Singleton(type):
|
||||
"""单例模式元类
|
||||
|
||||
Refs:
|
||||
- https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
|
||||
### Refs
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
- https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
|
||||
|
||||
class MyClass(BaseClass, metaclass=Singleton):
|
||||
pass
|
||||
### Examples
|
||||
|
||||
``` python
|
||||
class MyClass(BaseClass, metaclass=Singleton):
|
||||
pass
|
||||
|
||||
obj1 = MyClass()
|
||||
obj2 = MyClass()
|
||||
assert obj1 is obj2
|
||||
```
|
||||
"""
|
||||
|
||||
_instances = {}
|
||||
|
|
|
@ -9,15 +9,16 @@ T = TypeVar("T")
|
|||
def xmerge(*multi_list: Iterable[T]) -> Iterable[T]:
|
||||
"""将多个 list 交错地合并到一个 list
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
### Examples
|
||||
|
||||
multi_list = [
|
||||
[1, 2, 3, 4, 5],
|
||||
[6, 7, 8],
|
||||
[9, 10, 11, 12]
|
||||
]
|
||||
xmerge(*multi_list)
|
||||
# [1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5]
|
||||
``` python
|
||||
multi_list = [
|
||||
[1, 2, 3, 4, 5],
|
||||
[6, 7, 8],
|
||||
[9, 10, 11, 12]
|
||||
]
|
||||
xmerge(*multi_list)
|
||||
# [1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5]
|
||||
```
|
||||
"""
|
||||
return filter_none_value(chain(*zip_longest(*multi_list)))
|
||||
|
|
|
@ -5,9 +5,10 @@ def gen_priority_sequence(choice: int, num_choices: int) -> list[int]:
|
|||
- 在清晰度中,应当从左向右清晰度降低
|
||||
- 在编码方式中,应当从左向右兼容性提高,压缩率降低
|
||||
|
||||
Args:
|
||||
choice (int): 是当前选择的目标索引
|
||||
num_choices (int): 是可选择目标数量
|
||||
### Args:
|
||||
|
||||
- choice (int): 是当前选择的目标索引
|
||||
- num_choices (int): 是可选择目标数量
|
||||
|
||||
"""
|
||||
|
||||
|
|
Loading…
Reference in New Issue