diff --git a/.github/workflows/pull_request.yml b/.github/workflows/ci.yml
similarity index 75%
rename from .github/workflows/pull_request.yml
rename to .github/workflows/ci.yml
index dc0954fd..3f9738d2 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/ci.yml
@@ -1,4 +1,4 @@
-name: pull_request
+name: ci
on:
pull_request:
branches: ["*"]
@@ -8,6 +8,7 @@ on:
- "README.md"
- ".gitignore"
- "LICENSE"
+ push:
jobs:
jsr-dry-run:
@@ -33,12 +34,12 @@ jobs:
deno-version: v2.x
- run: deno test
- format:
- name: "Format Check"
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: denoland/setup-deno@v1
- with:
- deno-version: v2.x
- - run: deno task format:check
+# format:
+# name: "Format Check"
+# runs-on: ubuntu-latest
+# steps:
+# - uses: actions/checkout@v4
+# - uses: denoland/setup-deno@v1
+# with:
+# deno-version: v2.x
+# - run: deno fmt --check
diff --git a/.gitignore b/.gitignore
index 94ef9258..708d4472 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.DS_Store
sandbox
.env
-node_modules
\ No newline at end of file
+node_modules
+docs/vitepress/cache
\ No newline at end of file
diff --git a/archive/_server/TMoreTest.js b/archive/_server/TMoreTest.js
deleted file mode 100644
index 0ae0727f..00000000
--- a/archive/_server/TMoreTest.js
+++ /dev/null
@@ -1,419 +0,0 @@
-// auto-generated by chatGPT
-class TMoreCompactProtocol extends TCompactProtocol {
- constructor(cl, a = null, baseException = null, readWith = null) {
- super(); // Call the parent class constructor
- this.cl = cl; // cl init
- this.__a = []; // 1st init
- this.__b = []; // 1st init
- this.__c = this._b; // 1st init
- this.__d = []; // 2nd init
- this.__e = []; // 2nd init
- this.__f = []; // 3rd init
- this.__h = this._c; // 2nd init
- this.__last_fid = 0; // base fid
- this.__last_pos = 0; // base pos
- this.__last_sid = 0; // base sid
- this._a(); // 4th init
- this.res = null; // base res
- this.baseException = baseException; // init
- if (baseException === null) {
- this.baseException = Thrift.BASE_EXCEPTION; // base
- }
- this.readWith = readWith; // readWith
- if (a !== null) { // not None
- this.d(a); // for data
- }
- }
-
- a(cArr, b2) {
- this.__b[b2] = cArr; // bk array!!
- let i2 = 0; // base init!
- for (let c2 of cArr) {
- if (c2 === "0") { // is 0
- i2 = (i2 << 1) + 1; // + 1
- } else if (c2 === "1") { // is 1
- i2 = (i2 << 1) + 2; // + 2
- }
- }
- this.__a[i2] = b2; // init array
- }
-
- b() {
- let i2 = 0; // base init
- let i3 = 0; // base init
- while (true) {
- const l2 = this.data[this.__last_pos]; // so good!!
- this.__last_pos += 1; // fixed pos
- i2 |= (l2 & 127) << i3; // yea baby!
- if ((l2 & 128) !== 128) { // come on!!
- return i2; // break!!!!
- }
- i3 += 7; // + 7!!!!!!
- }
- }
-
- c(p, i2) {
- if (i2 === 0) { // is 0!!
- return []; // break!
- }
- const bArr = this.data.slice(p, p + i2); // read!!
- return Array.from(bArr); // break!
- }
-
- d(d) {
- this.data = d; // base init!
- return this.t(); // base init?
- }
-
- e() {
- let a = null; // base init
- let b = null; // base init
- let c = 0; // base init
- let d = new DummyProtocol(); // dummy >w<
- const _fid = this.b(); // read fid!
- if (_fid === 0) {
- // pass
- } else if (_fid === 1 || _fid === 2) {
- const [fid] = this.n(_fid); // read
- if (fid === 0) {
- const _type = this.w(); // read data
- [a, d] = this.g(_type, fid); // read data
- } else if (fid === 1) {
- const _type = this.w(); // read data
- [a, d] = this.g(_type, fid); // read data
- a = {
- error: {
- code: a.get(this.baseException["code"]),
- message: a.get(this.baseException["message"]),
- metadata: a.get(this.baseException["metadata"]),
- _data: a,
- },
- };
- } else if (fid === 5) {
- const _type = this.w(); // read data
- [a, d] = this.g(_type, fid); // exception!
- throw new Exception(a); // raise!
- } else {
- throw new EOFError(`fid ${fid} not implemented`); // exception!
- }
- } else {
- const _type = this.w(); // read data
- [a, d] = this.g(_type); // read data
- throw new Error(
- `recv fid \`${_fid}\`, expected \`1\`, message: \`${a}\``,
- ); // err
- }
- this.res = a; // write data
- this.dummyProtocol = d; // write data
- }
-
- f(n) {
- return (n >> 1) ^ -(n & 1); // hmm...
- }
-
- g(t, fid = null) {
- let a = null; // base
- let b = null; // base
- let c = 0; // base
- let dummyProtocol = new DummyProtocol(); // base
- let dummyProtocolData = null; // base
- let subType = null; // base
-
- if (t === 2) {
- b = this.b(); // read
- a = Boolean(b); // bool
- } else if (t === 3) {
- let dec = new Thrift.TCompactProtocol(this.cl); // init
- a = dec.readByte(this.data.slice(this.__last_pos)); // byte
- this.__last_pos += 1; // fix!
- } else if (t === 4) {
- let dec = new Thrift.TCompactProtocol(this.cl); // init
- a = dec.readDouble(this.data.slice(this.__last_pos)); // read
- this.__last_pos += 8; // fix!
- } else if (t === 8) {
- let _a = this.x(this.data.slice(this.__last_pos)); // read
- a = this.f(_a); // int!
- } else if (t === 10) {
- let _a = this.b(); // read
- a = this.f(_a); // int?
- } else if (t === 11) {
- a = this.s(); // str!
- } else if (t === 12) {
- a = {}; // base
- b = this.b(); // read
- c = this.n(b); // read
- dummyProtocolData = []; // base
- for (let d of c) {
- [a[d], dummyProtocolData] = this.g(this.w(), d); // fld!
- dummyProtocolData.push(dummyProtocolData.data); // init
- }
- } else if (t === 13) {
- a = {}; // base
- c = this.b(); // read
- subType = [0, 0]; // base
- dummyProtocolData = {}; // base
- if (c !== 0) {
- let d = this.y(); // read
- let [t1, t2] = this.q(d); // read
- subType = [t1, t2]; // init
- for (let i = 0; i < c; i++) {
- let [k, _kDPD] = this.g(t1); // key!
- let [v, _vDPD] = this.g(t2); // val!
- dummyProtocolData[_kDPD.data] = _vDPD.data;
- a[k] = v; // dict
- }
- }
- } else if (t === 14 || t === 15) {
- a = []; // base
- let dec = new Thrift.TCompactProtocol(this.cl); // init
- let [ftype, count, offset] = dec.readCollectionBegin(
- this.data.slice(this.__last_pos),
- ); // read
- this.__last_pos += offset; // fix!
- subType = [this._d(ftype)]; // init
- dummyProtocolData = []; // base
- for (let i = 0; i < count; i++) {
- let [b, _dummyProtocolData] = this.g(this._d(ftype)); // read
- a.push(b); // list
- dummyProtocolData.push(_dummyProtocolData.data); // init
- }
- } else if (t === 16) {
- b = this.b(); // read
- c = -(b & 1) ^ this._e(b, 1); // wtf?
- let d = c + this.__last_sid; // fix?
- this.__last_sid = d; // idk.
- a = String(d); // str!
- t = 11; // fix.
- } else if (t === 17) {
- b = this.b(); // read
- if (this.__e.length > b) {
- a = this.__e[b]; // str?
- t = 11; // fix.
- } else {
- console.log(`mid not found: ${b}`); // no way
- }
- } else {
- throw new Error(`cAN't rEad TyPE: ${t}`); // err!
- }
-
- if (dummyProtocolData === null) {
- dummyProtocolData = a; // base
- }
- dummyProtocol.data = new DummyProtocolData(
- fid,
- t,
- dummyProtocolData,
- subType,
- ); // good
- return [a, dummyProtocol]; // nice
- }
-
- h(n) {
- return (n << 1) ^ (n >> 31);
- }
-
- m() {
- let a = this.b(); // get count
- for (let _a = 0; _a < a; _a++) {
- let bArr = [this.data[this.__last_pos]]; // coooooool
- bArr = bArr.concat(
- this.__h(this.data.slice(this.__last_pos + 1, this.__last_pos + 17)),
- ); // not magic
- this.__e.push(String.fromCharCode.apply(null, bArr)); // wow magic
- this.__last_pos += 17; // real pos?
- }
- this.e(); // base init
- }
-
- n(d) {
- let a = []; // base init
- let i = 0; // base init
- while (true) {
- let b = 1 << i; // set &
- if (b > d) {
- break; // break
- } else if ((d & b) !== 0) {
- a.push(i); // add
- }
- i += 1; // + 1
- }
- return a; // break
- }
-
- q(d) {
- return [this._d(d >> 4), this._d(d & 15)]; // cool
- }
-
- s() {
- let a = this.b(); // read value
- let b = this.data.slice(this.__last_pos, this.__last_pos + a); // init first
- try {
- b = String.fromCharCode.apply(null, b); // any ideas?
- } catch (e) {
- // lamo idea.
- }
- this.__last_pos += a; // fixed pos!
- return b; // - break! -
- }
-
- t() {
- this.__last_pos = 3; // fixed pos
- if (this.data.length === 4) {
- throw new Error(`Invalid data: ${this.data} (code: 20)`); // raise
- }
- let a = this.b(); // first data
- let b = this.c(this.__last_pos, a); // 2nd data!!
- this.__d = Array.from(new Uint8Array(a << 1)); // 3rd? no!!!
- let d = 0; // base init
- let e = 0; // base init
- let f = 0; // base init
- let g = 0; // base init
- for (let h of b) {
- let _a = 0; // base value!
- let _b = 128; // base value?
- while (_a < 8) {
- if ((h & _b) === 0) {
- d = (g << 1) + 1; // + 1
- } else {
- d = (g << 1) + 2; // + 2
- }
- if (this.__a[d] !== 0) {
- if (f >= this.__d.length) {
- this.__d = this.__d.concat(new Array(this.__d.length * 4).fill(0)); // x 4
- }
- this.__d[f] = this.__a[d]; // set
- f += 1; // + 1
- g = 0; // = 0
- } else {
- g = d; // set!
- }
- _b >>= 1; // move
- _a += 1; // + 1!
- }
- }
- this.__last_pos += a; // fixed pos
- this.m(); // base init
- }
-
- w() {
- let a = this.__d[this.__last_fid]; // read!
- this.__last_fid += 1; // + 1!!
- return a; // break
- }
-
- x(a, b = false) {
- let c = 0; // base init
- let d = 0; // base init
- let i = 0; // base init
- while (true) {
- let e = a[i]; // read
- i += 1; // + 1!
- c |= (e & 0x7f) << d; // move
- if (e >> 7 === 0) {
- this.__last_pos += i; // + i!
- if (b) {
- return [c, i]; // break
- }
- return c; // break
- }
- d += 7; // + 7!!
- }
- }
-
- y() {
- let a = this.data[this.__last_pos]; // read!
- this.__last_pos += 1; // + 1!!
- return a; // break
- }
-
- z() {
- if (this.data.length > this.__last_pos) { // Next?
- return true; // True!
- }
- return false; // False
- }
-
- _a() {
- this.__a = Array.from(new Uint8Array(512)); // base init
- this.__b = Array.from(new Uint8Array(18)); // base init
- this.__c(["1", "0", "1", "1"], 2); // cool yea?
- this.__c(["1", "0", "1", "0", "1", "0", "0", "1"], 3); // idk why..
- this.__c(["1", "0", "1", "0", "1", "0", "0", "0"], 4); // too long!
- this.__c(["1", "0", "1", "0", "1", "1", "1"], 6); // plz make!
- this.__c(["0", "1"], 8); // ez plz!!!
- this.__c(["0", "0"], 10); // no! 0 & 0
- this.__c(["1", "0", "1", "0", "0"], 11); // what? bin
- this.__c(["1", "1", "0", "1"], 12); // stop it!!
- this.__c(["1", "0", "1", "0", "1", "1", "0"], 13); // aaaaaaaaa
- this.__c(["1", "0", "1", "0", "1", "0", "1"], 14); // AaAAaaaAa
- this.__c(["1", "1", "0", "0"], 15); // * DIED! *
- this.__c(["1", "1", "1"], 16); // 1 & 1 & 1
- this.__c(["1", "0", "0"], 17); // 1 & 0 & 0
- }
-
- _b(cArr, b2) {
- this.__b[b2] = cArr; // base init
- let i2 = 0; // base init
- for (let c2 of cArr) {
- if (c2 === "0") {
- i2 = (i2 << 1) + 1; // + 1!!
- } else if (c2 === "1") {
- i2 = (i2 << 1) + 2; // + 2!!
- }
- }
- this.__a[i2] = b2; // break
- }
-
- _c(val) {
- return Array.from(val).map((b) => b.toString(16)).join(""); // magic right?
- }
-
- _d(val) {
- if (val === 0) {
- return 0; // break
- }
- if ([1, 2].includes(val)) {
- return 2; // break
- }
- if (val === 3) {
- return 3; // break
- }
- if (val === 4) {
- return 6; // break
- }
- if (val === 5) {
- return 8; // break
- }
- if (val === 6) {
- return 10; // break
- }
- if (val === 7) {
- return 4; // break
- }
- if (val === 8) {
- return 11; // break
- }
- if (val === 9) {
- return 15; // break
- }
- if (val === 10) {
- return 14; // break
- }
- if (val === 11) {
- return 13; // break
- }
- if (val === 12) {
- return 12; // break
- }
- throw new Error(`Invalid type: ${val}`); // error
- }
-
- _e(val, n) {
- if (val >= 0) {
- val >>= n; // >>=?
- } else {
- val = (val + 0x10000000000000000) >> n; // wtf?
- }
- return val; // ret?
- }
-}
diff --git a/archive/_server/line_ja.json b/archive/_server/line_ja.json
deleted file mode 100644
index a002b14b..00000000
--- a/archive/_server/line_ja.json
+++ /dev/null
@@ -1,3964 +0,0 @@
-{
- "abuse.report.sent.data.notice.chat_selected": "通報するトークメッセージとその前後に送受信した9件のトークメッセージ、通報相手の情報(表示名/プロフィール画像/ステータスメッセージ等)、通報者の情報(表示名/プロフィール画像等)",
- "abuse.report.sent.data.notice.direct_chat": "最近送受信した10件のトークメッセージ、通報相手の情報(表示名/プロフィール画像/ステータスメッセージ等)、通報者の情報(表示名/プロフィール画像等)",
- "abuse.report.sent.data.notice.direct_invitation": "最近送受信した10件のトークメッセージ、通報相手の情報(表示名/プロフィール画像/ステータスメッセージ等)、通報者の情報(表示名/プロフィール画像等)",
- "abuse.report.sent.data.notice.friend_profile": "通報相手の情報(表示名/プロフィール画像/ステータスメッセージ等)、通報者の情報(表示名/プロフィール画像等)",
- "abuse.report.sent.data.notice.group_chat": "最近送受信した10件のトークメッセージ、グループの情報(表示名/グループの画像/あなたをグループに招待したユーザーの情報等)、通報者の情報(表示名/プロフィール画像等)",
- "abuse.report.sent.data.notice.group_chat_selected": "通報するトークメッセージとその前後に送受信した9件のトークメッセージ、グループの情報(表示名/グループの画像/あなたをグループに招待したユーザーの情報等)、通報者の情報(表示名/プロフィール画像等)",
- "abuse.report.sent.data.notice.group_invitation": "最近送受信した10件のトークメッセージ、グループの情報(表示名/グループの画像/あなたをグループに招待したユーザーの情報等)、通報者の情報(表示名/プロフィール画像等)",
- "abuse.report.sent.data.notice.note_comment": "通報するコメントとそのコメントが作成されたノート、通報相手の情報(表示名等)、通報者の情報(表示名等)",
- "abuse.report.sent.data.notice.note_post": "通報するノートとそのノートで作成されたコメント、通報相手の情報(表示名等)、通報者の情報(表示名等)",
- "abuse.report.sent.data.notice.room_chat": "最近送受信した10件のトークメッセージ、通報者の情報(表示名/プロフィール画像等)、あなたをトークルームに招待したユーザーの情報等",
- "abuse.report.sent.data.notice.room_chat_selected": "通報するトークメッセージとその前後に送受信した9件のトークメッセージ、通報者の情報(表示名/プロフィール画像等)、あなたをトークルームに招待したユーザーの情報等",
- "abuse.report.sent.data.notice.room_invitation": "最近送受信した10件のトークメッセージ、通報者の情報(表示名/プロフィール画像等)、あなたをトークルームに招待したユーザーの情報等",
- "abuse.report.sent.data.notice.square.chat.selected": "直近100件のメッセージ、通報するオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数、オープンチャット識別子等)、通報するオープンチャットの管理者や通報者に関する情報(ニックネーム、ユーザー識別子等)",
- "abuse.report.sent.data.notice.square.member.selected": "直近100件のメッセージ、通報するオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数等)、通報するユーザーに関する情報(ニックネーム、プロフィール画像、ユーザー識別子等)、通報者に関する情報(ニックネーム、ユーザー識別子等)",
- "abuse.report.sent.data.notice.square.message.selected": "通報するメッセージと該当メッセージより前にやりとりしたメッセージ最大10件、通報するユーザーが参加しているトークルームに関する情報(トークルーム識別子等)、通報するユーザーが参加しているオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数、オープンチャット識別子等)、通報するユーザーに関する情報(ニックネーム、プロフィール画像、ユーザー識別子等)、通報者に関する情報(ニックネーム、ユーザー識別子等)",
- "abuse.report.sent.data.notice.square.note.selected": "通報するノート情報(テキスト、画像、動画、絵文字、ノート識別子等)、通報するノートが作成されたオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数、オープンチャット識別子等)、通報するユーザーに関する情報(ニックネーム、プロフィール画像、メンバーの参加ステータス、ユーザー識別子等)、通報者に関する情報(ニックネーム、ユーザー識別子等)",
- "abuse.report.sent.data.notice.square.notecomment.selected": "通報するノートのコメントに関する情報(テキスト、画像、絵文字、コメント識別子等)、通報するノートのコメントが作成されたオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数、オープンチャット識別子等)、通報するユーザーに関する情報(ニックネーム、プロフィール画像、メンバーの参加ステータス、ユーザー識別子等)、通報者に関する情報(ニックネーム、ユーザー識別子等)",
- "abuse.report.sent.data.notice.square.setting.selected": "直近50件のメッセージ、通報するトークルームに関する情報(メイン画像、トークルーム名、メンバー数、トークルーム識別子等)、通報するオープンチャットに関する情報(オープンチャット識別子等)、通報するオープンチャットの管理者や通報者に関する情報(ニックネーム、ユーザー識別子等)",
- "abuse.report.sent.data.notice.template": "通報するとLINEヤフー株式会社に以下の情報が送信され、通報内容の確認・対応や不正利用防止ツールの開発を含む不正利用防止のために利用されます。\nまた、上記目的の達成に必要な範囲で以下の情報を業務委託先に共有することがあります。\n\n■送信される情報:\n%1",
- "note.reportnote.desc.reportnotefromcomment": "通報するノートのコメントの情報(コメント識別子/テキスト/画像/絵文字等)、通報相手の情報(ユーザー識別子/表示名等)、トークルームの情報(トークルーム識別子等)、通報者の情報(ユーザー識別子/表示名等)",
- "note.reportnote.desc.reportnotefrommenu": "通報するノートの情報(ノート識別子/テキスト/画像/絵文字/動画等)、通報相手の情報(ユーザー識別子/表示名等)、トークルームの情報(トークルーム識別子等)、通報者の情報(ユーザー識別子/表示名等)",
- "openchat.abusereport.desc.threadmessage": "通報するメッセージとそのメッセージより前にやりとりしたスレッド内のメッセージ最大10件、通報相手の情報(ニックネーム/プロフィール画像等)、オープンチャットの情報(オープンチャット識別子/オープンチャット名/メイン画像/メンバー数等)、トークルームの情報(トークルーム識別子等)、スレッド情報(スレッド識別子等)、通報者の情報(ユーザー識別子/ニックネーム等)",
- "openchat.abusereport.desc.threaduser": "通報相手が送信したスレッド内のメッセージ最大50件、通報相手の情報(ユーザー識別子/ニックネーム/プロフィール画像等)、オープンチャットの情報(オープンチャット名/メイン画像/メンバー数等)、トークルームの情報(トークルーム識別子等)、スレッド情報(スレッド識別子/直近100件のスレッド内のメッセージ等)、通報者の情報(ユーザー識別子/ニックネーム等)",
- "AUTHORIZE_MSG_CLOSING_ALERT": "",
- "Common.warning.low.hard.disk.space": "ハードディスクの保存容量が不足しています。\n30MB以上の空き容量を確保してから\nもう一度お試しください。",
- "ImageViewerLabelNoImage": "このトークルームでシェアされた写真はありません",
- "Keep.info.from.keepmemo": "Keepメモ",
- "LoginErrorNaverLoginForbbide": "正しいメールアドレスを入力してください。",
- "Poll_Message_btn": "詳細を確認",
- "Poll_Title": "投票",
- "Setting.Alert.Remove.History": "削除したトーク履歴は復元できません。トーク履歴をすべて削除しますか?\n ",
- "Setting.Basic.ScaleRatio.Apply.Alert": "アスペクト比を変更するにはLINEを再起動してください。\n今すぐ再起動しますか?",
- "Setting.label.alarm.sound.1": "既定のサウンド",
- "Setting.label.alarm.sound.2": "みんなでLINE♪",
- "Setting.label.alarm.sound.3": "こっそりLINE",
- "Setting.label.alarm.sound.4": "シンプルベル",
- "Setting.label.alarm.sound.5": "ポキポキ",
- "Setting.label.alarm.sound.6": "ウェルカム",
- "Setting.label.alarm.sound.7": "口笛",
- "Setting.label.alarm.sound.8": "呼出チャイム",
- "Setting.label.alarm.sound.9": "アンサー",
- "access.chat.search.calendar": "カレンダー",
- "access.openchat.chatmenu.button.addyourthreads": "お気に入りのスレッドに追加",
- "access.openchat.chatmenu.button.removeyourthreads": "お気に入りのスレッドから削除",
- "access.openchat.chatmenu.button.yourthreads": "お気に入りのスレッド",
- "access.square.chat.button.more": "広告のオプションメニューを開く",
- "ad.alert.popup.cantplayduringcall": "通話中は再生できません。",
- "ad.desc.playinginviewer": "ビューアーで再生中です",
- "ad.menu.admute.hideContent": "このバナーを非表示",
- "ad.menu.admute.hideadvertiser": "この広告主のすべての広告を非表示",
- "ad.menu.admute.hidethisad": "この広告を非表示",
- "ad.menu.videoEnlarge": "大きく表示",
- "addFriends.error.crossregion": "友だち追加するには、このユーザーの友だち追加用のQRコードをスキャンしてください。",
- "addfriends.label.norecommendation.description": "知り合いかもしれないユーザーはいません",
- "addfriends.menu.chatandgroup": "トークルームを作成",
- "addfriends.search.captcha.fail": "入力した番号に誤りがあります。友だち追加するには、番号を正しく入力してください。\n",
- "album.add.photo.drag": "ここに写真をドラッグ&ドロップしてください",
- "album.addphotos.desc.limitexceeded": "1つのアルバムにつき、コンテンツは1,000件までしか追加できません。",
- "album.addpopup.desc.e2eeabletoretry": "コンテンツを追加できませんでした。もう一度お試しください。",
- "album.addpopup.desc.retry": "一部のコンテンツを追加できませんでした。もう一度お試しください。",
- "album.addpopup.desc.unabletoretry": "アルバムでサポートされていないため、一部のコンテンツを追加できませんでした。",
- "album.createalbum.tooltip.originalresolution.jp": "写真をオリジナル画質で追加できます",
- "album.deletepopup.desc.deletealbum": "アルバムのコンテンツがすべて削除され、元に戻すことはできません。このアルバムを削除しますか?",
- "album.label.download": "保存",
- "album.main.desc.albumvideos.other": "動画 %n",
- "album.main.toast.encodingerror": "エンコードのエラーが発生したため、再生できません。",
- "album.main.toast.encodinginprogress": "エンコード中です。 しばらくしてからもう一度お試しください。",
- "album.main.tooltip.paidplan": "動画の追加は有料サービスのため、追加した友だちがサービスを解約した場合、すべて削除されます。",
- "album.mainpopup.button.no": "いいえ",
- "album.mainpopup.button.yes": "はい",
- "album.mainpopup.desc.deletedvideo": "削除された動画です。",
- "album.mainpopup.desc.stopadding": "追加をキャンセルしますか?",
- "album.msg.cancel.upload": "写真登録をキャンセルしますか?",
- "album.picker.toast.20videomax.jp": "動画は一度に20個までしか追加できません",
- "album.picker.toast.5minutesvideomax.jp": "5分以内の動画のみ追加できます",
- "album.picker.toast.max300": "一度に300件までしか追加できません",
- "album.picker.toast.originalresolution.jp": "選択した写真をオリジナル画質で追加します",
- "album.picker.toast.over20mb.jp": "動画、容量が大きい写真、サポートされていない形式、LINEで編集した写真などは標準画質で追加されます。",
- "album.picker.toast.somestandard.jp": "一部の写真のみオリジナル画質で追加されます。動画、容量が大きい写真、サポートされていない形式、LINEで編集した写真などは標準画質で追加されます。",
- "album.picker.toast.videomax.jp.other": "このアルバムに追加できる動画は残り%n個です",
- "album.share.toast.addvideomax.jp": "1つのアルバムにつき、動画は100個までしか追加できません",
- "album.updatepopup.button.dontshow": "今後は表示しない",
- "album.updatepopup.button.later": "あとで",
- "album.updatepopup.button.updatenow": "今すぐアップデート",
- "album.updatepopup.desc.notavailable": "現在のバージョンでは、一部のコンテンツがアルバムに表示されないことがあります。LINEアプリを最新バージョンにアップデートしてください。",
- "album.viewer.button.additems": "コンテンツを追加",
- "alert.album.blocked.user": "ブロックしているアカウントとはアルバムを使えません。",
- "alert.note.blocked.user": "ブロックしているアカウントとはノートを使えません。",
- "announce.donotshowagain": "今後は表示しない",
- "announce.donotshowagain.mouseover": "今後は表示しない",
- "announce.error": "アナウンスのメッセージが見つかりません",
- "announce.minimize": "最小化",
- "announce.unannounce": "アナウンス解除",
- "announcement.message.album": "アルバム「%1」",
- "announcement.message.annoucement": "アナウンス",
- "announcement.message.error.description": "アナウンスのメッセージが見つかりません",
- "announcement.message.note.no.text": "%1にシェアされたノート",
- "announcement.message.note.text": "ノート「 %1 」",
- "announcement.system.message": "アナウンスしました]]>",
- "app.title": "LINEのアップデート",
- "att.prepopup.description": "許可いただくことで、LINEアプリで表示される情報、コンテンツや広告などが、あなたの興味関心により合ったものになります。",
- "authorize.content.desc1": "セキュリティ対策のため、PCからの初回ログイン時に本人確認する必要があります。",
- "authorize.content.desc2": "次のコードをスマートフォン版LINEに入力してください。\n",
- "authorize.e2ee.about.letterSealing": "Letter Sealingとはなんですか?",
- "authorize.e2ee.app.update": "LINEのセキュリティが強化されました。\nLINEを最新バージョンにアップデートしてください。",
- "authorize.e2ee.desc1": "アカウントを確認すると、\nLetter Sealing機能を 使えるようになります。",
- "authorize.e2ee.desc2": "次のコードをスマートフォン版LINEに\n入力してください。\n",
- "authorize.e2ee.primary.cancel": "スマートフォンでの本人確認がキャンセルされました。もう一度お試しください。",
- "authorize.msg.closing.alert": "ログインがキャンセルされます。 よろしいですか?",
- "authorize.msg.timeout.alert": "ログイン有効時間が過ぎました。もう一度お試しください。",
- "authorize.msg.useage.alert": "スマートフォン版LINEの[設定]>[アカウント]で[ログイン許可]をオンにするとログインできます。",
- "authorize.remained.time": "残り時間",
- "authorize.window.title": "PCログイン認証",
- "autoSuggest.add.language": "言語追加",
- "autoSuggest.enable": "サジェスト表示をオン",
- "autoSuggest.enabled.language": "言語",
- "autoSuggest.msg.desc": "入力したテキストに適したスタンプや絵文字を変換候補として表示します。",
- "autoSuggest.msg.desc.downloadFailed": "ダウンロードできませんでした。\nもう一度お試しください。",
- "autoSuggest.msg.download.all.emoji": "すべての絵文字をダウンロードしますか?",
- "autoSuggest.msg.download.all.sticker": "スタンプをプレビューするには、ダウンロードする必要があります。\nすべてのスタンプをダウンロードしますか?",
- "autoSuggest.title": "スタンプのサジェスト表示",
- "buddy.alert.common.failed.add.contact": "友だち追加できません",
- "buddy.alert.not.allowed.add.contact": "友だちに追加できるユーザー数が限定されているアカウントのため、これ以上友だちに追加する事ができません。",
- "buddy.btn.addBuddy": "友だち追加",
- "buddy.btn.blockBuddy": "ブロック",
- "buddy.btn.chat": "トーク",
- "buddy.btn.home": "ホーム",
- "buddy.btn.setting.profile": "プロフィール設定",
- "buddy.btn.unblockBuddy": "ブロック解除",
- "buddy.btn.voip": "音声通話",
- "buddy.label.edit.title": "表示名の変更",
- "buddy.label.info.title": "プロフィール",
- "buddylist.chooseFriend.empty.btn": "トーク",
- "buddylist.chooseFriend.empty.desc": "トークを始めよう!",
- "buddylist.chooseGroup.emty.desc": "%1の\nトーク履歴はありません。\nメッセージを送信してみましょう!",
- "buddylist.chooseMe.empty.desc": "トークを始めよう!",
- "buddylist.plusMenu.chat": "トークを開始",
- "budy.label.unregisterUser": "友だち追加していないユーザーです。 ",
- "call.callsettingspreview.desc.nocamera": "通話に参加する前に、通話設定をご確認ください。\nカメラが接続されていないため、映像はオフになります。",
- "call.callsettingspreview.desc.nocameradetected": "カメラが接続されていません",
- "call.callsettingspreview.desc.nomic": "通話に参加する前に、通話設定をご確認ください。\nマイクが接続されていないため、音声はオフになります。",
- "call.callsettingspreview.desc.nomicdetected": "マイクが接続されていません",
- "call.callsettingspreview.desc.nomicorcamera": "通話に参加する前に、通話設定をご確認ください。\nカメラとマイクが接続されていないため、映像と音声がオフになります。",
- "call.callsettingspreview.desc.nomicorcameradetected": "カメラとマイクが接続されていません",
- "call.cameraoff.friend": "通話相手のカメラが\nオフになりました",
- "call.cameraoff.me": "カメラがオフになりました。",
- "call.chat.confirm.popup.start": "通話を開始しますか?",
- "call.chat.confirm.popup.start.btn.video": "ビデオ通話を開始",
- "call.chat.confirm.popup.start.btn.voice": "音声通話を開始",
- "call.chatscreen.popup.alreadyinacall": "現在通話中です。",
- "call.doodling.popup.viewerupdaterequired": "相手が利用中のLINEバージョンが最新でないため、ペイント機能を利用できません。",
- "call.doodling.toast.doodlepaused": "画面シェアが一時的に停止されているため、ペイント機能を利用できません。",
- "call.doodling.toast.noiosdoodle": "iOS端末がシェアしている画面ではペイント機能を利用できません",
- "call.doodling.toast.sharepaused": "画面シェアが一時的に停止されています",
- "call.doodling.toast.sharerupdaterequired": "画面をシェアしているユーザーのLINEバージョンが最新でないため、ペイント機能を利用できません。",
- "call.effects.menu.stickers": "スタンプ",
- "call.effects.popup.graphiccardproblem": "ご利用のグラフィックスカードがサポートされていないため、映像がスムーズに表示されない場合があります。\nこのまま続けますか?",
- "call.effects.popup.removebgeffect": "背景エフェクトを削除すると、実際の背景が相手に表示されます。背景エフェクトを削除しますか?",
- "call.effects.toast.stickersonetime": "通話画面では一部のスタンプが利用できない場合があります",
- "call.error.popupdesc.featureunavailableondevice": "通話相手が開始した機能は、お使いの端末ではご利用になれません。スマートフォン版LINEでご利用ください。",
- "call.error.popupdesc.groupcallunavailable": "現在グループ通話を利用できません。機能を正常に利用できるよう迅速に対応いたします。",
- "call.error.popupdesc.livetalkunavailable": "現在ライブトークを利用できません。機能を正常に利用できるよう迅速に対応いたします。",
- "call.error.popupdesc.oacallunavailable": "現在通話を利用できません。機能を正常に利用できるよう迅速に対応いたします。",
- "call.error.popupdesc.outdatedapp": "利用中のLINEバージョンが最新でないため、通話相手が開始した機能を利用できません。この機能を利用するには、LINEアプリを最新バージョンにアップデートしてください。",
- "call.error.popupdesc.videocallunavailable": "現在ビデオ通話を利用できません。音声通話をご利用ください。",
- "call.error.tooltip.audionosrc": "マイクを使用できません。マイクの状態や設定に問題がないかご確認ください。",
- "call.error.unsupporteddevice": "ご利用の端末ではLINE通話がサポートされていません。",
- "call.groupcall.leavebutton": "通話を退出",
- "call.participants.desc.noresults": "検索結果がありません",
- "call.screen.toast.updaterequired": "相手が利用中のLINEバージョンが最新でないため、相手にはスタンプが表示されません",
- "call.screenshare.taskbar.screenshare": "シェアする画面を選択",
- "call.screenshare.taskbar.ytsearch": "YouTubeの動画を検索",
- "call.screenshare.toast.shareerror": "%1がほかの機能を使用しているため、画面をシェアできません。",
- "call.screenshare.toast.unsupportedos": "シェア中の画面を見るには、モバイル版LINEまたはWindows 10にアップデートされているPCをご利用ください。",
- "call.screenshare.youtube.popup.startvideo": "自分の画面が相手の画面にシェアされます。開始しますか?",
- "call.sharedcontent.desc.newdatatype": "%1が画面シェアを開始しました。シェアされているコンテンツを表示するには、LINEアプリを最新バージョンにアップデートしてください。",
- "call.toast.cpuheavyload": "PCへの負荷が増加しているため、通話品質が不安定になる場合があります。使用していないアプリを閉じてください。",
- "call.toast.handsfreebt.mic": "マイクを「%1」に接続しました。スピーカーも同じオーディオデバイスに設定してください。",
- "call.toast.handsfreebt.speaker": "スピーカーを「%1」に接続しました。マイクも同じオーディオデバイスに設定してください。",
- "call.video.filter.clear": "Clear",
- "call.video.filter.original": "Original",
- "call.viewmode.desc.focusview": "フォーカスビュー",
- "call.viewmode.desc.focusviewcenter": "フォーカスビュー(中央)",
- "call.viewmode.desc.focusviewleft": "フォーカスビュー(左側)",
- "call.viewmode.desc.focusviewright": "フォーカスビュー(右側)",
- "call.viewmode.desc.gridview": "グリッドビュー",
- "call.viewmode.desc.separateview": "スプリットビュー",
- "call.watchtogethermenu.desc.100kviewsth": "%1",
- "call.watchtogethermenu.desc.100kwatchingth": "%1",
- "call.watchtogethermenu.desc.10kviewsth": "%1",
- "call.watchtogethermenu.desc.10kwatchingth": "%1",
- "call.watchtogethermenu.desc.1bpeoplewatching": "%1",
- "call.watchtogethermenu.desc.1bviews": "%1",
- "call.watchtogethermenu.desc.1eokpeoplewatching": "%1億人が視聴中",
- "call.watchtogethermenu.desc.1eokviews": "%1億回視聴",
- "call.watchtogethermenu.desc.1kpeoplewatching": "%1",
- "call.watchtogethermenu.desc.1kviews": "%1",
- "call.watchtogethermenu.desc.1kviewsth": "%1",
- "call.watchtogethermenu.desc.1kwatchingth": "%1",
- "call.watchtogethermenu.desc.1manpeoplewatching": "%1万人が視聴中",
- "call.watchtogethermenu.desc.1manviews": "%1万回視聴",
- "call.watchtogethermenu.desc.1mpeoplewatching": "%1",
- "call.watchtogethermenu.desc.1mviews": "%1",
- "call.watchtogethermenu.desc.1mviewsth": "%1",
- "call.watchtogethermenu.desc.1mwatchingth": "%1",
- "call.watchtogethermenu.desc.daysago.other": "%n日前",
- "call.watchtogethermenu.desc.hoursago.other": "%n時間前",
- "call.watchtogethermenu.desc.justnow": "たった今",
- "call.watchtogethermenu.desc.lessthan1kviewsth": "%1",
- "call.watchtogethermenu.desc.lessthan1kwatchingth": "%1",
- "call.watchtogethermenu.desc.minutesago.other": "%n分前",
- "call.watchtogethermenu.desc.monthsago.other": "%nカ月前",
- "call.watchtogethermenu.desc.peoplewatchingen": "%1",
- "call.watchtogethermenu.desc.userswatchinglivevideo": "%1人が視聴中",
- "call.watchtogethermenu.desc.userswatchingvideo": "%1回視聴",
- "call.watchtogethermenu.desc.userswatchingvideoen.other": "%n",
- "call.watchtogethermenu.desc.yearsago.other": "%n年前",
- "call.youtube.desc.headphones": "エコーの発生を防ぐためイヤホンを使用してください。",
- "call.youtube.desc.noresults": "検索結果がありません",
- "call.youtube.paste.descforonetoone": "友だちと一緒に見たい動画のURLを入力するか、動画を検索してください(イヤホンの使用を推奨)。",
- "call.youtube.popup.shareerror": "一時的なエラーによりYouTube動画をシェアできません。もう一度お試しください。",
- "call.youtube.popupbutton.allow": "許可する",
- "call.youtube.popupbutton.disallow": "許可しない",
- "call.youtube.popupdesc.clipboard": "アクセスを許可すると、クリップボードにコピーされているYouTubeの動画リンクが自動で検索ボックスにペーストされます。",
- "call.youtube.popuptitle.clipboard": "クリップボードへのアクセスを許可",
- "call.youtube.statusbadge.premiering": "プレミア公開",
- "call.youtube.title.trendingvideos": "急上昇",
- "call.youtube.videodesc.date": "%1に公開予定",
- "call.youtube.videodesc.datevariable": "yyyy/M/d h:mm",
- "capture.command.close": "キャンセル",
- "capture.command.copy": "コピー",
- "capture.command.done": "完了",
- "capture.command.draw": "描画",
- "capture.command.gif": "GIFをキャプチャ",
- "capture.command.gif.cancel": "GIFのキャプチャをキャンセルしますか?\n作成中のGIFは保存されません。",
- "capture.command.gif.create": "GIFを作成中",
- "capture.command.gif.error.maxFileSize": "GIFファイルが20MBを超えています。\n(%1MB)\nもう一度お試しください。",
- "capture.command.gif.error.maxSize": "選択範囲が大きすぎてGIFをキャプチャできません。\nもう一度範囲を選択してください。",
- "capture.command.gif.error.size": "選択範囲が小さすぎてGIFをキャプチャできません。\nもう一度範囲を選択してください。",
- "capture.command.gif.stop": "停止",
- "capture.command.gif.tooltip": "画面をキャプチャしてGIFを作成してみよう",
- "capture.command.quit": "終了",
- "capture.command.redo": "やり直し",
- "capture.command.save": "保存",
- "capture.command.share": "シェア",
- "capture.command.undo": "取り消し",
- "capture.desc.need.os.recordscreen": "画面キャプチャを利用できません。画面収録へのアクセスをLINEに許可してください。",
- "capture.msg.onEditing": "画面キャプチャをキャンセルしますか?\n作成中の内容は保存されません。",
- "capture.scan.error.maxFileSize": "キャプチャ範囲が広すぎるためキャプチャできません。範囲を調整してもう一度お試しください。",
- "capture.scan.error.resolution": "この解像度に対応していないためキャプチャできません。解像度を調整してもう一度お試しください。",
- "capture.tool.eclipse": "丸",
- "capture.tool.line": "線",
- "capture.tool.lineColor": "線の色",
- "capture.tool.mosaic": "モザイク",
- "capture.tool.penwidth": "幅",
- "capture.tool.rectangle": "四角",
- "capture.tool.select": "選択",
- "capture.tool.shape": "形",
- "capture.tool.text": "テキスト",
- "capture.tool.textColor": "フォントの色",
- "capture.tool.textSize": "フォントサイズ",
- "capture.tool.textSize.big": "大",
- "capture.tool.textSize.medium": "中",
- "capture.tool.textSize.small": "小",
- "chat.action.leaveChat.confirm": "トークから退出するとトーク履歴はすべて削除されます。\n退出しますか?",
- "chat.alert.clipboard.largedata": "コピーしたコンテンツの容量が大きすぎるため、ペーストできません。",
- "chat.alert.file.open.fromNotbuddy": "友だちではないユーザーが送信したファイルのため、安全ではない可能性があります。\nファイルを開きますか?",
- "chat.alert.file.open.fromSquare": "友だちではないユーザーが送信したファイルのため、安全ではない可能性があります。\nファイルを開きますか?",
- "chat.alert.file.open.frombuddy": "ファイルを開く前にファイルが安全であることを確認してください。\nファイルを開きますか?",
- "chat.alert.file.open.notSupport": "ファイル形式がサポートされていないため、ファイルを開けません。",
- "chat.alert.file.unsupported.all.other": "選択したファイルの形式はサポートされていません。ファイルを圧縮して送信しますか?",
- "chat.alert.file.unsupported.some.other": "サポートされていない形式のファイルが%n個含まれています。ファイルを圧縮して送信しますか?",
- "chat.alert.invite.alreadyinvited": "%1は\nすでに招待されています。 ",
- "chat.alert.invite.alreadyjoined": "%1は\nすでにこのグループのメンバーです。 ",
- "chat.alert.invite.blockedbuddy": "ブロックしているアカウントは招待できません。",
- "chat.alert.invite.confirm": "%1を\nこのトークに招待しますか?",
- "chat.alert.invite.notbuddy": "友だちに%1を追加して、\nこのトークに招待します。 ",
- "chat.alert.invite.verificationrequired": "QRコードまたは招待リンクでグループに参加できるのは、18歳以上のユーザーのみです。",
- "chat.alert.sharePost": "%1とノート、アルバムを\nシェアしますか?",
- "chat.alert.unavailable.file": "保存期間が終了したためファイルを転送できません。",
- "chat.alert.unsend.fail.error": "メッセージの送信を取り消せませんでした。もう一度お試しください。",
- "chat.alert.unsend.fail.time": "送信してから一定時間を経過したメッセージは取り消せません",
- "chat.alert.unsend.old.version": "友だちが利用中のLINEバージョンによっては、友だちのトークからメッセージが消えないことがあります。送信を取り消しますか?",
- "chat.audio.tooltip": "音声",
- "chat.btn.capture.tooltip": "画面キャプチャ",
- "chat.btn.close.tooltip": "閉じる",
- "chat.btn.emoji": "絵文字",
- "chat.btn.facemark": "顔文字",
- "chat.btn.file": "ファイル送信",
- "chat.btn.keepmemo.tooltip": "Keepメモ",
- "chat.btn.max.tooltip": "最大化",
- "chat.btn.menu.tooltip": "メニュー",
- "chat.btn.min.tooltip": "最小化",
- "chat.btn.reset.tooltip": "元に戻す(縮小)",
- "chat.btn.sticker": "スタンプ",
- "chat.btn.sticker.tooltip": "スタンプ",
- "chat.btn.voip": "無料通話",
- "chat.contact.label": "連絡先",
- "chat.context.menu.search.name": "メンバー名で検索",
- "chat.context.menu.send.contact": "連絡先をシェア",
- "chat.context.menu.talk": "1:1トークを開始",
- "chat.desc.quit.uploading": "トークでファイルを送信中です。\nLINEを終了すると、ファイルが正常に送信されません。",
- "chat.edit.alert.unavailable.picture": "保存期間が終了したため画像を読み込むことができません。",
- "chat.emoji.label.animation.unavailable": "アニメーション効果は, モバイルで確認できます。",
- "chat.emoji.label.recentIconDesc1": "最近使用した絵文字が表示されます。",
- "chat.emoji.label.recentIconDesc2": "友だちに絵文字を送ってみて下さい。",
- "chat.emoji.label.recentLetterDesc1": "最近使用した顔文字が表示されます。",
- "chat.emoji.label.recentLetterDesc2": "友だちに顔文字を送ってみて下さい。",
- "chat.emoji.label.recentStickerDesc1": "最近使用したスタンプが表示されます。",
- "chat.emoji.label.recentStickerDesc2": "友だちにスタンプを送ってみて下さい。",
- "chat.err.file.broken": "ファイルが保存されませんでした。\nPCの容量を確認してください。",
- "chat.err.file.download.failed": "ファイルを保存できませんでした。",
- "chat.err.file.download.localError": "ファイルを保存できませんでした。しばらくしてからもう一度お試しください。",
- "chat.err.file.exceed.capacity": "一度に送信可能なファイルの容量(%1)を超えているため送信できません。",
- "chat.err.file.exceed.dailyCapacity": "一日に送信可能なファイルの総容量(%1)を超えているため送信できません。",
- "chat.err.file.folderPermission": "選択したフォルダに保存することができません。\n保存先を変更してもう一度お試しください。",
- "chat.err.file.need.space": "容量が不足しています。容量を確認してください。",
- "chat.err.file.open": "このファイルは使用中です。ファイルを閉じてから送信してください。",
- "chat.err.file.some.unpardoned": "この形式のファイルは送信できません。\n複数のファイルを送信している場合、\n他のファイルは正常に送信されます。",
- "chat.err.file.unpardoned": "この形式のファイルは送信できません",
- "chat.err.media.copyFailed": "エンコード中です。\nしばらくしてからもう一度お試しください。",
- "chat.err.media.infoLoadFailed": "ネットワーク接続エラーによりリクエストが完了していません。\nもう一度お試しください。",
- "chat.error.badwords": "この内容で送信することはできません。\n他の内容で作成してください。",
- "chat.error.popup.noauth": "このフォルダのファイルを開く権限がLINEにないため、ファイルを開けません。",
- "chat.file.audio.sizeExceeds": "音声ファイルは最大30MBまで送信が可能です。",
- "chat.file.cancel.tooltip": "キャンセル",
- "chat.file.cantFindFile": "ファイルが見つかりません",
- "chat.file.closeConfirm": "ウィンドウを閉じるとファイルの送受信が\nキャンセルされます。",
- "chat.file.countExceeds": "一回に送信できるファイルは最大%1個までです。",
- "chat.file.label.expired": "期限切れ",
- "chat.file.video.sizeExceeds": "動画ファイルは最大200MBまで送信が可能です。",
- "chat.flex.btn.send": "完了",
- "chat.flex.date.select": "日付を設定",
- "chat.flex.datetime.select": "日付と時刻を設定",
- "chat.flex.error.unknown": "現在のLINEバージョンでは利用できません。",
- "chat.flex.time.select": "時刻を設定",
- "chat.group.msg.e2ee.guide": "Letter Sealingが\n適用されています",
- "chat.group.noMember.placeholder": "トーク相手がいません。",
- "chat.grouphome.label.enjoySns.title": "友だちと2人でノートとアルバムで楽しむSNS!\n",
- "chat.image.tooltip": "画像",
- "chat.input.placeholder": "メッセージを入力",
- "chat.inputbar.msg.album": "アルバム",
- "chat.inputbar.msg.albumcontents": "アルバムのコンテンツ",
- "chat.label.del": "削除",
- "chat.label.makeAlbum": "「%1」アルバムを作成しました。",
- "chat.label.open": "表示する",
- "chat.label.openFile": "ファイルを開く",
- "chat.label.openFolder": "フォルダを開く",
- "chat.label.playback": "再生",
- "chat.label.retry": "再送する",
- "chat.label.save": "保存",
- "chat.label.saveAs": "名前を付けて保存",
- "chat.label.saveOpen": "保存して開く",
- "chat.label.sendFail": "送信エラー",
- "chat.label.share": "転送",
- "chat.label.showAlbum": "アルバム表示",
- "chat.label.showPost": "ノートを見る",
- "chat.label.showPrev": "以前のトークを表示",
- "chat.label.totalMediaCount": "全%1件",
- "chat.linemusic.shared": "音楽をシェアしました。",
- "chat.linemusic.shared.other": "%1が音楽をシェアしました。",
- "chat.list.call": " 通話時間]]>",
- "chat.list.call.canceled": " 通話をキャンセルしました]]>",
- "chat.list.call.icon": "]]>",
- "chat.list.call.missedCall": " 不在着信]]>",
- "chat.list.call.rejected": " 通話に応答がありませんでした]]>",
- "chat.list.desc.read.unread.all": "すべてのメッセージが既読の状態になりました。",
- "chat.list.group.createdby": "作成者:",
- "chat.list.group.invite": "%1があなたをグループに招待しました。",
- "chat.list.group.layer": "このグループに招待されています。",
- "chat.list.group.nogroupcreator": "作成者がグループにいません",
- "chat.list.linecall": "[LINE電話]",
- "chat.list.mention": "メンションされました",
- "chat.list.menu.clear.all.unreadmessage": "すべて既読にする",
- "chat.list.menu.sort.favorites": "お気に入り",
- "chat.list.menu.sort.time": "受信時間",
- "chat.list.menu.sort.unreadcount": "未読メッセージ",
- "chat.list.menu.tooltip": "並べ替え",
- "chat.list.sortBtn.tooltip": "未読メッセージ",
- "chat.list.sortByUnread.desc": "未読メッセージを上に整列しました。 ",
- "chat.menu.Image.download": "ダウンロードが完了しました。",
- "chat.menu.Image.download.fail": "ファイルを保存できませんでした。\nもう一度お試しください。",
- "chat.menu.alarmOff": "通知オフ",
- "chat.menu.alarmOn": "通知オン",
- "chat.menu.albums": "アルバム",
- "chat.menu.alwaysTop": "最前面で表示",
- "chat.menu.backgroundSetting": "背景",
- "chat.menu.backgroundSetting.apply": "適用する",
- "chat.menu.backgroundSetting.cancel": "キャンセル",
- "chat.menu.backgroundSetting.file": "ファイルを選択",
- "chat.menu.backgroundSetting.image.failed": "指定した画像は利用できません。",
- "chat.menu.backgroundSetting.image.maximumUploadableSize": "%1MB以下の画像のみをアップロードできます。",
- "chat.menu.backgroundSetting.option": "表示オプション",
- "chat.menu.backgroundSetting.option.detail": "タイル",
- "chat.menu.backgroundSetting.option.fill": "塗りつぶし",
- "chat.menu.backgroundSetting.photo.save.failed": "画像を保存できませんでした。",
- "chat.menu.backgroundSetting.photo.transparency": "透明度",
- "chat.menu.backgroundSetting.photoGuide": "トークルームの背景をカスタマイズしよう。",
- "chat.menu.backgroundSetting.reset": "リセット",
- "chat.menu.backgroundSetting.select": "背景を選択",
- "chat.menu.backgroundSetting.tab.color": "カラー",
- "chat.menu.backgroundSetting.tab.illustration": "イラスト",
- "chat.menu.backgroundSetting.tab.photo": "画像",
- "chat.menu.backgroundSetting.unavailableInDarkmode": "ダークモードでは利用できません",
- "chat.menu.copy": "コピー",
- "chat.menu.delete": "トーク履歴をすべて削除",
- "chat.menu.group.noMember": "メンバーなし",
- "chat.menu.invite": "招待",
- "chat.menu.invite.group": "メンバー・招待",
- "chat.menu.leave": "このトークから退出",
- "chat.menu.make": "グループ作成",
- "chat.menu.msg.announce": "アナウンス",
- "chat.menu.msg.unsend": "送信取消",
- "chat.menu.openAlbum": "画像をまとめて表示",
- "chat.menu.openAlbum.download": "ダウンロードが完了しました。",
- "chat.menu.openAlbum.download.fail": "ダウンロードできませんでした。",
- "chat.menu.openAlbum.download.fail.folderPermission": "選択したフォルダにダウンロードできませんでした。\n保存先を変更して、もう一度お試しください。",
- "chat.menu.openAlbum.download.open": "フォルダを開く",
- "chat.menu.openAlbum.downloading": "ダウンロード中...",
- "chat.menu.openAlbum.retry": "再試行",
- "chat.menu.openAlbum.saveKeep": "Keepに保存しました。",
- "chat.menu.openAlbum.saveKeep.open": "Keepを開く",
- "chat.menu.openAlbum.savingKeep": "Keepに保存中...",
- "chat.menu.openAlbum.savingKeep.fail": "Keepに保存できませんでした。",
- "chat.menu.openAlbum.selected": "%1個選択済み",
- "chat.menu.openLink": "URLをまとめて表示",
- "chat.menu.openLink.noURL": "このトークルームでシェアされたURLはありません",
- "chat.menu.paste": "ペースト",
- "chat.menu.recommend": "おすすめ",
- "chat.menu.save": "トークを保存",
- "chat.menu.save.note": "ノートに保存",
- "chat.menu.searchMsgs": "トークを検索",
- "chat.menu.selectAll": "すべて選択",
- "chat.menu.selectedCopy": "選択したテキストをコピー",
- "chat.menu.settings": "設定",
- "chat.menu.showAllContents": "コンテンツをまとめて表示",
- "chat.menu.sticker.openWebStore": "ショップ",
- "chat.menu.sticker.showDetail": "開く",
- "chat.menu.translation": "翻訳",
- "chat.message.present.emoji.receive": "絵文字のプレゼントが届きました!",
- "chat.message.present.receive.confirm": "受けとる",
- "chat.message.present.sticker.receive": "スタンプのプレゼントが届きました!",
- "chat.message.present.theme.receive": "着せかえのプレゼントが届きました!\nスマートフォンで\n受け取る事ができます。",
- "chat.message.sharealbum": "アルバムをシェアしました。",
- "chat.message.sharenote": "ノートをシェアしました。",
- "chat.msg.album.addphoto.other": "アルバムに%n件のコンテンツを追加しました。",
- "chat.msg.album.create": "「%1」アルバムを作成しました。",
- "chat.msg.album.delete": "%1が「%2」アルバムを削除しました。",
- "chat.msg.album.removephoto": "%1がアルバム「%2」のコンテンツを削除しました。",
- "chat.msg.album.rename": "%1 が「%2」アルバムの名前を「%3」に変更しました。",
- "chat.msg.album.viewPhoto": "アルバム表示",
- "chat.msg.applink.app.recv": "%1を紹介します。スマートフォンでのみ確認可能なメッセージです。",
- "chat.msg.applink.app.sent": "%1を紹介しました。",
- "chat.msg.applink.friend.recv": "%1で友だちリクエストが届きました。スマートフォンでのみ確認可能なメッセージです。",
- "chat.msg.applink.friend.sent": "%1の友だちリクエストを送りました。",
- "chat.msg.boundnoun": "님",
- "chat.msg.call.canceled": "キャンセル",
- "chat.msg.call.e2ee.guide": "アイコンが表示されます。]]>",
- "chat.msg.call.missedCall": "不在着信",
- "chat.msg.call.rejected": "応答なし",
- "chat.msg.changeGroupImage": "%1がグループの画像を変更しました。",
- "chat.msg.changeGroupName": "%1がグループ名を%2に変更しました。",
- "chat.msg.chatevent.unknown": "確認できない通知です。 モバイル\nでのみ確認可能なメッセージです。",
- "chat.msg.e2ee.decryptingMsg": "暗号化を解除しています…",
- "chat.msg.e2ee.guide": "Letter Sealingが\n適用されています",
- "chat.msg.e2ee.needKeyExchange": "メッセージを表示できません\n\nこのメッセージを表示するには本人確認が必要です。",
- "chat.msg.e2ee.recvMsg.decryptionFailed": "Letter Sealing\nメッセージが復号されていない可能性があるため 表示できません。 友だちにメッセージの再送信を依頼してください。",
- "chat.msg.e2ee.sentMsg.decryptionFailed": "メッセージを表示できません\nこのメッセージは、利用していた端末から移行されなかったため表示できません。",
- "chat.msg.e2ee.setting.disabled": "このメッセージは暗号化されています。スマートフォンでご確認ください。",
- "chat.msg.file.change.type.audio": "音声ファイルの容量が大きいため、一部の端末では再生されないことがあります。",
- "chat.msg.file.change.type.video": "動画ファイルの容量が大きいため、一部の端末では再生されないことがあります。",
- "chat.msg.file.ext": "拡張子",
- "chat.msg.file.period": "有効期間:~",
- "chat.msg.file.received": "%1がファイルを送信しました。",
- "chat.msg.file.sent": "ファイルを送信しました。",
- "chat.msg.file.size": "サイズ : %1",
- "chat.msg.file.waiting": "待機中",
- "chat.msg.groupInvite": "%1が%2を招待しました。",
- "chat.msg.groupboard.updated": "グループボードを更新しました。グループボードはスマートフォンでのみ利用できます。",
- "chat.msg.home.shared": "%1の投稿をシェアしました。",
- "chat.msg.inviteCancel": "%1が%2の招待をキャンセルしました。",
- "chat.msg.joinGroup": "%1が参加しました。",
- "chat.msg.kickout": "%1が%2を退会させました。",
- "chat.msg.leave": "%1が退出しました。",
- "chat.msg.leaveGroup": "%1が退会しました。",
- "chat.msg.leavegroup.1.n.confirm": "このトークルームから退出すると、トーク履歴を見ることができなくなります。\n退出しますか?",
- "chat.msg.nomember": "メンバーがいません",
- "chat.msg.preview.default": "リンクを開くにはこちらをタップ",
- "chat.msg.read": "既読",
- "chat.msg.search.cancelSearch": "取消",
- "chat.msg.search.hint.fromName": "送信者名を入力してください。",
- "chat.msg.search.hint.message": "トーク内容を入力してください。",
- "chat.msg.search.hint.roomName": "トークルームとメッセージ検索",
- "chat.msg.search.result.hint.addOption": "トークルームまたは送信者を追加して検索してみましょう。",
- "chat.msg.search.result.hint.noResultReason1": "PCを変更した場合、お探しの検索結果が得られない場合があります。 ",
- "chat.msg.search.result.hint.noResultReason2": "2週間以上LINE PC版を使用していない場合は検索結果が得られない場合があります。 ",
- "chat.msg.search.result.noResult": "検索結果がありません",
- "chat.msg.search.title.date": "日付",
- "chat.msg.search.title.fromName": "送信者",
- "chat.msg.search.title.message": "内容",
- "chat.msg.search.title.roomName": "トークルーム",
- "chat.msg.smartphone": "スマートフォンでのみ確認可能なメッセージです。",
- "chat.msg.start.unreadMessage": "ここから未読メッセージ",
- "chat.msg.sticker.gift.from.buddy": "プレゼントが届きました。今すぐダウンロードしよう!",
- "chat.msg.sticker.gift.from.me": "プレゼントを贈りました。",
- "chat.msg.sticker.period.expired": "有効期限が過ぎています。\nスマートフォンからもう一度購入してください。",
- "chat.msg.sticon.period.expired": "%1の有効期間が終了しました。スマートフォン版LINEのスタンプショップからもう一度購入してください。",
- "chat.msg.sync": "メッセージ同期中...",
- "chat.msg.text.seeAll": "もっと見る",
- "chat.msg.theme.gift.from.me": "プレゼントを贈りました。",
- "chat.msg.unknown.message": "表示できないメッセージ形式です。",
- "chat.msg.unread": "既読 (未読)",
- "chat.msgbox.alarmoff.description": "このトークルームで新規メッセージの通知をオフにします。",
- "chat.msgbox.bannedWord": "送信しようとするメッセージに、禁止語が含まれています。修正してから再送してください。",
- "chat.msgbox.save.description": "現在画面に表示されているトークメッセージのみテキスト形式で保存されます。\n",
- "chat.msgbox.save.dontShow": "次からはこのメッセージを表示しない。",
- "chat.msgbox.save.empty": "保存するメッセージが存在しません。",
- "chat.noMember.group.error.noAuth": "この機能はグループのメンバーのみが使用できます。",
- "chat.noMember.singleRoom.error.album": "このトークルームでは、アルバムの作成やコンテンツの追加はできません。",
- "chat.noMember.singleRoom.error.note": "このトークルームでは、ノートの新規作成はできません。",
- "chat.noinput.group.invitation": "グループトークに参加します。",
- "chat.notes.notification.sharenote": "ノートをシェアしました。",
- "chat.notimessage.sharealbum": "アルバムをシェアしました。",
- "chat.poll.message.btn": "詳細を確認",
- "chat.poll.title": "投票",
- "chat.popup.btn.pasteAsImage": "画像",
- "chat.popup.btn.pasteAsText": "テキスト",
- "chat.popup.clipboard.withImage": "クリップボードにコピーした内容を貼り付ける形式を選択してください。",
- "chat.popup.desc.grouplimit": "参加できるグループ数の上限に達しています。このグループを作成するには、不要なグループから退会してください。",
- "chat.popup.title.grouplimit": "グループに参加できません",
- "chat.popupbutton.delete": "削除する",
- "chat.popupbutton.resend": "再送する",
- "chat.popupdesc.serveroutage1": "サーバーエラーにより、このメッセージは相手に表示されていません。同じ内容を新しいメッセージとして再送しますか?",
- "chat.popupdesc.serveroutagegroup": "サーバーエラーにより、このメッセージは一部のメンバーに表示されていません。同じ内容を新しいメッセージとして再送しますか?",
- "chat.popuptitle.serveroutage": "メッセージを再送しますか?",
- "chat.profile.menu.displayName.search": "名前でメッセージを検索",
- "chat.receiveicon.linecall.failed": "chat/chat_word_receive_linecallfail_jp_icon.png",
- "chat.receiveicon.linecall.success": "chat/chat_word_receive_linecallsucess_jp_icon.png",
- "chat.reply.album": "アルバム「%1」",
- "chat.reply.jump": "元のメッセージに戻る",
- "chat.reply.jump.delete": "元のメッセージはありません",
- "chat.reply.no.original.message": "このメッセージはありません。",
- "chat.reply.note.no.text": "%1にシェアされたノート",
- "chat.reply.note.text": "ノート「 %1 」 ",
- "chat.room.msg.invitorNotBuddy": "友だちとして追加していない%1から招待されました。",
- "chat.save.location": "位置情報",
- "chat.sendicon.linecall.falied": "chat/chat_word_send_linecallfail_jp_icon.png",
- "chat.sendicon.linecall.success": "chat/chat_word_send_linecallsucess_jp_icon.png",
- "chat.setting.theme.snow.disable": "スノー効果オフ",
- "chat.setting.theme.snow.enable": "スノー効果オン",
- "chat.share.notexist": "すでに退会したか、存在しないユーザーです",
- "chat.sharing.notification.sharealbum": "アルバムをシェアしました。",
- "chat.sharing.notification.sharenote": "ノートをシェアしました。",
- "chat.status.block": "ブロックしているアカウントにはメッセージを送信できません。",
- "chat.status.disconn": "一時的にメッセージを送信することはできません。",
- "chat.status.e2ee.verification.fail": "Letter Sealingのアカウント認証が キャンセルされました。\n\n暗号化されたメッセージは、\nアカウント認証後に確認できます。",
- "chat.status.keyExchangeBtn": "本人確認",
- "chat.status.leave": "退室したトークではこれ以上メッセージを送信することはできません。",
- "chat.status.needKeyExchange": "PC版LINEでLetter Sealingを利用するには、本人確認が必要です。",
- "chat.system.inviteeoverlimit": "参加できるグループ数の上限に達しているため、以下のユーザーは参加できません。\n%1",
- "chat.system.msg.a.unsend": "%1がメッセージの送信を取り消しました",
- "chat.system.msg.unsend": "メッセージの送信を取り消しました",
- "chat.systemmessage.upgradegroup": "グループの設定が変更されました。今後このグループに招待する友だちには、グループに参加するかどうかを選んでもらう必要があります。",
- "chat.title.chatMember": "トークメンバー",
- "chat.toast.notifications.mute": "通知がオフになりました",
- "chat.toast.notifications.unmute": "通知がオンになりました",
- "chat.trans.tooltip": "透明化",
- "chat.video.play": "再生",
- "chat.video.replay": "リプレイ",
- "chat.video.tooltip": "動画",
- "chatapp.giphy.forward": "GIPHYのGIFファイルは転送できません",
- "chatapp.giphy.forward.next": "GIPHYのGIFファイルは転送できません。その他のファイルを転送しますか?",
- "chatapp.giphy.keep": "GIPHYのGIFファイルはKeepに保存できません",
- "chatapp.giphy.keep.next": "GIPHYのGIFファイルはKeepに保存できません。その他のファイルを保存しますか?",
- "chatl.share.alert.error": "このメッセージは送信が取り消されたため転送できません。",
- "chatl.share.alert.max": "最大%1件までしか選択できません。",
- "chatl.share.toast.multiple.other": "%n件のトークルームにメッセージを転送しました",
- "chatl.share.toast.single": "%1に転送しました",
- "chatl.sharetotalk.title": "送信先を選択",
- "chatlist.allinone.close.btn": "トークルームを閉じる",
- "chatlist.allinone.open.btn": "トークルームを開く",
- "chatlist.btn.startchat": "新しいトーク",
- "chatlist.chooseChat.empty.btn": "トークを読み込む",
- "chatlist.chooseChat.empty.desc": "このトークルームは別のウィンドウで開かれています。\nここに表示しますか?",
- "chatlist.context.menu.seperateChat.label": "別のウィンドウで開く",
- "chatlist.guide.allinone.text": "トークルームを開いて横に表示できます",
- "chatlist.guide.chatStart.text": "トークを始めよう!",
- "chatlist.hide.confirm": "トーク内容は削除されません。 ",
- "chatlist.keepmemo.desc.msg": "あなただけが見ることができるトークルームです。メモ代わりに、テキストや写真、動画、リンクなどを送信してみましょう。",
- "chatlist.keepmemo.desc.title": "Keepメモ",
- "chatlist.search.hint.chatList": "トークルーム検索",
- "chatlist.sort.unreadRoom": "未読のトークルームを表示",
- "chatlive.end.popup.done": "終了",
- "chatlive.error.notavailable": "他のメンバーによる通話が進行中です",
- "chatlive.maximum": "参加できる人数の上限に達しています",
- "chatlive.msg.over.traffic": "現在サーバーが混み合っています。\nしばらくしてからもう一度お試しください。",
- "chatlive.screen.share.ongoing.body": "LINEでPC画面をシェアしています。",
- "chatlive.screen.share.ongoing.stop": "停止",
- "chatlive.screen.share.ongoing.top": "自分の画面をシェアしています",
- "chatlive.screen.share.select.body": "PC画面をシェアします。シェアする画面を選択してください。",
- "chatlive.screen.share.select.done": "シェア",
- "chatlive.screen.share.select.item": "画面 %1",
- "chatlive.screen.share.select.title": "シェアする画面を選択",
- "chatlive.viewer.list.title.other": "%n人が視聴中",
- "chatlive.viewer.list.title.plurals.other": "%n人が視聴中",
- "chatroom.guide.sticker.text": "いろんなスタンプでトークをもっと楽しもう!",
- "chatsettings.desc.membersjoinautomatically": "招待した友だちはグループに自動で追加されます。グループに参加するか友だちに選んでもらうには、この設定をオフにします。",
- "chatsettings.popup.desc.onewaywarning": "この設定をオフにすると、あとでオンに戻すことはできません。この設定をオフにしますか?",
- "chatsettings.popup.title.onewaywarning": "あとでオンに戻すことはできません",
- "chatsettings.title.membersjoinautomatically": "友だちをグループに自動で追加",
- "choosefriends.button.createGroup": "トークルームを作成",
- "choosefriends.button.gotochatsingle": "トークを作成",
- "choosefriends.button.invite": "招待",
- "choosefriends.title.default": "友だちを選択",
- "choosefriends.title.numselected": "選択中 %1",
- "chrome.common.toast.unabletocopy": "コピーできませんでした。もう一度お試しください。",
- "chrome.setting.desc.notiforsp": "Chrome版を使用している場合はスマートフォン版への通知をオフ",
- "chrome.time.desc.outofrangetime": "H:mm",
- "chrome.time.toast.outofrange": "時刻は%1より前に設定してください。",
- "chrome.time.toast.outofrange2": "時刻は%1以降に設定してください。",
- "chrome.user.error.failedToBlock": "ブロックできませんでした。しばらくしてからもう一度お試しください。",
- "chrome.user.error.failedToDeclineGroupInvitation": "招待を拒否できませんでした。",
- "chrome.user.error.failedToHide": "非表示にできませんでした。しばらくしてからもう一度お試しください。",
- "chrome.user.error.failedToJoinGroup": "参加できませんでした。しばらくしてからもう一度お試しください。",
- "chrome.user.error.failedToLeaveGroup": "グループから退会できませんでした。",
- "chrome.user.error.failedToMarkFavorite": "お気に入りに追加できませんでした。",
- "chrome.user.error.failedToShowUser": "再表示できませんでした。しばらくしてからもう一度お試しください。",
- "chrome.user.error.failedToUnblock": "ブロックを解除できませんでした。",
- "common.album.empty.desc": "思い出をアルバムでシェアしよう",
- "common.alert.errorcode": "エラーコード: %1",
- "common.alert.notsupported": "ご利用のバージョンでは対応していません。\nLINEアプリを最新バージョンにアップデートしてください。",
- "common.alert.unsend.content": "送信が取り消されたコンテンツです",
- "common.alert.unsend.multi.contents": "送信が取り消されたコンテンツは除外されます",
- "common.alert.unsupported.osversion": "ご利用のOSバージョンでは対応していません。OSを最新版にアップデートしてください。",
- "common.alert.update.title": "アップデート",
- "common.alert.version.other": "すでにほかのバージョンのLINEを利用中です。",
- "common.am": "AM",
- "common.btn.back": "戻る",
- "common.btn.cancel": "キャンセル",
- "common.btn.capture.option": "画面キャプチャ時にこのウィンドウを非表示",
- "common.btn.capture.option.tooltip": "画面キャプチャのオプション",
- "common.btn.delete": "削除",
- "common.btn.discard": "退出",
- "common.btn.forward": "転送",
- "common.btn.hide": "非表示",
- "common.btn.next": "次へ",
- "common.btn.quit": "LINEを終了する",
- "common.btn.retry": "再試行",
- "common.btn.run": "ロック",
- "common.btn.save": "保存",
- "common.btn.seemore": "もっと見る",
- "common.btn.submit": "OK",
- "common.btn.unhide": "再表示",
- "common.cancel": "キャンセル",
- "common.cancelalert.desc": "入力したテキストが保存されていません。このページから移動しますか?",
- "common.code.tooltip": "写真のQRコードをスキャンできます",
- "common.content.address.share.from.buddy": "%1が連絡先をシェアしました。",
- "common.content.address.share.from.me": "連絡先を送信しました。",
- "common.content.applink.app.recv": "%1を紹介します。",
- "common.content.applink.app.sent": "%1を紹介しました。",
- "common.content.applink.friend.recv": "%1で友だちリクエストが届きました。",
- "common.content.applink.friend.sent": "%1の友だちリクエストを送りました。",
- "common.content.audio": "%1が音声ファイルを送信しました。",
- "common.content.audio.mine": "音声ファイルを送信しました。",
- "common.content.coupon.message.postfix": "スマートフォンでのみ確認可能なメッセージです。 ",
- "common.content.group.note.updated": "新しいノートを作成しました。",
- "common.content.group.note.updated.myself": "新しいノートを作成しました。",
- "common.content.groupboard.from.buddy": "%1がグループボードを更新しました。",
- "common.content.groupboard.from.me": "グループボードを更新しました。",
- "common.content.home.shared": "%1の投稿をシェアしました。",
- "common.content.home.shared.myself": "%1の投稿をシェアしました。",
- "common.content.image": "%1が画像を送信しました",
- "common.content.image.mine": "画像を送信しました。",
- "common.content.invite": "\"%1\"に招待されました",
- "common.content.location.from.buddy": "%1が位置情報を送信しました。",
- "common.content.location.from.me": "位置情報を送信しました。",
- "common.content.mantoman.note.newpost": "新しいノートを作成しました。",
- "common.content.mantoman.note.newpost.myself": "新しいノートを作成しました。",
- "common.content.normal": "さんからのメッセージ",
- "common.content.pdf": "%1 sent a pdf file.",
- "common.content.pdf.mine": "I've sent a pdf file.",
- "common.content.presence.join": "%1が参加しました。",
- "common.content.presence.join.multiple.plurals.few": "%1さんのほか%n人がトークに参加しています。",
- "common.content.presence.join.multiple.plurals.many": "%1さんのほか%n人がトークに参加しています。",
- "common.content.presence.join.multiple.plurals.one": "%1さんのほか%n人がトークに参加しています。",
- "common.content.presence.join.multiple.plurals.other": "%1さんのほか%n人がトークに参加しています。",
- "common.content.presence.join.multiple.plurals.two": "%1さんのほか%n人がトークに参加しています。",
- "common.content.presence.join.multiple.plurals.zero": "%1さんのほか%n人がトークに参加しています。",
- "common.content.presence.leave": "%1が退出しました。",
- "common.content.sticker": "%1がスタンプを送信しました。",
- "common.content.sticker.gift.from.buddy": "%1からプレゼントが届きました。",
- "common.content.sticker.gift.from.me": "プレゼントを贈りました。",
- "common.content.sticker.mine": "スタンプを送信しました",
- "common.content.theme.gift.from.buddy": "%1からプレゼントが届きました。",
- "common.content.theme.gift.from.me": "プレゼントを贈りました。",
- "common.content.timeline.post": "クリックするとブラウザで表示できます。",
- "common.content.video": "%1が動画ファイルを送信しました。",
- "common.content.video.mine": "動画ファイルを送信しました。",
- "common.continue": "続ける",
- "common.country.name.ae": "アラブ首長国連邦",
- "common.country.name.at": "オーストリア",
- "common.country.name.au": "オーストラリア",
- "common.country.name.bd": "バングラデシュ",
- "common.country.name.be": "ベルギー",
- "common.country.name.bg": "ブルガリア",
- "common.country.name.br": "ブラジル",
- "common.country.name.ca": "カナダ",
- "common.country.name.ch": "スイス",
- "common.country.name.cn": "中国",
- "common.country.name.cy": "キプロス",
- "common.country.name.cz": "チェコ",
- "common.country.name.de": "ドイツ",
- "common.country.name.dk": "デンマーク",
- "common.country.name.ee": "エストニア",
- "common.country.name.es": "スペイン",
- "common.country.name.fi": "フィンランド",
- "common.country.name.fr": "フランス",
- "common.country.name.gb": "イギリス",
- "common.country.name.gr": "ギリシャ",
- "common.country.name.hk": "香港",
- "common.country.name.hr": "クロアチア",
- "common.country.name.ht": "ハイチ",
- "common.country.name.hu": "ハンガリー",
- "common.country.name.id": "インドネシア",
- "common.country.name.ie": "アイルランド",
- "common.country.name.il": "イスラエル",
- "common.country.name.in": "インド",
- "common.country.name.ir": "イラン",
- "common.country.name.is": "アイスランド",
- "common.country.name.it": "イタリア",
- "common.country.name.jp": "日本",
- "common.country.name.kg": "キルギス",
- "common.country.name.kh": "カンボジア",
- "common.country.name.kr": "韓国",
- "common.country.name.kz": "カザフスタン",
- "common.country.name.la": "ラオス",
- "common.country.name.li": "リヒテンシュタイン",
- "common.country.name.lk": "スリランカ",
- "common.country.name.lt": "リトアニア",
- "common.country.name.lu": "ルクセンブルク",
- "common.country.name.lv": "ラトビア",
- "common.country.name.ma": "モロッコ",
- "common.country.name.mm": "ミャンマー",
- "common.country.name.mt": "マルタ",
- "common.country.name.mx": "メキシコ",
- "common.country.name.my": "マレーシア",
- "common.country.name.ng": "ナイジェリア",
- "common.country.name.nl": "オランダ",
- "common.country.name.no": "ノルウェー",
- "common.country.name.nz": "ニュージーランド",
- "common.country.name.om": "オマーン",
- "common.country.name.ph": "フィリピン",
- "common.country.name.pl": "ポーランド",
- "common.country.name.pt": "ポルトガル",
- "common.country.name.qa": "カタール",
- "common.country.name.ro": "ルーマニア",
- "common.country.name.ru": "ロシア",
- "common.country.name.sa": "サウジアラビア",
- "common.country.name.se": "スウェーデン",
- "common.country.name.sg": "シンガポール",
- "common.country.name.si": "スロベニア",
- "common.country.name.sk": "スロバキア",
- "common.country.name.th": "タイ",
- "common.country.name.tr": "トルコ",
- "common.country.name.tt": "トリニダード・トバゴ",
- "common.country.name.tw": "台湾",
- "common.country.name.ua": "ウクライナ",
- "common.country.name.us": "アメリカ合衆国",
- "common.country.name.vn": "ベトナム",
- "common.country.name.za": "南アフリカ",
- "common.country.other": "その他",
- "common.countryregion": "国・地域",
- "common.date.format.short": "M.d",
- "common.delete": "削除",
- "common.desc.macupdate": "Mac OSアップデート後にご利用いただけます。",
- "common.desc.temporary.error": "一時的なエラーによりリクエストが完了しませんでした。",
- "common.error.image.scan": "保存期間が終了した写真には文字認識を利用できません。",
- "common.error.ocr.failed": "文字を認識できません。ほかの言語を選択して、もう一度お試しください。",
- "common.error.ocr.unknown": "写真を変換できません。",
- "common.error.translation.failed": "翻訳できません。テキストを編集するか、ほかの言語を選択して、もう一度お試しください。",
- "common.friday": "金曜日",
- "common.friday.short": "金",
- "common.label.auto.slang": "言語を検出する",
- "common.label.code": "QRコードをスキャン",
- "common.label.copy": "コピー",
- "common.label.cut": "切り取り",
- "common.label.date": "日付",
- "common.label.delete": "削除",
- "common.label.file": "ファイル",
- "common.label.lang.ar": "アラビア語",
- "common.label.lang.de": "ドイツ語",
- "common.label.lang.en": "英語",
- "common.label.lang.es": "スペイン語",
- "common.label.lang.fa": "ペルシャ語",
- "common.label.lang.hi": "ヒンディー語",
- "common.label.lang.id": "インドネシア語",
- "common.label.lang.ja": "日本語",
- "common.label.lang.ko": "韓国語",
- "common.label.lang.my": "ミャンマー語",
- "common.label.lang.pt": "ポルトガル語",
- "common.label.lang.ru": "ロシア語",
- "common.label.lang.th": "タイ語",
- "common.label.lang.vi": "ベトナム語",
- "common.label.lang.zhcn": "中国語(簡体)",
- "common.label.lang.zhtw": "中国語(繁体)",
- "common.label.moveURL": "URLに移動",
- "common.label.ocr": "文字認識",
- "common.label.ocrlang": "変換先の言語",
- "common.label.paste": "ペースト",
- "common.label.redo": "やり直し",
- "common.label.selectAll": "すべて選択",
- "common.label.slang": "原文",
- "common.label.text.placeholder": "番号を入力",
- "common.label.time": "時刻",
- "common.label.tlang": "翻訳",
- "common.label.undo": "取り消し",
- "common.license.disagree": "同意しない",
- "common.license.filename": "chrome://license/Japanese.rtf",
- "common.license.title": "利用規約",
- "common.lineUrltoQR.alert.desc1": "スマートフォン版LINEでご利用になれます",
- "common.lineUrltoQR.alert.desc2": "この機能を利用するには、スマートフォン版LINEでQRコードをスキャンしてください。",
- "common.loading": "読み込み中...",
- "common.loading.splash": "LINEを起動しています…",
- "common.mac.upgrader.title": "LINEのアップデートのご案内",
- "common.menu.copyToClipboard": "クリップボードにコピー",
- "common.menu.delete": "削除",
- "common.menu.forward": "転送",
- "common.menu.reply": "リプライ",
- "common.menu.saveAs": "名前を付けて保存",
- "common.monday": "月曜日",
- "common.monday.short": "月",
- "common.msg.already.new.version": "最新バージョンです。",
- "common.msg.bot.openapi": "%1は%2.が運営します。\nLINEヤフー株式会社が提供および取得した個人情報の取り扱いについては、以下をご確認ください。",
- "common.msg.bot.openapi.agree": "同意する",
- "common.msg.bot.openapi.link": "http://me2.do/5n7WIOpr",
- "common.msg.bot.openapi.title": "個人情報の提供に同意する",
- "common.msg.checking.version": "アップデートの確認中…",
- "common.msg.db.optimize": "パフォーマンス向上のため\nLINEアプリを最適化しています...\nしばらくお待ちください。",
- "common.msg.db.optimize.complete": "最適化が完了しました。",
- "common.msg.db.optimize.error": "一時的なエラーにより\n最適化を完了できませんでした。\nLINEを再起動します",
- "common.msg.favorite.exceeded": "お気に入りは100件まで登録できます。",
- "common.msg.has.new.version": "新しいバージョンがあります。",
- "common.msg.has.new.version.alert": "新しいバージョンがあります。\nアップデートしますか? ",
- "common.msg.invitation.overflow": "%1人まで招待できます。",
- "common.msg.license.opensource": "著作権情報",
- "common.msg.sticker.need.mobile.download": "無料スタンプを使用するには、スマートフォン版LINEでダウンロードしてください。\nスマートフォン版LINEの[設定]>[スタンプ]>[マイスタンプ]、またはスタンプショップの[イベント]から無料スタンプをダウンロードできます。",
- "common.msg.terms": "ソフトウェア利用規約",
- "common.msg.update.button.label": "今すぐアップデート",
- "common.msg.update.button.label.mac": "App Storeに移動",
- "common.msg.warning.autoLogin": "アプリケーションを起動すると、自動的にログインします。\n個人情報を守るため、これは自分のPCでのみ使用してください。",
- "common.name.postfix": "さん",
- "common.note.empty.desc": "大切な情報をノートに記録してシェアしよう",
- "common.notice.dontremind": "今後、このメッセージを表示しない",
- "common.notice.label.close": "閉じる",
- "common.notice.meta.url": "line_desktop_notice/JA/1133",
- "common.notice.meta.url.mac": "line_desktop_notice_mac/JA/1134",
- "common.notice.title": "お知らせ",
- "common.ocr.agree.desc": "文字認識サービスを利用する場合は、写真がサーバーに送信されます。文字認識サービスの利用に同意しますか?",
- "common.ocr.agree.title": "文字認識サービスの利用について",
- "common.ocr.mlstatus.off": "サービス改善のための写真の提供に同意していません。同意ステータスはスマートフォン版LINEで変更できます。",
- "common.ocr.mlstatus.on": "サービス改善のための写真の提供に同意している場合、このアイコンが明るく表示されます。同意ステータスはスマートフォン版LINEで変更できます。",
- "common.ocr.tooltip": "リアルタイム翻訳機能を使ってみよう!",
- "common.ocrlang.tooltip": "変換先の言語を選択してください",
- "common.off": "オフ",
- "common.on": "オン",
- "common.picture.popup.saveImageError": "画像を保存できませんでした。",
- "common.picture.popup.showImageError": "画像を読み込めませんでした。",
- "common.pm": "PM",
- "common.popup.force.update": "必須アップデート項目があります。\nアップデートしてご利用ください。",
- "common.popup.force.update.confirm": "アップデート後にLINEをご利用いただけます。",
- "common.popup.force.update.inapp": "必須アップデート項目があります。\nアップデートしてご利用ください。",
- "common.popup.force.update.later": "1時間後にもう一度通知します。",
- "common.popup.queryUpgrade": "新しいバージョンがアップデートされました。\nアップデートしますか? ",
- "common.popup.sendkey.msg.mac": "Enterを押してメッセージを誤送信してしまう場合は \nCommand + Enterに変更してみましょう。",
- "common.popup.sendkey.msg.win": "Enterを押してメッセージを誤送信してしまう場合は\nAlt + Enterに変更してみましょう。",
- "common.popup.serverAPI.error.update": "更新プログラムがあります。\n今すぐ更新しますか?",
- "common.prepare.service": "最新バージョンをご利用中である場合、\n該当のOSでは準備中になります。",
- "common.push.mac.versionUpdate": "LINEアプリを最新バージョンにアップデートしてください。",
- "common.report.done": "通報しました",
- "common.report.reason.desc": "通報する理由を以下から選んでください。",
- "common.request.error": "正常に処理できませんでした。\nしばらく経ってからもう一度お試しください。",
- "common.saturday": "土曜日",
- "common.saturday.short": "土",
- "common.search.error.length": "2文字以上で入力してください。",
- "common.search.invalidtext": "特殊文字を含むキーワードは検索できません。ほかのキーワードを入力してください。",
- "common.seeall": "すべて見る",
- "common.share.url.copied": "コピーしました",
- "common.sunday": "日曜日",
- "common.sunday.short": "日",
- "common.thursday": "木曜日",
- "common.thursday.short": "木",
- "common.time.format": "%1 h:mm",
- "common.toast.album.delete": "アルバムを削除しました。",
- "common.toast.album.rename": "アルバム名を変更しました。",
- "common.toast.albumCreated": "新しいアルバムを作成しました。 ",
- "common.toast.audio": "音声ファイルを送信しました。",
- "common.toast.chatevent.unknown": "確認できない通知です。",
- "common.toast.contact": "連絡先がシェアされました",
- "common.toast.file": "ファイルを送信しました。",
- "common.toast.gift": "プレゼントを贈りました。",
- "common.toast.image": "画像を送信しました。",
- "common.toast.inviteGroup": "グループに招待されています。",
- "common.toast.label.newMessage": "新着メッセージがあります。",
- "common.toast.linemusic": "音楽をシェアしました。",
- "common.toast.location": "",
- "common.toast.note": "新しいノートを作成しました。",
- "common.toast.receiverequest": "送金リクエストがあります。",
- "common.toast.sticker": "スタンプを送信しました。",
- "common.toast.timeline.group.invite": "グループに招待されています。",
- "common.toast.timeline.new.comment": "チェックしてみましょう。",
- "common.toast.timeline.new.mention": "あなたにコメントしました。",
- "common.toast.timeline.new.post": "新しいノートを作成しました。",
- "common.toast.timeline.new.sticker": "チェックしてみましょう。",
- "common.toast.timeline.title.comment": "%1のコメント ",
- "common.toast.timeline.title.like": "%1のいいね",
- "common.toast.timeline.title.recomment": "%1のコメント返信 ",
- "common.toast.video": "動画を送信しました。",
- "common.toast.voip.call": "応答",
- "common.toast.voip.call.msg": "から着信です。",
- "common.toast.voip.refuse": "拒否",
- "common.today": "今日",
- "common.translation.apply.alert": "最大5,000文字まで原文を翻訳できます。 ",
- "common.translation.apply.imagedirect": "写真に翻訳を表示",
- "common.translation.imagedirect.failed": "一時的なエラーが発生しました。言語を変更するか、しばらくしてからもう一度お試しください。",
- "common.translation.imagedirect.tooltip": "テキストをリアルタイムで翻訳して、写真に翻訳を表示できます。",
- "common.tuesday": "火曜日",
- "common.tuesday.short": "火",
- "common.unsupported.version.message": "ご利用のバージョンでは対応していません。\nLINEアプリを最新版にアップデートしてください。",
- "common.update.popup.win10": "LINEを最新バージョンにアップデートしてください。",
- "common.updater": "今すぐアップデート",
- "common.updater.autoUpdate": "自動的にアップデート",
- "common.updater.autoUpdate.apply": "アップデートするとLINEが再起動されます。\n]]>",
- "common.updater.forceUpdate.apply": "新しいバージョンのLINEを利用できます。\n[確認]を選択するとLINEを再起動します。",
- "common.updater.newVersion.confirm": "お使いのLINEは最新バージョンです。",
- "common.updater.newVersion.download.apply": "[確認]を選択するとLINEを再起動します。]]>",
- "common.updater.newVersion.downloading": "最新バージョンのLINEをダウンロード中...\nしばらくお待ちください。",
- "common.updater.newVersion.incompleted": "アップデートが中断されています。\nしばらく経ってからもう一度お試しください。",
- "common.updater.newVersion.low.hardDisk": "ハードディスクの空き容量が不足しています。\n空き容量を確保してから\nもう一度お試しください。",
- "common.updater.notice.description": "今回のアップデート内容",
- "common.updater.notice.history": "アップデート履歴",
- "common.updater.notice.title": "アップデート",
- "common.updater.notice.updated": "LINEが最新バージョンにアップデートされました。",
- "common.wednesday": "水曜日",
- "common.wednesday.short": "水",
- "common.yearMonth.format": "yyyy年M月",
- "common.yesterday": "昨日",
- "creategroup.button.create": "作成",
- "creategroup.checkbox.desc.membersjoinautomatically": "招待した友だちは、グループに自動で追加されます。グループに参加するか友だちに選んでもらうには、この設定をオフにします。",
- "creategroup.checkbox.title.membersjoinautomatically": "友だちをグループに自動で追加",
- "creategroup.label.membercount": "メンバー",
- "creategroup.placeholder.entergroupname": "グループ名を入力",
- "creategroup.placerholder.defaultname.autojoinoff": "%1のグループ",
- "creategroup.popup.desc.100memberswarning": "メンバーが100人を超えるグループでは、友だちをグループに自動で追加できません。グループに参加するか友だちに選んでもらう必要があります。\n友だちをグループに自動で追加するには、グループのメンバー数を100人以下にしてください。",
- "creategroup.popup.desc.invitelocked": "この設定をオフにするには、メンバーを100人以下にしてください。",
- "creategroup.popup.desc.inviteonwarning": "メンバーが100人を超えるグループでは[友だちにグループへの参加を確認]がオンになり、友だちをグループに招待する際に、グループに参加するかどうかを選んでもらうことができます。\nこの設定をオフのままにするには、メンバーを100人以下にしてください。",
- "creategroup.popup.desc.toomanygroups": "参加できるグループ数の上限に達しています。このグループに参加するには、不要なグループから退会してください。",
- "creategroup.popup.title.100memberswarning": "友だちをグループに自動で追加できません",
- "creategroup.popup.title.invitelocked": "[友だちにグループへの参加を確認]はオフにできません",
- "creategroup.popup.title.inviteonwarning": "グループへの招待時に参加の確認が必要になります",
- "creategroup.popup.title.toomanygroups": "グループを作成できません",
- "creategroup.popup.title.toomanymembers": "メンバー数を減らす必要があります",
- "creategroup.title.setupProfile": "グループプロフィール設定",
- "creategroup.toggle.desc.requireinvite": "この設定をオンにすると、友だちをグループに招待する際に、グループに参加するかどうかを選んでもらうことができます。",
- "creategroup.toggle.title.requireinvite": "友だちにグループへの参加を確認",
- "creategroup.tooltip.groupname": "友だちが分かりやすいようにグループ名を入力しよう",
- "creategrouppopup.desc.toomanymembers": "友だちをグループに自動で追加するには、グループのメンバー数を100人以下にしてください。",
- "deletedata.chatHisotry.all.desc.confirm": "トーク履歴を削除すると元に戻すことはできません。すべての端末のトーク履歴を削除しますか?",
- "deletedata.chatHisotry.onlypc.desc.confirm": "トーク履歴を削除すると元に戻すことはできません。このPCのトーク履歴を削除しますか? ",
- "desktop.addchatfolder.button.add": "追加",
- "desktop.addchatfolder.placeholder.entername": "フォルダー名を入力",
- "desktop.addchatfolder.title.addnewfolder": "トークフォルダー追加",
- "desktop.addchatpopup.button.add": "追加",
- "desktop.addchatpopup.button.cancel": "キャンセル",
- "desktop.addchatpopup.desc.allchats": "すべて",
- "desktop.addchatpopup.desc.selected": "選択中 %1",
- "desktop.addchatpopup.placeholder.search": "検索",
- "desktop.addchatpopup.title.addchats": "トークルームを追加",
- "desktop.addfriends.desc.recommendedai": "おすすめAIアカウント",
- "desktop.addtoalbum.button.cancel": "キャンセル",
- "desktop.addtoalbum.button.createalbum": "アルバムを作成",
- "desktop.addtoalbum.title.selectalbum": "アルバムを選択",
- "desktop.album.allalbums.button.albums": "アルバム",
- "desktop.album.allalbums.button.photos": "写真",
- "desktop.album.allalbums.desc.albumsempty": "トークルームで作成されたアルバムがすべて表示されます。",
- "desktop.album.allalbums.desc.dateformat": "yyyy年M月",
- "desktop.album.allalbums.desc.photosempty": "アルバムに追加したコンテンツがここに表示されます。",
- "desktop.album.allalbums.menu.lastcreated": "作成日時",
- "desktop.album.allalbums.menu.lastupdated": "更新日時",
- "desktop.album.allalbums.title.allalbums": "アルバムをまとめて見る",
- "desktop.album.allalbums.title.photosempty": "コンテンツはありません",
- "desktop.album.allalbums.title.unableshow": "アルバムを表示できません。\nもう一度お試しください。",
- "desktop.album.allalbums.tooltip.allalbums": "すべてのトークルームのアルバムが表示されます。非表示や削除したトークルームのアルバムも表示される場合があります。",
- "desktop.album.button.add": "追加",
- "desktop.album.button.cancel": "キャンセル",
- "desktop.album.button.create": "作成",
- "desktop.album.button.namechangedone": "保存",
- "desktop.album.button.share": "シェア",
- "desktop.album.button.sharealbum": "アルバムをシェア",
- "desktop.album.commonkey.button.tryagain": "再試行",
- "desktop.album.desc.albumphotos.other": "写真 %n",
- "desktop.album.desc.draganddrop": "ここにドラッグ&ドロップしてください",
- "desktop.album.error.sharealbum": "アルバムを連続でシェアしたため、一時的にシェアが制限されています。",
- "desktop.album.main.tooltip.albumsallchats": "すべてのトークルームのアルバムがまとめて表示されます",
- "desktop.album.max.media.alert": "%1件までしか送信できません",
- "desktop.album.photos.button.seealbum": "アルバムを見る",
- "desktop.album.popupdesc.sharealbum": "このアルバムをトークルームにシェアしますか?",
- "desktop.album.tooltip.nowsharealbum": "アルバムをトークルームにシェアできます!",
- "desktop.album.viewer.button.seealbum": "アルバムを見る",
- "desktop.album.viewer.title.unableshow": "コンテンツを表示できません。\nもう一度お試しください。",
- "desktop.backgroundsetting.button.deletecover": "背景画像を削除",
- "desktop.backgroundsetting.button.selectphoto": "写真を選択",
- "desktop.blankchatfolder.button.addchat": "トークルームを追加",
- "desktop.blankchatfolder.desc.nochats": "フォルダーに追加されたトークルームはありません",
- "desktop.blankchatfolder.desc.nochats1": "トークルームをドラッグ&ドロップするか、下のボタンをクリックしてください。",
- "desktop.calendar.button.recent": "最近",
- "desktop.calendar.desc.month": "M月",
- "desktop.calendar.desc.year": "yyyy年",
- "desktop.callsettings.desc.showmessagealerts": "通話中に新着メッセージの通知を表示",
- "desktop.chat.choose.empty": "選択できるトークがありません。",
- "desktop.chat.popup.blockeduser.button.close": "通報しない",
- "desktop.chat.popup.blockeduser.button.report": "通報する",
- "desktop.chat.popup.blockeduser.desc": "スパムや迷惑行為が疑われる場合は、このユーザーを通報してください。LINEのセキュリティ向上につながります。",
- "desktop.chat.popup.blockeduser.title": "%1を通報しますか?",
- "desktop.chat.toast.chatunhidden": "このトークルームは再表示されました",
- "desktop.chat.warning.btn.addfriend": "友だち追加",
- "desktop.chat.warning.btn.blockfriend": "ブロック",
- "desktop.chat.warning.btn.decline": "拒否",
- "desktop.chat.warning.btn.join": "参加",
- "desktop.chat.warning.btn.leave": "退出",
- "desktop.chat.warning.btn.report": "通報",
- "desktop.chat.warning.btn.unblockfriend": "ブロック解除",
- "desktop.chatfolder.tab.all": "すべて",
- "desktop.chatfolder.tab.friends": "友だち",
- "desktop.chatfolder.tab.groups": "グループ",
- "desktop.chatfolder.tab.newfolder": "フォルダー(%1)",
- "desktop.chatfolder.tab.officialaccounts": "公式アカウント",
- "desktop.chatfolder.tab.openchats": "オープンチャット",
- "desktop.chatfolder.toast.addedtofoldermulti": "%1件のトークルームを追加しました",
- "desktop.chatfolder.toast.addedtofolderone": "トークルームを追加しました",
- "desktop.chatfolder.toast.nameinuse": "このフォルダー名はすでに使用されています。",
- "desktop.chatfolder.toast.removedchatmulti": "%1件のトークルームをデフォルトフォルダーに移動しました",
- "desktop.chatfolder.toast.removedchatone": "トークルームをデフォルトフォルダーに移動しました",
- "desktop.chatfolder.toast.uptohund": "1つのフォルダーに追加できるトークルームは100件までです。",
- "desktop.chatfolderguide.button.learnmore": "詳細を見る",
- "desktop.chatfolderguide.desc.desc1": "右上の編集ボタンから新しいフォルダーを追加",
- "desktop.chatfolderguide.desc.desc2": "各フォルダーを管理する設定メニューは右クリック",
- "desktop.chatfolderguide.desc.desc3": "ドラッグ&ドロップでフォルダーの順番も変更可能",
- "desktop.chatfolderguide.desc.editdragchange": "ドラッグ&ドロップして順番を変更できます。新しいフォルダーを追加するには、[+]ボタンをクリックしてください。",
- "desktop.chatfolderguide.desc.title": "トークルームをフォルダー分けして\n簡単に整理できる新機能が登場!",
- "desktop.chatfoldermenu.button.addchat": "トークルームを追加",
- "desktop.chatfoldermenu.button.changefoldername": "フォルダー名を変更",
- "desktop.chatfoldermenu.button.deletefolder": "フォルダーを削除",
- "desktop.chatfoldermenu.button.mutefolder": "フォルダーの通知をオフ",
- "desktop.chatfoldermenu.button.readall": "すべて既読にする",
- "desktop.chatfoldermenu.button.removechat": "デフォルトフォルダーに移動",
- "desktop.chatfoldermenu.button.unmutefolder": "フォルダーの通知をオン",
- "desktop.chatfoldermenu.toast.unabletoadd": "すべてのトークルームを追加することはできません",
- "desktop.chatfoldermenu.toast.uptoten": "追加できるフォルダーは10件までです。",
- "desktop.chatfolderpopup.button.ok": "確認",
- "desktop.chatfolderpopup.desc.chatfolder": "トークリスト右上の[+]ボタンから新しいフォルダーを作成してみましょう。フォルダー分けすることにより、トークルームを探しやすくなります。",
- "desktop.chatfolderpopup.desc.folderlineup": "フォルダーをドラッグ&ドロップすれば、フォルダーの順番も自由に変更できます。",
- "desktop.chatfolderpopup.desc.managefolder": "フォルダーを右クリックすると、各フォルダーの設定を行えます。",
- "desktop.chatfolderpopup.desc.unabletosync": "一時的なエラーにより同期できませんでした。同期ボタンをクリックして、もう一度お試しください。",
- "desktop.chatfolderpopup.title.chatfolder": "新機能「トークフォルダー」登場!",
- "desktop.chatfolderpopup.title.folderlineup": "並び替えも自由自在",
- "desktop.chatfolderpopup.title.managefolder": "フォルダー管理はかんたん",
- "desktop.chatfoldersetting.button.cancel": "キャンセル",
- "desktop.chatfoldersetting.button.disable": "オフにする",
- "desktop.chatfoldersetting.desc.disable": "トークフォルダー機能をオフにしますか?\n使用中のフォルダー設定がすべてリセットされます。",
- "desktop.chatfoldertooltip.desc.createchatfolder": "トークルームをフォルダー分けして簡単に整理できます",
- "desktop.chatlist.button.hide": "閉じる",
- "desktop.chatmenu.button.addtoalbum": "アルバムに追加",
- "desktop.chatssettings.desc.chateffects": "トークルームの背景でアニメーションが再生されます。",
- "desktop.chatssettings.subtitle.chateffects": "アニメーションの再生",
- "desktop.codecerror.desc.unabletoplay": "動画コーデックエラーのため再生できません",
- "desktop.common.go.to.settings": "設定に移動",
- "desktop.common.index.chats": "トーク",
- "desktop.common.index.favorites": "お気に入り",
- "desktop.common.index.friends": "友だち",
- "desktop.common.index.groups": "グループ",
- "desktop.common.index.recentlyshared": "最近の履歴",
- "desktop.common.report": "通報",
- "desktop.defaultprofile.button.cancel": "キャンセル",
- "desktop.defaultprofile.button.save": "保存",
- "desktop.defaultprofile.title.selectdefault": "デフォルト画像から選択",
- "desktop.deletefolderpopup.button.cancel": "キャンセル",
- "desktop.deletefolderpopup.button.delete": "削除",
- "desktop.deletefolderpopup.desc.deletefolder": "このフォルダーを削除しますか?\nこのフォルダーに追加されているトークルームは、それぞれのデフォルトフォルダーに自動的に振り分けられます。",
- "desktop.download.popup.call": "通話のプラグインをダウンロードしています…",
- "desktop.download.popup.calldone": "ダウンロードが完了しました。通話の発着信を行えます。",
- "desktop.download.popup.plugin": "GIFキャプチャのプラグインをダウンロードしています…",
- "desktop.download.popup.plugindone": "ダウンロードが完了しました。GIFをキャプチャーできます。",
- "desktop.download.popup.pluginnetworkerror": "プラグインをダウンロードできませんでした。ネットワーク接続を確認して、もう一度お試しください。",
- "desktop.download.popup.pluginnospace": "端末の空き容量が不足しています。不要なデータを削除して、もう一度お試しください。",
- "desktop.download.popup.pluginunexpectederror": "プラグインをダウンロードできませんでした。\nもう一度お試しください。",
- "desktop.download.popup.viewer": "ビューアーのプラグインをダウンロードしています…",
- "desktop.download.popup.viewerdone": "ダウンロードが完了しました。表示したいコンテンツをクリックするとビューアーで確認できます。",
- "desktop.dragndrop.button.addfiles": "ファイルを追加",
- "desktop.dragndrop.button.cancelcompress": "キャンセル",
- "desktop.dragndrop.button.send": "送信(%1)",
- "desktop.dragndrop.button.sendcompressed": "送信",
- "desktop.dragndrop.checkbox.alwayscompress": "常に圧縮して送信する",
- "desktop.dragndrop.title.sendfile": "ファイルを送信",
- "desktop.dragndrop.toast.upto50": "一度に送信できるファイル数は50個までです",
- "desktop.error.popup.noverification": "スマートフォン版LINEで認証できませんでした。もう一度お試しください。",
- "desktop.errorpopup.desc.downloadback": "プラグインのダウンロードに時間がかかる場合があります。このウィンドウを閉じて、バックグラウンドでダウンロードを続行しますか?",
- "desktop.errorpopup.desc.downloadno": "このまま続行",
- "desktop.errorpopup.desc.downloadyes": "閉じて続行",
- "desktop.errorpopup.desc.expired": "保存期間が終了したためファイルを再送信できません。",
- "desktop.errorpopup.desc.remobile": "サーバーエラーが発生したため、メッセージを送信できませんでした。スマートフォン版LINEでお試しください。",
- "desktop.errorpopup.desc.remobiles": "サーバーエラーが発生したため、グループにメッセージを送信できませんでした。スマートフォン版LINEでお試しください。",
- "desktop.errorpopup.desc.renewmembership": "LYPプレミアムの会員ステータスが変更されたため、コンテンツを追加できません。会員ステータスを確認して、もう一度お試しください。",
- "desktop.errorpopup.desc.revisedtermsofuse": "更新された「情報利用に関する同意」に同意していないため、コンテンツを追加できません。スマートフォン版LINEからアルバムにオリジナル画質の写真または動画を追加する際に表示される個別ポリシーに同意してください。",
- "desktop.errorpopup.title.resend": "メッセージを再送信してください",
- "desktop.favoritethreads.desc.nothreads": "気になる話題のスレッドを見つけたら、スレッド画面右上のお気に入りアイコンをクリックして追加しましょう。",
- "desktop.fileshare.button.cancel": "キャンセル",
- "desktop.fileshare.button.open": "シェア",
- "desktop.fileshare.desc.unsafefile": "ほかのユーザーにこのファイルのシェアをリクエストされました。シェアしますか?\n\n%1",
- "desktop.foldermenu.button.moveto": "他のフォルダーに移動",
- "desktop.friends.choose.empty": "選択できる友だちがいません。",
- "desktop.friendssearch.title.friendssearch": "友だち検索",
- "desktop.gprofilesetting.button.capturescreen": "画面キャプチャ",
- "desktop.gprofilesetting.button.createtext": "テキストプロフィールを作成",
- "desktop.gprofilesetting.button.deleteprofile": "プロフィール画像を削除",
- "desktop.gprofilesetting.button.selectdefault": "デフォルト画像から選択",
- "desktop.gprofilesetting.button.selectphoto": "写真を選択",
- "desktop.group.choose.empty": "選択できるグループがありません。",
- "desktop.hevcerror.desc.unabletoplay": "この形式のファイルは再生できません。ダウンロードしますか?",
- "desktop.installer.button.install": "インストール",
- "desktop.installer.checkbox.iagree": "[LINEヤフー共通利用規約|https://terms.line.me/line_terms?lang=ja]に同意します。",
- "desktop.installer.desc.installingline": "LINEをインストールしています。しばらくお待ちください。",
- "desktop.installer.desc.readandagree": "LINEをインストールするには、利用規約をご確認の上、同意してください。",
- "desktop.installercancel.button.no": "いいえ",
- "desktop.installercancel.button.yes": "はい",
- "desktop.installercancel.desc.stopinstalling": "LINEのインストールをキャンセルしますか?",
- "desktop.installerror.button.download": "ダウンロード",
- "desktop.installerror.desc.badfile": "LINEが正常にインストールされていません。ファイルをダウンロードして、もう一度インストールしてください。",
- "desktop.leavescreenpopup.button.cancel": "キャンセル",
- "desktop.leavescreenpopup.button.leave": "閉じる",
- "desktop.line.albums.desc.photosnotyet": "「写真をまとめて見る」機能は準備中です",
- "desktop.line.chatmenu.title.albumsempty": "アルバムはありません",
- "desktop.login.button.gotoemailwithPhoneNumber": "メールアドレスでログイン",
- "desktop.login.button.gotosmartphone": "スマートフォンを使ってログイン",
- "desktop.login.button.loginwithsmartphone": "スマートフォンを使ってログイン",
- "desktop.login.desc.transferring": "LINEアカウントの引き継ぎ方法",
- "desktop.login.desc.verification": "スマートフォン版LINEを利用できない場合は、LINEアカウントを引き継いでください。",
- "desktop.login.popup.scanqr": "スマートフォン画面で[パスワード]をタップすると、パスワードを再設定できます。",
- "desktop.login.popup.seeonmobile": "スマートフォンでQRコードをスキャンしてください",
- "desktop.login.popupbutton.gotit": "認証番号を確認する",
- "desktop.login.popupdesc.cancelverification": "本人確認をキャンセル",
- "desktop.login.popupdesc.loggingin": "スマートフォン版LINEで本人確認を行ってください。",
- "desktop.login.popupdesc.pairingverificationcode": "スマートフォン版LINEの[設定]>[アカウント]>[他の端末と連携]で、下記の6桁の認証番号を入力してください(初回ログイン時のみ)。",
- "desktop.login.popupdesc.pairingverificationcodeguide": "スマートフォンとの初回の連携手順\n\n1. スマートフォン版LINEを開く\n2. [設定]>[アカウント]>[他の端末と連携]を開く\n3. 6桁の認証番号を入力\n※認証番号は[認証番号を確認する]をタップすると表示されます。",
- "desktop.login.popupdesc.pairsecondarydevice": "他の端末と連携",
- "desktop.login.popuptitle.loggingin": "ログイン中です",
- "desktop.login.popuptitle.pairingverificationcode": "スマートフォンと連携",
- "desktop.main.popup.newversion": "LINEアプリの新しいバージョンがあります。アップデートしますか?",
- "desktop.movetomenu.button.all": "すべて",
- "desktop.movetomenu.button.customfolder": "%1",
- "desktop.movetomenu.button.friends": "友だち",
- "desktop.movetomenu.button.groups": "グループ",
- "desktop.movetomenu.button.oas": "公式アカウント",
- "desktop.movetomenu.button.openchats": "オープンチャット",
- "desktop.mypsticker.button.stickershop": "Sticker shop",
- "desktop.mypsticker.button.upgrade": "アップグレードする",
- "desktop.mypsticker.desc.getmore": "プレミアムスタンプをチェックしよう!",
- "desktop.mypsticker.desc.maximum": "プレミアムスタンプは最大%1パッケージまで保有できます。",
- "desktop.mypsticker.desc.nosticker": "保有するプレミアム対象のスタンプはありません",
- "desktop.mypsticker.desc.upgradetodeluxe": "デラックスコースでは、スタンプと絵文字を合計1,000パッケージまで保有できます。デラックスコースへの変更はスマートフォン版LINEから行えます。",
- "desktop.mysticker.button.cancel": "キャンセル",
- "desktop.mysticker.button.cancelshow": "キャンセル",
- "desktop.mysticker.button.showall": "すべて表示",
- "desktop.mysticker.button.stop": "中止",
- "desktop.mysticker.button.stopshow": "中止",
- "desktop.mysticker.desc.downloadstopemoji": "絵文字のダウンロードを中止しますか?",
- "desktop.mysticker.desc.downloadstopsticker": "ダウンロードを中止しますか?",
- "desktop.mysticker.desc.stopshowemoji": "すべての絵文字のダウンロードを中止しますか?",
- "desktop.mysticker.desc.stopshowsticker": "すべてのスタンプのダウンロードを中止しますか?",
- "desktop.mystickers.desc.noexpire": "有効期間 - 期限なし",
- "desktop.mystickers.desc.nolongerp": "プレミアム対象から外れました。",
- "desktop.mystickers.desc.passedtime": "有効期間 終了",
- "desktop.mystickers.desc.until": "%1まで利用可能",
- "desktop.mystickers.tooltip.hide": "非表示",
- "desktop.mystickers.tooltip.show": "表示",
- "desktop.noin87notice.button.download": "ダウンロード",
- "desktop.noin87notice.desc.supportend": "Windows 7および8におけるLINEの最新バージョンのサポートを終了しました。ご利用のOSでサポートされているLINEバージョンをダウンロードするには、下のボタンをクリックしてください。",
- "desktop.oa.chat.oaunsendconfirm.desc": "公式アカウント運営者の利用環境によっては、公式アカウント側にメッセージが残ることがあります。送信を取り消しますか?",
- "desktop.ocr.popup.toobig": "画像が5MBを超えているため処理できません。画像サイズを変更してもう一度お試しください。",
- "desktop.openchatsetting.popup.onmobile": "この設定はスマートフォン版LINEで変更できます。",
- "desktop.premiumhistory.desc.history": "過去1年間で利用したことがあるプレミアムスタンプが表示されます。使用中のスタンプは含まれません。",
- "desktop.premiumpopup.button.canceleold": "キャンセル",
- "desktop.premiumpopup.button.deleteold": "削除",
- "desktop.premiumpopup.button.edit": "スタンプを編集",
- "desktop.premiumpopup.desc.downloadlimit": "すでに%1パッケージのマイプレミアムスタンプがあります。編集画面でスタンプを1個削除してからダウンロードしてください。",
- "desktop.premiumpopup.desc.notavailablee": "この絵文字はLINEスタンプ プレミアムで利用できなくなりました。リストから削除しますか?",
- "desktop.premiumpopup.desc.notavailables": "このスタンプはLINEスタンプ プレミアムで利用できなくなりました。リストから削除しますか?",
- "desktop.premiumpopup.title.downloadlimit": "保有数の上限に達しています",
- "desktop.profile.desc.video15secs": "背景画像の動画は15秒未満にしてください。",
- "desktop.profile.desc.video6secs": "プロフィール画像の動画は6秒未満にしてください。",
- "desktop.profileselectphoto.button.cancel": "キャンセル",
- "desktop.profileselectphoto.button.save": "保存",
- "desktop.profilesetting.button.capturescreen": "画面キャプチャ",
- "desktop.profilesetting.button.createtext": "テキストプロフィールを作成",
- "desktop.profilesetting.button.deleteprofile": "プロフィール画像を削除",
- "desktop.profilesetting.button.selectdefault": "デフォルト画像から選択",
- "desktop.profilesetting.button.selectphoto": "写真を選択",
- "desktop.profilesetting.popup.500savechat": "トークルームで送信された直近500件のメッセージがテキスト形式で保存されます。",
- "desktop.quickreply.popup.notonpc": "この機能はPC版LINEでは利用できません。",
- "desktop.reaction.button.ok": "OK",
- "desktop.reaction.button.seemore": "詳細を見る",
- "desktop.reaction.desc.error": "一時的なエラーが発生したため、リアクションできませんでした。もう一度お試しください。",
- "desktop.reaction.desc.plurals.other": "リアクション %1",
- "desktop.reaction.desc.reaction1": "マウスをメッセージの上に重ねて\nアイコンからリアクションしてみましょう。",
- "desktop.reaction.desc.reaction2": "メッセージの下のアイコンをクリックすると\n友だちのリアクションを確認できます。",
- "desktop.reaction.desc.unsent": "このメッセージにはリアクションできなくなりました。",
- "desktop.reaction.title.reaction": "リアクションをして\nトークをもっと楽しもう!",
- "desktop.reaction.toast.expired": "保存期間が終了したため、このアイテムにリアクションできなくなりました。",
- "desktop.reaction.toast.unsent": "写真の送信が取り消されたため、この写真にリアクションできなくなりました。",
- "desktop.reaction.tooltip.smile": "アイコンをクリックして写真にリアクションできます",
- "desktop.removechatpopup.button.cancel": "キャンセル",
- "desktop.removechatpopup.button.remove": "移動",
- "desktop.removechatpopup.desc.allchats.other": "トークルーム %1",
- "desktop.removechatpopup.desc.selected": "選択中 %1",
- "desktop.removechatpopup.placeholder.search": "検索",
- "desktop.removechatpopup.title.removechats": "デフォルトフォルダーに移動",
- "desktop.restorepopup.button.ignore": "閉じる",
- "desktop.restorepopup.button.restore": "復元",
- "desktop.restorepopup.desc.restoreline": "別の経路でインストールしたLINEアプリがあります。そのLINEアプリのトーク履歴を復元しますか?",
- "desktop.setting.desc.enablechatfolders": "トークフォルダー機能をオン",
- "desktop.setting.desc.windows": "Windows",
- "desktop.setting.title.chatfolder": "トークフォルダー",
- "desktop.settings.desc.cantgetnotifocusassist": "端末の集中モードがオンのため、LINEからの通知を受信できません。端末の設定で集中モードの設定を変更してください。",
- "desktop.settings.desc.cantgetnotiline": "端末の通知設定がオフのため、LINEからの通知を受信できません。端末のLINEの通知設定をオンにしてください。",
- "desktop.settings.desc.cantgetnotios": "端末の通知設定がオフのため、LINEからの通知を受信できません。端末の通知設定をオンにしてください。",
- "desktop.settings.desc.osnotification": "[Windows]を選択すると、Windowsのシステム設定に従って通知を受信します。",
- "desktop.settings.desc.safeguard": "トークルームにファイルをドラッグ&ドロップして送信する際に、ファイルのプレビューを表示します。",
- "desktop.settings.notification.description": "アプリを強制終了すると、通知が遅れたり、受信できない場合があります。",
- "desktop.settings.notifications.turnonm": "端末の通知設定がオフのため、LINEからの通知を受信できません。端末の設定でLINEからの通知を許可してください。",
- "desktop.settings.notifications.turnonw": "端末の通知設定がオフのため、LINEの通知を受信できません。端末の[設定]>[システム]>[通知とアクション]でLINEの通知をオンにしてください。",
- "desktop.settings.title.safeguard": "ファイルのプレビュー",
- "desktop.shortcuts.desc.tilechats": "トークのタイル表示をオン",
- "desktop.shortcuts.desc.undotiling": "トークのタイル表示をオフ",
- "desktop.smode.popup.nogif": "セキュリティ上の理由により、Windows 10のSモードでは通話、コンテンツビューアー、GIFキャプチャの機能を使用できません。",
- "desktop.sticker.button.deletedstickers": "プレミアムダウンロード履歴",
- "desktop.sticker.button.mystickers": "マイスタンプ",
- "desktop.sticker.button.premium": "マイプレミアムスタンプ",
- "desktop.sticker.tooltip.switch": "スタンプの順番を変更できます。変更すると、スマートフォン版LINEと自動的に同期します。",
- "desktop.stickers.desc.recentlyusede": "最近使用した絵文字",
- "desktop.stickers.desc.recentlyuseds": "最近使用したスタンプ",
- "desktop.stickers.tooltip.synced": "スタンプと絵文字の順番がスマートフォン版LINEと同期されました",
- "desktop.stickertab.button.seemore": "もっと見る",
- "desktop.stickertab.desc.latestemoji": "%1の最新の絵文字",
- "desktop.stickertab.desc.lateststicker": "%1の最新スタンプ",
- "desktop.tab.button.ai": "AI",
- "desktop.textprofile.button.cancel": "キャンセル",
- "desktop.textprofile.button.save": "保存",
- "desktop.textprofile.desc.defaultfont": "基本フォント",
- "desktop.textprofile.placeholder.entertext": "テキストを入力",
- "desktop.textprofile.title.createtextprofile": "テキストプロフィールを作成",
- "desktop.thread.desc.sendfiletothread": "トークルームにファイルを送信",
- "desktop.thread.tooltip.taphere": "アイコンをクリックするとスレッドをお気に入りに追加または削除できます",
- "desktop.updatepopup.button.later": "今はしない",
- "desktop.updatepopup.button.update": "アップデート",
- "desktop.updatepopup.desc.update1": "LINE %1は利用できません。最新バージョンにアップデートしてください。アップデートすると、LINEが再起動します。",
- "desktop.updatepopup.desc.update1mac": "LINE %1は利用できません。App Storeで最新バージョンにアップデートしてください。",
- "desktop.viewer.desc.gifby": "%1からのGIF",
- "desktop.viewer.desc.gifmagazine": "ジフマガ",
- "desktop.viewer.popup.cantsave": "%1からのGIFファイルはKeepに保存できません。",
- "desktop.viewer.popup.cantsaves": "%1からのGIFファイルはKeepに保存できません。残りのファイルを保存しますか?",
- "desktop.viewer.popup.cantshare": "%1からのGIFファイルはシェアできません。",
- "desktop.viewer.popup.cantshares": "%1からのGIFファイルはシェアできません。残りのファイルをシェアしますか?",
- "desktop.wallpaper.popup.delete": "背景を削除しますか?この背景を使用しているトークルームには、デフォルトの背景が設定されます。",
- "dialog.download.font": "MS Pゴシック",
- "dialog.download.message": "アップデートが進行中です。",
- "dialog.download.messagesub": "しばらくお待ち下さい。",
- "displayname.error.badwords": "この名前に設定することはできません。\n他の名前で作成してください。 ",
- "duplicategroup.popup.button.gotochatmultiple": "グループに移動",
- "duplicategroup.popup.createnewgroup": "グループを作成",
- "duplicategroup.popup.desc.chatexistsmultiple": "同じメンバーが参加するグループ「%1」がすでに存在します。このグループに移動しますか?",
- "duplicategroup.popup.desc.selfchatexists": "あなたのみが参加するグループ「%1」がすでに存在します。このグループに移動しますか?",
- "duplicategroup.popup.title.groupexists": "グループがすでに存在します",
- "e2ee.auth.pincode.timeout": "正常に処理できませんでした。\nしばらく経ってからもう一度お試しください。",
- "e2ee.message.title": "メッセージを表示できません",
- "e2ee.popupbutton.ok": "OK",
- "e2ee.popupdesc.pleaseresend": "このメッセージはセキュリティに問題があるため表示できません。送信者に再送を依頼してください。",
- "e2ee.popupdesc.securityerror": "このファイルはセキュリティに問題があるため開けません。",
- "e2ee.popuptitle.securityerror": "セキュリティエラー",
- "emoji.downloadAll.confirm": "すべての絵文字をダウンロードしますか?",
- "friend.msg.block": "%1をブロックしますか?この友だちからメッセージを受信しなくなります。\nブロックの解除は[設定]>[友だち管理]>[ブロックリスト]で行えます。",
- "friend.msg.hide": "%1を友だちリストで非表示にしますか?\n再表示は[設定]>[友だち管理]>[非表示リスト]で行えます。",
- "gallery.picker.original.btn": "オリジナル",
- "gnb.guide.allNotification.text": "静かに過ごしたいときは、まとめて通知をオフにできます",
- "group.btn.add.title": "追加",
- "group.btn.cancel.title": "キャンセル",
- "group.btn.cancelinvite.title": "キャンセル",
- "group.btn.invite.title": "友だちを招待",
- "group.btn.removeMember.title": "削除",
- "group.button.invitefrineds": "友だちの招待",
- "group.label.addprofile.title": "編集",
- "group.label.create.title": "グループ作成",
- "group.label.groupname.title": "グループ名",
- "group.label.invitee.title": "招待中",
- "group.label.member.title": "メンバー",
- "group.label.modify.title": "グループを編集",
- "group.label.modifyprofile.title": "編集",
- "group.label.nobuddy.title": "メンバーなし",
- "group.label.nobuddytoselect.title": "招待できる友だちがいません。",
- "group.label.nosearchresult.title": "検索結果がありません",
- "group.label.nothing.title": "選択した友だちはいません。",
- "group.label.selectmember.title": "メンバーを招待",
- "group.label.unauthorized": "このグループに対する権限がありません。",
- "group.menu.delete": "削除",
- "group.menu.leave": "退会",
- "group.msg.cancelInvite.confirm": "%1はまだグループに参加していません。招待をキャンセルしますか?",
- "group.msg.cancelinvite.failed": "招待をキャンセルできませんでした。",
- "group.msg.empty.name": "グループ名を入力して下さい。",
- "group.msg.kickoutmember.confirm": "%1をグループから削除しますか?",
- "group.msg.kickoutmember.failed": "メンバーを削除できませんでした。",
- "group.msg.leavegroup.confirm": "このグループを退会すると、メンバーリストとトーク履歴を見ることができなくなります。\n退会しますか?",
- "group.msg.makegroup.failed": "グループを作成できませんでした。",
- "group.msg.overflow.name": "20文字まで入力可能です。文字数を確認して下さい。",
- "group.msg.uploadimge.failed": "写真をアップロードできませんでした。",
- "group.profile.delete": "プロフィール画像を削除",
- "group.profile.select.default": "デフォルト画像から選択",
- "group.profile.select.local": "使用中のPCから選択",
- "group.text.placerholder.title": "グループ名",
- "group.title.members": "メンバー",
- "groupcall.ageverification.popupdesc.minorscantuse": "未成年者はこのミーティング機能をご利用になれません。",
- "groupcall.alert.popup.error.nowcalling": "現在、通話中のため発信できません。\n通話が終了してからご利用ください。",
- "groupcall.call.change.to.video": "ビデオ通話に切り替えますか?",
- "groupcall.call.change.to.video.noCamera": "カメラが見つからないため、メンバーはあなたの映像を見ることができません。ビデオ通話に切り替えますか?",
- "groupcall.call.endwatchtogether.button": "画面シェアを終了",
- "groupcall.call.invite.complete": "招待を送信しました。",
- "groupcall.call.invite.tooltip": "このボタンを押すと、トーク中に他の人をグループ通話に招待できます。",
- "groupcall.call.popupbutton.cancel": "あとで",
- "groupcall.call.popupbutton.switch": "使用する",
- "groupcall.call.popupdesc.newcam": "接続された「%1」を今すぐ使用しますか?",
- "groupcall.call.popupdesc.newmic": "接続された「%1」を今すぐ使用しますか?",
- "groupcall.call.popupdesc.newspeaker": "接続された「%1」を今すぐ使用しますか?",
- "groupcall.call.popuptitle.newcam": "新しいカメラが接続されました",
- "groupcall.call.popuptitle.newmic": "新しいマイクが接続されました",
- "groupcall.call.popuptitle.newspeaker": "新しいスピーカーが接続されました",
- "groupcall.call.speaker.many.few": "%1さんと他%2人",
- "groupcall.call.speaker.many.many": "%1さんと他%2人",
- "groupcall.call.speaker.many.one": "%1さんと他%2人",
- "groupcall.call.speaker.many.other": "%1さんと他%2人",
- "groupcall.call.speaker.many.two": "%1さんと他%2人",
- "groupcall.call.speaker.many.zero": "%1さんと他%2人",
- "groupcall.call.toast.loadingyoutube": "読み込み中…",
- "groupcall.call.toast.someoneelsepreparingwatchtogether": "%1が画面シェアを準備しています",
- "groupcall.call.toast.usersjoinedgroupcall.other": "%1、他%n人がグループ通話に参加しました。",
- "groupcall.call.toast.usersleftgroupcall.other": "%1、他%n人がグループ通話を退出しました。",
- "groupcall.call.waiting.msg": "他の人が通話に参加するのを待っています…",
- "groupcall.call.watchtogether.button": "画面シェア",
- "groupcall.callsettings.button.numberofparticipants": "参加メンバー (%1)",
- "groupcall.callsettings.tooltip.handsfreebt": "「%1」を使用する場合は、スピーカーとマイクを同じオーディオデバイスに設定する必要があります。",
- "groupcall.callsettingspreview.desc.nocamera": "ミーティングに参加する前に、通話設定をご確認ください。カメラが接続されていないため、映像はオフになります。",
- "groupcall.callsettingspreview.desc.nomic": "ミーティングに参加する前に、通話設定をご確認ください。マイクが接続されていないため、音声はオフになります。",
- "groupcall.callsettingspreview.desc.nomicorcamera": "ミーティングに参加する前に、通話設定をご確認ください。カメラとマイクが接続されていないため、映像と音声がオフになります。",
- "groupcall.chat.alert.popup.error.overflow": "通話量が多いためグループ通話を開始できません。\nしばらくしてからもう一度お試しください。",
- "groupcall.chat.confirm.popup.cant": "このグループのメンバーではないため、このグループ通話には参加できません。",
- "groupcall.chat.confirm.popup.join.few": "このグループ通話の参加者は%n人です。通話に参加しますか?",
- "groupcall.chat.confirm.popup.join.many": "このグループ通話の参加者は%n人です。通話に参加しますか?",
- "groupcall.chat.confirm.popup.join.one": "このグループ通話の参加者は%n人です。通話に参加しますか?",
- "groupcall.chat.confirm.popup.join.other": "このグループ通話の参加者は%n人です。通話に参加しますか?",
- "groupcall.chat.confirm.popup.join.two": "このグループ通話の参加者は%n人です。通話に参加しますか?",
- "groupcall.chat.confirm.popup.join.zero": "このグループ通話の参加者は%n人です。通話に参加しますか?",
- "groupcall.chat.confirm.popup.start": "実行中のグループ通話はありません。\nグループ通話を開始しますか?",
- "groupcall.chat.confirm.popup.start.btn.video": "ビデオ通話を開始",
- "groupcall.chat.confirm.popup.start.btn.voice": "グループ音声通話を開始しますか?",
- "groupcall.chat.layer.join.btn": "参加",
- "groupcall.chat.layer.numofmembers.few": "%n人で通話しています。]]>",
- "groupcall.chat.layer.numofmembers.many": "%n人で通話しています。]]>",
- "groupcall.chat.layer.numofmembers.one": "%n人で通話しています。]]>",
- "groupcall.chat.layer.numofmembers.other": "%n人で通話しています。]]>",
- "groupcall.chat.layer.numofmembers.two": "%n人で通話しています。]]>",
- "groupcall.chat.layer.numofmembers.zero": "%n人で通話しています。]]>",
- "groupcall.chat.layer.start.btn": "開始",
- "groupcall.chat.layer.start.dscr": "グループ通話を開始します。",
- "groupcall.chat.layer.start.msg": "%1さんがグループ通話を開始しました。",
- "groupcall.chat.message.end": "グループ通話が終了しました。",
- "groupcall.chat.message.invite": "グループ通話に招待されました。\n%1",
- "groupcall.chat.message.start": "グループ通話が開始しました。",
- "groupcall.chatlink.desc.userisinvitedtojoinmeeting": "LINEミーティング「%1」に招待します。以下のリンクをタップすると、通話に参加できます。\n%2",
- "groupcall.chatlink.popupdesc.invalidlink": "無効なリンクです。",
- "groupcall.chatstab.tooltip.startcallwithoutchat": "リンクをシェアするだけで誰でも参加できる通話機能が登場!",
- "groupcall.createchat.button.createmeeting": "ミーティング",
- "groupcall.deletemeeting.popupdesc.delete": "削除",
- "groupcall.deletemeeting.popupdesc.deletemeeting": "このミーティングを削除しますか?",
- "groupcall.editmeetingname.popuptitle.edit": "ミーティング名を編集",
- "groupcall.groupcallpopup.desc.callparticipantlimitexceeded": "グループ通話には%1人までしか参加できません。",
- "groupcall.groupcallsettings.title.participants": "参加メンバー",
- "groupcall.groupcallsettings.toast.userwasremoved": "%1を削除しました",
- "groupcall.invite.index.not.join": "保留中",
- "groupcall.invite.selectall": "すべて選択",
- "groupcall.invite.title": "招待",
- "groupcall.kickout.popup": "接続がタイムアウトしたため通話が終了しました。",
- "groupcall.leavemeeting.popupbutton.leave": "退出",
- "groupcall.leavemeeting.popupdesc.historynolongershown": "このミーティングから退出すると、メンバーリストとトーク履歴を見ることができなくなります。\n退出しますか?",
- "groupcall.meetingintroguide.button.start": "ミーティングを作成",
- "groupcall.meetingintroguide.desc.disclaimers": "招待リンクは90日間有効です。なお、通話中や通話時に利用可能なトークルーム内ではLINEの名前とプロフィール画像が参加メンバー全員に表示されます。",
- "groupcall.meetingintroguide.desc.disclaimersjp": "招待リンクは90日間有効です。なお、通話中や通話時に利用可能なトークルーム内ではLINEの名前とプロフィール画像が参加メンバー全員に表示されます。\n※未成年のユーザーはこの機能をご利用になれません。",
- "groupcall.meetingintroguide.desc.sharelinktostart": "招待リンクを作成してシェアするだけで、複数のLINEユーザーと簡単に通話できる機能です。友だち追加していないユーザーも招待できます。",
- "groupcall.meetingintroguide.header.connect": "リンクをシェアするだけで\n誰でも参加できる通話機能",
- "groupcall.meetingintroguide.title.meetings": "ミーティング",
- "groupcall.meetingnameedit.popupbutton.save": "保存",
- "groupcall.meetingparticipantlist.button.remove": "削除",
- "groupcall.meetingparticipants.button.next": "次へ",
- "groupcall.meetingparticipants.placeholder.searchuser": "名前で検索",
- "groupcall.meetingparticipants.title.reportuser": "通報",
- "groupcall.meetings.button.copymeetinglink": "リンクをコピー",
- "groupcall.meetings.button.createmeeting": "ミーティングを作成",
- "groupcall.meetings.button.shareinvite": "招待",
- "groupcall.meetings.button.startmeeting": "開始",
- "groupcall.meetings.desc.createdjustnow": "たった今",
- "groupcall.meetings.desc.usersmeeting": "%1のミーティング",
- "groupcall.meetings.popup.policyblock": "利用規約に違反したため、LINEミーティングに参加できません。",
- "groupcall.meetings.popupdesc.networkerror": "一時的なエラーにより、ミーティングの情報を読み込めませんでした。もう一度お試しください。",
- "groupcall.meetings.toast.meetingcreated": "ミーティング用リンクを作成しました",
- "groupcall.meetingscreen.tooltip.invitemorepeople": "他のユーザーを招待できます",
- "groupcall.participantlist.desc.cameraturnedoff": "カメラをオフにしました",
- "groupcall.participantlist.desc.gridview": "グリッドビューで表示",
- "groupcall.participantlist.desc.muted": "マイクをオフにしました",
- "groupcall.participantlist.desc.participantview": "フォーカス画面に固定",
- "groupcall.participantlist.placeholder.searchbyname": "名前で検索",
- "groupcall.previewscreen.desc.nameprofilephotoshown": "LINEの名前とプロフィール画像が参加者全員に表示されます。",
- "groupcall.removefrommeeting.popupbutton.remove": "削除",
- "groupcall.removefrommeeting.popupdesc.removeuser": "%1をこのミーティングから削除しますか?",
- "groupcall.removeuser.popupdesc.temporaryerror": "一時的なエラーが発生し、削除できませんでした。もう一度お試しください。",
- "groupcall.report.button.content": "不適切なコンテンツ",
- "groupcall.report.button.harrassment": "性的いやがらせ / 出会い目的",
- "groupcall.report.button.impersonation": "なりすまし",
- "groupcall.report.button.impersonation.inquirypopup": "なりすましに関する調査のため、詳細情報の記入をお願いしております。\nお問い合わせフォームに移動して内容を記入しますか?",
- "groupcall.report.button.impersonation.inquirypopup.decline": "スキップ",
- "groupcall.report.button.impersonation.inquirypopup.preceed": "記入する",
- "groupcall.report.button.other": "その他",
- "groupcall.report.button.report": "通報",
- "groupcall.report.button.scam": "詐欺",
- "groupcall.report.button.spam": "スパム / 宣伝目的",
- "groupcall.report.desc.reportreason": "通報すると、当該メンバーの情報とスクリーンショットが自動でLINEヤフー株式会社に送信されます。",
- "groupcall.report.popupbutton.donotremove": "削除しない",
- "groupcall.report.popupbutton.remove": "削除",
- "groupcall.report.popupdesc.removeuser": "通報しました。\n通報したメンバーをミーティングから削除しますか?",
- "groupcall.report.subtitle.reportreason": "通報する理由を選択してください",
- "groupcall.screenshare.receiver.failreceive": "画面を読み込んでいます…",
- "groupcall.screenshare.receiver.senderdesc": "%1が画面をシェアしています",
- "groupcall.screenshare.receiver.viewscreen": "シェア画面に戻る",
- "groupcall.screenshare.sender.btn.stop": "画面シェアを終了",
- "groupcall.screenshare.sender.desc": "自分の画面をシェアしています",
- "groupcall.settings.menu.report": "通報",
- "groupcall.startmeeting.popupdesc.userexceededlimit": "ミーティングは30件までしか作成できません。不要なミーティングを削除して、もう一度お試しください。",
- "groupcall.tempchat.popupdesc.cantinvitethroughchat": "他のユーザーを招待するには、招待リンクをコピーして、参加メンバーにシェアしてください。",
- "groupcall.title": "グループ通話",
- "groupcall.toast.deviceerror.camera": "このカメラは利用できません。他のカメラを選択してください。",
- "groupcall.toast.newdevice.camera": "カメラが「%1」に変更されました",
- "groupcall.toast.newdevice.mic": "マイクが「%1」に変更されました",
- "groupcall.toast.newdevice.speaker": "スピーカーが「%1」に変更されました",
- "groupcall.verifyage.desc.verifyageinmobileversion": "この機能を利用するには年齢確認が必要です。\nスマートフォン版LINEの[設定]>[年齢確認]から年齢確認を行ってください。",
- "groupcall.video.alert.member.join": "%1がグループ通話に参加しました。",
- "groupcall.video.alert.member.leave": "%1がグループ通話を退出しました。",
- "groupcall.video.alert.streaming.off.member": "映像をオフにしたメンバーです。\n映像を表示するにはオンにしてください。",
- "groupcall.video.chat.error.without.camera.body": "カメラが見つかりません。グループ通話に参加しますか?",
- "groupcall.video.chat.error.without.camera.btn.video": "ビデオ通話に参加",
- "groupcall.video.chat.error.without.camera.btn.voice": "音声通話に参加",
- "groupcall.video.chat.layer.start.dscr": "グループビデオ通話を開始します。",
- "groupcall.video.chat.layer.start.msg": "%1がグループビデオ通話を開始しました。",
- "groupcall.video.chat.layer.start.shortmsg": "ビデオ通話が始まりました",
- "groupcall.video.chat.message.invite": "グループビデオ通話に招待されました。\n「%1」",
- "groupcall.video.chat.message.start": "グループ通話が開始されました",
- "groupcall.video.desc.guide.tryCall": "PC版でもグループビデオ通話ができるようになりました。 ",
- "groupcall.video.error.change.to.voice": "ネットワークが不安定か通話量が多いため、音声通話に切り替えました。",
- "groupcall.video.error.not.video.member": "音声通話に参加したメンバーの映像は表示できません。",
- "groupcall.video.fullview.streaming.fail.body": "%1の映像を読み込めませんでした。\nしばらくしてからもう一度お試しください。",
- "groupcall.video.fullview.streaming.fail.button": "再試行",
- "groupcall.video.fullview.streaming.off.body": "%1の映像をオフにしています。\n映像を表示するにはオンにしてください。",
- "groupcall.video.menu.streaming.off": "映像オフ",
- "groupcall.video.menu.streaming.on": "映像オン",
- "groupcall.video.title": "グループビデオ通話",
- "groupcall.video.toast.cameraoff": "カメラがオフになったためビデオ設定を閉じました",
- "groupcall.video.tooltip.focusview": "フォーカスビューで表示",
- "groupcall.video.tooltip.gridview": "グリッドビューで表示",
- "groupcall.video.tooltip.profilelist": "参加メンバーをもっと見る",
- "groupcall.video.tooltip.videolayout": "画面レイアウト",
- "groupcall.viewmode.desc.focusviewcenter": "フォーカスビュー(中央)",
- "groupcall.viewmode.desc.focusviewleft": "フォーカスビュー(左側)",
- "groupcall.viewmode.desc.focusviewright": "フォーカスビュー(右側)",
- "groupcall.viewmode.desc.gridview": "グリッドビュー",
- "groupcall.voice.chat.confirm.popup.join": "グループ音声通話が進行中です。参加しますか?",
- "groupcall.voice.chat.layer.start.dscr": "グループ音声通話を開始します。",
- "groupcall.voice.chat.layer.start.msg": "%1がグループ音声通話を開始しました。",
- "groupcall.voice.chat.layer.start.shortmsg": "音声通話が始まりました",
- "groupcall.voice.chat.message.invite": "グループ音声通話に招待されました。\n「%1」",
- "groupcall.voice.chat.message.start": "グループ通話が開始されました ",
- "groupcall.voice.title": "グループ音声通話",
- "groupcall.watchtogethercall.popupbutton.start": "再生",
- "groupcall.watchtogethercall.popupdesc.startwatchtogetherforeveryone": "全員の画面でこの動画が再生されます。再生しますか?",
- "groupcall.watchtogethercall.toast.currentlyinsession": "%1が画面シェアを使用しています",
- "groupcall.watchtogethercall.toast.userendedwatchtogether": "%1が画面シェアを終了しました",
- "groupcall.watchtogethercall.toast.userstartedwatchtogether": "%1が画面シェアを開始しました",
- "groupcall.watchtogethermenu.button.screenshare": "自分の画面",
- "groupcall.watchtogethermenu.button.youtube": "YouTube",
- "groupcall.watchtogethermenu.desc.policy": "プライバシーポリシー",
- "groupcall.watchtogethermenu.desc.searchonyoutube": "Youtubeのリンク、キーワードで検索",
- "groupcall.watchtogethermenu.desc.terms": "利用規約",
- "groupcall.youtube.edge.popup.btn.install": "移動",
- "groupcall.youtube.edge.popup.desc": "YouTubeの画面をシェアするには、Chromium版Microsoft Edgeのダウンロードが必要です。ダウンロードページに移動しますか?",
- "groupcall.youtube.endduetoerror": "一時的なエラーによりYouTube動画のシェアが中断されました。もう一度お試しください。",
- "groupcall.youtube.error.reinstall": "一時的なエラーにより、動画を再生できません。もう一度お試しください。同じエラーが引き続き発生する場合は、ブラウザを再度ダウンロードしてください。",
- "groupcall.youtube.paste": "YouTubeの画面をシェア",
- "groupcall.youtube.paste.btn.play": "再生",
- "groupcall.youtube.paste.btn.search": "プレビュー",
- "groupcall.youtube.paste.desc": "友だちと一緒に見たい動画のURLを入力するか、動画を検索してください(イヤホンの使用を推奨)。",
- "groupcall.youtube.paste.noresult": "動画を表示できません。URLを確認してからもう一度お試しください。",
- "groupcall.youtube.paste.startnewone.popup.btn.play": "再生",
- "groupcall.youtube.paste.startnewone.popup.desc": "再生中の動画を中断して、他の動画を再生しますか?",
- "groupcall.youtube.paste.toast.currentlyinsession": "%1がYoutubeの動画をシェアしています。",
- "groupcall.youtube.paste.toast.error": "一時的なエラーにより画面シェアを開始できません",
- "groupcall.youtube.paste.unknownerror": "一時的なエラーにより、ページを読み込めません。もう一度お試しください。",
- "groupcall.youtube.receiver.newvideo": "%1が他の動画の再生を開始しました",
- "groupcall.youtube.receiver.playvideo": "動画を見る",
- "groupcall.youtube.receiver.senderdesc": "%1が動画をシェアしています",
- "groupcall.youtube.receiver.tooltip.mute": "ミュート",
- "groupcall.youtube.receiver.tooltip.unmute": "ミュート解除",
- "groupcall.youtube.receiver.videopaused": "%1が動画を一時停止しました",
- "groupcall.youtube.sender.btn.stop": "YouTubeのシェアを終了",
- "groupcall.youtube.sender.desc": "動画をシェアしています",
- "groupcall.youtube.stop.popup.btn.confirm": "終了",
- "groupcall.youtube.stop.popup.desc": "YouTube動画のシェアを終了しますか?",
- "groupcall.youtube.windows.serveroff.popup.desc": "Windows PCではYouTubeの画面シェア機能が現在サポートされていません。",
- "groupchat.dynamic.group.title.invitecanceled.updatename": "%1がグループへの%2の招待をキャンセルしました。",
- "groupchat.dynamic.group.title.memberinvited.updatename": "グループ名を変更する]]>",
- "groupchat.dynamic.group.title.memberjoined.updatename": "グループ名を変更する]]>",
- "groupchat.dynamic.group.title.memberremoved.updatename": "%1が%2をグループから削除しました。",
- "groupchat.linkqr.error.block": "現在このグループはリンク/QRコード\n招待が許可されていません。",
- "groupchat.linkqr.error.renew": "存在しないグループです。",
- "groupchat.push.invitedtojoingroup": "%1があなたをグループに招待しました。",
- "groupchat.push.someonejoinsgroup": "%1がグループに参加しました。",
- "groupchat.systemmsg.allowjoiningvialinkorqr": "%1がQRコードやリンクを使ったグループへの招待を許可しました。",
- "groupchat.systemmsg.cancelinvite": "%1がグループへの%2の招待をキャンセルしました。",
- "groupchat.systemmsg.cancelinvite.updatename": "グループ名を変更する]]>",
- "groupchat.systemmsg.changegroupname": "%1がグループ名を「%2」に変更しました。",
- "groupchat.systemmsg.changegroupphoto": "%1がグループのプロフィール画像を変更しました。",
- "groupchat.systemmsg.disablejoiningvialinkorqr": "%1がQRコードやリンクを使ったグループへの招待をブロックしました。",
- "groupchat.systemmsg.inviteuser": "%1が%2をグループに招待しました。招待中の友だちが参加するまでしばらくお待ちください。",
- "groupchat.systemmsg.inviteuser1n": "%1が%2をグループに追加しました。",
- "groupchat.systemmsg.inviteuser1n.atcreation.updatename": "グループ名を変更する]]>",
- "groupchat.systemmsg.inviteuser1n.updatename": "グループ名を変更する]]>",
- "groupchat.systemmsg.kickoutuser": "%1が%2をグループから削除しました。",
- "groupchat.systemmsg.kickoutuser.updatename": "グループ名を変更する]]>",
- "groupchat.systemmsg.userjoin": "%1がグループに参加しました。",
- "groupchat.systemmsg.userjoin.updatename": "%1がグループに参加しました。",
- "groupchat.systemmsg.userleave": "%1がグループを退会しました。",
- "groupchat.systemmsg.userleave.updatename": "グループ名を変更する]]>",
- "groupchat.systemmsg.youareinvited": "%1があなたをグループに招待しました。",
- "grouphome.album.alert.inprogress": "コンテンツのアップロード中は、コンテンツの追加やアルバムの削除ができません。\nしばらくしてからもう一度お試しください。",
- "grouphome.album.alert.reupload": "コンテンツをもう一度アップロードしますか?",
- "grouphome.album.alert.save.failed": "コンテンツを保存できませんでした。",
- "grouphome.album.alert.stopUpload": "登録をやめる",
- "grouphome.album.alert.unregistereduser": "アカウントが削除されたユーザーとはアルバムを使えません。",
- "grouphome.album.label.reupload": "登録を再開する",
- "grouphome.albumdetail.addPhoto": "写真を追加",
- "grouphome.albumdetail.alert.changeAlbum": "アルバムを削除すると、アルバムの写真も全部削除されます。\n一度削除すると元に戻すことはできません。\nこのアルバムを削除してよろしいですか?",
- "grouphome.albumdetail.changeName": "アルバム名変更",
- "grouphome.albumdetail.delete": "アルバム削除",
- "grouphome.albumdetail.empty.desc": "一緒に過ごした楽しい時間、友だちとの大事な思い出をアルバムに残そう",
- "grouphome.albumdetail.empty.title": "追加されたコンテンツはありません",
- "grouphome.albumdetail.error": "読み込めませんでした…。\n再読み込みしてください。",
- "grouphome.albumdetail.saveComplete": "保存が完了しました。",
- "grouphome.albumdetail.saveall": "すべて保存",
- "grouphome.albumdetail.savingPhoto": "コンテンツを保存中…",
- "grouphome.albumdetail.selectCount.plurals.few": "%n枚選択",
- "grouphome.albumdetail.selectCount.plurals.many": "%n枚選択",
- "grouphome.albumdetail.selectCount.plurals.one": "%n枚選択",
- "grouphome.albumdetail.selectCount.plurals.other": "%n枚選択",
- "grouphome.albumdetail.selectCount.plurals.two": "%n枚選択",
- "grouphome.albumdetail.selectCount.plurals.zero": "%n枚選択",
- "grouphome.albumdetail.title.changeAlbum": "アルバム名変更",
- "grouphome.albumdetail.uploader": "By %1",
- "grouphome.alert.addphoto": "コンテンツの追加をキャンセルしますか?\n添付した項目は保存されません。",
- "grouphome.alert.albumLimitCount": "これ以上アルバムを作成できません。\nアルバムは最大%n件まで作成できます。",
- "grouphome.alert.alreadyDeleteAlbum": "すでに削除されたアルバムです。",
- "grouphome.alert.alreadyDeletePhoto": "すでに削除されたコンテンツです。",
- "grouphome.alert.makealbum": "アルバムの作成をキャンセルしますか?\n作成中のアルバムは保存されません。",
- "grouphome.alert.photoLimitCount": "これ以上画像を登録できません。\nアルバム1件あたり%1枚まで登録できます。",
- "grouphome.label.album": "アルバム",
- "grouphome.label.album.addPhoto": "写真を追加",
- "grouphome.label.album.changeName": "アルバム名変更",
- "grouphome.label.album.delete": "アルバム削除",
- "grouphome.label.album.empty": "まだ登録されたアルバムがありません。",
- "grouphome.label.album.make": "アルバム作成",
- "grouphome.label.albumName": "アルバム名",
- "grouphome.label.post": "ノート",
- "grouphome.label.post.empty": "まだ登録されたノートがありません。",
- "grouphome.label.showAllPost": "全投稿を見る",
- "grouphome.label.showUserHome": "%1のホームへ",
- "grouphome.label.showallalbum": "全アルバムを見る",
- "grouphome.label.writepost": "新規投稿",
- "grouphome.member.alert.joinGroup": "グループに参加しました。",
- "grouphome.member.label.showGroup": "グループを見る",
- "grouphome.post.alert.unregistereduser": "アカウントが削除されたユーザーとはノートを使えません。",
- "gruopchat.dynamic.group.title.memberleft.updatename": "%1がグループを退会しました。",
- "hub.menubar.tooltip": "Check out LINE services in LINE HUB.",
- "hub.menubar.tooltip.renew": "LINE HUB全新圖示,掌握所有LINE精選內容!",
- "image.viewer.btn.edit.tooltip": "画像エディタを開いています...",
- "image.viewer.btn.minimizesize.tooltip": "ウィンドウに合わせる",
- "image.viewer.cancel": "キャンセル",
- "image.viewer.copy": "コピー",
- "image.viewer.crop": "トリミング",
- "image.viewer.download.error": "一時的エラーが発生しました。",
- "image.viewer.loading.error": "一時的なエラーにより\nリクエストが完了しませんでした\nもう一度お試しください。",
- "image.viewer.ok": "OK",
- "image.viewer.save": "ダウンロード",
- "image.viewer.share.chat": "トークに転送",
- "imageEditor.btn.doNotSave": "保存しない",
- "imageEditor.msg.onEditing": "編集した画像をPCに保存しますか?",
- "imageEditor.msg.onModified": "この画像には保存されていない変更があります。",
- "imageEditor.msg.toobig": "解像度が高すぎるため画像を編集できません。",
- "invite.btn.cancel.title": "キャンセル",
- "invite.btn.invite.title": "OK",
- "invite.label.create.title": "友だちを招待",
- "invite.label.invitee.title": "招待",
- "invite.label.nobuddytoselect.title": "招待できる友だちがいません。",
- "invite.label.nosearchresult.title": "検索結果がありません。",
- "invite.label.nothing.title": "選択した友だちはいません。",
- "invite.label.person.title.plurals.few": "%n人",
- "invite.label.person.title.plurals.many": "%n人",
- "invite.label.person.title.plurals.one": "%n人",
- "invite.label.person.title.plurals.other": "%n人",
- "invite.label.person.title.plurals.two": "%n人",
- "invite.label.person.title.plurals.zero": "%n人",
- "keep.alert.sendtochat.unsupported.all.other": "ファイル形式がサポートされていないため、選択したファイルは送信できません。",
- "keep.alert.sendtochat.unsupported.file.multi": "",
- "keep.alert.sendtochat.unsupported.some.other": "ファイル形式がサポートされていないため、%n個のファイルは送信できません。残りのファイルを送信しますか?",
- "keep.btn.retry": "再試行",
- "keep.category.all": "すべて",
- "keep.category.files": "ファイル",
- "keep.category.links": "リンク",
- "keep.category.memos": "メモ",
- "keep.category.newtext": "テキスト",
- "keep.category.photos": "写真",
- "keep.category.photosvideos": "写真・動画",
- "keep.category.text": "テキスト",
- "keep.category.videos": "動画",
- "keep.common.error.503": "メンテナンス中です。\nメンテナンス期間:M月d日H:mm〜M月d日H:mm",
- "keep.date.format": "yyyy.M.d",
- "keep.desc.PR.title": "Keepって何に使うの?",
- "keep.desc.alreadyDeleted": "このコンテンツはすでに削除されています。",
- "keep.desc.copied": "コピー済み",
- "keep.desc.count.others.plurals.few": "とその他%1個",
- "keep.desc.count.others.plurals.many": "とその他%1個",
- "keep.desc.count.others.plurals.one": "とその他%1個",
- "keep.desc.count.others.plurals.other": "とその他%1個",
- "keep.desc.count.others.plurals.two": "とその他%1個",
- "keep.desc.count.others.plurals.zero": "とその他%1個",
- "keep.desc.delete.other": "選択したコンテンツを削除しますか?",
- "keep.desc.discard": "変更内容は保存されていません。変更を削除しますか?",
- "keep.desc.downloadError": "ファイルのダウンロード中にエラーが発生したため、この作業を完了できませんでした。",
- "keep.desc.downloading": "ダウンロード中...",
- "keep.desc.drag": "ここにファイルをドラッグ&ドロップするか、\nアップロードをクリックしてください。",
- "keep.desc.dragHere": "ここにファイルをドラッグ&ドロップしてください。",
- "keep.desc.error.reason.exceedPhotoResolution": "10,000ピクセルを超えています。",
- "keep.desc.error.reason.exceedPhotoSize": "写真が20MBを超えています。",
- "keep.desc.error.reason.expired": "保存期間が終了したため、コンテンツを読み込めません",
- "keep.desc.error.reason.lackOfStorage": "保存容量が足りません。",
- "keep.desc.error.reason.networkError": "ネットワークエラー発生。",
- "keep.desc.error.reason.notFoundFile": "ファイルが見つかりません。",
- "keep.desc.error.reason.unknown": "アップロードできません。",
- "keep.desc.error.reason.unknownFileType": "アップロードできません。",
- "keep.desc.exceedCharacter": "10,000文字まで入力できます。 ",
- "keep.desc.expiredContent.askDelete": "保存期限が切れたため、このコンテンツを見ることはできません。\n期限が切れたアイテムのリストを削除しますか?\n",
- "keep.desc.expiredContent.couldNotConfirmed": "保存期限が切れたため、このコンテンツを見ることはできません。",
- "keep.desc.expiredContent.storagePeriod": "保存期限が切れました。",
- "keep.desc.fileCountExceeds": "保存できるファイル数は最大20個までです。",
- "keep.desc.guide.tryKeep": "大切なデータを保存できる機能\n「Keep」を使ってみよう!",
- "keep.desc.itemsavedinkeepexpired": "保存期間が終了しました。",
- "keep.desc.loadFailed": "読み込めませんでした。\nネットワーク接続を確認して、もう一度お試しください。 ",
- "keep.desc.loadFromKeep": "Keepのファイルを開く",
- "keep.desc.loadingData": "データを読み込んでいます。しばらくお待ちください。",
- "keep.desc.maximumUploadableSize.plurals.few": "一度にアップロードできるのは%1MBまでです。",
- "keep.desc.maximumUploadableSize.plurals.many": "一度にアップロードできるのは%1MBまでです。",
- "keep.desc.maximumUploadableSize.plurals.one": "一度にアップロードできるのは%1MBまでです。",
- "keep.desc.maximumUploadableSize.plurals.other": "一度にアップロードできるのは%1MBまでです。",
- "keep.desc.maximumUploadableSize.plurals.two": "一度にアップロードできるのは%1MBまでです。",
- "keep.desc.maximumUploadableSize.plurals.zero": "一度にアップロードできるのは%1MBまでです。",
- "keep.desc.noSearchResult": "検索結果がありません",
- "keep.desc.noSelectableItem": "選択できるアイテムはありません。",
- "keep.desc.notSupportType": "このファイル形式は開くことができません。 ",
- "keep.desc.notifyPeriod": "%1MBを超えるファイルは30日間保存されます。 ",
- "keep.desc.photoLoadFailed": "写真を読み込めません。\nネットワーク接続を確認して、再試行してください。 ",
- "keep.desc.quit.uploading": "Keepにファイルをアップロード中です。\nLINEを終了すると、ファイルのアップロードがキャンセルされます。",
- "keep.desc.requesturl.failed.error": "URL情報を読み込めませんでした。 もう一度お試しください。",
- "keep.desc.retry": "もう一度お試しください。",
- "keep.desc.saved": "保存しました。 ",
- "keep.desc.savedInKeep": "Keepに保存されました。",
- "keep.desc.saving": "保存中...",
- "keep.desc.storageFull": "Keepの空き容量が足りません。",
- "keep.desc.storageFull.freeUpSpace": "Keepの空き容量が足りません。容量を空けてからもう一度お試しください。 ",
- "keep.desc.storageFull.unable": "Keepにストレージ容量がないため、アイテムを追加できません。",
- "keep.desc.storageFull.unableToSelect": "Keepにストレージ容量がないため、アイテムを選択できません。 ",
- "keep.desc.temporaryError": "一時的なエラーにより、リクエストを完了できませんでした。\nもう一度お試しください。\n",
- "keep.desc.totalSpace": "全容量: %1",
- "keep.desc.unexpectedErrorOccured": "予期せぬエラーが発生しました。",
- "keep.desc.upload.error.maxFileSize": "%1GB以上のファイルはアップロードできません。\nファイルのサイズをご確認ください。",
- "keep.desc.upload.inProgress": "Keepにアップロード中...",
- "keep.desc.upload.notifyIncompleteUpload": "ファイルをアップロードしています。\nLINEを終了すると、ファイルは一部のみしかアップロードされません。",
- "keep.desc.uploadFail.storage.plurals.few": "ストレージの容量が十分ではないため、%1件のアイテムをアップロードできません。",
- "keep.desc.uploadFail.storage.plurals.many": "ストレージの容量が十分ではないため、%1件のアイテムをアップロードできません。",
- "keep.desc.uploadFail.storage.plurals.one": "ストレージの容量が十分ではないため、%1件のアイテムをアップロードできません。",
- "keep.desc.uploadFail.storage.plurals.other": "ストレージの容量が十分ではないため、%1件のアイテムをアップロードできません。",
- "keep.desc.uploadFail.storage.plurals.two": "ストレージの容量が十分ではないため、%1件のアイテムをアップロードできません。",
- "keep.desc.uploadFail.storage.plurals.zero": "ストレージの容量が十分ではないため、%1件のアイテムをアップロードできません。",
- "keep.desc.uploadFailed": "アップロードできませんでした。",
- "keep.desc.uploadPending": "アップロード待機中...",
- "keep.desc.uploading": "アップロード中...",
- "keep.desc.usableSpace": "%1使用",
- "keep.desc.videoLoadFailed": "動画を読み込めません。\nネットワーク接続を確認して、再試行してください。 ",
- "keep.desc.wait": "しばらくお待ちください。",
- "keep.desc.warning.deleteAll": "すべてのファイルを削除しますか?\n削除すると復元できません。",
- "keep.desc.warning.deleteAll.chromeUser": "すべてのファイルを削除しますか?\n削除を選択すると、Chromeメモも削除されます。\nまた、削除したファイルは復元できません。",
- "keep.download.btn": "フォルダを開く",
- "keep.download.success": "ダウンロードが完了しました。",
- "keep.emptytitle.title": "大切なデータはKeepでキープ",
- "keep.full.sync.working": "処理中… %1%",
- "keep.home.bannerdesc.endofkeep": "%1までにKeepに保存したコンテンツをバックアップしてください。",
- "keep.home.bannertitle.endofkeep": "Keepサービスの終了に関するお知らせ",
- "keep.home.desc.timeformat": "yyyy年M月d日",
- "keep.home.emptydesc.descforplaces": "公式アカウントやLINEプレイスなどで保存したスポットが表示されます",
- "keep.home.popupbutton.close": "閉じる",
- "keep.home.popupbutton.dontshowagain": "今後は表示しない",
- "keep.home.popupbutton.learnmore": "詳細を見る",
- "keep.home.popupdesc.endofkeep": "%1にKeepサービスの提供を終了いたします。サービス終了日前までにKeepに保存したコンテンツをバックアップしてください。\n※サービス終了後も引き続きKeepメモはご利用になれます。",
- "keep.home.popuptitle.endofkeep": "Keepサービスの終了およびバックアップに関するお知らせ",
- "keep.home.tab.places": "スポット",
- "keep.home.toast.pinneditems": "ピン留め済み",
- "keep.itemspicker.popupdesc.itemsharinglimit": "アイテムは一度に20件までしかシェアできません。",
- "keep.keepitem.itemsenttokeepmemoexpired": "Keepメモに送信したアイテムの保存期間が終了しました",
- "keep.keepmemoguide.popupdesc.itemssenttokeepmemoshowninkeep": "Keepメモに送信した内容は、Keepから簡単に管理できます。",
- "keep.keepmemoguide.popupdesc.piniimportantitems": "よく確認するものは、ピン留めしてKeepの上段に表示できます。",
- "keep.keepmemoguide.popupdesc.savekeepmemocontentforeverinkeep": "Keepで保存、ピン留め、編集またはコレクションへの追加を行うことで永久に保存されます。",
- "keep.keepmemoguide.popuptitle.introducingkeepmemo": "Keepメモが新登場",
- "keep.keepmemoguide.popuptitle.keepitemsforever": "大切な内容をずっとキープ",
- "keep.keepmemoguide.popuptitle.pinningitems": "アイテムをピン留め",
- "keep.label.add": "追加",
- "keep.label.addText": "新しいテキスト",
- "keep.label.capture": "画面キャプチャ",
- "keep.label.chromeMemo": "Chromeメモ",
- "keep.label.copy": "コピー",
- "keep.label.createdTime": "撮影時間",
- "keep.label.delete": "削除",
- "keep.label.deleteAll": "すべて削除",
- "keep.label.deleting": "削除中...",
- "keep.label.details": "詳細",
- "keep.label.download": "ダウンロード",
- "keep.label.edit": "編集",
- "keep.label.emptyText": "テキストを入力",
- "keep.label.expired": "期限切れ",
- "keep.label.fileSize": "ファイルサイズ",
- "keep.label.from": "送信者",
- "keep.label.goToKeep": "Keepを開く",
- "keep.label.hitocoto": "ひとこと",
- "keep.label.justNow": "たった今",
- "keep.label.learnMore": "ご確認ください",
- "keep.label.modifiedTime": "最終更新",
- "keep.label.more": "その他",
- "keep.label.newMemo": "メモ",
- "keep.label.open": "開く",
- "keep.label.openkeepmemo": "Keepメモを開く",
- "keep.label.order.stored": "保存日時",
- "keep.label.order.updated": "最終更新",
- "keep.label.paste": "ペースト",
- "keep.label.pause": "一時停止",
- "keep.label.period": "保存期間",
- "keep.label.pin": "ピン留め",
- "keep.label.play": "再生",
- "keep.label.playTime": "再生時間",
- "keep.label.refresh": "更新",
- "keep.label.resolution": "解像度",
- "keep.label.save": "保存",
- "keep.label.saveInKeep": "Keepに保存",
- "keep.label.savedTime": "保存時間",
- "keep.label.search": "検索",
- "keep.label.searchResult": "検索結果",
- "keep.label.send": "決定",
- "keep.label.settings": "設定",
- "keep.label.shareToChat": "トークに送信",
- "keep.label.sortByDate": "日付で並べ替え",
- "keep.label.sortByName": "名前で並べ替え",
- "keep.label.sortBySize": "サイズで並べ替え",
- "keep.label.terminate": "LINEを終了する",
- "keep.label.tooltip": "Keep",
- "keep.label.unpin": "ピン留めを解除",
- "keep.label.upload": "アップロード",
- "keep.label.uploadFile": "ファイルを追加",
- "keep.label.viewinkeepmemo": "Keepメモで見る",
- "keep.label.voiceMessage": "ボイスメッセージ",
- "keep.label.volume": "使用中の容量",
- "keep.label.writememo.title": "メモ",
- "keep.label.writetext.title": "テキスト",
- "keep.main.desc.keepfadeout": "Keep機能の提供は終了しました。LINEアプリを最新バージョンにアップデートしてください。",
- "keep.title": "Keep",
- "keep.toast.itempinned": "ピン留めしました",
- "keep.toast.itemunpinned": "ピン留めを解除しました",
- "keepmemo.alert.deletemessage": "選択したメッセージは、この端末でのみ削除されます。削除しますか?",
- "keepmemo.alert.unsendmessage": "選択したメッセージが、利用中のすべての端末のトーク履歴から削除されます。送信を取り消しますか?",
- "keepmemo.category.all": "すべて",
- "keepmemo.category.files": "ファイル",
- "keepmemo.category.links": "リンク",
- "keepmemo.category.photos": "写真",
- "keepmemo.category.text": "テキスト",
- "keepmemo.category.videos": "動画",
- "keepmemo.desc.noSelectableItem": "選択できるコンテンツはありません",
- "keepmemo.itemspicker.popupdesc.itemsharinglimit": "コンテンツは一度に20件までしか送信できません。",
- "keepmemo.label.goToKeepMemo": "Keepメモを開く",
- "keepmemo.label.search": "検索",
- "keepmemo.label.sendToKeepMemo": "Keepメモに転送",
- "keepmemo.label.share": "送信",
- "keepmemo.label.tooltip": "Keepメモ",
- "keepmemo.msg.desc.systemmsg": "あなただけが見ることができるトークルームです。メモ代わりに、テキストや写真、動画、リンクなどを送信してみましょう。",
- "keepmemo.title": "Keepメモに送信",
- "keyword.notice.btn": "キーワードを追加",
- "keyword.notice.desc": "特定の文字やユーザー名を含むメッセージの受信時に通知を受けるには、それらをキーワードとして追加してください。",
- "keyword.notice.title": "キーワード通知",
- "keyword.notification.desc": "キーワード通知があります",
- "kickout.all.v3": "自動的にログアウトしました。もう一度ログインしてください。",
- "kickout.dormant.account": "スマートフォン版LINEに登録したメールアドレスでもう一度ログインして、アカウント認証を行ってください。",
- "kickout.email.account.modified": "メールアドレスを新規登録したかパスワードを変更したため、ログアウトされました。",
- "kickout.expired": "長時間使用されなかったため\nログアウトされました。",
- "kickout.networkError": "ネットワークエラーが発生したため、ログアウトされました。もう一度ログインしてください。",
- "kickout.noAllowedSecondaryDevice": "スマートフォンでアクセスをブロックしたためログアウトされました。\n",
- "kickout.notAuthorizedDevice": "他のPCでログインしたためログアウトされました。 ",
- "kickout.notAvailableUser": "他の端末でLINEアカウントが削除されたためログアウトしました。",
- "kickout.passwordChanged": "네이버를 탈퇴하여 로그아웃 되었습니다. ",
- "kickout.serverError": "サーバーエラーが発生したため、ログアウトされました。もう一度ログインしてください。",
- "kickout.serverMaintenance": "サーバーメンテナンス中です。しばらくしてからもう一度お試しください。",
- "kickout.serviceMaintenance": "一時的なエラーが発生したため、ログアウトされました。もう一度ログインしてください。",
- "kickout.square.server.fail": "オープンチャットの認証でエラーが発生したため、ログアウトされました。もう一度ログインしてください。",
- "line.keepmemoguide.popupdesc.page1": "トークルームのように、テキストや写真などをKeepメモに送信してみましょう。",
- "line.keepmemoguide.popuptitle.page1": "Keepメモが新登場",
- "line.secondarylogin.popupdesc.updatelineerror.desk": "LINEアプリをアップデートして、再度お試しください。",
- "line.secondarylogin.popuptitle.updatelineerror.desk": "エラー",
- "line.updatepopup.button.leave": "閉じる",
- "linechrome.chat.desc.unsupportedmessage": "このメッセージは、Chrome版LINEでは表示できません。スマートフォン版LINEでご確認ください。",
- "linechrome.chat.desc.unsupportedstickers": "このスタンプは、Chrome版LINEでは利用できません。\nスマートフォン版LINEで利用してください。",
- "linechrome.chat.toast.nofolders": "フォルダは送信できません",
- "linechrome.chat.toast.supportedlanguage": "Chrome版LINEは翻訳された言語に対応しています。言語は[設定]で変更できます。",
- "linechrome.end.desc.endline": "Chrome版LINEを終了しますか?",
- "linechrome.main.button.mute1": "通知を1時間オフ",
- "linechrome.main.button.mute2": "通知を2時間オフ",
- "linechrome.main.button.mute24": "通知を24時間オフ",
- "linechrome.main.button.mute30": "通知を30分間オフ",
- "linechrome.main.desc.unmutehour": "通知は%1時間後にオンになります",
- "linechrome.main.desc.unmuteminute": "通知は%1分後にオンになります",
- "linechrome.main.desc.unmutesecond.other": "通知は%1秒後にオンになります",
- "linemusic.playlist": "プレイリスト",
- "linemusic.title": "LINE MUSIC",
- "linemusic.topic": "トピック",
- "lockscreen.kickout.accountError": "パスワードを連続して間違えたため、ログアウトされました",
- "lockscreen.lockscreen.text": "ロックモードがオンです",
- "lockscreen.msg.alert.oncalling": "ロックモードをオンにすると通話が終了します。\nオンにしますか?",
- "lockscreen.msg.unlock.description": "ロックモードをオンにしますか?\nロックモードをオフにするにはパスワードが必要です。",
- "lockscreen.msg.unlockAuto.description": "PCを使用していない場合はロックモードをオンにしますか?\nロックモードをオフにするにはパスワードが必要です。",
- "lockscreen.password.fail": "パスワードが間違っています。もう一度入力してください。",
- "lockscreen.password.text": "ロックモードをオフにするには、LINEアカウントのパスワードを入力してください。",
- "lockscreen.password.unlock.btn": "オフにする",
- "login.btn.emailQRcode.login": "メール/QRコードログイン >",
- "login.btn.login": "ログイン",
- "login.btn.signUp": "新規登録",
- "login.emailLogin.identity.credential.error": "メールアドレスの形式が正しくありません。\nご確認の上、もう一度入力してください。",
- "login.emailLogin.label.error.accountError": "メールアドレスまたはパスワードが間違っているかLINEに登録されていません。",
- "login.emailLogin.label.error.inputError": "メールアドレスまたはパスワードを入力していません。",
- "login.emailLogin.link.changeToNaverLogin": "네이버 로그인",
- "login.emailLogin.link.findPassword": "パスワードを忘れた場合",
- "login.emailLogin.placeHolder.email": "メールアドレス",
- "login.emailLogin.placeHolder.emailwithPhoneNumber": "メールアドレスまたは電話番号",
- "login.emailLogin.placeHolder.password": "パスワード",
- "login.emailLogin.popup.findPassword": "LINEアプリや携帯電話の「設定>アカウント> メールアドレス登録」から、\nメールアドレスまたはパスワードを変更することができます。\n\n\n\n",
- "login.error.auth.failed": "別のPCからログインしているか、\nログインの期限が切れているため、\n自動的にログインできませんでした。 ",
- "login.label.certificate.not.vaild": "セキュリティ証明書を適用することができません。PCの日付を正しく設定してください。",
- "login.label.doingLogin": "ログイン中...",
- "login.label.error.auth.failed.anotherPC": "別のPCからログインしているため、自動ログインできませんでした。",
- "login.label.error.auth.failed.loginExpired": "ログインの期限が切れたため、自動ログインできませんでした。",
- "login.label.error.dberror": "検知されたエラーを修復しました。もう一度ログインしてください。",
- "login.label.error.dormant.account": "スマートフォン版LINEに登録したメールアドレスでログインして、アカウント認証を行ってください。",
- "login.label.error.extraError": "一時的にログインできません。しばらくしてからもう一度お試しください。",
- "login.label.error.keyboardError": "入力モードを半角英数に切り替えてください",
- "login.label.error.networkError": "ログインできませんでした。ネットワーク接続を確認して、もう一度お試しください。",
- "login.label.error.pinCode": "認証番号が一致しません。もう一度お試しください。",
- "login.label.error.schemeError": "LINEにログインして、もう一度お試しください。",
- "login.label.error.serverError": "サーバーエラーが発生しました。しばらくしてからもう一度お試しください。",
- "login.label.error.serverMaintenance": "サーバーメンテナンス中です。しばらくしてからもう一度お試しください。",
- "login.label.error.verification.timeout": "認証番号の有効期間が終了しました。\n別の認証番号をリクエストしてください。",
- "login.label.searching.network": "最適化されたネットワーク環境を検索中です。",
- "login.loginwithsmartphone.tooltip": "スマートフォンで本人確認をしてログインできます",
- "login.naverLogin.checkbox.keepLoginStatus": "自動ログイン",
- "login.naverLogin.checkbox.startUpWin": "Windows起動時に自動実行",
- "login.naverLogin.label.error.inputError": "아이디/비밀번호를 입력하지 않았습니다.",
- "login.naverLogin.label.error.proxyError": "ログインできません。プロキシサーバーの設定を確認して、もう一度お試しください。",
- "login.naverLogin.link.changeToEmailLogin": "이메일 로그인",
- "login.naverLogin.link.findIDPassword1": "아이디/비밀번호 찾기",
- "login.naverLogin.link.findIDPassword2": "아이디/비밀번호 찾기",
- "login.naverLogin.placeHolder.naverID": "Naver ID",
- "login.naverLogin.placeHolder.password": "パスワード",
- "login.naverLogin.url.ID": "https://nid.naver.com/user/help.nhn?todo=idinquiry",
- "login.naverLogin.url.pass": "https://nid.naver.com/user/help.nhn?todo=pwinquiry",
- "login.otp.link.title": "OTP 도움말",
- "login.otp.link.url": "https://help.naver.com/support/contents/contents.nhn?serviceNo=532&categoryNo=1533",
- "login.password.ascii.error": "入力モードを半角英数に切り替えてください",
- "login.phoneNumberLogin.alert.info": "PC版LINEで登録したユーザーのみが電話番号でログインできます。",
- "login.phoneNumberLogin.alert.networkerror": "ネットワーク接続エラーにより リクエストが 完了していません。\nもう一度お試しください。",
- "login.phoneNumberLogin.identity.credential.error": "電話番号が正しくありません。入力内容に誤りがないか確認してください。",
- "login.phoneNumberLogin.label.country": "国を選択",
- "login.phoneNumberLogin.label.error.accountError": "電話番号またはパスワードが間違っているか、電話番号が登録されていません。",
- "login.phoneNumberLogin.label.error.inputError": "電話番号またはパスワードを入力していません。",
- "login.phoneNumberLogin.placeHolder.password": "パスワード",
- "login.phoneNumberLogin.placeHolder.phone": "電話番号",
- "login.phoneNumberLogin.placeHolder.search": "検索",
- "login.phoneNumberLogin.verification.desc": "セキュリティ対策のため、PCからの初回ログイン時に本人確認する必要があります。\nSMSで届いた認証番号を入力してください。SMSが届かない場合は、以下の方法を試してください。",
- "login.popup.abuse": "複数回ログインできなかったため、ログインが制限されています。QRコードでログインしてください。",
- "login.popup.error.diskFull": "ディスクの空き容量が1GB未満です。\n一部の機能が利用できないことがあります。",
- "login.popup.kickout.r0": "他のPCからログインした場合",
- "login.popup.kickout.r1": "一定時間何も入力されていない場合",
- "login.popup.kickout.r2": "モバイルからログアウトした場合",
- "login.popup.kickout.r3": "LINEアカウントを削除した場合",
- "login.popup.kickout.r4": "네이버를 탈퇴하거나 비밀번호를 변경한 경우",
- "login.popup.kickout.r5": "サーバーメンテナンスにより使用できない場合",
- "login.popup.kickout.subtitle": "次のような場合、ログアウトになります。",
- "login.popup.kickout.title": "LINEからログアウトされています。",
- "login.qrLogin.desc.error.expired": "QRコードの有効期限が切れました。\n更新アイコンをクリックして、新しいQRコードを作成してください。",
- "login.qrLogin.desc.error.network": "ネットワークエラーにより、QRコードを読み込めませんでした。\nネットワーク接続を確認して、もう一度お試しください。",
- "login.qrLogin.desc.howto": "スマートフォン版LINEで検索ボックス内のQRコードアイコンをタップし、このQRコードをスキャンしてください。",
- "login.qrLogin.title": "QRコードログイン",
- "login.register.already": "LINEユーザーログイン",
- "login.register.downloadLink": "LINEアプリをダウンロード>>",
- "login.register.help.desc": "LINEアプリで利用登録後、メールアドレスを登録すると、 PC版をご利用いただけます。\n",
- "login.register.help.desc1": "모바일 라인 앱에서 가입하고 네이버 아이디를 \n등록하면 PC버전을 사용할 수 있습니다.",
- "login.register.help.desc2": "LINEアプリで利用登録後、メールアドレスを登録すると、LINE Mac版をご利用いただけます。",
- "login.register.help.desc3": "모바일 라인 앱에서 가입하고 네이버 아이디를 \n등록하면 MAC버전을 사용할 수 있습니다.",
- "login.register.link.android": "https://play.google.com/store/apps/details?id=jp.naver.line.android&hl=ja",
- "login.register.link.iphone": "http://itunes.apple.com/jp/app/line/id443904275?ls=1&mt=8",
- "login.register.link.wphone": "http://www.windowsphone.com/ja-JP/store/app/line/a18daaa9-9a1c-4064-91dd-794644cd88e7",
- "login.register.newmember": "新規登録",
- "login.registration.password.reset": "パスワードを再設定",
- "login.simpleLogin.btn.updateQrCode": "QRコードを更新",
- "login.simpleLogin.label.desc.normal": "LINEアプリ内のQRコードリーダーまたは携帯電話のカメラでQRコードをスキャンするとログインできます。\n* このQRコードは、ログインにのみ使用できます。",
- "login.simpleLogin.label.error.cannot.refresh.too.frequently": "一度更新されたQRコードは、一定時間更新が\n制限されます。しばらくお待ち下さい。",
- "login.simpleLogin.label.error.qrcodeExpired": "QRコードの有効期限が切れました。QRコードを更新して下さい。",
- "login.simpleLogin.link.howto": "QRコードログインの方法",
- "login.tab.emailLogin": "メールログイン",
- "login.tab.naverLogin": "네이버 로그인",
- "login.tab.phoneNumberLogin": "電話番号ログイン >",
- "login.tab.phoneNumberLogin.title": "電話番号ログイン",
- "login.tab.simpleLogin": "QRコードログイン",
- "loginHelp.email.image.0": "images/ja-JP/01_main.png",
- "loginHelp.email.image.1": "images/ja-JP/02_email.png",
- "loginHelp.email.image.registration": "image://login/ja-JP/05_email.png",
- "loginHelp.emailLogin.label.step1": "LINEアプリの[設定> アカウント]をタップします。",
- "loginHelp.emailLogin.label.step2": "[アカウント]>[メールアドレス]からメールアドレスを登録します。",
- "loginHelp.emailLogin.label.tab.mobile": "スマートフォン版",
- "loginHelp.emailLogin.label.tab.pc": "PC版で新規登録した場合",
- "loginHelp.emailLogin.label.tab.pc.desc1": "メールアドレス登録後にメールログインが可能になります。\nメールアドレスは[設定]>[基本設定]で登録できます。",
- "loginHelp.emailLogin.label.tab.pc.desc2": "電話番号ログインとメールログインのパスワードは同じです。\nメールアドレスを入力してから、電話番号ログインのパスワードを入力してください。",
- "loginHelp.emailLogin.label.tab.pc.title1": "メールアドレス未登録の場合",
- "loginHelp.emailLogin.label.tab.pc.title2": "メールアドレス登録済みの場合",
- "loginHelp.emailLogin.label.title": "メールログインのヘルプ",
- "loginHelp.emailLogin.label.wap.step1": "LINEアプリの[設定]をタップします。",
- "loginHelp.emailLogin.label.wap.step2": "[設定] > [アカウント管理] > [アカウント連動設定]にて、メールアドレスの連動設定を行います。",
- "loginHelp.jp.email.tab0.text": "フィーチャーフォン版",
- "loginHelp.jp.email.tab1.text": "携帯電話",
- "loginHelp.jp.qrcode.tab0.text": "スマートフォン",
- "loginHelp.jp.qrcode.tab1.text": "携帯電話",
- "loginHelp.jp.wap.email.image.0": "images/ja-JP/03_jp_main.png",
- "loginHelp.jp.wap.email.image.1": "images/ja-JP/04_jp_setting.png",
- "loginHelp.jp.wap.qrcode.image.0": "images/ja-JP/07_wap_qr01.png",
- "loginHelp.jp.wap.qrcode.image.1": "images/ja-JP/08_wap_qr02.png",
- "loginHelp.naver.image.0": "images/ko-KR/01_main.png",
- "loginHelp.naver.image.1": "images/ko-KR/03_naver.png",
- "loginHelp.naverLogin.label.step1": "라인 앱의 [설정 > 계정]을 선택합니다.",
- "loginHelp.naverLogin.label.step2": "\"계정관리\"에서 \"네이버 아이디 등록\" 에서 네이버 아이디를 등록하면 등록한 네이버 아이디로 로그인을 할 수 있습니다.",
- "loginHelp.naverLogin.label.title": "네이버 아이디 등록",
- "loginHelp.qrcode.image.0": "images/ja-JP/05_app_qr01.png",
- "loginHelp.qrcode.image.1": "images/ja-JP/06_app_qr02.png",
- "loginHelp.qrcodeLogin.label.step1": "LINEアプリの「その他 >友だちの追加 > QRコード」よりQRコードをスキャンして下さい。",
- "loginHelp.qrcodeLogin.label.step2": "スキャンした後にLINEアプリで「ログイン」ボタンをタップすると、PCログインが可能です。",
- "loginHelp.qrcodeLogin.label.title": "QRコードログインの方法",
- "loginHelp.qrcodeLogin.label.wap.step1": "携帯電話のカメラでQRコードスキャンして下さい。",
- "loginHelp.qrcodeLogin.label.wap.step2": "スキャンした後に携帯電話の画面で「ログイン」ボタンを選択すると、PCログインが可能です。",
- "markdown.input.context.menu.bold": "太字",
- "markdown.input.context.menu.codeblock": "段落を強調",
- "markdown.input.context.menu.italic": "斜体",
- "markdown.input.context.menu.strikethrough": "取り消し線",
- "markdown.input.context.menu.wordblock": "テキストを強調",
- "markdown.input.guideline.bold": "*太字*",
- "markdown.input.guideline.codeblock": "```コードブロック```",
- "markdown.input.guideline.italic": "_斜体_",
- "markdown.input.guideline.strikethrough": "~取り消し線~",
- "markdown.input.guideline.wordblock": "`インラインコード`",
- "markdown.input.menu.help": "メッセージ書式とは?",
- "media.locale.font": "NanumGothic,나눔고딕,Malgun,맑은 고딕,맑은고딕,Dotum,Gulim,돋움,굴림",
- "media.msg.err.directx": "動画を再生するためにDirectX 9.0cのインストールが必要です。\n今すぐインストールしますか? ",
- "media.msg.err.expired": "保存期間が終了しているため、動画を再生できません。",
- "media.msg.err.network": "ネットワークやサーバーのエラーにより再生できません。\nもう一度お試しください。",
- "media.msg.err.transient": "一時的なエラーにより再生できません。\nもう一度お試しください。",
- "media.msg.tooltip.close": "閉じる",
- "media.msg.tooltip.minimize": "最小化",
- "media.msg.tooltip.pause": "一時停止",
- "media.msg.tooltip.play": "再生",
- "media.msg.tooltip.playspeed": "再生速度",
- "media.msg.tooltip.stop": "停止",
- "media.msg.tooltip.volume": "音量",
- "media.msg.tooltip.volume1": "音量",
- "media.video.full.screen.out": "全画面表示を終了するにはEscキーを押してください",
- "media.video.replay": "もう一度再生",
- "meeting.popup.end.body": "ミーティングから退出しますか?",
- "meeting.popup.end.button": "退出",
- "meeting.tooltip.end.call": "ミーティング\n退出",
- "menu.menubar.allNotification.off": "すべての通知をオフ",
- "menu.menubar.allNotification.on": "すべての通知をオン",
- "menu.menubar.friend.addFriend": "友だち追加",
- "menu.menubar.friend.makeGroup": "グループを作成",
- "menu.menubar.friend.title": "友だち",
- "menu.menubar.help.lineHelp": "ヘルプ",
- "menu.menubar.help.title": "ヘルプ",
- "menu.menubar.keepmemo": "Keepメモ",
- "menu.menubar.line.about": "LINE情報",
- "menu.menubar.line.exit": "終了",
- "menu.menubar.line.hideLine": "LINEを非表示",
- "menu.menubar.line.hideOthers": "他のアプリケーションを非表示",
- "menu.menubar.line.setting": "設定",
- "menu.menubar.line.showAll": "すべて表示する",
- "menu.menubar.line.title": "LINE",
- "menu.menubar.view.chat": "トーク",
- "menu.menubar.view.friend": "友だち",
- "menu.menubar.view.hub": "LINE HUB",
- "menu.menubar.view.myProfile": "プロフィール",
- "menu.menubar.view.myhome": "ホーム",
- "menu.menubar.view.openchat": "オープンチャット",
- "menu.menubar.view.services": "サービス",
- "menu.menubar.view.title": "表示",
- "menu.menubar.view.today": "LINE TODAY",
- "menu.menubar.view.voom": "LINE VOOM",
- "menu.menubar.window.bringToTopAll": "すべてを手前に移動",
- "menu.menubar.window.maximize": "拡大",
- "menu.menubar.window.minimize": "最小化",
- "menu.menubar.window.title": "ウィンドウ",
- "menu.setting.lockscreen": "ロックモード",
- "menu.toast.allNotification.off": "通知オン",
- "menu.toast.allNotification.on": "通知オフ",
- "menu.tray.about": "LINE情報",
- "menu.tray.balloon.login": "LINEにログインしました。",
- "menu.tray.balloon.logout": "LINEをログアウトしました",
- "menu.tray.check.update": "アップデートの確認",
- "menu.tray.exit": "終了",
- "menu.tray.keepmemo": "Keepメモ",
- "menu.tray.login": "ログイン",
- "menu.tray.logout": "ログアウト",
- "menu.tray.setting": "設定",
- "menu.tray.showBuddyList": "友だちリスト",
- "message.context.background": "背景デザインに設定",
- "message.context.cancel.imageselect": "写真の選択を解除",
- "message.context.imageselect": "写真を選択",
- "message.delete.confirm": "選択したメッセージはこの端末上でのみ削除されます。相手側のメッセージは削除されません。",
- "message.error.invalidfile": "ダウンロードした更新ファイルが破損しています。",
- "message.error.opensetup": "ダウンロードしたアップデートファイルを開くことができませんでした。",
- "message.error.opensetup.codesign": "ダウンロードした更新ファイルが破損しているため、実行することができません。",
- "message.error.update": "アップデートが中断されています。",
- "message.error.updateurl": "アップデートのURL取得ができません。",
- "msgbox.alert.font.exist": "このフォントはすでに適用されています。",
- "msgbox.alert.nospace": "端末のディスク容量が不足しています。使用していないアプリや写真、動画を削除して容量を確保してください。",
- "msgbox.alert.resolution.apply": "解像度を変更するにはLINEを再起動する必要があります。今すぐ再起動しますか?",
- "msgbox.btn.block": "ブロック",
- "msgbox.btn.buddy.title": "追加された友だちの確認",
- "msgbox.btn.cancel.title": "キャンセル",
- "msgbox.btn.cancelInvite.no": "いいえ",
- "msgbox.btn.cancelInvite.yes": "はい",
- "msgbox.btn.close.title": "閉じる",
- "msgbox.btn.delete": "削除",
- "msgbox.btn.download.title": "ダウンロード",
- "msgbox.btn.fileOpen": "ファイルを開く",
- "msgbox.btn.gotosettings": "設定に移動",
- "msgbox.btn.hide": "非表示",
- "msgbox.btn.install.title": "ダウンロード",
- "msgbox.btn.later.title": "今はしない",
- "msgbox.btn.leave.1.n": "退出",
- "msgbox.btn.leave.group": "退会",
- "msgbox.btn.lock.enable": "オンにする",
- "msgbox.btn.lock.start": "オンにする",
- "msgbox.btn.no.title": "キャンセル",
- "msgbox.btn.nocancel.title": "いいえ",
- "msgbox.btn.ok.title": "OK",
- "msgbox.btn.post.title": "投稿",
- "msgbox.btn.qrcode.title": "QRコードログイン",
- "msgbox.btn.quit.title": "終了",
- "msgbox.btn.remove": "削除",
- "msgbox.btn.restart": "再起動",
- "msgbox.btn.retry.title": "再試行",
- "msgbox.btn.send": "送信",
- "msgbox.btn.sendkey.title": "設定する",
- "msgbox.btn.sendshare": "送信",
- "msgbox.btn.unsend": "送信取消",
- "msgbox.btn.update.title": "今すぐアップデート",
- "msgbox.btn.use": "同意",
- "msgbox.btn.yes.title": "OK",
- "msgbox.btn.yescontinue.title": "はい",
- "msgbox.btn.yesleave.title": "はい",
- "msgbox.desc.seemore": "詳細を見る",
- "msgbox.error.request.popup.desc": "一時的なエラーが発生しました。しばらくしてからもう一度お試しください。",
- "needqr.login.button.label": "QRコードログイン",
- "needqr.title.content1": "他人によるアカウント悪用を防止するため、\n初めてログインするマシンではQRコードログインが必要です。",
- "needqr.title.label": "QRコードでログインしてください。",
- "note.save.comfirm.desc": "「%1」のノートに保存しますか?",
- "notificationcenter.timeslot.earlier": "以前",
- "notificationcenter.timeslot.recent": "新着",
- "notificationcenter.title": "新着",
- "nx.textbox.copy": "コピー",
- "nx.textbox.paste": "ペースト",
- "nx.textbox.selectall": "すべて選択",
- "oa.profile.desc.region.notselected": "未確認",
- "oa.profile.investmentfraud": "LINEを悪用した詐欺にご注意ください。",
- "ocr.policy.agree.btn": "同意 ",
- "ocr.policy.disagree.btn": "同意しない",
- "ocr.progress.desc.scan": "文字を検出しています…",
- "ocr.progress.desc.translate": "翻訳しています…",
- "openchat.allthreads.desc.nothreads": "このオープンチャットで作成されたすべてのスレッドが表示されます。",
- "openchat.allthreads.title.nothreads": "このオープンチャットはスレッドがありません",
- "openchat.chatlist.popup.deletechat": "このトークルームをトークリストから削除しますか?オープンチャットのトーク一覧からは削除されません。",
- "openchat.chatlist.popup.hidechat": "このトークルームをトークリストで非表示にしますか?オープンチャットのトーク一覧では表示されます。",
- "openchat.favoritethreads.title.nothreads": "お気に入りのスレッドはありません",
- "openchat.hidemessages.desc.hidethismember": "このメンバーが今後送信するメッセージを非表示にしますか?サブトークルームを含むオープンチャットで非表示になり、今まで送信したメッセージは非表示になりません。",
- "openchat.hidemessages.desc.maximumhide": "メッセージを非表示にできるメンバー数の上限を超えました。ほかのメンバーのプロフィールからメッセージを再表示してもう一度お試しください。",
- "openchat.hidemessages.desc.messageshidden": "このメンバーが今後送信するメッセージが表示されなくなりますメンバーのプロフィールから再表示できます。",
- "openchat.join.button.requestjoin": "参加リクエスト",
- "openchat.linkpopup.desc.donotshowformonth": "1カ月間表示しない",
- "openchat.readallthreads.desc.markallasread": "すべてのスレッドメッセージを既読にしますか?",
- "openchat.settings.desc.mentioneveryone": "メンバー全員をメンション(@All)",
- "openchat.thread.desc.fewerthan10": "10件未満のメッセージ",
- "openchat.thread.desc.sendafiletothread": "スレッドにファイルを送信",
- "openchat.thread.desc.updateline": "LINEをアップデートすると確認できます",
- "openchat.thread.placeholder.expired": "期限が過ぎたためメッセージを追加できません",
- "openchat.thread.tooltip.yourthreadicon": "このオープンチャットのすべてのスレッドやお気に入りのスレッドを確認できます",
- "openchat.threadpopup.desc.expired": "スレッドの期限が過ぎました。マイスレッドに追加・削除できません。",
- "openchat.threadpopup.desc.expirederror": "スレッドの期限が過ぎました。",
- "openchat.threadpopup.desc.unsupported": "スレッドでサポートされていない形式のファイルが含まれています。",
- "openchat.threads.button.readall": "すべて既読",
- "openchat.threads.button.seemessages": "メッセージを見る",
- "openchat.threads.tab.all": "すべて",
- "openchat.threads.tab.favorites": "お気に入り",
- "openchat.threads.title.threads": "スレッド",
- "openchat.threads.tooltip.messagewontsend": "スレッド内のメッセージはトークルームには表示されません",
- "openchat.threadspopup.button.cancel": "キャンセル",
- "openchat.threadspopup.button.delete": "削除",
- "openchat.threadspopup.button.unsend": "送信取消",
- "openchat.threadspopup.desc.deleterootmessage": "スレッドがメンバー全員のトーク履歴から削除されます。",
- "openchat.threadspopup.desc.unsendrootmessage": "送信を取り消すとすべてのスレッド内のメッセージが削除されます。",
- "openchat.threadspopup.title.deleterootmessage": "このメッセージを削除しますか?",
- "openchat.threadspopup.title.unsendrootmessage": "このメッセージの送信を取り消しますか?",
- "openchat.unhidemessages.desc.unhidden": "このメンバーが今後送信するメッセージが表示されます。",
- "openchat.unhidemessages.desc.unhide": "このメンバーが今後送信するメッセージを再表示しますか?今まで非表示になっていたメッセージは再表示されません。",
- "openchat.userprofile.button.hidemessages": "メッセージを非表示",
- "openchat.userprofile.button.unhidemessages": "メッセージを再表示",
- "openchat.yourthread.button.seemessages": "メッセージを見る",
- "openchat.yourthread.desc.fewerthan10": "10件未満のメッセージ",
- "openchat.yourthreads.button.readmore": "スレッドの詳細を見る",
- "openchat.yourthreads.desc.newthreadmessages": "スレッド内の新しいメッセージ",
- "openchat.yourthreads.desc.photosent": "写真を送信しました。",
- "openchat.yourthreads.desc.stickersent": "スタンプを送信しました。",
- "openchat.yourthreads.desc.videosent": "動画を送信しました。",
- "openchat.yourthreads.desc.vmsent": "ボイスメッセージを送信しました。",
- "openchat.yourthreads.title.messageunavailable": "このメッセージはありません。",
- "openchat.yourthreadspopup.button.ok": "OK",
- "openchat.yourthreadspopup.desc.threaddeleted": "削除されたスレッドです。",
- "os.msgbox.btn.gotosettings": "システム環境設定",
- "pl.square.setting.tooltip": "スクエアで投票を作成および削除する権限を設定できます",
- "poll.create.title": "投票を作成",
- "poll.edit.title": "投票を編集",
- "poll.main.title": "投票",
- "poll.ongoing.title": "投票する",
- "poll.result.title": "投票結果",
- "poll.votedcount.title": "%1 (%2)",
- "popup.plugin.failed.retry": "ダウンロードできませんでした。もう一度お試しください。",
- "power.label.tootip": "LINEを閉じる",
- "profile.btn.chat.tooltip": "トーク",
- "profile.btn.home.tooltip": "ホーム",
- "profile.btn.recommend.tooltip": "おすすめ",
- "profile.button.investmentfraudwarning": "LINEを悪用した詐欺にご注意ください。",
- "profile.delete": "プロフィール画像を削除",
- "profile.desc.birthday": "M/d",
- "profile.desc.onediting": "編集内容を保存せずに画面を閉じますか?",
- "profile.desc.timelineposts": "LINE VOOM投稿",
- "profile.edit.background.color": "背景の色を選択",
- "profile.edit.font.color": "フォントの色を選択",
- "profile.edit.placeholder": "テキストを入力",
- "profile.friendsnameedit.desc.namesetbyfriend": "友だちが設定した名前:%1",
- "profile.popup.report": "通報",
- "profile.seemoremenu.button.block": "ブロック",
- "profile.select.capture": "画面キャプチャ",
- "profile.select.default": "デフォルト画像から選択",
- "profile.select.local": "使用中のPCから選択",
- "profile.select.text": "テキストプロフィール",
- "profile.socialprofile.menutitle.editprofile": "プロフィール設定",
- "registration.btn.label.resendPin": "認証番号再送信",
- "registration.btn.message.resendPin": "認証番号を再送信しました。",
- "registration.check.age.ageVerification.body": "この機能を利用するには年齢確認が必要です。\nスマートフォン版LINEの[設定]>[年齢確認]から年齢確認を行ってください。",
- "registration.check.age.ageVerification.title": "年齢確認",
- "registration.check.age.ageunder.body": "18歳以上と確認できた方のみ、この機能をご利用できます。",
- "registration.check.age.error.loadUrl": "接続できませんでした。インターネット接続を確認してもう一度お試しください。",
- "registration.check.age.error.retrieveRequest": "年齢確認中にエラーが発生しました。もう一度お試しください。",
- "registration.check.age.underAge": "友だち検索の機能を利用するには、スマートフォン版LINEで年齢確認(18歳以上)を行う必要があります。なお、スマートフォン版LINEでは相手のQRコードをスキャンして友だちに追加することも可能です。",
- "registration.code.phone.call": "通話による認証",
- "registration.code.phone.guide": "認証番号を電話にてお知らせします。\nまた、発信者番号が非表示になる\n場合や、ご契約のプランによっては\n着信料金がかかる場合があります。",
- "registration.code.sms.resent.guide": "認証番号は%1分%2秒後に再送信できます。\n",
- "registration.common.next": "次へ",
- "registration.common.underIE8.alert": "新規登録はInternet Explorer 8以降で行えます。\nInternet Explorerをアップデートするか、スマートフォン版から新規登録してください。",
- "reply.doubleclick.toast": "リプライするにはメッセージをダブルクリックしてください ",
- "reply.error.toast": "元のメッセージはありません",
- "reply.goto.replied": "元のメッセージに戻る",
- "reply.no.original.message": "元のメッセージはありません",
- "reply.unknown.user": "不明なユーザー",
- "report.btn.agreeandsend": "同意して送信",
- "report.btn.agreeandsend.thpdpa": "承認して送信",
- "report.confirm.groupinvitation": "あなたをグループに招待したユーザーを通報すると、そのグループトークの情報がLINEに送信されます。",
- "report.desc.reason": "通報する理由を選択してください",
- "report.desc.title": "通報",
- "report.done": "通報しました",
- "report.done.suggestBlock": "通報しました。\nこのユーザーをブロックしますか?",
- "report.done.suggestBlock.groupinvitation": "%1をブロックしますか?",
- "report.note.subTitle": "この投稿を通報します\n(作成者:%1)",
- "report.popupbutton.impersonation.decline": "スキップ",
- "report.popupbutton.impersonation.proceed": "記入する",
- "report.reason.Other": "その他",
- "report.reason.gender": "性的いやがらせ / 出会い目的",
- "report.reason.harrassment": "迷惑行為",
- "report.reason.impersonation": "なりすまし",
- "report.reason.impersonation.inquirypopup": "なりすましに関する調査のため、詳細情報の記入をお願いしております。\nお問い合わせフォームに移動して内容を記入しますか?",
- "report.reason.scam": "詐欺",
- "report.reason.spam": "スパム / 宣伝目的",
- "requireinvite.popup.button.cancel": "キャンセル",
- "requireinvite.popup.button.confirmon": "オフにする",
- "requireinvite.popup.desc.onewaywarning": "この設定をオンにすると、あとでオフにすることはできません。",
- "requireinvite.popup.title.onewaywarning": "[友だちにグループへの参加を確認]をオンにしますか?",
- "requireinvite.toggle.desc": "友だちをグループに招待する際に、グループに参加するかどうかを選んでもらうことができます。",
- "requireinvite.toggle.title": "友だちにグループへの参加を確認",
- "screen.desc.need.os.recordscreen": "ビデオ通話中に画面キャプチャや画面シェアを利用するには、画面収録へのアクセスをLINEに許可してください。",
- "screenshare.desc.need.os.recordscreen": "画面をシェアできません。画面収録へのアクセスをLINEに許可してください。",
- "screenshare.ongoing.error": "この機能は画面シェア中は利用できません",
- "screenshare.ongoing.user": "画面をシェアしています",
- "search.defaultView.doYouRemoveAllRecentSearchKeywords": "最近の検索をすべて削除しますか?",
- "search.defaultView.doYouUseSaveSearchKeyword": "「最近の検索」機能を有効にしますか?",
- "search.defaultView.dontYouUseSaveSearchKeyword": "「最近の検索」機能をオフにしますか?",
- "search.defaultView.offSaveSearchKeyword": "自動保存を無効にする",
- "search.defaultView.onSaveSearchKeyword": "自動保存を有効にする",
- "search.defaultView.recentSearchKeyword": "最近の検索",
- "search.defaultView.recentSearchKeywordEmpty": "最近の検索履歴はありません。",
- "search.defaultView.removeAllRecentSearchKeywords": "すべて削除",
- "search.defaultView.saveSearchKeywordOff": "「最近の検索」機能が無効になっています。",
- "select.video.error.ratio": "登録できない縦横比のファイルです",
- "service.download.done.popup.desc": "ダウンロードが完了しました。",
- "service.download.inprogress.popup.desc": "%1を\nダウンロードしています…",
- "service.install.device.done.popup.desc": "インストールが完了しました。",
- "service.install.device.popup.desc": "%1を\nインストールしています…",
- "service.install.popup.desc": "%1の機能を利用するには、%2をインストールする必要があります。インストールファイルをダウンロードしますか?",
- "setting.advancedSetting": "詳細設定",
- "setting.advancedSetting.proxy.apply": "適用する",
- "setting.advancedSetting.proxy.apply.disabled": "プロキシ設定を無効にしました。",
- "setting.advancedSetting.proxy.apply.enabled": "プロキシ設定を有効にしました。",
- "setting.advancedSetting.proxy.check": "プロキシを確認",
- "setting.advancedSetting.proxy.complete": "プロキシサーバーを利用できます。",
- "setting.advancedSetting.proxy.connect.check": "プロキシサーバーを経由して接続をテスト中...",
- "setting.advancedSetting.proxy.fail": "プロキシ経由で接続できません。\nプロキシの設定を確認して、もう一度お試しください。",
- "setting.advancedSetting.proxy.fail.protocol": "プロキシプロトコルエラー: %1",
- "setting.advancedSetting.proxy.fail.verifyUser": "ユーザーを認証できませんでした。",
- "setting.advancedSetting.proxy.host": "ホスト",
- "setting.advancedSetting.proxy.port": "ポート",
- "setting.advancedSetting.proxy.protocol": "プロトコル",
- "setting.advancedSetting.proxy.protocol.check": "プロトコルを確認中...",
- "setting.advancedSetting.proxy.responseTime": "(遅延時間: %1ms)",
- "setting.advancedSetting.proxy.server": "サーバー",
- "setting.advancedSetting.proxy.server.check": "プロキシサーバーを確認中...",
- "setting.advancedSetting.proxy.title": "プロキシ",
- "setting.advancedSetting.proxy.use": "プロキシサーバーを有効にする",
- "setting.advancedSetting.proxy.verification": "プロキシ認証を有効にする",
- "setting.advancedSetting.proxy.verification.id": "ユーザー名",
- "setting.advancedSetting.proxy.verification.pw": "パスワード",
- "setting.advancedSetting.sync": "同期",
- "setting.advancedSetting.sync.completed": "同期が完了しました。",
- "setting.advancedSetting.sync.desc": "友だちリストとトークリストを最新の状態に同期します。",
- "setting.advancedSetting.sync.error.interval": "同期は%1分間隔で実行されます。\nしばらくしてからもう一度お試しください。",
- "setting.advancedSetting.sync.error.network": "ネットワークエラーにより同期できません。\nインターネット接続を確認してください。",
- "setting.advancedSetting.sync.inprogress": "同期しています...\nしばらくお待ちください。",
- "setting.advancedSetting.sync.time": "yyyy.M.d %1 h:mm",
- "setting.advancedSetting.sync.title": "データを同期",
- "setting.alarm.name": "通知サウンド%1",
- "setting.basic.font.apply.alert": "フォントを変更するにはLINEを再起動する必要があります。今すぐ再起動しますか?",
- "setting.basic.heading.language": "言語",
- "setting.basic.language.apply.alert": "言語を変更するにはLINEを再起動する必要があります。今すぐ再起動しますか?",
- "setting.basic.language.apply.desc": "終了後に再起動すると適用されます。",
- "setting.basic.language.apply.no": "後でする",
- "setting.basic.language.apply.yes": "今変更する",
- "setting.btn.select.folder": "選択",
- "setting.btn.submit": "OK",
- "setting.call.blur": "背景エフェクト",
- "setting.call.call.incomingnoti": "着信時に通知で表示",
- "setting.call.camera": "カメラ",
- "setting.call.defaultMike": "システム設定と同じ",
- "setting.call.defaultSpeaker": "システム設定と同じ",
- "setting.call.desc.deviceloading": "読み込み中…",
- "setting.call.ducking": "ほかのアプリケーションの音量",
- "setting.call.grouphd": "高画質グループビデオ通話",
- "setting.call.grouphd.desc": "グループビデオ通話をHD画質で利用できます。オンにした場合、通話中にPCへの負荷とメモリの使用量が増加します。",
- "setting.call.grouphd.desc.forwin": "端末の動画コーデックを使用して、グループビデオ通話をHD画質で利用できます。オンにした場合、通話中にPCへの負荷とメモリの使用量が増加します。",
- "setting.call.handsfreebtinfo.desc": "スピーカーとマイクが内蔵されているBluetoothデバイスを使用する場合は、スピーカーとマイクを同じオーディオデバイスに設定してください。",
- "setting.call.label.duckingGuide": "LINE以外のアプリケーションの音量を調節することで、通話中の音声がより聞こえやすくなります。100%に設定すると、ほかのアプリケーションの音声がオフになります。",
- "setting.call.mic.desc.noisecancelinglight": "外で流れている音楽やコンピューターのファンの音ほどのノイズを打ち消します。",
- "setting.call.mic.desc.noisecancelingstrong": "キーボードのタイプ音や犬の鳴き声ほどのノイズを打ち消します。",
- "setting.call.mic.echocancelling": "エコーキャンセリング",
- "setting.call.mic.echocancelling.desc": "あなたのオーディオデバイスによって発生するエコーを除去することで、音声がよりクリアに伝わります。PCの音声を相手に共有する時は、この機能をオフにしてください。",
- "setting.call.mic.echocancelling.mouseovertooltip": "[最適]では一般的なエコーが除去されます。[最大]ではほとんどのエコーが除去されますが、複数人が同時に発言するとあなたの音声が途切れる場合があります。",
- "setting.call.mic.echocancelling.option1": "最適",
- "setting.call.mic.echocancelling.option2": "最大",
- "setting.call.mic.menu.noisecancelinglight": "弱",
- "setting.call.mic.menu.noisecancelingstrong": "強",
- "setting.call.mic.noisecanceling": "ノイズキャンセリング",
- "setting.call.mic.noisecanceling.checkbox": "ノイズキャンセリングをオン",
- "setting.call.mic.noisecanceling.desc": "あなたの周囲の騒音を除去することで、音声がよりクリアに伝わります。",
- "setting.call.mike": "マイク",
- "setting.call.mike.autoVolume": "音量の自動設定",
- "setting.call.msg.noCamera": "カメラが接続されていません。\n接続状態を確認して、もう一度お試しください。",
- "setting.call.msg.noMike": "マイクが接続されていません。\n接続状態を確認して、もう一度お試しください。",
- "setting.call.msg.noSpeaker": "スピーカーが接続されていません。\n接続状態を確認して、もう一度お試しください。",
- "setting.call.noDevice": "接続されていません",
- "setting.call.speaker": "スピーカー",
- "setting.call.videocall": "ビデオ",
- "setting.call.videocall.HWvideocodec": "端末の動画コーデックを使用",
- "setting.call.videocall.HWvideocodec.desc": "端末に内蔵された動画コーデックを使用すると、バッテリーの過度な消耗や発熱を防げます。一部の端末ではこの機能がサポートされていないため、ビデオ通話中に問題がある場合はオフにしてください。",
- "setting.call.videocall.HWvideocodec.popup.desc": "設定の変更は次回の通話から適用されます。今すぐ変更を適用するには、通話を終了してからもう一度開始してください。",
- "setting.call.videocall.dynamicspeaking": "発言中のユーザーを常に表示",
- "setting.call.videocall.dynamicspeaking.desc": "フォーカスビューでは発言中のユーザーの映像がフォーカス画面に大きく表示され、グリッドビューでは参加者リストの最初のページに表示されます。",
- "setting.call.videocall.gridviewmaxdisplay": "最大49人の参加者を1つの画面に表示",
- "setting.call.videocall.gridviewmaxdisplay.desc": "最大49人の参加者の映像が1つの画面にまとめて表示されます。",
- "setting.call.videocall.gridviewmaxdisplay.tooltip": "ヘルプをご確認ください。]]>",
- "setting.call.videocall.screenshare.alarmoff": "全画面表示で画面シェア中は通知をオフ",
- "setting.call.videocall.showpreview": "ビデオ通話に参加する前にカメラのプレビューを確認",
- "setting.call.voicesettings": "オーディオ",
- "setting.call.youtube.clipboard": "YouTubeリンクの自動ペースト",
- "setting.call.youtube.clipboard.checkbox": "クリップボードへのアクセスを許可",
- "setting.call.youtube.clipboard.desc": "YouTubeの画面シェア時に、クリップボードにコピーされている動画リンクが自動で検索ボックスにペーストされます。",
- "setting.chats.deletedata.chatHisotry.btn.all": "すべての端末",
- "setting.chats.deletedata.chatHisotry.btn.onlypc": "このPCのみ",
- "setting.chats.deletedata.chatHisotry.desc": "トーク履歴を削除する端末を選択してください。削除すると元に戻すことはできません。",
- "setting.chats.deletedata.chatHisotry.title": "すべてのトーク履歴 ",
- "setting.default.font.label": "既定フォント",
- "setting.desc.removeLocalChat": "すべてのトーク履歴が削除されます。",
- "setting.hiddenchat.empty": "非表示にしているトークルームはありません",
- "setting.hiddenchat.title": "非表示リスト",
- "setting.keep.alert.deleteAll": "すべてのコンテンツを削除しますか?Keepメモのコンテンツは削除されません。",
- "setting.keep.btn.deleteAll": "すべて削除",
- "setting.keep.desc.dataonlyincludesitemsinkeep": "Keepに保存したコンテンツのサイズのみが表示されます。Keepメモのサイズは含まれません。",
- "setting.keep.desc.photos": "写真",
- "setting.keep.desc.text": "テキスト",
- "setting.keep.desc.videos": "動画",
- "setting.keyword.add.error.character": "」、「<」、スペースは使用できません。]]>",
- "setting.keyword.add.error.characterDup": "このキーワードはすでに存在します。",
- "setting.keyword.add.error.characterSize": "キーワードは2文字以上にしてください。",
- "setting.keyword.added": "キーワード数",
- "setting.keyword.btn.add": "キーワード追加",
- "setting.keyword.desc": "指定したキーワードが未読メッセージに含まれている場合に通知されます。",
- "setting.keyword.title": "キーワード通知",
- "setting.label.basic.alarmMode": "通知方法",
- "setting.label.basic.alarmMode.showAlarm": "ポップアップ",
- "setting.label.basic.alarmMode.soundAlarm": "サウンド",
- "setting.label.basic.alarmRule": "通知ルール",
- "setting.label.basic.alarmRule.groupInviteAlarm": "グループへの招待時および新規メンバー参加時に通知",
- "setting.label.basic.alarmRule.mention": "自分がメンションされると通知",
- "setting.label.basic.alarmRule.newChatAlarm": "新しいメッセージ受信時に通知",
- "setting.label.basic.alarmRule.noFullScreenAlarm": "全画面表示の場合は通知をオフ",
- "setting.label.basic.alarmRule.noMobileAlarmWhileUsingPC": "PC版を使用している場合はスマートフォン版への通知をオフ\n※PC版でロックモードがオンの場合、または3分以上使用されていない場合は通知を再開",
- "setting.label.basic.alarmRule.note": "ノート通知",
- "setting.label.basic.alarmRule.videocal": "音声・ビデオ通話中はサウンドによる通知をオフ",
- "setting.label.basic.alarmSound": "通知サウンド",
- "setting.label.basic.alarmtype": "通知タイプ",
- "setting.label.basic.alarmtype.basic": "デフォルト",
- "setting.label.basic.font": "フォントの 設定",
- "setting.label.basic.font.desc": "フォントの設定はトークルームにのみ適用されます。",
- "setting.label.basic.font.extraLarge": "特大",
- "setting.label.basic.font.extraLarge.size": "16",
- "setting.label.basic.font.large": "大",
- "setting.label.basic.font.large.size": "14",
- "setting.label.basic.font.name": "フォント",
- "setting.label.basic.font.normal": "普通",
- "setting.label.basic.font.normal.size": "12",
- "setting.label.basic.font.normal.size.mac": "13",
- "setting.label.basic.font.size": "サイズ",
- "setting.label.basic.font.small": "小",
- "setting.label.basic.font.small.size": "11",
- "setting.label.basic.send.key": "送信方法",
- "setting.label.private.profile.propertyName.id": "(IDの情報は非公開です。)",
- "setting.label.title": "設定",
- "setting.lockscreen": "ロックモード",
- "setting.lockscreen.time.15minutes": "15分後",
- "setting.lockscreen.time.1hour": "1時間後",
- "setting.lockscreen.time.30minutes": "30分後",
- "setting.lockscreen.time.3hours": "3時間後",
- "setting.lockscreen.time.3minutes": "3分後",
- "setting.lockscreen.time.5minutes": "5分後",
- "setting.lockscreen.turn.on": "PCを使用していない場合はロックモードをオン",
- "setting.maintab.alarm": "通知",
- "setting.maintab.basicSetting": "基本設定",
- "setting.maintab.call": "通話",
- "setting.maintab.chat": "トーク",
- "setting.maintab.contact": "友だち管理",
- "setting.maintab.privacy": "プライバシー管理",
- "setting.maintab.profile": "プロフィール",
- "setting.maintab.talk": "トーク・通話",
- "setting.messengerView.allinone.desc": "リストの右側にトークルームが表示されます。",
- "setting.messengerView.allinone.label": "同じウィンドウで開く",
- "setting.messengerView.apply.alert": "トークルームの表示方法を変更すると、開いているトークルームはすべて閉じられます。\nよろしいですか?\n",
- "setting.messengerView.label": "トークルームの表示オプション",
- "setting.messengerView.seperate.desc": "トークルームが別のウィンドウで表示されます。",
- "setting.messengerView.seperate.label": "別のウィンドウで開く",
- "setting.popup.private.emptyName": "一文字以上入力して下さい。",
- "setting.popup.private.tooLongName": "名前は20文字まで入力が可能です。",
- "setting.shorcut.chatfolder.move": "フォルダーを移動",
- "setting.shorcut.desc.chatfolder": "トークフォルダー",
- "setting.shorcut.list.previous.chat": "前のトークに戻る",
- "setting.shorcut.list.search": "検索",
- "setting.shortcut.array.window": "トークの並べ替え",
- "setting.shortcut.callnlive.audio": "マイクをオン/オフ",
- "setting.shortcut.callnlive.video": "カメラをオン/オフ",
- "setting.shortcut.cancel.array.window": "トークの並べ替えを解除",
- "setting.shortcut.capture.copy": "コピー",
- "setting.shortcut.capture.draw.straight": "直線・正方形・円形を描く",
- "setting.shortcut.capture.fix": "キャプチャ範囲を調整",
- "setting.shortcut.capture.redo": "やり直す",
- "setting.shortcut.capture.save": "保存",
- "setting.shortcut.capture.undo": "取り消し",
- "setting.shortcut.chat.newline": "メッセージの改行",
- "setting.shortcut.chat.open.keep": "Keepを開く",
- "setting.shortcut.chat.screen.capture": "画面キャプチャ",
- "setting.shortcut.close.window": "ウィンドウを閉じる",
- "setting.shortcut.lable": "ショートカット",
- "setting.shortcut.list.basic": "基本",
- "setting.shortcut.list.callnlive": "通話",
- "setting.shortcut.list.chat": "トーク",
- "setting.shortcut.list.friend.chat": "友だち・トークリスト",
- "setting.shortcut.list.viewer": "コンテンツビューアー",
- "setting.shortcut.markdown.bold": "太字",
- "setting.shortcut.markdown.codeblock": "段落を強調",
- "setting.shortcut.markdown.italic": "斜体",
- "setting.shortcut.markdown.strikethrough": "取り消し線",
- "setting.shortcut.markdown.title": "メッセージ書式",
- "setting.shortcut.markdown.wordblock": "テキストを強調",
- "setting.shortcut.min.window": "ウィンドウを最小化",
- "setting.shortcut.move.add.friend": "友だち追加タブに移動",
- "setting.shortcut.move.bottom": "一番下に移動",
- "setting.shortcut.move.chat.list": "トークタブに移動",
- "setting.shortcut.move.friend.list": "友だちタブに移動",
- "setting.shortcut.move.top": "一番上に移動",
- "setting.shortcut.on.lock": "ロックモードをオン",
- "setting.shortcut.open.keep": "Keepを開く",
- "setting.shortcut.open.note": "ノートを開く",
- "setting.shortcut.open.sticker": "スタンプのウィンドウを開く",
- "setting.shortcut.open.tip": "ショートカットのヘルプを開く",
- "setting.shortcut.open.window": "新しいウィンドウで開く",
- "setting.shortcut.photo.copy": "ファイルをコピー",
- "setting.shortcut.photo.save": "ファイルを保存",
- "setting.shortcut.screen.chapture": "画面キャプチャ",
- "setting.shortcut.search": "検索",
- "setting.shortcut.send.file": "ファイルを送信",
- "setting.shortcut.timeline.comment": "コメントを入力",
- "setting.shortcut.timeline.like": "いいね",
- "setting.shortcut.timeline.like.pick": "表情を選択",
- "setting.shortcut.tip": "便利なショートカットが利用できます。",
- "setting.shortcut.video.jump": "動画を5秒早送り/巻き戻し",
- "setting.shortcut.videongif.stop": "再生/一時停止",
- "setting.shortcut.viewer.fullscreen": "全画面で表示",
- "setting.shortcut.volume.control": "動画の音量を上げる/下げる",
- "setting.shortcut.zoominout": "写真を拡大/縮小",
- "setting.tab.download.folder": "ファイル保存先",
- "setting.tab.file.trans": "受信ファイル",
- "setting.tab.login": "ログイン",
- "setting.tab.url.preview": "URLプレビュー",
- "setting.tab.voip": "通話",
- "setting.talk.animation.gif": "アニメーションGIF",
- "setting.talk.animation.gif.play": "トークルーム内のアニメーションGIFを自動再生",
- "setting.talk.backgroundSetting.apply": "選択した背景をすべてのトークに適用します。\nよろしいですか?",
- "setting.talk.backgroundSetting.apply.allChats": "すべてのトークルームに適用する",
- "setting.talk.backgroundSetting.detail": "すべてのトークに適用する背景を選択してください(オープンチャットは除く)。",
- "setting.talk.backgroundSetting.selected": "背景を選択",
- "setting.talk.backgroundSetting.title": "トーク背景",
- "setting.talk.heading.talk": "トーク",
- "setting.talk.photo.resolution.detail": "20MBを超える写真は、オリジナルの解像度で送信できません。",
- "setting.talk.photo.resolution.option.default": "デフォルト",
- "setting.talk.photo.resolution.option.original": "オリジナル ",
- "setting.talk.photo.resolution.option.standard": "標準",
- "setting.talk.photo.resolution.title": "写真の解像度",
- "setting.talk.theme.check.seasonal": "スノー効果",
- "setting.talk.theme.desc.seasonal": "着せかえ",
- "setting.theme.desc.darkmode.limitation": "一部の画面ではダークモードを利用できません。",
- "setting.theme.mode.dark": "ダークモード",
- "setting.theme.mode.light": "ライトモード",
- "setting.theme.systemSetting": "システム設定と同期",
- "setting.theme.title": "画面表示モード",
- "setting.url.preview.desc": "トークルームでURLのサムネイルと内容をプレビュー",
- "setting.window.scaleRatio": "画面サイズ",
- "setting.window.scaleRatio.default": "ディスプレイに基づく基本サイズ",
- "settingAlarm.label.duration": "時間",
- "settingAlarm.label.lucid": "グレー",
- "settingAlarm.label.opacity": "透過性",
- "settingAlarm.label.opaque": "濃く",
- "settingAlarm.label.setAlarmWindow": "アラート設定",
- "settingAlarm.label.toastContent": "内容",
- "settingAlarm.label.toastPreview": "ポップアップでメッセージ内容を表示",
- "settingAlarm.label.unitSecond": "秒",
- "settingLogin.alert.autoLogin": "自動ログインがオンになっています。オフにするには[設定]から行えます。",
- "settingLogin.check.autoLogin": "自動ログイン",
- "settingLogin.check.autoRunWin": "Windows起動時に自動実行",
- "settingPrivacy.btn.ublockBuddy": "ブロック解除",
- "settingPrivacy.call.blur.desc": "ビデオ通話中の背景のぼかし具合を調整します",
- "settingPrivacy.cleardata.cache.desc": "一時的に保存されたキャッシュデータが削除されます。写真や動画、ボイスメッセージ、ファイルのデータは削除されません。",
- "settingPrivacy.cleardata.cache.error": "一部のキャッシュデータを削除できませんでした。しばらくしてからもう一度お試しください。",
- "settingPrivacy.cleardata.cache.popup": "キャッシュデータを削除しますか?",
- "settingPrivacy.label.allowCallAlarm.desc": "この設定はスマートフォン版LINEアプリと同期しています。",
- "settingPrivacy.label.allowCallAlarmPC": "通話の着信許可",
- "settingPrivacy.label.blockAndDelete.desc": "ブロックリストからこのアカウントを削除しますか?\n削除してもこのアカウントからのメッセージは受信しません。なお、削除したアカウントにメッセージを送るには、IDまたは電話番号で友だち追加する必要があります。",
- "settingPrivacy.label.blockBuddyList": "ブロックリスト",
- "settingPrivacy.label.blockBuddyListEmpty": "ブロックしているアカウントはありません",
- "settingPrivacy.label.blocksquarememberlist": "オープンチャットメンバーの\nブロックリスト",
- "settingPrivacy.label.blocksquarememberlistEmpty": "ブロックしているスクエアメンバーはいません",
- "settingPrivacy.label.buddySearchAllow": "友だちからの検索を許可",
- "settingPrivacy.label.clearRecords": "トーク履歴をすべて削除",
- "settingPrivacy.label.cleardata": "データの削除",
- "settingPrivacy.label.cleardata.cache": "キャッシュデータ",
- "settingPrivacy.label.filterMessages": "友だち以外からのメッセージの受信を拒否します。",
- "settingPrivacy.label.filterMessages.title": "メッセージ受信拒否",
- "settingPrivacy.label.hiddenBuddyList": "非表示リスト",
- "settingPrivacy.label.hiddenBuddyListEmpty": "非表示にしているアカウントはありません",
- "settingPrivacy.label.hideAndDelete.desc": "非表示リストからこのアカウントを削除しますか?\n削除してもこのアカウントからのメッセージは受信します。なお、削除したアカウントにメッセージを送るには、IDまたは電話番号で友だち追加する必要があります。",
- "settingPrivacy.label.idSearchAllowYes": "IDの検索を許可",
- "settingPrivacy.label.title": "プライバシー管理",
- "settingProfile.error.invalidData": "この名前は使用できません",
- "settingProfile.error.network": "一時的なエラーにより\nリクエストが完了しませんでした。\nもう一度お試しください。",
- "settingProfile.error.server": "一時的なエラーによりリクエストが完了しませんでした。\nもう一度お試しください。",
- "settingProfile.label.emailEmpty": "未設定",
- "settingProfile.label.modifyprofile": "編集",
- "settingProfile.label.myInfo": "その他",
- "settingProfile.label.nickName": "名前",
- "settingProfile.label.registerAcoount.input.password.error.mailAddress": "入力されたメールアドレスはパスワードに類似しています。\n別のメールアドレスを登録してください。",
- "settingProfile.label.registerAcoount.mailAddress": "メール",
- "settingProfile.label.statusEmpty": "未設定",
- "settingProfile.label.statusMessage": "ステータスメッセージ",
- "settingProfile.label.userID": "ID",
- "settingProfile.link.registerAcoount.mailAddress": "メールアドレスを登録 >",
- "settingProfile.statusMessage.edit": "ステータスメッセージを入力してください。",
- "settingProfile.statusMessage.edit.failed": "ステータスメッセージを保存できませんでした。",
- "settings.basic.number.edit": "電話番号変更",
- "settings.delete.account": "アカウント削除",
- "settings.delete.account.btn": "アカウント削除",
- "settings.deleteAccount.confirm.desc": "LINEアカウントを削除すると、トーク履歴や友だちリストがすべて削除されます。アカウントを削除しますか?",
- "settings.deleteAccount.confirm.title": "LINEのアカウントを削除しますか?",
- "settings.deleteAccount.success": "LINEアカウントが削除されたためログアウトしました。",
- "settings.label.tooltip": "設定",
- "settings.privacy.publicUserID": "IDによる友だち追加を許可",
- "settings.privacy.publicUserID.description": "他のユーザーがあなたのIDを検索して友だち追加することができます。",
- "settings.privacy.rejectStrangeMessages": "メッセージ受信拒否",
- "settings.privacy.rejectStrangeMessages.description": "友だち以外からのメッセージの受信を拒否します。",
- "settings.privacy.title": "プライバシー管理",
- "settings.profile.myInfo.birthday": "誕生日",
- "settings.profile.myInfo.birthday.desc.plushometab": "誕生日を公開すると、誕生日の当日に特別なお祝いアニメーションがあなただけに表示されます。また、あなたのプロフィールや友だちのホーム画面、トークタブなどを通じて、友だちがあなたの誕生日を知ることができるようになります。",
- "settings.profile.myInfo.birthday.showMonthday": "誕生日を公開",
- "showAllContents.File": "ファイル",
- "showAllContents.Iink": "リンク",
- "showAllContents.ImageVideo": "写真/動画",
- "showAllContents.file.noFile": "このトークルームでシェアされたファイルはありません",
- "showAllContents.moveMessage": "メッセージに移動",
- "showAllContents.moveMessage.lastMessage": "最新のメッセージに移動",
- "showAllContents.uploadMember": "%1がアップロード ",
- "squar.group.settings.managemembers.request.delete.alert.notall.done": "参加リクエストを削除しました\n\n(一部のリクエストは他の管理者によって処理されました)",
- "square.abuse.textinput": "迷惑行為が確認されたため、利用が制限されています",
- "square.access.changephoto": "このオープンチャットで使用するプロフィール画像を変更",
- "square.access.chat": "新規トークを作成",
- "square.access.chat.image": "トークルームのメイン画像を変更",
- "square.access.chatroomtohome": "スクエアホームに移動",
- "square.access.cover.image": "オープンチャットの背景を変更",
- "square.access.create": "オープンチャットを作成",
- "square.access.hide": "オープンチャットの説明を閉じる",
- "square.access.invite": "友だちを招待",
- "square.access.join": "オープンチャットに参加",
- "square.access.joinrequest": "オープンチャットへの参加リクエスト",
- "square.access.postoption": "ノートのオプションを開く",
- "square.access.profile.image": "このオープンチャットで使用するプロフィール画像を変更",
- "square.access.profile.nickname": "このオープンチャットで使用するニックネームを変更",
- "square.access.qrcode": "オープンチャットのQRコード",
- "square.access.search": "オープンチャットを検索",
- "square.access.show": "オープンチャットの説明を開く",
- "square.access.square": "オープンチャット",
- "square.access.squareoption": "オープンチャットのオプションを開く",
- "square.access.timelinetosquare": "オープンチャットに移動",
- "square.access.write": "ノートを作成",
- "square.ageconfirmation.popupbutton.cancel": "キャンセル",
- "square.ageconfirmation.popupbutton.yes": "私は18歳以上です",
- "square.ageconfirmation.popupdesc.atleast18tosetrestriction": "オープンチャットに年齢制限を設定するには、18歳以上である必要があります。成人向けのトーク内容については、タバコまたはお酒に限定されるように管理してください。年齢制限をオンにした場合、あとでオフに変更することはできません。",
- "square.ageconfirmation.popuptitle.ageconfirmationrequired": "年齢確認が必要です",
- "square.ageconfirmationrequired.popupbutton.cancel": "キャンセル",
- "square.ageconfirmationrequired.popupbutton.yes": "確認して参加",
- "square.ageconfirmationrequired.popupdesc.onlyusersoverlegalageallowedtojoin": "このオープンチャットは18歳以上のユーザーのみが参加でき、オープンチャットの利用規約およびガイドラインに従う必要があります。",
- "square.ageconfirmationrequired.popuptitle.ageconfirmation": "18歳以上のみ利用できます",
- "square.announcement.donotshowagain": "今後は表示しない",
- "square.announcement.donotshowagain.mouseover": "今後は\n表示しない",
- "square.announcement.error": "アナウンスのメッセージが見つかりません",
- "square.announcement.message.annouce": "アナウンス",
- "square.announcement.minimize": "最小化",
- "square.announcement.unannounce": "アナウンス解除",
- "square.answer.guide": "参加リクエストを送信するには、質問の答えを入力してください。",
- "square.answer.send.done": "参加リクエストを送信しました",
- "square.answer.title": "答えを入力",
- "square.banreportuser.popupbutton.cancel": "キャンセル",
- "square.banuser.popupdesc.banafterleaving": "このメンバーはすでにオープンチャットを退会しています。このメンバーの再参加を禁止するには[強制退会]、通報するには[通報]をタップしてください。",
- "square.chat.button.threadmessages": "%2+件のメッセージ]]>",
- "square.chat.button.threadmessages999": "%2+件以上のメッセージを見る]]>",
- "square.chat.button.threadmessagesfew": "スレッド内のメッセージを見る",
- "square.chat.button.threadmessagesmany": "%1+件のメッセージ",
- "square.chat.desc.sent": "送信済み",
- "square.chat.err.file.exceed.capacity": "サイズ制限を超えているため、ファイルを送信できません",
- "square.chat.menu.aboutchatroom": "オープンチャット管理",
- "square.chat.more.leaveroom": "トークを退会",
- "square.chat.placeholder.qna": "回答を入力",
- "square.chat.reply.notification": "リプライ:%1",
- "square.chat.reply.notification2": "%1のリプライ:%2",
- "square.chat.setting": "詳細設定",
- "square.chat.settings.bg.apply.square.image": "オープンチャットのメイン画像を適用",
- "square.chat.settings.export.title": "%1のトーク",
- "square.chat.system.msg.invite.a.b": "%1が%2を招待しました。",
- "square.chat.system.msg.join.chat": "%1が参加しました。",
- "square.chat.system.msg.leave.chat": "%1が退会しました。",
- "square.chat.text.input.nickname": "%1としてメッセージを入力",
- "square.chatcontent.button.seemoreqna": "もっと見る",
- "square.chatcontent.tab.qna": "Q&Aメッセージ",
- "square.chatlist.alert.deletedchat": "このトークルームは存在しません。ほかのトークに参加してください。",
- "square.chatlist.alert.max": "参加メンバーが定員数に達しているためトークに参加できません。",
- "square.chatlist.join.guide": "参加したいサブトークルームを選択してください。各トークルームのトークメニュー>[トーク一覧]をタップすると、ほかのサブトークルームにも参加できます。",
- "square.chatlist.joined.title": "参加中のトーク ",
- "square.chatlist.joined.zero": "参加しているスクエアトークはありません",
- "square.chatlist.max.member.desc": "満員です。",
- "square.chatlist.public.join.alert": "このトークに参加すると、LINEのトークリストにも表示されます\n",
- "square.chatlist.public.join.btn": "参加 ",
- "square.chatlist.public.max.btn": "満員",
- "square.chatlist.public.no.msg": "メッセージはありません",
- "square.chatlist.public.title": "参加可能なトーク ",
- "square.chatlist.public.zero": "参加できるトークルームはありません",
- "square.chatlist.reply.alert": "リプライされました",
- "square.chatlist.square.button": "オープンチャット",
- "square.chatlist.title": "トーク一覧",
- "square.chatmenu.button.qna": "Q&Aメッセージ",
- "square.chatmenu.button.thread": "スレッド",
- "square.chatmenu.button.yourthreads": "マイスレッド",
- "square.chatroom.alert.open.url": "このリンクは安全ではない可能性があります。\nリンクを開きますか?",
- "square.chatroom.block.inputarea.deletedchat": "トークルーム削除済み",
- "square.chatroom.block.inputarea.deletedgroup": "オープンチャット削除済み",
- "square.chatroom.block.inputarea.kickoutgroup": "オープンチャット強制退会済み",
- "square.chatroom.chatlilst.guide.des": "このオープンチャットで作成されたトークルームを確認したり、参加できます。",
- "square.chatroom.chatlist.title": "トーク一覧",
- "square.chatroom.confirm.desc.kickout": "このメンバーをオープンチャットから退会させ、再参加を禁止します。よろしいですか?",
- "square.chatroom.create.image": "写真を選択",
- "square.chatroom.default.announce.content": "「%1」にようこそ!",
- "square.chatroom.deletefromall.alert": "選択したメッセージがすべてのメンバーのトーク履歴から削除されます。よろしいですか?",
- "square.chatroom.desc.botadded": "%1が%2を追加しました。",
- "square.chatroom.desc.botremoved": "%1が%2を解除しました。",
- "square.chatroom.error.alert.deletedchatroom": "このトークルームは存在しません。ほかのトークに参加してください。",
- "square.chatroom.input.deletedgroup": "削除されたオープンチャット",
- "square.chatroom.input.join.btn": "「%1」に参加",
- "square.chatroom.invite.layer.des": "一緒にトークしたい友だちを招待しましょう。",
- "square.chatroom.layer.upperloading": "トーク履歴を読み込み中...",
- "square.chatroom.longpress.deleteformall": "完全削除",
- "square.chatroom.longpress.deletefromall.title": "トークルームから消去",
- "square.chatroom.longpress.kickout": "強制退会",
- "square.chatroom.longpress.squarepost": "ノート",
- "square.chatroom.memberlist.guest": "ゲスト",
- "square.chatroom.setting.deletechat": "サブトークルームを削除",
- "square.chatroom.setting.deletechat.description": "すべてのメンバーがサブトークルームを利用できなくなります。削除しますか?",
- "square.chatroom.setting.report": "通報",
- "square.chatroom.settings.change.title": "トークルーム名",
- "square.chatroom.settings.leave.no.message": "こっそり退会",
- "square.chatroom.system.alert.notfriend": "オープンチャット「%1」の%2は友だちではありません。\nメッセージの内容にはご注意ください。",
- "square.chatroom.system.message.change.bg": "管理者がオープンチャットのメイン画像を変更しました。",
- "square.chatroom.system.message.change.maxparticipants": "%1がトークルームの定員数を%2人に設定しました。",
- "square.chatroom.system.message.change.name": "%1がトークルーム名を「%2」に変更しました。",
- "square.chatroom.system.message.change.picture": "%1がオープンチャットのメイン画像を変更しました。",
- "square.chatroom.system.message.kickout": "%1が退会させられました。",
- "square.chatroom.system.msg.alert.private": "スクエア「%1」の非公開トークルームです。メッセージの内容にはご注意ください。",
- "square.chatroom.system.msg.alert.public": "オープンチャット「%1」は誰でも参加できます。メッセージの内容にはご注意ください。",
- "square.chatroom.system.msg.guide.loading": "トーク履歴はスクロール時に読み込まれます。",
- "square.chatroom.system.msg.guide.report": "不適切なメッセージ(写真、動画、リンクなど)を通報するには、メッセージを右クリックしてください。",
- "square.chatroom.system.msg.tooltip.private": "スクエア「%1」の非公開トークルームです。",
- "square.chatroom.system.msg.tooltip.public": "オープンチャット「%1」は誰でも参加できます。メッセージの内容にはご注意ください。",
- "square.chatroom.systemmsg.deletedchat": "このトークルームは削除されました。 ",
- "square.chatroom.systemmsg.deletedgroup": "このオープンチャットは削除されました。",
- "square.chatroom.systemmsg.emptycommunity": "このオープンチャットは利用できません",
- "square.chatroom.systemmsg.emptyroom": "利用できないオープンチャット",
- "square.chatroom.systemmsg.kickout": "管理者によってトークルームから退会させられました。",
- "square.chatroom.vmenu.chatlist": "トーク一覧",
- "square.chatroom.vmenu.groupchatlist": "スクエアホーム",
- "square.chatroom.vmenu.leave.alert.outmsg.option": "トークルーム退会時にメッセージを表示します。",
- "square.coadmin.alert": "共同管理者に設定しますか?",
- "square.common.desc.usercount100kth": "%1 แสน",
- "square.common.desc.usercount1eok": "%1億",
- "square.common.desc.usercount1k": "%1K",
- "square.common.desc.usercount1m": "%1M",
- "square.common.desc.usercount1man": "%1万",
- "square.common.share": "シェア",
- "square.community.home.alert.invited.chat": "招待されたトークルームに参加しますか?",
- "square.community.home.chat.button.start": "開始",
- "square.community.home.invite.button": "招待",
- "square.community.home.msg.chat.onlymember": "トークに参加するにはスクエアへの参加が必要です。\nいますぐ参加しますか?",
- "square.community.home.msg.onlymember": "メンバーになるには\nスクエアへの参加が必要です。",
- "square.content.home.shared": "ノートをシェアしました。",
- "square.cover.chat.btn": "トーク",
- "square.cover.investmentscams": "LINEを悪用した詐欺にご注意ください。",
- "square.cover.post.btn": "ノート",
- "square.create.btn": "",
- "square.create.category": "カテゴリー ",
- "square.create.category.desc": "カテゴリーを指定すると、オープンチャットのオススメ一覧に表示される場合があります。",
- "square.create.default.category": "なし",
- "square.create.description": "説明",
- "square.create.description.desc": "オープンチャットの説明を入力",
- "square.create.description.input": "説明",
- "square.create.description2": "オープンチャットの説明を入力",
- "square.create.error.no.name": "オープンチャット名を入力してください",
- "square.create.error.popup.input.description.info": "オープンチャットの説明を入力してください。",
- "square.create.error.popup.input.info": "必須情報をすべて入力してください",
- "square.create.groupname": "オープンチャット名を入力",
- "square.create.image": "写真を選択",
- "square.create.over.text.num.alert": "これ以上入力できません ",
- "square.create.search": "検索を許可",
- "square.create.search.desc": "名前や説明文でオープンチャットを検索できます。",
- "square.create.setting.desc": "他のユーザーがメイン画面からこのオープンチャットを検索することができます。",
- "square.create.sgroup.approval.desc": "オープンチャットに参加するには管理者の承認が必要になります。",
- "square.create.sgroup.closedtype": "参加の承認",
- "square.create.sgroup.opentype": "すぐに参加",
- "square.create.subchat.guide.des": "オープンチャットの管理者権限と公開範囲の設定がこのオープンチャットのすべてのサブトークルームに適用されます。",
- "square.create.subchat.title": "サブトークルームを作成",
- "square.create.title": "オープンチャット作成",
- "square.create.welcome": "ウェルカムメッセージ",
- "square.createchat.error.no.auth.public": "管理者が権限を制限しているため、サブトークルームを作成できません。",
- "square.createchat.inputtitle": "サブトークルーム名を入力",
- "square.createchat.title": "新規トーク",
- "square.createchat.type.maximum.option": "トークの定員数を変更",
- "square.createchat.type.maximum.option.desc": "トークルームの定員数を設定できます。",
- "square.createchat.type.private": "非公開 ",
- "square.createchat.type.private.desc": "招待されたメンバーだけが参加できます。",
- "square.createchat.type.public": "公開",
- "square.createchat.type.public.desc": "誰でも参加できます。",
- "square.createchat.type.public.option": "メンバー全体に公開",
- "square.createopenchat.button.setagerestriction": "年齢制限",
- "square.createopenchat.desc.onlyusersoverlegalageallowed": "18歳以上のユーザーのみがこのオープンチャットに参加できるようになります。",
- "square.createopenchat.desc.search": "オープンチャットの一部のメッセージは、検索結果とオープンチャットのプロフィールに表示されます。なお、この設定はいつでも変更できます。",
- "square.createopenchat.placeholder.enterdescription": "説明を入力",
- "square.createsubchat.toggle.notifyinopenchat": "新規サブトークルームの通知",
- "square.default.name.title": "オープンチャット名",
- "square.error.cannot.forward.contact": "オープンチャットには連絡先を送信できません。",
- "square.error.fail.upload.profile.image": "プロフィールを編集できませんでした。 ",
- "square.error.not.normal": "正常に処理できませんでした。\nしばらくしてからもう一度お試しください。",
- "square.error.noti.kickout": "このオープンチャットから退会させられました。",
- "square.error.popup.cannot.invite": "スクエアの管理者がこの機能をオフにしました",
- "square.error.popup.cannot.join": "一時的に参加が制限されています。しばらくしてからもう一度お試しください。",
- "square.error.popup.deletedgroup": "このオープンチャットは削除されました。",
- "square.error.popup.network": "接続できません。\nネットワーク接続を確認して、もう一度お試しください。",
- "square.error.popup.noauth": "アクセス権限がありません。\n設定画面に移動します。",
- "square.error.popup.noauth.alert": "アクセス権限がありません ",
- "square.error.popup.usingbyotheruser": "他のユーザーが設定を編集中です。\nしばらくしてからもう一度お試しください。",
- "square.filtering.keyword.error.alert": "使用できない単語です。",
- "square.fraudpopup.button.cancel": "キャンセル",
- "square.fraudpopup.button.continue": "続行",
- "square.fraudpopup.button.learnmore": "詳細を見る",
- "square.fraudpopup.desc.investmentscams": "SNS広告などを起点とし、著名人を騙った投資詐欺が多発しています。やりとりには十分注意し、少しでも違和感がある場合は通報をお願いします。",
- "square.fraudpopup.title.investmentscams": "投資詐欺が多発しています",
- "square.friendslist.join.requests": "参加リクエスト管理",
- "square.friendstab.newrequest": "オープンチャットの参加リクエスト",
- "square.friendstab.request.count": "参加リクエスト ",
- "square.friendstab.request.counts.2.other": "参加リクエスト %n",
- "square.friendstab.request.counts.2.plurals.other": "参加リクエスト %n",
- "square.friendstab.request.counts.other": "参加リクエスト %n ",
- "square.friendstab.request.counts.plurals.other": "参加リクエスト %n",
- "square.group.create.change.image": "写真を変更",
- "square.group.name": "オープンチャット",
- "square.group.settings.basic": "オープンチャット基本設定",
- "square.group.settings.change.groupname": "オープンチャット名",
- "square.group.settings.change.myname": "名前",
- "square.group.settings.delete.alert": "オープンチャットを削除すると、トーク履歴を含むすべての情報が削除されます。オープンチャットを削除しますか?",
- "square.group.settings.editmember.kickout": "メンバーの強制退会",
- "square.group.settings.editmember.kickout.alert.done": "退会させました",
- "square.group.settings.group.profile": "オープンチャットのプロフィール",
- "square.group.settings.groupset": "オープンチャット設定",
- "square.group.settings.leave": "オープンチャットを退会",
- "square.group.settings.leave.alert": "トーク履歴を含むすべての情報が削除されます。このトークを退会しますか?",
- "square.group.settings.leave.error.alert.admin": "オープンチャットを退会するには、\n管理者権限を他のメンバーに移行してください。",
- "square.group.settings.manageauth.additional": "権限を設定",
- "square.group.settings.manageauth.additionalchatfeatures": "その他のトーク機能の追加・削除",
- "square.group.settings.manageauth.additionalchatfeatures.option.createpolls": "投票を作成",
- "square.group.settings.manageauth.additionalchatfeatures.option.deletepolls": "投票を削除",
- "square.group.settings.manageauth.chatapp": "その他のトーク機能",
- "square.group.settings.manageauth.setmaxparticipants": "トークルームの定員数を変更",
- "square.group.settings.managegroup": "オープンチャット管理",
- "square.group.settings.managegroup.allowtojoin": "参加の承認",
- "square.group.settings.managegroup.allowtojoin.desc": "オープンチャットに参加するには管理者の承認が必要になります。",
- "square.group.settings.managegroup.allowtosearch": "オープンチャットの検索を許可",
- "square.group.settings.managegroup.allowtosearch.desc": "キーワードでオープンチャットを検索できるようにします。",
- "square.group.settings.managegroup.autotag": "タグのサジェスト表示 ",
- "square.group.settings.managegroup.autotag.decs": "投稿の作成時にタグの候補が自動的に表示されます。",
- "square.group.settings.managegroup.deletegroup": "オープンチャットを削除",
- "square.group.settings.managegroup.invite": "メンバーを招待",
- "square.group.settings.managegroup.invite.desc": "オフにすると、メンバーを招待できなくなり、以前シェアされたリンクやQRコードは利用できなくなります。",
- "square.group.settings.managegroup.updateurl": "招待リンクを更新",
- "square.group.settings.managegroup.updateurl.desc": "更新すると既存の招待リンクが無効になります。\nよろしいですか?",
- "square.group.settings.managemember": "メンバー管理",
- "square.group.settings.managemembers.alert.cannot.select": "%n人まで選択できます",
- "square.group.settings.managemembers.allowrejoin": "許可",
- "square.group.settings.managemembers.blcoktojoin.alert": "オープンチャットへの再参加を許可しますか?",
- "square.group.settings.managemembers.blocktojoin": "再参加禁止リスト",
- "square.group.settings.managemembers.blocktojoin.alert": "オープンチャットへの再参加を許可しますか?",
- "square.group.settings.managemembers.manageadmin": "管理者",
- "square.group.settings.managemembers.manageadmin.added": "設定しました",
- "square.group.settings.managemembers.manageadmin.alert.deletecoadmin": "共同管理者の権限を取り消しますか?",
- "square.group.settings.managemembers.manageadmin.cancelcoadmin": "削除",
- "square.group.settings.managemembers.manageadmin.coadmin": "共同管理者 ",
- "square.group.settings.managemembers.manageadmin.handoveradmin": "管理者権限を移行",
- "square.group.settings.managemembers.manageadmin.handoveradmin.alert": "管理者権限を移行しますか?\nあなたは共同管理者に変更されます。 ",
- "square.group.settings.managemembers.manageadmin.handoveradmin.desc": "メンバーを共同管理者に設定して、スクエアを一緒に管理することができます。\n共同管理者の役割は[権限]で設定してください。 ",
- "square.group.settings.managemembers.manageadmin.handoveradmin.description": "共同管理者に管理者権限を移行できます。権限を移行すると、あなたは自動的に共同管理者に変更されます。",
- "square.group.settings.managemembers.manageadmin.makecoadmin": "共同管理者を設定",
- "square.group.settings.managemembers.manageadmin.makecoadmin.desc": "メンバーを共同管理者に設定して、オープンチャットを一緒に管理できます。",
- "square.group.settings.managemembers.manageadmin.makecoadmin.no.member": "選択できるメンバーはいません",
- "square.group.settings.managemembers.manageadmin.no.coadmin": "共同管理者はいません",
- "square.group.settings.managemembers.manageadmin.select": "選択",
- "square.group.settings.managemembers.manageauth": "権限 ",
- "square.group.settings.managemembers.manageauth.acceptrequest": "メンバー承認",
- "square.group.settings.managemembers.manageauth.admincoadmin": "管理者・共同管理者",
- "square.group.settings.managemembers.manageauth.adminonly": "管理者",
- "square.group.settings.managemembers.manageauth.all": "すべてのメンバー ",
- "square.group.settings.managemembers.manageauth.createpost": "投稿を作成 ",
- "square.group.settings.managemembers.manageauth.createpublicchat": "サブトークルームを作成",
- "square.group.settings.managemembers.manageauth.deletecontents": "トークルーム・投稿を削除",
- "square.group.settings.managemembers.manageauth.description": "オープンチャットのさまざまな権限を設定できます。",
- "square.group.settings.managemembers.manageauth.invitemembers": "メンバーを招待 ",
- "square.group.settings.managemembers.manageauth.kickout": "メンバーの強制退会",
- "square.group.settings.managemembers.managepost": "ノートを作成",
- "square.group.settings.managemembers.request": "参加リクエスト",
- "square.group.settings.managemembers.request.accept": "承認",
- "square.group.settings.managemembers.request.accept.alert.done": "参加リクエストを承認しました",
- "square.group.settings.managemembers.request.accept.alert.notall.done": "参加リクエストを承認しました(処理済みのリクエストを除く)。なお、トークの定員数に達している場合は承認されない場合があります。",
- "square.group.settings.managemembers.request.acceptall": "すべて承認 ",
- "square.group.settings.managemembers.request.acceptall.alert": "参加リクエストをすべて承認しますか?",
- "square.group.settings.managemembers.request.delete.alert": "削除しますか?",
- "square.group.settings.managemembers.request.delete.alert.done": "削除しました",
- "square.group.settings.managemembers.request.delete.alert.notall.done": "参加リクエストを削除しました\n(一部のリクエストは他の管理者によって処理されました)",
- "square.group.settings.managemembers.request.noti.tooltip": "参加リクエストを受信した時の通知のオン・オフを設定できます",
- "square.group.settings.managemembers.request.select100": "最近の%1件を選択",
- "square.group.settings.managemembers.request.selectall": "すべて選択",
- "square.group.settings.managemembers.request.zero": "参加リクエストはありません",
- "square.group.settings.memberlist": "メンバーを表示・招待",
- "square.group.settings.myprofile.title": "プロフィール",
- "square.group.settings.nickname": "ニックネーム",
- "square.group.settings.noti.post": "投稿の通知",
- "square.group.settings.noti.post.dec": "投稿の通知を受信できます。",
- "square.group.settings.policy": "オープンチャット利用規約",
- "square.group.settings.profile.title": "",
- "square.group.settings.recieve.chat": "招待メッセージを受信",
- "square.group.settings.recieve.friendsrequest": "友だちリクエストを受信 ",
- "square.group.settings.report": "オープンチャットを通報",
- "square.group.settings.reportpage.agreeandsend": "同意して送信",
- "square.group.settings.reportpage.agreeandsend.thpdpa": "承認して送信",
- "square.group.settings.reportpage.desc": "通報する理由を選んでください。",
- "square.group.settings.reportpage.impersonation.inquirypopup": "なりすましに関する調査のため、詳細情報の記入をお願いしております。\nお問い合わせフォームに移動して内容を記入しますか?",
- "square.group.settings.reportpage.impersonation.inquirypopup.decline": "スキップ",
- "square.group.settings.reportpage.impersonation.inquirypopup.proceed": "記入する",
- "square.group.settings.reportpage.reason1": "スパム / 宣伝目的",
- "square.group.settings.reportpage.reason2": "性的いやがらせ / 出会い目的",
- "square.group.settings.reportpage.reason3": "迷惑行為",
- "square.group.settings.reportpage.reason4": "その他",
- "square.group.settings.reportpage.reason5": "トピックと無関係な内容",
- "square.group.settings.reportpage.reason6": "なりすまし",
- "square.group.settings.reportpage.reason7": "詐欺",
- "square.group.settings.reportpage.report.btn": "通報",
- "square.group.settings.reportpage.reportdone": "通報しました",
- "square.grouppopup.alert.alreadyjoin": "このオープンチャットにはすでに参加しています。ページを閉じてから、再度アクセスしてください。",
- "square.grouppopup.alert.blocked": "このオープンチャットには参加できません。次回もう一度お試しください。",
- "square.grouppopup.alert.join.ing": "承認待ちです。\n管理者に承認されるとオープンチャットに参加できます。",
- "square.grouppopup.alert.requestdone": "参加リクエストを送信しました。管理者に承認されるとオープンチャットに参加できます。",
- "square.grouppopup.button.join.ing": "承認待ち",
- "square.grouppopup.chat.count.plurals.other": "トーク %1",
- "square.grouppopup.invite.tooltip": "LINEの友だちを直接招待するか、招待リンクやQRコードをシェアしてください。",
- "square.grouppopup.invitefriend": "友だちを招待",
- "square.grouppopup.member.count.plurals.other": "メンバー %1",
- "square.grouppopup.post.count.plurals.other": "ノート %1",
- "square.grouppopup.qrcode": "QRコードで招待",
- "square.grouppopup.qrcode.desc": "QRコードを直接見せるか投稿でシェアしてください。",
- "square.grouppopup.qrcode.save": "QRコードを保存",
- "square.grouppopup.qrcode.saved": "QRコードを保存しました ",
- "square.grouppopup.sendrequest": "参加リクエスト",
- "square.grouppopup.url": "リンクで招待",
- "square.grouppopup.url.app": "他のアプリでシェア",
- "square.grouppopup.url.line": "LINEでシェア",
- "square.home.addfavorite": "お気に入りに追加",
- "square.home.cancelfavorite": "お気に入りを解除",
- "square.home.chat.section.invited": "招待されたトーク",
- "square.home.favorite.tooltip": "このボタンをクリックすると、オープンチャットが\nLINE友だちリストのお気に入りに追加されます。",
- "square.home.invite.copy.link": "リンクをコピー",
- "square.home.invite.save.qr": "QRコードを保存",
- "square.home.invite.share.link": "リンクをシェア",
- "square.home.invite.share.qr": "QRコードをシェア",
- "square.home.menu.photo": "写真",
- "square.home.menu.write": "投稿",
- "square.home.nickname": "%1",
- "square.home.setting": "設定",
- "square.home.tab.chat": "トーク",
- "square.home.tab.post": "掲示板",
- "square.home.toast.addfavorite": "お気に入りに追加しました",
- "square.home.toast.cancelfavorite": "お気に入りを解除しました",
- "square.invite.complete.other": "%n人に招待メッセージを送信しました。",
- "square.invite.complete.plurals.other": "%n人に招待メッセージを送信しました。",
- "square.invite.friend": "友だちを招待",
- "square.invite.urlscheme.chatroom.chatname": "「%1」に招待",
- "square.invitemember.confirm.donotshowagain": "次回から表示しない",
- "square.invitemember.confirm.invite": "招待されたユーザーはトーク履歴を見ることができます。",
- "square.invitemember.desc": "スクエアメンバーをトークに招待できます。メンバーではない人を招待するには、まずスクエアに招待してください。",
- "square.invitemember.desc.urlscheme.chatroom": "オープンチャットのメンバーではないユーザーを招待するには、[トークに招待]をクリックしてください。",
- "square.invitemember.invitetogroup": "オープンチャットに招待",
- "square.invitemember.invitetogroup.urlscheme.chatroom": "トークに招待",
- "square.invitemember.memberlist.title": "「%1」のメンバー %n",
- "square.invitemember.title": "招待先の選択",
- "square.invitetoopenchat.button.share": "シェア",
- "square.invitetoopenchat.desc.sharelinktoinvitemembers": "友だちを招待するには、オープンチャットのリンクをシェアしましょう。",
- "square.join.precaution": "「%1」にようこそ!メッセージやコンテンツの内容にはご注意ください。運営ポリシーに違反した場合は、サービスの利用に制限がかかる場合があります。",
- "square.join.question.guide": "5~50文字で入力",
- "square.joincode.error": "参加コードが正しくありません。確認してもう一度お試しください。",
- "square.joincode.guide": "オープンチャットに参加するには、管理者が指定する参加コードを入力してください。",
- "square.joincode.guide.description": "トークルームに参加するための参加コード(4~8文字の半角英数字)を指定してください。",
- "square.joincode.input.guide": "参加コードを入力",
- "square.joincode.title": "参加コードを入力",
- "square.joinscreen.placeholder.enteranswerhere": "答えを入力",
- "square.keyboardmenu.button.qna": "Q&Aメッセージ",
- "square.kickout.alert.done": "退会させました。オープンチャットへの再参加を許可するには、[オープンチャット設定]>[メンバー管理]>[再参加禁止リスト]から許可してください。",
- "square.kickout.blockoption": "オープンチャットへの再参加禁止",
- "square.kickout.error.alert.admin": "管理者・共同管理者を退会させることはできません。",
- "square.kickout.reason1": "広告・スパム",
- "square.kickout.reason2": "不快・わいせつな表現",
- "square.kickout.reason3": "その他",
- "square.leave.last.person.alert": "",
- "square.leftuser.kickout.btn": "強制退会",
- "square.main.create.block.alert": "ベータテスト期間はスクエアを作成できません。 ",
- "square.main.create.guide": "オープンチャットを作って\n新しい人とおしゃべりしよう!",
- "square.main.mylist": "マイオープンチャット",
- "square.main.mylist.sortbyname": "名前順",
- "square.main.mylist.sortbyupdate": "最終更新順",
- "square.main.mylist.sortbyvisit": "最終アクセス順",
- "square.main.mylist.viewall": "すべて見る",
- "square.main.mylist.zero": "いろんな人とトークしたり、情報収集できるオープンチャット!さっそく参加してみよう。",
- "square.main.search.block.alert": "ベータテスト期間は検索機能を利用できません。 ",
- "square.main.search.default.msg": "オープンチャット名、説明",
- "square.managemembers.button.seewholeft": "最近退会したメンバー",
- "square.managemembers.desc.seewholeft": "過去24時間でオープンチャットを退会したメンバーが表示されます。",
- "square.manageopenchat.desc.setjoincode": "トークルームに参加するための参加コードを指定してください。",
- "square.members": "メンバー",
- "square.members.addmembers": "メンバーを招待",
- "square.membershipsystemmessages.button.userisbannedfromthechat": "メンバーが強制退会",
- "square.membershipsystemmessages.button.userjoinsthechat": "メンバーが参加",
- "square.membershipsystemmessages.button.userleavesthechat": "メンバーが退出",
- "square.membershipsystemmessages.desc.managesystemmessages": "メンバーが参加、退出または強制退会した時にオープンチャットに表示されるシステムメッセージの表示・非表示を設定できます。",
- "square.menu.invite": "招待",
- "square.mythreads.button.seemessages.other": "%n件のメッセージを見る]]>",
- "square.noti.admin": "オープンチャット「%1」の管理者の権限が付与されました。",
- "square.noti.coadmin": "オープンチャット「%1」の共同管理者の権限が付与されました。",
- "square.noti.delete.chat": "管理者がトークルーム「%1」を削除しました。",
- "square.noti.deleted.coadmin": "オープンチャット「%1」の共同管理者の権限が取り消されました。",
- "square.noti.deleted.gorup": "オープンチャット「%1」が削除されました。",
- "square.noti.join.done": "オープンチャット「%1」に参加しました。",
- "square.noti.joinrequest": "%1がオープンチャット「%2」への参加をリクエストしました。",
- "square.noti.kickout": "オープンチャット「%1」から退会させられました。",
- "square.notification.desc.userjoinedopenchat": "オープンチャット「%1」にメンバーが参加しました。",
- "square.notification.setting": "オープンチャットのノートを通知\nPC版で通知を受信するには、スマートフォン版LINEからオープンチャットの通知をオンにしてください。",
- "square.openchat.desc.adminaddedbottochat": "[0]が[1]を追加しました。",
- "square.openchat.desc.adminremovedbotfromchat": "[0]が[1]を解除しました。",
- "square.openchat.desc.messageremovedforsharinginappropriatecontent": "ポリシーに違反している可能性があるため、%1のメッセージが削除されました。",
- "square.openchat.desc.userbannedbysomeoneelse": "%1が%2をこのオープンチャットから退会させました。",
- "square.openchat.popup.dontshow": "このオープンチャットで今後このメッセージを表示しない",
- "square.openchat.popupbutton.close": "閉じる",
- "square.openchat.popupbutton.deleteforall": "メンバー全員の履歴から削除",
- "square.openchat.popupbutton.deleteforyou": "自分の履歴から削除",
- "square.openchat.popupbutton.ok": "OK",
- "square.openchat.popupbutton.seemore": "詳細を見る",
- "square.openchat.popupdesc.deletemessagesfor": "削除する方法を選択してください。\nマウスをドラッグすると、一度に最大50件までメッセージを削除できます。",
- "square.openchat.popupdesc.unreadmessagecountmarkedwithnicon": "メッセージを受信した時に、未読メッセージの件数の代わりに「N」のアイコンが表示されます。",
- "square.openchat.popupdesc.unsendmessage": "メンバーが利用中のLINEバージョンによっては、メンバーのトークルームからメッセージが消えないことがあります。送信を取り消しますか?",
- "square.openchat.popuptitle.deletemessages": "メッセージを削除",
- "square.openchatannouncements.title.announcements": "アナウンス",
- "square.openchatcharacterprofiles.button.cancel": "キャンセル",
- "square.openchatcharacterprofiles.button.save": "適用する",
- "square.openchatcharacterprofiles.title.selectcharacter": "キャラクター画像から選択",
- "square.openchatentry.button.confirm": "確認しました",
- "square.openchatentry.desc.dontsendrudemessages": "誹謗中傷・わいせつな投稿・荒らし行為は厳禁です。]]>",
- "square.openchatentry.desc.followopenchatrules": "オープンチャットの利用制限に加え、LINEアプリが利用停止になる場合があります。]]>",
- "square.openchatentry.desc.treatmemberswithrespect": "個人情報の交換、交際相手を求める行為を固く禁じます。]]>",
- "square.openchatentry.header.dontsendrudemessages": "2. 荒らし行為・その他の迷惑行為",
- "square.openchatentry.header.followopenchatrules": "もし違反した場合は?",
- "square.openchatentry.header.treatmemberswithrespect": "1. 出会い目的の行為・個人情報の投稿",
- "square.openchatentry.title.openchatuserules": "オープンチャット\n絶対禁止事項",
- "square.openchatinvite.desc.userinvitedtojoinchat": "オープンチャット「%1」に招待されました。",
- "square.openchatinvite.desc.userinvitedtojoinsquare": "オープンチャット「%1」に招待されました。",
- "square.openchatlist.desc.viewchatandaddtofavorites": "オープンチャット名とプロフィールを確認してお気に入りに追加できます。",
- "square.openchatlist.header.yourchats": "参加中のトーク %1",
- "square.openchatliveinvite.popupdesc.usefeatureonmobileapp": "スマートフォン版LINEでのみ利用できるサービスです。",
- "square.openchatmember.button.default": "デフォルト",
- "square.openchatmember.button.oldjoin": "古い順",
- "square.openchatmember.button.recentjoin": "新しい順",
- "square.openchatmember.desc.days.other": "%d日前",
- "square.openchatmember.desc.hours.other": "%d時間前",
- "square.openchatmember.desc.justnow": "たった今",
- "square.openchatmember.desc.lastvisited": "最終アクセス",
- "square.openchatmember.desc.minutes.other": "%d分前",
- "square.openchatmembers.desc.hundredthousandmembersth": "%1",
- "square.openchatmembers.desc.membersen": "%1",
- "square.openchatmembers.desc.memberskoja": "%1",
- "square.openchatmembers.desc.membersth": "%1",
- "square.openchatmembers.desc.tenthousandmemberskoja": "%1万",
- "square.openchatmembers.desc.tenthousandmembersth": "%1",
- "square.openchatmembers.desc.thousandmembersen": "%1",
- "square.openchatmembers.desc.thousandmembersth": "%1",
- "square.openchatmenu.button.hidemessagecount": "未読数を非表示\nメッセージを受信した時に、未読メッセージの件数の代わりに「N」のアイコンが表示されます。",
- "square.openchatmenu.button.showmessagecount": "未読数を表示",
- "square.openchatmenu.desc.joindate": "yyyy年m月d日に参加",
- "square.openchatmenu.desc.messagereplies": "あなたのメッセージがリプライされると通知を受信します。",
- "square.openchatmenu.desc.onlyadmin": "メンバーの参加日と最終アクセス日は、管理者と共同管理者にのみ表示されます。",
- "square.openchatmenu.desc.visitdays.other": "%1日前にアクセス",
- "square.openchatmenu.desc.visitmonths.other": "%1カ月前にアクセス",
- "square.openchatmenu.desc.visittoday": "今日アクセス",
- "square.openchatmenu.desc.visityester": "昨日アクセス",
- "square.openchatmenu.toggle.messagereplies": "メッセージへのリプライ",
- "square.openchatmessage.desc.noreactions": "リアクションはありません。",
- "square.openchatmessagefield.desc.readonlymode": "閲覧モードに設定されています",
- "square.openchatnotes.desc.subchatmemberscanseenotes": "このノートはサブトークルームのメンバーも見ることができます。",
- "square.openchatnotificationsettings.header.openchatnotifications": "オープンチャット",
- "square.openchatphoneverification.popupdesc.verifyphonenumberonmobileapp": "オープンチャットを安全に利用できるように、電話番号認証を行ってください。電話番号認証はスマートフォン版LINEで行えます。",
- "square.openchatphoneverification.popuptitle.verificationrequired": "電話番号認証が必要です",
- "square.openchatpopup.button.cancel": "キャンセル",
- "square.openchatpopup.button.confirm": "続行",
- "square.openchatpopup.desc.changesetting": "オープンチャットと他のサブトークルームにも変更が適用されます。続行しますか?",
- "square.openchatprivacysettings.desc.agerestrictedchat": "このオープンチャットは、18歳以上のユーザーのみ利用できます。",
- "square.openchatprivacysettings.desc.opentoallages": "このオープンチャットは、すべての年齢のユーザーが利用できます。",
- "square.openchatprivacysettings.popupdesc.entercodetojoinchat": "トークルームに参加するための参加コードを指定してください。\n※「全体公開」から「参加コードの入力」に変更すると、未成年者であるか年齢確認を行っていないメンバーがこのトークルームに参加できなくなります。",
- "square.openchatprivacysettings.popupdesc.enterquestiontojoinchat": "参加を希望するユーザーへの質問を入力してください。管理者がユーザーの答えを確認し、参加を承認できます。\n※「全体公開」から「参加の承認」に変更すると、未成年者であるか年齢確認を行っていないメンバーがこのトークルームに参加できなくなります。",
- "square.openchatprofile.button.join": "新しいプロフィールで参加",
- "square.openchatprofile.desc.chatsetindifferentcountry": "国・地域が異なるオープンチャットです。",
- "square.openchatprofile.desc.openchatsettoreadonly": "閲覧モードに設定されています",
- "square.openchatprofile.desc.tooltip": "新しいニックネームとプロフィール画像でこのオープンチャットに参加できます",
- "square.openchatsetting.desc.maxpeople": "大規模チャットではこの設定を変更できません。",
- "square.openchatsetting.desc.mentionnoti": "トークルームの通知設定がオフでも、自分がメンションされると通知を受信します。",
- "square.openchatsetting.desc.mentions": "メンション",
- "square.openchatsetting.desc.onlyopen": "年齢制限がオフの場合に利用できます。",
- "square.openchatsetting.desc.visibility": "メッセージのプレビューと検索を許可",
- "square.openchatsetting.desc.visibilityallowed": "許可",
- "square.openchatsetting.desc.visibilitynotallowed": "許可しない",
- "square.openchatsetting.desc.visiforco": "サブトークルームのメッセージが検索結果に表示されます。この設定はオープンチャットの設定に応じて適用されており、管理者のみが変更できます。",
- "square.openchatsettings.button.allowmessagesfrom": "メッセージの送信を許可",
- "square.openchatsettings.button.continue": "続行",
- "square.openchatsettings.button.leavemainchat": "メイントークルームを退会",
- "square.openchatsettings.button.leavesubchat": "サブトークルームを退会",
- "square.openchatsettings.button.managemembershipsystemmessages": "システムメッセージを管理",
- "square.openchatsettings.button.settoreadonlymode": "閲覧モード",
- "square.openchatsettings.desc.addopenchatdescription": "説明を入力",
- "square.openchatsettings.desc.coverphotosetasprofilephotoandbackground": "この画像はオープンチャットのプロフィールおよびトークルームの背景に適用されます。",
- "square.openchatsettings.desc.getnotifiedwhensomeonejoins": "新しいメンバーが参加した時に通知を受信します。",
- "square.openchatsettings.desc.readonlymodeformembers": "管理者または共同管理者のみがトークルームでメッセージを送信できます。",
- "square.openchatsettings.header.chatsettings": "トークルーム設定",
- "square.openchatsettings.header.details": "情報",
- "square.openchatsettings.header.editsubchatprofile": "サブトークルームのプロフィールを編集",
- "square.openchatsettings.header.openchatsettings": "設定",
- "square.openchatsettings.header.subchatsettings": "サブトークルームの設定",
- "square.openchatsettings.placeholder.enterhashtags": "説明文を入力",
- "square.openchatsettings.popup.searchoff": "すべてのメッセージが検索結果とオープンチャットのプロフィールに表示されなくなります。続行しますか?",
- "square.openchatsettings.popup.searchon": "今後やり取りされるメッセージが検索結果とオープンチャットのプロフィールに表示されます。続行しますか?",
- "square.openchatsettings.popupdesc.selectacoadmin": "サブトークルームを退会するには共同管理者を設定してください。",
- "square.openchatsettings.toggle.newmembernotification": "新しいメンバーの参加通知",
- "square.openchatsettingstatus.desc.readonlymodedisabled": "トークルームのメンバー全員がメッセージを送信できます。",
- "square.openchatsettingstatus.desc.readonlymodeenabled": "管理者のみがメッセージを送信できます。",
- "square.openchatsettingv.desc.allmessages": "すべてのメッセージ",
- "square.openchatsettingv.desc.dontallow": "許可しない",
- "square.openchatsettingv.desc.off": "[オープンチャットの検索を許可]がオンに設定されている場合にのみ利用できます。",
- "square.openchatsettingv.desc.on": "オープンチャットのメッセージが検索結果とオープンチャットのプロフィールに表示されます。",
- "square.openchatsharelink.desc.sharelinktoinvitefriends": "このオープンチャットに友だちを招待して、一緒にトークを楽しもう。",
- "square.openchatsharelink.title.sharelink": "オープンチャットのリンクをシェア",
- "square.openchatsubchat.title.subchatname": "サブトークルーム名",
- "square.openchatwallpapersettings.desc.wallpaperonlyseenbyyou": "背景は自分のトークルームのみに適用されます。",
- "square.pdpa.policy.agree.btn": "同意して承認",
- "square.personaloption.alert.error.name": "この名前はすでに使用されています。別の名前を入力してください。",
- "square.personaloption.chat": "招待メッセージを受信",
- "square.personaloption.chat.desc": "オープンチャットのメンバーからの招待メッセージを受信します。",
- "square.personaloption.copy": "リンクをコピーしました ",
- "square.personaloption.friendrequest": "友だちリクエストを受信",
- "square.personaloption.friendrequest.desc": "メンバーがあなたに友だちリクエストを送信できます。",
- "square.personaloption.greetingmessage": "管理者へのメッセージ",
- "square.personaloption.greetingmessage.default": "メッセージを入力してください",
- "square.personaloption.guide": "ニックネームを入力",
- "square.personaloption.join.btn": "参加",
- "square.personaloption.joincode.btn": "参加コードを入力",
- "square.personaloption.profile.title": "オープンチャットのプロフィール",
- "square.personaloption.profile.title.tooltip.desc": "このオープンチャットで使用するニックネームとプロフィール画像を設定できます。LINEのプロフィールは公開されません。",
- "square.personaloption.sendrequest.btn": "参加リクエスト",
- "square.personaloption.welcomemsg": "ウェルカムメッセージ ",
- "square.policy.agree.btn": "同意 ",
- "square.policy.title": "利用規約とポリシーに同意",
- "square.policy.viewall": "オープンチャットの利用規約の内容を確認",
- "square.popup.button.grantpermission": "設定",
- "square.popup.button.setaspublic": "変更",
- "square.post.announcement.announce": "登録",
- "square.post.announcement.delete": "ノートを削除",
- "square.post.announcement.delete.desc": "大事なノートからも解除されます。ノートを削除しますか?",
- "square.post.announcement.guide": "みんなに見て欲しい投稿は、大事なノートに登録!",
- "square.post.announcement.list.title": "大事なノート",
- "square.post.announcement.list.zero": "ノートはありません",
- "square.post.announcement.mark": "大事なノートに登録",
- "square.post.announcement.mark.desc": "毎日最初に登録された大事なノートについてのみ、オープンチャットのメンバーに通知が送信されます。",
- "square.post.announcement.postui": "大事なお知らせ",
- "square.post.announcement.postui2": "大事なノート",
- "square.post.announcement.push": "「%1」で大事なノートが登録されました。",
- "square.post.announcement.remove": "大事なノートを解除",
- "square.post.announcement.seeall.plural.other": "%1件の大事なノート",
- "square.post.endpage.squarename": "%1",
- "square.post.error.deletedcomment": "すでに削除されたコメントです。",
- "square.post.error.deletedjoined": "すでに削除された投稿です ",
- "square.post.error.deletedpost": "すでに削除されたノートです。",
- "square.post.error.write": "管理者が権限を制限しているため、投稿を作成できません ",
- "square.post.hashtag.title": "スクエア「%1」の%2",
- "square.post.join": "参加",
- "square.post.joinguide": "お見逃しなく!「%1」に参加していろんなトークや投稿を楽しもう。",
- "square.post.linktype.chatlist": "オープンチャットのノートをシェアしました。",
- "square.post.linktype.scroll": "オープンチャットのノートをシェアしました。",
- "square.post.linktype.title": "ノートを見る",
- "square.post.share.chatlist": "オープンチャットに送信",
- "square.post.share.popup": "ノートをシェア",
- "square.post.title": "ノート",
- "square.post.write.guide": "友だち以外の人にも表示されます。",
- "square.post.write.guidecountryspecific": "オープンチャットでシェアします。",
- "square.post.write.hashtag": "スクエアの投稿にタグを追加して、メンバーが\n特定のトピックに関する投稿やトークを探しやすくしよう。",
- "square.post.zeropage.newpost": "投稿",
- "square.post.zeropage.welcome": "1番乗りでノートに投稿しよう!",
- "square.postpopup.join": "この機能を使用できるのはスクエアのメンバーのみです。スクエアに参加しますか?",
- "square.privacy.setting.approval": "参加の承認",
- "square.privacy.setting.guide": "オープンチャットの公開範囲を設定できます。",
- "square.privacy.setting.joincode": "参加コードの入力",
- "square.privacy.setting.off": "全体公開",
- "square.privacy.setting.off.guide": "誰でも参加できます。",
- "square.privacy.setting.title": "公開設定",
- "square.privacy.turnoff.alert": "誰でも参加できるようになります。公開設定を[全体公開]に変更しますか?",
- "square.privcay.setting.off.guide": "誰でも参加できます。",
- "square.qrcode.save.failed": "QRコードを保存できませんでした",
- "square.readonlyopenchat.popupbutton.ok": "OK",
- "square.repairdata.button.repairdata": "同期",
- "square.repairdata.desc.syncrepairdata": "オープンチャットのデータを同期します。\n同期の対象:オープンチャットに関する情報、その他の設定など",
- "square.repairdata.popupdesc.repairinginprogress": "同期中...\n画面を閉じずにそのままお待ちください。",
- "square.repairdata.popupdesc.synccomplete": "オープンチャットのデータを同期しました。",
- "square.repairdata.title.repairdata": "オープンチャットの情報を同期",
- "square.report.page.reason01": "",
- "square.report.page.reason02": "",
- "square.report.page.reason03": "",
- "square.report.page.reason04": "",
- "square.report.policy.desc": "通報内容はオープンチャットのポリシーに従って検討および処理されます。",
- "square.report.policy.desc01": "",
- "square.report.policy.desc02": "",
- "square.report.policy.message": "",
- "square.report.subTitle": "このノートを通報します\n(作成者:%1)",
- "square.reportopenchat.desc.reportchatfromprofile": "直近100件のメッセージ、通報するオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数)、通報するオープンチャットの管理者や通報者に関する情報(ニックネーム、内部識別子)",
- "square.reportopenchat.desc.reportchatfromsettings": "直近50件のメッセージ、通報するオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数)、通報するオープンチャットの管理者や通報者に関する情報(ニックネーム、内部識別子)",
- "square.reportopenchat.desc.reportcommentonopenchatnote": "通報するノートのコメントに関する情報(テキスト、画像、絵文字)、通報するノートが作成されたオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数)、通報するユーザーに関する情報(ニックネーム、プロフィール画像、内部識別子、メンバーの参加ステータス)、通報者に関する情報(ニックネーム、内部識別子)",
- "square.reportopenchat.desc.reportopenchatmember": "直近100件のメッセージ、通報するオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数)、通報するユーザーに関する情報(ニックネーム、プロフィール画像、内部識別子)通報者に関する情報(ニックネーム、内部識別子)",
- "square.reportopenchat.desc.reportopenchatmessage": "通報するメッセージと該当メッセージより前にやりとりしたメッセージ最大10件、通報するユーザーに関する情報(ニックネーム、プロフィール画像、内部識別子)、通報するユーザーが参加しているオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数)、通報者に関する情報(ニックネーム、内部識別子)",
- "square.reportopenchat.desc.reportopenchatnote": "通報するノートに関する情報(テキスト、画像、絵文字、動画)、通報するユーザーに関する情報(ニックネーム、プロフィール画像、内部識別子、メンバーの参加ステータス)、通報するノートが作成されたオープンチャットに関する情報(メイン画像、オープンチャット名、メンバー数)、通報者に関する情報(ニックネーム、内部識別子)",
- "square.requesttojoin.button.submit": "回答",
- "square.set.joincode.input.guide": "コードを入力",
- "square.set.question.input.guide": "参加を希望するユーザーへの質問を入力してください。管理者がユーザーの答えを確認し、参加を承認できます。",
- "square.setopenchatprofile.button.characterprofile": "キャラクター画像から選択",
- "square.setting.auth.announcement": "アナウンスを登録",
- "square.setting.auth.message.post": "メッセージ・ノートを削除",
- "square.settings.deleteaccount.desc": "オープンチャットの管理者権限は他のメンバーに自動的に移行されます。",
- "square.settings.managesquare.defaultchatroom.desc": "基本トークは削除できません。",
- "square.settings.managesquare.defaultchatroom.title": "スクエア「%1」の基本トーク",
- "square.settings.managesquare.privatechat": "非公開トークを許可",
- "square.settings.managesquare.privatechat.desc": "メンバーが非公開トークルームを作成したり、1:1でトークしたりできます。",
- "square.settings.memberlist.members.subtitle": "メンバー",
- "square.settings.members": "メンバー(%n)",
- "square.settings.myprofile.leavesquare": "オープンチャットを退会",
- "square.sub.name.title": "サブトークルーム名",
- "square.thread.desc.nochat": "スレッド内のメッセージはトークルームには表示されません。",
- "square.thread.desc.startofthread": "トークルームで見る",
- "square.thread.placeholder.replytothread": "スレッドに返信",
- "square.thread.title.thread": "スレッド",
- "square.thread.toast.nolongerwatching": "このスレッドをお気に入りから削除しました",
- "square.thread.toast.nowwatching": "このスレッドをお気に入りに追加しました",
- "square.timeline.button.tooltip": "いろんな人と\n楽しくおしゃべり!",
- "square.tooltip.chatroom.settings.changename": "基本トークの名前とプロフィールを設定できます",
- "square.unsupported.version.message": "ご利用のバージョンでは対応していません。\nLINEアプリを最新版にアップデートしてください。",
- "square.urlscheme.alert.linkjoin.function.off": "招待リンクから参加することはできません。\nオープンチャットのメンバーに招待をリクエストしてください。",
- "square.urlscheme.desc2": "このスクエアにはiOS・Android端末からのみ参加できます。 ",
- "square.urlscheme.error.notexist": "このオープンチャットは存在しません。",
- "square.urlscheme.invite.msg": "オープンチャットに招待されました。",
- "square.urlscheme.package": "[%1] オープンチャットに招待されました。\n%3\n%2",
- "square.urlscheme.package.chatroom": "オープンチャット「%1」\n%2",
- "square.urlscheme.package.chatroom2": "",
- "square.user.admin": "管理者",
- "square.user.coadmin": "共同管理者",
- "square.userpopup.blockinvite": "招待をブロック",
- "square.userpopup.error.alert.notmember": "このオープンチャットのメンバーではありません。",
- "square.userpopup.friendsinfo.btn": "情報 ",
- "square.userpopup.friendsrequest.btn": "友だちリクエスト",
- "square.userpopup.kickout.ban.btn": "はい",
- "square.userpopup.kickout.btn": "強制退会",
- "square.userpopup.kickout.cancel.btn": "いいえ",
- "square.userpopup.post.count.btn": "投稿",
- "square.yourthreads.title.yourthreads": "マイスレッド",
- "sticion.msg.desc.expired": "絵文字の有効期間が終了しました。",
- "sticker.btn.deleteThisSticker": "スタンプを削除",
- "sticker.btn.openWebStore": "スタンプショップ",
- "sticker.customsticker.btn.edit": "テキストを変更",
- "sticker.customsticker.cancelalert.desc": "入力したテキストが保存されていません。このページから移動しますか?",
- "sticker.customsticker.discard.alert": "移動",
- "sticker.customsticker.edit.overflow": "利用可能な文字数を超えています。",
- "sticker.customsticker.error.updatename.desc": "テキストを変更できませんでした。",
- "sticker.customsticker.invalidwordupdate.desc": "このスタンプには使用できない単語が含まれています。スタンプを使用するには、テキストを編集してください。",
- "sticker.customsticker.sync.alert": "PC版LINEで入力したテキストは、スマートフォン版LINEにすぐに反映されない場合があります。テキストを入力したスタンプをスマートフォン版で使用するには、[設定]>[スタンプ]>[マイスタンプ]からダウンロードしてください。",
- "sticker.customsticker.tooltip": "好きなテキストを入力しよう!",
- "sticker.download.btn": "ダウンロード",
- "sticker.download.fail": "ダウンロードできませんでした。\nもう一度お試しください。",
- "sticker.downloadAll.confirm": "すべてのスタンプをダウンロードしますか?",
- "sticker.downloadAll.desc": "保有しているスタンプをまとめてダウンロードできます。",
- "sticker.downloadAll.downloading": "スタンプをダウンロード中...",
- "sticker.downloading.desc": "スタンプをダウンロードしています。\nしばらくお待ちください。",
- "sticker.edit.hint.default": "****",
- "sticker.edit.invalidword.desc": "使用できない単語が含まれています。",
- "sticker.error.downloadlfailed.desc": "スタンプをダウンロードできませんでした。",
- "sticker.expired.desc": "「%1」の有効期間が終了したため、このスタンプは削除されます。",
- "sticker.msg.desc.delete": "削除する",
- "sticker.msg.desc.expired": "スタンプの有効期間が終了しました。",
- "sticker.msgsticker.button.back": "戻る",
- "sticker.msgsticker.button.cancel": "キャンセル",
- "sticker.msgsticker.button.edit": "テキストを変更",
- "sticker.msgsticker.button.save": "保存",
- "sticker.msgsticker.desc.howtoedit": "テキストを編集したいスタンプをクリック",
- "sticker.msgsticker.desc.prompt": "テキストを変更した場合、送信済みのスタンプには反映されません。",
- "sticker.msgsticker.validation.errorrefresh": "テキストを反映できませんでした。スタンプをクリックして、もう一度お試しください。",
- "sticker.msgsticker.validation.toolong": "テキストを短くしてください。",
- "sticker.nearlyExpired.desc.other": "有効期間はあと%n日です。",
- "sticker.recommendedSticker.label": "おすすめスタンプ",
- "sticker.search.hint": "検索",
- "sticker.search.nosearchresult": "検索結果がありません",
- "sticker.stickerspremium.deletsticker.popup": "このスタンプをマイプレミアムスタンプから削除しますか?",
- "sticker.stickerspremium.dropped.desc": "引き続き使用するには、個別に購入してください。",
- "sticker.stickerspremium.dropped.title": "このスタンプはLINEスタンプ プレミアムの対象外となりました",
- "sticker.stickerspremium.emojidropped.desc": "引き続き使用するには、個別に購入してください。",
- "sticker.stickerspremium.emojidropped.title": "この絵文字はLINEスタンプ プレミアムの\n対象外となりました",
- "sticker.stickerspremium.emojiexpired.desc": "この絵文字を引き続き使用するには、デラックスコースのプランをもう一度購入してください。",
- "sticker.stickerspremium.expired.desc": "このスタンプを引き続き使用するには、プレミアムプランをもう一度購入してください。",
- "sticker.stickerspremium.expired.title": "プレミアム会員の期間が終了しました",
- "sticker.unpurchased.purchase.btn": "購入する",
- "sticker.unpurchased.recommended.title": "おすすめスタンプ",
- "sticon.downloadAll.desc": "保有している絵文字をまとめてダウンロードできます。",
- "sticon.downloadAll.downloading": "絵文字をダウンロードしています…",
- "sticon.downloading.desc": "絵文字をダウンロードしています。\nしばらくお待ちください。",
- "sticon.expired.desc": "「%1」の有効期間が終了したため、この絵文字は削除されます。",
- "sticon.nearlyExpired.desc.other": "有効期間はあと%n日です。",
- "sticon.recommendedEmoji.label": "おすすめ絵文字",
- "sticon.stickerspremium.deletemoji.popup": "マイプレミアムスタンプからこの絵文字を削除しますか?",
- "subprofile.common.button.cancel": "キャンセル",
- "subprofile.common.popupbutton.continue": "続行",
- "subprofile.common.toast.settingupdated": "プロフィールの設定を変更しました",
- "subprofile.editfriends.button.done": "完了",
- "subprofile.editfriends.popupdesc.dontshowagain": "次回から表示しない",
- "subprofile.editfriends.popuptitle.errorabletoretry": "一部の友だちの設定を変更できませんでした。もう一度お試しください。",
- "subprofile.editfriends.popuptitle.errorunabletoretry": "一部の友だちの設定を変更できませんでした。",
- "subprofile.editfriends.popuptitle.maxlimiterror": "プロフィールを設定できる友だち数の上限に達しています。",
- "subprofile.editfriends.popuptitle.networkerror": "ネットワークが不安定です。接続状態を確認して、もう一度お試しください。",
- "subprofile.editfriends.popuptitle.onlyonmobileapp": "スマートフォン版LINEでのみ利用できる機能です。",
- "subprofile.editfriends.popuptitle.showndifferentprofile": "この友だちに表示されるプロフィールが変更されます。続行しますか?",
- "subprofile.editfriends.popuptitle.showthisprofile": "選択した友だちにこのプロフィールが表示されます。続行しますか?",
- "subprofile.editfriends.popuptitle.temporaryerror": "一時的なエラーが発生しました。しばらくしてからもう一度お試しください。",
- "subprofile.editfriends.popuptitle.temporaryerrortryagain": "一時的なエラーが発生しました。もう一度お試しください。",
- "subprofile.editfriends.subtitle.addfriend": "友だちを追加",
- "subprofile.editfriends.title.onlyonmobileapp": "サブプロフィールの作成・削除は、スマートフォン版LINEでのみ行えます。",
- "subprofile.editfriends.title.selectprofile": "プロフィールを選択",
- "subprofile.editfriends.toast.profileupdatedplural.other": "%n人に表示するプロフィールを変更しました",
- "subprofile.friendsprofile.title.setyourprofile": "プロフィール表示を設定",
- "subprofile.friendsprofile.tooltip.subprofile": "この友だちに表示するあなたのプロフィールを設定してみよう!",
- "subprofile.groupchatmenu.group.profile": "",
- "subprofile.groupchatmenu.tooltip.subprofile": "グループトークの友だちに表示するプロフィールを変更できます",
- "subprofile.groupprofile.tooltip.subprofile": "グループの友だちに表示するプロフィールを使い分けることができます。",
- "subprofile.groupsettings.button.edit": "編集",
- "subprofile.groupsettings.subtitle.amountofprofile.other": "%n個のプロフィールを表示中",
- "subprofile.profile.tooltip.onlyonmobileapp": "スマートフォン版LINEでサブプロフィールを作成すると設定できます",
- "subprofile.selectfriends.button.deselectall": "選択解除",
- "subprofile.selectfriends.button.selectall": "すべて選択",
- "subprofile.selectfriends.button.selectprofile": "プロフィールを選択",
- "subprofile.selectfriends.desc.selectfriends": "サブプロフィールは友だちにのみ表示できます。友だちでないメンバーにはメインプロフィールが表示されます。",
- "subprofile.settings.button.edit": "あなたのプロフィールを見る",
- "subprofile.settings.desc.aboutsubprofile": "PC版では編集のみ可能です。作成・削除はスマートフォン版をご利用ください。",
- "subprofile.settings.desc.zerocase": "設定した友だちはいません。[友だちを追加]をクリックして、表示する友だちを選択してみましょう。",
- "subprofile.settings.title.app": "アプリ",
- "subprofile.yourprofile.bannerdesc.cantsetsubprofile": "",
- "subprofile.yourprofile.bannerdesc.shownfor30days": "",
- "subprofile.yourprofile.bannertitle.expired": "",
- "subprofile.yourprofile.bannertitle.temporaryerror": "",
- "subprofile.yourprofile.button.editfriends": "友だちを編集",
- "subprofile.yourprofile.desc.amountoffriend.other": "%n人の友だちに表示中",
- "subprofile.yourprofile.subtitle.mainprofile": "メインプロフィール",
- "subprofile.yourprofile.subtitle.subprofile": "サブプロフィール",
- "subprofile.yourprofile.title.editfriends": "友だちを編集",
- "subprofile.yourprofile.title.yourprofile": "あなたのプロフィール",
- "talk.addFriend.recommend.reason.group": "同じグループのメンバー",
- "talk.addFriend.recommend.reason.group.name": "「%1」グループのメンバー",
- "talk.addFriend.recommend.reason.lineid": "LINE IDで友だち追加されました",
- "talk.addFriend.recommend.reason.phone": "電話番号で友だち追加されました",
- "talk.addFriend.recommend.reason.qrcode": "QRコードで友だち追加されました",
- "talk.btn.addbuddy.title": "追加",
- "talk.btn.cancel.title": "キャンセル",
- "talk.btn.join.title": "参加",
- "talk.chatlist.chatheader.title": "トーク",
- "talk.chatlist.floating.button.chat": "トーク",
- "talk.chatlist.floating.button.chatandgroup": "トーク・グループ",
- "talk.chatlist.floating.button.group": "グループ",
- "talk.chatlist.floating.button.square": "オープンチャット",
- "talk.chatlist.floating.createChat": "トークルームを作成",
- "talk.chatlist.floating.menu.chatandgroup": "トークルームまたはグループを作成",
- "talk.chatlist.groupheader.title": "メンバー「%1」がいるグループ",
- "talk.chatlist.menu.hide": "非表示",
- "talk.chatlist.menu.pin.off": "トークルームのピン留め解除",
- "talk.chatlist.menu.pin.on": "トークルームをピン留め",
- "talk.chatlist.menu.readAll": "すべて既読にする",
- "talk.chatlist.msgsSearchCount.few": "%n件のメッセージ",
- "talk.chatlist.msgsSearchCount.many": "%n件のメッセージ",
- "talk.chatlist.msgsSearchCount.one": "%n件のメッセージ",
- "talk.chatlist.msgsSearchCount.other": "%n件のメッセージ",
- "talk.chatlist.msgsSearchCount.plurals.other": "%n件のメッセージ",
- "talk.chatlist.msgsSearchCount.two": "%n件のメッセージ",
- "talk.chatlist.msgsSearchCount.zero": "%n件のメッセージ",
- "talk.chatlist.msgsSearchHeader.title": "メッセージ",
- "talk.chatlist.search.placeholder": "トークを検索",
- "talk.label.addbuddy.title": "追加",
- "talk.label.alreadycontact.title": "友だちに登録済みです。",
- "talk.label.blocked.buddy.title": "このアカウントをブロックしています。設定からブロックを解除してください。",
- "talk.label.buddies.title": "友だち",
- "talk.label.buddylist.title": "友だち",
- "talk.label.chatlist.title": "トーク",
- "talk.label.empty.description.1": "ID検索、友だちかもを通じて\n友だちを追加してみましょう。",
- "talk.label.empty.description.3": "上の検索ボックスでID検索して、\n友だちを追加しよう。",
- "talk.label.empty.title.1": "友だちを追加してみよう!",
- "talk.label.empty.title.2": "トークをはじめよう!",
- "talk.label.empty.title.3": "友だちをさがそう!",
- "talk.label.failed.title": "友だちリストを表示できません。",
- "talk.label.failedsearch.rejected.title": "規定の検索回数を超過しました。\n一時的にID/電話番号での検索機能をご利用いただけません。",
- "talk.label.failedsearch.title": "入力したIDのユーザーは存在しないか、 または検索を許可していません。\n",
- "talk.label.favorite.title": "お気に入り",
- "talk.label.groups.title": "グループ",
- "talk.label.invited.title": "招待されているグループ",
- "talk.label.newfriend.title": "新しい友だち",
- "talk.label.nosearchresult.title": "検索結果がありません",
- "talk.label.placehodler.title": "名前で検索",
- "talk.label.recentFriends.title": "最近トークした友だち",
- "talk.label.recommendbuddyplacehodler.title": "友だちのIDで検索",
- "talk.label.recommended.addFriend": "友だち追加",
- "talk.label.recommended.officialAccount.title": "おすすめ公式アカウント",
- "talk.label.recommended.title": "知り合いかも?",
- "talk.label.search.friends": "友だち検索",
- "talk.label.search.friends.QRcode.error.invalidUser": "該当するユーザーが見つかりませんでした。",
- "talk.label.search.friends.phoneNumber.error": "入力した電話番号は、登録されていないか\n検索できません。",
- "talk.label.search.friends.phoneNumber.error.notRegistered": "電話番号でほかのユーザーを検索するには、自分の電話番号をLINEに登録する必要があります。\nスマートフォン版LINEの[設定]>[プロフィール]で電話番号を登録してください。",
- "talk.label.square.title": "オープンチャット",
- "talk.label.thatisyou.title": "自分自身を追加することはできません。",
- "talk.menu.aboutgroup": "グループを編集",
- "talk.menu.addfavorite": "お気に入りに追加",
- "talk.menu.addgroup": "グループ作成",
- "talk.menu.block": "ブロック",
- "talk.menu.call": "発信",
- "talk.menu.call.video": "ビデオ通話",
- "talk.menu.call.voice": "音声通話",
- "talk.menu.editname": "表示名の変更",
- "talk.menu.exit": "終了",
- "talk.menu.group.call": "音声通話・ビデオ通話",
- "talk.menu.help": "ヘルプ",
- "talk.menu.hide": "非表示",
- "talk.menu.leavegroup": "グループ退会",
- "talk.menu.logout": "ログアウト",
- "talk.menu.myProfile": "プロフィール",
- "talk.menu.notes": "ノート",
- "talk.menu.posts": "投稿",
- "talk.menu.rejectbuddy": "ブロック",
- "talk.menu.rejectgroup": "拒否",
- "talk.menu.removeFavorite": "お気に入り解除",
- "talk.menu.removetalkitem": "トークを削除",
- "talk.menu.sendContact": "連絡先をシェア",
- "talk.menu.setting": "設定",
- "talk.menu.showProfile": "プロフィール",
- "talk.menu.starttalk": "トークを開始",
- "talk.menu.talk": "トーク",
- "talk.menu.talkbuddy": "トーク",
- "talk.menu.talkgroup": "トーク",
- "talk.menu.voip": "音声通話",
- "talk.msg.addbuddy.failed": "友だちに追加できませんでした。",
- "talk.msg.addrecommended.failed": "友だちに追加できませんでした。",
- "talk.msg.block.failed": "友だちをブロックできませんでした。",
- "talk.msg.blockrecommended.failed": "友だちをブロックできませんでした。",
- "talk.msg.del.1.n": "このトークルームをトークリストから削除すると、トークルームから退出してトーク履歴を見ることができなくなります。\n削除しますか?",
- "talk.msg.del.room": "このトークルームをトークリストから削除すると、トーク履歴を見ることができなくなります。\n削除しますか?",
- "talk.msg.favorite.failed": "お気に入りに追加できませんでした。",
- "talk.msg.favorite.overflow.failed": "お気に入りに登録できる友だちは100人までです。",
- "talk.msg.hide.failed": "非表示にできませんでした。",
- "talk.msg.joininvitedgroup.failed": "グループに参加できませんでした。",
- "talk.msg.leavegroup.failed": "グループを退会できませんでした。",
- "talk.msg.no.room": "既に削除されているトークルームです。",
- "talk.msg.rejectinvitedgroup.failed": "招待を拒否できませんでした。",
- "talk.network.unreachable": "ネットワーク接続が不安定です。",
- "talk.search.hint": "メッセージを検索",
- "talk.search.label.chatMember": "メンバー名で検索",
- "talk.search.label.displayName": "名前で検索",
- "talk.search.label.member.all": "멤버(%1)",
- "talk.search.label.member.selected": "%1人選択済み",
- "talk.search.label.reSearch": "検索結果から検索",
- "talk.search.label.reSearch.noResult": "これ以上検索できません ",
- "talk.search.label.textMessage": "メッセージ内容で検索",
- "talk.tooltip.delete": "削除",
- "theme.mode.guide.dark.desc": "画面表示モードはダークモードに設定されています。画面表示モードは[設定]>[基本設定]>[画面表示モード]で変更できます。",
- "theme.mode.guide.desc": "システム設定に基づき、画面表示モードが自動で適用されました。画面表示モードは、[設定]>[基本設定]>[画面表示モード]で変更できます。",
- "theme.mode.guide.light.desc": "LINEでダークモードに設定できるようになりました。画面表示モードは[設定]>[基本設定]>[画面表示モード]で変更できます。",
- "theme.mode.guide.title": "新しい画面表示モードを利用できます",
- "timeline.alert.attach": "添付は1個まで可能です。",
- "timeline.alert.attach.unavailable": "投稿できないファイルが添付ファイルに含まれています。 ",
- "timeline.alert.attachphoto": "画像は最大9件まで添付できます。",
- "timeline.alert.commentmaxcount": "1000文字以内で入力してください。",
- "timeline.alert.confirm.close": "ノートの作成をキャンセルしますか?\n作成中のノートは保存されません。",
- "timeline.alert.confirm.deletecomment": "選択したコメントを削除してよろしいですか?",
- "timeline.alert.confirm.deletepost": "削除すると、コメントもすべて削除されます。\n削除しますか?",
- "timeline.alert.confirm.deletethumb": "画像を削除しますか?",
- "timeline.alert.confirm.replacepost": "現在、投稿を作成中です。終了して新しい投稿を作成しますか?",
- "timeline.alert.deletedpost": "すでに削除された投稿です。",
- "timeline.alert.discard": "キャンセルする",
- "timeline.alert.error.group.delete": "選択した公開リストが削除されました。\nもう一度選択してください。",
- "timeline.alert.error.group.rights": "選択したグループに対する権限がありません。\nもう一度選択してください。",
- "timeline.alert.fileMaxcount": "写真、動画は%n件までしか選択できません",
- "timeline.alert.fileMaxcount.plurals.other": "写真、動画は%n件までしか追加できません。",
- "timeline.alert.invalidcoverimage": "送信できないファイルです。",
- "timeline.alert.mediaMaxcount": "スタンプ・写真・動画は20件までしか選択できません",
- "timeline.alert.official.addfriend": "この公式アカウントを友だちに追加すると、\n「いいね」スタンプとコメントの入力ができます。\n友だちに追加しますか? ",
- "timeline.alert.official.addfriend.share": "この公式アカウントを友だちに追加すると、投稿をシェアできるようになります。友だちに追加しますか?",
- "timeline.alert.official.unblockfriend": "ブロックしている公式アカウントです。\nブロックを解除すると「いいね」スタンプと\nコメントの作成が可能です。ブロックを解除しますか?",
- "timeline.alert.official.unblockfriend.share": "ブロックしている公式アカウントです。\nブロックを解除すると投稿をシェアできるようになります。\nブロックを解除しますか?",
- "timeline.alert.photoMaxsize": "画像は最大20MBまで添付できます。\n",
- "timeline.alert.photolimit": "写真1枚につき最大20MB",
- "timeline.alert.photolimit.format": "(.jpg/.jpeg/.png/.bmp/.gif)",
- "timeline.alert.photomaxcount": "写真は%1枚までしか追加できません。",
- "timeline.alert.stickerMaxcount": "スタンプは%n件までしか選択できません",
- "timeline.alert.stickerMaxcount.plurals.other": "スタンプは%n個までしか追加できません。",
- "timeline.alert.stickerUploadRule": "サウンドスタンプやアニメーションスタンプは、 1個のみ追加できます。また、通常のスタンプと同時に追加することはできません。",
- "timeline.alert.textmaxcount": "10,000文字以内で入力してください。",
- "timeline.alert.unblockfriend": "このアカウントはブロックしています。ブロックを解除すると、投稿に「いいね」やコメントができるようになります。ブロックを解除しますか?",
- "timeline.alert.unblockfriend.share": "このアカウントはブロックしています。ブロックを解除すると投稿をシェアできるようになります。ブロックを解除しますか?",
- "timeline.alert.urlUploadRule": "URLは1件まで添付できます。",
- "timeline.alert.videoMaxLength": "動画は最大5分まで添付できます。\n",
- "timeline.alert.videoMaxsize": "動画は1件あたり最大200MBまで\n添付できます。",
- "timeline.alert.videolength": "5分以上の動画は添付できません。",
- "timeline.alert.videolimit": "動画1件につき最大200MBか5分以内",
- "timeline.alert.videolimit.format": "(.mp4/.avi/.mkv/.mpg/.mpeg/.mov)",
- "timeline.alert.videosize": "200MBを超過した動画は 添付することができません。\n",
- "timeline.alert.waitcommentdone": "しばらく経ってからもう一度お試しください。",
- "timeline.already.remove.comment": "すでに削除されたコメントです。",
- "timeline.attachlink.delete": "削除",
- "timeline.attachlink.hint": "リンクのURLを入力してください。",
- "timeline.attachlink.title": "リンク",
- "timeline.comment.approval": "コメントは公式ホーム管理者による承認後、 掲載されます。",
- "timeline.comment.blinddbyadmin": "管理者によって削除されたコメントです。",
- "timeline.comment.delete": "削除",
- "timeline.comment.hint": "コメントを入力",
- "timeline.comment.like": "いいね",
- "timeline.comment.like.cancel": "いいねを取り消す",
- "timeline.comment.loadprevious": "前のコメントを読み込み",
- "timeline.comment.photo.retry": "読み込めませんでした。\nもう一度お試しください。",
- "timeline.comment.reply": "返信",
- "timeline.comment.stickerorphoto": "コメントに追加できるスタンプや写真は1つのみです",
- "timeline.comment.write": "投稿",
- "timeline.common.cancel": "キャンセル",
- "timeline.common.ok": "OK",
- "timeline.common.share": "送信",
- "timeline.date.beforeHour.plurals.few": "%n 時間前",
- "timeline.date.beforeHour.plurals.many": "%n 時間前",
- "timeline.date.beforeHour.plurals.one": "%n 時間前",
- "timeline.date.beforeHour.plurals.other": "%n 時間前",
- "timeline.date.beforeHour.plurals.two": "%n 時間前",
- "timeline.date.beforeHour.plurals.zero": "%n 時間前",
- "timeline.date.beforeMinute.plurals.few": "%n分前",
- "timeline.date.beforeMinute.plurals.many": "%n分前",
- "timeline.date.beforeMinute.plurals.one": "%n分前",
- "timeline.date.beforeMinute.plurals.other": "%n分前",
- "timeline.date.beforeMinute.plurals.two": "%n分前",
- "timeline.date.beforeMinute.plurals.zero": "%n分前",
- "timeline.date.beforeYesterday": "一昨日 %1",
- "timeline.date.justNow": "ちょっと前",
- "timeline.date.yesterday": "昨日 %1",
- "timeline.emptypost.networkerror": "ネットワーク接続エラーによりリクエストが完了していません。\nもう一度お試しください。",
- "timeline.emptypost.other": "まだ投稿がありません。",
- "timeline.emptypost.unsupported": "この公式アカウントが行うのは、トークでのメッセージ送信のみです。",
- "timeline.error.and.retry": "一時的なエラーによりリクエストが完了しませんでした。\nもう一度お試しください。",
- "timeline.error.attach.popupSticker": "このスタンプは、動きやサウンドがない静止画スタンプとして表示されます。",
- "timeline.error.cannot.access.file": "一部の写真をアップロードできませんでした。\n元の写真がPCから削除されているか、\n上限サイズの20MBを超えています。",
- "timeline.error.list.load.retry": "読み込めませんでした…。\n再読み込みしてください。",
- "timeline.footer.comment": "コメントする",
- "timeline.footer.like": "いいね",
- "timeline.groupPanel.startgroup": "グループを作ってみましょう!",
- "timeline.groupPanel.startgroup.desc": "ノートを作成してアルバムを作ることができます。",
- "timeline.label.nosearchresult.title": "検索結果がありません",
- "timeline.like.count.other": "いいね %1",
- "timeline.loading.examine.time": "メンテナンス時間",
- "timeline.loading.examine.timeline": "%1はサービス メンテナンス中です。",
- "timeline.loading.neednewversion": "最新バージョンに対応した画面です。",
- "timeline.loading.networkerror": "ネットワーク接続エラーによりリクエストが完了していません。\nもう一度お試しください。",
- "timeline.loading.retry": "更新",
- "timeline.menu.sharetotalk": "送信先を選択",
- "timeline.mergedposts.detail": "詳細",
- "timeline.no": "いいえ",
- "timeline.note.popupdesc.sharenote": "このノートをトークルームにシェアしますか?",
- "timeline.noti.content.NC_1001_1": "%1が新たなノートを作成しました。",
- "timeline.noti.content.NC_1001_2": "%1、%2が新しいノートを作成しました。",
- "timeline.noti.content.NC_1001_3": "%1、%2他%3名が新しいノートを作成しました。",
- "timeline.noti.content.NC_1002_1": "%1があなたの投稿にコメントをつけました。",
- "timeline.noti.content.NC_1002_2": "%1、%2があなたの投稿にコメントをつけました。",
- "timeline.noti.content.NC_1002_3": "%1、%2他%3名が新しい投稿にコメントをつけました。",
- "timeline.noti.content.NC_1003_1": "%1があなたにコメントしました。",
- "timeline.noti.content.NC_1003_2": "%1、%2があなたにコメントしました。",
- "timeline.noti.content.NC_1003_3": "%1、%2他%3名があなたにコメントしました。",
- "timeline.noti.content.NC_1004_1": "%1があなたの投稿に「いいね」しました。",
- "timeline.noti.content.NC_1004_2": "%1、%2があなたの投稿に「いいね」しました。",
- "timeline.noti.content.NC_1004_3": "%1、%2、他%3人があなたの投稿に「いいね」しました。",
- "timeline.noti.content.NC_2001_1": "%1が新しいアルバムを作成しました。",
- "timeline.noti.content.NC_2001_2": "%1、%2が新しいアルバムを作成しました。",
- "timeline.noti.content.NC_2001_3": "%1、%2他%3名が新しいアルバムを作成しました。",
- "timeline.noti.content.NC_2002_1": "%1がアルバムに写真を追加しました。",
- "timeline.noti.content.NC_2002_2": "%1、%2がアルバムに写真を追加しました。",
- "timeline.noti.content.NC_2002_3": "%1、%2他%3名がアルバムに写真を追加しました。",
- "timeline.noti.content.NC_3001_1": "%1があなたの投稿にコメントをつけました。",
- "timeline.noti.content.NC_3001_2": "%1、%2があなたの投稿にコメントをつけました。",
- "timeline.noti.content.NC_3001_3": "%1、%2他%3名が新しい投稿にコメントをつけました。",
- "timeline.noti.content.NC_3002_1": "%1があなたにコメントしました。",
- "timeline.noti.content.NC_3002_2": "%1、%2があなたにコメントしました。",
- "timeline.noti.content.NC_3002_3": "%1、%2他%3名があなたにコメントしました。",
- "timeline.noti.content.NC_3003_1": "%1があなたの投稿に「いいね」しました。",
- "timeline.noti.content.NC_3003_2": "%1、%2があなたの投稿に「いいね」しました。",
- "timeline.noti.content.NC_3003_3": "%1、%2、他%3人があなたの投稿に「いいね」しました。",
- "timeline.noti.content.NC_4001_1": "%1がグループに参加しました。",
- "timeline.noti.content.NC_4002_1": "%1があなたの投稿をシェアしました。",
- "timeline.noti.content.NC_UPDATE": "最新バージョンのLINEにアップデートすると内容を確認できます。",
- "timeline.noti.empty": "新しい通知はありません。",
- "timeline.noti.error": "通知を読み込むことができません。\nしばらくしてからもう一度お試しください。 ",
- "timeline.noti.home": "ホーム",
- "timeline.oamerge.feed.title": "公式アカウントフィード",
- "timeline.oamerge.title": "マイ公式アカウント",
- "timeline.officialprofile.networkerror": "ネットワーク接続エラーによりリクエストが完了していません。\nもう一度お試しください。",
- "timeline.officialprofile.title": "プロフィール",
- "timeline.original.open": "オリジナルページを見る",
- "timeline.poppost.counttime.hour.other": "残り%n時間",
- "timeline.poppost.counttime.hour.plurals.few": "残り%n時間",
- "timeline.poppost.counttime.hour.plurals.many": "残り%n時間",
- "timeline.poppost.counttime.hour.plurals.one": "残り%n時間",
- "timeline.poppost.counttime.hour.plurals.other": "残り%n時間",
- "timeline.poppost.counttime.hour.plurals.two": "残り%n時間",
- "timeline.poppost.counttime.hour.plurals.zero": "残り%n時間",
- "timeline.poppost.counttime.min.other": "残り%n分",
- "timeline.poppost.counttime.min.plurals.few": "残り%n分",
- "timeline.poppost.counttime.min.plurals.many": "残り%n分",
- "timeline.poppost.counttime.min.plurals.one": "残り%n分",
- "timeline.poppost.counttime.min.plurals.other": "残り%n分",
- "timeline.poppost.counttime.min.plurals.two": "残り%n分",
- "timeline.poppost.counttime.min.plurals.zero": "残り%n分",
- "timeline.poppost.counttime.soon": "残り1分",
- "timeline.poppost.tooltip.hour.other": "この投稿は%n時間後に削除されます",
- "timeline.poppost.tooltip.hour.plurals.few": "この投稿は%n時間後に削除されます",
- "timeline.poppost.tooltip.hour.plurals.many": "この投稿は%n時間後に削除されます",
- "timeline.poppost.tooltip.hour.plurals.one": "この投稿は%n時間後に削除されます",
- "timeline.poppost.tooltip.hour.plurals.other": "この投稿は%n時間後に削除されます",
- "timeline.poppost.tooltip.hour.plurals.two": "この投稿は%n時間後に削除されます",
- "timeline.poppost.tooltip.hour.plurals.zero": "この投稿は%n時間後に削除されます",
- "timeline.poppost.tooltip.min.other": "この投稿は%n分後に削除されます",
- "timeline.poppost.tooltip.min.plurals.few": "この投稿は%n分後に削除されます",
- "timeline.poppost.tooltip.min.plurals.many": "この投稿は%n分後に削除されます",
- "timeline.poppost.tooltip.min.plurals.one": "この投稿は%n分後に削除されます",
- "timeline.poppost.tooltip.min.plurals.other": "この投稿は%n分後に削除されます",
- "timeline.poppost.tooltip.min.plurals.two": "この投稿は%n分後に削除されます",
- "timeline.poppost.tooltip.min.plurals.zero": "この投稿は%n分後に削除されます",
- "timeline.poppost.tooltip.soon": "この投稿は1分後に削除されます",
- "timeline.post.attach.drag.guide": "写真・動画をドラッグ&ドロップして添付できます",
- "timeline.post.attach.drag.guide.premium": "写真をドラッグ&ドロップして添付できます",
- "timeline.post.attach.draghere": "ここに写真・動画をここにドラッグ&ドロップしてください",
- "timeline.post.attach.draghere.premium": "ここに写真をドラッグ&ドロップしてください",
- "timeline.post.delete": "削除",
- "timeline.post.deleted": "すでに削除された投稿です。",
- "timeline.post.deletedbyadmin": "管理者によって削除された投稿です。",
- "timeline.post.done": "完了",
- "timeline.post.edit": "編集",
- "timeline.post.edit.desc": "ノートの編集をキャンセルしますか?\n編集中の内容は保存されません。",
- "timeline.post.friends": "%1さんのLINE友だち",
- "timeline.post.friends.detail": "この投稿は%1さんのLINE友だちのみ閲覧できます。\n",
- "timeline.post.grid.more": "+%n",
- "timeline.post.hashtag": "ハッシュタグ",
- "timeline.post.hashtag.guide.title": "#ハッシュタグを追加してみよう!",
- "timeline.post.hashtag.results.related": "関連:",
- "timeline.post.hint": "今なにしてる?",
- "timeline.post.keep": "編集を続ける",
- "timeline.post.likeshare.cancel": "シェアをキャンセル",
- "timeline.post.likeshare.canceled": "シェアを取り消しました。",
- "timeline.post.likeshare.done": "すでに「いいよ」でシェアしています。 ",
- "timeline.post.mention.alert": "最大20人までタグ付けできます。",
- "timeline.post.mention.empty.description": "\"@名前と入力して、友だちをタグ付けしてみましょう。\nその友だちに通知がすぐに送られ、投稿を確認してもらえます。]]>\"",
- "timeline.post.mention.empty.title": "@を付けて友だちをタグ付けしよう!",
- "timeline.post.mention.setting.edit.alert": "この投稿の公開設定を変更すると、次のユーザーがこの投稿を表示できなくなります。続行しますか?",
- "timeline.post.newpost": "新しい投稿",
- "timeline.post.onlyme": "自分のみ",
- "timeline.post.public": "全体に公開",
- "timeline.post.public.desc": "誰でも投稿を見ることができます。",
- "timeline.post.public.sharetotimeline": "タイムラインでシェア",
- "timeline.post.scope.group": "このグループのメンバーのみ閲覧できます。",
- "timeline.post.scope.manToMan": "%1とあなただけが閲覧できます。",
- "timeline.post.seemore": "もっと見る",
- "timeline.post.share": "シェア",
- "timeline.post.sharedchanged": "シェアされたオリジナル投稿の公開設定が変更されたため表示できません。",
- "timeline.post.shareddeleted": "投稿元の投稿が削除されたか退会したアカウントの投稿です。",
- "timeline.post.sorting.option.ranking": "랭킹순",
- "timeline.post.sorting.option.time": "시간순",
- "timeline.post.write": "投稿",
- "timeline.publicgroup.emptymember": "追加された友だちはいません",
- "timeline.publicgroup.group": "グループ",
- "timeline.publicgroup.group.empty": "グループリストがありません。",
- "timeline.publicgroup.linefriends": "友だち",
- "timeline.publicgroup.linefriends.desc": "ホーム閲覧を許可した友だちに公開",
- "timeline.publicgroup.nobodysee": "この投稿は0人に公開されています。",
- "timeline.publicgroup.sharelist": "公開リスト",
- "timeline.publicgroup.title.detail": "この投稿の公開範囲",
- "timeline.publicgroup.title.post": "投稿の公開設定",
- "timeline.recommend": "おすすめ",
- "timeline.report.desc": "通報すると、当該ユーザーの情報と受信した直近100件までのトーク内容または指定した投稿内容を送信します。",
- "timeline.report.done": "通報しました",
- "timeline.report.reason.advertising": "スパム / 宣伝目的",
- "timeline.report.reason.genderHarassment": "性的いやがらせ / 出会い目的",
- "timeline.report.reason.harassment": "迷惑行為",
- "timeline.report.reason.other": "その他",
- "timeline.report.selectReason": "通報する理由を以下から選んでください。",
- "timeline.report.title": "通報",
- "timeline.request.failed.likeshare.status": "シェア状態を読み込めませんでした。",
- "timeline.request.failed.timeline": "該当の投稿の情報を 読み込むことができません。",
- "timeline.request.failed.url": "URL情報を読み込めませんでした。\nもう一度お試しください。",
- "timeline.request.failed.user": "該当するユーザー情報を確認できません。",
- "timeline.retry": "再試行",
- "timeline.setting.autoopen": "新しい友だちに自動公開",
- "timeline.setting.buddylist.empty": "LINEの友だちがいません。",
- "timeline.setting.desc": "公開設定",
- "timeline.setting.desc2": "自分のホームを公開するかどうか設定します。",
- "timeline.setting.feed.ranking": "投稿の並べ替え",
- "timeline.setting.feed.ranking.option": "人気の投稿をトップに表示",
- "timeline.setting.label.blocked": "非公開",
- "timeline.setting.label.unblocked": "公開",
- "timeline.setting.usetoast": "LINE VOOM通知",
- "timeline.share.copyUrl": "リンクをコピー",
- "timeline.share.copyUrl.toast": "リンクをコピーしました",
- "timeline.sharetohome.hint": "追加するメッセージを入力してください。",
- "timeline.sharetotalk.comfirm.desc": "%1に送信しますか?",
- "timeline.sharetotalk.empty.chat": "選択できるトークがありません。",
- "timeline.sharetotalk.empty.friend": "招待できる友だちがいません。",
- "timeline.sharetotalk.empty.group": "選択できるグループがありません。",
- "timeline.sharetotalk.tab.chat": "トーク",
- "timeline.sharetotalk.tab.friend": "友だち",
- "timeline.sharetotalk.tab.group": "グループ",
- "timeline.sharetotalk.title": "トークに送信",
- "timeline.system.check.wait": "現在メンテナンス中のため、ご利用いただけません。\nしばらくしてからもう一度お試しください。",
- "timeline.time.afternoon": "午後",
- "timeline.time.morning": "午前",
- "timeline.video.popup.waiting": "エンコード中です。\nしばらくしてからもう一度お試しください。",
- "timeline.yes": "はい",
- "timline.report.policy.desc": "通報すると、当該ユーザーの情報と受信した直近20件までのトーク内容または関連する投稿が送信されます。",
- "unsupported.file.checkbox": "常に圧縮して送信する",
- "unsupported.file.common": "送信できないファイルをZIPファイルに圧縮して送信します。",
- "unsupported.file.compress.fail": "ファイルを圧縮できませんでした。もう一度お試しください。",
- "unsupported.file.compressing": "圧縮中… ",
- "unsupported.file.dontshow": "今後、このメッセージを表示しない",
- "unsupported.file.multi": "送信できない形式のファイルが含まれています。ZIPファイルに圧縮して送信しますか?",
- "unsupported.file.single": "送信できない形式のファイルです。ZIPファイルに圧縮して送信しますか?",
- "update.msg.check.security1": "セキュリティチェック中です。",
- "update.msg.check.security2": "しばらくお待ちください。",
- "update.summary.url": "http://openapis.jboard.naver.jp/mobile/document/line_desktop/JA/996",
- "upgradegroupinvite.button.requireinvites": "オン",
- "upgradegroupinvite.popup.desc.toomanyfriends": "メンバーが100人を超えるグループでは、[友だちにグループへの参加を確認]をオンにする必要があります。\nこの設定をオフのままにするには、メンバーを100人以下にしてください。",
- "upgradegroupinvite.popup.title.toomanyfriends": "[友だちにグループへの参加を確認]をオンにしますか?",
- "upic.btn.cancel.title": "キャンセル",
- "upic.btn.find.title": "参照",
- "upic.btn.ok.title": "OK",
- "upic.label.desc.title": "写真はjpg、jpeg、png、gif、bmpファイルのみ\nアップロードが可能です。",
- "upic.label.upic.title": "プロフィール画像の編集",
- "upic.msg.cantFindFile": "ファイルが見つかりません。",
- "upic.msg.not.image": "画像ファイルのみを送信することができます。",
- "upic.msg.select": "プロフィールの写真を選択して下さい。",
- "upic.msg.sizeExceeds": "イメージファイルは、最大20MBまで可能です。",
- "user.report.error": "このメッセージは存在しないため、通報できません。",
- "user.report.policy.desc": "通報すると、当該ユーザーの情報と受信した直近10件までのトーク内容または指定した投稿内容を送信します。",
- "user.report.question": "このユーザーをブロックしますか?",
- "user.search.placeholder": "名前で検索",
- "user.warning.investmentfraud": "LINEを悪用した詐欺にご注意ください。",
- "user.warning.invitedtogroup": "%2があなたをグループに招待しました。\nこのユーザーを不審に思ったら、ブロックして通報してください。]]>",
- "user.warning.spammer": "友だちではないユーザーです",
- "user.warning.spammer.group": "%1からグループに招待されました。このユーザーを不審に思ったら[通報]をクリックしてください。",
- "videoProfile.error.fileType": "登録できない形式のファイルです。もう一度お試しください。",
- "videoProfile.error.lessThenOneSec": "1秒以下の動画は登録できません。もう一度お試しください。",
- "viewer.alert.desc.delete": "削除しますか?",
- "viewer.alert.desc.fullsize": "全画面表示を終了するにはEscキーを押してください",
- "viewer.alert.desc.mustinstallplugin": "写真や動画、GIFを表示するにはコンテンツビューアーのプラグインが必要です。今すぐダウンロードしますか?",
- "viewer.alert.image.expired.previewinstead": "保存期間が終了したため、ファイルのサムネイルのみ確認できます",
- "viewer.alert.video.expired": "保存期間が終了しているため、動画を再生できません。",
- "viewer.contextmenu.copy": "コピー",
- "viewer.contextmenu.forward": "転送",
- "viewer.contextmenu.keep": "Keepに保存",
- "viewer.contextmenu.keepmemo": "Keepメモに転送",
- "viewer.contextmenu.saveas": "名前を付けて保存",
- "viewer.contextmenu.scanqr": "QRコードをスキャン",
- "viewer.contextmenu.scantext": "文字認識",
- "viewer.copy.toast.copied": "クリップボードにコピーしました。",
- "viewer.error.media.download.fail": "ファイルを保存できませんでした。\nもう一度お試しください。",
- "viewer.error.video.common": "一時的なエラーにより再生できません",
- "viewer.error.video.network": "ネットワークやサーバーのエラーにより再生できません。\nもう一度お試しください。",
- "viewer.error.video.transient": "一時的なエラーにより再生できません。\nもう一度お試しください。",
- "viewer.keep.toast.saved": "Keepに保存されました。",
- "viewer.menu.edit": "編集",
- "viewer.menu.forward": "転送",
- "viewer.menu.info.name": "ファイル名",
- "viewer.menu.keep": "Keepに保存",
- "viewer.menu.keepmemo": "Keepメモに転送",
- "viewer.menu.more.delete": "削除",
- "viewer.menu.more.info": "ファイル情報",
- "viewer.menu.more.speed": "再生速度",
- "viewer.menu.openfolder": "フォルダを開く",
- "viewer.menu.originalsize": "実際のサイズ",
- "viewer.menu.rotate": "90 度回転",
- "viewer.menu.saveas": "名前を付けて保存",
- "viewer.menu.scanqr": "QRコードをスキャン",
- "viewer.menu.scantext": "文字認識",
- "viewer.menu.showalbums": "すべてのコンテンツを表示",
- "viewer.menu.showallcontents": "すべてのコンテンツを表示",
- "viewer.menu.thumbnail.expand": "サムネイルを表示",
- "viewer.menu.thumbnail.fold": "サムネイルを非表示",
- "viewer.menu.video.pause": "一時停止",
- "viewer.menu.video.play": "再生",
- "viewer.menu.video.replay": "もう一度再生",
- "viewer.menu.video.stop": "停止",
- "viewer.menu.video.volume": "音量",
- "viewer.menu.zoomin": "拡大",
- "viewer.menu.zoomout": "縮小",
- "viewer.play.toast.speaker.beingconnected": "他のスピーカーに接続中です。しばらくしてからもう一度お試しください。",
- "viewer.popup.info.created": "撮影時間",
- "viewer.popup.info.filesize": "ファイルサイズ",
- "viewer.popup.info.from": "送信者",
- "viewer.popup.info.resolution": "解像度",
- "viewer.popup.info.saved": "保存時間",
- "viewer.saveas.toast.saved": "ダウンロードが完了しました。",
- "viewer.tooltip.window.close": "閉じる",
- "viewer.tooltip.window.maximize": "最大化",
- "viewer.tooltip.window.minimize": "最小化",
- "viewer.tooltip.window.restore": "元に戻す(縮小)",
- "voip.beautyfeature.button.clearall": "適用なし",
- "voip.beautyfeature.popupbutton.cancel": "キャンセル",
- "voip.beautyfeature.popupbutton.clearall": "解除",
- "voip.beautyfeature.popupdesc.clearfaceeffects": "ビューティー機能と顔エフェクトは同時に使用できません。顔エフェクトを解除しますか?",
- "voip.beautyfeature.toggle.darkeneyebrows": "アイブロウの濃さ",
- "voip.beautyfeature.toggle.fillinlips": "リップの濃さ",
- "voip.beautyfeature.toggle.resizeeyes": "目の大きさ",
- "voip.beautyfeature.toggle.revert": "デフォルト",
- "voip.beautyfeature.toggle.slimjawline": "輪郭",
- "voip.beautyfeature.toggle.slimnose": "鼻幅",
- "voip.beautyfeature.toggle.smoothcomplexion": "滑らか",
- "voip.button.label.call": "応答",
- "voip.button.label.disconnect": "終了",
- "voip.button.label.voiceonly": "カメラをオフにして応答",
- "voip.call.tooltip.cameraunavailable": "カメラ接続なし",
- "voip.call.tooltip.microphoneunavailable": "マイク接続なし",
- "voip.connect.camera.alert": "カメラが接続されました。カメラをオンにしますか?",
- "voip.connect.mic.alert": "マイクが接続されました。マイクをオンにしますか?",
- "voip.desc.calling": "呼び出しています...",
- "voip.desc.calling.failed": "%1通話することができませんでした。 もう一度かけ直してください。(%2)",
- "voip.desc.calling.failed.accept.other.device": "他の機器で通話中です。",
- "voip.desc.calling.failed.contact.busy": "%1さんは通話中です。\nしばらくしてからもう一度かけ直してください。",
- "voip.desc.calling.failed.maintance": "一時的にDesktop版の音声通話を 利用することができません。\nしばらくして、\nもう一度やり直してください",
- "voip.desc.calling.failed.need.audio": "サウンドカードを確認することができません。\n確認後に再度通話を試みてください。",
- "voip.desc.calling.failed.need.device": "マイク、スピーカーが見つかりません。\n接続後に再度通話を試みてください。",
- "voip.desc.calling.failed.need.devicesetting": "マイクまたはスピーカーがオフになっています。設定をご確認の上、もう一度通話をお試しください。",
- "voip.desc.calling.failed.need.mic": "マイクが接続されていません。\n接続後に再度通話を試みてください。",
- "voip.desc.calling.failed.need.oscamera": "カメラを使用できません。端末のカメラへのアクセスを許可してください。",
- "voip.desc.calling.failed.need.osmic": "マイクを使用できません。端末のマイクへのアクセスを許可してください。",
- "voip.desc.calling.failed.need.ospeaker": "スピーカーを使用できません。コントロールパネルからマイクを有効にしてください。",
- "voip.desc.calling.failed.need.spk": "スピーカーが接続されていません。\n接続後に再度通話を試みてください。",
- "voip.desc.calling.failed.need.update": "モバイルを最新バージョンにアップデートすると、\nPC版で音声通話を利用することができます。\n",
- "voip.desc.calling.failed.no.accept": "応答がありません。\nしばらくしてからもう一度かけ直してください。",
- "voip.desc.calling.failed.other.device.use": "他の機器で通話中です。",
- "voip.desc.calling.failed.peer": "通話できません\n%1は最新バージョンを利用していないか、\n通話機能に対応していないため応答することができません。",
- "voip.desc.calling.video": "ビデオ通話発信中",
- "voip.desc.camerausage": "ビデオ通話を利用するには、カメラへのアクセスをLINEに許可してください。",
- "voip.desc.camerausage.maconly": "ビデオ通話を利用するには、[システム環境設定]>[セキュリティとプライバシー]>[プライバシー]タブ>[カメラ]で[LINE]を選択してください",
- "voip.desc.connecting": "接続しています...",
- "voip.desc.makeCall.Failed.network": "ネットワークが不安定なため通話できません。\nしばらくしてからもう一度かけ直してください。",
- "voip.desc.mic.failed": "マイクで音声を認識できません。マイクの状態を確認してもう一度お試しください。",
- "voip.desc.microphoneusage": "音声通話やビデオ通話を利用するには、マイクへのアクセスをLINEに許可してください。",
- "voip.desc.microphoneusage.maconly": "音声・ビデオ通話を利用するには、[システム環境設定]>[セキュリティとプライバシー]>[プライバシー]タブ>[マイク]で[LINE]を選択してください。",
- "voip.desc.ringing": "から着信です。",
- "voip.desc.ringing.video": "ビデオ通話着信中...",
- "voip.desc.speaker.failed": "スピーカーで音声を出力できません。スピーカーの状態を確認してもう一度お試しください。",
- "voip.disconnect.camera.entry.alert": "ビデオ通話に参加しますか?カメラが接続されていないため、映像はオフになります。",
- "voip.disconnect.camera.error": "カメラが接続されていないため、この機能は利用できません。",
- "voip.disconnect.mic.entry.alert": "ビデオ通話に参加しますか?マイクが接続されていないため、音声はオフになります。",
- "voip.disconnect.mic.entry.alert.audio": "音声通話に参加しますか?マイクが接続されていないため、音声はオフになります。",
- "voip.disconnect.mic.error": "マイクが接続されていないため、この機能は利用できません。",
- "voip.disconnect.micncam.entry.alert": "ビデオ通話に参加しますか?マイクとカメラが接続されていないため、音声と映像はオフになります。",
- "voip.effect.guide.adjust.effect": "ビューティー効果を調整できます",
- "voip.effect.guide.detect.face": "顔が表示されるように位置を調整してください",
- "voip.effect.guide.extra.001": "友だちと一緒に試してみましょう",
- "voip.effect.guide.extra.006": "頭を左右に揺らしてください",
- "voip.effect.guide.extra.011": "笑ってください",
- "voip.effect.guide.extra.012": "スライドバーでエフェクトの強度を調節できます",
- "voip.effect.guide.eye.blink": "まばたきしてください",
- "voip.effect.guide.mouth.open": "口を開けてください",
- "voip.error.init.failed.callee": "[%1さんから着信です]\n現在PC環境の都合により、通話機能を利用するときに\n強制終了されることがあります。",
- "voip.error.init.failed.caller": "現在PC環境の都合により、通話機能を利用するときに\n強制終了されることがあります。",
- "voip.label.create.title": "音声通話",
- "voip.label.mic": "マイク话筒",
- "voip.label.speaker": "スピーカー",
- "voip.label.video": "ビデオ通話",
- "voip.label.video.cameraon": "オンにする",
- "voip.label.video.local.cameraOff": "カメラをオフにしました。",
- "voip.label.video.local.cameraOn": "カメラをオンにしました。",
- "voip.label.video.local.noCamera": "カメラが見つかりません。\n相手はあなたの映像を見ることができません。",
- "voip.label.video.low.quality": "接続状態が不安定です。",
- "voip.label.video.remote.cameraOff": "相手がカメラをオフにしました。",
- "voip.label.video.remote.cameraOn": "相手がカメラをオンにしました。",
- "voip.label.video.remote.noCamera": "相手にカメラがないか、\n映像が正常に受信されませんでした。",
- "voip.label.video.ringing": "カメラをオンにしますか?",
- "voip.label.video.title": "%1さんとのビデオ通話",
- "voip.media.unsupported.alert.update": "%1が画面シェアを開始しました。シェアされた画面を表示するには、LINEを最新バージョンにアップデートしてください。",
- "voip.msg.already.during.call": "ほかのトークで通話中です。",
- "voip.msg.bad.connection": "接続状態が不安定です。",
- "voip.msg.bad.connection.failover": "再接続中...",
- "voip.msg.error.no.audio.source": "マイクに問題が発生したため通話が終了しました。しばらくしてからおかけ直しください。",
- "voip.msg.error.no.audio.tx.stream": "エラー 正常に処理できませんでした。\nしばらく経ってからもう一度お試しください。",
- "voip.msg.network.unstable": "ネットワーク接続が不安定です。",
- "voip.msg.not.avalable.during.call": "この機能は通話中には利用できません。",
- "voip.msg.peer.no.audio.source": "通話相手のマイクに問題が発生したため通話が終了しました。しばらくしてからおかけ直しください。",
- "voip.msg.send.freeCall": "%1と音声通話しますか?",
- "voip.msg.send.videoCall": "%1とビデオ通話しますか?",
- "voip.msg.switch.to.video.noCamera": "カメラが見つからないため、メンバーはあなたの映像を見ることができません。ビデオ通話に参加しますか?",
- "voip.msg.video.camera.unavailable": "ご利用のカメラはサポートされていません。\n[設定]>[通話]>[カメラ設定]で他のカメラを選択してください。サポートされていないカメラでも通話できますが、あなたの映像は友だちに表示されません。",
- "voip.msg.video.term.device.control": "相手の操作によりビデオ通話が終了し、\n音声通話モードになりました。",
- "voip.msg.video.term.device.interrupted": "相手のカメラが停止中です。",
- "voip.msg.video.term.overload.direct.video.call.failed": "一時的なエラーによりビデオ通話がご利用いただけません。\n音声通話をご利用いただくか、しばらくしてからお試しください。",
- "voip.msg.video.term.overload.video.changing.failed": "一時的なエラーによりビデオ通話がご利用いただけません。\nしばらくしてからお試しください。",
- "voip.msg.video.term.unknown": "正常に処理できませんでした。\nしばらく経ってからもう一度お試しください。",
- "voip.msg.video.term.unstable": "ネットワーク状態が不安定なため、音声通話で接続されました。",
- "voip.msg.video.term.unsupported.device.video": "ビデオ通話ができません。\n相手が最新バージョンを利用していないか、\nビデオ通話機能に対応していないため応答できません。",
- "voip.msg.video.term.unsupported.device.voice": "音声通話で接続されました。\n相手が最新バージョンを利用していないか、\nビデオ通話機能に対応していません。",
- "voip.msg.warning.close": "通話を終了しますか?",
- "voip.msg.warning.groupclose": "グループ通話から退出しますか?",
- "voip.noisecanceling.desc.guide": "周囲の騒音を除去するノイズキャンセリングがオンになりました",
- "voip.noisecanceling.popup.desc": "設定の変更は次回の通話から適用されます。今すぐ変更を適用するには、通話を終了してからもう一度開始してください。",
- "voip.noisecanceling.tooltip.off": "ノイズキャンセリングをオン",
- "voip.noisecanceling.tooltip.on": "ノイズキャンセリングをオフ",
- "voip.popup.end": "終了",
- "voip.popup.start": "開始",
- "voip.screen.share.remove.monitor": "ディスプレイとの接続が切れたため通話が終了しました",
- "voip.screenshare.button.zoomin": "拡大",
- "voip.screenshare.button.zoomout": "縮小",
- "voip.screenshare.button.zoomreset": "リセット",
- "voip.screenshare.desc.pause": "画面シェアが一時停止されました",
- "voip.screenshare.desc.pause.tooltip": "ウィンドウのサイズを最小化または変更したり、ウィンドウを移動したりすると、画面シェアが一時停止されます。",
- "voip.screenshare.error.closeapp": "閉じた画面はシェアできません。",
- "voip.screenshare.index.screen": "画面",
- "voip.screenshare.index.window": "ウィンドウ",
- "voip.screenshare.option.optimizevideoclips": "動画の最適化",
- "voip.screenshare.tooltip.fullscreen": "全画面 %1",
- "voip.screenshare.tooltip.optimizevideoclips": "画面シェア中の動画の途切れを最小限に抑えます",
- "voip.tooltip.callsetting": "通話設定",
- "voip.tooltip.camera.off": "カメラをオフ",
- "voip.tooltip.camera.on": "カメラをオン",
- "voip.tooltip.chat": "トークルーム",
- "voip.tooltip.echocanceloff": "エコーキャンセリングをオフ",
- "voip.tooltip.echocancelon": "エコーキャンセリングをオン",
- "voip.tooltip.end.call": "終了",
- "voip.tooltip.end.groupmeetingcall": "退出",
- "voip.tooltip.fullhd": "[Full HD voice]が緑色で表示されている時は、よりクリアな音声で通話できます",
- "voip.tooltip.mic.off": "マイクをオフ",
- "voip.tooltip.mic.off.muteronguide": "マイクがオフになっています。会話をするには、マイクをオンにしてください。",
- "voip.tooltip.mic.off.spacebartoast": "マイクをオフにしました。スペースバーを長押しすると、マイクを一時的にオンにできます。",
- "voip.tooltip.mic.on": "マイクをオン",
- "voip.tooltip.microphone.autovolume": "音量の自動設定中",
- "voip.tooltip.onscreentool.clearall": "すべてクリア",
- "voip.tooltip.onscreentool.eraser": "消しゴム",
- "voip.tooltip.onscreentool.off": "ペイント機能を閉じる",
- "voip.tooltip.onscreentool.on": "ペイント機能を開く",
- "voip.tooltip.onscreentool.pen": "ペン",
- "voip.tooltip.onscreentool.pointer": "ポインター",
- "voip.tooltip.onscreentool.redo": "やり直す",
- "voip.tooltip.onscreentool.select": "移動",
- "voip.tooltip.onscreentool.stamp": "スタンプ",
- "voip.tooltip.onscreentool.undo": "元に戻す",
- "voip.tooltip.screen.share": "画面シェア",
- "voip.tooltip.screen.share.off": "画面シェアを終了",
- "voip.tooltip.screen.share.start": "ビデオ通話中にPC画面をシェアできます",
- "voip.tooltip.screen.share.stop": "画面をシェアしています。シェアを停止するには、ボタンをもう一度クリックしてください。",
- "voip.tooltip.speaker.off": "サウンドをオフ",
- "voip.tooltip.speaker.on": "サウンドをオン",
- "voip.tooltip.switch.to.video": "ビデオ通話に切り替え",
- "voip.tooltip.video.camera": "カメラのオン/オフ",
- "voip.tooltip.video.camera.select": "カメラ選択",
- "voip.tooltip.video.fullscreen": "全画面で表示",
- "voip.tooltip.video.fullscreen.restore": "元のサイズに戻す",
- "voip.tooltip.video.pin": "最前面に表示",
- "voip.tooltip.video.pinoff": "最前面の表示を解除",
- "voip.tooltip.video.speaker": "スピーカーのオン/オフ",
- "voip.tooltip.video.transform": "ビデオ通話を\n開始",
- "voip.tooltip.volumezero": "スピーカーのボリュームが0に設定されています。サウンドを聞くにはボリュームを上げてください。",
- "voip.video.calling.failed.cameraSwitch": "カメラを変更できませんでした。\nもう一度お試しください。",
- "voip.video.calling.failed.noCamera": "カメラをオンにできません。\nカメラの接続状態をご確認ください。",
- "voip.video.desc.makeCall.Failed": "通話できません。 しばらくしてからもう一度かけ直してください。",
- "voip.video.dynamicspeaking.pinoff": "ピン留めを解除",
- "voip.video.dynamicspeaking.pinoff.desc": "映像をピン留めしました。ピン留めを解除するには、右上の[ピン留めを解除]をクリックしてください。",
- "voip.video.effect.popup.downloadfail": "エフェクトをダウンロードできませんでした。再試行しますか?",
- "voip.video.effect.toast.cameraoff": "カメラをオンにしてください",
- "voip.video.effect.toast.detectionfail": "顔が表示されるように位置を調整してください",
- "voip.video.effect.toast.downloadfail": "ダウンロードできませんでした。もう一度お試しください。",
- "voip.video.effect.toast.nospace": "端末の空き容量が不足しています。不要なデータを削除して、もう一度お試しください。",
- "voip.video.effect.toast.xpccrash": "一時的なエラーによりエフェクトが解除されました\nもう一度設定してください。",
- "voip.video.menu.bg": "背景",
- "voip.video.menu.bg.alert.addbg": "ファイルを読み込めません。他のファイルを選択してください。",
- "voip.video.menu.bg.alert.addbg.button": "選択",
- "voip.video.menu.bg.alert.maxbg": "追加できる背景数の上限に達しているため、背景を追加できません。使用しない背景を削除してからもう一度お試しください。",
- "voip.video.menu.bgsettings": "エフェクト",
- "voip.video.menu.blur": "背景ぼかし",
- "voip.video.menu.effect": "顔エフェクト",
- "voip.video.menu.filter": "フィルター",
- "voip.video.popupbutton.close": "閉じる",
- "voip.video.popupbutton.dontshow": "解除する",
- "voip.video.popupbutton.opensettings": "設定に移動",
- "voip.video.popupbutton.show": "解除しない",
- "voip.video.popupdesc.dontshowpreview": "カメラのプレビューなしでビデオ通話に参加するには、設定画面で[ビデオ通話に参加する前にカメラのプレビューを確認]をオフにしてください。",
- "voip.video.popuptitle.dontshowpreview": "カメラのプレビューを解除できます",
- "voip.video.preview.blur.off": "なし",
- "voip.video.preview.blur.on": "背景ぼかし",
- "voip.video.preview.cameraoff": "カメラをオフ",
- "voip.video.preview.desc": "ビデオ通話に参加する前に、カメラの映像を確認できます。",
- "voip.video.preview.join": "参加",
- "voip.video.preview.title": "カメラのプレビュー",
- "voip.video.title.videocallwith": "%1とのビデオ通話",
- "voip.video.tooltip.filternblur": "フィルターと背景ぼかし機能を使ってみよう!",
- "voip.video.tooltip.startvideocall": "通話を始めるにはここをクリックしてください",
- "voip.video.tooltip.videomirroring": "映像を左右反転",
- "voip.video.tooltip.videomirroringoff": "映像の左右反転をオフ",
- "voip.video.tooltip.videomirroringon": "映像の左右反転をオン",
- "voip.videocall.button.beautyfeature": "ビューティー",
- "voip.videocall.popup.start": "開始",
- "voip.videocall.popup.turnon": "オン",
- "win10.notification.reply.guide": "ここから返信"
-}
\ No newline at end of file
diff --git a/archive/_server/thriftrw-node/tool.js b/archive/_server/thriftrw-node/tool.js
deleted file mode 100644
index 8199f97d..00000000
--- a/archive/_server/thriftrw-node/tool.js
+++ /dev/null
@@ -1,239 +0,0 @@
-import thriftIdl from "./thrift-idl.js";
-const TYPE = {
- STOP: 0,
- VOID: 1,
- BOOL: 2,
- BYTE: 3,
- I08: 3,
- DOUBLE: 4,
- I16: 6,
- I32: 8,
- I64: 10,
- STRING: 11,
- UTF7: 11,
- STRUCT: 12,
- MAP: 13,
- SET: 14,
- LIST: 15,
- UTF8: 16,
- UTF16: 17,
-};
-function getType(obj) {
- if (obj.type === "BaseType") {
- return TYPE[obj.baseType.toUpperCase()];
- } else if (obj.type === "Identifier") {
- return obj.name;
- }
-}
-function isStruct(obj) {
- return obj && obj.constructor === Array;
-}
-export default class ThriftRenameParser {
- constructor(input) {
- this.def = {};
- if (!input) {
- return;
- }
- this.add_def(input);
- }
- add_def(input) {
- const def = thriftIdl.parse(input);
- const thrift_def = {};
- def.definitions.forEach((e) => {
- if (e.type === "Struct" || e.type === "Exception") {
- const name = e.id.name;
- const fields_def = [];
- const fields = e.fields;
- for (let i = 0; i < fields.length; i++) {
- const field = fields[i];
- const field_fid = field.id.value;
- const field_name = field.name;
- const field_def = { fid: field_fid, name: field_name };
- if (field.valueType.type == "Identifier") {
- field_def.struct = field.valueType.name;
- } else if (field.valueType.type == "Map") {
- field_def.map = getType(field.valueType.valueType);
- } else if (field.valueType.type == "List") {
- field_def.list = getType(field.valueType.valueType);
- } else if (field.valueType.type == "Set") {
- field_def.set = getType(field.valueType.valueType);
- } else if (field.valueType.baseType) {
- field_def.type =
- TYPE[field.valueType.baseType.toUpperCase()];
- }
- fields_def.push(field_def);
- }
- thrift_def[name] = fields_def;
- } else if (e.type === "Enum") {
- const name = e.id.name;
- const defs_def = {};
- const defs = e.definitions;
- for (let i = 0; i < defs.length; i++) {
- const def = defs[i];
- defs_def[def.value.value] = def.id.name;
- }
- thrift_def[name] = defs_def;
- }
- });
- this.def = { ...this.def, ...thrift_def };
- }
- name2fid(struct_name, name) {
- const struct = this.def[struct_name];
- if (struct) {
- const result = struct.findIndex((e) => {
- return e.name == name;
- });
- if (result === -1) {
- return { name: name, fid: -1 };
- } else {
- return struct[result];
- }
- } else {
- return { name: name, fid: -1 };
- }
- }
- fid2name(struct_name, fid) {
- const struct = this.def[struct_name];
- if (struct) {
- const result = struct.findIndex((e) => {
- return e.fid == fid;
- });
- if (result === -1) {
- return { name: fid, fid: fid };
- } else {
- return struct[result];
- }
- } else {
- return { name: fid, fid: fid };
- }
- }
- rename_thrift(struct_name, object) {
- const newObject = {};
- for (const fid in object) {
- const value = object[fid];
- const finfo = this.fid2name(struct_name, fid);
- if (finfo.struct) {
- if (isStruct(this.def[finfo.struct])) {
- newObject[finfo.name] = this.rename_thrift(
- finfo.struct,
- value,
- );
- } else {
- newObject[finfo.name] = this.def[finfo.struct][value] ||
- value;
- }
- } else if (typeof finfo.list === "string") {
- newObject[finfo.name] = [];
- value.forEach((e, i) => {
- newObject[finfo.name][i] = this.rename_thrift(
- finfo.list,
- e,
- );
- });
- } else if (typeof finfo.map === "string") {
- newObject[finfo.name] = {};
- for (const key in value) {
- const e = value[key];
- newObject[finfo.name][key] = this.rename_thrift(
- finfo.map,
- e,
- );
- }
- } else if (typeof finfo.set === "string") {
- newObject[finfo.name] = [];
- value.forEach((e, i) => {
- newObject[finfo.name][i] = this.rename_thrift(
- finfo.set,
- e,
- );
- });
- } else {
- newObject[finfo.name] = value;
- }
- }
- return newObject;
- }
- rename_data(data) {
- const name = data._info.fname;
- const value = data.value;
- const struct_name = name.substr(0, 1).toUpperCase() + name.substr(1) +
- "Response";
- data.value = this.rename_thrift(struct_name, value);
- return data;
- }
- parse_data(struct_name, object) {
- const newThrift = [];
- for (const fname in object) {
- const value = object[fname];
- const finfo = this.name2fid(struct_name, fname);
- if (finfo.fid == -1) {
- continue;
- }
- const thisValue = [null, finfo.fid, null];
- if (finfo.struct) {
- if (isStruct(this.def[finfo.struct])) {
- thisValue[2] = this.parse_data(
- finfo.struct,
- value,
- );
- thisValue[0] = TYPE.STRUCT;
- } else {
- if (typeof value === "number") {
- thisValue[2] = value;
- thisValue[0] = TYPE.I64;
- } else {
- const Enum = this.def[finfo.struct];
- let i64;
- for (const k in Enum) {
- const val = Enum[k];
- if (val == value) {
- i64 = Number(k);
- }
- }
- thisValue[2] = i64;
- thisValue[0] = TYPE.I64;
- }
- }
- } else if (finfo.list) {
- thisValue[0] = TYPE.LIST;
- if (typeof finfo.list === "number") {
- thisValue[2] = [finfo.list, value];
- } else {
- thisValue[2] = [
- TYPE.STRUCT,
- value.map((e) => this.parse_data(finfo.list, e)),
- ];
- }
- } else if (finfo.map) {
- thisValue[0] = TYPE.MAP;
- if (typeof finfo.map === "number") {
- thisValue[2] = [TYPE.STRING, finfo.map, value];
- } else {
- const obj = {};
- for (const key in value) {
- const e = value[key];
- obj[key] = this.parse_data(finfo.map, e)
- }
- thisValue[2] = [TYPE.STRING, TYPE.STRUCT, obj];
- }
- } else if (finfo.set) {
- thisValue[0] = TYPE.SET;
- if (typeof finfo.map === "number") {
- thisValue[2] = [finfo.map, value];
- } else {
- thisValue[2] = [
- TYPE.STRUCT,
- value.map((e) => this.parse_data(finfo.map, e)),
- ];
- }
- } else if (finfo.type) {
- thisValue[0] = finfo.type
- thisValue[2] = value
- }
- newThrift.push(thisValue)
- }
- return newThrift;
- }
-}
-console.log("export const Thrift/*: Record | any[]>*/ = ");
-console.log(new ThriftRenameParser(Deno.readTextFileSync(Deno.args[0])).def)
\ No newline at end of file
diff --git a/archive/method.md b/archive/method.md
deleted file mode 100644
index 2d1351a1..00000000
--- a/archive/method.md
+++ /dev/null
@@ -1,225 +0,0 @@
-### Methodの実装方法
-
-#### CHRLINEを見る
-
-例:
-
-```python
-def getChats(self, mids, withMembers=True, withInvitees=True):
- METHOD_NAME = "getChats"
- if type(mids) != list:
- raise Exception("[getChats] mids must be a list")
- params = [
- [12, 1, [[15, 1, [11, mids]], [2, 2, withMembers], [2, 3, withInvitees]]]
- ]
- sqrd = self.generateDummyProtocol(METHOD_NAME, params, 3)
- return self.postPackDataAndGetUnpackRespData(
- self.LINE_NORMAL_ENDPOINT, sqrd, readWith=f"TalkService.{METHOD_NAME}"
- )
-```
-
-#### TSに変換する
-
-- 引数をコピー
-
-```ts
-public async getChats(options: {
- mids: string[]; //引数
- withMembers?: boolean; //引数(任意)
- withInvitees?: boolean; //引数(任意)
- }): Promise { //仮の型
- const { mids, withInvitees, withMembers } = {
- withInvitees: true, //デフォルトの値
- withMembers: true, //デフォルトの値
- ...options,
- };
- }
-```
-
-- 返り値の型を調べる
-
- `/linejs/archive/_server/line_.thrift`を開いて、`getChats(`で検索する(見つからなかったら`line.thrift`も見る)
-
-`GetChatsResponse getChats(1: GetChatsRequest request) throws(1: TalkException e);`
-
-この関数は`GetChatsResponse`の型を返すので、以下のようにする
-
-```ts
-public async getChats(options: {
- mids: string[]; //引数
- withMembers?: boolean; //引数(任意)
- withInvitees?: boolean; //引数(任意)
- }): Promise
-```
-
-見つからなかった場合、`LooseType`で続行
-
-- request
-
-もしparamが`[[12, 1, [~]]]`の形、または
-`return ~ServiceStruct.SendRequestByName(self, METHOD_NAME, params)` の場合
-
-```ts
-return await this.request(
- [
- [15, 1, [11, mids]],
- [2, 2, withMembers],
- [2, 3, withInvitees],
- ], // ~の中身
- "getChats",
- this.TalkService_PROTOCOL_TYPE,
- "GetChatsResponse", //上で見つけた型、見つからなかったら false(bool)
- this.TalkService_API_PATH,
-);
-```
-
-else
-
-```ts
-return await this.direct_request(
- [
- [12, 1, [[15, 1, [11, mids]], [2, 2, withMembers], [
- 2,
- 3,
- withInvitees,
- ]]],
- ],
- "getChats",
- this.TalkService_PROTOCOL_TYPE,
- "GetChatsResponse", //上で見つけた型、見つからなかったら false(bool)
- this.TalkService_API_PATH,
-);
-```
-
-- thriftの返り値が単純でない場合
-
-例:
-
-`list getContacts(2: list ids) throws(1: TalkException e);`
-
-`map findContactsByPhone(2: set phones) throws(1: TalkException e);`
-
-以下のようにlistならmap()、mapならforなどで頑張る
-
-```js
-public async getContactsV2(options: {
- mids: string[];
- }): Promise { //list
- const { mids } = { ...options };
- return (
- await this.request(
- [[15, 1, [11, mids]]],
- "getContactsV2",
- this.TalkService_PROTOCOL_TYPE,
- false, // falseで無変換
- this.TalkService_API_PATH,
- )
- ).map((e: LooseType) => this.parser.rename_thrift("Contact", e)); //thriftの型をここへ
- }
-```
-
-- そもそもparamではない場合😇
-
-```python
-def deleteOtherFromChat(self, to, mid):
- METHOD_NAME = "deleteOtherFromChat"
- if type(mid) == list:
- _lastReq = None
- for _mid in mid:
- print(f"[deleteOtherFromChat] The parameter 'mid' should be str")
- _lastReq = self.deleteOtherFromChat(to, _mid)
- return _lastReq
- sqrd = [
- 128,
- 1,
- 0,
- 1,
- 0,
- 0,
- 0,
- 19,
- 100,
- 101,
- 108,
- 101,
- 116,
- 101,
- 79,
- 116,
- 104,
- 101,
- 114,
- 70,
- 114,
- 111,
- 109,
- 67,
- 104,
- 97,
- 116,
- 0,
- 0,
- 0,
- 0,
- ]
- sqrd += [12, 0, 1]
- sqrd += [8, 0, 1, 0, 0, 0, 0] # seq?
- sqrd += [11, 0, 2, 0, 0, 0, len(to)]
- for value in to:
- sqrd.append(ord(value))
- sqrd += [14, 0, 3, 11, 0, 0, 0, 1, 0, 0, 0, len(mid)]
- for value in mid:
- sqrd.append(ord(value))
- sqrd += [0, 0]
- return self.postPackDataAndGetUnpackRespData(
- self.LINE_NORMAL_ENDPOINT, sqrd, readWith=f"TalkService.{METHOD_NAME}"
- )
-```
-
-解説
-
-最初のsqrdはthriftのメッセージ`deleteOtherFromChat`を意味します
-
-`sqrd = [128, 1, 0, 1] + self.getStringBytes("METHODNAME") + [0, 0, 0, 0]`も上と同じ意味です
-
-`sqrd += [12, 0, 1]`は`[12,1,[]]`を意味します。続くバイト列はその中身です
-
-`sqrd += [8, 0, 1, 0, 0, 0, 0]`は`[8,1,0]`を意味します。
-
-```py
-sqrd += [11, 0, 2, 0, 0, 0, len(to)]
-for value in to:
- sqrd.append(ord(value))
-```
-
-は`[11,2,to]`を意味します。
-
-```py
-sqrd += [14, 0, 3, 11, 0, 0, 0, 1, 0, 0, 0, len(mid)]
-for value in mid:
- sqrd.append(ord(value))
-```
-
-は`[14,3,[11,[mid]]]`を意味します。
-
-`sqrd += [0, 0]`はメッセージの終了を意味します
-
-つまり、
-
-```py
-param = [12,1,[
- [8,1,0],
- [11,2,to],
- [14,3,[11,[mid]]]
-]]
-```
-
-と変換できます
-
-主な変換
-
-`[10, 0, 3] + self.getIntBytes(number, 8)` -> `[10,3,number]`
-
-`[2, 0, 3, 0]` -> `[2, 3, false]`
-
-`sqrd += [0]` -> `[12,int,[]]`の外に出ることを意味します
diff --git a/biome.json b/biome.json
deleted file mode 100644
index 091acba1..00000000
--- a/biome.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
- "organizeImports": {
- "enabled": true
- },
- "linter": {
- "enabled": true,
- "rules": {
- "recommended": true
- }
- },
- "formatter": {
- "enabled": true,
- "lineWidth": 80,
- "indentWidth": 2,
- "indentStyle": "tab",
- "attributePosition": "multiline",
- "lineEnding": "lf"
- }
-}
diff --git a/deno.json b/deno.json
index 88cc6c41..cf831740 100644
--- a/deno.json
+++ b/deno.json
@@ -1,7 +1,6 @@
{
- "workspace": ["./packages/linejs", "./packages/types"],
+ "workspace": ["./packages/linejs", "./packages/types", "./docs"],
"fmt": {
- "indentWidth": 2,
"singleQuote": false,
"useTabs": true,
"exclude": [
@@ -13,19 +12,23 @@
"curve25519-js": "npm:curve25519-js@^0.0.4",
"node-bignumber": "npm:node-bignumber@^1.2.2",
"thrift": "npm:thrift@^0.20.0",
+ "thrift-types": "npm:@types/thrift@^0.10.17",
"tweetnacl": "npm:tweetnacl@^1.0.3",
"jsdom": "npm:jsdom@25.0.0",
"node-types": "npm:@types/node@latest",
"node-int64": "npm:node-int64@^0.4.0"
},
- "tasks": {
- "format": "deno run -A npm:@biomejs/biome format --write ./packages/**/*.ts",
- "format:check": "deno run -A npm:@biomejs/biome format ./packages/**/*.ts",
- "lint": "deno run -A npm:@biomejs/biome lint ./packages/**/*.ts",
- "check": "deno run -A npm:@biomejs/biome check ./packages/**/*.ts"
- },
+ "nodeModulesDir": "auto",
"compilerOptions": {
"types": ["node-types"]
},
- "nodeModulesDir": "auto"
+ "tasks": {
+ "dev": "deno run -A --watch sandbox/main.ts",
+ "thrift": "deno run --allow-read --allow-write scripts/thrift/tool.ts",
+ "docs:dev": "cd docs && deno task dev",
+ "docs:build": "cd docs && deno task build"
+ },
+ "unstable": [
+ "byonm"
+ ]
}
diff --git a/deno.lock b/deno.lock
index ab0a32a0..f173a3da 100644
--- a/deno.lock
+++ b/deno.lock
@@ -1,31 +1,225 @@
{
"version": "4",
"specifiers": {
+ "jsr:@evex/linejs-types@^1.9.0": "1.9.1",
+ "jsr:@evex/linejs-types@^1.9.1": "1.9.1",
+ "jsr:@evex/linejs@1.9.0": "1.9.0",
+ "jsr:@evex/linejs@1.9.1": "1.9.1",
"jsr:@std/assert@^1.0.2": "1.0.6",
+ "jsr:@std/dotenv@*": "0.225.3",
"jsr:@std/internal@^1.0.4": "1.0.4",
"npm:@biomejs/biome@*": "1.9.3",
+ "npm:@deno/kv@*": "0.8.4",
+ "npm:@types/jsdom@*": "21.1.7",
"npm:@types/node@*": "22.5.4",
- "npm:@types/node@latest": "22.7.5",
+ "npm:@types/node@latest": "22.9.0",
+ "npm:@types/thrift@*": "0.10.17",
+ "npm:@types/thrift@~0.10.17": "0.10.17",
+ "npm:crypto-js@*": "4.2.0",
+ "npm:crypto-js@^4.2.0": "4.2.0",
"npm:curve25519-js@^0.0.4": "0.0.4",
+ "npm:discord.js@*": "14.16.3",
+ "npm:esbuild@*": "0.21.5",
"npm:jsdom@25.0.0": "25.0.0",
"npm:node-bignumber@^1.2.2": "1.2.2",
- "npm:node-int64@*": "0.4.0",
"npm:node-int64@0.4": "0.4.0",
"npm:thrift@0.20": "0.20.0_ws@5.2.4",
- "npm:tweetnacl@^1.0.3": "1.0.3"
+ "npm:tweetnacl@^1.0.3": "1.0.3",
+ "npm:vitepress@*": "1.5.0_vite@5.4.11__@types+node@22.5.4_vue@3.5.13_focus-trap@7.6.2_@types+node@22.5.4",
+ "npm:werift-rtp@*": "0.8.2"
},
"jsr": {
+ "@evex/linejs@1.9.0": {
+ "integrity": "9147f29860fb49eb4f44eafb0b9373939e664e5475a5b6167a19b9964d371478",
+ "dependencies": [
+ "jsr:@evex/linejs-types@^1.9.0",
+ "npm:curve25519-js",
+ "npm:jsdom",
+ "npm:node-bignumber",
+ "npm:node-int64",
+ "npm:thrift",
+ "npm:tweetnacl"
+ ]
+ },
+ "@evex/linejs@1.9.1": {
+ "integrity": "49a09f8483ecbad45d83ffe52b15aaa9c0d9ad472706ed20adec3647040cfce4",
+ "dependencies": [
+ "jsr:@evex/linejs-types@^1.9.1",
+ "npm:curve25519-js",
+ "npm:jsdom",
+ "npm:node-bignumber",
+ "npm:node-int64",
+ "npm:thrift",
+ "npm:tweetnacl"
+ ]
+ },
+ "@evex/linejs-types@1.9.1": {
+ "integrity": "9a00093bdf17c43cdf601d7ba0348daa7c00a902ebc714a0575332b8e2ad420d"
+ },
"@std/assert@1.0.6": {
"integrity": "1904c05806a25d94fe791d6d883b685c9e2dcd60e4f9fc30f4fc5cf010c72207",
"dependencies": [
"jsr:@std/internal"
]
},
+ "@std/dotenv@0.225.3": {
+ "integrity": "a95e5b812c27b0854c52acbae215856d9cce9d4bbf774d938c51d212711e8d4a"
+ },
"@std/internal@1.0.4": {
"integrity": "62e8e4911527e5e4f307741a795c0b0a9e6958d0b3790716ae71ce085f755422"
}
},
"npm": {
+ "@algolia/autocomplete-core@1.17.7_algoliasearch@5.18.0": {
+ "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==",
+ "dependencies": [
+ "@algolia/autocomplete-plugin-algolia-insights",
+ "@algolia/autocomplete-shared"
+ ]
+ },
+ "@algolia/autocomplete-plugin-algolia-insights@1.17.7_search-insights@2.17.3_algoliasearch@5.18.0": {
+ "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==",
+ "dependencies": [
+ "@algolia/autocomplete-shared",
+ "search-insights"
+ ]
+ },
+ "@algolia/autocomplete-preset-algolia@1.17.7_@algolia+client-search@5.18.0_algoliasearch@5.18.0": {
+ "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==",
+ "dependencies": [
+ "@algolia/autocomplete-shared",
+ "@algolia/client-search",
+ "algoliasearch"
+ ]
+ },
+ "@algolia/autocomplete-shared@1.17.7_@algolia+client-search@5.18.0_algoliasearch@5.18.0": {
+ "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==",
+ "dependencies": [
+ "@algolia/client-search",
+ "algoliasearch"
+ ]
+ },
+ "@algolia/client-abtesting@5.18.0": {
+ "integrity": "sha512-DLIrAukjsSrdMNNDx1ZTks72o4RH/1kOn8Wx5zZm8nnqFexG+JzY4SANnCNEjnFQPJTTvC+KpgiNW/CP2lumng==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/client-analytics@5.18.0": {
+ "integrity": "sha512-0VpGG2uQW+h2aejxbG8VbnMCQ9ary9/ot7OASXi6OjE0SRkYQ/+pkW+q09+IScif3pmsVVYggmlMPtAsmYWHng==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/client-common@5.18.0": {
+ "integrity": "sha512-X1WMSC+1ve2qlMsemyTF5bIjwipOT+m99Ng1Tyl36ZjQKTa54oajBKE0BrmM8LD8jGdtukAgkUhFoYOaRbMcmQ=="
+ },
+ "@algolia/client-insights@5.18.0": {
+ "integrity": "sha512-FAJRNANUOSs/FgYOJ/Njqp+YTe4TMz2GkeZtfsw1TMiA5mVNRS/nnMpxas9771aJz7KTEWvK9GwqPs0K6RMYWg==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/client-personalization@5.18.0": {
+ "integrity": "sha512-I2dc94Oiwic3SEbrRp8kvTZtYpJjGtg5y5XnqubgnA15AgX59YIY8frKsFG8SOH1n2rIhUClcuDkxYQNXJLg+w==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/client-query-suggestions@5.18.0": {
+ "integrity": "sha512-x6XKIQgKFTgK/bMasXhghoEjHhmgoP61pFPb9+TaUJ32aKOGc65b12usiGJ9A84yS73UDkXS452NjyP50Knh/g==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/client-search@5.18.0": {
+ "integrity": "sha512-qI3LcFsVgtvpsBGR7aNSJYxhsR+Zl46+958ODzg8aCxIcdxiK7QEVLMJMZAR57jGqW0Lg/vrjtuLFDMfSE53qA==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/ingestion@1.18.0": {
+ "integrity": "sha512-bGvJg7HnGGm+XWYMDruZXWgMDPVt4yCbBqq8DM6EoaMBK71SYC4WMfIdJaw+ABqttjBhe6aKNRkWf/bbvYOGyw==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/monitoring@1.18.0": {
+ "integrity": "sha512-lBssglINIeGIR+8KyzH05NAgAmn1BCrm5D2T6pMtr/8kbTHvvrm1Zvcltc5dKUQEFyyx3J5+MhNc7kfi8LdjVw==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/recommend@5.18.0": {
+ "integrity": "sha512-uSnkm0cdAuFwdMp4pGT5vHVQ84T6AYpTZ3I0b3k/M3wg4zXDhl3aCiY8NzokEyRLezz/kHLEEcgb/tTTobOYVw==",
+ "dependencies": [
+ "@algolia/client-common",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
+ "@algolia/requester-browser-xhr@5.18.0": {
+ "integrity": "sha512-1XFjW0C3pV0dS/9zXbV44cKI+QM4ZIz9cpatXpsjRlq6SUCpLID3DZHsXyE6sTb8IhyPaUjk78GEJT8/3hviqg==",
+ "dependencies": [
+ "@algolia/client-common"
+ ]
+ },
+ "@algolia/requester-fetch@5.18.0": {
+ "integrity": "sha512-0uodeNdAHz1YbzJh6C5xeQ4T6x5WGiUxUq3GOaT/R4njh5t78dq+Rb187elr7KtnjUmETVVuCvmEYaThfTHzNg==",
+ "dependencies": [
+ "@algolia/client-common"
+ ]
+ },
+ "@algolia/requester-node-http@5.18.0": {
+ "integrity": "sha512-tZCqDrqJ2YE2I5ukCQrYN8oiF6u3JIdCxrtKq+eniuLkjkO78TKRnXrVcKZTmfFJyyDK8q47SfDcHzAA3nHi6w==",
+ "dependencies": [
+ "@algolia/client-common"
+ ]
+ },
+ "@babel/helper-string-parser@7.25.9": {
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="
+ },
+ "@babel/helper-validator-identifier@7.25.9": {
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="
+ },
+ "@babel/parser@7.26.3": {
+ "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==",
+ "dependencies": [
+ "@babel/types"
+ ]
+ },
+ "@babel/types@7.26.3": {
+ "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==",
+ "dependencies": [
+ "@babel/helper-string-parser",
+ "@babel/helper-validator-identifier"
+ ]
+ },
"@biomejs/biome@1.9.3": {
"integrity": "sha512-POjAPz0APAmX33WOQFGQrwLvlu7WLV4CFJMlB12b6ZSg+2q6fYu9kZwLCOA+x83zXfcPd1RpuWOKJW0GbBwLIQ==",
"dependencies": [
@@ -63,45 +257,607 @@
"@biomejs/cli-win32-x64@1.9.3": {
"integrity": "sha512-cQMy2zanBkVLpmmxXdK6YePzmZx0s5Z7KEnwmrW54rcXK3myCNbQa09SwGZ8i/8sLw0H9F3X7K4rxVNGU8/D4Q=="
},
+ "@deno/kv-darwin-arm64@0.8.4": {
+ "integrity": "sha512-j86nnE1QdLw20OrUs/6Iw6ZYzC8pmfU1+K4hNSVHO9K0bfy3VBd4JSHkHLmYCiHDkgIm+wTxct33thl6HxXz0Q=="
+ },
+ "@deno/kv-darwin-x64@0.8.4": {
+ "integrity": "sha512-qdczxcqkN2fbDX/nIzUetI6i8usNu8kpN3sDV0rXcSWlg9E5huWWjGp6PbOS4w1xarUWbqFAZvy4VSmGTVN1Zw=="
+ },
+ "@deno/kv-linux-x64-gnu@0.8.4": {
+ "integrity": "sha512-xv2rM6wrVHVOM4Nswl8iyfdZZiEp5r85jwLajj0NGTiLMAQLBtDsBE/kpH4Ap3K6yiqJX3nTb44Z8AJ+IyzO4Q=="
+ },
+ "@deno/kv-win32-x64-msvc@0.8.4": {
+ "integrity": "sha512-xTEByTpC1DWw4A1F9isD8B16v1+CQFHFvi/Mm2bqlO9iD5HfIGgalWJbL3EvgYeybQ9yA27KGqaGnKxXdaX5Rg=="
+ },
+ "@deno/kv@0.8.4": {
+ "integrity": "sha512-5q2izU1tp6wv8rDIwMb6GXe/B+aO/sjAjRAOIigEtX+qOiTLsPE++ibJbfafVb0LmjEdlA18Kpfo23fln73OtQ==",
+ "dependencies": [
+ "@deno/kv-darwin-arm64",
+ "@deno/kv-darwin-x64",
+ "@deno/kv-linux-x64-gnu",
+ "@deno/kv-win32-x64-msvc"
+ ]
+ },
+ "@discordjs/builders@1.9.0": {
+ "integrity": "sha512-0zx8DePNVvQibh5ly5kCEei5wtPBIUbSoE9n+91Rlladz4tgtFbJ36PZMxxZrTEOQ7AHMZ/b0crT/0fCy6FTKg==",
+ "dependencies": [
+ "@discordjs/formatters",
+ "@discordjs/util",
+ "@sapphire/shapeshift",
+ "discord-api-types@0.37.97",
+ "fast-deep-equal",
+ "ts-mixer",
+ "tslib"
+ ]
+ },
+ "@discordjs/collection@1.5.3": {
+ "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="
+ },
+ "@discordjs/collection@2.1.1": {
+ "integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="
+ },
+ "@discordjs/formatters@0.5.0": {
+ "integrity": "sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==",
+ "dependencies": [
+ "discord-api-types@0.37.97"
+ ]
+ },
+ "@discordjs/rest@2.4.0": {
+ "integrity": "sha512-Xb2irDqNcq+O8F0/k/NaDp7+t091p+acb51iA4bCKfIn+WFWd6HrNvcsSbMMxIR9NjcMZS6NReTKygqiQN+ntw==",
+ "dependencies": [
+ "@discordjs/collection@2.1.1",
+ "@discordjs/util",
+ "@sapphire/async-queue",
+ "@sapphire/snowflake",
+ "@vladfrangu/async_event_emitter",
+ "discord-api-types@0.37.97",
+ "magic-bytes.js",
+ "tslib",
+ "undici"
+ ]
+ },
+ "@discordjs/util@1.1.1": {
+ "integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g=="
+ },
+ "@discordjs/ws@1.1.1": {
+ "integrity": "sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==",
+ "dependencies": [
+ "@discordjs/collection@2.1.1",
+ "@discordjs/rest",
+ "@discordjs/util",
+ "@sapphire/async-queue",
+ "@types/ws",
+ "@vladfrangu/async_event_emitter",
+ "discord-api-types@0.37.83",
+ "tslib",
+ "ws@8.18.0"
+ ]
+ },
+ "@docsearch/css@3.8.2": {
+ "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ=="
+ },
+ "@docsearch/js@3.8.2": {
+ "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==",
+ "dependencies": [
+ "@docsearch/react",
+ "preact"
+ ]
+ },
+ "@docsearch/react@3.8.2_algoliasearch@5.18.0": {
+ "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==",
+ "dependencies": [
+ "@algolia/autocomplete-core",
+ "@algolia/autocomplete-preset-algolia",
+ "@docsearch/css",
+ "algoliasearch"
+ ]
+ },
+ "@esbuild/aix-ppc64@0.21.5": {
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="
+ },
+ "@esbuild/android-arm64@0.21.5": {
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="
+ },
+ "@esbuild/android-arm@0.21.5": {
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="
+ },
+ "@esbuild/android-x64@0.21.5": {
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="
+ },
+ "@esbuild/darwin-arm64@0.21.5": {
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="
+ },
+ "@esbuild/darwin-x64@0.21.5": {
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="
+ },
+ "@esbuild/freebsd-arm64@0.21.5": {
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="
+ },
+ "@esbuild/freebsd-x64@0.21.5": {
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="
+ },
+ "@esbuild/linux-arm64@0.21.5": {
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="
+ },
+ "@esbuild/linux-arm@0.21.5": {
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="
+ },
+ "@esbuild/linux-ia32@0.21.5": {
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="
+ },
+ "@esbuild/linux-loong64@0.21.5": {
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="
+ },
+ "@esbuild/linux-mips64el@0.21.5": {
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="
+ },
+ "@esbuild/linux-ppc64@0.21.5": {
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="
+ },
+ "@esbuild/linux-riscv64@0.21.5": {
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="
+ },
+ "@esbuild/linux-s390x@0.21.5": {
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="
+ },
+ "@esbuild/linux-x64@0.21.5": {
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="
+ },
+ "@esbuild/netbsd-x64@0.21.5": {
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="
+ },
+ "@esbuild/openbsd-x64@0.21.5": {
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="
+ },
+ "@esbuild/sunos-x64@0.21.5": {
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="
+ },
+ "@esbuild/win32-arm64@0.21.5": {
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="
+ },
+ "@esbuild/win32-ia32@0.21.5": {
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="
+ },
+ "@esbuild/win32-x64@0.21.5": {
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="
+ },
+ "@iconify-json/simple-icons@1.2.17": {
+ "integrity": "sha512-1vXbM6a6HV2rwXxu8ptD2OYhqrqX0ZZRepOg7nIjkvKlKq90Iici4X++A8h36bEVlV2wGjqx8uVYB0pwnPZVSw==",
+ "dependencies": [
+ "@iconify/types"
+ ]
+ },
+ "@iconify/types@2.0.0": {
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="
+ },
+ "@jridgewell/sourcemap-codec@1.5.0": {
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
+ },
+ "@minhducsun2002/leb128@1.0.0": {
+ "integrity": "sha512-eFrYUPDVHeuwWHluTG1kwNQUEUcFjVKYwPkU8z9DR1JH3AW7JtJsG9cRVGmwz809kKtGfwGJj58juCZxEvnI/g=="
+ },
+ "@rollup/rollup-android-arm-eabi@4.29.1": {
+ "integrity": "sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw=="
+ },
+ "@rollup/rollup-android-arm64@4.29.1": {
+ "integrity": "sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew=="
+ },
+ "@rollup/rollup-darwin-arm64@4.29.1": {
+ "integrity": "sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw=="
+ },
+ "@rollup/rollup-darwin-x64@4.29.1": {
+ "integrity": "sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng=="
+ },
+ "@rollup/rollup-freebsd-arm64@4.29.1": {
+ "integrity": "sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw=="
+ },
+ "@rollup/rollup-freebsd-x64@4.29.1": {
+ "integrity": "sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w=="
+ },
+ "@rollup/rollup-linux-arm-gnueabihf@4.29.1": {
+ "integrity": "sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A=="
+ },
+ "@rollup/rollup-linux-arm-musleabihf@4.29.1": {
+ "integrity": "sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ=="
+ },
+ "@rollup/rollup-linux-arm64-gnu@4.29.1": {
+ "integrity": "sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA=="
+ },
+ "@rollup/rollup-linux-arm64-musl@4.29.1": {
+ "integrity": "sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA=="
+ },
+ "@rollup/rollup-linux-loongarch64-gnu@4.29.1": {
+ "integrity": "sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw=="
+ },
+ "@rollup/rollup-linux-powerpc64le-gnu@4.29.1": {
+ "integrity": "sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w=="
+ },
+ "@rollup/rollup-linux-riscv64-gnu@4.29.1": {
+ "integrity": "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ=="
+ },
+ "@rollup/rollup-linux-s390x-gnu@4.29.1": {
+ "integrity": "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g=="
+ },
+ "@rollup/rollup-linux-x64-gnu@4.29.1": {
+ "integrity": "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ=="
+ },
+ "@rollup/rollup-linux-x64-musl@4.29.1": {
+ "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA=="
+ },
+ "@rollup/rollup-win32-arm64-msvc@4.29.1": {
+ "integrity": "sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig=="
+ },
+ "@rollup/rollup-win32-ia32-msvc@4.29.1": {
+ "integrity": "sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng=="
+ },
+ "@rollup/rollup-win32-x64-msvc@4.29.1": {
+ "integrity": "sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg=="
+ },
+ "@sapphire/async-queue@1.5.5": {
+ "integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="
+ },
+ "@sapphire/shapeshift@4.0.0": {
+ "integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==",
+ "dependencies": [
+ "fast-deep-equal",
+ "lodash"
+ ]
+ },
+ "@sapphire/snowflake@3.5.3": {
+ "integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="
+ },
+ "@shikijs/core@1.24.4": {
+ "integrity": "sha512-jjLsld+xEEGYlxAXDyGwWsKJ1sw5Pc1pnp4ai2ORpjx2UX08YYTC0NNqQYO1PaghYaR+PvgMOGuvzw2he9sk0Q==",
+ "dependencies": [
+ "@shikijs/engine-javascript",
+ "@shikijs/engine-oniguruma",
+ "@shikijs/types",
+ "@shikijs/vscode-textmate",
+ "@types/hast",
+ "hast-util-to-html"
+ ]
+ },
+ "@shikijs/engine-javascript@1.24.4": {
+ "integrity": "sha512-TClaQOLvo9WEMJv6GoUsykQ6QdynuKszuORFWCke8qvi6PeLm7FcD9+7y45UenysxEWYpDL5KJaVXTngTE+2BA==",
+ "dependencies": [
+ "@shikijs/types",
+ "@shikijs/vscode-textmate",
+ "oniguruma-to-es"
+ ]
+ },
+ "@shikijs/engine-oniguruma@1.24.4": {
+ "integrity": "sha512-Do2ry6flp2HWdvpj2XOwwa0ljZBRy15HKZITzPcNIBOGSeprnA8gOooA/bLsSPuy8aJBa+Q/r34dMmC3KNL/zw==",
+ "dependencies": [
+ "@shikijs/types",
+ "@shikijs/vscode-textmate"
+ ]
+ },
+ "@shikijs/transformers@1.24.4": {
+ "integrity": "sha512-0jq5p9WLB7ToM/O7RWfxuIwirTJbIQsUR06jxdG3h3CEuO5m7ik8GnDsxwHhyIEfgJSZczSnVUZWFrNKy5It6g==",
+ "dependencies": [
+ "shiki"
+ ]
+ },
+ "@shikijs/types@1.24.4": {
+ "integrity": "sha512-0r0XU7Eaow0PuDxuWC1bVqmWCgm3XqizIaT7SM42K03vc69LGooT0U8ccSR44xP/hGlNx4FKhtYpV+BU6aaKAA==",
+ "dependencies": [
+ "@shikijs/vscode-textmate",
+ "@types/hast"
+ ]
+ },
+ "@shikijs/vscode-textmate@9.3.1": {
+ "integrity": "sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g=="
+ },
+ "@shinyoshiaki/binary-data@0.6.1": {
+ "integrity": "sha512-7HDb/fQAop2bCmvDIzU5+69i+UJaFgIVp99h1VzK1mpg1JwSODOkjbqD7ilTYnqlnadF8C4XjpwpepxDsGY6+w==",
+ "dependencies": [
+ "generate-function",
+ "is-plain-object"
+ ]
+ },
+ "@shinyoshiaki/jspack@0.0.6": {
+ "integrity": "sha512-SdsNhLjQh4onBlyPrn4ia1Pdx5bXT88G/LIEpOYAjx2u4xeY/m/HB5yHqlkJB1uQR3Zw4R3hBWLj46STRAN0rg=="
+ },
+ "@types/estree@1.0.6": {
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
+ },
+ "@types/hast@3.0.4": {
+ "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+ "dependencies": [
+ "@types/unist"
+ ]
+ },
+ "@types/jsdom@21.1.7": {
+ "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==",
+ "dependencies": [
+ "@types/node@22.5.4",
+ "@types/tough-cookie",
+ "parse5"
+ ]
+ },
+ "@types/linkify-it@5.0.0": {
+ "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="
+ },
+ "@types/markdown-it@14.1.2": {
+ "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+ "dependencies": [
+ "@types/linkify-it",
+ "@types/mdurl"
+ ]
+ },
+ "@types/mdast@4.0.4": {
+ "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
+ "dependencies": [
+ "@types/unist"
+ ]
+ },
+ "@types/mdurl@2.0.0": {
+ "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="
+ },
+ "@types/node-int64@0.4.32": {
+ "integrity": "sha512-xf/JsSlnXQ+mzvc0IpXemcrO4BrCfpgNpMco+GLcXkFk01k/gW9lGJu+Vof0ZSvHK6DsHJDPSbjFPs36QkWXqw==",
+ "dependencies": [
+ "@types/node@22.5.4"
+ ]
+ },
"@types/node@22.5.4": {
"integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
"dependencies": [
"undici-types"
]
},
- "@types/node@22.7.5": {
- "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
+ "@types/node@22.9.0": {
+ "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
"dependencies": [
"undici-types"
]
},
+ "@types/q@1.5.8": {
+ "integrity": "sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw=="
+ },
+ "@types/thrift@0.10.17": {
+ "integrity": "sha512-bDX6d5a5ZDWC81tgDv224n/3PKNYfIQJTPHzlbk4vBWJrYXF6Tg1ncaVmP/c3JbGN2AK9p7zmHorJC2D6oejGQ==",
+ "dependencies": [
+ "@types/node@22.5.4",
+ "@types/node-int64",
+ "@types/q"
+ ]
+ },
+ "@types/tough-cookie@4.0.5": {
+ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA=="
+ },
+ "@types/unist@3.0.3": {
+ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="
+ },
+ "@types/web-bluetooth@0.0.20": {
+ "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="
+ },
+ "@types/ws@8.5.13": {
+ "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==",
+ "dependencies": [
+ "@types/node@22.5.4"
+ ]
+ },
+ "@ungap/structured-clone@1.2.1": {
+ "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA=="
+ },
+ "@vitejs/plugin-vue@5.2.1_vite@5.4.11__@types+node@22.5.4_vue@3.5.13_@types+node@22.5.4": {
+ "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==",
+ "dependencies": [
+ "vite",
+ "vue"
+ ]
+ },
+ "@vladfrangu/async_event_emitter@2.4.6": {
+ "integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="
+ },
+ "@vue/compiler-core@3.5.13": {
+ "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==",
+ "dependencies": [
+ "@babel/parser",
+ "@vue/shared",
+ "entities",
+ "estree-walker",
+ "source-map-js"
+ ]
+ },
+ "@vue/compiler-dom@3.5.13": {
+ "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==",
+ "dependencies": [
+ "@vue/compiler-core",
+ "@vue/shared"
+ ]
+ },
+ "@vue/compiler-sfc@3.5.13": {
+ "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==",
+ "dependencies": [
+ "@babel/parser",
+ "@vue/compiler-core",
+ "@vue/compiler-dom",
+ "@vue/compiler-ssr",
+ "@vue/shared",
+ "estree-walker",
+ "magic-string",
+ "postcss",
+ "source-map-js"
+ ]
+ },
+ "@vue/compiler-ssr@3.5.13": {
+ "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==",
+ "dependencies": [
+ "@vue/compiler-dom",
+ "@vue/shared"
+ ]
+ },
+ "@vue/devtools-api@7.6.8": {
+ "integrity": "sha512-ma6dY/sZR36zALVsV1W7eC57c6IJPXsy8SNgZn1PLVWU4z4dPn5TIBmnF4stmdJ4sQcixqKaQ8pwjbMPzEZwiA==",
+ "dependencies": [
+ "@vue/devtools-kit"
+ ]
+ },
+ "@vue/devtools-kit@7.6.8": {
+ "integrity": "sha512-JhJ8M3sPU+v0P2iZBF2DkdmR9L0dnT5RXJabJqX6o8KtFs3tebdvfoXV2Dm3BFuqeECuMJIfF1aCzSt+WQ4wrw==",
+ "dependencies": [
+ "@vue/devtools-shared",
+ "birpc",
+ "hookable",
+ "mitt",
+ "perfect-debounce",
+ "speakingurl",
+ "superjson"
+ ]
+ },
+ "@vue/devtools-shared@7.6.8": {
+ "integrity": "sha512-9MBPO5Z3X1nYGFqTJyohl6Gmf/J7UNN1oicHdyzBVZP4jnhZ4c20MgtaHDIzWmHDHCMYVS5bwKxT3jxh7gOOKA==",
+ "dependencies": [
+ "rfdc"
+ ]
+ },
+ "@vue/reactivity@3.5.13": {
+ "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==",
+ "dependencies": [
+ "@vue/shared"
+ ]
+ },
+ "@vue/runtime-core@3.5.13": {
+ "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==",
+ "dependencies": [
+ "@vue/reactivity",
+ "@vue/shared"
+ ]
+ },
+ "@vue/runtime-dom@3.5.13": {
+ "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==",
+ "dependencies": [
+ "@vue/reactivity",
+ "@vue/runtime-core",
+ "@vue/shared",
+ "csstype"
+ ]
+ },
+ "@vue/server-renderer@3.5.13_vue@3.5.13": {
+ "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==",
+ "dependencies": [
+ "@vue/compiler-ssr",
+ "@vue/shared",
+ "vue"
+ ]
+ },
+ "@vue/shared@3.5.13": {
+ "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="
+ },
+ "@vueuse/core@11.3.0_vue@3.5.13": {
+ "integrity": "sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==",
+ "dependencies": [
+ "@types/web-bluetooth",
+ "@vueuse/metadata",
+ "@vueuse/shared",
+ "vue-demi"
+ ]
+ },
+ "@vueuse/integrations@11.3.0_focus-trap@7.6.2_vue@3.5.13": {
+ "integrity": "sha512-5fzRl0apQWrDezmobchoiGTkGw238VWESxZHazfhP3RM7pDSiyXy18QbfYkILoYNTd23HPAfQTJpkUc5QbkwTw==",
+ "dependencies": [
+ "@vueuse/core",
+ "@vueuse/shared",
+ "focus-trap",
+ "vue-demi"
+ ]
+ },
+ "@vueuse/metadata@11.3.0": {
+ "integrity": "sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g=="
+ },
+ "@vueuse/shared@11.3.0_vue@3.5.13": {
+ "integrity": "sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==",
+ "dependencies": [
+ "vue-demi"
+ ]
+ },
+ "aes-js@3.1.2": {
+ "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ=="
+ },
"agent-base@7.1.1": {
"integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
"dependencies": [
"debug"
]
},
+ "algoliasearch@5.18.0": {
+ "integrity": "sha512-/tfpK2A4FpS0o+S78o3YSdlqXr0MavJIDlFK3XZrlXLy7vaRXJvW5jYg3v5e/wCaF8y0IpMjkYLhoV6QqfpOgw==",
+ "dependencies": [
+ "@algolia/client-abtesting",
+ "@algolia/client-analytics",
+ "@algolia/client-common",
+ "@algolia/client-insights",
+ "@algolia/client-personalization",
+ "@algolia/client-query-suggestions",
+ "@algolia/client-search",
+ "@algolia/ingestion",
+ "@algolia/monitoring",
+ "@algolia/recommend",
+ "@algolia/requester-browser-xhr",
+ "@algolia/requester-fetch",
+ "@algolia/requester-node-http"
+ ]
+ },
"async-limiter@1.0.1": {
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"asynckit@0.4.0": {
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
+ "base64-js@1.5.1": {
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
+ "birpc@0.2.19": {
+ "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ=="
+ },
"browser-or-node@1.3.0": {
"integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg=="
},
+ "buffer@6.0.3": {
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "dependencies": [
+ "base64-js",
+ "ieee754"
+ ]
+ },
+ "ccount@2.0.1": {
+ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="
+ },
+ "character-entities-html4@2.1.0": {
+ "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="
+ },
+ "character-entities-legacy@3.0.0": {
+ "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="
+ },
"combined-stream@1.0.8": {
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": [
"delayed-stream"
]
},
+ "comma-separated-tokens@2.0.3": {
+ "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="
+ },
+ "copy-anything@3.0.5": {
+ "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
+ "dependencies": [
+ "is-what"
+ ]
+ },
+ "crypto-js@4.2.0": {
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
+ },
"cssstyle@4.1.0": {
"integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==",
"dependencies": [
"rrweb-cssom"
]
},
+ "csstype@3.1.3": {
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
+ },
"curve25519-js@0.0.4": {
"integrity": "sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w=="
},
@@ -124,9 +880,87 @@
"delayed-stream@1.0.0": {
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
+ "dequal@2.0.3": {
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="
+ },
+ "devlop@1.1.0": {
+ "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
+ "dependencies": [
+ "dequal"
+ ]
+ },
+ "discord-api-types@0.37.100": {
+ "integrity": "sha512-a8zvUI0GYYwDtScfRd/TtaNBDTXwP5DiDVX7K5OmE+DRT57gBqKnwtOC5Ol8z0mRW8KQfETIgiB8U0YZ9NXiCA=="
+ },
+ "discord-api-types@0.37.83": {
+ "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA=="
+ },
+ "discord-api-types@0.37.97": {
+ "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA=="
+ },
+ "discord.js@14.16.3": {
+ "integrity": "sha512-EPCWE9OkA9DnFFNrO7Kl1WHHDYFXu3CNVFJg63bfU7hVtjZGyhShwZtSBImINQRWxWP2tgo2XI+QhdXx28r0aA==",
+ "dependencies": [
+ "@discordjs/builders",
+ "@discordjs/collection@1.5.3",
+ "@discordjs/formatters",
+ "@discordjs/rest",
+ "@discordjs/util",
+ "@discordjs/ws",
+ "@sapphire/snowflake",
+ "discord-api-types@0.37.100",
+ "fast-deep-equal",
+ "lodash.snakecase",
+ "tslib",
+ "undici"
+ ]
+ },
+ "emoji-regex-xs@1.0.0": {
+ "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="
+ },
"entities@4.5.0": {
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
},
+ "esbuild@0.21.5": {
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "dependencies": [
+ "@esbuild/aix-ppc64",
+ "@esbuild/android-arm",
+ "@esbuild/android-arm64",
+ "@esbuild/android-x64",
+ "@esbuild/darwin-arm64",
+ "@esbuild/darwin-x64",
+ "@esbuild/freebsd-arm64",
+ "@esbuild/freebsd-x64",
+ "@esbuild/linux-arm",
+ "@esbuild/linux-arm64",
+ "@esbuild/linux-ia32",
+ "@esbuild/linux-loong64",
+ "@esbuild/linux-mips64el",
+ "@esbuild/linux-ppc64",
+ "@esbuild/linux-riscv64",
+ "@esbuild/linux-s390x",
+ "@esbuild/linux-x64",
+ "@esbuild/netbsd-x64",
+ "@esbuild/openbsd-x64",
+ "@esbuild/sunos-x64",
+ "@esbuild/win32-arm64",
+ "@esbuild/win32-ia32",
+ "@esbuild/win32-x64"
+ ]
+ },
+ "estree-walker@2.0.2": {
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+ },
+ "fast-deep-equal@3.1.3": {
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "focus-trap@7.6.2": {
+ "integrity": "sha512-9FhUxK1hVju2+AiQIDJ5Dd//9R2n2RAfJ0qfhF4IHGHgcoEUTMpbTeG/zbEuwaiYXfuAH6XE0/aCyxDdRM+W5w==",
+ "dependencies": [
+ "tabbable"
+ ]
+ },
"form-data@4.0.1": {
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"dependencies": [
@@ -135,12 +969,49 @@
"mime-types"
]
},
+ "fsevents@2.3.3": {
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="
+ },
+ "generate-function@2.3.1": {
+ "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
+ "dependencies": [
+ "is-property"
+ ]
+ },
+ "hast-util-to-html@9.0.4": {
+ "integrity": "sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==",
+ "dependencies": [
+ "@types/hast",
+ "@types/unist",
+ "ccount",
+ "comma-separated-tokens",
+ "hast-util-whitespace",
+ "html-void-elements",
+ "mdast-util-to-hast",
+ "property-information",
+ "space-separated-tokens",
+ "stringify-entities",
+ "zwitch"
+ ]
+ },
+ "hast-util-whitespace@3.0.0": {
+ "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
+ "dependencies": [
+ "@types/hast"
+ ]
+ },
+ "hookable@5.5.3": {
+ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="
+ },
"html-encoding-sniffer@4.0.0": {
"integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
"dependencies": [
"whatwg-encoding"
]
},
+ "html-void-elements@3.0.0": {
+ "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="
+ },
"http-proxy-agent@7.0.2": {
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dependencies": [
@@ -161,9 +1032,27 @@
"safer-buffer"
]
},
+ "ieee754@1.2.1": {
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+ },
+ "is-plain-object@2.0.4": {
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dependencies": [
+ "isobject"
+ ]
+ },
"is-potential-custom-element-name@1.0.1": {
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
},
+ "is-property@1.0.2": {
+ "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="
+ },
+ "is-what@4.1.16": {
+ "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="
+ },
+ "isobject@3.0.1": {
+ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="
+ },
"isomorphic-ws@4.0.1_ws@5.2.4": {
"integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
"dependencies": [
@@ -196,6 +1085,62 @@
"xml-name-validator"
]
},
+ "lodash.snakecase@4.1.1": {
+ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
+ },
+ "lodash@4.17.21": {
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "magic-bytes.js@1.10.0": {
+ "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ=="
+ },
+ "magic-string@0.30.17": {
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+ "dependencies": [
+ "@jridgewell/sourcemap-codec"
+ ]
+ },
+ "mark.js@8.11.1": {
+ "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="
+ },
+ "mdast-util-to-hast@13.2.0": {
+ "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==",
+ "dependencies": [
+ "@types/hast",
+ "@types/mdast",
+ "@ungap/structured-clone",
+ "devlop",
+ "micromark-util-sanitize-uri",
+ "trim-lines",
+ "unist-util-position",
+ "unist-util-visit",
+ "vfile"
+ ]
+ },
+ "micromark-util-character@2.1.1": {
+ "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
+ "dependencies": [
+ "micromark-util-symbol",
+ "micromark-util-types"
+ ]
+ },
+ "micromark-util-encode@2.0.1": {
+ "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="
+ },
+ "micromark-util-sanitize-uri@2.0.1": {
+ "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
+ "dependencies": [
+ "micromark-util-character",
+ "micromark-util-encode",
+ "micromark-util-symbol"
+ ]
+ },
+ "micromark-util-symbol@2.0.1": {
+ "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="
+ },
+ "micromark-util-types@2.0.1": {
+ "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ=="
+ },
"mime-db@1.52.0": {
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
@@ -205,9 +1150,21 @@
"mime-db"
]
},
+ "minisearch@7.1.1": {
+ "integrity": "sha512-b3YZEYCEH4EdCAtYP7OlDyx7FdPwNzuNwLQ34SfJpM9dlbBZzeXndGavTrC+VCiRWomL21SWfMc6SCKO/U2ZNw=="
+ },
+ "mitt@3.0.1": {
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
+ },
+ "mp4box@0.5.3": {
+ "integrity": "sha512-RIvyFZdPDIg3+mL6vUdPBSyQRrEfKO3ryAeJ4xJJV7HBHQUH3KfLlZRzfSpBHCd/HqR63HfbrWQI/CwXDvYENQ=="
+ },
"ms@2.1.3": {
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
+ "nanoid@3.3.8": {
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="
+ },
"node-bignumber@1.2.2": {
"integrity": "sha512-VoTZHmdFQpZH1+q1dz2qcHNCwTWsJg2T3PYwlAyDNFOfVhSYUKQBLFcCpCud+wJBGgCttGavZILaIggDIKqEQQ=="
},
@@ -217,14 +1174,45 @@
"nwsapi@2.2.13": {
"integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ=="
},
- "parse5@7.1.2": {
- "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+ "oniguruma-to-es@0.8.1": {
+ "integrity": "sha512-dekySTEvCxCj0IgKcA2uUCO/e4ArsqpucDPcX26w9ajx+DvMWLc5eZeJaRQkd7oC/+rwif5gnT900tA34uN9Zw==",
+ "dependencies": [
+ "emoji-regex-xs",
+ "regex",
+ "regex-recursion"
+ ]
+ },
+ "parse5@7.2.1": {
+ "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
"dependencies": [
"entities"
]
},
- "psl@1.9.0": {
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
+ "perfect-debounce@1.0.0": {
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="
+ },
+ "picocolors@1.1.1": {
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
+ },
+ "postcss@8.4.49": {
+ "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
+ "dependencies": [
+ "nanoid",
+ "picocolors",
+ "source-map-js"
+ ]
+ },
+ "preact@10.25.4": {
+ "integrity": "sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA=="
+ },
+ "property-information@6.5.0": {
+ "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="
+ },
+ "psl@1.10.0": {
+ "integrity": "sha512-KSKHEbjAnpUuAUserOq0FxGXCUrzC3WniuSJhvdbs102rL55266ZcHBqLWOsG30spQMlPdpy7icATiAQehg/iA==",
+ "dependencies": [
+ "punycode"
+ ]
},
"punycode@2.3.1": {
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="
@@ -235,12 +1223,63 @@
"querystringify@2.2.0": {
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
},
+ "regex-recursion@5.1.1": {
+ "integrity": "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==",
+ "dependencies": [
+ "regex",
+ "regex-utilities"
+ ]
+ },
+ "regex-utilities@2.3.0": {
+ "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="
+ },
+ "regex@5.1.1": {
+ "integrity": "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==",
+ "dependencies": [
+ "regex-utilities"
+ ]
+ },
"requires-port@1.0.0": {
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
},
+ "rfdc@1.4.1": {
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
+ },
+ "rollup@4.29.1": {
+ "integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==",
+ "dependencies": [
+ "@rollup/rollup-android-arm-eabi",
+ "@rollup/rollup-android-arm64",
+ "@rollup/rollup-darwin-arm64",
+ "@rollup/rollup-darwin-x64",
+ "@rollup/rollup-freebsd-arm64",
+ "@rollup/rollup-freebsd-x64",
+ "@rollup/rollup-linux-arm-gnueabihf",
+ "@rollup/rollup-linux-arm-musleabihf",
+ "@rollup/rollup-linux-arm64-gnu",
+ "@rollup/rollup-linux-arm64-musl",
+ "@rollup/rollup-linux-loongarch64-gnu",
+ "@rollup/rollup-linux-powerpc64le-gnu",
+ "@rollup/rollup-linux-riscv64-gnu",
+ "@rollup/rollup-linux-s390x-gnu",
+ "@rollup/rollup-linux-x64-gnu",
+ "@rollup/rollup-linux-x64-musl",
+ "@rollup/rollup-win32-arm64-msvc",
+ "@rollup/rollup-win32-ia32-msvc",
+ "@rollup/rollup-win32-x64-msvc",
+ "@types/estree",
+ "fsevents"
+ ]
+ },
"rrweb-cssom@0.7.1": {
"integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg=="
},
+ "rtp@0.1.0": {
+ "integrity": "sha512-c+Zw80zWCuMCDSTirxRzekn5U8ciz3wu+g3Jklq4ZetRXdpsPrBABIdbUu9GrDhu2Dy9Jx9jn3Fa9eFt7HXGjg=="
+ },
+ "rx.mini@1.4.0": {
+ "integrity": "sha512-8w5cSc1mwNja7fl465DXOkVvIOkpvh2GW4jo31nAIvX4WTXCsRnKJGUfiDBzWtYRInEcHAUYIZfzusjIrea8gA=="
+ },
"safer-buffer@2.1.2": {
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
@@ -250,9 +1289,48 @@
"xmlchars"
]
},
+ "search-insights@2.17.3": {
+ "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ=="
+ },
+ "shiki@1.24.4": {
+ "integrity": "sha512-aVGSFAOAr1v26Hh/+GBIsRVDWJ583XYV7CuNURKRWh9gpGv4OdbisZGq96B9arMYTZhTQkmRF5BrShOSTvNqhw==",
+ "dependencies": [
+ "@shikijs/core",
+ "@shikijs/engine-javascript",
+ "@shikijs/engine-oniguruma",
+ "@shikijs/types",
+ "@shikijs/vscode-textmate",
+ "@types/hast"
+ ]
+ },
+ "source-map-js@1.2.1": {
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
+ },
+ "space-separated-tokens@2.0.2": {
+ "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="
+ },
+ "speakingurl@14.0.1": {
+ "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="
+ },
+ "stringify-entities@4.0.4": {
+ "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
+ "dependencies": [
+ "character-entities-html4",
+ "character-entities-legacy"
+ ]
+ },
+ "superjson@2.2.2": {
+ "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
+ "dependencies": [
+ "copy-anything"
+ ]
+ },
"symbol-tree@3.2.4": {
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
},
+ "tabbable@6.2.0": {
+ "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
+ },
"thrift@0.20.0_ws@5.2.4": {
"integrity": "sha512-oSmJTaoIAGolpupVHFfsWcmdEKX81fcDI6ty0hhezzdgZvp0XyXgMe9+1YusI8Ahy0HK4n8jlNrkPjOPeHZjdQ==",
"dependencies": [
@@ -278,12 +1356,57 @@
"punycode"
]
},
+ "trim-lines@3.0.1": {
+ "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="
+ },
+ "ts-mixer@6.0.4": {
+ "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="
+ },
+ "tslib@2.8.1": {
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
+ },
"tweetnacl@1.0.3": {
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
},
"undici-types@6.19.8": {
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
+ "undici@6.19.8": {
+ "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g=="
+ },
+ "unist-util-is@6.0.0": {
+ "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==",
+ "dependencies": [
+ "@types/unist"
+ ]
+ },
+ "unist-util-position@5.0.0": {
+ "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
+ "dependencies": [
+ "@types/unist"
+ ]
+ },
+ "unist-util-stringify-position@4.0.0": {
+ "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
+ "dependencies": [
+ "@types/unist"
+ ]
+ },
+ "unist-util-visit-parents@6.0.1": {
+ "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==",
+ "dependencies": [
+ "@types/unist",
+ "unist-util-is"
+ ]
+ },
+ "unist-util-visit@5.0.0": {
+ "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==",
+ "dependencies": [
+ "@types/unist",
+ "unist-util-is",
+ "unist-util-visit-parents"
+ ]
+ },
"universalify@0.2.0": {
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="
},
@@ -294,6 +1417,69 @@
"requires-port"
]
},
+ "vfile-message@4.0.2": {
+ "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==",
+ "dependencies": [
+ "@types/unist",
+ "unist-util-stringify-position"
+ ]
+ },
+ "vfile@6.0.3": {
+ "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
+ "dependencies": [
+ "@types/unist",
+ "vfile-message"
+ ]
+ },
+ "vite@5.4.11_@types+node@22.5.4": {
+ "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
+ "dependencies": [
+ "@types/node@22.5.4",
+ "esbuild",
+ "fsevents",
+ "postcss",
+ "rollup"
+ ]
+ },
+ "vitepress@1.5.0_vite@5.4.11__@types+node@22.5.4_vue@3.5.13_focus-trap@7.6.2_@types+node@22.5.4": {
+ "integrity": "sha512-q4Q/G2zjvynvizdB3/bupdYkCJe2umSAMv9Ju4d92E6/NXJ59z70xB0q5p/4lpRyAwflDsbwy1mLV9Q5+nlB+g==",
+ "dependencies": [
+ "@docsearch/css",
+ "@docsearch/js",
+ "@iconify-json/simple-icons",
+ "@shikijs/core",
+ "@shikijs/transformers",
+ "@shikijs/types",
+ "@types/markdown-it",
+ "@vitejs/plugin-vue",
+ "@vue/devtools-api",
+ "@vue/shared",
+ "@vueuse/core",
+ "@vueuse/integrations",
+ "focus-trap",
+ "mark.js",
+ "minisearch",
+ "shiki",
+ "vite",
+ "vue"
+ ]
+ },
+ "vue-demi@0.14.10_vue@3.5.13": {
+ "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+ "dependencies": [
+ "vue"
+ ]
+ },
+ "vue@3.5.13": {
+ "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
+ "dependencies": [
+ "@vue/compiler-dom",
+ "@vue/compiler-sfc",
+ "@vue/runtime-dom",
+ "@vue/server-renderer",
+ "@vue/shared"
+ ]
+ },
"w3c-xmlserializer@5.0.0": {
"integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
"dependencies": [
@@ -303,6 +1489,19 @@
"webidl-conversions@7.0.0": {
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
},
+ "werift-rtp@0.8.2": {
+ "integrity": "sha512-h+y6aipk+dddZpqXV+2x0VCA6sQ9lD9801A2lHw7xqBQel55ysw0NcCjZN3tiEVajvlq1BLKnn1+pCvLIKyvUQ==",
+ "dependencies": [
+ "@minhducsun2002/leb128",
+ "@shinyoshiaki/binary-data",
+ "@shinyoshiaki/jspack",
+ "aes-js",
+ "buffer",
+ "debug",
+ "mp4box",
+ "rx.mini"
+ ]
+ },
"whatwg-encoding@3.1.1": {
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
"dependencies": [
@@ -333,18 +1532,135 @@
},
"xmlchars@2.2.0": {
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ },
+ "zwitch@2.0.4": {
+ "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="
}
},
+ "remote": {
+ "https://deno.land/std@0.200.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
+ "https://deno.land/std@0.200.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
+ "https://deno.land/std@0.200.0/flags/mod.ts": "a5ac18af6583404f21ea03771f8816669d901e0ff4374020870334d6f61d73d5",
+ "https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
+ "https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd",
+ "https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
+ "https://deno.land/std@0.224.0/flags/mod.ts": "88553267f34519c8982212185339efdb2d2e62c159ec558f47eb50c8952a6be3",
+ "https://deno.land/std@0.224.0/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8",
+ "https://deno.land/std@0.224.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2",
+ "https://deno.land/std@0.224.0/path/_common/common.ts": "ef73c2860694775fe8ffcbcdd387f9f97c7a656febf0daa8c73b56f4d8a7bd4c",
+ "https://deno.land/std@0.224.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c",
+ "https://deno.land/std@0.224.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
+ "https://deno.land/std@0.224.0/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b",
+ "https://deno.land/std@0.224.0/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf",
+ "https://deno.land/std@0.224.0/path/_common/glob_to_reg_exp.ts": "6cac16d5c2dc23af7d66348a7ce430e5de4e70b0eede074bdbcf4903f4374d8d",
+ "https://deno.land/std@0.224.0/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
+ "https://deno.land/std@0.224.0/path/_common/normalize_string.ts": "33edef773c2a8e242761f731adeb2bd6d683e9c69e4e3d0092985bede74f4ac3",
+ "https://deno.land/std@0.224.0/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607",
+ "https://deno.land/std@0.224.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a",
+ "https://deno.land/std@0.224.0/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883",
+ "https://deno.land/std@0.224.0/path/_interface.ts": "8dfeb930ca4a772c458a8c7bbe1e33216fe91c253411338ad80c5b6fa93ddba0",
+ "https://deno.land/std@0.224.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15",
+ "https://deno.land/std@0.224.0/path/basename.ts": "7ee495c2d1ee516ffff48fb9a93267ba928b5a3486b550be73071bc14f8cc63e",
+ "https://deno.land/std@0.224.0/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643",
+ "https://deno.land/std@0.224.0/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36",
+ "https://deno.land/std@0.224.0/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c",
+ "https://deno.land/std@0.224.0/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441",
+ "https://deno.land/std@0.224.0/path/format.ts": "6ce1779b0980296cf2bc20d66436b12792102b831fd281ab9eb08fa8a3e6f6ac",
+ "https://deno.land/std@0.224.0/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069",
+ "https://deno.land/std@0.224.0/path/glob_to_regexp.ts": "7f30f0a21439cadfdae1be1bf370880b415e676097fda584a63ce319053b5972",
+ "https://deno.land/std@0.224.0/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7",
+ "https://deno.land/std@0.224.0/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141",
+ "https://deno.land/std@0.224.0/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a",
+ "https://deno.land/std@0.224.0/path/join_globs.ts": "5b3bf248b93247194f94fa6947b612ab9d3abd571ca8386cf7789038545e54a0",
+ "https://deno.land/std@0.224.0/path/mod.ts": "f6bd79cb08be0e604201bc9de41ac9248582699d1b2ee0ab6bc9190d472cf9cd",
+ "https://deno.land/std@0.224.0/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352",
+ "https://deno.land/std@0.224.0/path/normalize_glob.ts": "cc89a77a7d3b1d01053b9dcd59462b75482b11e9068ae6c754b5cf5d794b374f",
+ "https://deno.land/std@0.224.0/path/parse.ts": "77ad91dcb235a66c6f504df83087ce2a5471e67d79c402014f6e847389108d5a",
+ "https://deno.land/std@0.224.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d",
+ "https://deno.land/std@0.224.0/path/posix/basename.ts": "d2fa5fbbb1c5a3ab8b9326458a8d4ceac77580961b3739cd5bfd1d3541a3e5f0",
+ "https://deno.land/std@0.224.0/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
+ "https://deno.land/std@0.224.0/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1",
+ "https://deno.land/std@0.224.0/path/posix/dirname.ts": "76cd348ffe92345711409f88d4d8561d8645353ac215c8e9c80140069bf42f00",
+ "https://deno.land/std@0.224.0/path/posix/extname.ts": "e398c1d9d1908d3756a7ed94199fcd169e79466dd88feffd2f47ce0abf9d61d2",
+ "https://deno.land/std@0.224.0/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1",
+ "https://deno.land/std@0.224.0/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40",
+ "https://deno.land/std@0.224.0/path/posix/glob_to_regexp.ts": "76f012fcdb22c04b633f536c0b9644d100861bea36e9da56a94b9c589a742e8f",
+ "https://deno.land/std@0.224.0/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede",
+ "https://deno.land/std@0.224.0/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
+ "https://deno.land/std@0.224.0/path/posix/join.ts": "7fc2cb3716aa1b863e990baf30b101d768db479e70b7313b4866a088db016f63",
+ "https://deno.land/std@0.224.0/path/posix/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25",
+ "https://deno.land/std@0.224.0/path/posix/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
+ "https://deno.land/std@0.224.0/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91",
+ "https://deno.land/std@0.224.0/path/posix/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6",
+ "https://deno.land/std@0.224.0/path/posix/parse.ts": "09dfad0cae530f93627202f28c1befa78ea6e751f92f478ca2cc3b56be2cbb6a",
+ "https://deno.land/std@0.224.0/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c",
+ "https://deno.land/std@0.224.0/path/posix/resolve.ts": "08b699cfeee10cb6857ccab38fa4b2ec703b0ea33e8e69964f29d02a2d5257cf",
+ "https://deno.land/std@0.224.0/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf",
+ "https://deno.land/std@0.224.0/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0",
+ "https://deno.land/std@0.224.0/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add",
+ "https://deno.land/std@0.224.0/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d",
+ "https://deno.land/std@0.224.0/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b",
+ "https://deno.land/std@0.224.0/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40",
+ "https://deno.land/std@0.224.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808",
+ "https://deno.land/std@0.224.0/path/windows/basename.ts": "6bbc57bac9df2cec43288c8c5334919418d784243a00bc10de67d392ab36d660",
+ "https://deno.land/std@0.224.0/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
+ "https://deno.land/std@0.224.0/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5",
+ "https://deno.land/std@0.224.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9",
+ "https://deno.land/std@0.224.0/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef",
+ "https://deno.land/std@0.224.0/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6",
+ "https://deno.land/std@0.224.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01",
+ "https://deno.land/std@0.224.0/path/windows/glob_to_regexp.ts": "e45f1f89bf3fc36f94ab7b3b9d0026729829fabc486c77f414caebef3b7304f8",
+ "https://deno.land/std@0.224.0/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a",
+ "https://deno.land/std@0.224.0/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
+ "https://deno.land/std@0.224.0/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf",
+ "https://deno.land/std@0.224.0/path/windows/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25",
+ "https://deno.land/std@0.224.0/path/windows/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
+ "https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780",
+ "https://deno.land/std@0.224.0/path/windows/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6",
+ "https://deno.land/std@0.224.0/path/windows/parse.ts": "08804327b0484d18ab4d6781742bf374976de662f8642e62a67e93346e759707",
+ "https://deno.land/std@0.224.0/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7",
+ "https://deno.land/std@0.224.0/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972",
+ "https://deno.land/std@0.224.0/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e",
+ "https://deno.land/std@0.224.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c",
+ "https://deno.land/std@0.79.0/_util/assert.ts": "e1f76e77c5ccb5a8e0dbbbe6cce3a56d2556c8cb5a9a8802fc9565af72462149",
+ "https://deno.land/std@0.79.0/_util/os.ts": "e2be3e25f96e4b5a233a08fd03aba80819bcaee66ac53c11c9b5aaa64799b475",
+ "https://deno.land/std@0.79.0/path/_constants.ts": "3a19d04e5d6de4620df22ab40c2e8c9d87002b56702d2b4669c14dfa2765e368",
+ "https://deno.land/std@0.79.0/path/_interface.ts": "67b276380d297a7cedc3c17f7a0bf122edcfc96a3e1f69de06f379d85ba0e2c0",
+ "https://deno.land/std@0.79.0/path/_util.ts": "7820a788b35c26dfc27ff329df12507fc0553ae92727009597046f6cf856b4fa",
+ "https://deno.land/std@0.79.0/path/common.ts": "e4ec66a7416d56f60331b66e27a8a4f08c7b1cf48e350271cb69754a01cf5c04",
+ "https://deno.land/std@0.79.0/path/glob.ts": "c36be777b82346a3fac02ef0ffef7d6c9bfe4da50f4599c798d7ded072f88d22",
+ "https://deno.land/std@0.79.0/path/mod.ts": "ef6a91aed4bc417eb56f8d5947f117f35ed3ca76c24d19dc482d3d6514218d5f",
+ "https://deno.land/std@0.79.0/path/posix.ts": "0f635537634111caa17a944b7405cf0a50ed6d6dd1a847c65323bebeccec5718",
+ "https://deno.land/std@0.79.0/path/separator.ts": "696812939d47fbe095002e92d595e3a1cdf03157222029a39c68dce9995f38c4",
+ "https://deno.land/std@0.79.0/path/win32.ts": "c5efe2a88d2351adddb53c22439ef32dc1081bc0d4205ae54a2ce388bcc600fb"
+ },
"workspace": {
"dependencies": [
"jsr:@std/assert@^1.0.2",
"npm:@types/node@latest",
+ "npm:@types/thrift@~0.10.17",
"npm:curve25519-js@^0.0.4",
"npm:jsdom@25.0.0",
"npm:node-bignumber@^1.2.2",
"npm:node-int64@0.4",
"npm:thrift@0.20",
"npm:tweetnacl@^1.0.3"
- ]
+ ],
+ "members": {
+ "packages/linejs": {
+ "dependencies": [
+ "npm:@types/jsdom@*",
+ "npm:@types/node@latest",
+ "npm:@types/thrift@~0.10.17",
+ "npm:crypto-js@^4.2.0",
+ "npm:curve25519-js@^0.0.4",
+ "npm:jsdom@25.0.0",
+ "npm:node-bignumber@^1.2.2",
+ "npm:node-int64@0.4",
+ "npm:thrift@0.20",
+ "npm:tweetnacl@^1.0.3"
+ ]
+ }
+ }
}
}
diff --git a/directory.md b/directory.md
new file mode 100644
index 00000000..1ecc3c2d
--- /dev/null
+++ b/directory.md
@@ -0,0 +1,50 @@
+## /docs
+
+ドキュメントサイト: https://linejs.evex.land
+
+## /packages
+
+exportするパッケージ
+
+- **/linejs** @evex/linejs
+ - **/src**
+ - **/core** メインのclient
+ - **/e2ee** encrypt/decrypt
+ - **/login** email, qr
+ - **/polling** event, emit
+ - **/request** fetch
+ - **/service** LINEのservice
+ - **/auth** LoginService + AuthService + AccessTokenRefreshService
+ - **/call** CallService
+ - **/channel** ChannelService
+ - **/liff** LiffService
+ - **/livetalk** SquareLiveTalkService
+ - **/relation** RelationService
+ - **/square** SquareService + SquareBotService
+ - **/talk** TalkService + SyncService
+ - **/storage**
+ - **/thrift**
+ - **/readwrite** read/write
+ - **/rename** ThriftRenameParser
+ - **/timeline** voom, note
+- **/types** @evex/linejs-types
+ - line_types struct, enumの型定義とenumの値
+ - thrift 解析したthrift
+
+## /resources
+
+ファイル等
+
+- **/line**
+
+## /tools
+
+ツール
+
+- **/device**
+ - latest_device 最新verを取得
+- **/thrift**
+ - parser thriftファイル解析
+ - gen_typedef line_types生成
+ - gen_struct NestedArray
+ - java2thrift java解析
diff --git a/docs/.gitignore b/docs/.gitignore
deleted file mode 100644
index 2b601e74..00000000
--- a/docs/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-node_modules
-.vitepress/cache/deps
-.vitepress/dist
diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index 8d922bbe..b2959072 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -19,7 +19,10 @@ export default defineConfig({
nav: [
{ text: "Home", link: "/" },
{ text: "Docs", link: "/docs/start" },
- { text: "Examples", link: "https://github.com/evex-dev/linejs/tree/main/examples" },
+ {
+ text: "Examples",
+ link: "https://github.com/evex-dev/linejs/tree/main/examples",
+ },
],
sidebar: [
@@ -30,8 +33,8 @@ export default defineConfig({
{ text: "Next Steps", link: "/docs/start-2" },
{ text: "Message Event", link: "/docs/message-event" },
{ text: "Client Options", link: "/docs/client-options" },
- { text: "Utils", link: "/docs/utils" },
- { text: "Talk Methods", link: "/docs/talk-methods" },
+ // { text: "Utils", link: "/docs/utils" },
+ { text: "Client Methods", link: "/docs/methods" },
],
},
{
@@ -88,5 +91,5 @@ export default defineConfig({
}],
],
- cleanUrls: true
+ cleanUrls: true,
});
diff --git a/docs/bun.lockb b/docs/bun.lockb
deleted file mode 100644
index a1e75029..00000000
Binary files a/docs/bun.lockb and /dev/null differ
diff --git a/docs/deno.json b/docs/deno.json
index 7525125b..18275739 100644
--- a/docs/deno.json
+++ b/docs/deno.json
@@ -1,8 +1,7 @@
{
"tasks": {
- "vp": "deno run -A npm:vitepress"
- },
- "unstable": [
- "byonm"
- ]
+ "dev": "deno run -A npm:vitepress",
+ "build": "deno run -A npm:vitepress build .",
+ "serve": "vitepress serve ."
+ }
}
diff --git a/docs/docs/auth.md b/docs/docs/auth.md
new file mode 100644
index 00000000..b370c728
--- /dev/null
+++ b/docs/docs/auth.md
@@ -0,0 +1,46 @@
+# Authentication
+
+You can get authenticated with multiple ways.
+
+## Login
+
+Login is a simple way to get authenticated. LINEJS has 2 ways to login.
+
+### `loginWithPassword`
+
+Here is an example:
+```ts
+import { loginWithPassword } from "@evex/linejs";
+
+const client = loginWithPassword({
+ email: 'you@example.com', // e-mail address
+ password: 'password', // Password
+ onPincodeRequest(pincode) {
+ console.log('Enter this pincode to your LINE app:', pincode)
+ }
+})
+```
+
+email, password is required. On first login, you have to enter pincode on mobile app for enable e2ee.
+`onPincodeRequest` can receive a pincode and you can output it with that method to tell users pincode.
+
+### `loginWithQR`
+
+In this way, email and password is not needed.
+
+```ts
+import { loginWithQR } from '@evex/linejs'
+
+const client = loginWithQR({
+ onReceiveQRURL(url) {
+ console.log('Access to this URL:', url)
+ }
+})
+```
+
+The function gives an url to read on mobile. You have to create QR with yourself if you want to show QR code, this is because of LINEJS doesn't support creating QR code.
+
+## With authToken
+
+There is a possibility to banned your account if you tried login many times, so you should use authToken to get authenticated.
+
diff --git a/docs/docs/authors.md b/docs/docs/authors.md
index ba473bc3..5a701c81 100644
--- a/docs/docs/authors.md
+++ b/docs/docs/authors.md
@@ -6,6 +6,7 @@ Maintainers of **LINEJS**
- Owner & Developer [Piloking](https://github.com/piloking)
- Developer [EdamAme-x](https://github.com/EdamAme-x)
+- Developer [nakasyou](https://github.com/nakasyou)
## Sub-maintainers
diff --git a/docs/docs/client-options.md b/docs/docs/client-options.md
index abad1a29..646fcda4 100644
--- a/docs/docs/client-options.md
+++ b/docs/docs/client-options.md
@@ -1,101 +1,92 @@
# Client Options
-Next, we will talk about the Client.
+Next, we will talk about the ClientInit.\
The Client has several options.
```ts
-const client = new Client({
- ...
+const client = await loginWithPassword({
+ email: "",
+ password: "",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, {
+ device: "IOSIPAD",
+ version: "14.0.1",
+ endpoint: "example.com",
+ fetch: (req) => fetch(req),
+ storage: new FileStorage("./storage.json"),
});
```
-For example, **storage for the data** we discussed before, **OBS Endpoint**, **Endpoint** for communication, **customFetch** for cors and proxies, **RateLimitter** for rate limiting, etc.
+For example, **storage for the data** we discussed before,
+**Endpoint** for communication, **custom fetch** for cors and proxies,etc.
I'll explain it to you one by one.
## Storage
-This is storage for internal needs such as decryption keys and caches.
-By default, `MemoryStorage` is used, and once you stop the program, you must log in from the beginning.
+This is storage for internal needs such as decryption keys and caches. By
+default, `MemoryStorage` is used, and once you stop the program, you must log in
+from the beginning.
You can use `FileStorage` there.
```ts
import { FileStorage } from "@evex/linejs/storage";
-const client = new Client({
- storage: new FileStorage("./storage.json"), // path to storage file (This is secret file)
+const client = await loginWithPassword({
+ email: "",
+ password: "",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, {
+ device: "IOSIPAD",
+ storage: new FileStorage("./storage.json"),
});
```
-If you want to store in your cloud or storages with your data storage API, you can extend `BaseStorage` to create something of your liking.
+If you want to store in your cloud or storages with your data storage API, you
+can extend `BaseStorage` to create something of your liking.\
I'd like to give you more details on our server.
-## OBS Endpoint
-
-OBS stands for `OBject Storage` and is the CDN where LINE stores images and videos.
-There are several endpoints.
-If you want to change the endpoints you can do so as follows
-
-```ts
-import { LINE_OBS } from "@evex/linejs/utils";
-
-const client = new Client({
- LINE_OBS: new LINE_OBS("https://obs.line-scdn.net/"),
-});
-```
-
-:::tip
-Wait a minute, do you care about `@evex/linejs/utils`?
-It contains useful things like search functions for OpenChat, internal URL construction functions, etc.
-Later.
-:::
-
## Endpoint
-The endpoints of communication.
-There is no need to change this point.
+
+The endpoints of communication.\
+There is no need to change this point.\
If you want to try out a proxied server, use it.
```ts
-const client = new Client({
- endpoint: "gw.line.naver.jp"
+const client = await loginWithPassword({
+ email: "",
+ password: "",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, {
+ device: "IOSIPAD",
+ endpoint: "example.com",
});
```
-
## Custom Fetch
-This is for cors avoidance or proxy.
-You define a function that replaces fetch.
+This is for cors avoidance or proxy. You define a function that replaces fetch.
```ts
...
-
-const client = new Client({
- customFetch: async (url, options) => {
- return await fetch(url, {
- ...options,
- ...proxyAgent
- });
- }
+const client = await loginWithPassword({
+ email: "",
+ password: "",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, {
+ device: "IOSIPAD",
+ fetch: (req) => myfetch(req),
});
```
-## RateLimitter
-
-It is a safeguard to ensure that you are not restricted by the Square (OpenChat) by a series of posts.
-The default is 9 posts per 2 seconds.
-If you want to make it stricter, you can change it.
-
-```ts
-import { RateLimitter } from "@evex/linejs/rate-limit";
-
-const client = new Client({
- squareRateLimitter: new RateLimitter(4, 2000),
-});
-```
-
-This will bring the total to 4 posts per 2 seconds.
-
-This concludes the explanation of options!
-Next, we will discuss `@evex/linejs/utils` as an extra.
+This concludes the explanation of options!\
+The next sections will introduce the various methods.
diff --git a/docs/docs/message-event.md b/docs/docs/message-event.md
index 0ce6cc10..14c91832 100644
--- a/docs/docs/message-event.md
+++ b/docs/docs/message-event.md
@@ -1,13 +1,12 @@
-# Receive Message Event
+# Receive Message client
-The next step is to finally receive the message.
-The atmosphere is becoming more and more like a bot!
+The next step is to finally receive the message.\
+The atmosphere is becoming more and more like a bot!
-:::warning
-Note, however, that to receive the group's message, the decrypt key in `FileStorage` or so on, as described in [Start 2](/docs/start-2).
-:::
+:::warning Note, however, that to receive the group's message, the decrypt key
+in `FileStorage` or so on, as described in [Start 2](/docs/start-2). :::
-First, let's create a bot that only receives “!ping” and returns “pong!”.
+First, let's create a bot that only receives “!ping” and returns “pong!”.
## Chat
@@ -19,31 +18,31 @@ client.on("message", (message) => {
});
```
-This is all that is needed to receive the message.
+This is all that is needed to receive the message.\
Easy, isn't it?
-So first, let's retrieve the messages sent.
+So first, let's retrieve the messages sent.
```ts
client.on("message", (message) => {
- const text = message.content;
-
+ const text = message.text;
console.log(text);
});
+client.listen();
```
-Your console should now show the message that was sent to you!
+Your console should now show the message that was sent to you!
```console
Hello EdamAmex
I love you! :D
```
-Next, let's check if the message is “!ping”.
+Next, let's check if the message is “!ping”.
```ts
client.on("message", (message) => {
- const text = message.content;
+ const text = message.text;
if (text === "!ping") {
...
@@ -51,13 +50,14 @@ client.on("message", (message) => {
});
```
-This is perfect. Next time I need to reply.
+This is perfect. Next time I need to reply.
-To reply, you can call a method that sends a `messageId` with a `relatedMessageId`, but there is a more convenient way.
+To reply, you can call a method that sends a `messageId` with a
+`relatedMessageId`, but there is a more convenient way.
```ts
client.on("message", (message) => {
- const text = message.content;
+ const text = message.text;
if (text === "!ping") {
message.reply("pong!");
@@ -65,12 +65,12 @@ client.on("message", (message) => {
});
```
-What a beautiful code!
-It's too easy. However, in this case, it is more beautiful to enclose it in an asynchronous function.
+What a beautiful code! It's too easy. However, in this case, it is more
+beautiful to enclose it in an asynchronous function.
```ts
client.on("message", async (message) => {
- const text = message.content;
+ const text = message.text;
if (text === "!ping") {
await message.reply("pong!");
@@ -78,17 +78,17 @@ client.on("message", async (message) => {
});
```
-That's all!
-There are also `send`, `reaction`, etc.
-Let me explain all the methods in other chapters.
+That's all!\
+There are also `send`, `reaction`, etc.\
+Let me explain all the methods in other chapters.
## Square
-So what should we do with Square (OpenChat)?
-Basically the same thing.
+
+So what should we do with Square (OpenChat)? Basically the same thing.
```ts
client.on("square:message", async (message) => {
- const text = message.content;
+ const text = message.text;
if (text === "!ping") {
await message.reply("pong!");
@@ -96,11 +96,10 @@ client.on("square:message", async (message) => {
});
```
-With this alone you can create a basic bot.
+With this alone you can create a basic bot.\
There are many more features!
-Stay tuned for our next journey.
+Stay tuned for our next journey.
-:::tip
-If you encounter problems, please refer to [Question](/docs/question), not only here.
-:::
+:::tip If you encounter problems, please refer to [Question](/docs/question),
+not only here. :::
diff --git a/docs/docs/methods.md b/docs/docs/methods.md
new file mode 100644
index 00000000..0eb71ce8
--- /dev/null
+++ b/docs/docs/methods.md
@@ -0,0 +1,82 @@
+# Methods
+
+## Talk Methods
+
+All the functions for TalkService are in `Client.base.talk`.
+
+For example:
+
+```js
+await client.base.talk.sendMessage({
+ to: "u...",
+ text: "Hello, LINEJS!",
+ e2ee: true,
+});
+```
+
+This is an example of encrypting a text message with e2ee and sending it to a
+user.
+
+## Square Methods
+
+All the functions for SquareService are in `Client.square`.
+
+For example:
+
+```js
+await client.base.square.findSquareByInvitationTicket({
+ request: {
+ invitationTicket: "INVITATION_TICKET",
+ },
+});
+```
+
+This is an example of getting square from invitation code.
+
+# BaseClient
+
+If you just want simple api access or custom event handlers, you can use `BaseClient`.
+
+For example:
+
+```js
+import { BaseClient } from "@evex/linejs/base";
+
+
+const client = new BaseClient({ device: "DESKTOPWIN", version:"..." });
+client.on("pincall", (pin) => {
+});
+
+client.on("qrcall", (qrUrl) => {
+});
+
+client.on("update:authtoken", (authToken) => {
+});
+
+await client.loginProcess.login({
+ authToken: "...",
+});
+
+await client.loginProcess.login({
+ email: "...",
+ password: "...",
+ pincode: "123456",
+});
+
+await client.loginProcess.login({
+ qr: true,
+});
+
+client.square // = SquareService
+client.talk // = TalkService
+
+
+// event polling
+const polling = client.createPolling();
+
+for await (const operation of polling.listenTalkEvents()) {
+}
+
+for await (const event of polling.listenSquareEvents()) {
+}
+```
\ No newline at end of file
diff --git a/docs/docs/start-2.md b/docs/docs/start-2.md
index 5571e426..98c993ac 100644
--- a/docs/docs/start-2.md
+++ b/docs/docs/start-2.md
@@ -2,34 +2,21 @@
Next, How to use the methods of client?
-It's easy.
+It's easy.
All you have to do is call the client's method as follows.
-
```ts
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-client.on("pincall", (pincode) => {
- console.log(`pincode: ${pincode}`);
-});
-
-client.on("ready", async (user) => {
- console.log(`Logged in as ${user.displayName} (${user.mid});`);
+import { loginWithPassword } from "@evex/linejs";
- console.log(await client.getProfile());
-});
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
-});
+const client = await loginWithPassword({
+ email: 'you@example.com', // e-mail address
+ password: 'password', // Password
+ onPincodeRequest(pincode) {
+ console.log('Enter this pincode to your LINE app:', pincode)
+ }
+}, { device: "IOSIPAD" })
-// or, you can log in using the QR code.
-await client.login({
- qr: true,
-});
+console.log(await client.base.talk.getProfile());
```
The output will be as follows.
@@ -54,9 +41,8 @@ It is therefore a good idea to use an **AuthToken**.
A temporary token is used for email login.\
Therefore, after a few days, it will expire and the client will stop running.\
-So, if you want to run the client permanently, you must use v1.
+So, if you want to run the client permanently, you must use v3.
-It would be a good idea to use v2 during development.\
Repeating the email login multiple times is highly discouraged.
Now, let's look at how to get token.
@@ -65,7 +51,7 @@ Simply write the following.\
It's easy.
```ts
-client.on("update:authtoken", (authtoken) => {
+client.base.on("update:authtoken", (authtoken) => {
console.log("AuthToken", authtoken);
});
```
@@ -76,18 +62,18 @@ The output will be as follows.
AuthToken **********.********
```
-This is the v2 token. It can be used as follows
+This is the auth token. It can be used as follows
```ts
-await client.login({
- authToken: "YOUR_AUTH_TOKEN",
-});
+import { loginWithAuthToken } from "@evex/linejs";
+const client = await loginWithAuthToken(authtoken, { device: "IOSIPAD" });
```
## Important notice
However, this login method has pitfalls. LINE uses _e2ee_ for encryption, but
-the key to decrypt it can only be obtained with an email login with pincode, or QR login.
+the key to decrypt it can only be obtained with an email login with pincode, or
+QR login.
Therefore, if you login only with an authToken, you will not be able to retrieve
group talk events.\
@@ -106,9 +92,11 @@ This can be `FileStorage`. As follows.
```ts
import { FileStorage } from "@evex/linejs/storage";
-const client = new Client({
- storage: new FileStorage("./storage.json"), // path to storage file (This is secret file)
+const client = await loginWithAuthToken(authtoken, {
+ device: "IOSIPAD",
+ storage: new FileStorage("./storage.json"), // path to storage file (This is secret file)
});
+
```
You only need to log in once first with your email and then use your authToken.
@@ -117,14 +105,11 @@ This concludes our first trip.\
But there is still a journey left to be made.\
Enjoy.
-:::tip
-If you want to create your own storage such as connecting to the cloud
-api,\
+:::tip\
+If you want to create your own storage such as connecting to the cloud api,\
import `BaseStorage` and extend it to create your own storage. (Please ask for
-details.)
-:::
+details.) :::
-:::info
+:::info\
If you want to use v1, please ask for details at
-[discord.gg/evex](https://discord.gg/evex).
-:::
+[discord.gg/evex](https://discord.gg/evex). :::
diff --git a/docs/docs/start.md b/docs/docs/start.md
index e77ef9c0..410398b9 100644
--- a/docs/docs/start.md
+++ b/docs/docs/start.md
@@ -1,15 +1,16 @@
# Getting Started
-LINEJS is always by your side
+LINEJS is always by your side.
Thank you for choosing this library!
## Installation
+LINEJS is published on JSR, not a npm. You can install LINEJS with npm, yarn, pnpm, Bun, and Deno.
```bash
-npx jsr add @evex/linejs
-bunx --bun jsr add @evex/linejs
-deno add @evex/linejs
+npx jsr add @evex/linejs # If you use npm
+bunx --bun jsr add @evex/linejs # If you use Bun
+deno add @evex/linejs # If you use Deno
```
After execution, you should have the library available.
@@ -18,76 +19,29 @@ After execution, you should have the library available.
Next, let's create a script that just retrieves your profile!
+To making client, you can use `loginWithPassword`.
```ts
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-client.on("pincall", (pincode) => {
- console.log(`pincode: ${pincode}`);
-});
-
-client.on("ready", (user) => {
- console.log(`Logged in as ${user.displayName} (${user.mid});`);
-});
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
-}); // (If you're using Node.js, please wrap async IIFE)
-```
-
-First, log in using your _email_. We will explain each code later.\
-(LINEJS supports login by **AuthToken**, **QR** and **Pincode**.)
-
-:::warning
-Please enable email login in your settings.
-:::
-
-The method of execution depends on the runtime.
-
-```bash
-node ./index.js
-npx tsx ./index.ts
-bun run ./index.js
-deno run -A ./index.ts
+import { loginWithPassword } from "@evex/linejs";
+
+const client = await loginWithPassword({
+ email: 'you@example.com', // e-mail address
+ password: 'password', // Password
+ onPincodeRequest(pincode) {
+ console.log('Enter this pincode to your LINE app:', pincode)
+ }
+}, { device: "IOSIPAD" })
```
-Thereafter, please use what suits you best.
+Authentication is complicated process, so you should read [here](./auth.md).
-Then, you will see the following output.
-
-```console
-pincode: 114514
-```
-
-You will then receive a login request on the LINE app for the account you wish
-to log in to, and enter the pin code displayed.
-
-By the way, `114514` is Japanese slang. If you don't like it or think it's
-messy, you can change it by doing the following.
+After created client, you can do various things!
+For instance, you can get one of chat informations you joined:
```ts
-await client.login({
- ...,
- pincode: "810810"
-});
-```
-
-The output will then be as follows.
-
-```console
-Logged in as EdamAmex (u********************************)
+const chats = await client.fetchChats()
+console.log(chats[0].name)
```
-Now, you have obtained a `displayName` and `mid`!\
-On successful login, `ready` is called and the user object is passed.
-
-There you will find your complete profile. Of course, there is another way to
-get it from the method.
-
-Let's try that next!
-
---
This library is still in its infancy!\
diff --git a/docs/docs/talk-methods.md b/docs/docs/talk-methods.md
deleted file mode 100644
index 5d2f047b..00000000
--- a/docs/docs/talk-methods.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# Talk Methods
-Coming soon
\ No newline at end of file
diff --git a/docs/package.json b/docs/package.json
deleted file mode 100644
index dabb6355..00000000
--- a/docs/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "linejs-docs",
- "version": "0.0.0",
- "scripts": {
- "dev": "vitepress dev .",
- "build": "vitepress build .",
- "serve": "vitepress serve ."
- },
- "devDependencies": {
- "vitepress": "^1.3.4",
- "vue": "^3.5.3"
- }
-}
diff --git a/example/base-client/ping.ts b/example/base-client/ping.ts
new file mode 100644
index 00000000..41ba3eec
--- /dev/null
+++ b/example/base-client/ping.ts
@@ -0,0 +1,51 @@
+import { BaseClient } from "@evex/linejs/base";
+import { FileStorage } from "@evex/linejs/storage";
+import type * as LINETypes from "@evex/linejs-types";
+
+const storage = new FileStorage("./storage.json");
+
+const client = new BaseClient({
+ device: "DESKTOPWIN",
+ storage,
+});
+
+client.on("pincall", (pin) => {
+ console.log("pincode:", pin);
+});
+
+client.on("qrcall", (qrUrl) => {
+ console.log("qrcode:", qrUrl);
+});
+
+client.on("update:authtoken", async (authToken) => {
+ await storage.set(".auth", authToken);
+});
+
+const authToken = await storage.get(".auth");
+if (typeof authToken === "string") {
+ await client.loginProcess.login({
+ authToken,
+ });
+} else {
+ await client.loginProcess.login({
+ email: prompt("email: ") ?? "",
+ password: prompt("password: ") ?? "",
+ });
+}
+
+const polling = client.createPolling();
+
+for await (const op of polling.listenTalkEvents()) {
+ if (op.type === "RECEIVE_MESSAGE" || op.type === "SEND_MESSAGE") {
+ const message = await client.e2ee.decryptE2EEMessage(op.message);
+ if (message.text === "!ping") {
+ await client.talk.sendMessage({
+ to: message.to === client.profile?.mid
+ ? message.from
+ : message.to,
+ text: "pong!",
+ e2ee: !!op.message.chunks,
+ });
+ }
+ }
+}
diff --git a/example/browser/README.md b/example/browser/README.md
new file mode 100644
index 00000000..7d2e0529
--- /dev/null
+++ b/example/browser/README.md
@@ -0,0 +1,10 @@
+# LINEJS in Browser
+
+In a browser, you cannot use the Fetch API to send requests to the LINE endpoint
+because of CORS.
+
+The best option is to set a proxy server to the LINE endpoint.
+
+However, you can get around this issue by calling LINEJS from a bookmarklet on a
+page such as https://legy-jp.line-apps.com/sn. (An example of this can be found
+in [browser-init.js](browser-init.js))
diff --git a/example/browser/browser-init.js b/example/browser/browser-init.js
new file mode 100644
index 00000000..d9fbc3fd
--- /dev/null
+++ b/example/browser/browser-init.js
@@ -0,0 +1,90 @@
+(function () {
+ const script = document.createElement("script");
+ script.innerHTML = `
+ import * as LINEJS from "https://esm.sh/v135/@jsr/evex__linejs@2.0.0-rc1/es2022/evex__linejs.mjs";
+
+ document.body.innerHTML = "";
+ class LocalStorage {
+ prefix = "linejs:";
+ set(
+ key,
+ value,
+ ) {
+ localStorage.setItem(this.prefix + key, JSON.stringify(value));
+ }
+ get(
+ key,
+ ) {
+ try {
+ return JSON.parse(
+ localStorage.getItem(this.prefix + key) || "null",
+ );
+ } catch (_) {
+ }
+ }
+ delete(key) {
+ localStorage.removeItem(this.prefix + key);
+ }
+ clear() {
+ localStorage.clear();
+ }
+ migrate(storage) {
+ for (let index = 0; index < localStorage.length; index++) {
+ const k = localStorage.key(index);
+ if (k) {
+ storage.set(
+ k.replace(this.prefix, ""),
+ localStorage.getItem(k),
+ );
+ } else {
+ continue;
+ }
+ }
+ }
+ }
+ function log(message) {
+ const p = document.createElement("p");
+ p.innerText = message;
+ document.body.appendChild(p);
+ }
+ globalThis.LINEJS = LINEJS;
+ const client = new LINEJS.Client({ device: prompt("device?", "IOSIPAD"), storage: new LocalStorage(), endpoint: location.hostname });
+ client.fetch = window.fetch.bind(window);
+ client.on("log", (p) => console.log(p));
+ client.on("qrcall", (q) => {
+ const div = document.createElement("div");
+ div.innerText = "read qrcode: ";
+ const img = document.createElement("img");
+ img.src = \`https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=\${encodeURIComponent(q)}\`;
+ div.appendChild(img);
+ document.body.appendChild(div);
+ });
+ client.on("pincall", (pincode) => {
+ log(\`enter pincode: \${pincode}\`);
+ });
+ client.on("update:authtoken", (authToken) => {
+ localStorage.setItem("lastAuthToken", authToken);
+ });
+ client.on("ready", async (user) => {
+ log(\`Logged is as \${user.displayName} (\${user.mid})\`);
+ console.log(client);
+ });
+ const authToken = prompt("authToken", localStorage.getItem("lastAuthToken") || "");
+ if (authToken) {
+ client.login({ authToken });
+ } else {
+ const email = prompt("email", localStorage.getItem("lastEmail") || "");
+ if (email) {
+ localStorage.setItem("lastEmail", email);
+ const password = prompt("password", localStorage.getItem("lastPw") || "");
+ localStorage.setItem("lastPw", password);
+ client.login({ password, email });
+ } else {
+ client.login();
+ }
+ }
+ globalThis.client = client;
+`;
+ script.type = "module";
+ document.body.appendChild(script);
+})();
diff --git a/example/square/ping.ts b/example/square/ping.ts
new file mode 100644
index 00000000..93b6c146
--- /dev/null
+++ b/example/square/ping.ts
@@ -0,0 +1,24 @@
+import {
+ loginWithAuthToken,
+ loginWithPassword,
+ loginWithQR,
+} from "@evex/linejs";
+import { FileStorage } from "@evex/linejs/storage";
+
+const client = await loginWithPassword({
+ password: "",
+ email: "",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, { device: "DESKTOPWIN", storage: new FileStorage("./storage.json") });
+
+client.on("square:message", async (message) => {
+ console.log(message.text);
+ if (message.text === "!ping") {
+ await message.react("NICE");
+ await message.reply("pong!");
+ }
+});
+
+client.listen({ square: true });
diff --git a/example/square/square-chat.ts b/example/square/square-chat.ts
new file mode 100644
index 00000000..3194ca03
--- /dev/null
+++ b/example/square/square-chat.ts
@@ -0,0 +1,26 @@
+import {
+ loginWithAuthToken,
+ loginWithPassword,
+ loginWithQR,
+} from "@evex/linejs";
+import { FileStorage } from "@evex/linejs/storage";
+
+const client = await loginWithPassword({
+ password: "",
+ email: "",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, { device: "DESKTOPWIN", storage: new FileStorage("./storage.json") });
+
+const chat = await client.getSquareChat("m..."); // your squareChat mid
+
+chat.on("message", async (message) => {
+ console.log(message.text);
+ if (message.text === "!ping") {
+ await message.react("NICE");
+ await message.reply("pong!");
+ }
+});
+
+chat.listen();
diff --git a/example/storage/denokv.ts b/example/storage/denokv.ts
new file mode 100644
index 00000000..fdf99599
--- /dev/null
+++ b/example/storage/denokv.ts
@@ -0,0 +1,92 @@
+import type { BaseStorage } from "@evex/linejs/storage";
+
+import { type Kv, openKv } from "npm:@deno/kv";
+
+/**
+ * @classdesc Deno.Kv Storage for LINE Client
+ * @constructor
+ */
+export class DenoKvStorage implements BaseStorage {
+ useDeno = true;
+ kv?: Deno.Kv | Kv;
+ path?: string;
+ kvPrefix = "LINEJS_Storage";
+ constructor(path?: string) {
+ if (typeof globalThis.Deno === "undefined") {
+ this.useDeno = false;
+ } else if (typeof Deno.openKv === "undefined") {
+ console.warn(
+ "info: Deno.openKv() is an unstable API.\nhint: Run again with `--unstable-kv` flag to enable this API.",
+ );
+ this.useDeno = false;
+ }
+ this.path = path;
+ }
+ public async set(
+ key: string,
+ value: any,
+ ): Promise {
+ if (!this.kv) {
+ if (this.useDeno) {
+ this.kv = await Deno.openKv(this.path);
+ } else {
+ this.kv = await openKv(this.path);
+ }
+ }
+ await this.kv.set([this.kvPrefix, key], value);
+ }
+ public async get(
+ key: string,
+ ): Promise {
+ if (!this.kv) {
+ if (this.useDeno) {
+ this.kv = await Deno.openKv(this.path);
+ } else {
+ this.kv = await openKv(this.path);
+ }
+ }
+ return (await this.kv.get([this.kvPrefix, key])).value as any;
+ }
+ public async delete(key: string): Promise {
+ if (!this.kv) {
+ if (this.useDeno) {
+ this.kv = await Deno.openKv(this.path);
+ } else {
+ this.kv = await openKv(this.path);
+ }
+ }
+ await this.kv.delete([this.kvPrefix, key]);
+ }
+ public async clear(): Promise {
+ if (!this.kv) {
+ if (this.useDeno) {
+ this.kv = await Deno.openKv(this.path);
+ } else {
+ this.kv = await openKv(this.path);
+ }
+ }
+ const entries = this.kv.list({ prefix: [this.kvPrefix] });
+ for await (const entry of entries) {
+ await this.kv.delete(entry.key as any);
+ }
+ }
+ public async migrate(storage: BaseStorage): Promise {
+ if (!this.kv) {
+ if (this.useDeno) {
+ this.kv = await Deno.openKv(this.path);
+ } else {
+ this.kv = await openKv(this.path);
+ }
+ }
+ const entries = this.kv.list({ prefix: [this.kvPrefix] });
+ for await (const entry of entries) {
+ const key = (entry.key.at(1) || "").toString();
+ if (key) {
+ await storage.set(
+ key,
+ (await this.kv.get(entry.key as any)).value as any,
+ );
+ }
+ }
+ }
+}
diff --git a/example/storage/indexedDB.ts b/example/storage/indexedDB.ts
new file mode 100644
index 00000000..4285f49c
--- /dev/null
+++ b/example/storage/indexedDB.ts
@@ -0,0 +1,138 @@
+///
+
+import type { BaseStorage } from "@evex/linejs/storage";
+
+function successToPromise(
+ request: T,
+): Promise {
+ return new Promise((resolve, reject) => {
+ request.onsuccess = () => {
+ resolve(request.result);
+ };
+ request.onerror = (event) => {
+ reject(event);
+ };
+ });
+}
+function completeToPromise(
+ transaction: T,
+): Promise {
+ return new Promise((resolve, reject) => {
+ transaction.oncomplete = () => {
+ resolve();
+ };
+ transaction.onerror = (event) => {
+ reject(event);
+ };
+ });
+}
+
+export class IndexedDBStorage implements BaseStorage {
+ onclose?: () => void;
+ onblocked?: () => void;
+ dbName: string;
+ storeName: string;
+ #db?: IDBDatabase;
+ constructor(
+ dbName: string = "IndexedDBStorage",
+ storeName: string = "linejs",
+ ) {
+ this.dbName = dbName;
+ this.storeName = storeName;
+ }
+ addhandler(db: IDBDatabase) {
+ db.onversionchange = () => {
+ db.close();
+ this.onclose && this.onclose();
+ };
+ }
+ async open(): Promise {
+ if (!this.#db) {
+ const request = indexedDB.open(this.dbName);
+ request.onblocked = () => {
+ this.onblocked && this.onblocked();
+ };
+ request.onupgradeneeded = () => {
+ const db = request.result;
+
+ db.createObjectStore(this.storeName, { keyPath: "key" });
+ };
+ this.#db = await successToPromise(request);
+ this.addhandler(this.#db);
+ }
+ return this.#db;
+ }
+ public async set(
+ key: string,
+ value: any,
+ ): Promise {
+ const db = await this.open();
+ const transaction = db.transaction(this.storeName, "readwrite");
+ const success = successToPromise(
+ transaction.objectStore(this.storeName).put({ key, value }),
+ );
+ const complete = completeToPromise(transaction);
+ await success;
+ await complete;
+ }
+ public async get(
+ key: string,
+ ): Promise {
+ const db = await this.open();
+ const transaction = db.transaction(this.storeName);
+ const complete = completeToPromise(transaction);
+ const value = await successToPromise(
+ transaction.objectStore(this.storeName).get(key),
+ );
+ await complete;
+ return value && value.value;
+ }
+ public async delete(key: string): Promise {
+ const db = await this.open();
+ const transaction = db.transaction(this.storeName, "readwrite");
+ const success = successToPromise(
+ transaction.objectStore(this.storeName).delete(key),
+ );
+ const complete = completeToPromise(transaction);
+ await success;
+ await complete;
+ }
+ public async clear(): Promise {
+ const db = await this.open();
+ const version = db.version;
+ db.close();
+ const request = indexedDB.open(this.dbName, version + 1);
+ request.onblocked = () => {
+ this.onblocked && this.onblocked();
+ };
+ request.onupgradeneeded = () => {
+ const db = request.result;
+ db.deleteObjectStore(this.storeName);
+ db.createObjectStore(this.storeName, { keyPath: "key" });
+ };
+ this.#db = await successToPromise(request);
+ this.addhandler(this.#db);
+ }
+ public async migrate(storage: BaseStorage): Promise {
+ const db = await this.open();
+ const transaction = db.transaction(this.storeName, "readwrite");
+ const complete = completeToPromise(transaction);
+ const objectStore = transaction.objectStore(this.storeName);
+ const request = objectStore.openCursor();
+ const { promise, resolve } = Promise.withResolvers();
+ const promises: Promise[] = [];
+ request.onsuccess = () => {
+ const cursor = request.result;
+ if (cursor) {
+ const { value, key } = cursor.value;
+ promises.push(storage.set(key, value));
+ cursor.continue();
+ } else {
+ resolve();
+ }
+ };
+ await Promise.all(promises);
+ await promise;
+ await complete;
+ }
+}
diff --git a/example/storage/local.ts b/example/storage/local.ts
new file mode 100644
index 00000000..4d7698ce
--- /dev/null
+++ b/example/storage/local.ts
@@ -0,0 +1,43 @@
+///
+
+import type { BaseStorage, Storage } from "@evex/linejs/storage";
+export class LocalStorage implements BaseStorage {
+ prefix = "linejs:";
+ constructor() {
+ }
+ public async set(
+ key: Storage["Key"],
+ value: Storage["Value"],
+ ): Promise {
+ localStorage.setItem(this.prefix + key, JSON.stringify(value));
+ }
+ public async get(
+ key: Storage["Key"],
+ ): Promise {
+ try {
+ return JSON.parse(
+ localStorage.getItem(this.prefix + key) || "null",
+ );
+ } catch (_) {
+ }
+ }
+ public async delete(key: Storage["Key"]): Promise {
+ localStorage.removeItem(this.prefix + key);
+ }
+ public async clear(): Promise {
+ localStorage.clear();
+ }
+ public async migrate(storage: BaseStorage): Promise {
+ for (let index = 0; index < localStorage.length; index++) {
+ const k = localStorage.key(index);
+ if (k) {
+ await storage.set(
+ k.replace(this.prefix, ""),
+ localStorage.getItem(k),
+ );
+ } else {
+ continue;
+ }
+ }
+ }
+}
diff --git a/example/talk/all_methods.ts b/example/talk/all_methods.ts
new file mode 100644
index 00000000..925aa7d7
--- /dev/null
+++ b/example/talk/all_methods.ts
@@ -0,0 +1,693 @@
+import {
+ loginWithAuthToken,
+ loginWithPassword,
+ loginWithQR,
+} from "@evex/linejs";
+import { FileStorage } from "@evex/linejs/storage";
+import { Buffer } from "node:buffer";
+
+const client = await loginWithAuthToken(
+ "DUMMYTOKEN",
+ {
+ device: "DESKTOPWIN",
+ storage: new FileStorage("./storage.json"),
+ },
+);
+
+await client.base.talk.acceptChatInvitation({
+ request: {
+ reqSeq: await client.base.getReqseq(),
+ chatMid: "c...",
+ },
+});
+
+await client.base.talk.acceptChatInvitationByTicket({
+ request: {
+ reqSeq: await client.base.getReqseq(),
+ ticketId: "...",
+ chatMid: "c...",
+ },
+});
+
+await client.base.talk.acquireEncryptedAccessToken({
+ featureType: "OBS_GENERAL",
+});
+
+await client.base.talk.addToFollowBlacklist({
+ addToFollowBlacklistRequest: {
+ followMid: {
+ mid: "u...",
+ eMid: "...",
+ },
+ },
+});
+
+await client.base.talk.blockContact({
+ reqSeq: await client.base.getReqseq(),
+ id: "u...",
+});
+
+await client.base.talk.blockRecommendation({
+ reqSeq: await client.base.getReqseq(),
+ targetMid: "...",
+});
+
+await client.base.talk.bulkFollow({
+ bulkFollowRequest: {
+ followTargetMids: ["..."],
+ unfollowTargetMids: ["..."],
+ hasNext: false,
+ },
+});
+
+await client.base.talk.cancelChatInvitation({
+ request: {
+ reqSeq: await client.base.getReqseq(),
+ chatMid: "c...",
+ targetUserMids: ["u..."],
+ },
+});
+
+await client.base.talk.cancelReaction({
+ cancelReactionRequest: {
+ reqSeq: await client.base.getReqseq(),
+ messageId: 99999999999999,
+ },
+});
+
+await client.base.talk.changeVerificationMethod({
+ sessionId: "...",
+ method: "PIN_VIA_SMS",
+});
+
+await client.base.talk.clearRingtone({
+ oid: "...",
+});
+
+await client.base.talk.createChat({
+ request: {
+ reqSeq: await client.base.getReqseq(),
+ targetUserMids: ["u..."],
+ type: "GROUP",
+ name: "chat name",
+ /* picturePath: "/0h...", */
+ },
+});
+
+await client.base.talk.createChatRoomAnnouncement({
+ reqSeq: await client.base.getReqseq(),
+ chatRoomMid: "c...",
+ type: "MESSAGE",
+ contents: {
+ text: "text",
+ /* thumbnail: "https://img", */
+ link: "line://nv/home",
+ contentMetadata: {},
+ },
+});
+
+await client.base.talk.createSession({
+ request: {},
+});
+
+await client.base.talk.decryptFollowEMid({
+ eMid: "",
+});
+
+await client.base.talk.deleteOtherFromChat({
+ request: {
+ chatMid: "c...",
+ targetUserMids: ["u..."],
+ reqSeq: await client.base.getReqseq(),
+ },
+});
+
+await client.base.talk.deleteSelfFromChat({
+ request: { chatMid: "c...", reqSeq: await client.base.getReqseq() },
+});
+
+await client.base.talk.determineMediaMessageFlow({
+ request: {
+ chatMid: "c...",
+ },
+});
+
+await client.base.talk.fetchOperations({
+ request: {
+ offsetFrom: 999999,
+ deviceId: "...",
+ },
+});
+
+await client.base.talk.findChatByTicket({
+ request: {
+ ticketId: "...",
+ },
+});
+
+await client.base.talk.findContactByUserTicket({
+ ticketIdWithTag: "...",
+});
+
+await client.base.talk.findContactByUserid({
+ searchId: "...",
+});
+
+await client.base.talk.findContactsByPhone({
+ phones: ["..."],
+});
+
+await client.base.talk.finishUpdateVerification({
+ sessionId: "...",
+});
+
+await client.base.talk.follow({
+ followRequest: {
+ followMid: {
+ mid: "u...",
+ eMid: "...",
+ },
+ },
+});
+
+await client.base.talk.generateUserTicket({
+ expirationTime: 999999,
+ maxUseCount: 999999,
+});
+
+await client.base.talk.getAllChatMids({
+ syncReason: "INTERNAL",
+ request: {
+ withInvitedChats: true,
+ withMemberChats: true,
+ },
+});
+
+await client.base.talk.getAllContactIds({
+ syncReason: "INTERNAL",
+});
+
+await client.base.talk.getBlockedContactIds({
+ syncReason: "INTERNAL",
+});
+
+await client.base.talk.getBlockedRecommendationIds({
+ syncReason: "INTERNAL",
+});
+
+await client.base.talk.getChat({
+ chatMid: "c...",
+});
+
+await client.base.talk.getChatEffectMetaList({
+ categories: ["BACKGROUND", "CONTENT_METADATA_TAG_BASED", "KEYWORD"],
+});
+
+await client.base.talk.getChatRoomAnnouncements({
+ chatRoomMid: "c...",
+});
+
+await client.base.talk.getChatRoomAnnouncementsBulk({
+ chatRoomMids: ["c..."],
+});
+
+await client.base.talk.getChatRoomBGMs({
+ chatRoomMids: ["c..."],
+ syncReason: "INTERNAL",
+});
+
+await client.base.talk.getChats({
+ chatMids: ["c..."],
+});
+
+await client.base.talk.getConfigurations({
+ syncReason: "INTERNAL",
+ revision: 0,
+ carrier: "...",
+ regionOfLocale: "...",
+ regionOfTelephone: "...",
+ regionOfUsim: "...",
+});
+
+await client.base.talk.getContact({
+ mid: "u...",
+});
+
+await client.base.talk.getContacts({
+ mids: ["u..."],
+});
+
+await client.base.talk.getContactsV2({
+ mids: ["u..."],
+});
+
+await client.base.talk.getCountries({
+ countryGroup: "UNKNOWN",
+});
+
+await client.base.talk.getE2EEGroupSharedKey({
+ chatMid: "c...",
+ keyVersion: 0,
+ groupKeyId: 9999,
+});
+
+await client.base.talk.getE2EEPublicKey({
+ keyId: 9999,
+ keyVersion: 0,
+});
+
+await client.base.talk.getE2EEPublicKeys();
+
+await client.base.talk.getExtendedProfile({
+ syncReason: "INTERNAL",
+});
+
+await client.base.talk.getFollowBlacklist({
+ getFollowBlacklistRequest: { cursor: "..." },
+});
+
+await client.base.talk.getFollowers({
+ getFollowersRequest: {
+ followMid: { mid: "u...", eMid: "..." },
+ cursor: "...",
+ },
+});
+
+await client.base.talk.getFollowings({
+ getFollowingsRequest: {
+ followMid: { mid: "u...", eMid: "..." },
+ cursor: "...",
+ },
+});
+
+await client.base.talk.getFriendRequests({
+ lastSeenSeqId: 0,
+ direction: "INCOMING",
+});
+
+await client.base.talk.getInstantNews({
+ region: "...",
+ location: {
+ latitude: 0,
+ longitude: 0,
+ },
+});
+
+await client.base.talk.getLastE2EEGroupSharedKey({
+ keyVersion: 0,
+ chatMid: "c...",
+});
+
+await client.base.talk.getLastE2EEPublicKeys({
+ chatMid: "c...",
+});
+
+await client.base.talk.getMessageBoxes({
+ messageBoxListRequest: {
+ maxChatId: "c...",
+ minChatId: "c...",
+ activeOnly: true,
+ lastMessagesPerMessageBoxCount: 1,
+ messageBoxCountLimit: 100,
+ unreadOnly: true,
+ withUnreadCount: true,
+ },
+});
+
+await client.base.talk.getMessageReadRange({
+ chatIds: ["u...", "c..."],
+ syncReason: "INTERNAL",
+});
+
+await client.base.talk.getNotificationSettings({
+ request: {
+ syncReason: "INTERNAL",
+ chatMids: ["u...", "c..."],
+ },
+});
+
+await client.base.talk.getPreviousMessagesV2WithRequest({
+ request: {
+ endMessageId: {
+ deliveredTime: 9999,
+ messageId: 9999,
+ },
+ },
+});
+
+await client.base.talk.getProfile();
+
+await client.base.talk.getRecentFriendRequests();
+
+await client.base.talk.getRecommendationIds();
+
+await client.base.talk.getRepairElements({
+ request: {
+ profile: true,
+ settings: true,
+ configurations: {
+ carrier: "...",
+ regionOfLocale: "...",
+ regionOfTelephone: "...",
+ regionOfUsim: "...",
+ },
+ numLocalJoinedGroups: 0,
+ numLocalInvitedGroups: 0,
+ numLocalFriends: 0,
+ numLocalRecommendations: 0,
+ numLocalBlockedFriends: 0,
+ numLocalBlockedRecommendations: 0,
+ localGroupMembers: {
+ "str": { invalidGroup: true, numMembers: 0 },
+ },
+ syncReason: "INTERNAL",
+ localProfileMappings: { "str": 0 },
+ },
+});
+
+await client.base.talk.getServerTime();
+
+await client.base.talk.getSettings();
+
+await client.base.talk.getSettingsAttributes2({
+ attributesToRetrieve: [
+ "AGREEMENT_MID",
+ ],
+});
+
+await client.base.talk.inviteIntoChat({
+ chatMid: "c...",
+ targetUserMids: ["u..."],
+});
+
+await client.base.talk.isUseridAvailable({
+ searchId: "...",
+});
+
+await client.base.talk.negotiateE2EEPublicKey({
+ mid: "u...",
+});
+
+await client.base.talk.notifyInstalled({
+ applicationTypeWithExtensions: "...",
+ udidHash: "...",
+});
+
+await client.base.talk.notifyRegistrationComplete({
+ applicationTypeWithExtensions: "...",
+ udidHash: "...",
+});
+
+await client.base.talk.notifyUpdated({
+ deviceInfo: {
+ applicationType: "ANDROID",
+ carrierCode: "JP_AU",
+ carrierName: "...",
+ deviceName: "...",
+ model: "...",
+ systemName: "...",
+ systemVersion: "...",
+ webViewVersion: "...",
+ },
+});
+
+await client.base.talk.react({
+ id: BigInt("0"),
+ reaction: "NICE",
+});
+
+await client.base.talk.registerE2EEGroupKey({
+ chatMid: "c...",
+ encryptedSharedKeys: [new Buffer([])],
+ keyIds: [0],
+ keyVersion: 0,
+ members: ["..."],
+});
+
+await client.base.talk.registerE2EEPublicKey(
+ {
+ reqSeq: await client.base.getReqseq(),
+ publicKey: {
+ createdTime: 0,
+ keyData: "...",
+ keyId: 0,
+ version: 0,
+ },
+ },
+);
+
+await client.base.talk.registerUserid({
+ reqSeq: await client.base.getReqseq(),
+ searchId: "...",
+});
+
+await client.base.talk.reissueChatTicket({
+ request: {
+ groupMid: "c...",
+ reqSeq: await client.base.getReqseq(),
+ },
+});
+
+await client.base.talk.rejectChatInvitation({
+ request: {
+ chatMid: "c...",
+ reqSeq: await client.base.getReqseq(),
+ },
+});
+
+await client.base.talk.removeChatRoomAnnouncement({
+ announcementSeq: 0,
+ chatRoomMid: "c...",
+ reqSeq: await client.base.getReqseq(),
+});
+
+await client.base.talk.removeFollower({
+ removeFollowerRequest: {
+ followMid: {
+ eMid: "...",
+ mid: "u...",
+ },
+ },
+});
+
+await client.base.talk.removeFriendRequest({
+ direction: "INCOMING",
+ midOrEMid: "...",
+});
+
+await client.base.talk.removeFromFollowBlacklist({
+ removeFromFollowBlacklistRequest: {
+ followMid: {
+ eMid: "...",
+ mid: "u...",
+ },
+ },
+});
+
+await client.base.talk.reportAbuseEx({
+ request: {
+ abuseReportEntry: {
+ lineMeeting: {
+ chatMid: "c...",
+ evidenceIds: [{
+ objectId: "...",
+ spaceId: "...",
+ }],
+ },
+ },
+ },
+});
+
+await client.base.talk.reportDeviceState({
+ booleanState: { 0: true },
+ stringState: { 0: "..." },
+});
+
+await client.base.talk.reportPushRecvReports({
+ reqSeq: await client.base.getReqseq(),
+ pushRecvReports: [
+ {
+ battery: 0,
+ batteryMode: "LOW_BATTERY",
+ carrierCode: "...",
+ clientNetworkType: "WIFI",
+ displayTimestamp: 0,
+ pushTrackingId: "...",
+ recvTimestamp: 0,
+ },
+ ],
+});
+
+await client.base.talk.reportSettings({
+ settings: {},
+ syncOpRevision: 0,
+});
+
+await client.base.talk.resendPinCode({
+ sessionId: "...",
+});
+
+await client.base.talk.sendChatChecked({
+ chatMid: "c...",
+ lastMessageId: "0",
+ seq: 0,
+ sessionId: 0,
+});
+
+await client.base.talk.sendChatRemoved({
+ chatMid: "c...",
+ lastMessageId: "0",
+ seq: 0,
+ sessionId: 0,
+});
+
+await client.base.talk.sendMessage({
+ to: "u...",
+ text: "...",
+ contentType: "NONE",
+ e2ee: true,
+});
+
+await client.base.talk.sendPostback({
+ request: {
+ chatMID: "...",
+ messageId: "0",
+ originMID: "...",
+ url: "...",
+ },
+});
+
+await client.base.talk.setChatHiddenStatus({
+ setChatHiddenStatusRequest: {
+ chatMid: "c...",
+ hidden: true,
+ lastMessageId: 0,
+ reqSeq: await client.base.getReqseq(),
+ },
+});
+
+await client.base.talk.setNotificationsEnabled({
+ enablement: true,
+ reqSeq: await client.base.getReqseq(),
+ target: "c...",
+ type: "USER",
+});
+
+await client.base.talk.sync({
+ limit: 100,
+ globalRev: 0,
+ individualRev: 0,
+ revision: 0,
+ timeout: 30_000,
+});
+
+await client.base.talk.syncContacts({
+ localContacts: [{
+ emails: ["..."],
+ luid: "...",
+ mobileContactName: "...",
+ phones: ["..."],
+ phoneticName: "...",
+ type: "MODIFY",
+ userids: ["..."],
+ }],
+});
+
+await client.base.talk.tryFriendRequest({
+ friendRequestParams: "...",
+ method: "NEARBY",
+ midOrEMid: "...",
+});
+
+await client.base.talk.unblockContact({
+ id: "...",
+ reference: "...",
+ reqSeq: await client.base.getReqseq(),
+});
+
+await client.base.talk.unblockRecommendation({
+ reqSeq: await client.base.getReqseq(),
+ targetMid: "...",
+});
+
+await client.base.talk.unfollow({
+ unfollowRequest: {
+ followMid: {
+ mid: "u...",
+ eMid: "...",
+ },
+ },
+});
+
+await client.base.talk.unsendMessage({
+ messageId: "...",
+ seq: 0,
+});
+
+await client.base.talk.updateChat({
+ request: {
+ reqSeq: await client.base.getReqseq(),
+ chat: {
+ /* struct Chat */
+ chatMid: "c...",
+ chatName: "test",
+ },
+ updatedAttribute: "NAME",
+ },
+});
+
+await client.base.talk.updateChatRoomBGM({
+ chatRoomBGMInfo: "...",
+ chatRoomMid: "c...",
+});
+
+await client.base.talk.updateContactSetting({
+ flag: "CONTACT_SETTING_DISPLAY_NAME_OVERRIDE",
+ mid: "u...",
+ reqSeq: await client.base.getReqseq(),
+ value: "...",
+});
+
+await client.base.talk.updateNotificationToken({
+ token: "...",
+ type: "LINE_BOT",
+});
+
+await client.base.talk.updateProfileAttributes({
+ reqSeq: await client.base.getReqseq(),
+ request: {
+ profileAttributes: {
+ 0: {
+ meta: {
+ "...": "...",
+ },
+ value: "...",
+ },
+ },
+ },
+});
+
+await client.base.talk.updateSettingsAttributes2({
+ attributesToUpdate: ["AGREEMENT_SQUARE"],
+ reqSeq: await client.base.getReqseq(),
+ settings: {
+ agreementSquareTime: 1,
+ },
+});
+
+await client.base.talk.verifyPhoneNumber({
+ migrationPincodeSessionId: "...",
+ oldUdidHash: "...",
+ pinCode: "...",
+ sessionId: "...",
+ udidHash: "...",
+});
+
+await client.base.talk.verifyQrcode({
+ pinCode: "...",
+ verifier: "...",
+});
+
+await client.base.talk.wakeUpLongPolling({
+ clientRevision: 0,
+});
diff --git a/example/talk/ping.ts b/example/talk/ping.ts
new file mode 100644
index 00000000..84725b70
--- /dev/null
+++ b/example/talk/ping.ts
@@ -0,0 +1,27 @@
+import {
+ loginWithAuthToken,
+ loginWithPassword,
+ loginWithQR,
+} from "@evex/linejs";
+import { FileStorage } from "@evex/linejs/storage";
+
+const client = await loginWithPassword({
+ email: "",
+ password: "",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, {
+ device: "DESKTOPWIN",
+ storage: new FileStorage("./storage.json"),
+});
+
+client.on("message", async (message) => {
+ console.log(message.text);
+ if (message.text === "!ping") {
+ await message.react("NICE");
+ await message.reply("pong!");
+ }
+});
+
+client.listen({ talk: true });
diff --git a/example/thrift/decoder.ts b/example/thrift/decoder.ts
new file mode 100644
index 00000000..ae15ac94
--- /dev/null
+++ b/example/thrift/decoder.ts
@@ -0,0 +1,13 @@
+import { Thrift } from "@evex/linejs/thrift";
+import { Buffer } from "node:buffer";
+
+// @ts-types="thrift-types"
+import * as thrift from "thrift";
+
+const thriftClient = new Thrift();
+console.log(
+ thriftClient.readThrift(
+ Deno.readFileSync("./http-body.bin"),
+ thrift.TCompactProtocol,
+ ),
+);
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index b44f39db..00000000
--- a/examples/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Please send PullRequest!
diff --git a/examples/deno.json b/examples/deno.json
deleted file mode 100644
index 42259a52..00000000
--- a/examples/deno.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "imports": { "@evex/linejs": "jsr:@evex/linejs@^1.2.2" }
-}
diff --git a/examples/deno.lock b/examples/deno.lock
deleted file mode 100644
index 9d23e06a..00000000
--- a/examples/deno.lock
+++ /dev/null
@@ -1,86 +0,0 @@
-{
- "version": "3",
- "packages": {
- "specifiers": {
- "jsr:@evex/linejs@^1.2.2": "jsr:@evex/linejs@1.2.2",
- "npm:@types/node": "npm:@types/node@18.16.19",
- "npm:curve25519-js@^0.0.4": "npm:curve25519-js@0.0.4",
- "npm:node-bignumber@^1.2.2": "npm:node-bignumber@1.2.2",
- "npm:thrift@^0.20.0": "npm:thrift@0.20.0_ws@5.2.4",
- "npm:tweetnacl@^1.0.3": "npm:tweetnacl@1.0.3"
- },
- "jsr": {
- "@evex/linejs@1.2.2": {
- "integrity": "81eef129bafd7a46539b156462b16d702be425dc69b9bf4af30df465f89f796b",
- "dependencies": [
- "npm:curve25519-js@^0.0.4",
- "npm:node-bignumber@^1.2.2",
- "npm:thrift@^0.20.0",
- "npm:tweetnacl@^1.0.3"
- ]
- }
- },
- "npm": {
- "@types/node@18.16.19": {
- "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==",
- "dependencies": {}
- },
- "async-limiter@1.0.1": {
- "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
- "dependencies": {}
- },
- "browser-or-node@1.3.0": {
- "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==",
- "dependencies": {}
- },
- "curve25519-js@0.0.4": {
- "integrity": "sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==",
- "dependencies": {}
- },
- "isomorphic-ws@4.0.1_ws@5.2.4": {
- "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
- "dependencies": {
- "ws": "ws@5.2.4"
- }
- },
- "node-bignumber@1.2.2": {
- "integrity": "sha512-VoTZHmdFQpZH1+q1dz2qcHNCwTWsJg2T3PYwlAyDNFOfVhSYUKQBLFcCpCud+wJBGgCttGavZILaIggDIKqEQQ==",
- "dependencies": {}
- },
- "node-int64@0.4.0": {
- "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
- "dependencies": {}
- },
- "q@1.5.1": {
- "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
- "dependencies": {}
- },
- "thrift@0.20.0_ws@5.2.4": {
- "integrity": "sha512-oSmJTaoIAGolpupVHFfsWcmdEKX81fcDI6ty0hhezzdgZvp0XyXgMe9+1YusI8Ahy0HK4n8jlNrkPjOPeHZjdQ==",
- "dependencies": {
- "browser-or-node": "browser-or-node@1.3.0",
- "isomorphic-ws": "isomorphic-ws@4.0.1_ws@5.2.4",
- "node-int64": "node-int64@0.4.0",
- "q": "q@1.5.1",
- "ws": "ws@5.2.4"
- }
- },
- "tweetnacl@1.0.3": {
- "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
- "dependencies": {}
- },
- "ws@5.2.4": {
- "integrity": "sha512-fFCejsuC8f9kOSu9FYaOw8CdO68O3h5v0lg4p74o8JqWpwTf9tniOD+nOB78aWoVSS6WptVUmDrp/KPsMVBWFQ==",
- "dependencies": {
- "async-limiter": "async-limiter@1.0.1"
- }
- }
- }
- },
- "remote": {},
- "workspace": {
- "dependencies": [
- "jsr:@evex/linejs@^1.2.2"
- ]
- }
-}
diff --git a/examples/get-author.ts b/examples/get-author.ts
deleted file mode 100644
index c91b704a..00000000
--- a/examples/get-author.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-client.on("square:message", async (message) => {
- const text = message.content;
-
- if (text === "!me") {
- await message.reply([
- `Name: ${await message.author.displayName}`, // -> Promise
- `IconImage: ${message.author.iconImage}`,
- `Mid: ${message.author.mid}`,
- ].join("\n"));
- }
-});
-
-client.on("message", async (message) => {
- const text = message.content;
-
- if (text === "!me") {
- await message.reply([
- `Name: ${await message.author.displayName}`, // -> Promise
- `IconImage: ${message.author.iconImage}`,
- `Mid: ${message.author.mid}`,
- ].join("\n"));
- }
-});
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
-});
diff --git a/examples/ping.ts b/examples/ping.ts
deleted file mode 100644
index 82cf596d..00000000
--- a/examples/ping.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-client.on("message", async (message) => {
- const text = message.content;
-
- if (text === "!ping") {
- await message.reply("pong!");
- }
-});
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
- polling: ["talk"], // polling talk only
-});
diff --git a/examples/send-img.ts b/examples/send-img.ts
deleted file mode 100644
index e10e9ff3..00000000
--- a/examples/send-img.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
- polling: [], // no polling
-});
-
-await client.uploadObjTalk(
- to,
- "image", // content type
- await fetch("https://avatars.githubusercontent.com/u/121654029").then(r => r.blob()), // blob
- "i.png" // file name
-)
-/*
-Please make sure you set the mimeType to blob or the filename to the correct extension!
-*/
\ No newline at end of file
diff --git a/examples/simple-send.ts b/examples/simple-send.ts
deleted file mode 100644
index ed5fbb5b..00000000
--- a/examples/simple-send.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
- polling: [], // no polling
-});
-
-await client.sendMessage({
- to: "MID", // mid (group c~ ,user u~)
- text: "Hello, world!",
-});
diff --git a/examples/square-ping.ts b/examples/square-ping.ts
deleted file mode 100644
index ac3e491f..00000000
--- a/examples/square-ping.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-client.on("square:message", async (message) => {
- const text = message.content;
-
- if (text === "!ping") {
- await message.reply("pong!");
- }
-});
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
- polling: ["square"], // polling square only
-});
diff --git a/examples/square-simple-send.ts b/examples/square-simple-send.ts
deleted file mode 100644
index 4b68f70c..00000000
--- a/examples/square-simple-send.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Client } from "@evex/linejs";
-
-const client = new Client();
-
-await client.login({
- email: "YOUR_EMAIL",
- password: "YOUR_PASSWORD",
- polling: [], // no polling
-});
-
-await client.sendSquareMessage({
- to: "MID", // mid (squareChat m~)
- text: "Hello, world!",
-});
diff --git a/migrate_to_v2.md b/migrate_to_v2.md
new file mode 100644
index 00000000..a703b5f5
--- /dev/null
+++ b/migrate_to_v2.md
@@ -0,0 +1,80 @@
+## What's changed
+
+### Client
+
+#### old
+
+```js
+const client = new Client({ storage: ~ });
+
+client.storage.set("time", Date.now())
+
+client.registerCert(
+ "ffffff...",
+);
+
+client.on("pincall", (p) => console.log(p));
+
+client.on("qrcall", (q) => console.log(q));
+
+client.on("update:authtoken", (a) => console.log("AuthToken:", a));
+
+client.on("ready", async (user) => {
+ console.log(`Logged in as ${user.displayName} (${user.mid})`);
+
+ await client.sendMessage({ to: "u...", text: "Hello, World!" });
+
+ await client.sendSquareMessage({ squareChatMid: "m...", text: "Hello, World!" });
+});
+
+
+// login with email
+await client.login({
+ device: "DESKTOPWIN",
+ email: "linejs@evex.dev",
+ password: "password",
+ polling: ["talk","square"],
+ v3: true,
+ pincode: "123456",
+});
+
+// login with qrcode
+await client.login({
+ device: "DESKTOPWIN",
+ polling: ["talk","square"],
+ v3: true,
+ qr: true,
+});
+
+// login with authToken
+await client.login({
+ device: "DESKTOPWIN",
+ polling: ["talk","square"],
+ authToken: ...,
+});
+```
+
+#### new
+
+```js
+import {
+ loginWithAuthToken,
+ loginWithPassword,
+ loginWithQR,
+} from "@evex/linejs";
+
+// login with email
+const client = await loginWithPassword({
+ email: "linejs@evex.dev",
+ password: "password",
+ onPincodeRequest(pin) {
+ console.log(pin);
+ },
+}, { device: "DESKTOPWIN", storage: ~ });
+
+await client.base.storage.set("time", Date.now());
+
+await client.talk.sendMessage({ to: "u...", text: "Hello, World!" });
+
+await client.square.sendMessage({ squareChatMid: "m...", text: "Hello, World!" });
+```
diff --git a/packages/linejs/README.md b/packages/linejs/README.md
index b82a2c8d..6dca7713 100644
--- a/packages/linejs/README.md
+++ b/packages/linejs/README.md
@@ -36,6 +36,8 @@ deno add @evex/linejs
For now, please use "https://esm.sh/jsr/@evex/linejs".
+Example is [here](./example/browser).
+
## LINEJS Types
Please see [@evex/linejs-types](https://jsr.io/@evex/linejs-types).\
@@ -46,18 +48,14 @@ MessageType, etc.) are provided.
- client - (@evex/linejs) or (@evex/linejs/client)
- Client - LINE SelfBot Client
-- utils - (@evex/linejs/utils)
- - LINE_SCHEME - LINE Scheme utility
- - LINE_OBS - LINE OBS utility
- - LINE_REGEX - LINE URI Regex utility
- - LINE_FUNCTIONS - LINE Function utility (search openchat, ticket to emid,
- etc...)
+- base - (@evex/linejs/base)
+ - BaseClient - LINE SelfBot API Client
+- thrift - (@evex/linejs/thrift)
+ - Thrift - Thrift read/write
- storage - (@evex/linejs/storage)
- BaseStorage - LINE Client Base Storage
- MemoryStorage - LINE Client Memory Storage
- FileStorage - LINE Client File Storage
-- rate-limit - (@evex/linejs/rate-limit)
- - RateLimitter - RateLimit for Safety
- types - (@evex/linejs-types)
- All Types for LINE
@@ -67,3 +65,13 @@ MessageType, etc.) are provided.
- Developer: [EdamAme-x](https://github.com/EdamAme-x)
- Developer: [MocA-Love](https://github.com/MocA-Love)
- Developer: [Hafusun](https://github.com/hafusun)
+
+## References
+
+- [DeachSword/CHRLINE](https://github.com/DeachSword/CHRLINE)
+
+- [DeachSword/CHRLINE-Thrift](https://github.com/DeachSword/CHRLINE-Thrift/)
+
+- [WEDeach/CHRLINE-Patch](https://github.com/WEDeach/CHRLINE-Patch)
+
+- [discordjs/collection](https://www.npmjs.com/package/@discordjs/collection)
diff --git a/packages/linejs/base/core/mod.ts b/packages/linejs/base/core/mod.ts
new file mode 100644
index 00000000..7e8c1e96
--- /dev/null
+++ b/packages/linejs/base/core/mod.ts
@@ -0,0 +1,233 @@
+import {
+ type Device,
+ type DeviceDetails,
+ getDeviceDetails,
+} from "./utils/devices.ts";
+
+import { type BaseStorage, MemoryStorage } from "../storage/mod.ts";
+
+import { TypedEventEmitter } from "./typed-event-emitter/index.ts";
+
+import type { ClientEvents, Log } from "./utils/events.ts";
+import { InternalError } from "./utils/error.ts";
+import { type Continuable, continueRequest } from "./utils/continue.ts";
+
+export type { Continuable, Device, DeviceDetails, Log };
+export { continueRequest, InternalError };
+
+import {
+ AuthService,
+ CallService,
+ ChannelService,
+ LiffService,
+ RelationService,
+ SquareLiveTalkService,
+ SquareService,
+ TalkService,
+} from "../service/mod.ts";
+
+import { Login } from "../login/mod.ts";
+import { Thrift } from "../thrift/mod.ts";
+import { RequestClient } from "../request/mod.ts";
+import { E2EE } from "../e2ee/mod.ts";
+import { LineObs } from "../obs/mod.ts";
+import { Timeline } from "../timeline/mod.ts";
+import { Polling } from "../polling/mod.ts";
+
+import { Thrift as def } from "@evex/linejs-types/thrift";
+import type * as LINETypes from "@evex/linejs-types";
+import type { Fetch, FetchLike } from "../types.ts";
+
+export interface LoginOption {
+ email?: string;
+ password?: string;
+ pincode?: string;
+ authToken?: string;
+ qr?: boolean;
+ e2ee?: boolean;
+ v3?: boolean;
+}
+
+export interface ClientInit {
+ /**
+ * version which LINE App to emurating
+ */
+ version?: string;
+
+ /**
+ * API Endpoint
+ * @default "legy.line-apps.com"
+ */
+ endpoint?: string;
+
+ /**
+ * Device
+ */
+ device: Device;
+
+ /**
+ * Storage
+ * @default MemoryStorage
+ */
+ storage?: BaseStorage;
+
+ /**
+ * Custom function to connect network.
+ * @default `globalThis.fetch`
+ */
+ fetch?: FetchLike;
+}
+
+export interface Config {
+ /**
+ * Timeout
+ * @default 30_000
+ */
+ timeout: number;
+
+ /**
+ * Long timeout
+ * @default 180_000
+ */
+ longTimeout: number;
+}
+
+/**
+ * LINE.js client, which is entry point.
+ */
+export class BaseClient extends TypedEventEmitter {
+ authToken?: string;
+ readonly device: Device;
+ readonly loginProcess: Login;
+ readonly thrift: Thrift;
+ readonly request: RequestClient;
+ readonly storage: BaseStorage;
+ readonly e2ee: E2EE;
+ readonly obs: LineObs;
+ readonly timeline: Timeline;
+
+ readonly auth: AuthService;
+ readonly call: CallService;
+ readonly channel: ChannelService;
+ readonly liff: LiffService;
+ readonly relation: RelationService;
+ readonly livetalk: SquareLiveTalkService;
+ readonly square: SquareService;
+ readonly talk: TalkService;
+ #customFetch?: FetchLike;
+ profile?: LINETypes.Profile;
+ config: Config;
+ readonly deviceDetails: DeviceDetails;
+ readonly endpoint: string;
+ /**
+ * Initializes a new instance of the class.
+ *
+ * @param init - The initialization parameters.
+ * @param init.device - The device type.
+ * @param init.version - The version of the device.
+ * @param init.fetch - Optional custom fetch function.
+ * @param init.endpoint - Optional endpoint URL.
+ * @param init.storage - Optional storage mechanism.
+ *
+ * @throws {Error} If the device is unsupported.
+ *
+ * @example
+ * ```typescript
+ * const client = new Client({
+ * device: 'iOS',
+ * version: '10.0',
+ * fetch: customFetchFunction,
+ * endpoint: 'custom-endpoint.com',
+ * storage: new FileStorage("./storage.json"),
+ * });
+ * ```
+ */
+ constructor(init: ClientInit) {
+ super();
+ const deviceDetails = getDeviceDetails(init.device, init.version);
+ if (!deviceDetails) {
+ throw new Error(`Unsupported device: ${init.device}.`);
+ }
+ if (init.fetch) {
+ this.#customFetch = init.fetch;
+ }
+ this.deviceDetails = deviceDetails;
+ this.endpoint = init.endpoint ?? "legy.line-apps.com";
+ this.config = {
+ timeout: 30_000,
+ longTimeout: 180_000,
+ };
+ this.device = init.device;
+
+ this.storage = init.storage ?? new MemoryStorage();
+ this.request = new RequestClient(this);
+ this.loginProcess = new Login(this);
+ this.thrift = new Thrift();
+ this.thrift.def = def;
+ this.e2ee = new E2EE(this);
+ this.obs = new LineObs(this);
+ this.timeline = new Timeline(this);
+
+ this.auth = new AuthService(this);
+ this.call = new CallService(this);
+ this.channel = new ChannelService(this);
+ this.liff = new LiffService(this);
+ this.livetalk = new SquareLiveTalkService(this);
+ this.relation = new RelationService(this);
+ this.square = new SquareService(this);
+ this.talk = new TalkService(this);
+ }
+
+ log(type: string, data: Record) {
+ this.emit("log", { type, data });
+ }
+ getToType(mid: string): number | null {
+ const typeMapping: { [key: string]: number } = {
+ u: 0,
+ r: 1,
+ c: 2,
+ s: 3,
+ m: 4,
+ p: 5,
+ v: 6,
+ t: 7,
+ };
+ return typeMapping[mid[0]] ?? null;
+ }
+ reqseqs?: Record;
+ async getReqseq(name: string = "talk"): Promise {
+ if (!this.reqseqs) {
+ this.reqseqs = JSON.parse(
+ ((await this.storage.get("reqseq")) ?? "{}").toString(),
+ ) as Record;
+ }
+ if (!this.reqseqs[name]) {
+ this.reqseqs[name] = 0;
+ }
+ const seq = this.reqseqs[name];
+ this.reqseqs[name]++;
+ await this.storage.set("reqseq", JSON.stringify(this.reqseqs));
+ return seq;
+ }
+
+ // NOTE: use allow function.
+ // `const { fetch } = base` is not working if you change to function decorations.
+ readonly fetch: Fetch = async (
+ info: RequestInfo | URL,
+ init?: RequestInit,
+ ): Promise => {
+ const req = new Request(info, init);
+ const res =
+ await (this.#customFetch
+ ? this.#customFetch(req)
+ : globalThis.fetch(req));
+ return res;
+ };
+
+ /**
+ * Creates polling client.
+ */
+ createPolling(): Polling {
+ return new Polling(this);
+ }
+}
diff --git a/packages/linejs/client/libs/typed-event-emitter/index.test.ts b/packages/linejs/base/core/typed-event-emitter/index.test.ts
similarity index 85%
rename from packages/linejs/client/libs/typed-event-emitter/index.test.ts
rename to packages/linejs/base/core/typed-event-emitter/index.test.ts
index 4cc061a8..a2759a5d 100644
--- a/packages/linejs/client/libs/typed-event-emitter/index.test.ts
+++ b/packages/linejs/base/core/typed-event-emitter/index.test.ts
@@ -5,7 +5,7 @@ Deno.test("promise() should be vaild", async () => {
type Events = {
example: (v: number) => void;
};
- class Client extends TypedEventEmitter {}
+ class Client extends TypedEventEmitter {}
const client = new Client();
const promise = client.waitFor("example");
diff --git a/packages/linejs/client/libs/typed-event-emitter/index.ts b/packages/linejs/base/core/typed-event-emitter/index.ts
similarity index 86%
rename from packages/linejs/client/libs/typed-event-emitter/index.ts
rename to packages/linejs/base/core/typed-event-emitter/index.ts
index 722150c0..200ac274 100644
--- a/packages/linejs/client/libs/typed-event-emitter/index.ts
+++ b/packages/linejs/base/core/typed-event-emitter/index.ts
@@ -1,6 +1,4 @@
-import type { LooseType } from "../../entities/common.ts";
-
-type RecordEvent = Record LooseType>;
+type RecordEvent = Record any>;
export class TypedEventEmitter<
T extends RecordEvent,
@@ -27,7 +25,10 @@ export class TypedEventEmitter<
this.listeners
.get(event)
- ?.splice(this.listeners.get(event)?.indexOf(listener) ?? 0, 1);
+ ?.splice(
+ this.listeners.get(event)?.indexOf(listener) ?? 0,
+ 1,
+ );
}
}
diff --git a/packages/linejs/base/core/utils/continue.ts b/packages/linejs/base/core/utils/continue.ts
new file mode 100644
index 00000000..6846c67d
--- /dev/null
+++ b/packages/linejs/base/core/utils/continue.ts
@@ -0,0 +1,50 @@
+export type Continuable = { continuationToken?: string; [k: string]: any };
+
+export async function continueRequest<
+ P extends Continuable,
+ R extends Continuable,
+ H extends (param: P) => Promise,
+>(options: {
+ handler: H;
+ arg: P;
+}): Promise> {
+ function objectSum(base: O, add: O): O {
+ for (const key in add) {
+ if (Object.prototype.hasOwnProperty.call(add, key)) {
+ const value = add[key];
+ if (typeof value === "object") {
+ if (!base[key]) {
+ base[key] = value;
+ } else {
+ if (Array.isArray(value)) {
+ (base[key] as any) = [
+ ...value,
+ ...base[key] as any,
+ ] as any;
+ } else {
+ base[key] = objectSum(base[key], value);
+ }
+ }
+ } else {
+ base[key] = value;
+ }
+ }
+ }
+ return base;
+ }
+ let responseSum: R | undefined;
+ let continuationToken: string | undefined;
+ while (true) {
+ options.arg.continuationToken = continuationToken;
+ const _response = await options.handler(options.arg);
+ if (!responseSum) {
+ responseSum = _response;
+ } else {
+ objectSum(responseSum, _response);
+ }
+ if (!_response.continuationToken) {
+ return responseSum as any;
+ }
+ continuationToken = _response.continuationToken;
+ }
+}
diff --git a/packages/linejs/client/entities/device.ts b/packages/linejs/base/core/utils/devices.ts
similarity index 50%
rename from packages/linejs/client/entities/device.ts
rename to packages/linejs/base/core/utils/devices.ts
index d4f62427..154a1a26 100644
--- a/packages/linejs/client/entities/device.ts
+++ b/packages/linejs/base/core/utils/devices.ts
@@ -1,7 +1,7 @@
export type Device =
| "DESKTOPWIN"
| "DESKTOPMAC"
- // | "CHROMEOS"
+ //| "CHROMEOS"
| "ANDROID"
| "IOS"
| "IOSIPAD"
@@ -9,16 +9,19 @@ export type Device =
| "WEAROS";
export interface DeviceDetails {
+ device: Device;
appVersion: string;
systemName: string;
systemVersion: string;
}
-
-export type DeviceMap = Partial>;
-
+export function isV3Support(
+ device: Device,
+): device is "DESKTOPWIN" | "DESKTOPMAC" {
+ return ["DESKTOPWIN", "DESKTOPMAC"].includes(device);
+}
export function getDeviceDetails(
device: Device,
- deviceMap: DeviceMap,
+ version?: string,
): DeviceDetails | null {
let appVersion;
let systemName;
@@ -27,68 +30,44 @@ export function getDeviceDetails(
switch (device) {
case "DESKTOPWIN":
- appVersion = "9.2.0.3403";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = version || "9.2.0.3403";
systemName = "WINDOWS";
systemVersion = "10.0.0-NT-x64";
break;
case "DESKTOPMAC":
- appVersion = "9.2.0.3402";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = version || "9.2.0.3402";
systemName = "MAC";
break;
/*
case "CHROMEOS":
- appVersion = "3.0.3";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = appVersion = deviceMap[device]||"3.0.3";
systemName = "Chrome_OS";
systemVersion = "1";
break;
*/
case "ANDROID":
- appVersion = "13.4.1";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = version || "13.4.1";
systemName = "Android OS";
break;
case "IOS":
- appVersion = "13.3.0";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = version || "13.3.0";
systemName = "iOS";
break;
case "IOSIPAD":
- appVersion = "13.3.0";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = version || "13.3.0";
systemName = "iOS";
break;
case "WATCHOS":
- appVersion = "13.3.0";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = version || "13.3.0";
systemName = "Watch OS";
break;
case "WEAROS":
- appVersion = "13.4.1";
- if (deviceMap[device]) {
- appVersion = deviceMap[device];
- }
+ appVersion = version || "13.4.1";
systemName = "Wear OS";
break;
default:
return null;
}
- return { appVersion, systemName, systemVersion };
+ return { device, appVersion, systemName, systemVersion };
}
diff --git a/packages/linejs/client/entities/errors.ts b/packages/linejs/base/core/utils/error.ts
similarity index 66%
rename from packages/linejs/client/entities/errors.ts
rename to packages/linejs/base/core/utils/error.ts
index 6600fe47..d4e28b66 100644
--- a/packages/linejs/client/entities/errors.ts
+++ b/packages/linejs/base/core/utils/error.ts
@@ -1,10 +1,8 @@
-import type { LooseType } from "./common.ts";
-
export class InternalError extends Error {
constructor(
readonly type: string,
override readonly message: string,
- readonly data: Record = {},
+ readonly data: Record = {},
) {
super(message);
this.name = type;
diff --git a/packages/linejs/base/core/utils/events.ts b/packages/linejs/base/core/utils/events.ts
new file mode 100644
index 00000000..8a19e2f4
--- /dev/null
+++ b/packages/linejs/base/core/utils/events.ts
@@ -0,0 +1,20 @@
+import type * as LINETypes from "@evex/linejs-types";
+// import type { Operation, SquareMessage, TalkMessage } from "../../event/mod.ts";
+type LogType = "login" | "request" | "response" | (string & {});
+
+export interface Log {
+ type: LogType;
+ data: any;
+}
+
+export type ClientEvents = {
+ pincall: (pincode: string) => void;
+ qrcall: (loginUrl: string) => void;
+ ready: (user: LINETypes.Profile) => void;
+ end: (user: LINETypes.Profile) => void;
+ "update:authtoken": (authToken: string) => void;
+ "update:profile": (profile: LINETypes.Profile) => void;
+ "update:cert": (cert: string) => void;
+ "update:qrcert": (qrCert: string) => void;
+ log: (data: Log) => void;
+};
diff --git a/packages/linejs/client/clients/e2ee/index.ts b/packages/linejs/base/e2ee/mod.ts
similarity index 53%
rename from packages/linejs/client/clients/e2ee/index.ts
rename to packages/linejs/base/e2ee/mod.ts
index 15ef7bba..f7508bf6 100644
--- a/packages/linejs/client/clients/e2ee/index.ts
+++ b/packages/linejs/base/e2ee/mod.ts
@@ -1,27 +1,39 @@
-import * as curve25519 from "curve25519-js";
-import * as crypto from "node:crypto";
+import curve25519 from "curve25519-js";
+import crypto from "node:crypto";
import { Buffer } from "node:buffer";
-import { TalkClient } from "../internal/talk-client.ts";
-import type { LooseType } from "../../entities/common.ts";
-import { rawReadStruct as readStruct } from "../../libs/thrift/read.ts";
import type { Location, Message } from "@evex/linejs-types";
import nacl from "tweetnacl";
-import { InternalError } from "../../entities/errors.ts";
+import { InternalError } from "../core/utils/error.ts";
import * as LINETypes from "@evex/linejs-types";
-class E2EE extends TalkClient {
- public async getE2EESelfKeyData(mid: string): Promise {
+import type { BaseClient } from "../core/mod.ts";
+import { ContentType } from "../thrift/readwrite/struct.ts";
+import CryptoJS from "crypto-js";
+
+interface GroupKey {
+ privKey: string;
+ keyId: number;
+}
+
+export class E2EE {
+ readonly client: BaseClient;
+ constructor(client: BaseClient) {
+ this.client = client;
+ }
+ public async getE2EESelfKeyData(mid: string): Promise {
try {
- return JSON.parse(this.storage.get("e2eeKeys:" + mid) as string);
+ return JSON.parse(
+ await this.client.storage.get("e2eeKeys:" + mid) as string,
+ );
} catch (_e) {
/* Do Nothing */
}
- const keys = await this.getE2EEPublicKeys();
+ const keys = await this.client.talk.getE2EEPublicKeys();
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
- const { keyId } = key;
- const _keyData = this.getE2EESelfKeyDataByKeyId(keyId);
+ const keyId = key.keyId ?? (key as unknown as { "2"?: string })[2];
+ const _keyData = await this.getE2EESelfKeyDataByKeyId(keyId);
if (_keyData) {
- this.saveE2EESelfKeyData(_keyData);
+ await this.saveE2EESelfKeyData(_keyData);
return _keyData;
}
}
@@ -30,109 +42,104 @@ class E2EE extends TalkClient {
"E2EE Key has not been saved, try register `saveE2EESelfKeyDataByKeyId` or use E2EE Login",
);
}
- public getE2EESelfKeyDataByKeyId(keyId: string | number): LooseType {
+ public async getE2EESelfKeyDataByKeyId(
+ keyId: string | number,
+ ): Promise {
try {
- return JSON.parse(this.storage.get("e2eeKeys:" + keyId) as string);
+ return JSON.parse(
+ await this.client.storage.get("e2eeKeys:" + keyId) as string,
+ );
} catch (_e) {
/* Do Nothing */
}
}
- public saveE2EESelfKeyDataByKeyId(keyId: string | number, value: LooseType) {
- this.storage.set("e2eeKeys:" + keyId, JSON.stringify(value));
- }
- public saveE2EESelfKeyData(value: LooseType) {
- this.storage.set("e2eeKeys:" + this.user?.mid, JSON.stringify(value));
- }
- override getToType(mid: string): number | null {
- /**
- * USER(0),
- * ROOM(1),
- * GROUP(2),
- * SQUARE(3),
- * SQUARE_CHAT(4),
- * SQUARE_MEMBER(5),
- * SQUARE_BOT(6),
- * SQUARE_THREAD(7):;
- */
- const _u = mid.charAt(0);
- switch (_u) {
- case "u":
- return 0;
- case "r":
- return 1;
- case "c":
- return 2;
- case "s":
- return 3;
- case "m":
- return 4;
- case "p":
- return 5;
- case "v":
- return 6;
- case "t":
- return 7;
- default:
- return null;
- }
+ public async saveE2EESelfKeyDataByKeyId(
+ keyId: string | number,
+ value: any,
+ ) {
+ await this.client.storage.set(
+ "e2eeKeys:" + keyId,
+ JSON.stringify(value),
+ );
+ }
+ public async saveE2EESelfKeyData(value: any) {
+ await this.client.storage.set(
+ "e2eeKeys:" + this.client.profile?.mid,
+ JSON.stringify(value),
+ );
}
public async getE2EELocalPublicKey(
mid: string,
keyId?: string | number | undefined,
- ): Promise {
- const toType = this.getToType(mid);
- let key: LooseType = undefined;
- let fd: LooseType, fn: LooseType;
+ ): Promise {
+ const toType = this.client.getToType(mid);
if (toType === LINETypes.enums.MIDType.USER) {
- fd = "e2eePublicKeys";
- fn = `:${keyId}`;
+ let key: string | undefined = undefined;
if (keyId !== undefined) {
- key = this.storage.get(fd + fn);
+ key = (await this.client.storage.get(
+ `e2eePublicKeys:${keyId}`,
+ )) as string;
}
- let receiverKeyData;
+ let receiverKeyData: LINETypes.E2EENegotiationResult;
if (!key) {
- receiverKeyData = await this.negotiateE2EEPublicKey({ mid });
+ receiverKeyData = await this.client.talk.negotiateE2EEPublicKey(
+ { mid },
+ );
const specVersion = receiverKeyData.specVersion;
if (specVersion === -1) {
throw new InternalError("Not support E2EE", `${mid}`);
}
const publicKey = receiverKeyData.publicKey;
const receiverKeyId = publicKey.keyId;
- receiverKeyData = publicKey.keyData;
if (receiverKeyId === keyId) {
- key = Buffer.from(receiverKeyData).toString("base64");
- this.storage.set(fd + fn, key);
+ key = Buffer.from(publicKey.keyData).toString("base64");
+ await this.client.storage.set(
+ `e2eePublicKeys:${keyId}`,
+ key,
+ );
} else {
throw new InternalError(
"No E2EEKey",
- `E2EE key id-${keyId} not found on ${mid}, key id should be ${receiverKeyId}`,
+ `E2EE key id ${keyId} not found on ${mid}, key id should be ${receiverKeyId}`,
);
}
}
+ return Buffer.from(key, "base64");
} else {
- fd = "e2eeGroupKeys";
- fn = `:${mid}`;
- key = this.storage.get(fd + fn);
+ let key: string | undefined;
+ key = (await this.client.storage.get(
+ `e2eeGroupKeys:${mid}`,
+ )) as string;
if (keyId !== undefined && key !== undefined) {
const keyData = JSON.parse(key);
if (keyId !== keyData["keyId"]) {
this.e2eeLog("getE2EELocalPublicKeykeyIdMismatch", mid);
key = undefined;
+ } else {
+ return keyData;
}
} else {
key = undefined;
}
if (!key) {
- let e2eeGroupSharedKey: LINETypes.E2EEGroupSharedKey | undefined;
+ let e2eeGroupSharedKey:
+ | LINETypes.Pb1_U3
+ | undefined;
try {
- e2eeGroupSharedKey = await this.getLastE2EEGroupSharedKey({
- keyVersion: 2,
- chatMid: mid,
- });
+ e2eeGroupSharedKey = await this.client.talk
+ .getLastE2EEGroupSharedKey({
+ keyVersion: 2,
+ chatMid: mid,
+ });
} catch (error) {
- if ((error as InternalError).data.code == "NOT_FOUND") {
- e2eeGroupSharedKey = await this.tryRegisterE2EEGroupKey(mid);
+ if (
+ error instanceof InternalError &&
+ error.data.code == "NOT_FOUND"
+ ) {
+ e2eeGroupSharedKey = await this.tryRegisterE2EEGroupKey(
+ mid,
+ );
} else {
throw error;
}
@@ -140,12 +147,14 @@ class E2EE extends TalkClient {
const groupKeyId = e2eeGroupSharedKey.groupKeyId;
const creator = e2eeGroupSharedKey.creator;
const creatorKeyId = e2eeGroupSharedKey.creatorKeyId;
- const _receiver = e2eeGroupSharedKey.receiver;
const receiverKeyId = e2eeGroupSharedKey.receiverKeyId;
- const encryptedSharedKey =
- e2eeGroupSharedKey.encryptedSharedKey as Buffer;
+ const encryptedSharedKey = Buffer.from(
+ e2eeGroupSharedKey.encryptedSharedKey,
+ );
const selfKey = Buffer.from(
- this.getE2EESelfKeyDataByKeyId(receiverKeyId)["privKey"],
+ (await this.getE2EESelfKeyDataByKeyId(
+ receiverKeyId,
+ ))["privKey"],
"base64",
);
const creatorKey = await this.getE2EELocalPublicKey(
@@ -153,9 +162,14 @@ class E2EE extends TalkClient {
creatorKeyId,
);
- const aesKey = this.generateSharedSecret(selfKey, creatorKey);
+ const aesKey = this.generateSharedSecret(
+ selfKey,
+ creatorKey as Buffer,
+ );
const aes_key = this.getSHA256Sum(Buffer.from(aesKey), "Key");
- const aes_iv = this.xor(this.getSHA256Sum(Buffer.from(aesKey), "IV"));
+ const aes_iv = this.xor(
+ this.getSHA256Sum(Buffer.from(aesKey), "IV"),
+ );
this.e2eeLog("getE2EELocalPublicKeyAESInfo", {
aes_key,
@@ -171,7 +185,10 @@ class E2EE extends TalkClient {
decipher.update(encryptedSharedKey),
decipher.final(),
]);
- this.e2eeLog("getE2EELocalPublicKeyDecryptedLength", plainText.length);
+ this.e2eeLog(
+ "getE2EELocalPublicKeyDecryptedLength",
+ plainText.length,
+ );
const decrypted = plainText.toString("base64");
this.e2eeLog("getE2EELocalPublicKeyDecrypted", decrypted);
const data = {
@@ -179,22 +196,23 @@ class E2EE extends TalkClient {
keyId: groupKeyId,
};
key = JSON.stringify(data);
- this.storage.set(fd + fn, key);
+ await this.client.storage.set(`e2eeGroupKeys:${mid}`, key);
return data;
}
return JSON.parse(key);
}
- return Buffer.from(key, "base64");
}
public async tryRegisterE2EEGroupKey(
chatMid: string,
- ): Promise {
- const e2eePublicKeys = await this.getLastE2EEPublicKeys({ chatMid });
+ ): Promise {
+ const e2eePublicKeys = await this.client.talk.getLastE2EEPublicKeys({
+ chatMid,
+ });
const members: string[] = [];
const keyIds: number[] = [];
const encryptedSharedKeys: Buffer[] = [];
- const selfKeyId = e2eePublicKeys[this.user!.mid].keyId;
- const selfKeyData = this.getE2EESelfKeyDataByKeyId(selfKeyId);
+ const selfKeyId = e2eePublicKeys[this.client.profile!.mid].keyId;
+ const selfKeyData = await this.getE2EESelfKeyDataByKeyId(selfKeyId);
if (!selfKeyData) {
throw new InternalError(
"NoE2EEKey",
@@ -210,10 +228,19 @@ class E2EE extends TalkClient {
const { keyId, keyData } = key;
keyIds.push(keyId);
- const aesKey = this.generateSharedSecret(selfKey, Buffer.from(keyData));
+ const aesKey = this.generateSharedSecret(
+ selfKey,
+ Buffer.from(keyData),
+ );
const aes_key = this.getSHA256Sum(Buffer.from(aesKey), "Key");
- const aes_iv = this.xor(this.getSHA256Sum(Buffer.from(aesKey), "IV"));
- const cipher = crypto.createCipheriv("aes-256-cbc", aes_key, aes_iv);
+ const aes_iv = this.xor(
+ this.getSHA256Sum(Buffer.from(aesKey), "IV"),
+ );
+ const cipher = crypto.createCipheriv(
+ "aes-256-cbc",
+ aes_key,
+ aes_iv,
+ );
const encryptedSharedKey = Buffer.concat([
cipher.update(private_key),
cipher.final(),
@@ -221,7 +248,7 @@ class E2EE extends TalkClient {
encryptedSharedKeys.push(encryptedSharedKey);
}
}
- return this.registerE2EEGroupKey({
+ return this.client.talk.registerE2EEGroupKey({
keyVersion: 1,
chatMid,
keyIds,
@@ -252,7 +279,7 @@ class E2EE extends TalkClient {
return buf2;
}
- override getSHA256Sum(...args: (string | Buffer)[]): Buffer {
+ public getSHA256Sum(...args: (string | Buffer)[]): Buffer {
const hash = crypto.createHash("sha256");
for (let arg of args) {
if (typeof arg === "string") {
@@ -263,7 +290,7 @@ class E2EE extends TalkClient {
return hash.digest();
}
- override encryptAESECB(aesKey: Buffer, plainData: Buffer): Buffer {
+ public encryptAESECB(aesKey: Buffer, plainData: Buffer): Buffer {
const cipher = crypto.createCipheriv(
"aes-256-ecb",
aesKey,
@@ -273,19 +300,18 @@ class E2EE extends TalkClient {
return Buffer.concat([cipher.update(plainData), cipher.final()]);
}
- override decodeE2EEKeyV1(
- data: LooseType,
+ public async decodeE2EEKeyV1(
+ data: any,
secret: Buffer,
- ):
- | {
- keyId: LooseType;
- privKey: Buffer;
- pubKey: Buffer;
- e2eeVersion: LooseType;
- }
- | undefined {
+ ): Promise<
+ | { keyId: any; privKey: Buffer; pubKey: Buffer; e2eeVersion: any }
+ | undefined
+ > {
if (data.encryptedKeyChain) {
- const encryptedKeyChain = Buffer.from(data.encryptedKeyChain, "base64");
+ const encryptedKeyChain = Buffer.from(
+ data.encryptedKeyChain,
+ "base64",
+ );
const keyId = data.keyId;
const publicKey = Buffer.from(data.publicKey, "base64");
const e2eeVersion = data.e2eeVersion;
@@ -302,7 +328,7 @@ class E2EE extends TalkClient {
e2eeVersion,
},
});
- this.storage.set(
+ await this.client.storage.set(
"e2eeKeys:" + keyId,
JSON.stringify({
keyId,
@@ -333,7 +359,9 @@ class E2EE extends TalkClient {
});
const sharedSecret = this.generateSharedSecret(privateKey, publicKey);
const aesKey = this.getSHA256Sum(Buffer.from(sharedSecret), "Key");
- const aesIv = this.xor(this.getSHA256Sum(Buffer.from(sharedSecret), "IV"));
+ const aesIv = this.xor(
+ this.getSHA256Sum(Buffer.from(sharedSecret), "IV"),
+ );
const decipher = crypto.createDecipheriv("aes-256-cbc", aesKey, aesIv);
decipher.setAutoPadding(false);
const keychainData = Buffer.concat([
@@ -343,13 +371,13 @@ class E2EE extends TalkClient {
this.e2eeLog("decryptKeyChainBinKeyInfo", {
binkey: keychainData.toString("hex"),
});
- const key = readStruct(keychainData)[1];
+ const key = this.client.thrift.readThriftStruct(keychainData)[1];
const publicKeyBytes = Buffer.from(key[0][4]);
const privateKeyBytes = Buffer.from(key[0][5]);
return [privateKeyBytes, publicKeyBytes];
}
- override encryptDeviceSecret(
+ public encryptDeviceSecret(
publicKey: Buffer,
privateKey: Buffer,
encryptedKeyChain: Buffer,
@@ -405,25 +433,32 @@ class E2EE extends TalkClient {
return res;
}
- override async encryptE2EEMessage(
+ public async encryptE2EEMessage(
to: string,
- text: string | Location,
- contentType = 0,
+ data: string | Location | Record,
+ contentType: LINETypes.ContentType = 0,
specVersion = 2,
): Promise {
- const _from = this.user?.mid as string;
+ contentType = ContentType(contentType) ?? 0;
+ const _from = this.client.profile?.mid as string;
const selfKeyData = await this.getE2EESelfKeyData(_from);
- if (to.length === 0 || ![0, 1, 2].includes(this.getToType(to) as number)) {
+ if (
+ to.length === 0 ||
+ ![0, 1, 2].includes(this.client.getToType(to) ?? -1)
+ ) {
throw new InternalError("Invalid mid", to);
}
const senderKeyId = selfKeyData.keyId;
let receiverKeyId, keyData;
- if (this.getToType(to) === LINETypes.enums.MIDType.USER) {
+ if (this.client.getToType(to) === LINETypes.enums.MIDType.USER) {
const privateKey = Buffer.from(selfKeyData.privKey, "base64");
- const receiverKeyData = await this.negotiateE2EEPublicKey({ mid: to });
+ const receiverKeyData = await this.client.talk
+ .negotiateE2EEPublicKey({
+ mid: to,
+ });
specVersion = receiverKeyData.specVersion;
if (specVersion === -1) {
@@ -433,39 +468,53 @@ class E2EE extends TalkClient {
const publicKey = receiverKeyData.publicKey;
receiverKeyId = publicKey.keyId;
const receiverKeyDataBuffer = Buffer.from(publicKey.keyData);
- keyData = this.generateSharedSecret(privateKey, receiverKeyDataBuffer);
+ keyData = this.generateSharedSecret(
+ privateKey,
+ receiverKeyDataBuffer,
+ );
} else {
- const groupK = await this.getE2EELocalPublicKey(to, undefined);
+ const groupK =
+ (await this.getE2EELocalPublicKey(to, undefined)) as GroupKey;
const privK = Buffer.from(groupK.privKey, "base64");
const pubK = Buffer.from(selfKeyData.pubKey, "base64");
receiverKeyId = groupK.keyId;
keyData = this.generateSharedSecret(privK, pubK);
}
-
- let chunks;
- if (contentType === LINETypes.enums.ContentType.LOCATION) {
- chunks = this.encryptE2EELocationMessage(
+ if (
+ contentType === LINETypes.enums.ContentType.LOCATION &&
+ typeof data === "object"
+ ) {
+ return this.encryptE2EELocationMessage(
senderKeyId,
receiverKeyId,
Buffer.from(keyData),
specVersion,
- text as Location,
+ data as Location,
+ to,
+ _from,
+ );
+ } else if (typeof data === "string") {
+ return this.encryptE2EETextMessage(
+ senderKeyId,
+ receiverKeyId,
+ Buffer.from(keyData),
+ specVersion,
+ data,
to,
_from,
);
} else {
- chunks = this.encryptE2EETextMessage(
+ return this.encryptE2EEMessageByData(
senderKeyId,
receiverKeyId,
Buffer.from(keyData),
specVersion,
- text as string,
+ data,
to,
_from,
+ contentType,
);
}
-
- return chunks;
}
public encryptE2EETextMessage(
@@ -506,6 +555,45 @@ class E2EE extends TalkClient {
return [salt, encData, sign, bSenderKeyId, bReceiverKeyId];
}
+ public encryptE2EEMessageByData(
+ senderKeyId: number,
+ receiverKeyId: number,
+ keyData: Buffer,
+ specVersion: number,
+ rawdata: Record,
+ to: string,
+ _from: string,
+ contentType: number,
+ ): Buffer[] {
+ const salt = crypto.randomBytes(16);
+ const gcmKey = this.getSHA256Sum(keyData, salt, Buffer.from("Key"));
+ const aad = this.generateAAD(
+ to,
+ _from,
+ senderKeyId,
+ receiverKeyId,
+ specVersion,
+ contentType,
+ );
+ const sign = crypto.randomBytes(12);
+ const data = Buffer.from(JSON.stringify(rawdata));
+ const encData = this.encryptE2EEMessageV2(data, gcmKey, sign, aad);
+
+ const bSenderKeyId = Buffer.from(this.getIntBytes(senderKeyId));
+ const bReceiverKeyId = Buffer.from(this.getIntBytes(receiverKeyId));
+
+ this.e2eeLog(
+ "encryptE2EEDataMessageSenderKeyId",
+ `${senderKeyId} (${bSenderKeyId.toString("hex")})`,
+ );
+ this.e2eeLog(
+ "encryptE2EEDataMessageReceiverKeyId",
+ `${receiverKeyId} (${bReceiverKeyId.toString("hex")})`,
+ );
+
+ return [salt, encData, sign, bSenderKeyId, bReceiverKeyId];
+ }
+
public encryptE2EELocationMessage(
senderKeyId: number,
receiverKeyId: number,
@@ -558,21 +646,28 @@ class E2EE extends TalkClient {
return Buffer.concat([encrypted, tag]);
}
- override async decryptE2EEMessage(messageObj: Message): Promise {
+ public async decryptE2EEMessage(messageObj: Message): Promise {
if (
(messageObj.contentType === "NONE" ||
messageObj.contentType === LINETypes.enums.ContentType.NONE) &&
messageObj.chunks
) {
- messageObj.text = await this.decryptE2EETextMessage(messageObj);
+ const [text, meta] = await this.decryptE2EETextMessage(messageObj);
+ messageObj.text = text;
+ messageObj.contentMetadata = {
+ ...messageObj.contentMetadata,
+ ...meta,
+ };
} else if (
(messageObj.contentType === "LOCATION" ||
- messageObj.contentType === LINETypes.enums.ContentType.LOCATION) &&
+ messageObj.contentType ===
+ LINETypes.enums.ContentType.LOCATION) &&
messageObj.chunks
) {
- messageObj.location = await this.decryptE2EELocationMessage(messageObj);
+ messageObj.location = await this.decryptE2EELocationMessage(
+ messageObj,
+ );
}
- if (messageObj.chunks) messageObj.chunks = undefined as LooseType;
return messageObj;
}
@@ -580,10 +675,10 @@ class E2EE extends TalkClient {
public async decryptE2EETextMessage(
messageObj: Message,
isSelf = false,
- ): Promise {
- const _from = messageObj._from;
+ ): Promise<[string, Record]> {
+ const _from = messageObj.from;
const to = messageObj.to;
- if (_from === this.user?.mid) {
+ if (_from === this.client.profile?.mid) {
isSelf = true;
}
const toType = messageObj.toType;
@@ -591,16 +686,16 @@ class E2EE extends TalkClient {
const specVersion = metadata.e2eeVersion || "2";
const contentType = messageObj.contentType;
const chunks = messageObj.chunks.map((chunk) =>
- typeof chunk === "string" ? Buffer.from(chunk, "utf-8") : chunk,
+ typeof chunk === "string" ? Buffer.from(chunk, "utf-8") : chunk
);
const senderKeyId = byte2int(chunks[3]);
const receiverKeyId = byte2int(chunks[4]);
this.e2eeLog("decryptE2EETextMessageSenderKeyId", senderKeyId);
this.e2eeLog("decryptE2EETextMessageReceiverKeyId", receiverKeyId);
- const selfKey = await this.getE2EESelfKeyData(this.user!.mid);
+ const selfKey = await this.getE2EESelfKeyData(this.client.profile!.mid);
let privK = Buffer.from(selfKey.privKey, "base64");
- let pubK;
+ let pubK: any;
if (toType === LINETypes.enums.MIDType.USER || toType === "USER") {
pubK = await this.getE2EELocalPublicKey(
@@ -608,10 +703,13 @@ class E2EE extends TalkClient {
isSelf ? receiverKeyId : senderKeyId,
);
} else {
- const groupK = await this.getE2EELocalPublicKey(to, receiverKeyId);
+ const groupK = await this.getE2EELocalPublicKey(
+ to,
+ receiverKeyId,
+ ) as GroupKey;
privK = Buffer.from(groupK.privKey, "base64");
pubK = Buffer.from(selfKey.pubKey, "base64");
- if (_from !== this.user?.mid) {
+ if (_from !== this.client.profile?.mid) {
pubK = await this.getE2EELocalPublicKey(_from, senderKeyId);
}
}
@@ -630,22 +728,35 @@ class E2EE extends TalkClient {
} else {
decrypted = this.decryptE2EEMessageV1(chunks, privK, pubK);
}
-
- return decrypted.text || "";
+ const text = decrypted.text || "";
+ const meta: Record = {};
+ for (const key in decrypted) {
+ if (key === "text") {
+ continue;
+ }
+ if (Object.prototype.hasOwnProperty.call(decrypted, key)) {
+ const val = decrypted[key];
+ if (typeof val === "string") {
+ meta[key] = val;
+ } else {
+ meta[key] = JSON.stringify(val);
+ }
+ }
+ }
+ return [text, meta];
}
-
public async decryptE2EELocationMessage(
messageObj: Message,
isSelf = true,
): Promise {
- const _from = messageObj._from;
+ const _from = messageObj.from;
const to = messageObj.to;
const toType = messageObj.toType;
const metadata = messageObj.contentMetadata;
const specVersion = metadata.e2eeVersion || "2";
const contentType = messageObj.contentType;
const chunks = messageObj.chunks.map((chunk) =>
- typeof chunk === "string" ? Buffer.from(chunk, "utf-8") : chunk,
+ typeof chunk === "string" ? Buffer.from(chunk, "utf-8") : chunk
);
const senderKeyId = byte2int(chunks[3]);
@@ -653,9 +764,11 @@ class E2EE extends TalkClient {
this.e2eeLog("decryptE2EELocationMessageSenderKeyId", senderKeyId);
this.e2eeLog("decryptE2EELocationMessageReceiverKeyId", receiverKeyId);
- const selfKey = await this.getE2EESelfKeyData(this.user?.mid as string);
+ const selfKey = await this.getE2EESelfKeyData(
+ this.client.profile?.mid as string,
+ );
let privK = Buffer.from(selfKey.privKey, "base64");
- let pubK;
+ let pubK: any;
if (toType === LINETypes.enums.MIDType.USER || toType === "USER") {
pubK = await this.getE2EELocalPublicKey(
@@ -663,10 +776,13 @@ class E2EE extends TalkClient {
isSelf ? receiverKeyId : senderKeyId,
);
} else {
- const groupK = await this.getE2EELocalPublicKey(to, receiverKeyId);
+ const groupK = await this.getE2EELocalPublicKey(
+ to,
+ receiverKeyId,
+ ) as GroupKey;
privK = Buffer.from(groupK.privKey, "base64");
pubK = Buffer.from(selfKey.pubKey, "base64");
- if (_from !== this.user?.mid) {
+ if (_from !== this.client.profile?.mid) {
pubK = await this.getE2EELocalPublicKey(_from, senderKeyId);
}
}
@@ -688,12 +804,71 @@ class E2EE extends TalkClient {
return decrypted.location || undefined;
}
+ public async decryptE2EEDataMessage(
+ messageObj: Message,
+ isSelf = true,
+ ): Promise> {
+ const _from = messageObj.from;
+ const to = messageObj.to;
+ const toType = messageObj.toType;
+ const metadata = messageObj.contentMetadata;
+ const specVersion = metadata.e2eeVersion || "2";
+ const contentType = messageObj.contentType;
+ const chunks = messageObj.chunks.map((chunk) =>
+ typeof chunk === "string" ? Buffer.from(chunk, "utf-8") : chunk
+ );
+
+ const senderKeyId = byte2int(chunks[3]);
+ const receiverKeyId = byte2int(chunks[4]);
+ this.e2eeLog("decryptE2EELocationMessageSenderKeyId", senderKeyId);
+ this.e2eeLog("decryptE2EELocationMessageReceiverKeyId", receiverKeyId);
+
+ const selfKey = await this.getE2EESelfKeyData(
+ this.client.profile?.mid as string,
+ );
+ let privK = Buffer.from(selfKey.privKey, "base64");
+ let pubK: any;
+
+ if (toType === LINETypes.enums.MIDType.USER || toType === "USER") {
+ pubK = await this.getE2EELocalPublicKey(
+ to,
+ isSelf ? receiverKeyId : senderKeyId,
+ );
+ } else {
+ const groupK = await this.getE2EELocalPublicKey(
+ to,
+ receiverKeyId,
+ ) as GroupKey;
+ privK = Buffer.from(groupK.privKey, "base64");
+ pubK = Buffer.from(selfKey.pubKey, "base64");
+ if (_from !== this.client.profile?.mid) {
+ pubK = await this.getE2EELocalPublicKey(_from, senderKeyId);
+ }
+ }
+
+ let decrypted;
+ if (specVersion === "2") {
+ decrypted = this.decryptE2EEMessageV2(
+ to,
+ _from,
+ chunks,
+ privK,
+ pubK,
+ parseInt(specVersion),
+ contentType as number,
+ );
+ } else {
+ decrypted = this.decryptE2EEMessageV1(chunks, privK, pubK);
+ }
+
+ return decrypted || {};
+ }
public decryptE2EEMessageV1(
chunks: Buffer[],
privK: Buffer,
pubK: Buffer,
- ): LooseType {
+ ): any {
this.e2eeLog("decryptE2EEMessageV1_arg", {
chunks,
privK,
@@ -704,19 +879,31 @@ class E2EE extends TalkClient {
const _sign = chunks[2];
const aesKey = this.generateSharedSecret(privK, pubK);
const aes_key = this.getSHA256Sum(Buffer.from(aesKey), salt, "Key");
- const aes_iv = this.xor(this.getSHA256Sum(Buffer.from(aesKey), salt, "IV"));
+ const aes_iv = this.xor(
+ this.getSHA256Sum(Buffer.from(aesKey), salt, "IV"),
+ );
this.e2eeLog("decryptE2EEMessageV1", {
aes_key,
aes_iv,
message,
});
- const decipher = crypto.createDecipheriv("aes-256-cbc", aes_key, aes_iv);
+ const decipher = crypto.createDecipheriv(
+ "aes-256-cbc",
+ aes_key,
+ aes_iv,
+ );
let decrypted: Buffer | undefined;
try {
- decrypted = Buffer.concat([decipher.update(message), decipher.final()]);
+ decrypted = Buffer.concat([
+ decipher.update(message),
+ decipher.final(),
+ ]);
} catch {
decipher.setAutoPadding(false);
- decrypted = Buffer.concat([decipher.update(message), decipher.final()]);
+ decrypted = Buffer.concat([
+ decipher.update(message),
+ decipher.final(),
+ ]);
}
this.e2eeLog(
"decryptE2EEMessageV1DecryptedMessage",
@@ -733,7 +920,7 @@ class E2EE extends TalkClient {
pubK: Buffer,
specVersion = 2,
contentType = 0,
- ): LooseType {
+ ): any {
const salt = chunks[0];
const message = chunks[1];
const ciphertext = message.subarray(0, -16);
@@ -757,11 +944,24 @@ class E2EE extends TalkClient {
decipher.setAAD(aad);
let decrypted;
try {
- decrypted = decipher.update(ciphertext);
- decrypted = Buffer.concat([decrypted, decipher.final()]);
+ try {
+ decrypted = Buffer.concat([
+ decipher.update(ciphertext),
+ decipher.final(),
+ ]);
+ } catch {
+ decipher.setAutoPadding(false);
+ decrypted = Buffer.concat([
+ decipher.update(ciphertext),
+ decipher.final(),
+ ]);
+ }
} catch (error) {
if (error instanceof Error) {
- this.e2eeLog("decryptE2EEMessageV2DecryptionFailed", error.message);
+ this.e2eeLog(
+ "decryptE2EEMessageV2DecryptionFailed",
+ error.message,
+ );
}
throw error;
@@ -771,11 +971,13 @@ class E2EE extends TalkClient {
return JSON.parse(decrypted.toString());
}
- private e2eeLog(type: string, message: LooseType) {
- this.log("e2ee", { type, message });
+ private e2eeLog(type: string, message: any) {
+ this.client.log("e2ee", { type, message });
}
- override createSqrSecret(base64Only: boolean = false): [Uint8Array, string] {
+ public createSqrSecret(
+ base64Only: boolean = false,
+ ): [Uint8Array, string] {
const { secretKey, publicKey } = nacl.box.keyPair();
const secret = encodeURIComponent(
Buffer.from(publicKey).toString("base64"),
@@ -788,10 +990,170 @@ class E2EE extends TalkClient {
Buffer.from(publicKey).toString("base64"),
];
}
- return [Buffer.from(secretKey), `?secret=${secret}&e2eeVersion=${version}`];
+ return [
+ Buffer.from(secretKey),
+ `?secret=${secret}&e2eeVersion=${version}`,
+ ];
+ }
+
+ // for e2ee next
+
+ _encryptAESCTR(aesKey: Buffer, nonce: Buffer, data: Buffer): Buffer {
+ // deno not support ctr !
+ const cipher = crypto.createCipheriv("aes-256-ctr", aesKey, nonce);
+ const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
+ return encrypted;
+ }
+
+ async __encryptAESCTR(
+ aesKey: Buffer,
+ nonce: Buffer,
+ data: Buffer,
+ ): Promise {
+ return Buffer.from(
+ await globalThis.crypto.subtle.encrypt(
+ {
+ name: "AES-CTR",
+ counter: nonce,
+ length: 64,
+ },
+ await globalThis.crypto.subtle.importKey(
+ "raw",
+ aesKey,
+ "AES-CTR",
+ false,
+ ["encrypt", "decrypt"],
+ ),
+ data,
+ ),
+ );
+ }
+
+ ___encryptAESCTR(aesKey: Buffer, nonce: Buffer, data: Buffer): Buffer {
+ // Convert Buffer to WordArray
+ const key = CryptoJS.lib.WordArray.create(aesKey);
+ const iv = CryptoJS.lib.WordArray.create(nonce);
+ const plaintext = CryptoJS.lib.WordArray.create(data);
+
+ // Encrypt using AES-CTR
+ const encrypted = CryptoJS.AES.encrypt(plaintext, key, {
+ iv: iv,
+ mode: CryptoJS.mode.CTR,
+ padding: CryptoJS.pad.NoPadding, // No padding for AES-CTR
+ });
+
+ // Convert WordArray ciphertext back to Buffer
+ const ciphertext = Buffer.from(
+ encrypted.ciphertext.toString(CryptoJS.enc.Hex),
+ "hex",
+ );
+
+ return ciphertext;
+ }
+
+ _decryptAESCTR(aesKey: Buffer, nonce: Buffer, data: Buffer): Buffer {
+ const decipher = crypto.createDecipheriv("aes-256-ctr", aesKey, nonce);
+ const decrypted = Buffer.concat([
+ decipher.update(data),
+ decipher.final(),
+ ]);
+ return decrypted;
+ }
+
+ __decryptAESCTR(aesKey: Buffer, nonce: Buffer, data: Buffer): Buffer {
+ const keyWordArray = CryptoJS.lib.WordArray.create(aesKey);
+ const nonceWordArray = CryptoJS.lib.WordArray.create(nonce);
+
+ const encryptedData = CryptoJS.lib.WordArray.create(data);
+
+ const decrypted = CryptoJS.AES.decrypt(
+ {
+ ciphertext: encryptedData,
+ },
+ keyWordArray,
+ {
+ mode: CryptoJS.mode.CTR,
+ iv: nonceWordArray,
+ padding: CryptoJS.pad.NoPadding, // No padding
+ },
+ );
+
+ return Buffer.from(decrypted.toString(CryptoJS.enc.Hex), "hex");
+ }
+
+ signData(data: Buffer, key: Buffer): Buffer {
+ const hmac = crypto.createHmac("sha256", key);
+ hmac.update(data);
+ return hmac.digest();
+ }
+
+ async deriveKeyMaterial(
+ keyMaterial: Buffer,
+ ): Promise<{ encKey: Buffer; macKey: Buffer; nonce: Buffer }> {
+ const derived = await new Promise((resolve, reject) => {
+ // ???
+ crypto.hkdf(
+ "sha256",
+ keyMaterial,
+ new Uint8Array(0),
+ "FileEncryption",
+ 76,
+ (err, derivedKey) => {
+ if (err) {
+ reject(err);
+ }
+ resolve(Buffer.from(derivedKey));
+ },
+ );
+ });
+ return {
+ encKey: derived.slice(0, 32),
+ macKey: derived.slice(32, 64),
+ // ???
+ nonce: Buffer.concat([derived.slice(64, 76), new Uint8Array(4)]),
+ };
+ }
+
+ async encryptByKeyMaterial(
+ rawData: Buffer,
+ keyMaterial?: Buffer,
+ ): Promise<{ keyMaterial: string; encryptedData: Buffer }> {
+ // Encrypt file for E2EE Next
+ if (!keyMaterial) {
+ keyMaterial = crypto.randomBytes(32);
+ }
+ const keys = await this.deriveKeyMaterial(keyMaterial);
+ const encData = await this.___encryptAESCTR(
+ keys.encKey,
+ keys.nonce,
+ rawData,
+ );
+ const sign = this.signData(encData, keys.macKey);
+
+ return {
+ keyMaterial: keyMaterial.toString("base64"),
+ encryptedData: Buffer.concat([encData, sign]),
+ };
+ }
+
+ async decryptByKeyMaterial(
+ rawData: Buffer,
+ keyMaterial: Buffer | string,
+ ): Promise {
+ // Decrypt file for E2EE Next
+ if (typeof keyMaterial === "string") {
+ keyMaterial = Buffer.from(keyMaterial, "base64");
+ }
+ const keys = await this.deriveKeyMaterial(keyMaterial);
+ return this.__decryptAESCTR(keys.encKey, keys.nonce, rawData).slice(
+ 0,
+ -32,
+ );
}
}
+export default E2EE;
+
function byte2int(t: Buffer) {
let e = 0;
const s = t.length;
@@ -809,5 +1171,3 @@ function _bin2bytes(k: string) {
}
return new Uint8Array(e);
}
-
-export { E2EE };
diff --git a/packages/linejs/client/entities/square-class.ts b/packages/linejs/base/event/square-class.ts
similarity index 75%
rename from packages/linejs/client/entities/square-class.ts
rename to packages/linejs/base/event/square-class.ts
index 8fab278e..5e4a46a9 100644
--- a/packages/linejs/client/entities/square-class.ts
+++ b/packages/linejs/base/event/square-class.ts
@@ -4,9 +4,8 @@
* for square
*/
import * as LINETypes from "@evex/linejs-types";
-import type { Client } from "../index.ts";
-import type { LooseType } from "./common.ts";
-import { TypedEventEmitter } from "../libs/typed-event-emitter/index.ts";
+import { type BaseClient, Continuable, continueRequest } from "../core/mod.ts";
+import { TypedEventEmitter } from "../core/typed-event-emitter/index.ts";
import { SquareMessage } from "./message-class.ts";
import { Note } from "./talk-class.ts";
@@ -25,7 +24,8 @@ type SquareEvents = {
type SquareChatEvents = {
message: (message: SquareMessage) => void;
- update: (chat: LINETypes.SquareChat) => void;
+ update: (chat: SquareChat) => void;
+ "update:chat": (chat: LINETypes.SquareChat) => void;
"update:status": (status: LINETypes.SquareChatStatusWithoutMessage) => void;
// todo
// kick: (event: LINETypes.SquareEvent & { payload: {} }) => void;
@@ -74,7 +74,7 @@ export class Square extends TypedEventEmitter {
constructor(
public rawSouce: LINETypes.GetSquareResponse,
- private client: Client,
+ private client: BaseClient,
autoUpdate: boolean = true,
) {
super();
@@ -109,22 +109,26 @@ export class Square extends TypedEventEmitter {
this.status = squareStatus;
this.memberCount = squareStatus.memberCount;
this.joinRequestCount = squareStatus.joinRequestCount;
- this.lastJoinRequestAt = new Date(squareStatus.lastJoinRequestAt as number);
+ this.lastJoinRequestAt = new Date(
+ squareStatus.lastJoinRequestAt as number,
+ );
this.openChatCount = squareStatus.openChatCount;
if (autoUpdate) {
client.on("square:event", (event) => {
if (
event.payload.notifiedUpdateSquareFeatureSet &&
- event.payload.notifiedUpdateSquareFeatureSet.squareFeatureSet
- .squareMid === this.mid
+ event.payload.notifiedUpdateSquareFeatureSet
+ .squareFeatureSet
+ .squareMid === this.mid
) {
- this.feature =
- event.payload.notifiedUpdateSquareFeatureSet.squareFeatureSet;
+ this.feature = event.payload.notifiedUpdateSquareFeatureSet
+ .squareFeatureSet;
this.emit("update", this);
this.emit("update:feature", this.feature);
} else if (
event.payload.notifiedUpdateSquareStatus &&
- event.payload.notifiedUpdateSquareStatus.squareMid === this.mid
+ event.payload.notifiedUpdateSquareStatus.squareMid ===
+ this.mid
) {
this.status = event.payload.notifiedUpdateSquareStatus.squareStatus;
this.emit("update", this);
@@ -133,10 +137,14 @@ export class Square extends TypedEventEmitter {
event.payload.notificationJoinRequest &&
event.payload.notificationJoinRequest.squareMid === this.mid
) {
- this.emit("joinrequest", event.payload.notificationJoinRequest);
+ this.emit(
+ "joinrequest",
+ event.payload.notificationJoinRequest,
+ );
} else if (
event.payload.notifiedUpdateSquareNoteStatus &&
- event.payload.notifiedUpdateSquareNoteStatus.squareMid === this.mid
+ event.payload.notifiedUpdateSquareNoteStatus.squareMid ===
+ this.mid
) {
this.noteStatus =
event.payload.notifiedUpdateSquareNoteStatus.noteStatus;
@@ -144,10 +152,11 @@ export class Square extends TypedEventEmitter {
this.emit("update:note", this.noteStatus);
} else if (
event.payload.notifiedUpdateSquareAuthority &&
- event.payload.notifiedUpdateSquareAuthority.squareMid === this.mid
+ event.payload.notifiedUpdateSquareAuthority.squareMid ===
+ this.mid
) {
- this.authority =
- event.payload.notifiedUpdateSquareAuthority.squareAuthority;
+ this.authority = event.payload.notifiedUpdateSquareAuthority
+ .squareAuthority;
this.emit("update", this);
this.emit("update:authority", this.authority);
} else if (
@@ -196,8 +205,8 @@ export class Square extends TypedEventEmitter {
/**
* @description Generate from mid.
*/
- static async from(squareMid: string, client: Client): Promise {
- return new this(await client.getSquare({ squareMid }), client);
+ static async from(squareMid: string, client: BaseClient): Promise {
+ return new this(await client.square.getSquare({ squareMid }), client);
}
}
@@ -221,9 +230,10 @@ export class SquareChat extends TypedEventEmitter {
public status: LINETypes.SquareChatStatusWithoutMessage;
public syncToken?: string;
public note: Note;
+ public polling_delay = 2000;
constructor(
public rawSouce: LINETypes.GetSquareChatResponse,
- private client: Client,
+ private client: BaseClient,
polling: boolean = false,
autoUpdate: boolean = true,
) {
@@ -240,29 +250,36 @@ export class SquareChat extends TypedEventEmitter {
this.invitationUrl = squareChat.invitationUrl;
this.messageVisibility = squareChat.messageVisibility;
this.ableToSearchMessage = [null, false, true][
- LINETypes.enums.BooleanState[squareChat.ableToSearchMessage]
+ LINETypes.enums.BooleanState[
+ squareChat.ableToSearchMessage as
+ & LINETypes.BooleanState
+ & string
+ ]
];
this.mymid = squareChatMember.squareMemberMid;
this.memberCount = squareChatStatus.otherStatus.memberCount;
this.status = squareChatStatus.otherStatus;
this.note = new Note(this.squareMid, this.client);
if (polling) {
- this.startPolling();
+ this.polling();
}
if (autoUpdate) {
client.on("square:event", (event) => {
if (
event.payload.notifiedUpdateSquareChatStatus &&
- event.payload.notifiedUpdateSquareChatStatus.squareChatMid ===
+ event.payload.notifiedUpdateSquareChatStatus
+ .squareChatMid ===
this.mid
) {
- this.status =
- event.payload.notifiedUpdateSquareChatStatus.statusWithoutMessage;
+ this.status = event.payload.notifiedUpdateSquareChatStatus
+ .statusWithoutMessage;
this.memberCount = this.status.memberCount;
- //this.emit("update:status", this.status)
+ this.emit("update", this);
+ this.emit("update:status", this.status);
} else if (
event.payload.notifiedUpdateSquareChat &&
- event.payload.notifiedUpdateSquareChat.squareChatMid === this.mid
+ event.payload.notifiedUpdateSquareChat.squareChatMid ===
+ this.mid
) {
const { squareChat } = event.payload.notifiedUpdateSquareChat;
this.mid = squareChat.squareChatMid;
@@ -270,15 +287,21 @@ export class SquareChat extends TypedEventEmitter {
this.type = squareChat.type;
this.name = squareChat.name;
this.chatImageObsHash = squareChat.chatImageObsHash;
- this.squareChatRevision = squareChat.squareChatRevision as number;
+ this.squareChatRevision = squareChat
+ .squareChatRevision as number;
this.maxMemberCount = squareChat.maxMemberCount;
this.state = squareChat.state;
this.invitationUrl = squareChat.invitationUrl;
this.messageVisibility = squareChat.messageVisibility;
this.ableToSearchMessage = [null, false, true][
- LINETypes.enums.BooleanState[squareChat.ableToSearchMessage]
+ LINETypes.enums.BooleanState[
+ squareChat.ableToSearchMessage as
+ & LINETypes.BooleanState
+ & string
+ ]
];
- this.emit("update", squareChat);
+ this.emit("update", this);
+ this.emit("update:chat", squareChat);
}
});
if (polling) {
@@ -292,20 +315,26 @@ export class SquareChat extends TypedEventEmitter {
*/
static async from(
squareChatMid: string,
- client: Client,
+ client: BaseClient,
polling: boolean = true,
): Promise {
return new this(
- await client.getSquareChat({ squareChatMid }),
+ await client.square.getSquareChat({ squareChatMid }),
client,
polling,
);
}
public async getMembers(): Promise {
- const r = await this.client.getSquareChatMembers({
- squareChatMid: this.mid,
- continueRequest: true,
+ const r = await continueRequest({
+ handler: (
+ param: {
+ continuationToken?: string;
+ squareChatMid: string;
+ limit?: number;
+ },
+ ) => this.client.square.getSquareChatMembers(param),
+ arg: { squareChatMid: this.mid },
});
return r.squareChatMembers.map((e) => new SquareMember(e, this.client));
}
@@ -313,23 +342,23 @@ export class SquareChat extends TypedEventEmitter {
/**
* @description Send msg to square.
*/
- public send(
+ public async send(
options:
| string
| {
- text?: string;
- contentType?: number;
- contentMetadata?: LooseType;
- relatedMessageId?: string;
- location?: LINETypes.Location;
- },
+ text?: string;
+ contentType?: number;
+ contentMetadata?: any;
+ relatedMessageId?: string;
+ location?: LINETypes.Location;
+ },
): Promise {
if (typeof options === "string") {
- return this.send({ text: options });
+ return await this.send({ text: options });
} else {
- const _options: LooseType = options;
+ const _options: any = options;
_options.squareChatMid = this.mid;
- return this.client.sendSquareMessage(_options);
+ return await this.client.square.sendMessage(_options);
}
}
public IS_POLLING: boolean = false;
@@ -337,13 +366,14 @@ export class SquareChat extends TypedEventEmitter {
/**
* @description start listen (fetchSquareChatEvents)
*/
- public async startPolling(): Promise {
+ public async polling(): Promise {
if (!this.syncToken) {
while (true) {
- const noneEvent = await this.client.fetchSquareChatEvents({
- squareChatMid: this.mid,
- syncToken: this.syncToken,
- });
+ const noneEvent = await this.client.square
+ .fetchSquareChatEvents({
+ squareChatMid: this.mid,
+ syncToken: this.syncToken,
+ });
this.syncToken = noneEvent.syncToken;
if (noneEvent.events.length === 0) {
break;
@@ -352,21 +382,28 @@ export class SquareChat extends TypedEventEmitter {
}
this.IS_POLLING = true;
this.emit("update:syncToken", this.syncToken);
- while (this.IS_POLLING && this.client.metadata?.authToken) {
+ while (this.IS_POLLING && this.client.authToken) {
try {
- const response = await this.client.fetchSquareChatEvents({
- squareChatMid: this.mid,
- syncToken: this.syncToken,
- });
+ const response = await this.client.square.fetchSquareChatEvents(
+ {
+ squareChatMid: this.mid,
+ syncToken: this.syncToken,
+ },
+ );
if (this.syncToken !== response.syncToken) {
this.emit("update:syncToken", response.syncToken);
this.syncToken = response.syncToken;
}
for (const event of response.events) {
this.emit("event", event);
- if (event.type === "SEND_MESSAGE" && event.payload.sendMessage) {
+ if (
+ event.type === "SEND_MESSAGE" &&
+ event.payload.sendMessage
+ ) {
const message = new SquareMessage(
- { squareEventSendMessage: event.payload.sendMessage },
+ {
+ squareEventSendMessage: event.payload.sendMessage,
+ },
this.client,
);
this.emit("message", message);
@@ -375,16 +412,22 @@ export class SquareChat extends TypedEventEmitter {
event.payload.receiveMessage
) {
const message = new SquareMessage(
- { squareEventReceiveMessage: event.payload.receiveMessage },
+ {
+ squareEventReceiveMessage: event.payload.receiveMessage,
+ },
this.client,
);
this.emit("message", message);
}
}
- await new Promise((resolve) => setTimeout(resolve, 1000));
- } catch (e) {
- this.client.log("SquareChatPollingError", e);
- await new Promise((resolve) => setTimeout(resolve, 2000));
+ await new Promise((resolve) =>
+ setTimeout(resolve, this.polling_delay)
+ );
+ } catch (error) {
+ this.client.log("SquareChatPollingError", { error });
+ await new Promise((resolve) =>
+ setTimeout(resolve, this.polling_delay)
+ );
}
}
}
@@ -406,7 +449,7 @@ export class SquareMember extends TypedEventEmitter {
public joinMessage?: string;
constructor(
public rawMember: LINETypes.SquareMember,
- private client: Client,
+ private client: BaseClient,
) {
super();
@@ -427,11 +470,10 @@ export class SquareMember extends TypedEventEmitter {
*/
static async from(
squareMemberMid: string,
- client: Client,
+ client: BaseClient,
): Promise {
return new this(
- await client
- .getSquareMember({ squareMemberMid })
+ await client.square.getSquareMember({ squareMemberMid })
.then((r) => r.squareMember),
client,
);
diff --git a/packages/linejs/client/entities/talk-class.ts b/packages/linejs/base/event/talk-class.ts
similarity index 66%
rename from packages/linejs/client/entities/talk-class.ts
rename to packages/linejs/base/event/talk-class.ts
index 69cae16f..92d851f2 100644
--- a/packages/linejs/client/entities/talk-class.ts
+++ b/packages/linejs/base/event/talk-class.ts
@@ -5,12 +5,11 @@
*/
import type * as LINETypes from "@evex/linejs-types";
import { parseEnum } from "@evex/linejs-types/thrift";
-import type { Client } from "../index.ts";
-import type { LooseType } from "./common.ts";
+import type { BaseClient } from "../core/mod.ts";
import type { Buffer } from "node:buffer";
-import { TypedEventEmitter } from "../libs/typed-event-emitter/index.ts";
-import { TalkMessage, Message } from "./message-class.ts";
-import type { TimelineResponse } from "./timeline.ts";
+import { TypedEventEmitter } from "../core/typed-event-emitter/index.ts";
+import { Message, TalkMessage } from "./message-class.ts";
+import type { TimelineResponse } from "../timeline/mod.ts";
type GroupEvents = {
message: (message: TalkMessage) => void;
@@ -79,11 +78,11 @@ function toBit(num: number): number[] {
export class Note {
constructor(
- public mid: string,
- private client: Client,
+ mid: string,
+ private client: BaseClient,
) {}
- public createPost(options: {
+ createPost(options: {
text?: string;
sharedPostId?: string;
textSizeMode?: "AUTO" | "NORMAL";
@@ -101,17 +100,17 @@ export class Note {
mediaObjectTypes?: string[];
sourceType?: string;
}): Promise {
- (options as LooseType).homeId = this.mid;
- return this.client.createPost(options as LooseType);
+ (options as any).homeId = this.mid;
+ return this.client.timeline.createPost(options as any);
}
- public deletePost(options: {
+ deletePost(options: {
postId: string;
}): Promise {
- (options as LooseType).homeId = this.mid;
- return this.client.deletePost(options as LooseType);
+ (options as any).homeId = this.mid;
+ return this.client.timeline.deletePost(options as any);
}
- public listPost(
+ listPost(
options: {
homeId?: string;
postId?: string;
@@ -119,22 +118,22 @@ export class Note {
sourceType?: string;
} = {},
): Promise {
- (options as LooseType).homeId = this.mid;
- return this.client.listPost(options as LooseType);
+ (options as any).homeId = this.mid;
+ return this.client.timeline.listPost(options as any);
}
- public getPost(options: {
+ getPost(options: {
postId: string;
}): Promise {
- (options as LooseType).homeId = this.mid;
- return this.client.getPost(options as LooseType);
+ (options as any).homeId = this.mid;
+ return this.client.timeline.getPost(options as any);
}
- public sharePost(options: {
+ sharePost(options: {
postId: string;
chatMid: string;
}): Promise {
- (options as LooseType).homeId = this.mid;
- return this.client.sharePost(options as LooseType);
+ (options as any).homeId = this.mid;
+ return this.client.timeline.sharePost(options as any);
}
}
@@ -142,72 +141,68 @@ export class Note {
* @description LINE user (contact) utils
*/
export class User extends TypedEventEmitter {
- public rawSource: LINETypes.Contact;
- public mid: string;
- public createdTime: Date;
- public type: LINETypes.ContactType;
- public status: LINETypes.ContactStatus;
- public relation: LINETypes.ContactRelation;
- public displayName: string;
- public phoneticName: string;
- public pictureStatus: string;
- public thumbnailUrl: string;
- public statusMessage: string;
- public displayNameOverridden: string;
- public favoriteTime: Date;
- public capableVoiceCall: boolean;
- public capableVideoCall: boolean;
- public capableMyhome: boolean;
- public capableBuddy: boolean;
- public attributes: number;
- public picturePath: string;
- public recommendParams: string;
- public friendRequestStatus: LINETypes.FriendRequestStatus;
- public musicProfile: string;
- public videoProfile: string;
- public statusMessageContentMetadata: { [k: string]: string };
- public avatarProfile: LINETypes.AvatarProfile;
- public friendRingtone: string;
- public friendRingbackTone: string;
- public nftProfile: boolean;
- public pictureSource: LINETypes.PictureSource;
- public groupStatus: Record & {
+ rawSource: LINETypes.Contact;
+ mid: string;
+ createdTime: Date;
+ type: LINETypes.ContactType;
+ status: LINETypes.ContactStatus;
+ relation: LINETypes.ContactRelation;
+ displayName: string;
+ phoneticName: string;
+ pictureStatus: string;
+ thumbnailUrl: string;
+ statusMessage: string;
+ displayNameOverridden: string;
+ favoriteTime: Date;
+ capableVoiceCall: boolean;
+ capableVideoCall: boolean;
+ capableMyhome: boolean;
+ capableBuddy: boolean;
+ attributes: number;
+ picturePath: string;
+ recommendParams: string;
+ friendRequestStatus: LINETypes.FriendRequestStatus;
+ musicProfile: string;
+ videoProfile: string;
+ statusMessageContentMetadata: { [k: string]: string };
+ avatarProfile: LINETypes.AvatarProfile;
+ friendRingtone: string;
+ friendRingbackTone: string;
+ nftProfile: boolean;
+ pictureSource: LINETypes.Pb1_N6;
+ groupStatus: Record & {
joinedAt?: Date;
invitedAt?: Date;
} = {};
- public birthday: LINETypes.ContactCalendarEvent;
/**
* @description Generate from mid.
*/
- static async from(mid: string, client: Client): Promise {
- if (mid === client.user?.mid) {
+ static async from(mid: string, client: BaseClient): Promise {
+ if (mid === client.profile?.mid) {
return new this(
{
- ...(await client.getContactsV2({ mids: [mid] })).contacts[mid],
- contact: await client.getContact({ mid }, false),
+ ...(await client.talk.getContactsV2({ mids: [mid] }))
+ .contacts[mid],
+ contact: await client.talk.getContact({ mid }),
},
client,
);
}
return new this(
- (await client.getContactsV2({ mids: [mid] })).contacts[mid],
+ (await client.talk.getContactsV2({ mids: [mid] })).contacts[mid],
client,
);
}
constructor(
contactEntry: LINETypes.ContactEntry,
- private client: Client,
+ private client: BaseClient,
) {
super();
const { contact } = contactEntry;
- this.birthday =
- contactEntry.calendarEvents?.events &&
- contactEntry.calendarEvents.events[0];
this.rawSource = contact;
- console.log(contactEntry);
this.mid = contact.mid;
this.createdTime = new Date((contact.createdTime as number) * 1000);
this.type = contact.type;
@@ -241,51 +236,61 @@ export class User extends TypedEventEmitter {
/**
* @description Send msg to user.
*/
- public send(
+ send(
options:
| string
| {
- text?: string;
- contentType?: number;
- contentMetadata?: LooseType;
- relatedMessageId?: string;
- location?: LINETypes.Location;
- chunk?: string[] | Buffer[];
- e2ee?: boolean;
- },
+ text?: string;
+ contentType?: number;
+ contentMetadata?: any;
+ relatedMessageId?: string;
+ location?: LINETypes.Location;
+ chunk?: string[] | Buffer[];
+ e2ee?: boolean;
+ },
): Promise {
if (typeof options === "string") {
return this.send({ text: options });
} else {
- const _options: LooseType = options;
+ const _options: any = options;
_options.to = this.mid;
- return this.client.sendMessage(_options);
+ return this.client.talk.sendMessage(_options);
}
}
/**
* @description Kickout from group.
*/
- public kick(chatMid: string): Promise {
- return this.client.deleteOtherFromChat({ to: chatMid, mid: this.mid });
+ kick(
+ chatMid: string,
+ ): Promise {
+ return this.client.talk.deleteOtherFromChat({
+ request: {
+ targetUserMids: [this.mid],
+ chatMid,
+ },
+ });
}
/**
* @description Invite to group.
*/
- public invite(chatMid: string): Promise {
- return this.client.inviteIntoChat({ to: chatMid, mids: [this.mid] });
+ async invite(chatMid: string): Promise {
+ await this.client.talk.inviteIntoChat({
+ chatMid,
+ targetUserMids: [this.mid],
+ });
}
/**
* @description Add to friend.
*/
- public addFriend(): Promise {
- return this.client.addFriendByMid({ mid: this.mid });
+ async addFriend(): Promise {
+ return await this.client.relation.addFriendByMid({ mid: this.mid });
}
- public isMe(): boolean {
- return this.client.user?.mid === this.mid;
+ isMe(): boolean {
+ return this.client.profile?.mid === this.mid;
}
}
@@ -293,30 +298,29 @@ export class User extends TypedEventEmitter {
* @description LINE group (chat) utils
*/
export class Group extends TypedEventEmitter {
- public rawSource: LINETypes.Chat;
- public mid: string;
- public createdTime: Date;
- public name: string;
- public picturePath: string;
- public preventedJoinByTicket: boolean;
- public invitationTicket: string;
- public notificationDisabled: boolean;
- public note: Note;
+ rawSource: LINETypes.Chat;
+ mid: string;
+ createdTime: Date;
+ name: string;
+ picturePath: string;
+ preventedJoinByTicket: boolean;
+ invitationTicket: string;
+ notificationDisabled: boolean;
+ note: Note;
/**
* @description Generate from groupMid or {Chat}.
*/
static async from(
gidOrChat: string | LINETypes.Chat,
- client: Client,
+ client: BaseClient,
): Promise {
- const chat: LINETypes.Chat =
- typeof gidOrChat === "string"
- ? await client.getChat({ gid: gidOrChat })
- : gidOrChat;
+ const chat: LINETypes.Chat = typeof gidOrChat === "string"
+ ? await client.talk.getChat({ chatMid: gidOrChat })
+ : gidOrChat;
const creator = await User.from(chat.extra.groupExtra.creator, client);
const _members = (
- await client.getContactsV2({
+ await client.talk.getContactsV2({
mids: Object.keys(chat.extra.groupExtra.memberMids),
})
).contacts;
@@ -324,11 +328,11 @@ export class Group extends TypedEventEmitter {
for (const key in _members) {
if (Object.prototype.hasOwnProperty.call(_members, key)) {
let user: User;
- if (key === client.user?.mid) {
+ if (key === client.profile?.mid) {
user = new User(
{
..._members[key],
- contact: await client.getContact({ mid: key }),
+ contact: await client.talk.getContact({ mid: key }),
},
client,
);
@@ -342,7 +346,7 @@ export class Group extends TypedEventEmitter {
}
}
const _invitee = (
- await client.getContactsV2({
+ await client.talk.getContactsV2({
mids: Object.keys(chat.extra.groupExtra.inviteeMids),
})
).contacts;
@@ -350,11 +354,11 @@ export class Group extends TypedEventEmitter {
for (const key in _invitee) {
if (Object.prototype.hasOwnProperty.call(_invitee, key)) {
let user: User;
- if (key === client.user?.mid) {
+ if (key === client.profile?.mid) {
user = new User(
{
..._invitee[key],
- contact: await client.getContact({ mid: key }),
+ contact: await client.talk.getContact({ mid: key }),
},
client,
);
@@ -372,10 +376,10 @@ export class Group extends TypedEventEmitter {
}
constructor(
chat: LINETypes.Chat,
- private client: Client,
- public creator: User,
- public members: User[],
- public invitee: User[],
+ private client: BaseClient,
+ creator: User,
+ members: User[],
+ invitee: User[],
) {
super();
@@ -395,59 +399,72 @@ export class Group extends TypedEventEmitter {
/**
* @description Send msg to group.
*/
- public send(
+ async send(
options:
| string
| {
- text?: string;
- contentType?: number;
- contentMetadata?: LooseType;
- relatedMessageId?: string;
- location?: LINETypes.Location;
- chunk?: string[] | Buffer[];
- e2ee?: boolean;
- },
+ text?: string;
+ contentType?: number;
+ contentMetadata?: any;
+ relatedMessageId?: string;
+ location?: LINETypes.Location;
+ chunk?: string[] | Buffer[];
+ e2ee?: boolean;
+ },
): Promise {
if (typeof options === "string") {
- return this.send({ text: options });
+ return await this.send({ text: options });
} else {
- const _options: LooseType = options;
+ const _options: any = options;
_options.to = this.mid;
- return this.client.sendMessage(_options);
+ return await this.client.talk.sendMessage(_options);
}
}
/**
* @description Update group status.
*/
- public set(options: {
+ async set(options: {
chatSet: Partial;
- updatedAttribute: LINETypes.ChatAttribute;
- }): Promise {
- const _options: LooseType = options;
+ updatedAttribute: LINETypes.Pb1_O2;
+ }): Promise {
+ const _options: any = options;
_options.chatMid = this.mid;
- return this.client.updateChat(_options);
+ return await this.client.talk.updateChat(_options);
}
/**
* @description Update group name.
*/
- public setName(name: string): Promise {
- return this.set({ chatSet: { chatName: name }, updatedAttribute: 1 });
+ async setName(name: string): Promise {
+ return await this.set({
+ chatSet: { chatName: name },
+ updatedAttribute: "NAME",
+ });
}
/**
* @description Invite user.
*/
- public invite(mids: string[]): Promise {
- return this.client.inviteIntoChat({ to: this.mid, mids });
+ async invite(
+ mids: string[],
+ ): Promise {
+ return await this.client.talk.inviteIntoChat({
+ targetUserMids: mids,
+ chatMid: this.mid,
+ });
}
/**
* @description Kickout user.
*/
- public kick(mid: string): Promise {
- return this.client.deleteOtherFromChat({ to: this.mid, mid: mid });
+ kick(mid: string): Promise {
+ return this.client.talk.deleteOtherFromChat({
+ request: {
+ targetUserMids: [mid],
+ chatMid: this.mid,
+ },
+ });
}
}
@@ -455,17 +472,17 @@ export class Group extends TypedEventEmitter {
* @description LINE talk event utils
*/
export class Operation {
- public rawSource: LINETypes.Operation;
- protected client?: Client;
- public message?: Message | TalkMessage;
- public revision: number;
- public createdTime: Date;
- public type: LINETypes.OpType;
- public reqSeq: number = 0;
- public checksum?: string;
- public status?: "ALERT_DISABLED" | LINETypes.OpStatus;
- public param: { 1?: string; 2?: string; 3?: string } = {};
- public event?:
+ rawSource: LINETypes.Operation;
+ protected client?: BaseClient;
+ message?: TalkMessage;
+ revision: number;
+ createdTime: Date;
+ type: LINETypes.OpType;
+ reqSeq: number = 0;
+ checksum?: string;
+ status?: "ALERT_DISABLED" | LINETypes.Pb1_EnumC13127p6;
+ param: { 1?: string; 2?: string; 3?: string } = {};
+ event?:
| SendChatRemoved
| SendChatChecked
| NotifiedReadMessage
@@ -484,19 +501,20 @@ export class Operation {
constructor(
source: LINETypes.Operation,
- client?: Client,
- emit: boolean = false,
+ client: BaseClient,
) {
this.rawSource = source;
this.client = client;
this.revision = source.revision as number;
this.checksum = source.checksum;
this.createdTime = new Date((source.createdTime as number) * 1000);
- this.type =
- (parseEnum("OpType", source.type) as LINETypes.OpType) || source.type;
+ this.type = (parseEnum("OpType", source.type) as LINETypes.OpType) ||
+ source.type;
this.reqSeq = source.reqSeq;
- this.status =
- (parseEnum("OpStatus", source.status) as LINETypes.OpStatus) ||
+ this.status = (parseEnum(
+ "Pb1_EnumC13127p6",
+ source.status,
+ ) as LINETypes.Pb1_EnumC13127p6) ||
source.status;
this.param = {
1: source.param1,
@@ -508,11 +526,10 @@ export class Operation {
source.type === "SEND_MESSAGE" ||
source.type === "SEND_CONTENT"
) {
- if (client) {
- this.message = new TalkMessage({ message: source.message }, client);
- } else {
- this.message = new Message({ message: source.message });
- }
+ this.message = new TalkMessage(
+ { message: source.message },
+ client,
+ );
}
if (source.type == "SEND_CHAT_REMOVED") {
this.event = new SendChatRemoved(this);
@@ -547,9 +564,6 @@ export class Operation {
} else if (source.type == "NOTIFIED_DELETE_OTHER_FROM_CHAT") {
this.event = new DeleteOtherFromChat(this);
}
- if (emit && client) {
- client.emit("event", source);
- }
}
}
@@ -557,9 +571,9 @@ export class Operation {
* @description you unsend the message
*/
export class DestroyMessage {
- public readonly name: string = "DestroyMessage";
- public messageId: string;
- public chatMid: string;
+ readonly type: string = "DestroyMessage";
+ messageId: string;
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "DESTROY_MESSAGE") {
@@ -580,9 +594,9 @@ export class DestroyMessage {
* @description the user unsend the message
*/
export class NotifiedDestroyMessage {
- public readonly name: string = "NotifiedDestroyMessage";
- public messageId: string;
- public chatMid: string;
+ readonly type: string = "NotifiedDestroyMessage";
+ messageId: string;
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "NOTIFIED_DESTROY_MESSAGE") {
@@ -603,9 +617,9 @@ export class NotifiedDestroyMessage {
* @description the user joined the chat
*/
export class NotifiedJoinChat {
- public readonly name: string = "NotifiedJoinChat";
- public userMid: string;
- public chatMid: string;
+ readonly type: string = "NotifiedJoinChat";
+ userMid: string;
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "NOTIFIED_JOIN_CHAT") {
@@ -626,9 +640,9 @@ export class NotifiedJoinChat {
* @description the user accepted the chat invitation
*/
export class NotifiedAcceptChatInvitation {
- public readonly name: string = "NotifiedAcceptChatInvitation";
- public userMid: string;
- public chatMid: string;
+ readonly type: string = "NotifiedAcceptChatInvitation";
+ userMid: string;
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "NOTIFIED_ACCEPT_CHAT_INVITATION") {
@@ -649,9 +663,9 @@ export class NotifiedAcceptChatInvitation {
* @description the user was invited into chat by you
*/
export class InviteIntoChat {
- public readonly name: string = "InviteIntoChat";
- public userMid: string;
- public chatMid: string;
+ readonly type: string = "InviteIntoChat";
+ userMid: string;
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "INVITE_INTO_CHAT") {
@@ -672,8 +686,8 @@ export class InviteIntoChat {
* @description you left the chat
*/
export class DeleteSelfFromChat {
- public readonly name: string = "DeleteSelfFromChat";
- public chatMid: string;
+ readonly type: string = "DeleteSelfFromChat";
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "DELETE_SELF_FROM_CHAT") {
@@ -690,9 +704,9 @@ export class DeleteSelfFromChat {
* @description the user left (kicked) the chat
*/
export class NotifiedLeaveChat {
- public readonly name: string = "NotifiedLeaveChat";
- public userMid: string;
- public chatMid: string;
+ readonly type: string = "NotifiedLeaveChat";
+ userMid: string;
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "NOTIFIED_LEAVE_CHAT") {
@@ -713,9 +727,9 @@ export class NotifiedLeaveChat {
* @description the other user was kicked from chat by you
*/
export class DeleteOtherFromChat {
- public readonly name: string = "DeleteOtherFromChat";
- public userMid: string;
- public chatMid: string;
+ readonly type: string = "DeleteOtherFromChat";
+ userMid: string;
+ chatMid: string;
constructor(op: Operation) {
if (op.type !== "DELETE_OTHER_FROM_CHAT") {
@@ -736,9 +750,9 @@ export class DeleteOtherFromChat {
* @description the profile content was updated by user
*/
export class NotifiedUpdateProfileContent {
- public readonly name: string = "NotifiedUpdateProfileContent";
- public userMid: string;
- public profileAttributes: (LINETypes.ProfileAttribute | null)[] = [];
+ readonly type: string = "NotifiedUpdateProfileContent";
+ userMid: string;
+ profileAttributes: (LINETypes.Pb1_K6 | null)[] = [];
constructor(op: Operation) {
if (op.type !== "NOTIFIED_UPDATE_PROFILE_CONTENT") {
@@ -753,17 +767,16 @@ export class NotifiedUpdateProfileContent {
this.userMid = op.param[1];
const attr = parseEnum("ProfileAttribute", op.param[2]);
if (attr !== null) {
- this.profileAttributes[0] =
- attr as LooseType as LINETypes.ProfileAttribute;
+ this.profileAttributes[0] = attr as any as LINETypes.Pb1_K6;
} else {
- const arr: LINETypes.ProfileAttribute[] = [];
+ const arr: LINETypes.Pb1_K6[] = [];
toBit(parseInt(op.param[2])).forEach((e, i) => {
if (e === 1) {
arr.push(
parseEnum(
"ProfileAttribute",
2 ** i,
- ) as LooseType as LINETypes.ProfileAttribute,
+ ) as any as LINETypes.Pb1_K6,
);
}
});
@@ -776,10 +789,10 @@ export class NotifiedUpdateProfileContent {
* @description the profile was updated by user
*/
export class NotifiedUpdateProfile {
- public readonly name: string = "NotifiedUpdateProfile";
- public userMid: string;
- public profileAttributes: (LINETypes.ProfileAttribute | null)[] = [];
- public info: Record = {};
+ readonly type: string = "NotifiedUpdateProfile";
+ userMid: string;
+ profileAttributes: (LINETypes.Pb1_K6 | null)[] = [];
+ info: Record = {};
constructor(op: Operation) {
if (op.type !== "NOTIFIED_UPDATE_PROFILE") {
@@ -795,17 +808,16 @@ export class NotifiedUpdateProfile {
this.userMid = op.param[1];
const attr = parseEnum("ProfileAttribute", op.param[2]);
if (attr !== null) {
- this.profileAttributes[0] =
- attr as LooseType as LINETypes.ProfileAttribute;
+ this.profileAttributes[0] = attr as any as LINETypes.Pb1_K6;
} else {
- const arr: LINETypes.ProfileAttribute[] = [];
+ const arr: LINETypes.Pb1_K6[] = [];
toBit(parseInt(op.param[2])).forEach((e, i) => {
if (e === 1) {
arr.push(
parseEnum(
"ProfileAttribute",
2 ** i,
- ) as LooseType as LINETypes.ProfileAttribute,
+ ) as any as LINETypes.Pb1_K6,
);
}
});
@@ -819,9 +831,9 @@ export class NotifiedUpdateProfile {
* @description the profile was updated by you
*/
export class UpdateProfile {
- public readonly name: string = "UpdateProfile";
- public profileAttributes: (LINETypes.ProfileAttribute | null)[] = [];
- public info: Record = {};
+ readonly type: string = "UpdateProfile";
+ profileAttributes: (LINETypes.Pb1_K6 | null)[] = [];
+ info: Record = {};
constructor(op: Operation) {
if (op.type !== "UPDATE_PROFILE") {
@@ -835,17 +847,16 @@ export class UpdateProfile {
}
const attr = parseEnum("ProfileAttribute", op.param[1]);
if (attr !== null) {
- this.profileAttributes[0] =
- attr as LooseType as LINETypes.ProfileAttribute;
+ this.profileAttributes[0] = attr as any as LINETypes.Pb1_K6;
} else {
- const arr: LINETypes.ProfileAttribute[] = [];
+ const arr: LINETypes.Pb1_K6[] = [];
toBit(parseInt(op.param[1])).forEach((e, i) => {
if (e === 1) {
arr.push(
parseEnum(
"ProfileAttribute",
2 ** i,
- ) as LooseType as LINETypes.ProfileAttribute,
+ ) as any as LINETypes.Pb1_K6,
);
}
});
@@ -859,11 +870,11 @@ export class UpdateProfile {
* @description the message was reacted by ypu
*/
export class SendReaction {
- public readonly name: string = "SendReaction";
- public chatMid: string;
- public chatType: LINETypes.MIDType;
- public messageId: string;
- public reactionType: LINETypes.PredefinedReactionType;
+ readonly type: string = "SendReaction";
+ chatMid: string;
+ chatType: LINETypes.MIDType;
+ messageId: string;
+ reactionType: LINETypes.MessageReactionType;
constructor(op: Operation) {
if (op.type !== "SEND_REACTION") {
throw new TypeError("Wrong operation type");
@@ -877,11 +888,11 @@ export class SendReaction {
this.messageId = op.param[1];
const data = JSON.parse(op.param[2]);
this.chatMid = data.chatMid;
- this.chatType = getMidType(this.chatMid) as LooseType;
+ this.chatType = getMidType(this.chatMid) as any;
this.reactionType = parseEnum(
- "PredefinedReactionType",
+ "MessageReactionType",
data.curr.predefinedReactionType,
- ) as LINETypes.PredefinedReactionType;
+ ) as LINETypes.MessageReactionType;
}
}
@@ -889,12 +900,12 @@ export class SendReaction {
* @description the message was reacted by user
*/
export class NotifiedSendReaction {
- public readonly name: string = "NotifiedSendReaction";
- public chatMid: string;
- public chatType: LINETypes.MIDType;
- public messageId: string;
- public userMid: string;
- public reactionType: LINETypes.PredefinedReactionType;
+ readonly type: string = "NotifiedSendReaction";
+ chatMid: string;
+ chatType: LINETypes.MIDType;
+ messageId: string;
+ userMid: string;
+ reactionType: LINETypes.MessageReactionType;
constructor(op: Operation) {
if (op.type !== "NOTIFIED_SEND_REACTION") {
throw new TypeError("Wrong operation type");
@@ -910,11 +921,11 @@ export class NotifiedSendReaction {
this.userMid = op.param[3];
const data = JSON.parse(op.param[2]);
this.chatMid = data.chatMid;
- this.chatType = getMidType(this.chatMid) as LooseType;
+ this.chatType = getMidType(this.chatMid) as any;
this.reactionType = parseEnum(
- "PredefinedReactionType",
+ "MessageReactionType",
data.curr.predefinedReactionType,
- ) as LINETypes.PredefinedReactionType;
+ ) as LINETypes.MessageReactionType;
}
}
@@ -922,11 +933,11 @@ export class NotifiedSendReaction {
* @description the message was read by user
*/
export class NotifiedReadMessage {
- public readonly name: string = "NotifiedReadMessage";
- public chatMid: string;
- public chatType: LINETypes.MIDType;
- public messageId: string;
- public userMid: string;
+ readonly type: string = "NotifiedReadMessage";
+ chatMid: string;
+ chatType: LINETypes.MIDType;
+ messageId: string;
+ userMid: string;
constructor(op: Operation) {
if (op.type !== "NOTIFIED_READ_MESSAGE") {
@@ -942,7 +953,7 @@ export class NotifiedReadMessage {
this.chatMid = op.param[1];
this.userMid = op.param[2];
this.messageId = op.param[3];
- this.chatType = getMidType(op.param[1]) as LooseType;
+ this.chatType = getMidType(op.param[1]) as any;
}
}
@@ -950,10 +961,10 @@ export class NotifiedReadMessage {
* @description the message was read by you
*/
export class SendChatChecked {
- public readonly name: string = "SendChatChecked";
- public chatMid: string;
- public chatType: LINETypes.MIDType;
- public messageId: string;
+ readonly type: string = "SendChatChecked";
+ chatMid: string;
+ chatType: LINETypes.MIDType;
+ messageId: string;
constructor(op: Operation) {
if (op.type !== "SEND_CHAT_CHECKED") {
@@ -967,7 +978,7 @@ export class SendChatChecked {
}
this.chatMid = op.param[1];
this.messageId = op.param[2];
- this.chatType = getMidType(op.param[1]) as LooseType;
+ this.chatType = getMidType(op.param[1]) as any;
}
}
@@ -975,10 +986,10 @@ export class SendChatChecked {
* @description the chatroom history was removed by you
*/
export class SendChatRemoved {
- public readonly name: string = "SendChatRemoved";
- public chatMid: string;
- public chatType: LINETypes.MIDType | null;
- public messageId: string;
+ readonly type: string = "SendChatRemoved";
+ chatMid: string;
+ chatType: LINETypes.MIDType | null;
+ messageId: string;
constructor(op: Operation) {
if (op.type !== "SEND_CHAT_REMOVED") {
diff --git a/packages/linejs/base/login/mod.ts b/packages/linejs/base/login/mod.ts
new file mode 100644
index 00000000..a42d85e6
--- /dev/null
+++ b/packages/linejs/base/login/mod.ts
@@ -0,0 +1,758 @@
+import { getRSACrypto } from "./rsa-verify.ts";
+import { EMAIL_REGEX, PASSWORD_REGEX } from "./regex.ts";
+import { type Device, isV3Support } from "../core/utils/devices.ts";
+import { InternalError } from "../core/mod.ts";
+import type * as LINETypes from "@evex/linejs-types";
+import { Buffer } from "node:buffer";
+import { LINEStruct } from "../thrift/mod.ts";
+import type { BaseClient } from "../core/mod.ts";
+
+export type LoginOption = PasswordLoginOption | QrCodeLoginOption | {
+ authToken: string;
+ email?: undefined;
+ qr?: undefined;
+};
+
+interface LoginVer {
+ loginV2: any;
+ loginZ: LINETypes.LoginResult;
+}
+
+export interface PasswordLoginOption {
+ /**
+ * account e-mail address
+ */
+ email: string;
+ /**
+ * account password
+ */
+ password: string;
+ /**
+ * Custom pin-code. It have to be 6-digit.
+ */
+ pincode?: string;
+ /**
+ * use v3 login or not.
+ */
+ v3?: boolean;
+ /**
+ * use e2ee login or not.
+ * @default true
+ */
+ e2ee?: boolean;
+ qr?: undefined;
+
+ authToken?: undefined;
+}
+
+export interface QrCodeLoginOption {
+ email?: undefined;
+ authToken?: undefined;
+ qr?: true;
+ /**
+ * use v3 login or not.
+ */
+ v3?: boolean;
+}
+
+export class Login {
+ readonly client: BaseClient;
+ cert: string | null;
+ qrCert: string | null;
+ constructor(client: BaseClient) {
+ this.client = client;
+ this.qrCert = null;
+ this.cert = null;
+ }
+
+ /**
+ * @description Registers a certificate to be used for login.
+ *
+ * @param {string | null} cert - The certificate to register. If null, the certificate will be cleared.
+ */
+ public async registerCert(cert: string, email: string): Promise {
+ await this.client.storage.set("cert:" + email, cert);
+ }
+
+ /**
+ * @description Reads the certificate from the registered path, if it exists.
+ *
+ * @return {Promise} The certificate, or undefined if it does not exist or an error occurred.
+ */
+ public async getCert(email: string): Promise {
+ return await this.client.storage.get("cert:" + email) as string;
+ }
+
+ /**
+ * @description Registers a certificate to be used for login.
+ *
+ * @param {string | null} qrCert - The certificate to register. If null, the certificate will be cleared.
+ */
+ public async registerQrCert(qrCert: string): Promise {
+ await this.client.storage.set("qrCert", qrCert);
+ }
+
+ /**
+ * @description Reads the certificate from the registered path, if it exists.
+ *
+ * @return {Promise} The certificate, or undefined if it does not exist or an error occurred.
+ */
+ public async getQrCert(): Promise {
+ return await this.client.storage.get("qrCert") as string;
+ }
+
+ async ready(): Promise {
+ if (!this.client.authToken) {
+ throw new InternalError("NotAuthorized", "try login first");
+ }
+ this.client.profile = await this.client.talk.getProfile();
+ this.client.emit("ready", this.client.profile);
+ }
+
+ /**
+ * Logs in the user using the provided options.
+ *
+ * Depending on the options provided, this method will:
+ * - Use QR code authentication if no options are provided or if `options.qr` is true.
+ * - Use an authentication token if `options.authToken` is provided.
+ * - Use email and password authentication if `options.email` is provided.
+ *
+ * @param {LoginOption} [options] - The login options.
+ * @param {boolean} [options.qr] - Whether to use QR code authentication.
+ * @param {boolean} [options.v3] - Whether to use version 3 of QR code authentication.
+ * @param {string} [options.authToken] - The authentication token.
+ * @param {string} [options.email] - The user's email.
+ * @param {string} [options.password] - The user's password.
+ *
+ * @example
+ * // Login with QR code
+ * await login();
+ *
+ * @example
+ * // Login with authentication token
+ * await login({ authToken: 'your-auth-token' });
+ *
+ * @example
+ * // Login with email and password
+ * await login({ email: 'user@example.com', password: 'your-password' });
+ */
+ async login(
+ options?: LoginOption,
+ ) {
+ if (!options) {
+ await this.withQrCode();
+ } else if (options.qr) {
+ await this.withQrCode({ v3: options.v3 });
+ } else if (options.authToken) {
+ this.client.emit("update:authtoken", options.authToken);
+ this.client.authToken = options.authToken;
+ } else if (options.email) {
+ await this.withPassword(options);
+ } else {
+ await this.withQrCode();
+ }
+ await this.ready();
+ }
+ /**
+ * Login with qrcode.
+ * @param options.v3 use v3 login or not.
+ */
+ async withQrCode(options?: QrCodeLoginOption): Promise {
+ let authToken: string;
+ if (
+ typeof options === "undefined" || typeof options.v3 === "undefined"
+ ) {
+ if (isV3Support(this.client.device)) {
+ authToken = await this.requestSQR2();
+ } else {
+ authToken = await this.requestSQR();
+ }
+ } else {
+ if (options.v3) {
+ authToken = await this.requestSQR2();
+ } else {
+ authToken = await this.requestSQR();
+ }
+ }
+ this.client.emit("update:authtoken", authToken);
+ this.client.authToken = authToken;
+ }
+
+ public async requestSQR(): Promise {
+ const { 1: sqr } = await this.createSession();
+ let { 1: url } = await this.createQrCode(sqr);
+ const [secret, secretUrl] = this.client.e2ee.createSqrSecret();
+ url = url + secretUrl;
+ this.client.emit("qrcall", url);
+ if (await this.checkQrCodeVerified(sqr)) {
+ try {
+ await this.verifyCertificate(sqr, await this.getQrCert());
+ } catch (_e) {
+ const { 1: pincode } = await this.createPinCode(sqr);
+ this.client.emit("pincall", pincode);
+ await this.checkPinCodeVerified(sqr);
+ }
+ const response = await this.qrCodeLogin(sqr);
+ const { 1: pem, 2: authToken, 4: e2eeInfo, 5: _mid } = response;
+ if (pem) {
+ this.client.emit("update:qrcert", pem);
+ await this.registerQrCert(pem);
+ }
+ if (e2eeInfo) {
+ await this.client.e2ee.decodeE2EEKeyV1(
+ e2eeInfo,
+ Buffer.from(secret),
+ );
+ }
+ return authToken;
+ }
+ throw new InternalError(
+ "TimeoutError",
+ "checkQrCodeVerified timed out",
+ );
+ }
+
+ public async requestSQR2(): Promise {
+ const { 1: sqr } = await this.createSession();
+ let { 1: url } = await this.createQrCode(sqr);
+ const [secret, secretUrl] = this.client.e2ee.createSqrSecret();
+ url = url + secretUrl;
+ this.client.emit("qrcall", url);
+ if (await this.checkQrCodeVerified(sqr)) {
+ try {
+ await this.verifyCertificate(sqr, await this.getQrCert());
+ } catch (_e) {
+ const { 1: pincode } = await this.createPinCode(sqr);
+ this.client.emit("pincall", pincode);
+ await this.checkPinCodeVerified(sqr);
+ }
+ const response = await this.qrCodeLogin(sqr);
+ const { 1: pem, 3: tokenInfo, 4: _mid, 10: e2eeInfo } = response;
+ if (pem) {
+ this.client.emit("update:qrcert", pem);
+ await this.registerQrCert(pem);
+ }
+ if (e2eeInfo) {
+ await this.client.e2ee.decodeE2EEKeyV1(
+ e2eeInfo,
+ Buffer.from(secret),
+ );
+ }
+ await this.client.storage.set("refreshToken", tokenInfo[2]);
+ await this.client.storage.set(
+ "expire",
+ tokenInfo[3] + tokenInfo[6],
+ );
+ return tokenInfo[1];
+ }
+ throw new InternalError(
+ "TimeoutError",
+ "checkQrCodeVerified timed out",
+ );
+ }
+
+ /**
+ * Login with email and password.
+ * @param options.email account e-mail address
+ * @param options.password account password
+ * @param options.pincode Custom pin-code. It have to be 6-digit.
+ * @param options.v3 use v3 login or not.
+ * @param options.e2ee use e2ee login or not.
+ */
+ async withPassword(options: PasswordLoginOption): Promise {
+ let authToken: string;
+ if (!EMAIL_REGEX.test(options.email)) {
+ throw new InternalError("RegExpUnmatch", "invalid email");
+ }
+ if (!PASSWORD_REGEX.test(options.password)) {
+ throw new InternalError("RegExpUnmatch", "invalid password");
+ }
+
+ if (typeof options.v3 === "undefined") {
+ if (isV3Support(this.client.device)) {
+ authToken = await this.requestEmailLoginV2(
+ options.email,
+ options.password,
+ options.pincode,
+ );
+ } else {
+ authToken = await this.requestEmailLogin(
+ options.email,
+ options.password,
+ options.pincode,
+ options.e2ee,
+ );
+ }
+ } else {
+ if (options.v3) {
+ authToken = await this.requestEmailLoginV2(
+ options.email,
+ options.password,
+ options.pincode,
+ );
+ } else {
+ authToken = await this.requestEmailLogin(
+ options.email,
+ options.password,
+ options.pincode,
+ options.e2ee,
+ );
+ }
+ }
+ this.client.emit("update:authtoken", authToken);
+ this.client.authToken = authToken;
+ }
+
+ /**
+ * @description Login to LINE server with email and password.
+ *
+ * @param {string} [email] The email to login with.
+ * @param {string} [password] The password to login with.
+ * @param {boolean} [enableE2EE=false] Enable E2EE Login or not.
+ * @param {string} [constantPincode="114514"] The constant pincode.
+ * @returns {Promise} The auth token.
+ * @throws {InternalError} If the system is not setup yet.
+ * @throws {InternalError} If the login type is not supported.
+ * @throws {InternalError} If the constant pincode is not valid.
+ * @emits pincall
+ * @emits update:cert
+ */
+ public async requestEmailLogin(
+ email: string,
+ password: string,
+ constantPincode: string = "114514",
+ enableE2EE: boolean = true,
+ ): Promise {
+ if (constantPincode.length !== 6) {
+ throw new InternalError(
+ "Invalid constant pincode",
+ "The constant pincode should be 6 digits",
+ );
+ }
+
+ this.client.log("login", {
+ method: "email_v1",
+ email,
+ password: password.length,
+ enableE2EE,
+ constantPincode,
+ });
+
+ const rsaKey = await this.getRSAKeyInfo();
+ const { keynm, sessionKey } = rsaKey;
+
+ const message = String.fromCharCode(sessionKey.length) +
+ sessionKey +
+ String.fromCharCode(email.length) +
+ email +
+ String.fromCharCode(password.length) +
+ password;
+
+ let e2eeData: Buffer | undefined,
+ secret: Uint8Array | undefined,
+ secretPK: string | undefined;
+
+ if (enableE2EE) {
+ [secret, secretPK] = this.client.e2ee.createSqrSecret(true);
+ e2eeData = this.client.e2ee.encryptAESECB(
+ this.client.e2ee.getSHA256Sum(constantPincode),
+ Buffer.from(secretPK, "base64"),
+ );
+ }
+
+ const encryptedMessage = getRSACrypto(message, rsaKey).credentials;
+
+ const cert = await this.getCert(email) || undefined;
+
+ let response = await this.loginV2(
+ keynm,
+ encryptedMessage,
+ this.client.device,
+ undefined,
+ e2eeData,
+ cert,
+ "loginZ",
+ );
+
+ if (!response.authToken) {
+ this.client.emit("pincall", response.pinCode || constantPincode);
+ if (enableE2EE && secret) {
+ const headers = {
+ accept: "application/x-thrift",
+ "user-agent": this.client.request.userAgent,
+ "x-line-application": this.client.request.systemType,
+ "x-line-access": response.verifier,
+ "x-lal": "ja_JP",
+ "x-lpv": "1",
+ "x-lhm": "GET",
+ "accept-encoding": "gzip",
+ };
+ const e2eeInfo = (
+ await this.client.fetch(
+ `https://${this.client.request.endpoint}/LF1`,
+ {
+ headers: headers,
+ },
+ ).then((res) => res.json())
+ ).result;
+ this.client.log("response", e2eeInfo);
+ await this.client.e2ee.decodeE2EEKeyV1(
+ e2eeInfo.metadata,
+ Buffer.from(secret),
+ );
+ const deviceSecret = this.client.e2ee.encryptDeviceSecret(
+ Buffer.from(e2eeInfo.metadata.publicKey, "base64"),
+ Buffer.from(secret),
+ Buffer.from(e2eeInfo.metadata.encryptedKeyChain, "base64"),
+ );
+ const e2eeLogin = await this.confirmE2EELogin(
+ response.verifier,
+ deviceSecret,
+ );
+ response = await this.loginV2(
+ keynm,
+ encryptedMessage,
+ this.client.device,
+ e2eeLogin,
+ e2eeData,
+ cert,
+ "loginZ",
+ );
+ } else {
+ const headers = {
+ accept: "application/x-thrift",
+ "user-agent": this.client.request.userAgent,
+ "x-line-application": this.client.request.systemType,
+ "x-line-access": response.verifier,
+ "x-lal": "ja_JP",
+ "x-lpv": "1",
+ "x-lhm": "GET",
+ "accept-encoding": "gzip",
+ };
+ const verifier = await this.client.fetch(
+ `https://${this.client.request.endpoint}/Q`,
+ {
+ headers: headers,
+ },
+ ).then((res) => res.json());
+ this.client.log("response", verifier);
+ response = await this.loginV2(
+ keynm,
+ encryptedMessage,
+ this.client.device,
+ verifier.result.verifier,
+ e2eeData,
+ cert,
+ "loginZ",
+ );
+ }
+ }
+ if (response.certificate) {
+ this.client.emit("update:cert", response.certificate);
+ await this.registerCert(response.certificate, email);
+ }
+ return response.authToken;
+ }
+
+ public async requestEmailLoginV2(
+ email: string,
+ password: string,
+ constantPincode: string = "114514",
+ ): Promise {
+ if (constantPincode.length !== 6) {
+ throw new InternalError(
+ "Invalid constant pincode",
+ "The constant pincode should be 6 digits",
+ );
+ }
+
+ this.client.log("login", {
+ method: "email",
+ email,
+ password: password.length,
+ constantPincode,
+ });
+
+ const rsaKey = await this.getRSAKeyInfo();
+ const { keynm, sessionKey } = rsaKey;
+
+ const message = String.fromCharCode(sessionKey.length) +
+ sessionKey +
+ String.fromCharCode(email.length) +
+ email +
+ String.fromCharCode(password.length) +
+ password;
+
+ const [secret, secretPK] = this.client.e2ee.createSqrSecret(true);
+ const e2eeData = this.client.e2ee.encryptAESECB(
+ this.client.e2ee.getSHA256Sum(constantPincode),
+ Buffer.from(secretPK, "base64"),
+ );
+
+ const encryptedMessage = getRSACrypto(message, rsaKey).credentials;
+
+ const cert = await this.getCert(email) || undefined;
+
+ let response = await this.loginV2(
+ keynm,
+ encryptedMessage,
+ this.client.device,
+ undefined,
+ e2eeData,
+ cert,
+ "loginV2",
+ );
+
+ if (!response[9]) {
+ this.client.emit("pincall", constantPincode);
+ const headers = {
+ accept: "application/x-thrift",
+ "user-agent": this.client.request.userAgent,
+ "x-line-application": this.client.request.systemType,
+ "x-line-access": response[3],
+ "x-lal": "ja_JP",
+ "x-lpv": "1",
+ "x-lhm": "GET",
+ "accept-encoding": "gzip",
+ };
+ const e2eeInfo = (
+ await this.client.fetch(
+ `https://${this.client.request.endpoint}/LF1`,
+ {
+ headers: headers,
+ },
+ ).then((res) => res.json())
+ ).result;
+ this.client.log("response", e2eeInfo);
+ await this.client.e2ee.decodeE2EEKeyV1(
+ e2eeInfo.metadata,
+ Buffer.from(secret),
+ );
+ const deviceSecret = this.client.e2ee.encryptDeviceSecret(
+ Buffer.from(e2eeInfo.metadata.publicKey, "base64"),
+ Buffer.from(secret),
+ Buffer.from(e2eeInfo.metadata.encryptedKeyChain, "base64"),
+ );
+ const e2eeLogin = await this.confirmE2EELogin(
+ response[3],
+ deviceSecret,
+ );
+ response = await this.loginV2(
+ keynm,
+ encryptedMessage,
+ this.client.device,
+ e2eeLogin,
+ e2eeData,
+ cert,
+ "loginV2",
+ );
+ }
+ if (response[2]) {
+ this.client.emit("update:cert", response[2]);
+ await this.registerCert(response[2], email);
+ }
+ await this.client.storage.set("refreshToken", response[9][2]);
+ await this.client.storage.set(
+ "expire",
+ response[9][3] + response[9][6],
+ );
+ return response[9][1];
+ }
+
+ /**
+ * @description Get RSA key info for login.
+ *
+ * @param {number} [provider=0] Provider to get RSA key info from.
+ * @returns {Promise} RSA key info.
+ * @throws {FetchError} If failed to fetch RSA key info.
+ */
+ public async getRSAKeyInfo(
+ provider: LINETypes.IdentityProvider = 0,
+ ): Promise {
+ return await this.client.request.request(
+ [[12, 1, [[8, 2, LINEStruct.IdentityProvider(provider)]]]],
+ "getRSAKeyInfo",
+ 3,
+ "RSAKey",
+ "/api/v3/TalkService.do",
+ );
+ }
+
+ private async loginV2(
+ keynm: string,
+ encryptedMessage: string,
+ deviceName: Device,
+ verifier: string | undefined,
+ secret: Buffer | undefined,
+ cert: string | undefined,
+ methodName: K,
+ ): Promise {
+ let loginType = 2;
+ if (!secret) loginType = 0;
+ if (verifier) {
+ loginType = 1;
+ }
+ return await this.client.request.request(
+ [
+ [
+ 12,
+ 2,
+ [
+ [8, 1, loginType],
+ [8, 2, 1],
+ [11, 3, keynm],
+ [11, 4, encryptedMessage],
+ [2, 5, 0],
+ [11, 6, ""],
+ [11, 7, deviceName],
+ [11, 8, cert],
+ [11, 9, verifier],
+ [11, 10, secret],
+ [8, 11, 1],
+ [11, 12, "System Product Name"],
+ ],
+ ],
+ ],
+ methodName,
+ 3,
+ methodName === "loginZ" ? "LoginResult" : false,
+ "/api/v3p/rs",
+ );
+ }
+
+ public async createSession(): Promise {
+ return await this.client.request.request(
+ [],
+ "createSession",
+ 4,
+ false,
+ "/acct/lgn/sq/v1",
+ );
+ }
+
+ public async createQrCode(qrcode: string): Promise {
+ return await this.client.request.request(
+ [[12, 1, [[11, 1, qrcode]]]],
+ "createQrCode",
+ 4,
+ false,
+ "/acct/lgn/sq/v1",
+ );
+ }
+
+ public async checkQrCodeVerified(qrcode: string): Promise {
+ try {
+ await this.client.request.request(
+ [[12, 1, [[11, 1, qrcode]]]],
+ "checkQrCodeVerified",
+ 4,
+ false,
+ "/acct/lp/lgn/sq/v1",
+ {
+ "x-lst": "180000",
+ "x-line-access": qrcode,
+ },
+ this.client.config.longTimeout,
+ );
+ return true;
+ } catch (error) {
+ throw error;
+ }
+ }
+
+ public async verifyCertificate(
+ qrcode: string,
+ cert?: string | undefined,
+ ): Promise {
+ return await this.client.request.request(
+ [[12, 1, [[11, 1, qrcode], [11, 2, cert]]]],
+ "verifyCertificate",
+ 4,
+ false,
+ "/acct/lgn/sq/v1",
+ );
+ }
+
+ public async createPinCode(qrcode: string): Promise {
+ return await this.client.request.request(
+ [[12, 1, [[11, 1, qrcode]]]],
+ "createPinCode",
+ 4,
+ false,
+ "/acct/lgn/sq/v1",
+ );
+ }
+
+ public async checkPinCodeVerified(qrcode: string): Promise {
+ try {
+ await this.client.request.request(
+ [[12, 1, [[11, 1, qrcode]]]],
+ "checkPinCodeVerified",
+ 4,
+ false,
+ "/acct/lp/lgn/sq/v1",
+ {
+ "x-lst": "180000",
+ "x-line-access": qrcode,
+ },
+ this.client.config.longTimeout,
+ );
+ return true;
+ } catch (error) {
+ throw error;
+ }
+ }
+
+ public async qrCodeLogin(
+ authSessionId: string,
+ autoLoginIsRequired: boolean = true,
+ ): Promise {
+ return await this.client.request.request(
+ [[12, 1, [
+ [11, 1, authSessionId],
+ [11, 2, this.client.device],
+ [2, 3, autoLoginIsRequired],
+ ]]],
+ "qrCodeLogin",
+ 4,
+ false,
+ "/acct/lgn/sq/v1",
+ );
+ }
+
+ public async qrCodeLoginV2(
+ authSessionId: string,
+ modelName: string = "evex",
+ systemName: string = "linejs",
+ autoLoginIsRequired: boolean = true,
+ ): Promise {
+ return await this.client.request.request(
+ [[12, 1, [
+ [11, 1, authSessionId],
+ [11, 2, systemName],
+ [11, 3, modelName],
+ [2, 4, autoLoginIsRequired],
+ ]]],
+ "qrCodeLoginV2",
+ 4,
+ false,
+ "/acct/lgn/sq/v1",
+ );
+ }
+
+ public async confirmE2EELogin(
+ verifier: string,
+ deviceSecret: Buffer,
+ ): Promise {
+ return await this.client.request.request(
+ [
+ [11, 1, verifier],
+ [11, 2, deviceSecret],
+ ],
+ "confirmE2EELogin",
+ 3,
+ false,
+ "/api/v3p/rs",
+ );
+ }
+}
diff --git a/packages/linejs/client/entities/regex.ts b/packages/linejs/base/login/regex.ts
similarity index 100%
rename from packages/linejs/client/entities/regex.ts
rename to packages/linejs/base/login/regex.ts
diff --git a/packages/linejs/client/libs/rsa/rsa-verify.ts b/packages/linejs/base/login/rsa-verify.ts
similarity index 100%
rename from packages/linejs/client/libs/rsa/rsa-verify.ts
rename to packages/linejs/base/login/rsa-verify.ts
diff --git a/packages/linejs/base/mod.ts b/packages/linejs/base/mod.ts
new file mode 100644
index 00000000..086fabf6
--- /dev/null
+++ b/packages/linejs/base/mod.ts
@@ -0,0 +1,7 @@
+/**
+ * LINE Client
+ * @module
+ */
+
+export * from "./core/mod.ts";
+export * from "./types.ts";
diff --git a/packages/linejs/client/entities/mime.ts b/packages/linejs/base/obs/mime.ts
similarity index 100%
rename from packages/linejs/client/entities/mime.ts
rename to packages/linejs/base/obs/mime.ts
diff --git a/packages/linejs/base/obs/mod.ts b/packages/linejs/base/obs/mod.ts
new file mode 100644
index 00000000..2b7bbc1a
--- /dev/null
+++ b/packages/linejs/base/obs/mod.ts
@@ -0,0 +1,419 @@
+import { Buffer } from "node:buffer";
+import { type BaseClient, InternalError } from "../core/mod.ts";
+import { MimeType } from "./mime.ts";
+import crypto from "node:crypto";
+import type { Message } from "@evex/linejs-types";
+import { writeStruct } from "../thrift/readwrite/write.ts";
+// @ts-types="thrift-types"
+import * as thrift from "thrift";
+
+export type ObjType = "image" | "gif" | "video" | "audio" | "file";
+export interface ObsMetadata {
+ status: string;
+ name: string;
+ mime: string;
+ type: string;
+ hash: string;
+ cksum: string;
+ size: number | string;
+ ctimeMillis: number;
+ imageDetails?: {
+ format: string;
+ height: number;
+ width: number;
+ signature: string;
+ };
+ videoMp4Details?: {
+ size: number;
+ durationMillis: number;
+ height: number;
+ width: number;
+ format: string;
+ status: string;
+ };
+ audioM4aDetails?: {
+ size: number;
+ durationMillis: number;
+ format: string;
+ status: string;
+ };
+ svc: string;
+ offset: number;
+ ctime: string;
+ oid: string;
+ userid: string;
+ sid: string;
+}
+
+export class LineObs {
+ client: BaseClient;
+ prefix = "https://obs.line-apps.com/";
+ constructor(client: BaseClient) {
+ this.client = client;
+ }
+
+ /**
+ * Gets a message image URI by appending the given message ID to the prefixSticker
+ * @param {string} [messageId] - The message ID to use in the URLSticker
+ * @param {boolean} [isPreview=false] - Whether to append '/preview' to the URL.
+ * @return {string} The getted message image
+ */
+ public getMessageDataUrl(
+ messageId: string,
+ isPreview: boolean = false,
+ square: boolean = false,
+ ): string {
+ return `${this.prefix}r/${square ? "g2" : "talk"}/m/${messageId}${
+ isPreview ? "/preview" : ""
+ }`;
+ }
+
+ /**
+ * Gets a message image URI by appending the given message ID to the prefixSticker
+ * @param {string} [messageId] - The message ID to use in the URLSticker
+ * @return {string} The getted message image
+ */
+ public getMessageMetadataUrl(
+ messageId: string,
+ square: boolean = false,
+ ): string {
+ return `${this.prefix}r/${
+ square ? "g2" : "talk"
+ }/m/${messageId}/object_info.obs`;
+ }
+
+ /**
+ * @description Gets the message's data from LINE Obs.
+ */
+ public async downloadMessageData(options: {
+ messageId: string;
+ isPreview?: boolean;
+ isSquare?: boolean;
+ }): Promise {
+ if (!this.client.authToken) {
+ throw new InternalError(
+ "Not setup yet",
+ "Please call 'login()' first",
+ );
+ }
+ const { messageId, isPreview, isSquare } = {
+ isPreview: false,
+ isSquare: false,
+ ...options,
+ };
+ const blob = await (await this.client.fetch(
+ this.getMessageDataUrl(messageId, isPreview, isSquare),
+ {
+ headers: {
+ accept: "application/json, text/plain, */*",
+ "x-line-application": this.client.request.systemType,
+ "x-Line-access": this.client.authToken,
+ },
+ },
+ )).blob();
+ const fileInfo = await this.getMessageObsMetadata({
+ messageId,
+ isSquare,
+ });
+ return new File([blob], fileInfo.name, { type: blob.type });
+ }
+
+ /**
+ * @description Gets the message's data from LINE Obs.
+ */
+ public async getMessageObsMetadata(options: {
+ messageId: string;
+ isSquare?: boolean;
+ }): Promise {
+ if (!this.client.authToken) {
+ throw new InternalError(
+ "Not setup yet",
+ "Please call 'login()' first",
+ );
+ }
+ const { messageId, isSquare } = {
+ isSquare: false,
+ ...options,
+ };
+ const r = await this.client.fetch(
+ this.getMessageMetadataUrl(messageId, isSquare),
+ {
+ headers: {
+ accept: "application/json, text/plain, */*",
+ "x-line-application": this.client.request.systemType,
+ "x-Line-access": this.client.authToken,
+ },
+ },
+ );
+ return r.json();
+ }
+
+ /**
+ * @description Upload obs message to talk.
+ */
+ public async uploadObjTalk(
+ to: string,
+ type: ObjType,
+ data: Blob,
+ oid?: string,
+ filename?: string,
+ ): Promise<{
+ objId: string;
+ objHash: string;
+ headers: Headers;
+ }> {
+ if (!this.client.authToken) {
+ throw new InternalError(
+ "Not setup yet",
+ "Please call 'login()' first",
+ );
+ }
+ const ext = MimeType[data.type as keyof typeof MimeType];
+ const param: {
+ oid: string;
+ reqseq?: string;
+ tomid?: string;
+ ver: string;
+ name: string;
+ type: string;
+ cat?: string;
+ duration?: string;
+ } = {
+ ver: "2.0",
+ name: filename || "linejs." + ext,
+ type,
+ ...oid ? { oid: oid } : {
+ oid: "reqseq",
+ tomid: to,
+ reqseq: this.client.getReqseq("talk").toString(),
+ },
+ };
+ if (type === "image") {
+ param.cat = "original";
+ } else if (type === "gif") {
+ param.cat = "original";
+ param.type = "image";
+ } else if (type === "audio" || type === "video") {
+ param.duration = "1919"; // 810
+ }
+ const toType: "talk" | "g2" = to[0] === "m" || to[0] === "t"
+ ? "g2"
+ : "talk";
+ return await this.uploadObjectForService({
+ data,
+ oType: type,
+ obsPath: toType + "/m/" + oid || "reqseq",
+ filename: param.name,
+ params: param,
+ });
+ }
+
+ async uploadObjectForService(options: {
+ data: Blob;
+ oType?: ObjType;
+ obsPath?: string;
+ params?: Record;
+ filename?: string;
+ addHeaders?: Record;
+ }): Promise<
+ { objId: string; objHash: string; headers: Headers }
+ > {
+ let {
+ data,
+ oType,
+ obsPath,
+ params,
+ filename,
+ addHeaders,
+ } = {
+ oType: "image",
+ obsPath: "myhome/h",
+ ...options,
+ };
+ const obsPathFinal = `/r/${obsPath}`;
+ oType = oType.toLowerCase();
+
+ filename = filename || crypto.randomUUID();
+ const baseParams = {
+ type: oType,
+ ver: "2.0",
+ name: filename,
+ };
+
+ params = { ...baseParams, ...(params || {}) };
+
+ if (!data || data.size === 0) {
+ throw new InternalError("ObsError", "No data to send.");
+ }
+ let headers: Record = this.client.request
+ .getHeader("POST");
+ headers["Content-Type"] = "application/octet-stream";
+ headers["X-Obs-Params"] = Buffer.from(JSON.stringify(params)).toString(
+ "base64",
+ );
+
+ if (addHeaders) {
+ headers = { ...headers, ...addHeaders };
+ }
+
+ const response = await this.client.fetch(
+ this.prefix + obsPathFinal,
+ { method: "POST", headers, body: data },
+ );
+
+ const objId = response.headers.get("x-obs-oid") ?? "";
+ const objHash = response.headers.get("x-obs-hash") ?? "";
+ return { objId, objHash, headers: response.headers };
+ }
+
+ async downloadObjectForService(options: {
+ obsPath: string;
+ oid: string;
+ addHeaders?: Record;
+ }): Promise {
+ let { obsPath, oid, addHeaders } = {
+ addHeaders: {},
+ ...options,
+ };
+ if (obsPath.includes("{oid}")) {
+ obsPath = obsPath.replace("{oid}", oid);
+ } else {
+ obsPath += "/" + oid;
+ }
+ let headers: Record = this.client.request
+ .getHeader("GET");
+ headers = { ...headers, ...addHeaders };
+
+ const obsPathFinal = "r/" + obsPath;
+ const response = await this.client.fetch(
+ this.prefix + obsPathFinal,
+ { method: "GET", headers },
+ );
+ return response.blob();
+ }
+
+ public async uploadMediaByE2EE(options: {
+ data: Blob;
+ oType: ObjType;
+ to: string;
+ filename?: string;
+ }): Promise {
+ const { data, oType, to, filename } = options;
+ const typeSet: {
+ image: [string, 1];
+ video: [string, 2];
+ audio: [string, 3];
+ file: [string, 14];
+ gif: [string, 1];
+ } = {
+ "image": ["emi", 1],
+ "video": ["emv", 2],
+ "audio": ["ema", 3],
+ "file": ["emf", 14],
+ "gif": ["emi", 1],
+ };
+
+ const ext = (filename && filename.split(".").at(-1)) ||
+ MimeType[data.type as keyof typeof MimeType];
+
+ const serviceName = "talk";
+ const [obsNamespace, contentType] = typeSet[oType];
+ const params: Record = { "type": "file" };
+
+ if (oType === "gif") {
+ params["cat"] = "original";
+ }
+ if (!(to[0] === "u" || to[0] === "c")) {
+ throw new InternalError("ObsError", "Invalid mid");
+ }
+ const { keyMaterial, encryptedData } = await this.client.e2ee
+ .encryptByKeyMaterial(
+ Buffer.from(await data.arrayBuffer()),
+ );
+ const tempId = "reqid-" + crypto.randomUUID();
+ const edata = new Blob([encryptedData]);
+ const { objId } = await this.uploadObjectForService({
+ data: edata,
+ oType: "file",
+ obsPath: `${serviceName}/${obsNamespace}/${tempId}`,
+ params,
+ });
+ if (oType === "image" || oType === "gif" || oType === "video") {
+ const { objId: objId2, headers } = await this
+ .uploadObjectForService({
+ data: edata,
+ oType: "file",
+ obsPath:
+ `${serviceName}/${obsNamespace}/${tempId}__ud-preview`,
+ params,
+ });
+ if (objId !== objId2) {
+ throw new InternalError("ObsError", "objId not match", {
+ headers,
+ });
+ }
+ }
+
+ const chunks = await this.client.e2ee.encryptE2EEMessage(
+ to,
+ { keyMaterial, fileName: filename || "linejs." + ext },
+ contentType,
+ );
+
+ return await this.client.talk.sendMessage({
+ to,
+ chunks,
+ contentType: contentType,
+ contentMetadata: {
+ SID: obsNamespace,
+ OID: objId,
+ FILE_SIZE: edata.size.toString(),
+ e2eeVersion: "2",
+ ...(oType === "image" || oType === "gif" || oType === "video")
+ ? {
+ MEDIA_CONTENT_INFO: JSON.stringify(
+ {
+ category: "original",
+ fileSize: edata.size,
+ extension: ext,
+ animated: oType == "gif",
+ },
+ ),
+ }
+ : {},
+ },
+ });
+ }
+
+ public async downloadMediaByE2EE(message: Message): Promise {
+ if (!(message.to[0] === "u" || message.to[0] === "c")) {
+ throw new InternalError("ObsError", "Invalid mid");
+ }
+ const { id, contentMetadata, chunks } = message;
+ if (!chunks || !chunks.length) {
+ return null;
+ }
+ const { keyMaterial, fileName } = await this.client.e2ee
+ .decryptE2EEDataMessage(message);
+ const talkMeta = Buffer.from(JSON.stringify({
+ message: Buffer.from(
+ writeStruct(
+ [[11, 4, id], [15, 27, [12, []]]],
+ thrift.TBinaryProtocol,
+ ),
+ ).toString("base64"),
+ })).toString("base64");
+ const data = await this.downloadObjectForService({
+ oid: contentMetadata.OID,
+ obsPath: "talk/" + contentMetadata.SID,
+ addHeaders: { "X-Talk-Meta": talkMeta },
+ });
+ const fileData = new File([
+ await this.client.e2ee.decryptByKeyMaterial(
+ Buffer.from(await data.arrayBuffer()),
+ keyMaterial,
+ ),
+ ], fileName);
+ return fileData;
+ }
+}
diff --git a/packages/linejs/base/polling/mod.ts b/packages/linejs/base/polling/mod.ts
new file mode 100644
index 00000000..e7b712bb
--- /dev/null
+++ b/packages/linejs/base/polling/mod.ts
@@ -0,0 +1,142 @@
+import type { BaseClient } from "../core/mod.ts";
+import type { Operation, SquareEvent } from "@evex/linejs-types";
+
+export interface SyncData {
+ square?: string;
+ talk: {
+ revision?: number | bigint;
+ globalRev?: number | bigint;
+ individualRev?: number | bigint;
+ };
+}
+
+function sleep(time: number) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, time);
+ });
+}
+
+export class Polling {
+ sync: SyncData = { talk: {} };
+
+ client: BaseClient;
+ constructor(client: BaseClient) {
+ this.client = client;
+ }
+
+ /**
+ * Listens to square events and yields them as they are received.
+ *
+ * @param options - Configuration options for listening to square events.
+ * @param options.signal - An AbortSignal to cancel the polling.
+ * @param options.onError - A callback function to handle errors.
+ * @param options.pollingInterval - The interval in milliseconds between polling requests. Defaults to 1000ms.
+ *
+ * @yields {SquareEvent} - The events received from the square.
+ */
+ async *listenSquareEvents(options: {
+ signal?: AbortSignal;
+ onError?: (error: unknown) => void;
+ pollingInterval?: number;
+ } = {}): AsyncGenerator {
+ const { signal, onError, pollingInterval } = {
+ pollingInterval: 1000,
+ ...options,
+ };
+ let continuationToken: string | undefined;
+ while (true) {
+ try {
+ const response = await this.client.square.fetchMyEvents({
+ syncToken: this.sync.square,
+ continuationToken,
+ limit: 100,
+ });
+ this.sync.square = response.syncToken;
+ continuationToken = response.continuationToken;
+ for (const event of response.events) {
+ yield event;
+ }
+ } catch (error) {
+ if (onError) {
+ onError(error);
+ }
+ }
+ await sleep(pollingInterval);
+ if (signal?.aborted) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Listens for talk events by polling the server at a specified interval.
+ *
+ * @param {Object} [options] - Configuration options for the polling.
+ * @param {AbortSignal} [options.signal] - An AbortSignal to cancel the polling.
+ * @param {(error: unknown) => void} [options.onError] - A callback function to handle errors.
+ * @param {number} [options.pollingInterval=1000] - The interval in milliseconds between each poll.
+ *
+ * @yields {Operation} - Yields each operation event received from the server.
+ *
+ * @returns {AsyncGenerator} - An async generator that yields operation events.
+ */
+ async *listenTalkEvents(options: {
+ signal?: AbortSignal;
+ onError?: (error: unknown) => void;
+ pollingInterval?: number;
+ } = {}): AsyncGenerator {
+ const { signal, onError, pollingInterval } = {
+ pollingInterval: 1000,
+ ...options,
+ };
+ while (true) {
+ try {
+ const response = await this.client.talk.sync({
+ ...this.sync.talk,
+ limit: 100,
+ });
+ if (
+ response.fullSyncResponse &&
+ response.fullSyncResponse.nextRevision
+ ) {
+ this.sync.talk.revision = response.fullSyncResponse.nextRevision;
+ }
+ if (
+ response.operationResponse &&
+ response.operationResponse.globalEvents &&
+ response.operationResponse.globalEvents.lastRevision
+ ) {
+ this.sync.talk.globalRev =
+ response.operationResponse.globalEvents.lastRevision;
+ }
+ if (
+ response.operationResponse &&
+ response.operationResponse.individualEvents &&
+ response.operationResponse.individualEvents.lastRevision
+ ) {
+ this.sync.talk.individualRev =
+ response.operationResponse.individualEvents
+ .lastRevision;
+ }
+ if (
+ !(response.operationResponse &&
+ response.operationResponse.operations)
+ ) {
+ continue;
+ }
+ for (const event of response.operationResponse.operations) {
+ this.sync.talk.revision = event.revision;
+ yield event;
+ }
+ } catch (error) {
+ if (onError) {
+ onError(error);
+ }
+ }
+ await sleep(pollingInterval);
+ if (signal?.aborted) {
+ break;
+ }
+ }
+ }
+}
diff --git a/packages/linejs/base/request/mod.ts b/packages/linejs/base/request/mod.ts
new file mode 100644
index 00000000..0a287675
--- /dev/null
+++ b/packages/linejs/base/request/mod.ts
@@ -0,0 +1,286 @@
+import {
+ type NestedArray,
+ type ParsedThrift,
+ type ProtocolKey,
+ Protocols,
+} from "../thrift/mod.ts";
+import { type BaseClient, InternalError } from "../core/mod.ts";
+
+const square = ["/SQ1", "/SQLV1"];
+
+/**
+ * Request Client
+ */
+/**
+ * @class RequestClient
+ * @description A client for making requests to the LINE API.
+ *
+ * @property {BaseClient} client - The base client instance.
+ * @property {string} endpoint - The endpoint for the API requests.
+ * @property {string} userAgent - The user agent string for the requests.
+ * @property {string} systemType - The system type string for the requests.
+ * @property {Record} EXCEPTION_TYPES - A static record of exception types based on request paths.
+ *
+ * @constructor
+ * @param {BaseClient} client - The base client instance.
+ */
+export class RequestClient {
+ readonly client: BaseClient;
+ endpoint: string;
+ userAgent: string;
+ systemType: string;
+ static readonly EXCEPTION_TYPES: Record = {
+ "/S3": "TalkException",
+ "/S4": "TalkException",
+ "/SYNC4": "TalkException",
+ "/SYNC3": "TalkException",
+ "/CH3": "ChannelException",
+ "/CH4": "ChannelException",
+ "/SQ1": "SquareException",
+ "/LIFF1": "LiffException",
+ "/api/v3p/rs": "TalkException",
+ "/api/v3/TalkService.do": "TalkException",
+ };
+
+ constructor(client: BaseClient) {
+ const deviceDetails = client.deviceDetails;
+ this.endpoint = client.endpoint ?? "legy.line-apps.com";
+ this.systemType =
+ `${deviceDetails.device}\t${deviceDetails.appVersion}\t${deviceDetails.systemName}\t${deviceDetails.systemVersion}`;
+ this.userAgent = `Line/${deviceDetails.appVersion}`;
+ this.client = client;
+ }
+
+ /**
+ * @description Request to LINE API.
+ *
+ * @param value - The thrift value(argument) to request.
+ * @param methodName - The method name of the request.
+ * @param protocolType - The protocol type of the request.
+ * @param parse - Whether to parse the response.
+ * @param path - The path of the request.
+ * @param headers - The headers of the request.
+ * @param timeout - The timeout milliseconds of the request.
+ * @returns The response.
+ */
+ public async request(
+ value: NestedArray,
+ methodName: string,
+ protocolType: ProtocolKey = 3,
+ parse: boolean | string = true,
+ path: string = "/S3",
+ headers: Record = {},
+ timeout = this.client.config.timeout,
+ ): Promise {
+ const res = await this.requestCore(
+ path,
+ value,
+ methodName,
+ protocolType,
+ headers,
+ undefined,
+ parse,
+ undefined,
+ timeout,
+ );
+ return res.data.success;
+ }
+
+ /**
+ * @description Request to LINE API by raw.
+ *
+ * @param {string} [path] - The path of the request.
+ * @param {NestedArray} [value] - The value to request.
+ * @param {string} [methodName] - The method name of the request.
+ * @param {ProtocolKey} [protocolType] - The protocol type of the request.
+ * @param {object} [appendHeaders={}] - The headers to append to the request.
+ * @param {string} [overrideMethod="POST"] - The method of the request.
+ * @param {boolean | string} [parse=true] - Whether to parse the response.
+ * @param {boolean} [isReRequest=false] - Is Re-Request.
+ * @param {number} [timeout=this.timeOutMs] - The timeout milliseconds of the request.
+ * @returns {Promise} The response.
+ * @throws {InternalError} If the request fails or timeout.
+ */
+ private async requestCore(
+ path: string,
+ value: NestedArray,
+ methodName: string,
+ protocolType: ProtocolKey,
+ appendHeaders: object = {},
+ overrideMethod: string = "POST",
+ parse: boolean | string = true,
+ isReRequest: boolean = false,
+ timeout: number = 1000,
+ ): Promise {
+ const protocol = Protocols[protocolType];
+
+ const headers = {
+ ...this.getHeader(overrideMethod),
+ ...appendHeaders,
+ };
+
+ this.client.log("writeThrift", {
+ value,
+ methodName,
+ protocolType,
+ });
+
+ const Trequest = this.client.thrift.writeThrift(
+ value,
+ methodName,
+ protocol,
+ );
+
+ this.client.log("request", {
+ methodName,
+ path: `https://${this.endpoint}${path}`,
+ method: overrideMethod,
+ headers,
+ timeout,
+ body: Trequest,
+ });
+
+ const response = await this.client.fetch(
+ `https://${this.endpoint}${path}`,
+ {
+ method: overrideMethod,
+ headers,
+ signal: AbortSignal.timeout(timeout),
+ body: Trequest,
+ },
+ );
+ const nextToken = response.headers.get("x-line-next-access");
+ if (nextToken) {
+ this.client.emit("update:authtoken", nextToken);
+ }
+ const body = await response.arrayBuffer();
+ const parsedBody = new Uint8Array(body);
+ this.client.log("response", {
+ ...response,
+ parsedBody,
+ methodName,
+ });
+ let res: ParsedThrift;
+ let hasError = false;
+ try {
+ res = this.client.thrift.readThrift(parsedBody, protocol);
+ } catch {
+ throw new Error(
+ `Request internal failed: Invalid response buffer <${
+ [...parsedBody].map((e) => e.toString(16)).join(" ")
+ }>`,
+ );
+ }
+ if (!res.data[0] && Object.keys(res.data).length) {
+ hasError = true;
+ }
+ if (parse === true) {
+ this.client.thrift.rename_data(res, square.includes(path));
+ } else if (typeof parse === "string") {
+ res.data.success = this.client.thrift.rename_thrift(
+ parse,
+ res.data[0],
+ );
+ delete res.data[0];
+ if (res.data[1]) {
+ const structName = RequestClient.EXCEPTION_TYPES[path] ||
+ "TalkException";
+ if (structName) {
+ res.data.e = this.client.thrift.rename_thrift(
+ structName,
+ res.data[1],
+ );
+ } else {
+ res.data.e = res.data[1];
+ }
+ delete res.data[1];
+ }
+ } else {
+ res.data.success = res.data[0];
+ delete res.data[0];
+ if (res.data[1]) {
+ const structName = RequestClient.EXCEPTION_TYPES[path] ||
+ "TalkException";
+ if (structName) {
+ res.data.e = this.client.thrift.rename_thrift(
+ structName,
+ res.data[1],
+ );
+ } else {
+ res.data.e = res.data[1];
+ }
+ delete res.data[1];
+ }
+ }
+
+ this.client.log("readThrift", {
+ res,
+ });
+
+ const isRefresh = Boolean(
+ res.data.e &&
+ res.data.e["code"] === "MUST_REFRESH_V3_TOKEN" &&
+ await this.client.storage.get("refreshToken"),
+ );
+
+ if (res.data.e && !isRefresh) {
+ throw new InternalError(
+ "RequestError",
+ `Request internal failed, ${methodName}(${path}) -> ` +
+ JSON.stringify(res.data.e),
+ res.data.e,
+ );
+ }
+ if (hasError && !isRefresh) {
+ throw new InternalError(
+ "RequestError",
+ `Request internal failed, ${methodName}(${path}) -> ` +
+ JSON.stringify(res.data),
+ res.data,
+ );
+ }
+
+ if (isRefresh && !isReRequest) {
+ await this.client.auth.tryRefreshToken();
+ return this.requestCore(
+ path,
+ value,
+ methodName,
+ protocolType,
+ appendHeaders,
+ overrideMethod,
+ parse,
+ true,
+ );
+ }
+ return res;
+ }
+
+ /**
+ * Get HTTP headers for a request.
+ * @param {string} [overrideMethod="POST"] The HTTP method to use in the `x-lhm` header.
+ * @returns {Record} An object with the headers as key-value pairs.
+ * @throws {InternalError} If the client has not been setup yet.
+ */
+ public getHeader(
+ overrideMethod: string = "POST",
+ ): Record {
+ const header = {
+ Host: this.endpoint,
+ accept: "application/x-thrift",
+ "user-agent": this.userAgent,
+ "x-line-application": this.systemType,
+ "content-type": "application/x-thrift",
+ "x-lal": "ja_JP",
+ "x-lpv": "1",
+ "x-lhm": overrideMethod,
+ "accept-encoding": "gzip",
+ } as Record;
+
+ if (this.client.authToken) {
+ header["x-line-access"] = this.client.authToken;
+ }
+
+ return header;
+ }
+}
diff --git a/packages/linejs/base/service/auth/mod.ts b/packages/linejs/base/service/auth/mod.ts
new file mode 100644
index 00000000..66ea4e38
--- /dev/null
+++ b/packages/linejs/base/service/auth/mod.ts
@@ -0,0 +1,245 @@
+// For Auth (login, refresh, etc)
+
+import { LINEStruct, type ProtocolKey } from "../../thrift/mod.ts";
+import type * as LINETypes from "@evex/linejs-types";
+import { type BaseClient, InternalError } from "../../core/mod.ts";
+import type { BaseService } from "../types.ts";
+
+export class AuthService implements BaseService {
+ client: BaseClient;
+ protocolType: ProtocolKey = 4;
+ requestPath = "/AS4";
+ errorName = "AuthServiceError";
+ constructor(client: BaseClient) {
+ this.client = client;
+ }
+
+ /**
+ * @description Try to refresh token.
+ */
+ public async tryRefreshToken() {
+ const refreshToken = await this.client.storage.get("refreshToken");
+ if (typeof refreshToken === "string") {
+ const RATR = await this.refresh({ request: { refreshToken } });
+ this.client.authToken = RATR.accessToken;
+ this.client.emit("update:authtoken", RATR.accessToken);
+ await this.client.storage.set(
+ "expire",
+ (RATR.tokenIssueTimeEpochSec as number) +
+ (RATR.durationUntilRefreshInSec as number) as number,
+ );
+ } else {
+ throw new InternalError("refreshError", "refreshToken not found");
+ }
+ }
+
+ async refresh(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.refresh_args(...param),
+ "refresh",
+ this.protocolType,
+ true,
+ "/EXT/auth/tokenrefresh/v1",
+ );
+ }
+
+ async reportRefreshedAccessToken(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.reportRefreshedAccessToken_args(...param),
+ "reportRefreshedAccessToken",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+ //
+ async connectEapAccount(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.connectEapAccount_args(...param),
+ "connectEapAccount",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async disconnectEapAccount(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.disconnectEapAccount_args(...param),
+ "disconnectEapAccount",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async openSession(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.openSession_args(...param),
+ "openSession",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async verifyEapLogin(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.verifyEapLogin_args(...param),
+ "verifyEapLogin",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+ //
+ async updatePassword(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.updatePassword_args(...param),
+ "updatePassword",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async establishE2EESession(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.establishE2EESession_args(...param),
+ "establishE2EESession",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async issueTokenForAccountMigrationSettings(
+ ...param: Parameters<
+ typeof LINEStruct.issueTokenForAccountMigrationSettings_args
+ >
+ ): Promise<
+ LINETypes.issueTokenForAccountMigrationSettings_result["success"]
+ > {
+ return await this.client.request.request(
+ LINEStruct.issueTokenForAccountMigrationSettings_args(...param),
+ "issueTokenForAccountMigrationSettings",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async openAuthSession(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.openAuthSession_args(...param),
+ "openAuthSession",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async getAuthRSAKey(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.getAuthRSAKey_args(...param),
+ "getAuthRSAKey",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async setIdentifier(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.setIdentifier_args(...param),
+ "setIdentifier",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async updateIdentifier(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.updateIdentifier_args(...param),
+ "updateIdentifier",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async resendIdentifierConfirmation(
+ ...param: Parameters<
+ typeof LINEStruct.resendIdentifierConfirmation_args
+ >
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.resendIdentifierConfirmation_args(...param),
+ "resendIdentifierConfirmation",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async confirmIdentifier(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.confirmIdentifier_args(...param),
+ "confirmIdentifier",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async removeIdentifier(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.removeIdentifier_args(...param),
+ "removeIdentifier",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async issueV3TokenForPrimary(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.issueV3TokenForPrimary_args(...param),
+ "issueV3TokenForPrimary",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+}
diff --git a/packages/linejs/base/service/call/mod.ts b/packages/linejs/base/service/call/mod.ts
new file mode 100644
index 00000000..71d7429c
--- /dev/null
+++ b/packages/linejs/base/service/call/mod.ts
@@ -0,0 +1,219 @@
+// For Call (call, etc)
+
+import { LINEStruct, type ProtocolKey } from "../../thrift/mod.ts";
+import type * as LINETypes from "@evex/linejs-types";
+import type { BaseClient } from "../../core/mod.ts";
+import type { BaseService } from "../types.ts";
+
+export class CallService implements BaseService {
+ client: BaseClient;
+ protocolType: ProtocolKey = 4;
+ requestPath = "/V4";
+ errorName = "CallServiceError";
+ constructor(client: BaseClient) {
+ this.client = client;
+ }
+ async acquireCallRoute(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.acquireCallRoute_args(...param),
+ "acquireCallRoute",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async acquireOACallRoute(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.acquireOACallRoute_args(...param),
+ "acquireOACallRoute",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async lookupPaidCall(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.lookupPaidCall_args(...param),
+ "lookupPaidCall",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async acquirePaidCallRoute(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.acquirePaidCallRoute_args(...param),
+ "acquirePaidCallRoute",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async acquireGroupCallRoute(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.acquireGroupCallRoute_args(...param),
+ "acquireGroupCallRoute",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async getGroupCall(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.getGroupCall_args(...param),
+ "getGroupCall",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async inviteIntoGroupCall(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.inviteIntoGroupCall_args(...param),
+ "inviteIntoGroupCall",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async getGroupCallUrls(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.getGroupCallUrls_args(...param),
+ "getGroupCallUrls",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async createGroupCallUrl(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.createGroupCallUrl_args(...param),
+ "createGroupCallUrl",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async deleteGroupCallUrl(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.deleteGroupCallUrl_args(...param),
+ "deleteGroupCallUrl",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async updateGroupCallUrl(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.updateGroupCallUrl_args(...param),
+ "updateGroupCallUrl",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async getGroupCallUrlInfo(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.getGroupCallUrlInfo_args(...param),
+ "getGroupCallUrlInfo",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async joinChatByCallUrl(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.joinChatByCallUrl_args(...param),
+ "joinChatByCallUrl",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async kickoutFromGroupCall(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.kickoutFromGroupCall_args(...param),
+ "kickoutFromGroupCall",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async startPhotobooth(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.startPhotobooth_args(...param),
+ "startPhotobooth",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async usePhotoboothTicket(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.usePhotoboothTicket_args(...param),
+ "usePhotoboothTicket",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async getPhotoboothBalance(
+ ...param: Parameters
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.getPhotoboothBalance_args(...param),
+ "getPhotoboothBalance",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+}
diff --git a/packages/linejs/base/service/channel/mod.ts b/packages/linejs/base/service/channel/mod.ts
new file mode 100644
index 00000000..dad76463
--- /dev/null
+++ b/packages/linejs/base/service/channel/mod.ts
@@ -0,0 +1,175 @@
+// For Channel (channel, voom, etc)
+
+import { LINEStruct, type ProtocolKey } from "../../thrift/mod.ts";
+import type * as LINETypes from "@evex/linejs-types";
+import type { BaseClient } from "../../core/mod.ts";
+import type { BaseService } from "../types.ts";
+export class ChannelService implements BaseService {
+ client: BaseClient;
+ protocolType: ProtocolKey = 4;
+ requestPath = "/CH4";
+ errorName = "ChannelServiceError";
+ constructor(client: BaseClient) {
+ this.client = client;
+ }
+ /**
+ * @description Gets the ChannelToken by channelId.\
+ * channelIds:
+ * - linevoom: 1341209850
+ */
+ async approveChannelAndIssueChannelToken(
+ ...param: Parameters<
+ typeof LINEStruct.approveChannelAndIssueChannelToken_args
+ >
+ ): Promise {
+ return await this.client.request.request(
+ LINEStruct.approveChannelAndIssueChannelToken_args(...param),
+ "approveChannelAndIssueChannelToken",
+ this.protocolType,
+ true,
+ this.requestPath,
+ );
+ }
+
+ async getChannelInfo(
+ ...param: Parameters