From 752fea9e763d1d2b3921dbac1dace9322fb37158 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 8 May 2025 00:21:05 +0900 Subject: [PATCH 1/5] feat: export withReplies of UserList --- packages/backend/src/core/UserListService.ts | 3 ++- .../ExportUserListsProcessorService.ts | 4 +++- .../ImportUserListsProcessorService.ts | 19 ++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts index f0a8768c8f..61435500b7 100644 --- a/packages/backend/src/core/UserListService.ts +++ b/packages/backend/src/core/UserListService.ts @@ -91,7 +91,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit { } @bindThis - public async addMember(target: MiUser, list: MiUserList, me: MiUser) { + public async addMember(target: MiUser, list: MiUserList, me: MiUser, options: { withReplies?: boolean } = {}) { const currentCount = await this.userListMembershipsRepository.countBy({ userListId: list.id, }); @@ -104,6 +104,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit { userId: target.id, userListId: list.id, userListUserId: list.userId, + withReplies: options.withReplies ?? false, } as MiUserListMembership); this.globalEventService.publishInternalEvent('userListMemberAdded', { userListId: list.id, memberId: target.id }); diff --git a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts index c483d79854..733e75f65f 100644 --- a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts @@ -67,10 +67,12 @@ export class ExportUserListsProcessorService { const users = await this.usersRepository.findBy({ id: In(memberships.map(j => j.userId)), }); + const usersWithReplies = new Set(memberships.filter(m => m.withReplies).map(m => m.userId)); for (const u of users) { const acct = this.utilityService.getFullApAccount(u.username, u.host); - const content = `${list.name},${acct}`; + // 3rd column and later will be key=value pairs + const content = `${list.name},${acct},withReplies=${usersWithReplies.has(u.id)}`; await new Promise((res, rej) => { stream.write(content + '\n', err => { if (err) { diff --git a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts index db9255b35d..bf061a1f78 100644 --- a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts @@ -70,8 +70,19 @@ export class ImportUserListsProcessorService { linenum++; try { - const listName = line.split(',')[0].trim(); - const { username, host } = Acct.parse(line.split(',')[1].trim()); + const parts = line.split(','); + const listName = parts[0].trim(); + const { username, host } = Acct.parse(parts[1].trim()); + let withReplies = false; + + for (const keyValue of parts.slice(2)) { + const [key, value] = keyValue.split('='); + switch (key) { + case 'withReplies': + withReplies = value === 'true'; + break; + } + } let list = await this.userListsRepository.findOneBy({ userId: user.id, @@ -100,7 +111,9 @@ export class ImportUserListsProcessorService { if (await this.userListMembershipsRepository.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue; - this.userListService.addMember(target, list!, user); + await this.userListService.addMember(target, list, user, { + withReplies: withReplies, + }); } catch (e) { this.logger.warn(`Error in line:${linenum} ${e}`); } From 75264e7bf731506b260172bb11937a943af714b2 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 8 May 2025 00:24:31 +0900 Subject: [PATCH 2/5] feat: export withReplies of following --- .../processors/ExportFollowingProcessorService.ts | 3 ++- .../processors/ImportFollowingProcessorService.ts | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts index 903f962515..91c39cb758 100644 --- a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts @@ -94,7 +94,8 @@ export class ExportFollowingProcessorService { continue; } - const content = this.utilityService.getFullApAccount(u.username, u.host); + const userAcct = this.utilityService.getFullApAccount(u.username, u.host); + const content = `${userAcct},withReplies=${following.withReplies}`; await new Promise((res, rej) => { stream.write(content + '\n', err => { if (err) { diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index 70c9f3a096..03663d3b06 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -67,8 +67,19 @@ export class ImportFollowingProcessorService { const user = job.data.user; try { - const acct = line.split(',')[0].trim(); + const parts = line.split(','); + const acct = parts[0].trim(); const { username, host } = Acct.parse(acct); + let withReplies: boolean | null = null; + + for (const keyValue of parts.slice(2)) { + const [key, value] = keyValue.split('='); + switch (key) { + case 'withReplies': + withReplies = value === 'true'; + break; + } + } if (!host) return; @@ -95,7 +106,7 @@ export class ImportFollowingProcessorService { this.logger.info(`Follow ${target.id} ${job.data.withReplies ? 'with replies' : 'without replies'} ...`); - this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: job.data.withReplies }]); + await this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: withReplies ?? job.data.withReplies }]); } catch (e) { this.logger.warn(`Error: ${e}`); } From 5e6823ead3b1a94c4e1d8c07368acfafeca52c02 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 8 May 2025 00:26:00 +0900 Subject: [PATCH 3/5] =?UTF-8?q?import=20following=E6=99=82=E3=81=AEwithRep?= =?UTF-8?q?lies=E3=81=8C=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB=E3=83=88?= =?UTF-8?q?=E5=80=A4=E3=81=A7=E3=81=82=E3=82=8B=E3=81=93=E3=81=A8=E3=82=92?= =?UTF-8?q?=E6=98=8E=E7=A4=BA=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f0512925f3..64e80d62f3 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2515,7 +2515,7 @@ _exportOrImport: userLists: "リスト" excludeMutingUsers: "ミュートしているユーザーを除外" excludeInactiveUsers: "使われていないアカウントを除外" - withReplies: "インポートした人による返信をTLに含むようにする" + withReplies: "返信をTLに含むかの情報がファイルにない場合に、インポートした人による返信をTLに含むようにする" _charts: federation: "連合" From fca63813d8926d2bd05ce6f7da4a4ab985b13480 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 8 May 2025 00:27:36 +0900 Subject: [PATCH 4/5] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a55ab735b4..7b65eeaefe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - ### Server -- +- Enhance: リストやフォローをエクスポートする際にリプライを含むかどうかの情報を含むように ## 2025.5.0 From d9d0fe47fc7d475de31ebd0dd59cf2b1a2f39f5e Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 8 May 2025 01:19:50 +0900 Subject: [PATCH 5/5] update index.d.ts --- locales/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 281568a5fd..1a582e5ba3 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -9549,7 +9549,7 @@ export interface Locale extends ILocale { */ "excludeInactiveUsers": string; /** - * インポートした人による返信をTLに含むようにする + * 返信をTLに含むかの情報がファイルにない場合に、インポートした人による返信をTLに含むようにする */ "withReplies": string; };