feat: support marketface

This commit is contained in:
Il Harper 2024-04-26 16:02:11 +08:00
parent 60fa49ae01
commit 72cdae235e
No known key found for this signature in database
GPG Key ID: 4B71FCA698E7E8EC
9 changed files with 216 additions and 19 deletions

View File

@ -1,31 +1,63 @@
import type { Media } from '@chronocat/red' import type { AssetRequest } from '@chronocat/red'
import { ChatType } from '@chronocat/red' import { ChatType } from '@chronocat/red'
import type { ChronocatContext } from '@chronocat/shell' import type { ChronocatContext } from '@chronocat/shell'
import { downloadRichMedia } from '../../../definitions/msgService' import {
import { richMediaDownloadMap } from '../../../globalVars' downloadRichMedia,
fetchMarketEmoticonAioImage,
} from '../../../definitions/msgService'
import { emojiDownloadMap, richMediaDownloadMap } from '../../../globalVars'
export const buildAssetsGet = export const buildAssetsGet =
(ctx: ChronocatContext) => async (raw: string) => { (ctx: ChronocatContext) => async (raw: string) => {
const data = JSON.parse( const data = JSON.parse(
Buffer.from(raw, 'base64url').toString('utf-8'), Buffer.from(raw, 'base64url').toString('utf-8'),
) as Media ) as AssetRequest
const downloadId = data.msgId + '::' + data.elementId if ('type' in data) {
switch (data.type) {
case 'marketface': {
const downloadId = data.tabId + '::' + data.faceId
const downloadCompletePromise = new Promise<string>((res, rej) => { const downloadCompletePromise = new Promise<string>((res, rej) => {
richMediaDownloadMap[downloadId] = res emojiDownloadMap[downloadId] = res
void ctx.chronocat.sleep(1000).then(rej) void ctx.chronocat.sleep(5000).then(rej)
}) })
if (data.chatType === ChatType.Private && !data.peerUid.startsWith('u_')) await fetchMarketEmoticonAioImage({
data.peerUid = ctx.chronocat.uix.getUid(data.peerUid)! marketEmoticonAioImageReq: {
eId: data.faceId,
epId: data.tabId,
name: data.name,
width: 200,
height: 200,
jobType: 0,
encryptKey: data.key,
filePath: data.filePath,
downloadType: 3,
},
})
await downloadRichMedia({ return await downloadCompletePromise
getReq: { }
...data, }
downloadType: 1, } else {
}, const downloadId = data.msgId + '::' + data.elementId
})
return await downloadCompletePromise const downloadCompletePromise = new Promise<string>((res, rej) => {
richMediaDownloadMap[downloadId] = res
void ctx.chronocat.sleep(1000).then(rej)
})
if (data.chatType === ChatType.Private && !data.peerUid.startsWith('u_'))
data.peerUid = ctx.chronocat.uix.getUid(data.peerUid)!
await downloadRichMedia({
getReq: {
...data,
downloadType: 1,
},
})
return await downloadCompletePromise
}
} }

View File

