Skip to content

Instantly share code, notes, and snippets.

@journey-ad
Last active February 26, 2024 07:29
Show Gist options
  • Star 38 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save journey-ad/be8d977683297fd32d5680cdd6e914a7 to your computer and use it in GitHub Desktop.
Save journey-ad/be8d977683297fd32d5680cdd6e914a7 to your computer and use it in GitHub Desktop.
在哔站右下角添加嘉然小姐的live2d模型
// ==UserScript==
// @name #相亲相爱一嘉人#
// @description 在哔站右下角添加嘉然小姐的live2d模型
// @version 1.0.1
// @namespace https://github.com/journey-ad
// @author journey-ad
// @include /^https:\/\/(www|live|space|t)\.bilibili\.com\/.*$/
// @icon https://www.google.com/s2/favicons?domain=bilibili.com
// @license GPL v2
// @run-at document-end
// @grant none
// ==/UserScript==
(async function () {
'use strict';
if (inIframe()) {
console.log('iframe中不加载');
return false;
}
const 引流 = [
"https://space.bilibili.com/672328094",
"https://www.bilibili.com/video/BV1FZ4y1F7HH",
"https://www.bilibili.com/video/BV1FX4y1g7u8",
"https://www.bilibili.com/video/BV1aK4y1P7Cg",
"https://www.bilibili.com/video/BV17A411V7Uh",
"https://www.bilibili.com/video/BV1JV411b7Pc",
"https://www.bilibili.com/video/BV1AV411v7er",
"https://www.bilibili.com/video/BV1564y1173Q",
"https://www.bilibili.com/video/BV1MX4y1N75X",
"https://www.bilibili.com/video/BV17h411U71w",
"https://www.bilibili.com/video/BV1ry4y1Y71t",
"https://www.bilibili.com/video/BV1Sy4y1n7c4",
"https://www.bilibili.com/video/BV15y4y177uk",
"https://www.bilibili.com/video/BV1PN411X7QW",
"https://www.bilibili.com/video/BV1Dp4y1H7iB",
"https://www.bilibili.com/video/BV1bi4y1P7Eh",
"https://www.bilibili.com/video/BV1vQ4y1Z7C2",
"https://www.bilibili.com/video/BV1oU4y1h7Sc",
]
const CUSTOM_CSS = `#pio-container {
display: block !important;
bottom: -0.3rem;
z-index: 22637261;
transition: transform 0.3s;
cursor: grab;
}
#pio-container:hover {
transform: translateY(-0.3rem);
}
#pio-container:active {
cursor: grabbing;
}
#pio-container .pio-dialog {
right: 10%;
line-height: 1.5;
background: rgba(255, 255, 255, 0.9);
}
#pio {
height: 240px;
}
.pio-action .pio-home {
display: none;
}
.pio-action span {
background: none;
background-size: 100%;
border: 1px solid #fdcf7b;
border: 0;
width: 2em;
height: 2em;
margin-bottom: 0.6em;
}
.pio-action .pio-skin {
background: url("data:image/svg+xml,%3Csvg class='icon' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 512c0 282.774 229.226 512 512 512s512-229.226 512-512S794.774 0 512 0 0 229.226 0 512z' fill='%23FEC43C'/%3E%3Cpath d='M1013.76 408.576C965.632 175.104 759.808 0 512 0 229.376 0 0 229.376 0 512c0 123.904 44.032 236.544 116.736 324.608 87.04 48.128 186.368 74.752 292.864 74.752 301.056 0 550.912-217.088 604.16-502.784z' fill='%23FFD73A'/%3E%3Cpath d='M233.456 460.383a93.759 93.759 0 1 0 187.526 0c0-51.783-41.984-93.76-93.767-93.76s-93.759 41.977-93.759 93.76zm458.39 0c0 51.782 41.976 93.759 93.759 93.759s93.759-41.984 93.759-93.76c0-51.782-41.984-93.758-93.76-93.758-51.782 0-93.758 41.976-93.758 93.759z' fill='%23873A18'/%3E%3Cpath d='M556.41 689.577H410.561c-17.707 0-31.256-13.548-31.256-31.255 0-17.715 13.549-31.256 31.256-31.256h145.85c17.714 0 31.255 13.548 31.255 31.256s-13.549 31.255-31.256 31.255zM320.97 429.127H156.357c-14.588 0-27.089-13.548-27.089-31.256s12.5-31.247 27.097-31.247H320.96c14.58 0 27.089 13.54 27.089 31.247 0 17.715-12.509 31.256-27.097 31.256zm454.215 0H618.92c-17.715 0-31.255-13.548-31.255-31.256s13.548-31.247 31.255-31.247h156.263c17.715 0 31.255 13.54 31.255 31.247 0 17.715-13.548 31.256-31.255 31.256z' fill='%23873A18'/%3E%3Cpath d='M102.4 327.68C46.08 327.68 0 281.6 0 225.28 0 133.12 102.4 0 102.4 0s102.4 133.12 102.4 225.28c0 56.32-46.08 102.4-102.4 102.4z' fill='%2361A3E0'/%3E%3C/svg%3E");
}
.pio-action .pio-info {
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg'%3E%3Crect transform='rotate(45.001 238.211 363.575)' x='29.285' y='22.411' width='273.903' height='505.038' rx='70' ry='70' fill='%23dcdcdc'/%3E%3Cpath d='M218.543 249.999l-47.186 47.186c-8.987 8.988-8.987 22.47 0 31.457 8.988 8.988 22.47 8.988 31.457 0L250 281.456l15.728 15.729c17.976 17.976 17.976 46.063 0 64.038l-64.037 64.038c-17.976 17.975-46.063 17.975-64.038 0l-64.038-64.038c-17.975-17.975-17.975-46.062 0-64.038l64.038-64.037c17.975-17.976 46.062-17.976 64.038 0l16.852 16.851z' fill='%23fff'/%3E%3Cpath d='M281.457 249.999l47.186-47.186c8.988-8.987 8.988-22.469 0-31.457-8.987-8.987-22.469-8.987-31.457 0L250 218.542l-15.729-15.729c-17.975-17.975-17.975-46.062 0-64.037l64.038-64.038c17.975-17.975 46.062-17.975 64.038 0l64.037 64.038c17.977 17.975 17.977 46.062 0 64.037l-64.037 64.038c-17.976 17.976-46.063 17.976-64.038 0l-16.852-16.852z' fill='%2361a3e0'/%3E%3C/svg%3E");
}
.pio-action .pio-top {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M262.737 70.075c-3.175-2.89-8.439-5.365-12.737-5.365-4.29 0-9.448 2.37-12.632 5.263l-87.814 87.812c-2.921 3.255-5.23 8.518-5.23 12.73 0 4.203 2.196 9.353 5.118 12.617 3.246 2.915 8.621 5.345 12.842 5.345 4.203 0 9.353-2.197 12.617-5.118l75.093-74.848 74.992 74.993c3.175 2.889 8.433 5.359 12.731 5.359 4.29 0 9.448-2.371 12.632-5.263 2.918-3.247 5.329-8.61 5.329-12.827 0-4.204-2.197-9.354-5.118-12.616zm-103.97 233.514v-36.181H19.695v36.181h51.447v131.444h36.178V303.589zm126.788-35.923h-63.85c-8.732.187-18.571 3.868-25.539 10.451-6.579 6.961-10.367 16.85-10.557 25.589v95.488c.179 8.709 3.781 18.668 10.493 25.582 6.913 6.712 16.839 10.334 25.548 10.514h63.849c8.732-.187 18.571-3.868 25.538-10.45 6.581-6.962 10.368-16.852 10.558-25.59v-95.488c-.187-8.733-3.87-18.573-10.452-25.539-6.962-6.581-16.85-10.367-25.588-10.557zm-.14 131.589l.003.105.403.021a20.74 20.74 0 0 0-.322-.013h-.08c.006.172.014.313.021.414l-.027-.414h-.118l.01-.013.107.005-.007-.117-.033.025-.079.1h-63.648l-.106.003-.032.438c.007-.092.015-.243.021-.438-.163.005-.283.012-.365.017l.365-.023.003-.139-.055-.039-.301-.208.356.244.001-.029v-95.493a3.627 3.627 0 0 0-.004-.108l-.417-.028c.106.007.253.014.417.019a10.069 10.069 0 0 0-.023-.42l.031.42.123.004.016-.022.087-.113.036-.047-.137.182.044.001h63.551l.096.074.064.05-.001.049zm184.441-121.032c-6.963-6.58-16.852-10.367-25.59-10.557h-88.627V435.29h36.181v-68.165h52.39c8.732-.187 18.572-3.87 25.54-10.452 6.579-6.961 10.366-16.851 10.556-25.588v-27.323c-.187-8.733-3.868-18.572-10.45-25.539zm-25.471 52.609l.003.105.437.032a10.682 10.682 0 0 0-.437-.021c.007.211.017.355.023.436l-.033-.436a79.554 79.554 0 0 0-.142-.003l-.038.054-.112.166-.119.175.262-.396H391.82v-27.099h52.451l.112-.004.025-.405a14.96 14.96 0 0 0-.018.405c.171-.006.313-.015.416-.023l-.416.031-.004.122-.01-.008.007-.113-.119.008.041.054.081.062-.001.045z' fill='%234c4c4c'/%3E%3C/svg%3E");
}
.pio-action .pio-close {
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M249.999 198.668L352.665 96c14.667-14.666 36.668-14.666 51.335 0 14.666 14.667 14.666 36.668 0 51.334L301.333 250 404 352.668c14.666 14.667 14.666 36.666 0 51.332-14.667 14.667-36.667 14.667-51.334 0L249.999 301.334 147.333 404c-14.668 14.667-36.666 14.667-51.334 0-14.666-14.666-14.666-36.665 0-51.332L198.666 250 95.999 147.334c-14.666-14.666-14.666-36.667 0-51.334 14.668-14.666 36.665-14.666 51.333 0l102.667 102.668z' fill='%23873a18'/%3E%3C/svg%3E");
}
`
// 用到的库
const LIBS = [
'https://cdn.jsdelivr.net/gh/journey-ad/blog-img@94eb7e2/live2d/lib/pio.css',
'https://cdn.jsdelivr.net/npm/greensock@1.20.2/dist/TweenLite.js',
'https://cubism.live2d.com/sdk-web/cubismcore/live2dcubismcore.min.js',
'https://cdn.jsdelivr.net/npm/pixi.js@5.3.6/dist/pixi.min.js',
'https://cdn.jsdelivr.net/npm/pixi-live2d-display@0.3.1/dist/cubism4.min.js',
'https://cdn.jsdelivr.net/gh/journey-ad/blog-img@94eb7e2/live2d/lib/pio_sdk4.js',
'https://cdn.jsdelivr.net/gh/journey-ad/blog-img@94eb7e2/live2d/lib/pio.js'
]
const reqArr = LIBS.map(src => loadSource(src))
// 创建顺序加载队列
const doTask = reqArr.reduce((prev, next) => prev.then(() => next()), Promise.resolve());
// 队列执行完毕后
doTask.then(() => {
// 移除自带看板娘
const haruna = document.getElementById('my-dear-haruna-vm')
haruna && haruna.remove()
// 初始化pio
_pio_initialize_pixi()
// 添加自定义样式
addStyle(CUSTOM_CSS)
加载圣·嘉然()
console.log("all done.")
});
// 初始化设定
const initConfig = {
mode: "fixed",
hidden: true,
content: {
link: 引流[Math.floor(Math.random() * 引流.length)], // 引流链接
referer: "Hi!", // 存在访问来源时的欢迎文本
welcome: ["Hi!"], // 未开启时间问好时的欢迎文本
skin: ["诶,想看看其他团员吗?", "替换后入场文本"], // 0更换模型提示文案 1更换完毕入场文案
custom: [
// 鼠标移上去提示元素
{ "selector": ".most-viewed-panel .most-viewed-item, .live-up-list .live-detail, .card .user-name, .user .name, .post-content .content-full a, .tag-list .content, .title, h2 a[title]", "type": "link" }
],
},
model: [
// 待加载的模型列表
"https://cdn.jsdelivr.net/gh/journey-ad/blog-img/live2d/Diana/Diana.model3.json",
"https://cdn.jsdelivr.net/gh/journey-ad/blog-img/live2d/Ava/Ava.model3.json",
],
tips: true, // 时间问好
onModelLoad: onModelLoad // 模型加载完成回调
}
let pio_reference // pio实例
function 加载圣·嘉然() {
pio_reference = new Paul_Pio(initConfig)
pio_alignment = "right" // 右下角
const closeBtn = document.querySelector(".pio-container .pio-action .pio-close")
closeBtn.insertAdjacentHTML('beforebegin', '<span class="pio-top"></span>')
const topBtn = document.querySelector(".pio-container .pio-action .pio-top")
// 返回顶部
topBtn.onclick = function () {
window.scrollTo({ top: 0, behavior: 'smooth' });
};
topBtn.onmouseover = function () {
pio_reference.modules.render("想回到页面顶部吗?");
};
// Then apply style
pio_refresh_style()
}
// 模型加载完成回调
function onModelLoad(model) {
const canvas = document.getElementById("pio")
const modelNmae = model.internalModel.settings.name
const coreModel = model.internalModel.coreModel
const motionManager = model.internalModel.motionManager
let touchList = [
{
text: "点击展示文本1",
motion: "Idle"
},
{
text: "点击展示文本2",
motion: "Idle"
}
]
// 播放动作
function playAction(action) {
action.text && pio_reference.modules.render(action.text) // 展示文案
action.motion && pio_reference.model.motion(action.motion) // 播放动作
if (action.from && action.to) {
// 指定部件渐入渐出
Object.keys(action.from).forEach(id => {
const hidePartIndex = coreModel._partIds.indexOf(id)
TweenLite.to(coreModel._partOpacities, 0.6, { [hidePartIndex]: action.from[id] });
// coreModel._partOpacities[hidePartIndex] = action.from[id]
})
motionManager.once("motionFinish", (data) => {
Object.keys(action.to).forEach(id => {
const hidePartIndex = coreModel._partIds.indexOf(id)
TweenLite.to(coreModel._partOpacities, 0.6, { [hidePartIndex]: action.to[id] });
// coreModel._partOpacities[hidePartIndex] = action.to[id]
})
})
}
}
canvas.onclick = function () {
// 除闲置动作外不打断
if (motionManager.state.currentGroup !== "Idle") return
// 随机选择并播放动作
const action = pio_reference.modules.rand(touchList)
playAction(action)
}
if (modelNmae === "Diana") {
// 嘉然小姐
// 入场动作及文案
initConfig.content.skin[1] = ["我是吃货担当 嘉然 Diana~", "嘉心糖们 想然然了没有呀~", "有人在吗?"]
playAction({ motion: "Tap抱阿草-左手" })
// 点击动作及文案,不区分区域
touchList = [
{
text: "嘉心糖屁用没有",
motion: "Tap生气 -领结"
},
{
text: "有人急了,但我不说是谁~",
motion: "Tap= = 左蝴蝶结"
},
{
text: "呜呜...呜呜呜....",
motion: "Tap哭 -眼角"
},
{
text: "想然然了没有呀~",
motion: "Tap害羞-中间刘海"
},
{
text: "阿草好软呀~",
motion: "Tap抱阿草-左手"
},
{
text: "不要再戳啦!好痒!",
motion: "Tap摇头- 身体"
},
{
text: "嗷呜~~~",
motion: "Tap耳朵-发卡"
},
{
text: "zzZ。。。",
motion: "Leave"
},
{
text: "哇!好吃的!",
motion: "Tap右头发"
},
]
} else if (modelNmae === "Ava") {
initConfig.content.skin[1] = ["我是<s>拉胯</s>Gamer担当 向晚 AvA~", "怎么推流辣!", "AAAAAAAAAAvvvvAAA 向晚!"]
playAction({
motion: "Tap左眼",
from: {
"Part15": 1
},
to: {
"Part15": 0
}
})
touchList = [
{
text: "水母 水母~ 只是普通的生物",
motion: "Tap右手"
},
{
text: "可爱的鸽子鸽子~我喜欢你~",
motion: "Tap胸口项链",
from: {
"Part12": 1
},
to: {
"Part12": 0
}
},
{
text: "好...好兄弟之间喜欢很正常啦",
motion: "Tap中间刘海",
from: {
"Part12": 1
},
to: {
"Part12": 0
}
},
{
text: "啊啊啊!怎么推流辣",
motion: "Tap右眼",
from: {
"Part16": 1
},
to: {
"Part16": 0
}
},
{
text: "你怎么老摸我,我的身体是不是可有魅力",
motion: "Tap嘴"
},
{
text: "AAAAAAAAAAvvvvAAA 向晚!",
motion: "Tap左眼",
from: {
"Part15": 1
},
to: {
"Part15": 0
}
}
]
// 钻头比较大,宽度*1.2倍,模型位移也要重新计算
canvas.width = model.width * 1.2
model.x = canvas.width - model.width
// 模型问题,手动隐藏指定部件
const hideParts = [
"Part5", // 晕
"neko", // 喵喵拳
"game", // 左手游戏手柄
"Part15", // 墨镜
"Part21", // 右手小臂
"Part22", // 左手垂下
"Part", // 双手抱拳
"Part16", // 惊讶特效
"Part12" // 小心心
]
const hidePartsIndex = hideParts.map(id => coreModel._partIds.indexOf(id))
hidePartsIndex.forEach(idx => {
coreModel._partOpacities[idx] = 0
})
}
}
// 检测是否处于iframe内嵌环境
function inIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
// 加载js或css,返回函数包裹的promise实例,用于顺序加载队列
function loadSource(src) {
return () => {
return new Promise(function (resolve, reject) {
const TYPE = src.split('.').pop()
let s = null;
let r = false;
if (TYPE === 'js') {
s = document.createElement('script');
s.type = 'text/javascript';
s.src = src;
s.async = true;
} else if (TYPE === 'css') {
s = document.createElement('link');
s.rel = 'stylesheet';
s.type = 'text/css';
s.href = src;
}
s.onerror = function (err) {
reject(err, s);
};
s.onload = s.onreadystatechange = function () {
// console.log(this.readyState); // uncomment this line to see which ready states are called.
if (!r && (!this.readyState || this.readyState == 'complete')) {
r = true;
console.log(src)
resolve();
}
};
const t = document.getElementsByTagName('script')[0];
t.parentElement.insertBefore(s, t);
});
}
}
// 添加css
function addStyle(css) {
if (typeof GM_addStyle != "undefined") {
GM_addStyle(css);
} else if (typeof PRO_addStyle != "undefined") {
PRO_addStyle(css);
} else {
const node = document.createElement("style");
node.type = "text/css";
node.appendChild(document.createTextNode(css));
const heads = document.getElementsByTagName("head");
if (heads.length > 0) {
heads[0].appendChild(node);
} else {
// no head yet, stick it whereever
document.documentElement.appendChild(node);
}
}
}
})();
@journey-ad
Copy link
Author

以上模型作者为木果阿木果

@lorre0322
Copy link

大佬,怎么让然然在移动端也显示捏

@journey-ad
Copy link
Author

大佬,怎么让然然在移动端也显示捏

这个只在网页上有效,不会真有人用移动版网页的哔站吧
如果是想在手机主屏幕上显示,可以参考 发布视频 的评论区
安卓有很多 APP 都支持导入 lpk 的 live2d 模型,iOS 只支持视频类型的动态桌面,可能没有

@qianran0628
Copy link

大佬我才开始学前端怎么在网页上用上啊

@Lancer0322
Copy link

大佬我才开始学前端怎么在网页上用上啊

复制粘贴,样式自己改,那个piojs是添加按钮功能的,我已经在自己博客整上了

@Lancer0322
Copy link

大佬,怎么让然然在移动端也显示捏

这个只在网页上有效,不会真有人用移动版网页的哔站吧
如果是想在手机主屏幕上显示,可以参考 发布视频 的评论区
安卓有很多 APP 都支持导入 lpk 的 live2d 模型,iOS 只支持视频类型的动态桌面,可能没有

我想着放博客呢,最近闲着折腾成了,再弄点功能就舒服了

@qianran0628
Copy link

我也才开始学啊也就学到css,但我想自己做个博客然后在博客上用嘉心糖啊应该怎么做啊

@Lancer0322
Copy link

我也才开始学啊也就学到css,但我想自己做个博客然后在博客上用嘉心糖啊应该怎么做啊

加我,693739563

@qianran0628
Copy link

加我,693739563

qq搜不到啊

@i-mango
Copy link

i-mango commented Jul 21, 2023

谢谢大佬,好可爱。
image
我用到了自己的博客,好好看。https://blog.manggo.cn/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment