Merge branch 'develop' into pr/ThatOneCalculator/8764
This commit is contained in:
		
						commit
						c8200e63b4
					
				
					 33 changed files with 134 additions and 43 deletions
				
			
		|  | @ -10,8 +10,8 @@ | |||
| 		"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json", | ||||
| 		"watch": "node watch.mjs", | ||||
| 		"lint": "eslint --quiet \"src/**/*.ts\"", | ||||
| 		"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --detectOpenHandles --runInBand", | ||||
| 		"jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --detectOpenHandles --runInBand", | ||||
| 		"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand", | ||||
| 		"jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand", | ||||
| 		"jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache", | ||||
| 		"test": "yarn jest", | ||||
| 		"test-and-coverage": "yarn jest-and-coverage" | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { UsersRepository } from '@/models/index.js'; | ||||
| import type { NotesRepository, UserNotePiningsRepository, UsersRepository } from '@/models/index.js'; | ||||
| import { IdentifiableError } from '@/misc/identifiable-error.js'; | ||||
| import type { User } from '@/models/entities/User.js'; | ||||
| import type { Note } from '@/models/entities/Note.js'; | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import type { Packed } from '@/misc/schema.js'; | |||
| import type { Note } from '@/models/entities/Note.js'; | ||||
| import { IdService } from '@/core/IdService.js'; | ||||
| import { GlobalEventService } from '@/core/GlobalEventService.js'; | ||||
| import type { UsersRepository, NoteUnreadsRepository, MutingsRepository, NoteThreadMutingsRepository, FollowingsRepository, ChannelFollowingsRepository, AntennaNotesRepository } from '@/models/index.js'; | ||||
| import { UserEntityService } from './entities/UserEntityService.js'; | ||||
| import { NotificationService } from './NotificationService.js'; | ||||
| import { AntennaService } from './AntennaService.js'; | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { Not } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { NotesRepository, UsersRepository, BlockingsRepository } from '@/models/index.js'; | ||||
| import type { NotesRepository, UsersRepository, BlockingsRepository, PollsRepository, PollVotesRepository } from '@/models/index.js'; | ||||
| import type { Note } from '@/models/entities/Note.js'; | ||||
| import { RelayService } from '@/core/RelayService.js'; | ||||
| import type { CacheableUser } from '@/models/entities/User.js'; | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; | |||
| import { Brackets } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { User } from '@/models/entities/User.js'; | ||||
| import type { UserProfilesRepository, FollowingsRepository, ChannelFollowingsRepository, MutedNotesRepository, BlockingsRepository, NoteThreadMutingsRepository, MutingsRepository } from '@/models/index.js'; | ||||
| import type { SelectQueryBuilder } from 'typeorm'; | ||||
| 
 | ||||
| @Injectable() | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ export class QueueService { | |||
| 		@Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue, | ||||
| 	) {} | ||||
| 
 | ||||
| 	public deliver(user: ThinUser, content: IActivity, to: string | null) { | ||||
| 	public deliver(user: ThinUser, content: IActivity | null, to: string | null) { | ||||
| 		if (content == null) return null; | ||||
| 		if (to == null) return null; | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ import { QueueService } from '@/core/QueueService.js'; | |||
| import { GlobalEventService } from '@/core/GlobalEventService.js'; | ||||
| import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import logger from '@/logger.js'; | ||||
| import type { UsersRepository, FollowingsRepository, FollowRequestsRepository, BlockingsRepository, UserListsRepository, UserListJoiningsRepository } from '@/models/index.js'; | ||||
| import { UserEntityService } from './entities/UserEntityService.js'; | ||||
| import { WebhookService } from './WebhookService.js'; | ||||
| import { ApRendererService } from './remote/activitypub/ApRendererService.js'; | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; | |||
| import { WebhookService } from '@/core/WebhookService.js'; | ||||
| import { CreateNotificationService } from '@/core/CreateNotificationService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { BlockingsRepository, FollowingsRepository, FollowRequestsRepository, InstancesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js'; | ||||
| import Logger from '../logger.js'; | ||||
| import { UserEntityService } from './entities/UserEntityService.js'; | ||||
| import { ApRendererService } from './remote/activitypub/ApRendererService.js'; | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ import { DataSource, In } from 'typeorm'; | |||
| import * as mfm from 'mfm-js'; | ||||
| import { ModuleRef } from '@nestjs/core'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { Notes, Polls, PollVotes, DriveFiles, Channels, Followings, Users, NoteReactions } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type { Packed } from '@/misc/schema.js'; | ||||
| import { nyaize } from '@/misc/nyaize.js'; | ||||
|  | @ -11,6 +10,7 @@ import { awaitAll } from '@/misc/prelude/await-all.js'; | |||
| import type { User } from '@/models/entities/User.js'; | ||||
| import type { Note } from '@/models/entities/Note.js'; | ||||
| import type { NoteReaction } from '@/models/entities/NoteReaction.js'; | ||||
| import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository, DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { OnModuleInit } from '@nestjs/common'; | ||||
| import type { CustomEmojiService } from '../CustomEmojiService.js'; | ||||
| import type { ReactionService } from '../ReactionService.js'; | ||||
|  | @ -267,7 +267,7 @@ export class NoteEntityService implements OnModuleInit { | |||
| 		let text = note.text; | ||||
| 
 | ||||
| 		if (note.name && (note.url ?? note.uri)) { | ||||
| 			text = `【${note.name}】\n${(note.text || '').trim()}\n\n${note.url ?? note.uri}`; | ||||
| 			text = `【${note.name}】\n${(note.text ?? '').trim()}\n\n${note.url ?? note.uri}`; | ||||
| 		} | ||||
| 
 | ||||
| 		const channel = note.channelId | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { forwardRef, Inject, Injectable } from '@nestjs/common'; | ||||
| import { EntityRepository, Repository, In, Not } from 'typeorm'; | ||||
| import { In, Not } from 'typeorm'; | ||||
| import Ajv from 'ajv'; | ||||
| import { ModuleRef } from '@nestjs/core'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
|  | @ -12,6 +12,7 @@ import { Cache } from '@/misc/cache.js'; | |||
| import type { Instance } from '@/models/entities/Instance.js'; | ||||
| import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js'; | ||||
| import { birthdaySchema, descriptionSchema, localUsernameSchema, locationSchema, nameSchema, passwordSchema } from '@/models/entities/User.js'; | ||||
| import type { UsersRepository, UserSecurityKeysRepository, FollowingsRepository, FollowRequestsRepository, BlockingsRepository, MutingsRepository, DriveFilesRepository, NoteUnreadsRepository, ChannelFollowingsRepository, NotificationsRepository, UserNotePiningsRepository, UserProfilesRepository, InstancesRepository, AnnouncementReadsRepository, MessagingMessagesRepository, UserGroupJoiningsRepository, AnnouncementsRepository, AntennaNotesRepository, PagesRepository } from '@/models/index.js'; | ||||
| import type { OnModuleInit } from '@nestjs/common'; | ||||
| import type { AntennaService } from '../AntennaService.js'; | ||||
| import type { CustomEmojiService } from '../CustomEmojiService.js'; | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; | |||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { QueueService } from '@/core/QueueService.js'; | ||||
| import { MessagingService } from '@/core/MessagingService.js'; | ||||
| import type { UsersRepository, NotesRepository, FollowingsRepository, MessagingMessagesRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js'; | ||||
| import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; | ||||
| import { ApNoteService } from './models/ApNoteService.js'; | ||||
| import { ApLoggerService } from './ApLoggerService.js'; | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import { MfmService } from '@/core/MfmService.js'; | |||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; | ||||
| import type { UserKeypair } from '@/models/entities/UserKeypair.js'; | ||||
| import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, EmojisRepository, PollsRepository } from '@/models/index.js'; | ||||
| import { LdSignatureService } from './LdSignatureService.js'; | ||||
| import { ApMfmService } from './ApMfmService.js'; | ||||
| import type { IActivity } from './type.js'; | ||||
|  |  | |||
|  | @ -81,12 +81,12 @@ class LdSignature { | |||
| 		delete transformedOptions['id']; | ||||
| 		delete transformedOptions['signatureValue']; | ||||
| 		const canonizedOptions = await this.normalize(transformedOptions); | ||||
| 		const optionsHash = this.sha256(canonizedOptions); | ||||
| 		const optionsHash = this.sha256(canonizedOptions.toString()); | ||||
| 		const transformedData = { ...data }; | ||||
| 		delete transformedData['signature']; | ||||
| 		const cannonidedData = await this.normalize(transformedData); | ||||
| 		if (this.debug) console.debug(`cannonidedData: ${cannonidedData}`); | ||||
| 		const documentHash = this.sha256(cannonidedData); | ||||
| 		const documentHash = this.sha256(cannonidedData.toString()); | ||||
| 		const verifyData = `${optionsHash}${documentHash}`; | ||||
| 		return verifyData; | ||||
| 	} | ||||
|  |  | |||
|  | @ -1,8 +0,0 @@ | |||
| import * as mfm from 'mfm-js'; | ||||
| import type { Note } from '@/models/entities/Note.js'; | ||||
| import { toHtml } from '../../../../mfm/to-html.js'; | ||||
| 
 | ||||
| export default function(note: Note) { | ||||
| 	if (!note.text) return ''; | ||||
| 	return toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers)); | ||||
| } | ||||
|  | @ -53,7 +53,7 @@ export class DbQueueProcessorsService { | |||
| 			importBlocking: (job, done) => this.importBlockingProcessorService.process(job, done), | ||||
| 			importUserLists: (job, done) => this.importUserListsProcessorService.process(job, done), | ||||
| 			importCustomEmojis: (job, done) => this.importCustomEmojisProcessorService.process(job, done), | ||||
| 			deleteAccount: (job, done) => this.deleteAccountProcessorService.process(job, done), | ||||
| 			deleteAccount: (job) => this.deleteAccountProcessorService.process(job), | ||||
| 		} as Record<string, Bull.ProcessCallbackFunction<DbJobData | Bull.ProcessPromiseFunction<DbJobData>>>; | ||||
| 		 | ||||
| 		for (const [k, v] of Object.entries(jobs)) { | ||||
|  |  | |||
|  | @ -19,8 +19,8 @@ export class ObjectStorageQueueProcessorsService { | |||
| 
 | ||||
| 	public start(q: Bull.Queue) { | ||||
| 		const jobs = { | ||||
| 			deleteFile: (job, done) => this.deleteFileProcessorService.process(job, done), | ||||
| 			cleanRemoteFiles: (job, done) => this.cleanRemoteFilesProcessorService.process(job, done), | ||||
| 			deleteFile: (job) => this.deleteFileProcessorService.process(job), | ||||
| 			cleanRemoteFiles: (job) => this.cleanRemoteFilesProcessorService.process(job), | ||||
| 		} as Record<string, Bull.ProcessCallbackFunction<ObjectStorageJobData | Bull.ProcessPromiseFunction<ObjectStorageJobData>>>; | ||||
| 		 | ||||
| 		for (const [k, v] of Object.entries(jobs)) { | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { MoreThan } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { DriveFilesRepository, UserProfilesRepository } from '@/models/index.js'; | ||||
| import type { DriveFilesRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import { DriveService } from '@/core/DriveService.js'; | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ import { Inject, Injectable } from '@nestjs/common'; | |||
| import { In, MoreThan, Not } from 'typeorm'; | ||||
| import { format as dateFormat } from 'date-fns'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { FollowingsRepository, MutingsRepository } from '@/models/index.js'; | ||||
| import type { UsersRepository, FollowingsRepository, MutingsRepository } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import { DriveService } from '@/core/DriveService.js'; | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { IsNull, MoreThan } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { BlockingsRepository, DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { UsersRepository, BlockingsRepository, DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import * as Acct from '@/misc/acct.js'; | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { IsNull, MoreThan } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { UsersRepository, DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import * as Acct from '@/misc/acct.js'; | ||||
|  |  | |||
|  | @ -1,13 +1,12 @@ | |||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { IsNull, MoreThan } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { UsersRepository, DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import * as Acct from '@/misc/acct.js'; | ||||
| import { ResolveUserService } from '@/core/remote/ResolveUserService.js'; | ||||
| import { DownloadService } from '@/core/DownloadService.js'; | ||||
| import type { UserFollowingService } from '@/core/UserFollowingService.js'; | ||||
| import { UserMutingService } from '@/core/UserMutingService.js'; | ||||
| import { UtilityService } from '@/core/UtilityService.js'; | ||||
| import { QueueLoggerService } from '../QueueLoggerService.js'; | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { IsNull, MoreThan } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { DriveFilesRepository, UserListJoiningsRepository, UserListsRepository } from '@/models/index.js'; | ||||
| import type { UsersRepository, DriveFilesRepository, UserListJoiningsRepository, UserListsRepository } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import * as Acct from '@/misc/acct.js'; | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ import { Inject, Injectable } from '@nestjs/common'; | |||
| import { MoreThan } from 'typeorm'; | ||||
| import httpSignature from '@peertube/http-signature'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { InstancesRepository, DriveFilesRepository } from '@/models/index.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import { MetaService } from '@/core/MetaService.js'; | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import json from 'koa-json-body'; | |||
| import httpSignature from '@peertube/http-signature'; | ||||
| import { Brackets, In, IsNull, LessThan, Not } from 'typeorm'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository } from '@/models/index.js'; | ||||
| import type { FollowingsRepository, NotesRepository, EmojisRepository, NoteReactionsRepository, UserProfilesRepository, UserNotePiningsRepository, UsersRepository } from '@/models/index.js'; | ||||
| import * as url from '@/misc/prelude/url.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import { ApRendererService } from '@/core/remote/activitypub/ApRendererService.js'; | ||||
|  | @ -73,7 +73,7 @@ export class ActivityPubServerService { | |||
| 	 */ | ||||
| 	private async packActivity(note: Note): Promise<any> { | ||||
| 		if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { | ||||
| 			const renote = await Notes.findOneByOrFail({ id: note.renoteId }); | ||||
| 			const renote = await this.notesRepository.findOneByOrFail({ id: note.renoteId }); | ||||
| 			return this.apRendererService.renderAnnounce(renote.uri ? renote.uri : `${this.config.url}/notes/${renote.id}`, note); | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import type { NotesRepository, UsersRepository } from '@/models/index.js'; | |||
| import { IdentifiableError } from '@/misc/identifiable-error.js'; | ||||
| import type { User } from '@/models/entities/User.js'; | ||||
| import type { Note } from '@/models/entities/Note.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class GetterService { | ||||
|  | @ -13,6 +14,8 @@ export class GetterService { | |||
| 
 | ||||
| 		@Inject(DI.notesRepository) | ||||
| 		private notesRepository: NotesRepository, | ||||
| 
 | ||||
| 		private userEntityService: UserEntityService, | ||||
| 	) { | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; | |||
| import type { UsersRepository } from '@/models/index.js'; | ||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	tags: ['admin'], | ||||
|  | @ -45,6 +46,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | |||
| 	constructor( | ||||
| 		@Inject(DI.usersRepository) | ||||
| 		private usersRepository: UsersRepository, | ||||
| 
 | ||||
| 		private userEntityService: UserEntityService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const query = this.usersRepository.createQueryBuilder('user'); | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; | |||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { QueryService } from '@/core/QueryService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models'; | ||||
| import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models/index.js'; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	tags: ['meta'], | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common'; | |||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { QueryService } from '@/core/QueryService.js'; | ||||
| import { PageEntityService } from '@/core/entities/PageEntityService.js'; | ||||
| import type { PagesRepository } from '@/models'; | ||||
| import type { PagesRepository } from '@/models/index.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| 
 | ||||
| export const meta = { | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ import { awaitAll } from '@/misc/prelude/await-all.js'; | |||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import type { UsersRepository, NotesRepository, FollowingsRepository, DriveFilesRepository, NoteReactionsRepository, PageLikesRepository, NoteFavoritesRepository, PollVotesRepository } from '@/models/index.js'; | ||||
| import { ApiError } from '../../error.js'; | ||||
| 
 | ||||
| export const meta = { | ||||
|  | @ -217,10 +218,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { | |||
| 				driveUsage: this.driveFileEntityService.calcDriveUsageOf(user), | ||||
| 			}); | ||||
| 
 | ||||
| 			result.followingCount = result.localFollowingCount + result.remoteFollowingCount; | ||||
| 			result.followersCount = result.localFollowersCount + result.remoteFollowersCount; | ||||
| 
 | ||||
| 			return result; | ||||
| 			return { | ||||
| 				...result, | ||||
| 				followingCount: result.localFollowingCount + result.remoteFollowingCount, | ||||
| 				followersCount: result.localFollowersCount + result.remoteFollowersCount, | ||||
| 			}; | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -18,13 +18,14 @@ import { getNoteSummary } from '@/misc/get-note-summary.js'; | |||
| import { DI } from '@/di-symbols.js'; | ||||
| import * as Acct from '@/misc/acct.js'; | ||||
| import { MetaService } from '@/core/MetaService.js'; | ||||
| import { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/queue/QueueModule.js'; | ||||
| import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/queue/QueueModule.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; | ||||
| import { PageEntityService } from '@/core/entities/PageEntityService.js'; | ||||
| import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; | ||||
| import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; | ||||
| import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; | ||||
| import type { ChannelsRepository, ClipsRepository, GalleryPostsRepository, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js'; | ||||
| import manifest from './manifest.json' assert { type: 'json' }; | ||||
| import { FeedService } from './FeedService.js'; | ||||
| import { UrlPreviewService } from './UrlPreviewService.js'; | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ | |||
| 	<transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in"> | ||||
| 		<component :is="self ? 'MkA' : 'a'" v-if="!fetching" class="link" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url"> | ||||
| 			<div v-if="thumbnail" class="thumbnail" :style="`background-image: url('${thumbnail}')`"> | ||||
| 				<button v-if="!playerEnabled && player.url" class="_button" :title="i18n.ts.enablePlayer" @click.prevent="playerEnabled = true"><i class="fas fa-play-circle"></i></button> | ||||
| 				<button v-if="!playerEnabled && player.url" class="_button" :title="i18n.ts.enablePlayer" @click.prevent="isMobile? playerEnabled = true : openPlayer()"><i class="fas fa-play-circle"></i></button> | ||||
| 			</div> | ||||
| 			<article> | ||||
| 				<header> | ||||
|  | @ -33,9 +33,11 @@ | |||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { onMounted, onUnmounted } from 'vue'; | ||||
| import { defineAsyncComponent, onMounted, onUnmounted } from 'vue'; | ||||
| import { url as local, lang } from '@/config'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import * as os from '@/os'; | ||||
| import { deviceKind } from '@/scripts/device-kind'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	url: string; | ||||
|  | @ -46,6 +48,9 @@ const props = withDefaults(defineProps<{ | |||
| 	compact: false, | ||||
| }); | ||||
| 
 | ||||
| const MOBILE_THRESHOLD = 500; | ||||
| const isMobile = $ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD); | ||||
| 
 | ||||
| const self = props.url.startsWith(local); | ||||
| const attr = self ? 'to' : 'href'; | ||||
| const target = self ? null : '_blank'; | ||||
|  | @ -103,6 +108,12 @@ function adjustTweetHeight(message: any) { | |||
| 	if (height) tweetHeight = height; | ||||
| } | ||||
| 
 | ||||
| const openPlayer = (): void => { | ||||
| 	os.popup(defineAsyncComponent(() => import('@/components/MkYoutubePlayer.vue')), { | ||||
| 		url: requestUrl.href, | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| (window as any).addEventListener('message', adjustTweetHeight); | ||||
| 
 | ||||
| onUnmounted(() => { | ||||
|  |  | |||
							
								
								
									
										72
									
								
								packages/client/src/components/MkYoutubePlayer.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								packages/client/src/components/MkYoutubePlayer.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| <template> | ||||
| <XWindow :initial-width="640" :initial-height="402" :can-resize="true" :close-button="true"> | ||||
| 	<template #header> | ||||
| 		<i class="icon fa-brands fa-youtube" style="margin-right: 0.5em;"></i> | ||||
| 		<span>{{ title ?? 'Youtube Player' }}</span> | ||||
| 	</template> | ||||
| 
 | ||||
| 	<div class="poamfof"> | ||||
| 		<transition :name="$store.state.animation ? 'fade' : ''" mode="out-in"> | ||||
| 			<div v-if="player.url" class="player"> | ||||
| 				<iframe v-if="!fetching" :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen/> | ||||
| 			</div> | ||||
| 		</transition> | ||||
| 		<MkLoading v-if="fetching"/> | ||||
| 		<MkError v-else-if="!player.url" @retry="ytFetch()"/> | ||||
| 	</div> | ||||
| </XWindow> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import XWindow from '@/components/MkWindow.vue'; | ||||
| import { lang } from '@/config'; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
| 	url: string; | ||||
| }>(); | ||||
| 
 | ||||
| const requestUrl = new URL(props.url); | ||||
| 
 | ||||
| let fetching = $ref(true); | ||||
| let title = $ref<string | null>(null); | ||||
| let player = $ref({ | ||||
| 	url: null, | ||||
| 	width: null, | ||||
| 	height: null, | ||||
| }); | ||||
| 
 | ||||
| const requestLang = (lang ?? 'ja-JP').replace('ja-KS', 'ja-JP'); | ||||
| 
 | ||||
| const ytFetch = (): void => { | ||||
| 	fetching = true; | ||||
| 	fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${requestLang}`).then(res => { | ||||
| 		res.json().then(info => { | ||||
| 			if (info.url == null) return; | ||||
| 			title = info.title; | ||||
| 			fetching = false; | ||||
| 			player = info.player; | ||||
| 		}); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| ytFetch(); | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss"> | ||||
| .poamfof { | ||||
| 	position: relative; | ||||
| 	overflow: hidden; | ||||
| 	height: 100%; | ||||
| 
 | ||||
| 	.player { | ||||
| 		position: absolute; | ||||
| 		inset: 0; | ||||
| 
 | ||||
| 		iframe { | ||||
| 			width: 100%; | ||||
| 			height: 100%; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue