Album (Moa)
MoaService exposes the LINE Album (Moa) REST API on client.base.moa. Unlike Talk / Square, Moa speaks JSON over HTTPS through the LEGY proxy, so this service uses client.base.fetch directly with a channel token issued for the album channel (1375220249).
Listing albums
ts
import { loginWithAuthToken } from "@evex/linejs";
const client = await loginWithAuthToken("YOUR_AUTH_TOKEN", {
device: "IOSIPAD",
});
let cursor = "";
while (true) {
const resp = await client.base.moa.getAlbums({ cursor });
const result = resp.result;
for (const album of result?.albums ?? []) {
console.log(`[${album.albumId}] ${album.title} (${album.photoCount} photos)`);
}
const next = result?.nextCursor ?? result?.cursor ?? "";
if (!next || next === cursor || !(result?.hasMore ?? true)) break;
cursor = next;
}Listing photos in an album
ts
let cursor = "";
while (true) {
const resp = await client.base.moa.getPhotos({
chatId: "cxxxxxxxxxxxxxxx",
albumId: "1234567890123456789",
cursor,
pageSize: 100,
});
for (const photo of resp.result?.photos ?? []) {
console.log(photo.oid, "shot at", photo.shotTime);
}
const next = resp.result?.nextCursor ?? "";
if (!next || next === cursor) break;
cursor = next;
}Downloading the original bytes of a photo
downloadPhoto returns a Uint8Array so the caller can save it or process it further.
ts
import { writeFileSync } from "node:fs";
const bytes = await client.base.moa.downloadPhoto({
chatId: "cxxxxxxxxxxxxxxx",
albumId: "1234567890123456789",
oid: "someOid",
});
writeFileSync("./out.jpg", bytes);For videos, pass prefix: "album/v" (the sid field on obsResourceId tells you whether the item is an image or a video):
ts
const isVideo = photo.obsResourceId?.sid === "v";
const bytes = await client.base.moa.downloadPhoto({
chatId,
albumId,
oid: photo.obsResourceId!.oid!,
prefix: isVideo ? "album/v" : "album/a",
});Notes
- The channel token issued for
1375220249is memoised inside the service and reused within the same session. Changing the access token, MID or endpoint invalidates it. If the token is rejected (expiry or revocation), callclient.base.moa.clearAlbumChannelToken()before an explicit retry. Requests are not automatically retried. REST requests and downloads useclient.base.config.timeout. - Moa uses
X-Line-ChannelToken,X-Line-Mid(your MID) and — for photo fetches —X-Line-Album(the album id) andX-Line-Midset to the chat id. All of these are set for you automatically. - The header override
accept: application/jsonis important: the defaultclient.base.request.getHeader("GET")returnsapplication/x-thrift, which LEGY rejects for REST endpoints with{"code":102001,"message":"一時的なエラーが発生しました。"}.