-
-
Notifications
You must be signed in to change notification settings - Fork 58
API
-
正式环境:
https://bsbsb.top/api/**
,例如https://bsbsb.top/api/skipSegments
-
测试环境:
https://bsbsb.top/test/api/**
,例如https://bsbsb.top/test/api/skipSegments
测试环境和正式环境功能基本相同,可能会多一些测试功能。两个环境的数据是分开的,如果需要开发测试接口请使用测试环境,每天5:00am从正式环境同步数据到测试环境。
-
所有的 API 都是基于 HTTP 协议的 RESTful API。
-
API大量使用了HTTP错误状态码。例如如果请求参数有误,会返回400;获取数据的接口无数据,会返回404;重复提交会返回429;因此看到错误码不一定是调用出错,
-
用户ID有两种,公开ID或者私人ID。私人ID类似密码,用于插件的鉴权,不应该公开;公开ID是私人ID的哈希值,可以用于公开展示,排行榜和统计数据中展示的就是公开ID。
-
私人ID可以自行设置,要求至少为30个字符长度的纯字符串。服务器不会保存任何私人ID,如果你不幸弄丢了私人ID,那就再也没办法找回了。
-
公开ID是私人ID用
SHA256
算法哈希5000次的值,应该为64个字符长度。
设置私人ID的位置
设置 -> 备份/恢复 -> 导入/导出您的私人用户ID
复制公开ID的位置
-
GET方法的参数都是以URL参数传递的,POST、DELETE方法的参数基本都是在body中传递的。所有的返回都是JSON格式。
-
列表类型的URL参数,例如
categories
,传递的是带着括号的列表,例如categories=["sponsor","poi_highlight"]
。
获取某个视频的片段。可以指定类别、动作类型、强制返回的片段等。默认返回除了"fill"类别之外的所有数据。
GET /api/skipSegments
参数
{
videoID: string, // 视频BVID
category: string, // 片段类别,默认返回除了"fill"之外的所有类别,可以重复以包含多个类别
categories: string[], // 和category二选一
requiredSegment: string, // 强制返回的片段 UUID,即使未达到最小投票阈值。可以重复以包含多个片段
requiredSegments: string[], // 和requiredSegment二选一
actionType: string, // 行为类别,默认返回所有类型,不建议设置。可以重复以包含多个类型
actionTypes: string[], // 和actionType二选一
}
返回
[{ // 片段对象
segment: float[], // 起始和结束时间(秒),例如 [0, 15.23]
UUID: string, // 片段UUID
category: string, // 片段类别
actionType: string, // 片段动作类型
locked: int, // 该提交是否锁定
votes: int, // 该片段的投票数
videoDuration: int, // 提交时的视频时长,用于判断提交是否过期,未知时为 0,要求误差在 ±2 秒内
}]
错误状态码
400: 参数错误
404: 未找到数据
获取视频的片段,提供额外的隐私保护。sha256HashPrefix
是BVID的哈希值的前缀,长度4-32字符(建议使用4字符)。这样的访问方式使得服务器无法知道客户端具体在访问哪个视频,因此提高了隐私保护。这也是插件获取片段的方式。
默认返回除了"fill"类别之外的所有数据。
GET /api/skipSegments/:sha256HashPrefix
参数
{
sha256HashPrefix: string, // 视频BVID的哈希值前缀
category: string, // 片段类别,默认返回除了"fill"之外的所有类别,可以重复以包含多个类别
categories: string[], // 和category二选一
requiredSegment: string, // 强制返回的片段 UUID,即使未达到最小投票阈值。可以重复以包含多个片段
requiredSegments: string[], // 和requiredSegment二选一
actionType: string, // 行为类别,默认返回所有类型,不建议设置。可以重复以包含多个类型
actionTypes: string[], // 和actionType二选一
}
返回
[{ // 视频对象
videoID: string, // BVID
segments: [{ // 片段对象
segment: float[], // 起始和结束时间(秒),例如 [0, 15.23]
UUID: string, // 片段UUID
category: string, // 片段类别
actionType: string, // 片段动作类型
locked: int, // 该提交是否锁定
votes: int, // 该片段的投票数
videoDuration: int, // 提交时的视频时长,用于判断提交是否过期,未知时为 0,要求误差在 ±2 秒内
}]
}]
错误状态码
400: 参数错误
404: 未找到数据
提交片段
POST /api/skipSegments
参数
{
videoID: string, // 视频BVID
userID: string, // 私人用户ID
userAgent: string, // 发起请求的客户端和版本,例如 "Chromium/1.0.0"
videoDuration: float, // 视频时长,用于判断视频是否经过换源
segments: [
{ // 片段列表
segment: float[], // 起始和结束时间(秒),例如 [0, 15.23]
category: string, // 片段类别
actionType: string // 片段动作类型
},
...
]
}
返回
[ // 片段列表
{
UUID: string, // 新片段的UUID
category: string, // 片段类别
segment: float[], // start起始和结束时间(秒)
}
]
错误状态码
400: 参数错误
403: 被自动审核机制拒绝,原因在返回信息中
429: 重复提交太快(触发速率控制)
409: 重复提交
对一个片段进行投票,或者投票修改片段的类别。片段提交者和VIP用户可以一票隐藏片段或者修改片段的类别。
POST /api/voteOnSponsorTime
参数
常规投票:
{
UUID: string, // 片段UUID
userID: string, // 私人用户ID,用于鉴权
type: int // 投票类型:0 -> 点踩,1 -> 点赞,20 -> 撤销投票
}
修改类别:
{
UUID: string, // 片段UUID
userID: string, // 私人用户ID,用于鉴权
category: string // 新的类别
}
返回
无
错误状态码
400: 参数错误
403: 被自动审核机制拒绝,原因在返回信息中
跳过一次片段后调用此接口,记录片段的观看次数。
POST /api/viewedVideoSponsorTime
参数
{
UUID: string // 片段UUID
}
返回 无
错误状态码
400: 参数错误
获取片段的详细信息,最多一次查询10个片段。
GET /api/segmentInfo
参数
{
// 最多一次查询10个片段
UUID: string,
// 或者
UUIDs: string[]
}
返回
[{ // 片段列表
videoID: string, // 视频BVID
startTime: float, // 片段开始时间
endTime: float, // 片段结束时间
votes: int, // 净点赞数
locked: int, // 是否锁定
UUID: string, // 片段UUID
userID: string, // 提交者的公开用户ID
timeSubmitted: int, // 提交时间戳
views: int, // 跳过次数
category: string, // 片段类别
actionType: string, // 片段动作类型
videoDuration: int, // 视频时长
hidden: int, // 是否隐藏,0为未隐藏,1为隐藏,2为被自动审核机制隐藏
reputation: int, // 提交者的声誉
shadowHidden: int, // 暗藏,0为未暗藏,1为暗藏
hashedVideoID: string, // 视频ID的哈希值
userAgent: string, // 提交者的客户端信息
}]
错误状态码
400: 参数错误
404: 未找到数据
根据特定的过滤条件,查询一个视频上的片段。注意,这个接口不应该用于获取用户需要跳过的片段,因为没有经过匹配和过滤,可能会看到很多低质量片段。获取最佳片段应该使用/api/skipSegments
接口。
GET /api/searchSegments
参数
{ videoID: string,
category: string,
// 或者
categories: string[],
actionType: string,
// 或者
actionTypes: string[],
page: int, // 分页页码
// 投票数范围
minVotes: int,
maxVotes: int,
// 跳过数范围
minViews: int,
maxViews: int,
// 默认为true,如果传false,则不显示匹配该种类型的片段
locked: boolean,
hidden: boolean,
ignored: boolean, // 隐藏或者
}
返回
{
segmentCount: int, // 片段总数
page: int, // 分页页码
segments: [{ // 片段列表,最大10个
UUID: string,
timeSubmitted: int,
startTime: int,
endTime: int,
category: string,
actionType: string,
votes: int,
views: int,
locked: int,
hidden: int,
shadowHidden: int,
userID: string,
description: string,
}]
}
错误状态码
400: 参数错误
404: 未找到数据
GET /api/portVideo
参数
{
videoID: string, // 视频BVID
}
返回
{
"bvID": string, // B站视频BVID
"ytbID": string, // YouTube视频ID
"UUID": string, // 绑定记录的UUID(不是视频中片段的UUID,是绑定记录本身的UUID)
"votes": int, // 绑定记录的投票数
"locked": int, // 绑定记录是否锁定
}
错误状态码
400: 参数错误
404: 未找到数据
通过BVID的哈希值获取绑定视频记录。
GET /api/portVideo/:sha256HashPrefix
参数
{
sha256HashPrefix: string, // 视频BVID的哈希前缀(4-32字符)
}
返回
[ // 绑定记录列表
{
"bvID": string, // B站视频BVID
"ytbID": string, // YouTube视频ID
"UUID": string, // 绑定记录的UUID(不是视频中片段的UUID,是绑定记录本身的UUID)
"votes": int, // 绑定记录的投票数
"locked": int, // 绑定记录是否锁定
}
]
错误状态码
400: 参数错误
404: 未找到数据
POST /api/portVideo
参数
{ // 全部必填
"bvID": string, // B站视频BVID
"ytbID": string, // YouTube视频ID
"userID": string, // 私人用户ID
"biliDuration": int, // B站视频时长(单位:秒)
}
返回
{ // 刚刚创建的绑定记录
"bvID": string, // B站视频BVID
"ytbID": string, // YouTube视频ID
"UUID": string, // 绑定记录的UUID(不是视频中片段的UUID,是绑定记录本身的UUID)
"votes": int, // 绑定记录的投票数
"locked": int, // 绑定记录是否锁定
}
错误状态码
500: 服务器无法获取绑定的YouTube视频信息
400: 参数错误
409:重复提交
429:正在提交中
通过BVID的哈希值获取绑定视频记录。
POST /api/votePort
参数
{
"UUID": string, // 绑定记录的UUID(不是视频中片段的UUID,是绑定记录本身的UUID)
"bvID": string, // B站视频BVID
"userID": string, // 私人用户ID
"type": int, // 投票类型:0 -> 点踩,1 -> 点赞,20 -> 撤销投票
}
返回 无
错误状态码
400: 参数错误
404: 未找到数据
429:正在提交中
更新来自绑定视频的片段,已有的片段会更新投票数,新的片段会被添加,被删除的片段会被隐藏。
POST /api/updatePortedSegments
参数
{
videoID: string, // 视频BVID
}
返回 无
错误状态码
400: 参数错误
404: 未找到数据
429:正在提交中
获取是否锁定了某个视频的类别
GET /api/lockCategories
参数
{
videoID: string, // 视频BVID
actionTypes: string[] // 动作类型
}
返回
{
categories: string[], // 锁定的类别
reason: string, // 锁定的原因
actionTypes: string[] // 动作类型
}
错误状态码
400: 参数错误
404: 未找到锁定数据
Get locked categories for a video with extra privacy
sha256HashPrefix is a hash of the YouTube videoID. It should be the first 4 - 32 characters (4 is recommended). This provides extra privacy by potentially finding more than just the video you are looking for. This makes the server not know exactly what video you are looking for.
GET /api/lockCategories/:sha256HashPrefix
参数
{
prefix: sha256HashPrefix // BVID哈希值前缀
}
返回
[{ // 锁定类别列表
videoID: string, // BVID
hash: string, // BVID哈希值
categories: string[], // 锁定的类别
reason: string // 锁定的原因
}]
错误状态码
400: 参数错误
404: 未找到锁定数据
GET /api/lockReason
参数
{
videoID: string,
category: string,
// 或
categories: string[],
actionTypes: string[]
}
返回
[{
category: string, // category [1]
locked: integer, // status of lock
reason: string, // reason for lock
userID: string, // publicID of locking VIP
userName: string // username of locking VIP
}]
错误状态码
400: 参数错误
GET /api/userInfo
参数
{
userID: string // local UserID
// OR
publicUserID: string // Public userID
values: string[] // Optional, Values to get from userInfo
// default values are
// ["userID", "userName", "minutesSaved", "segmentCount", "ignoredSegmentCount",
// "viewCount", "ignoredViewCount", "warnings", "warningReason", "reputation",
// "vip", "lastSegmentID"]
// OR
value: string // Optional, Value to get from userInfo, can be repeated for multiple values
}
返回
{
userID: string, // Public userID
userName: string, // Public userID if not set
minutesSaved: float, // Minutes saved
segmentCount: int, // Total number of segments excluding ignored/ hidden segments
ignoredSegmentCount: int, // Total number of ignored/ hidden segments
viewCount: int, // Total number of views excluding view on ignored/ hidden segments
ignoredViewCount: int, // Total number of view on ignored/ hidden segments
warnings: int, // Currently enabled warnings
reputation: float,
vip: int, // VIP status
lastSegmentID: string, // UUID of last submitted segment
permissions: { // Can the user submit segments of this category?
category: boolean // [1]
}
}
错误状态码
400: 参数错误
GET /api/userStats
参数
{
userID: string // 私人用户ID
// 或
publicUserID: string // 公开用户ID
fetchCategoryStats: boolean // 是否获取类别统计,默认为false
fetchActionTypeStats: boolean // 是否获取动作类型统计,默认为false
}
返回
{
userID: string // 公开用户ID
userName: string // 用户名
overallStats: {
minutesSaved: integer // same as userInfo
segmentCount: integer // same as userInfo
}
// 如果指明
categoryCount: {
sponsor: integer
intro: integer
outro: integer
interaction: integer
selfpromo: integer
music_offtopic: integer
preview: integer
poi_highlight: integer
filler: integer,
exclusive_access: integer,
chapter: integer
}
// 如果指明
actionTypeCount: {
skip: integer,
mute: integer,
full: integer,
poi: integer,
chapter: integer
}
}
错误状态码
400: 参数错误
获取一个用户提交的片段跳过数量的总数
GET /api/getViewsForUser
参数
{
userID: string // 私人用户ID
}
返回
{
viewCount: int
}
错误状态码
404: Not Found
获取一个用户提交片段节省的总时间
GET /api/getSavedTimeForUser
参数
{
userID: string // 私人用户ID
}
返回
{
timeSaved: float // 单位分钟
}
错误状态码
404: Not Found
POST /api/setUsername
参数
为自己设置用户名
{
userID: string, // 私人用户ID
username: string, // 可选,用户名
}
或
为他人设置用户名(管理员)
{
userID: string, // 公开用户ID
username: string, // 可选,用户名
adminUserID: string // 管理员私人用户ID
}
返回 无
错误状态码
400: 参数错误
403: 权限不足
GET /api/getUsername
参数
{
userID: string // 私人用户ID
}
返回
{
userName: string // 如果没有设置用户名,返回公开用户ID
}
错误状态码
400: 参数错误
搜索匹配用户名的公开用户ID
GET /api/userID
参数
{
username: string, // 搜索用户名,区分大小写。模糊搜索最小3个字符,最大64个字符
exact: boolean // 是否精确匹配
}
返回
[{ // 用户列表,最多10个
userName: string,
userID: string
}]
错误状态码
400: 参数错误
404: Not Found
GET /api/getTopUsers
参数
{
sortType: int
// 排序类型
// 0 -> 节省时间
// 1 -> 跳过数量
// 2 -> 提交数量
// 3 -> 点赞数量
// 4 -> 绑定搬运视频
}
返回
{
userNames: string[],
viewCounts: int[],
totalSubmissions: int[],
minutesSaved: float[]
}
错误状态码
400: 参数错误
GET /api/getTopCategoryUsers
参数
{
sortType: int
// 排序类型
// 0 -> 节省时间
// 1 -> 跳过数量
// 2 -> 提交数量
// 3 -> 点赞数量
// 4 -> 绑定搬运视频
category: string // 分类
}
返回
{
userNames: string[],
viewCounts: int[],
totalSubmissions: int[],
minutesSaved: float[]
}
错误状态码
400: 参数错误
GET /api/getTotalStats
参数
{
countContributingUsers: boolean // Optional, default false
}
返回
{
userCount: int, // Only if countContributingUsers was true
activeUsers: int, // Sum of public install stats from Chrome webstore and Firefox addons store
apiUsers: int, // 48-hour active API users (https://github.com/ajayyy/PrivacyUserCount)
viewCount: int,
totalSubmissions: int,
minutesSaved: float
}
可以使用返回体中的任意键作为value传入,不传入将返回所有值。
GET /api/status/:value
返回
{
uptime: int, // Uptime of server in seconds
commit: string, // Full SHA hash of latest git commit, development or test
db: int, // Current database version
startTime: int, // Unix time (miliseconds) that request was received
processTime: int, // Delay between DB request made and response received (miliseconds)
redisProcessTime: int, // Delay between redis request made and response received (miliseconds)
loadavg: int[], // 5 and 15 minute loadavg
statusRequests: int, // number of /status requests in the last minute
hostname: string // hostname of current server
}
错误状态码
404: Not Found