@ -277,6 +277,19 @@ export class Messager {
return return
} }
case `${this.ctx.chronocat.platform}:marketface`: {
this.children.push(
r.marketFace(
Number(attrs['tabId']),
attrs['faceId'] as string,
attrs['key'] as string,
),
)
this.isEndLine = false
return
}
case 'quote': { case 'quote': {
const [author] = this.ctx.chronocat.h.select(children, 'author') const [author] = this.ctx.chronocat.h.select(children, 'author')

View File

@ -114,6 +114,28 @@ const b = () => {
}, },
}), }),
marketFace: (
tabId: number,
faceId: string,
key: string,
): O.Partial<Element, 'deep'> => ({
elementType: 11,
elementId: '',
marketFaceElement: {
itemType: 6,
faceInfo: 1,
emojiPackageId: tabId,
subType: 3,
mediaType: 0,
imageWidth: 200,
imageHeight: 200,
faceName: '[动画表情]',
emojiId: faceId,
key: key,
emojiType: 1,
},
}),
pcPoke: (pokeType: number): O.Partial<Element, 'deep'> => ({ pcPoke: (pokeType: number): O.Partial<Element, 'deep'> => ({
elementId: '0', elementId: '0',
elementType: 6, elementType: 6,

View File

@ -151,3 +151,22 @@ export const deleteActiveChatByUid = define<Record<string, never>, [string]>(
'ns-ntApi-2', 'ns-ntApi-2',
'nodeIKernelMsgService/deleteActiveChatByUid', 'nodeIKernelMsgService/deleteActiveChatByUid',
) )
export const fetchMarketEmoticonAioImage = define<
never,
[
{
marketEmoticonAioImageReq: {
eId: string // '94c8ffa6977fd17e8b180b312cdddc28'
epId: number // 235125
name: string // '[抱抱]'
width: 200
height: 200
jobType: 0
encryptKey: string // 'ea4dc6c26b6f9c31'
filePath: string
downloadType: 3 | 4
}
},
]
>('ns-ntApi-2', 'nodeIKernelMsgService/fetchMarketEmoticonAioImage')

View File

@ -11,6 +11,7 @@ export const groupMap: Record<string, Group> = {}
export const roleMap: Record<string, Record<string, number>> = {} export const roleMap: Record<string, Record<string, number>> = {}
export const friendMap: Record<string, Profile> = {} export const friendMap: Record<string, Profile> = {}
export const richMediaDownloadMap: Record<string, (path: string) => void> = {} export const richMediaDownloadMap: Record<string, (path: string) => void> = {}
export const emojiDownloadMap: Record<string, (path: string) => void> = {}
export const sendQueue: ((msg: RedMessage) => void)[] = [] export const sendQueue: ((msg: RedMessage) => void)[] = []
export const sendCallbackMap: Record<string, (msg: RedMessage) => void> = {} export const sendCallbackMap: Record<string, (msg: RedMessage) => void> = {}

View File

@ -3,6 +3,7 @@ import type {
MsgsIncludeSelf, MsgsIncludeSelf,
OnAddSendMsg, OnAddSendMsg,
OnBuddyListChange, OnBuddyListChange,
OnEmojiDownloadComplete,
OnGroupListUpdate, OnGroupListUpdate,
OnMemberInfoChange, OnMemberInfoChange,
OnMemberListChange, OnMemberListChange,
@ -20,6 +21,7 @@ import type { ChronocatContext } from '@chronocat/shell'
import type { IpcManData } from 'ipcman' import type { IpcManData } from 'ipcman'
import { import {
chronoEventEmitter, chronoEventEmitter,
emojiDownloadMap,
friendMap, friendMap,
groupMap, groupMap,
requestCallbackMap, requestCallbackMap,
@ -131,6 +133,19 @@ const responseDispatcher = async (
return return
} }
case 'nodeIKernelMsgListener/onEmojiDownloadComplete': {
const { notifyInfo } = payload as OnEmojiDownloadComplete
const downloadId = `${notifyInfo.emojiPackageId}::${notifyInfo.emojiId}`
if (notifyInfo.downloadType === 0 && emojiDownloadMap[downloadId]) {
emojiDownloadMap[downloadId]!(notifyInfo.path)
delete emojiDownloadMap[downloadId]
}
return
}
case 'nodeIKernelProfileListener/onProfileSimpleChanged': case 'nodeIKernelProfileListener/onProfileSimpleChanged':
case 'nodeIKernelProfileListener/onProfileDetailInfoChanged': case 'nodeIKernelProfileListener/onProfileDetailInfoChanged':
case 'nodeIKernelGroupListener/onSearchMemberChange': case 'nodeIKernelGroupListener/onSearchMemberChange':

View File

@ -552,6 +552,34 @@ async function parseElements(
break break
} }
case 11: {
elements.push(
ctx.chronocat.h(
`${ctx.chronocat.platform}:marketface`,
{
tabId: m.marketFaceElement!.emojiPackageId,
faceId: m.marketFaceElement!.emojiId,
key: m.marketFaceElement!.key,
},
[
ctx.chronocat.h('img', {
src: `${config.self_url}/v1/assets/${Buffer.from(
JSON.stringify({
type: 'marketface',
tabId: m.marketFaceElement!.emojiPackageId,
faceId: m.marketFaceElement!.emojiId,
key: m.marketFaceElement!.key,
name: m.marketFaceElement!.faceName,
filePath: m.marketFaceElement!.staticFacePath,
}),
).toString('base64url')}`,
}),
],
),
)
break
}
default: default:
break break
} }

View File

@ -275,7 +275,7 @@ export interface Element {
inlineKeyboardElement?: InlineKeyboardElement inlineKeyboardElement?: InlineKeyboardElement
liveGiftElement?: unknown liveGiftElement?: unknown
markdownElement?: MarkdownElement markdownElement?: MarkdownElement
marketFaceElement?: unknown marketFaceElement?: MarketFaceElement
multiForwardMsgElement?: unknown multiForwardMsgElement?: unknown
pttElement?: PttElement pttElement?: PttElement
replyElement?: ReplyElement replyElement?: ReplyElement
@ -653,6 +653,17 @@ export interface Media {
downloadType: number downloadType: number
} }
export interface MarketFaceAssetRequest {
type: 'marketface'
tabId: number
faceId: string
key: string
name: string
filePath: string
}
export type AssetRequest = MarketFaceAssetRequest | Media
export interface InlineKeyboardElement { export interface InlineKeyboardElement {
rows: InlineKeyboardRow[] rows: InlineKeyboardRow[]
} }
@ -762,6 +773,41 @@ export interface MarkdownElement {
content: string content: string
} }
export interface MarketFaceElement {
itemType: 6
faceInfo: 1
emojiPackageId: number // 235125
subType: 3
mediaType: 0
imageWidth: number // 200
imageHeight: number // 200
faceName: string // '[好耶]'
emojiId: string // 'e6e7817c449efdea0be5ceeef3a40c06'
key: string // 'ea4dc6c26b6f9c31'
param: unknown
mobileParam: unknown
sourceType: 0
startTime: 0
endTime: 0
emojiType: 1
hasIpProduct: 0
voiceItemHeightArr: unknown
sourceName: unknown
sourceJumpUrl: unknown
sourceTypeName: string // ''
backColor: unknown
volumeColor: unknown
staticFacePath: string
dynamicFacePath: string
supportSize: MarketFaceElementSupportSize[]
apngSupportSize: unknown
}
export interface MarketFaceElementSupportSize {
width: number // 300
height: number // 300
}
export interface ArkElement { export interface ArkElement {
bytesData: string bytesData: string
linkInfo: never linkInfo: never

View File

@ -75,6 +75,27 @@ export interface OnRichMediaDownloadComplete {
} }
} }
export interface OnEmojiDownloadComplete {
notifyInfo: {
result: 0
errMsg: string // ''
emojiType: 0
md5: string // ''
resId: string // ''
path: string
extraData: Record<string, never>
emojiId: string // '94c8ffa6977fd17e8b180b312cdddc28'
emojiPackageId: string // '235125'
/**
* 3 PNG4 0 PNG4
*/
downloadType: 0 | 4
dynamicFacePath: string // ''
}
}
export interface OnGroupListUpdate { export interface OnGroupListUpdate {
updateType: 1 updateType: 1
groupList: Group[] groupList: Group[]