Compare commits
9 Commits
578fb2fe37
...
2d37302422
| Author | SHA1 | Date |
|---|---|---|
|
|
2d37302422 | |
|
|
2a88d8ee2d | |
|
|
dade11433d | |
|
|
52a82ac193 | |
|
|
d82b3a08e2 | |
|
|
f6e1ee1d40 | |
|
|
0bddd0ceae | |
|
|
53099cad5a | |
|
|
145c5c8b2b |
|
|
@ -5,7 +5,7 @@
|
|||
"workspaceFolder": "/workspace",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers-contrib/features/pnpm:2": {
|
||||
"version": "8.8.0"
|
||||
"version": "8.9.2"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/node:1": {
|
||||
"version": "20.5.1"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
### Server
|
||||
- Enhance: ストリーミングAPIのパフォーマンスを向上
|
||||
- Fix: users/notesでDBから参照した際にチャンネル投稿のみ取得される問題を修正
|
||||
- Fix: コントロールパネルの設定項目が正しく保存できない問題を修正
|
||||
|
||||
## 2023.10.1
|
||||
### General
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ poll: "アンケート"
|
|||
useCw: "内容を隠す"
|
||||
enablePlayer: "プレイヤーを開く"
|
||||
disablePlayer: "プレイヤーを閉じる"
|
||||
expandTweet: "ツイートを展開する"
|
||||
expandTweet: "ポストを展開する"
|
||||
themeEditor: "テーマエディター"
|
||||
description: "説明"
|
||||
describeFile: "キャプションを付ける"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"type": "git",
|
||||
"url": "https://github.com/misskey-dev/misskey.git"
|
||||
},
|
||||
"packageManager": "pnpm@8.8.0",
|
||||
"packageManager": "pnpm@8.9.2",
|
||||
"workspaces": [
|
||||
"packages/frontend",
|
||||
"packages/backend",
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@
|
|||
"@aws-sdk/client-s3": "3.412.0",
|
||||
"@aws-sdk/lib-storage": "3.412.0",
|
||||
"@smithy/node-http-handler": "2.1.5",
|
||||
"@bull-board/api": "5.8.4",
|
||||
"@bull-board/fastify": "5.8.4",
|
||||
"@bull-board/ui": "5.8.4",
|
||||
"@bull-board/api": "5.9.1",
|
||||
"@bull-board/fastify": "5.9.1",
|
||||
"@bull-board/ui": "5.9.1",
|
||||
"@discordapp/twemoji": "14.1.2",
|
||||
"@fastify/accepts": "4.2.0",
|
||||
"@fastify/cookie": "9.1.0",
|
||||
|
|
@ -155,7 +155,7 @@
|
|||
"strict-event-emitter-types": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"summaly": "github:misskey-dev/summaly",
|
||||
"systeminformation": "5.21.11",
|
||||
"systeminformation": "5.21.12",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tmp": "0.2.1",
|
||||
"tsc-alias": "1.8.8",
|
||||
|
|
@ -173,13 +173,13 @@
|
|||
"@jest/globals": "29.7.0",
|
||||
"@simplewebauthn/typescript-types": "8.0.0",
|
||||
"@swc/jest": "0.2.29",
|
||||
"@types/accepts": "1.3.5",
|
||||
"@types/archiver": "5.3.3",
|
||||
"@types/bcryptjs": "2.4.4",
|
||||
"@types/body-parser": "1.19.3",
|
||||
"@types/accepts": "1.3.6",
|
||||
"@types/archiver": "5.3.4",
|
||||
"@types/bcryptjs": "2.4.5",
|
||||
"@types/body-parser": "1.19.4",
|
||||
"@types/cbor": "6.0.0",
|
||||
"@types/color-convert": "2.0.1",
|
||||
"@types/content-disposition": "0.5.6",
|
||||
"@types/color-convert": "2.0.2",
|
||||
"@types/content-disposition": "0.5.7",
|
||||
"@types/fluent-ffmpeg": "2.1.22",
|
||||
"@types/http-link-header": "1.0.3",
|
||||
"@types/jest": "29.5.5",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import type { AntennasRepository, UserListMembershipsRepository } from '@/models
|
|||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -39,7 +39,7 @@ export class AntennaService implements OnApplicationShutdown {
|
|||
|
||||
private utilityService: UtilityService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
this.antennasFetched = false;
|
||||
this.antennas = [];
|
||||
|
|
@ -84,7 +84,7 @@ export class AntennaService implements OnApplicationShutdown {
|
|||
const redisPipeline = this.redisForTimelines.pipeline();
|
||||
|
||||
for (const antenna of matchedAntennas) {
|
||||
this.redisTimelineService.push(`antennaTimeline:${antenna.id}`, note.id, 200, redisPipeline);
|
||||
this.funoutTimelineService.push(`antennaTimeline:${antenna.id}`, note.id, 200, redisPipeline);
|
||||
this.globalEventService.publishAntennaStream(antenna.id, 'note', note);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ import { FileInfoService } from './FileInfoService.js';
|
|||
import { SearchService } from './SearchService.js';
|
||||
import { ClipService } from './ClipService.js';
|
||||
import { FeaturedService } from './FeaturedService.js';
|
||||
import { RedisTimelineService } from './RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from './FunoutTimelineService.js';
|
||||
import { ChartLoggerService } from './chart/ChartLoggerService.js';
|
||||
import FederationChart from './chart/charts/federation.js';
|
||||
import NotesChart from './chart/charts/notes.js';
|
||||
|
|
@ -190,7 +190,7 @@ const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: Fi
|
|||
const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService };
|
||||
const $ClipService: Provider = { provide: 'ClipService', useExisting: ClipService };
|
||||
const $FeaturedService: Provider = { provide: 'FeaturedService', useExisting: FeaturedService };
|
||||
const $RedisTimelineService: Provider = { provide: 'RedisTimelineService', useExisting: RedisTimelineService };
|
||||
const $FunoutTimelineService: Provider = { provide: 'FunoutTimelineService', useExisting: FunoutTimelineService };
|
||||
|
||||
const $ChartLoggerService: Provider = { provide: 'ChartLoggerService', useExisting: ChartLoggerService };
|
||||
const $FederationChart: Provider = { provide: 'FederationChart', useExisting: FederationChart };
|
||||
|
|
@ -323,7 +323,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||
SearchService,
|
||||
ClipService,
|
||||
FeaturedService,
|
||||
RedisTimelineService,
|
||||
FunoutTimelineService,
|
||||
ChartLoggerService,
|
||||
FederationChart,
|
||||
NotesChart,
|
||||
|
|
@ -449,7 +449,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||
$SearchService,
|
||||
$ClipService,
|
||||
$FeaturedService,
|
||||
$RedisTimelineService,
|
||||
$FunoutTimelineService,
|
||||
$ChartLoggerService,
|
||||
$FederationChart,
|
||||
$NotesChart,
|
||||
|
|
@ -576,7 +576,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||
SearchService,
|
||||
ClipService,
|
||||
FeaturedService,
|
||||
RedisTimelineService,
|
||||
FunoutTimelineService,
|
||||
FederationChart,
|
||||
NotesChart,
|
||||
UsersChart,
|
||||
|
|
@ -701,7 +701,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
|||
$SearchService,
|
||||
$ClipService,
|
||||
$FeaturedService,
|
||||
$RedisTimelineService,
|
||||
$FunoutTimelineService,
|
||||
$FederationChart,
|
||||
$NotesChart,
|
||||
$UsersChart,
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
|
|||
|
||||
const queryOrNull = async () => (await this.emojisRepository.findOneBy({
|
||||
name,
|
||||
host: host ?? IsNull(),
|
||||
host,
|
||||
})) ?? null;
|
||||
|
||||
const emoji = await this.cache.fetch(`${name} ${host}`, queryOrNull);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { bindThis } from '@/decorators.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
|
||||
@Injectable()
|
||||
export class RedisTimelineService {
|
||||
export class FunoutTimelineService {
|
||||
constructor(
|
||||
@Inject(DI.redisForTimelines)
|
||||
private redisForTimelines: Redis.Redis,
|
||||
|
|
@ -45,7 +45,7 @@ export class HashtagService {
|
|||
await this.updateHashtag(user, tag, true, true);
|
||||
}
|
||||
|
||||
for (const tag of (user.tags ?? []).filter(x => !tags.includes(x))) {
|
||||
for (const tag of user.tags.filter(x => !tags.includes(x))) {
|
||||
await this.updateHashtag(user, tag, true, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ import { RoleService } from '@/core/RoleService.js';
|
|||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { SearchService } from '@/core/SearchService.js';
|
||||
import { FeaturedService } from '@/core/FeaturedService.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { nyaize } from '@/misc/nyaize.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
private idService: IdService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private queueService: QueueService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
private noteReadService: NoteReadService,
|
||||
private notificationService: NotificationService,
|
||||
private relayService: RelayService,
|
||||
|
|
@ -317,7 +317,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
data.text = data.text.trim();
|
||||
|
||||
if (user.isCat) {
|
||||
patsedText = patsedText ?? mfm.parse(data.text);
|
||||
patsedText = mfm.parse(data.text);
|
||||
function nyaizeNode(node: mfm.MfmNode) {
|
||||
if (node.type === 'quote') return;
|
||||
if (node.type === 'text') {
|
||||
|
|
@ -359,7 +359,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
|
||||
}
|
||||
|
||||
tags = tags.filter(tag => Array.from(tag ?? '').length <= 128).splice(0, 32);
|
||||
tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);
|
||||
|
||||
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
|
||||
mentionedUsers.push(await this.usersRepository.findOneByOrFail({ id: data.reply!.userId }));
|
||||
|
|
@ -851,9 +851,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
const r = this.redisForTimelines.pipeline();
|
||||
|
||||
if (note.channelId) {
|
||||
this.redisTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r);
|
||||
this.funoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r);
|
||||
|
||||
this.redisTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
this.funoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
|
||||
const channelFollowings = await this.channelFollowingsRepository.find({
|
||||
where: {
|
||||
|
|
@ -863,9 +863,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
});
|
||||
|
||||
for (const channelFollowing of channelFollowings) {
|
||||
this.redisTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
this.funoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.redisTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
this.funoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -903,9 +903,9 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
if (!following.withReplies) continue;
|
||||
}
|
||||
|
||||
this.redisTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
this.funoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.redisTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
this.funoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -921,36 +921,36 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||
if (!userListMembership.withReplies) continue;
|
||||
}
|
||||
|
||||
this.redisTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r);
|
||||
this.funoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.redisTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r);
|
||||
this.funoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
|
||||
if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身のHTL
|
||||
this.redisTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
this.funoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.redisTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
this.funoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
|
||||
}
|
||||
}
|
||||
|
||||
// 自分自身以外への返信
|
||||
if (note.replyId && note.replyUserId !== note.userId) {
|
||||
this.redisTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
this.funoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
|
||||
if (note.visibility === 'public' && note.userHost == null) {
|
||||
this.redisTimelineService.push('localTimelineWithReplies', note.id, 300, r);
|
||||
this.funoutTimelineService.push('localTimelineWithReplies', note.id, 300, r);
|
||||
}
|
||||
} else {
|
||||
this.redisTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
this.funoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.redisTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r);
|
||||
this.funoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r);
|
||||
}
|
||||
|
||||
if (note.visibility === 'public' && note.userHost == null) {
|
||||
this.redisTimelineService.push('localTimeline', note.id, 1000, r);
|
||||
this.funoutTimelineService.push('localTimeline', note.id, 1000, r);
|
||||
if (note.fileIds.length > 0) {
|
||||
this.redisTimelineService.push('localTimelineWithFiles', note.id, 500, r);
|
||||
this.funoutTimelineService.push('localTimelineWithFiles', note.id, 500, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ export class ReactionService {
|
|||
reaction = FALLBACK;
|
||||
}
|
||||
} else {
|
||||
reaction = this.normalize(reaction ?? null);
|
||||
reaction = this.normalize(reaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { IdService } from '@/core/IdService.js';
|
|||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import type { Packed } from '@/misc/json-schema.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||
|
||||
export type RolePolicies = {
|
||||
|
|
@ -103,7 +103,7 @@ export class RoleService implements OnApplicationShutdown {
|
|||
private globalEventService: GlobalEventService,
|
||||
private idService: IdService,
|
||||
private moderationLogService: ModerationLogService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
//this.onMessage = this.onMessage.bind(this);
|
||||
|
||||
|
|
@ -470,7 +470,7 @@ export class RoleService implements OnApplicationShutdown {
|
|||
const redisPipeline = this.redisClient.pipeline();
|
||||
|
||||
for (const role of roles) {
|
||||
this.redisTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline);
|
||||
this.funoutTimelineService.push(`roleTimeline:${role.id}`, note.id, 1000, redisPipeline);
|
||||
this.globalEventService.publishRoleTimelineStream(role.id, 'note', note);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ export class DriveFileEntityService {
|
|||
if (file.type.startsWith('video')) {
|
||||
if (file.thumbnailUrl) return file.thumbnailUrl;
|
||||
|
||||
return this.videoProcessingService.getExternalVideoThumbnailUrl(file.webpublicUrl ?? file.url ?? file.uri);
|
||||
return this.videoProcessingService.getExternalVideoThumbnailUrl(file.webpublicUrl ?? file.url);
|
||||
} else if (file.uri != null && file.userHost != null && this.config.externalMediaProxyEnabled) {
|
||||
// 動画ではなくリモートかつメディアプロキシ
|
||||
return this.getProxiedUrl(file.uri, 'static');
|
||||
|
|
@ -145,7 +145,7 @@ export class DriveFileEntityService {
|
|||
.select('SUM(file.size)', 'sum')
|
||||
.getRawOne();
|
||||
|
||||
return parseInt(sum, 10) ?? 0;
|
||||
return parseInt(sum, 10) || 0;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -157,7 +157,7 @@ export class DriveFileEntityService {
|
|||
.select('SUM(file.size)', 'sum')
|
||||
.getRawOne();
|
||||
|
||||
return parseInt(sum, 10) ?? 0;
|
||||
return parseInt(sum, 10) || 0;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -169,7 +169,7 @@ export class DriveFileEntityService {
|
|||
.select('SUM(file.size)', 'sum')
|
||||
.getRawOne();
|
||||
|
||||
return parseInt(sum, 10) ?? 0;
|
||||
return parseInt(sum, 10) || 0;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
@ -181,7 +181,7 @@ export class DriveFileEntityService {
|
|||
.select('SUM(file.size)', 'sum')
|
||||
.getRawOne();
|
||||
|
||||
return parseInt(sum, 10) ?? 0;
|
||||
return parseInt(sum, 10) || 0;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ export class NoteEntityService implements OnModuleInit {
|
|||
text: text,
|
||||
cw: note.cw,
|
||||
visibility: note.visibility,
|
||||
localOnly: note.localOnly ?? undefined,
|
||||
localOnly: note.localOnly,
|
||||
reactionAcceptance: note.reactionAcceptance,
|
||||
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
|
||||
renoteCount: note.renoteCount,
|
||||
|
|
|
|||
|
|
@ -333,8 +333,8 @@ export class UserEntityService implements OnModuleInit {
|
|||
host: user.host,
|
||||
avatarUrl: user.avatarUrl ?? this.getIdenticonUrl(user),
|
||||
avatarBlurhash: user.avatarBlurhash,
|
||||
isBot: user.isBot ?? falsy,
|
||||
isCat: user.isCat ?? falsy,
|
||||
isBot: user.isBot,
|
||||
isCat: user.isCat,
|
||||
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
|
||||
name: instance.name,
|
||||
softwareName: instance.softwareName,
|
||||
|
|
@ -367,7 +367,7 @@ export class UserEntityService implements OnModuleInit {
|
|||
bannerBlurhash: user.bannerBlurhash,
|
||||
isLocked: user.isLocked,
|
||||
isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote),
|
||||
isSuspended: user.isSuspended ?? falsy,
|
||||
isSuspended: user.isSuspended,
|
||||
description: profile!.description,
|
||||
location: profile!.location,
|
||||
birthday: profile!.birthday,
|
||||
|
|
|
|||
|
|
@ -108,6 +108,5 @@ async function net() {
|
|||
|
||||
// FS STAT
|
||||
async function fs() {
|
||||
const data = await si.disksIO().catch(() => ({ rIO_sec: 0, wIO_sec: 0 }));
|
||||
return data ?? { rIO_sec: 0, wIO_sec: 0 };
|
||||
return await si.disksIO().catch(() => ({ rIO_sec: 0, wIO_sec: 0 }));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export class InboxProcessorService {
|
|||
if (err.isClientError) {
|
||||
throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`);
|
||||
}
|
||||
throw new Error(`Error in actor ${activity.actor} - ${err.statusCode ?? err}`);
|
||||
throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ export const paramDef = {
|
|||
tosUrl: { type: 'string', nullable: true },
|
||||
repositoryUrl: { type: 'string' },
|
||||
feedbackUrl: { type: 'string' },
|
||||
impressumUrl: { type: 'string' },
|
||||
privacyPolicyUrl: { type: 'string' },
|
||||
impressumUrl: { type: 'string', nullable: true },
|
||||
privacyPolicyUrl: { type: 'string', nullable: true },
|
||||
useObjectStorage: { type: 'boolean' },
|
||||
objectStorageBaseUrl: { type: 'string', nullable: true },
|
||||
objectStorageBucket: { type: 'string', nullable: true },
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { NoteReadService } from '@/core/NoteReadService.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
|
@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private noteEntityService: NoteEntityService,
|
||||
private queryService: QueryService,
|
||||
private noteReadService: NoteReadService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
|
|
@ -90,7 +90,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
lastUsedAt: new Date(),
|
||||
});
|
||||
|
||||
let noteIds = await this.redisTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId);
|
||||
let noteIds = await this.funoutTimelineService.get(`antennaTimeline:${antenna.id}`, untilId, sinceId);
|
||||
noteIds = noteIds.slice(0, ps.limit);
|
||||
if (noteIds.length === 0) {
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
|||
import ActiveUsersChart from '@/core/chart/charts/active-users.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
|
@ -69,7 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private idService: IdService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private queryService: QueryService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
private cacheService: CacheService,
|
||||
private activeUsersChart: ActiveUsersChart,
|
||||
) {
|
||||
|
|
@ -95,7 +95,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
this.cacheService.userMutingsCache.fetch(me.id),
|
||||
]) : [new Set<string>()];
|
||||
|
||||
let noteIds = await this.redisTimelineService.get(`channelTimeline:${channel.id}`, untilId, sinceId);
|
||||
let noteIds = await this.funoutTimelineService.get(`channelTimeline:${channel.id}`, untilId, sinceId);
|
||||
noteIds = noteIds.slice(0, ps.limit);
|
||||
|
||||
if (noteIds.length > 0) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { RoleService } from '@/core/RoleService.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
|
@ -74,7 +74,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private activeUsersChart: ActiveUsersChart,
|
||||
private idService: IdService,
|
||||
private cacheService: CacheService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
|
|
@ -98,20 +98,20 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
let noteIds: string[];
|
||||
|
||||
if (ps.withFiles) {
|
||||
const [htlNoteIds, ltlNoteIds] = await this.redisTimelineService.getMulti([
|
||||
const [htlNoteIds, ltlNoteIds] = await this.funoutTimelineService.getMulti([
|
||||
`homeTimelineWithFiles:${me.id}`,
|
||||
'localTimelineWithFiles',
|
||||
], untilId, sinceId);
|
||||
noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds]));
|
||||
} else if (ps.withReplies) {
|
||||
const [htlNoteIds, ltlNoteIds, ltlReplyNoteIds] = await this.redisTimelineService.getMulti([
|
||||
const [htlNoteIds, ltlNoteIds, ltlReplyNoteIds] = await this.funoutTimelineService.getMulti([
|
||||
`homeTimeline:${me.id}`,
|
||||
'localTimeline',
|
||||
'localTimelineWithReplies',
|
||||
], untilId, sinceId);
|
||||
noteIds = Array.from(new Set([...htlNoteIds, ...ltlNoteIds, ...ltlReplyNoteIds]));
|
||||
} else {
|
||||
const [htlNoteIds, ltlNoteIds] = await this.redisTimelineService.getMulti([
|
||||
const [htlNoteIds, ltlNoteIds] = await this.funoutTimelineService.getMulti([
|
||||
`homeTimeline:${me.id}`,
|
||||
'localTimeline',
|
||||
], untilId, sinceId);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { RoleService } from '@/core/RoleService.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
|
@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private activeUsersChart: ActiveUsersChart,
|
||||
private idService: IdService,
|
||||
private cacheService: CacheService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
|
|
@ -94,9 +94,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
let noteIds: string[];
|
||||
|
||||
if (ps.withFiles) {
|
||||
noteIds = await this.redisTimelineService.get('localTimelineWithFiles', untilId, sinceId);
|
||||
noteIds = await this.funoutTimelineService.get('localTimelineWithFiles', untilId, sinceId);
|
||||
} else {
|
||||
const [nonReplyNoteIds, replyNoteIds] = await this.redisTimelineService.getMulti([
|
||||
const [nonReplyNoteIds, replyNoteIds] = await this.funoutTimelineService.getMulti([
|
||||
'localTimeline',
|
||||
'localTimelineWithReplies',
|
||||
], untilId, sinceId);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { DI } from '@/di-symbols.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
|
@ -63,7 +63,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private activeUsersChart: ActiveUsersChart,
|
||||
private idService: IdService,
|
||||
private cacheService: CacheService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
|
|
@ -81,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
this.cacheService.userBlockedCache.fetch(me.id),
|
||||
]);
|
||||
|
||||
let noteIds = await this.redisTimelineService.get(ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, untilId, sinceId);
|
||||
let noteIds = await this.funoutTimelineService.get(ps.withFiles ? `homeTimelineWithFiles:${me.id}` : `homeTimeline:${me.id}`, untilId, sinceId);
|
||||
noteIds = noteIds.slice(0, ps.limit);
|
||||
|
||||
if (noteIds.length === 0) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { DI } from '@/di-symbols.js';
|
|||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
|
@ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private activeUsersChart: ActiveUsersChart,
|
||||
private cacheService: CacheService,
|
||||
private idService: IdService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
|
|
@ -105,7 +105,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
this.cacheService.userBlockedCache.fetch(me.id),
|
||||
]);
|
||||
|
||||
let noteIds = await this.redisTimelineService.get(ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, untilId, sinceId);
|
||||
let noteIds = await this.funoutTimelineService.get(ps.withFiles ? `userListTimelineWithFiles:${list.id}` : `userListTimeline:${list.id}`, untilId, sinceId);
|
||||
noteIds = noteIds.slice(0, ps.limit);
|
||||
|
||||
if (noteIds.length === 0) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { QueryService } from '@/core/QueryService.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
|
@ -66,7 +66,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private idService: IdService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private queryService: QueryService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
|
|
@ -84,7 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
return [];
|
||||
}
|
||||
|
||||
let noteIds = await this.redisTimelineService.get(`roleTimeline:${role.id}`, untilId, sinceId);
|
||||
let noteIds = await this.funoutTimelineService.get(`roleTimeline:${role.id}`, untilId, sinceId);
|
||||
noteIds = noteIds.slice(0, ps.limit);
|
||||
|
||||
if (noteIds.length === 0) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { CacheService } from '@/core/CacheService.js';
|
|||
import { IdService } from '@/core/IdService.js';
|
||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { RedisTimelineService } from '@/core/RedisTimelineService.js';
|
||||
import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
|
|
@ -71,7 +71,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private queryService: QueryService,
|
||||
private cacheService: CacheService,
|
||||
private idService: IdService,
|
||||
private redisTimelineService: RedisTimelineService,
|
||||
private funoutTimelineService: FunoutTimelineService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
||||
|
|
@ -87,9 +87,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
]) : [new Set<string>()];
|
||||
|
||||
const [noteIdsRes, repliesNoteIdsRes, channelNoteIdsRes] = await Promise.all([
|
||||
this.redisTimelineService.get(ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, untilId, sinceId),
|
||||
ps.withReplies ? this.redisTimelineService.get(`userTimelineWithReplies:${ps.userId}`, untilId, sinceId) : Promise.resolve([]),
|
||||
ps.withChannelNotes ? this.redisTimelineService.get(`userTimelineWithChannel:${ps.userId}`, untilId, sinceId) : Promise.resolve([]),
|
||||
this.funoutTimelineService.get(ps.withFiles ? `userTimelineWithFiles:${ps.userId}` : `userTimeline:${ps.userId}`, untilId, sinceId),
|
||||
ps.withReplies ? this.funoutTimelineService.get(`userTimelineWithReplies:${ps.userId}`, untilId, sinceId) : Promise.resolve([]),
|
||||
ps.withChannelNotes ? this.funoutTimelineService.get(`userTimelineWithChannel:${ps.userId}`, untilId, sinceId) : Promise.resolve([]),
|
||||
]);
|
||||
|
||||
let noteIds = Array.from(new Set([
|
||||
|
|
@ -151,7 +151,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
||||
|
||||
if (ps.withChannelNotes) {
|
||||
if (!isSelf) query.andWhere('channel.isSensitive = false');
|
||||
if (!isSelf) query.andWhere(new Brackets(qb => {
|
||||
qb.orWhere('note.channelId IS NULL');
|
||||
qb.orWhere('channel.isSensitive = false');
|
||||
}));
|
||||
} else {
|
||||
query.andWhere('note.channelId IS NULL');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class HomeTimelineChannel extends Channel {
|
|||
}
|
||||
|
||||
// Ignore notes from instances the user has muted
|
||||
if (isInstanceMuted(note, new Set<string>(this.userProfile!.mutedInstances ?? []))) return;
|
||||
if (isInstanceMuted(note, new Set<string>(this.userProfile!.mutedInstances))) return;
|
||||
|
||||
if (note.visibility === 'followers') {
|
||||
if (!Object.hasOwn(this.following, note.userId)) return;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class HybridTimelineChannel extends Channel {
|
|||
}
|
||||
|
||||
// Ignore notes from instances the user has muted
|
||||
if (isInstanceMuted(note, new Set<string>(this.userProfile!.mutedInstances ?? []))) return;
|
||||
if (isInstanceMuted(note, new Set<string>(this.userProfile!.mutedInstances))) return;
|
||||
|
||||
// 関係ない返信は除外
|
||||
if (note.reply && !this.following[note.userId]?.withReplies && !this.withReplies) {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export class FeedService {
|
|||
date: this.idService.parse(note.id).date,
|
||||
description: note.cw ?? undefined,
|
||||
content: note.text ?? undefined,
|
||||
image: file ? this.driveFileEntityService.getPublicUrl(file) ?? undefined : undefined,
|
||||
image: file ? this.driveFileEntityService.getPublicUrl(file) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,24 +78,24 @@
|
|||
"vuedraggable": "next"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-actions": "7.4.6",
|
||||
"@storybook/addon-essentials": "7.4.6",
|
||||
"@storybook/addon-interactions": "7.4.6",
|
||||
"@storybook/addon-links": "7.4.6",
|
||||
"@storybook/addon-storysource": "7.4.6",
|
||||
"@storybook/addons": "7.4.6",
|
||||
"@storybook/blocks": "7.4.6",
|
||||
"@storybook/core-events": "7.4.6",
|
||||
"@storybook/addon-actions": "7.5.0",
|
||||
"@storybook/addon-essentials": "7.5.0",
|
||||
"@storybook/addon-interactions": "7.5.0",
|
||||
"@storybook/addon-links": "7.5.0",
|
||||
"@storybook/addon-storysource": "7.5.0",
|
||||
"@storybook/addons": "7.5.0",
|
||||
"@storybook/blocks": "7.5.0",
|
||||
"@storybook/core-events": "7.5.0",
|
||||
"@storybook/jest": "0.2.3",
|
||||
"@storybook/manager-api": "7.4.6",
|
||||
"@storybook/preview-api": "7.4.6",
|
||||
"@storybook/react": "7.4.6",
|
||||
"@storybook/react-vite": "7.4.6",
|
||||
"@storybook/manager-api": "7.5.0",
|
||||
"@storybook/preview-api": "7.5.0",
|
||||
"@storybook/react": "7.5.0",
|
||||
"@storybook/react-vite": "7.5.0",
|
||||
"@storybook/testing-library": "0.2.2",
|
||||
"@storybook/theming": "7.4.6",
|
||||
"@storybook/types": "7.4.6",
|
||||
"@storybook/vue3": "7.4.6",
|
||||
"@storybook/vue3-vite": "7.4.6",
|
||||
"@storybook/theming": "7.5.0",
|
||||
"@storybook/types": "7.5.0",
|
||||
"@storybook/vue3": "7.5.0",
|
||||
"@storybook/vue3-vite": "7.5.0",
|
||||
"@testing-library/vue": "7.0.0",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
"@types/estree": "1.0.2",
|
||||
|
|
@ -129,7 +129,7 @@
|
|||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"start-server-and-test": "2.0.1",
|
||||
"storybook": "7.4.6",
|
||||
"storybook": "7.5.0",
|
||||
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
||||
"summaly": "github:misskey-dev/summaly",
|
||||
"vite-plugin-turbosnap": "1.0.3",
|
||||
|
|
|
|||
|
|
@ -190,6 +190,9 @@ const patronsWithIcon = [{
|
|||
}, {
|
||||
name: '百日紅',
|
||||
icon: 'https://misskey-hub.net/patrons/302dce2898dd457ba03c3f7dc037900b.jpg',
|
||||
}, {
|
||||
name: 'taichan',
|
||||
icon: 'https://misskey-hub.net/patrons/f981ab0159fb4e2c998e05f7263e1cd9.png',
|
||||
}];
|
||||
|
||||
const patrons = [
|
||||
|
|
|
|||
965
pnpm-lock.yaml
965
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue