ハッシュタグタイムラインを実装
This commit is contained in:
		
							parent
							
								
									433dbe179d
								
							
						
					
					
						commit
						109738ccb9
					
				
					 19 changed files with 555 additions and 92 deletions
				
			
		| 
						 | 
				
			
			@ -13,12 +13,18 @@ export const meta = {
 | 
			
		|||
	},
 | 
			
		||||
 | 
			
		||||
	params: {
 | 
			
		||||
		tag: $.str.note({
 | 
			
		||||
		tag: $.str.optional.note({
 | 
			
		||||
			desc: {
 | 
			
		||||
				'ja-JP': 'タグ'
 | 
			
		||||
			}
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		query: $.arr($.arr($.str)).optional.note({
 | 
			
		||||
			desc: {
 | 
			
		||||
				'ja-JP': 'クエリ'
 | 
			
		||||
			}
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		includeUserIds: $.arr($.type(ID)).optional.note({
 | 
			
		||||
			default: []
 | 
			
		||||
		}),
 | 
			
		||||
| 
						 | 
				
			
			@ -59,11 +65,9 @@ export const meta = {
 | 
			
		|||
			}
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		withFiles: $.bool.optional.nullable.note({
 | 
			
		||||
			default: null,
 | 
			
		||||
 | 
			
		||||
		withFiles: $.bool.optional.note({
 | 
			
		||||
			desc: {
 | 
			
		||||
				'ja-JP': 'ファイルが添付された投稿に限定するか否か'
 | 
			
		||||
				'ja-JP': 'true にすると、ファイルが添付された投稿だけ取得します'
 | 
			
		||||
			}
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -126,8 +130,14 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	const q: any = {
 | 
			
		||||
		$and: [{
 | 
			
		||||
		$and: [ps.tag ? {
 | 
			
		||||
			tagsLower: ps.tag.toLowerCase()
 | 
			
		||||
		} : {
 | 
			
		||||
			$or: ps.query.map(tags => ({
 | 
			
		||||
				$and: tags.map(t => ({
 | 
			
		||||
					tagsLower: t.toLowerCase()
 | 
			
		||||
				}))
 | 
			
		||||
			}))
 | 
			
		||||
		}],
 | 
			
		||||
		deletedAt: { $exists: false }
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -281,25 +291,10 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
 | 
			
		|||
 | 
			
		||||
	const withFiles = ps.withFiles != null ? ps.withFiles : ps.media;
 | 
			
		||||
 | 
			
		||||
	if (withFiles != null) {
 | 
			
		||||
		if (withFiles) {
 | 
			
		||||
			push({
 | 
			
		||||
				fileIds: {
 | 
			
		||||
					$exists: true,
 | 
			
		||||
					$ne: null
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		} else {
 | 
			
		||||
			push({
 | 
			
		||||
				$or: [{
 | 
			
		||||
					fileIds: {
 | 
			
		||||
						$exists: false
 | 
			
		||||
					}
 | 
			
		||||
				}, {
 | 
			
		||||
					fileIds: null
 | 
			
		||||
				}]
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	if (withFiles) {
 | 
			
		||||
		push({
 | 
			
		||||
			fileIds: { $exists: true, $ne: [] }
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ps.poll != null) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								src/server/api/stream/hashtag.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/server/api/stream/hashtag.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
import * as websocket from 'websocket';
 | 
			
		||||
import Xev from 'xev';
 | 
			
		||||
 | 
			
		||||
import { IUser } from '../../../models/user';
 | 
			
		||||
import Mute from '../../../models/mute';
 | 
			
		||||
import { pack } from '../../../models/note';
 | 
			
		||||
 | 
			
		||||
export default async function(
 | 
			
		||||
	request: websocket.request,
 | 
			
		||||
	connection: websocket.connection,
 | 
			
		||||
	subscriber: Xev,
 | 
			
		||||
	user?: IUser
 | 
			
		||||
) {
 | 
			
		||||
	const mute = user ? await Mute.find({ muterId: user._id }) : null;
 | 
			
		||||
	const mutedUserIds = mute ? mute.map(m => m.muteeId.toString()) : [];
 | 
			
		||||
 | 
			
		||||
	const q: Array<string[]> = JSON.parse((request.resourceURL.query as any).q);
 | 
			
		||||
 | 
			
		||||
	// Subscribe stream
 | 
			
		||||
	subscriber.on('hashtag', async note => {
 | 
			
		||||
		const matched = q.some(tags => tags.every(tag => note.tags.map((t: string) => t.toLowerCase()).includes(tag.toLowerCase())));
 | 
			
		||||
		if (!matched) return;
 | 
			
		||||
 | 
			
		||||
		// Renoteなら再pack
 | 
			
		||||
		if (note.renoteId != null) {
 | 
			
		||||
			note.renote = await pack(note.renoteId, user, {
 | 
			
		||||
				detail: true
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//#region 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
 | 
			
		||||
		if (mutedUserIds.indexOf(note.userId) != -1) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (note.reply != null && mutedUserIds.indexOf(note.reply.userId) != -1) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (note.renote != null && mutedUserIds.indexOf(note.renote.userId) != -1) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		//#endregion
 | 
			
		||||
 | 
			
		||||
		connection.send(JSON.stringify({
 | 
			
		||||
			type: 'note',
 | 
			
		||||
			body: note
 | 
			
		||||
		}));
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ import reversiGameStream from './stream/games/reversi-game';
 | 
			
		|||
import reversiStream from './stream/games/reversi';
 | 
			
		||||
import serverStatsStream from './stream/server-stats';
 | 
			
		||||
import notesStatsStream from './stream/notes-stats';
 | 
			
		||||
import hashtagStream from './stream/hashtag';
 | 
			
		||||
import { ParsedUrlQuery } from 'querystring';
 | 
			
		||||
import authenticate from './authenticate';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +58,11 @@ module.exports = (server: http.Server) => {
 | 
			
		|||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (request.resourceURL.pathname === '/hashtag') {
 | 
			
		||||
			hashtagStream(request, connection, ev, user);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (user == null) {
 | 
			
		||||
			connection.send('authentication-failed');
 | 
			
		||||
			connection.close();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue