Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add get_short_url to generate the b23.tv url from the bilibili.com url #720

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bilibili_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .utils.sync import sync
from .utils.credential_refresh import Credential
from .utils.picture import Picture
from .utils.short import get_real_url
from .utils.short import get_real_url, get_short_url
from .utils.parse_link import ResourceType, parse_link
from .utils.aid_bvid_transformer import aid2bvid, bvid2aid
from .utils.danmaku import DmMode, Danmaku, DmFontSize, SpecialDanmaku
Expand Down Expand Up @@ -135,6 +135,7 @@
"game",
"get_aiohttp_session",
"get_real_url",
"get_short_url",
"get_session",
"homepage",
"hot",
Expand Down
95 changes: 90 additions & 5 deletions bilibili_api/utils/short.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,109 @@

from .. import settings
from .credential import Credential
from .network import get_session, get_aiohttp_session
from .network import get_session, get_aiohttp_session, HEADERS
from ..exceptions import ApiException, ArgsException

import re
import random
import string

async def get_real_url(short_url: str, credential: Optional[Credential] = None) -> str:

def acquire_buvid(credential: Optional[Credential] = None) -> str:
"""
获取短链接跳转目标,以进行操作
从Credential中取出buvid3,若不存在则生成一个随机的buvid3

Args:
short_url(str): 短链接。
credential(Credential \| None): 凭据类。

Returns:
buvid3的字符串
"""

# return given buvid3 if possible
if credential:
buvid3 = credential.get_cookies()['buvid3']

if buvid3 is not None:
return buvid3

# random generation
buvid3_pattern = '8-4-4-4-17' # current buvid3 char-length pattern, might be changed later
parts = buvid3_pattern.split('-')

buvid3_rand_gen = ["".join(random.choices(string.digits + string.ascii_letters, k=int(part))) for part in parts]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不建议随机,有spi接口可以用


return "-".join(buvid3_rand_gen) + "infoc"


async def get_short_url(real_url: str, credential: Optional[Credential] = None) -> str:
"""
获取目标链接的短链接。支持bilibili.com的相关链接。

Args:
real_url(str): 目标链接。

credential(Credential \| None): 凭据类。

Returns:
目标链接的b23.tv短链接。

尽管目标链接可能不存在,但仍然会生成短链接。

相同的目标链接重复调用此方法会获得不同的短链接。
"""

# validate the starting part of url
url_start_pattern = re.compile(pattern=r'^https?:\/\/(?:www\.)?bilibili\.com')

if not re.match(pattern=url_start_pattern, string=real_url):
raise ArgsException(msg=f"提供的real_url {real_url} 不符合格式。"
f"支持的格式为bilibili.com的相关链接并含有http或https协议。")

# POST request
try:
post_data = {
'build': str(random.randint(6000000, 10000000)),
'buvid': acquire_buvid(credential=credential),
'oid': real_url,
'platform': random.choice(['android', 'ios']),
'share_channel': 'COPY',
'share_id': 'public.webview.0.0.pv',
'share_mode': str(random.randint(1, 10))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不了解的参数可以照旧,build 也是

}

api_url = 'https://api.biliapi.net/x/share/click'

if settings.http_client == settings.HTTPClient.HTTPX:
resp_content = (await get_session().post(url=api_url, headers=HEADERS, data=post_data)).json()
else:
resp = await get_aiohttp_session().post(
url=api_url, data=post_data, headers=HEADERS
)
resp_content = await resp.json()

# the 'content' sometimes will not be in the returned content due to build version, real_url, or buvid (rarely)
if 'content' not in resp_content['data']:
raise ApiException(msg="生成短链接失败。若提供的目标链接格式确认正确,请反馈此bug以更新相应params")

return resp_content['data']['content']

except Exception as e:
raise e


async def get_real_url(short_url: str) -> str:
"""
获取短链接跳转目标,以进行操作。

Args:
short_url(str): 短链接。

Returns:
目标链接(如果不是有效的链接会报错)

返回值为原 url 类型
"""
credential = credential if credential else Credential()

try:
if settings.http_client == settings.HTTPClient.HTTPX:
Expand Down
9 changes: 8 additions & 1 deletion docs/b23tv.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@

bilibili_api 从 10.0.0 开始支持短链接了(说白了就是支持查看短链目标了)

获取默认链接(长链接)的短链接
``` python
from bilibili_api import get_short_url, sync
print(sync(get_short_url(real_url="https://www.bilibili.com/video/BV18X4y1N7Yh/"))) # optionally pass in Credential
```

获取短链接的对应默认链接(长链接)
``` python
from bilibili_api import get_real_url, sync
print(sync(get_real_url("https://b23.tv/mx00St"))) # https://www.bilibili.com/video/BV1YQ4y127Rd?p=1&share_medium=android&share_plat=android&share_session_id=d6c56bd5-db84-4cc8-9bb7-8f91cd8edfe0&share_source=COPY&share_tag=s_i&timestamp=1629155789&unique_k=mx00St
print(sync(get_real_url(short_url="https://b23.tv/mx00St"))) # https://www.bilibili.com/video/BV1YQ4y127Rd?p=1&share_medium=android&share_plat=android&share_session_id=d6c56bd5-db84-4cc8-9bb7-8f91cd8edfe0&share_source=COPY&share_tag=s_i&timestamp=1629155789&unique_k=mx00St
```
14 changes: 13 additions & 1 deletion docs/modules/bilibili_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,24 @@ BV 号转 AV 号。

---

## async def get_short_url()

| name | type | description |
|------------|---------------------|-------------|
| real_url | str | 真实链接 |
| credential | Optional[Credential] | 凭据类. |

获取bilibili真实链接对应的短链接。

**注意:** 这个函数对于同一个真实链接的每一次调用都会返回不同的短链接。并且,请注意短链接也会包含你的分享信息(因为会redirect)。

**Returns:** b23.tv的短链接

## async def get_real_url()

| name | type | description |
| - | - | - |
| short_url | str | 短链接 |
| credential | Optional[Credential] | 凭据类. |

获取短链接对应的真实链接。

Expand Down