别着急,坐和放宽
云函数是 Mix Space 中的一个重要功能,它极大地辅助了使用者在 Mix Space 中的体验。通过云函数,Mix Space 可以额外实现实现歌单解析,追番列表等等的功能。
建议食用官方文档 https://mx-space.js.org/usage 本篇仅作参考
具体配置需要一个一个修改,最多免去了创建过程。
这个是我当前配置 ,仅供参考,根据需要更改
Mix-Space 后台,进入「配置与云函数」页面,点击右上角的新增按钮,在编辑页面中,填入以下设置:
数据类型:JSON
需要在主题配置中配置我的动态
模块
这个地方还需要设置一个密钥,在 Secret 中填入 key,在 Value 中填入你自己的密钥。
export default async function handler(ctx: Context) {
const {
timestamp,
process: processName,
key,
media,
meta,
} = ctx.req.body || {}
// handle GET
{
const [processInfo, mediaInfo] = await Promise.all([
ctx.storage.cache.get('ps') as any as Promise<Process | undefined>,
ctx.storage.cache.get('media') as any as Promise<Media | undefined>,
])
if (!key) {
return {
processName: processInfo?.name,
processInfo,
mediaInfo,
}
}
}
const ts = +new Date()
// if (Math.abs(ts - timestamp) > 1000 * 10) {
// ctx.throws(400, 'this request is outdate')
// return
// }
const processInfo: Process = {
name: processName,
...meta,
}
const validKey = (await ctx.secret.key) || 'testing'
if (key != validKey)
ctx.throws(401, "You haven't permission to update process info")
const originalPsInfo: Process | null = (await ctx.storage.cache.get(
'ps',
)) as any
await ctx.storage.cache.set('ps', processInfo, 300)
if (originalPsInfo?.name !== processName)
ctx?.broadcast?.('ps-update', {
processInfo,
process: processInfo.name,
ts,
})
if (media) {
await ctx.storage.cache.set('media', media, 10)
}
const mediaInfo: Media | undefined = (await ctx.storage.cache.get(
'media',
)) as any
if (mediaInfo?.title !== media?.title)
ctx?.broadcast?.('media-update', media || null)
return {
ok: 1,
mediaInfo,
process: processInfo.name,
processInfo,
timestamp: +new Date(),
}
}
interface Media {
title: string
artist: string
}
interface Process {
name: string
iconBase64?: string
iconUrl?: string
description?: string
}
另外需要下载对应平台的状态上报软件
参考官方文档:
https://mx-space.js.org/themes/shiro/extra#配置软件
这个地方还需要设置一个密钥,在 Secret 中填入 key,在 Value 中填入你自己的密钥。
设置状态,前端首页->双击左上角头像->登录,点击左上角头像的右下方设置状态。
"
为 \ "
,否则会报错。{
# 站点底部相关信息
"footer": {
"otherInfo": {
"date": "2022-{{now}}",
"icp": {
"text": "豫 ICP 备 2022029096号-2",
"link": "https://beian.miit.gov.cn"
}
},
"linkSections": [
{
"name": "😊关于",
"links": [
{
"name": "关于我",
"href": "/about"
},
{
"name": "关于此项目",
"href": "https://github.com/innei/Shiro",
"external": true
}
]
},
{
"name": "🧐更多",
"links": [
{
"name": "时间线",
"href": "/timeline"
},
{
"name": "友链",
"href": "/friends"
},
{
"name": "思考",
"href": "/thinking",
"external": true
}
]
},
{
"name": "🤗联系",
"links": [
{
"name": "写留言",
"href": "/message"
},
{
"name": "发邮件",
"href": "mailto:i@vlo.cc",
"external": true
},
{
"name": "GitHub",
"href": "https://github.com/jiuyue52",
"external": true
}
]
}
]
},
"config": {
"color": {
"light": [
"#33A6B8",
"#FF6666",
"#26A69A",
"#fb7287",
"#69a6cc",
"#F11A7B",
"#78C1F3",
"#FF6666",
"#7ACDF6"
],
"dark": [
"#F596AA",
"#A0A7D4",
"#ff7b7b",
"#99D8CF",
"#838BC6",
"#FFE5AD",
"#9BE8D8",
"#A1CCD1",
"#EAAEBA"
]
},
"custom": {
"css": [],
"styles": [],
"js": [],
"scripts": []
},
# 站点图标
"site": {
"favicon": "https://mio.vlo.cc/resource/image/J99Y.svg",
"faviconDark": "https://mio.vlo.cc/resource/image/J99Y.svg"
},
"hero": {
"title": {
"template": [
{
"type": "h1",
"text": "Hi, I'm ",
"class": "font-light text-4xl"
},
{
"type": "h1",
"text": "JiuYue",
"class": "font-medium mx-2 text-4xl"
},
{
"type": "h1",
"text": "👋。",
"class": "font-light text-4xl"
},
{
"type": "br"
},
{
"type": "h1",
"text": "语言是思想的直接的现实",
"class": "font-light text-4xl"
},
{
"type": "code",
"text": "<Developer />",
"class": "font-medium mx-2 text-3xl rounded p-1 bg-gray-200 dark:bg-gray-800/0 hover:dark:bg-gray-800/100 bg-opacity-0 hover:bg-opacity-100 transition-background duration-200"
},
{
"type": "span",
"class": "inline-block w-[1px] h-8 -bottom-2 relative bg-gray-800/80 dark:bg-gray-200/80 opacity-0 group-hover:opacity-100 transition-opacity duration-200 group-hover:animation-blink"
}
]
},
# hitokoto闭源专属,首页随机一言
"hitokoto": {
"random": true
},
"description": "内心湛然,则无往而不乐。"
},
"module": {
# 我的动态
"activity": {
"enable": true,
"endpoint": "/fn/ps/update"
},
# 打赏地址及收款二维码
"donate": {
"enable": true,
"link": "https://afdian.net/@huasui",
"qrcode": [
"https://mio.vlo.cc/image/2408/66b853da25ce7.webp",
"https://mio.vlo.cc/image/2408/66b853da25ce7.webp"
]
},
# b站直播间房间号,获取直播状态
"bilibili": {
"liveId": 23359061
},
# svg签名动画,shiroi闭源版专属
"signature": {
"svg": ""
}
}
}
}
interface Status {
emoji: string
icon?: string
desc?: string
ttl: number
untilAt: number
}
function assetAuth(ctx: Context) {
const body = ctx.req.body
const authKey = ctx.secret.key
if (ctx.isAuthenticated) return
if (body.key !== authKey) {
ctx.throws(401, 'Unauthorized')
}
}
export default async function handler(ctx: Context) {
const method = ctx.req.method.toLowerCase()
switch (method) {
case 'get': {
return GET(ctx)
}
case 'post': {
assetAuth(ctx)
return POST(ctx)
}
case 'delete': {
assetAuth(ctx)
return DELETE(ctx)
}
default: {
ctx.throws(405, 'Method Not Allowed')
}
}
}
const cacheKey = 'shiro:status'
function DELETE(ctx: Context) {
ctx.storage.cache.del(cacheKey)
ctx.broadcast('shiro#status', null)
}
function POST(ctx: Context) {
const body = ctx.req.body
const { emoji, icon, desc } = body as Status
const ttl = body.ttl || 86400 // 1 day
const status = {
emoji,
icon,
desc,
ttl,
untilAt: Date.now() + ttl * 1000,
} as Status
ctx.storage.cache.set(cacheKey, JSON.stringify(status), ttl)
ctx.status(204)
ctx.broadcast('shiro#status', status)
}
function GET(ctx: Context) {
const status = ctx.storage.cache.get(cacheKey)
ctx.res.type('application/json')
return status
}