Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/linejs/base/obs/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export class LineObs {
data: Blob,
oid?: string,
filename?: string,
durationMs?: number,
): Promise<{
objId: string;
objHash: string;
Expand Down Expand Up @@ -195,7 +196,10 @@ export class LineObs {
param.cat = "original";
param.type = "image";
} else if (type === "audio" || type === "video") {
param.duration = "1919"; // 810
// LINE uses this obs param verbatim as the displayed length (it does not
// recompute it from the uploaded file), so a caller-supplied real duration
// must be honoured; keep the historical value as the fallback.
param.duration = (durationMs ?? 1919).toString();
}
const toType: "talk" | "g2" = to[0] === "m" || to[0] === "t"
? "g2"
Expand Down
56 changes: 56 additions & 0 deletions packages/linejs/client/features/square/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
import type * as LINETypes from "@evex/linejs-types";
import type { Client } from "../../mod.ts";
import { continueRequest } from "../../../base/mod.ts";
import type { ObjType } from "../../../base/obs/mod.ts";
import { SquareMessage } from "../message/mod.ts";
import { TypedEventEmitter } from "../../../base/core/typed-event-emitter/index.ts";

Expand Down Expand Up @@ -109,6 +110,61 @@ export class SquareChat extends TypedEventEmitter<SquareChatEvents> {
});
}

/**
* Sends an image to this OpenChat.
*
* OpenChat rejects the "reserve an empty IMAGE/AUDIO/VIDEO message via
* `sendMessage`, then attach the obs object to its id" pattern with
* ILLEGAL_ARGUMENT. Uploading the obs object with no `oid` ("reqseq" mode)
* instead makes the server create the message itself. A consequence is that
* such a message can't carry a `relatedMessageId`, so media sent this way is
* never threaded as a reply.
*/
async sendImage(
data: Blob,
filename = "image",
): Promise<{ objId: string; objHash: string }> {
return await this.#sendMedia("image", data, filename);
}

/** Sends a video to this OpenChat. See {@link sendImage} for the caveats. */
async sendVideo(
data: Blob,
filename = "video",
durationMs?: number,
): Promise<{ objId: string; objHash: string }> {
return await this.#sendMedia("video", data, filename, durationMs);
}

/**
* Sends a voice/audio message to this OpenChat.
* See {@link sendImage} for the caveats.
*/
async sendAudio(
data: Blob,
filename = "voice.m4a",
durationMs?: number,
): Promise<{ objId: string; objHash: string }> {
return await this.#sendMedia("audio", data, filename, durationMs);
}

async #sendMedia(
type: ObjType,
data: Blob,
filename: string,
durationMs?: number,
): Promise<{ objId: string; objHash: string }> {
const { objId, objHash } = await this.#client.base.obs.uploadObjTalk(
this.raw.squareChatMid,
type,
data,
undefined, // oid unset => reqseq mode => the server creates the message
filename,
durationMs,
);
return { objId, objHash };
}

async updateSquareChat(
input: {
updatedAttrs: LINETypes.SquareChatAttribute[];
Expand Down
Loading