diff --git a/packages/linejs/base/e2ee/mod.ts b/packages/linejs/base/e2ee/mod.ts index c0f5426..70c06d7 100644 --- a/packages/linejs/base/e2ee/mod.ts +++ b/packages/linejs/base/e2ee/mod.ts @@ -662,6 +662,7 @@ export class E2EE { ...messageObj.contentMetadata, ...meta, }; + if (messageObj.chunks) messageObj.chunks = undefined as any; } else if ( (messageObj.contentType === "LOCATION" || messageObj.contentType === @@ -671,8 +672,8 @@ export class E2EE { messageObj.location = await this.decryptE2EELocationMessage( messageObj, ); + if (messageObj.chunks) messageObj.chunks = undefined as any; } - if (messageObj.chunks) messageObj.chunks = undefined as any; return messageObj; } diff --git a/packages/linejs/client/features/message/square.ts b/packages/linejs/client/features/message/square.ts index ead6a46..ce90b70 100644 --- a/packages/linejs/client/features/message/square.ts +++ b/packages/linejs/client/features/message/square.ts @@ -13,7 +13,9 @@ import type { StickerMetadata, } from "./internal-types.ts"; import type { DecorationsData, From, MentionTarget, To } from "./types.ts"; +import { InternalError } from "../../../base/core/mod.ts"; +const hasContents = ["IMAGE", "VIDEO", "AUDIO", "FILE"]; export interface SquareMessageInit { client: Client; raw: Message; @@ -28,6 +30,7 @@ export class SquareMessage { readonly isSquare = true; readonly isTalk = false; + #authorIsMe?: boolean; constructor(init: SquareMessageInit) { this.#client = init.client; @@ -97,7 +100,9 @@ export class SquareMessage { */ async unsend() { if (!this.isMyMessage) { - throw new TypeError("Cannot unsend the message which is not yours."); + throw new TypeError( + "Cannot unsend the message which is not yours.", + ); } await this.#client.base.square.unsendMessage({ messageId: this.#raw.message.id, @@ -141,7 +146,8 @@ export class SquareMessage { throw new TypeError("The message is not text message."); } const emojiUrls: string[] = []; - const emojiData = this.#raw.message.contentMetadata as unknown as EmojiMeta; + const emojiData = this.#raw.message + .contentMetadata as unknown as EmojiMeta; const emojiResources = emojiData?.REPLACE?.sticon?.resources ?? []; for (const emoji of emojiResources) { emojiUrls.push( @@ -303,8 +309,42 @@ export class SquareMessage { }; } - get isMyMessage(): boolean { - return this.#client.base.profile?.mid === this.from.id; + /** + * @return {Blob} message data + */ + async getData(preview?: boolean): Promise { + if (!hasContents.includes(this.#raw.message.contentType as string)) { + throw new TypeError( + "message have no contents", + ); + } + if (this.#raw.message.contentMetadata.DOWNLOAD_URL) { + if (preview) { + const r = await this.#client.base + .fetch(this.#raw.message.contentMetadata.PREVIEW_URL); + return await r.blob(); + } else { + const r_1 = await this.#client.base + .fetch(this.#raw.message.contentMetadata.DOWNLOAD_URL); + return await r_1.blob(); + } + } + return this.#client.base.obs.getMessageObsData({ + messageId: this.#raw.message.id, + isPreview: preview, + isSquare: true, + }); + } + + public async isMyMessage(): Promise { + if (typeof this.#authorIsMe === "boolean") { + return this.#authorIsMe; + } + this.#authorIsMe = this.from.id === + (await this.#client.base.square.getSquareChat({ + squareChatMid: this.to.id, + })).squareChatMember.squareMemberMid; + return this.#authorIsMe; } get to(): To { diff --git a/packages/linejs/client/features/message/talk.ts b/packages/linejs/client/features/message/talk.ts index 5bf309d..f48b89f 100644 --- a/packages/linejs/client/features/message/talk.ts +++ b/packages/linejs/client/features/message/talk.ts @@ -14,12 +14,15 @@ import type { StickerMetadata, } from "./internal-types.ts"; import type { DecorationsData, From, MentionTarget, To } from "./types.ts"; +import { InternalError } from "../../../base/core/mod.ts"; export interface TalkMessageInit { client: Client; raw: Message; } +const hasContents = ["IMAGE", "VIDEO", "AUDIO", "FILE"]; + export class TalkMessage { #client: Client; #raw: Message; @@ -107,7 +110,9 @@ export class TalkMessage { */ async unsend() { if (!this.isMyMessage) { - throw new TypeError("Cannot unsend the message which is not yours."); + throw new TypeError( + "Cannot unsend the message which is not yours.", + ); } await this.#client.base.talk.unsendMessage({ messageId: this.#raw.id, @@ -247,7 +252,9 @@ export class TalkMessage { */ getSharedContact(): ContactMeta { if (this.#content.type !== "CONTACT") { - throw new TypeError("The message does not share contact infomation."); + throw new TypeError( + "The message does not share contact infomation.", + ); } const contactData = this.#content.metadata as unknown as ContactMeta; return { mid: contactData.mid, displayName: contactData.displayName }; @@ -313,6 +320,42 @@ export class TalkMessage { }; } + /** + * @return {Blob} message data + */ + async getData(preview?: boolean): Promise { + if (!hasContents.includes(this.#content.type as string)) { + throw new TypeError( + "message have no contents", + ); + } + if (this.#raw.contentMetadata.DOWNLOAD_URL) { + if (preview) { + const r = await this.#client.base + .fetch(this.#raw.contentMetadata.PREVIEW_URL); + return await r.blob(); + } else { + const r = await this.#client.base + .fetch(this.#raw.contentMetadata.DOWNLOAD_URL); + return await r.blob(); + } + } + if (this.#raw.chunks) { + const file = await this.#client.base.obs.downloadMediaByE2EE( + this.#raw, + ); + if (!file) { + throw new InternalError("ObsError", "Download failed"); + } + return file; + } else { + return await this.#client.base.obs.getMessageObsData({ + messageId: this.#raw.id, + isPreview: preview, + isSquare: false, + }); + } + } get isMyMessage(): boolean { return this.#client.base.profile?.mid === this.from.id; } @@ -347,7 +390,10 @@ export class TalkMessage { ): Promise { return this.fromRawTalk(source.event.message, client); } - static async fromRawTalk(raw: Message, client: Client): Promise { + static async fromRawTalk( + raw: Message, + client: Client, + ): Promise { if (raw.contentMetadata.e2eeVersion) { raw = await client.base.e2ee.decryptE2EEMessage(raw); }