parent
99c196afad
commit
8cdf2a6655
|
|
@ -0,0 +1,121 @@
|
|||
/* 哔哩小窗样式 */
|
||||
*{
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body{
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
img{
|
||||
max-width: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
a{
|
||||
color: inherit;
|
||||
transition: color .3s;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.bili-box{
|
||||
color: #555;
|
||||
height: 10em;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bili-box.white{ background: #fff }
|
||||
.bili-box.gray{ background: #f9f9f9 }
|
||||
.bili-box.black{
|
||||
color: #eee;
|
||||
background: #333;
|
||||
}
|
||||
.bili-box h1{
|
||||
overflow: hidden;
|
||||
font-size: 1.05em;
|
||||
font-weight: normal;
|
||||
white-space: nowrap;
|
||||
margin-bottom: .5em;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.bili-box h1 a:hover{
|
||||
color: #4cb1f3;
|
||||
}
|
||||
|
||||
.bili-box .bili-img{
|
||||
flex: 0 0 30%;
|
||||
max-width: 30%;
|
||||
}
|
||||
.bili-box .bili-img img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.bili-box .bili-info{
|
||||
padding: 1em;
|
||||
max-width: 70%;
|
||||
}
|
||||
.bili-info p{
|
||||
opacity: .75;
|
||||
font-size: .85em;
|
||||
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
}
|
||||
.bili-powered{
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
color: #fff;
|
||||
opacity: .8;
|
||||
padding: .5em;
|
||||
line-height: 1;
|
||||
font-size: .5em;
|
||||
position: absolute;
|
||||
background: #4cb1f3;
|
||||
transition: opacity .3s;
|
||||
border-radius: 1em 0 0 0;
|
||||
}
|
||||
.bili-powered:hover{ opacity: 1 }
|
||||
.black .bili-powered{ background: #0d5e92 }
|
||||
|
||||
.bili-hidden{ display: none }
|
||||
|
||||
@media screen and (max-width: 768px){
|
||||
.bili-box .bili-info{
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
|
||||
color: #fff;
|
||||
max-width: none;
|
||||
font-size: .875em;
|
||||
padding: 1em .75em;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
-webkit-backdrop-filter: blur(3px);
|
||||
backdrop-filter: blur(3px);
|
||||
}
|
||||
|
||||
.bili-info p{
|
||||
-webkit-line-clamp: 1;
|
||||
}
|
||||
|
||||
.bili-box .bili-img{
|
||||
flex: 1;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.bili-powered{
|
||||
top: 0;
|
||||
bottom: inherit;
|
||||
border-radius: 0 0 0 1em;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
import { Api, Get, Query, useContext } from "@midwayjs/hooks";
|
||||
|
||||
import { getVideoInfo } from "./utils/bili";
|
||||
|
||||
import { client } from "./utils/redis";
|
||||
|
||||
const availableStyle = ["gray", "white", "black", "shadow"];
|
||||
|
||||
export default Api(
|
||||
Get(),
|
||||
Query<{ av?: string, bv?: string }>(),
|
||||
async () => {
|
||||
const ctx = useContext();
|
||||
|
||||
const id = ctx.query.av || ctx.query.bv;
|
||||
const type = "av" in ctx.query ? "av" : "bv" in ctx.query ? "bv" : undefined;
|
||||
|
||||
if (!id) {
|
||||
return "请输入 ID";
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
return "无效的 type";
|
||||
}
|
||||
|
||||
// 增加使用数量
|
||||
await client.incr("api-next:stat:bili");
|
||||
|
||||
// 尝试使用缓存
|
||||
const cached = await client.lRange(`api-next:bili:${id}`, 0, 3);
|
||||
|
||||
let result;
|
||||
|
||||
if (cached.length) {
|
||||
result = {
|
||||
title: cached[0],
|
||||
image: cached[1],
|
||||
desc: cached[2],
|
||||
};
|
||||
}
|
||||
else {
|
||||
const info = await getVideoInfo(id, type);
|
||||
|
||||
if (!info) {
|
||||
return "获取失败";
|
||||
}
|
||||
|
||||
await client.rPush(`api-next:bili:${id}`, [
|
||||
info.title,
|
||||
info.image,
|
||||
info.desc,
|
||||
]);
|
||||
await client.expire(`api-next:bili:${id}`, 21600);
|
||||
|
||||
result = info;
|
||||
}
|
||||
|
||||
// 后期参数填补
|
||||
let classname = "bili-box";
|
||||
|
||||
if (ctx.query.style && availableStyle.includes(ctx.query.style)) {
|
||||
classname += ` ${ctx.query.style}`;
|
||||
}
|
||||
|
||||
const link = `https://www.bilibili.com/video/${type === "av" ? "av" : ""}/${id}`;
|
||||
|
||||
return (`
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-cmn-hans">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>哔哩小窗 iFrame API</title>
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
<link href="/assets/bili.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="${classname}">
|
||||
<a class="bili-img" href="${link}" target="_blank">
|
||||
<img src="${result.image}" alt="${result.title}" referrerpolicy="no-referrer" />
|
||||
</a>
|
||||
<div class="bili-info">
|
||||
<h1><a href="${link}" target="_blank">${result.title}</a></h1>
|
||||
<p>${result.desc}</p>
|
||||
</div>
|
||||
<div class="bili-powered">
|
||||
<a href="https://api.paugram.com" target="_blank" title="使用了奇趣保罗的哔哩哔哩小窗接口">哔哩小窗</a>
|
||||
</div>
|
||||
<div class="bili-hidden">Cached: ${cached.length ? true : false}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`)
|
||||
}
|
||||
);
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { Api, Get, Query, useContext } from "@midwayjs/hooks";
|
||||
|
||||
import { client } from "./utils/redis";
|
||||
|
||||
export default Api(
|
||||
Get(),
|
||||
Query<{ id?: string, loop?: string }>(),
|
||||
async () => {
|
||||
const ctx = useContext();
|
||||
|
||||
// 增加使用数量
|
||||
await client.incr("api-next:stat:dji");
|
||||
|
||||
return (`
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-cmn-hans">
|
||||
<head>
|
||||
<title>大疆视频外链</title>
|
||||
<meta name="referrer" content="no-referrer"/>
|
||||
<style>*{ margin: 0 } video{ width: 100%; height: 100%; background: #000; max-width: 100%; outline: none }</style>
|
||||
</head>
|
||||
<body>
|
||||
${ctx.query.id ? `<video src="https://cn-videos.dji.net/video_trans/${ctx.query.id}/720.mp4" controls${"loop" in ctx.query ? " loop" : ""}></video>` : "<p>没有输入 ID</p>"}
|
||||
</body>
|
||||
</html>`)
|
||||
}
|
||||
);
|
||||
|
|
@ -14,9 +14,6 @@ export default Api(
|
|||
ctx.set("access-control-allow-origin", "*");
|
||||
ctx.set("access-control-allow-headers", "x-requested-with");
|
||||
|
||||
// 增加使用数量
|
||||
await client.incr("api-next:stat:netease");
|
||||
|
||||
const { id } = ctx.query;
|
||||
|
||||
if (!id) {
|
||||
|
|
@ -26,6 +23,9 @@ export default Api(
|
|||
}
|
||||
}
|
||||
|
||||
// 增加使用数量
|
||||
await client.incr("api-next:stat:netease");
|
||||
|
||||
// 直接播放
|
||||
if ("play" in ctx.query) {
|
||||
ctx.status = 302;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import fetch from "isomorphic-unfetch";
|
||||
|
||||
export const getVideoInfo = async (id: number | string, type: "av" | "bv") => {
|
||||
return fetch(`https://api.bilibili.com/x/web-interface/view?${type === "av" ? "aid" : "bvid"}=${id}`).then(res => {
|
||||
try{
|
||||
return res.json();
|
||||
}
|
||||
catch(e){
|
||||
// Todo: 这个地方可能会有问题
|
||||
return undefined;
|
||||
}
|
||||
}).then(json => {
|
||||
return json ? parseVideoData(json.data) : undefined;
|
||||
})
|
||||
}
|
||||
|
||||
export const parseVideoData = (json: any) => {
|
||||
return {
|
||||
title: json.title,
|
||||
image: json.pic.replace(/^http:\/\//, "https://"),
|
||||
desc: json.desc.length > 60 ? `${json.desc.substring(0, 60)}...` : json.desc,
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue