Compare commits
No commits in common. "713b8ed627dd1ace7463b14a14e3578b60c99876" and "678b718c24c5f9c9a3bfd611037c39b0533631ec" have entirely different histories.
713b8ed627
...
678b718c24
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.3.2-beta.15",
|
"version": "2025.3.2-beta.14",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -593,35 +593,4 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
relations: ['user'],
|
relations: ['user'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async ogogogo(noteIds: MiNote['id'][]) {
|
|
||||||
if (noteIds.length === 0) return [];
|
|
||||||
|
|
||||||
const notes = await this.notesRepository.find({
|
|
||||||
where: {
|
|
||||||
id: In(noteIds),
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
reactions: true,
|
|
||||||
reactionAndUserPairCache: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(notes);
|
|
||||||
|
|
||||||
const bufferedReactionsMap = this.meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(noteIds) : null;
|
|
||||||
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
for (const note of notes) {
|
|
||||||
const bufferedReactions = bufferedReactionsMap?.get(note.id);
|
|
||||||
const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferedReactions.pairs.map(x => x.join('/')));
|
|
||||||
|
|
||||||
results.push({
|
|
||||||
id: note.id,
|
|
||||||
reactions: this.reactionService.convertLegacyReactions(this.reactionsBufferingService.mergeReactions(note.reactions, bufferedReactions.deltas ?? {})),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
|
||||||
import { GetterService } from '@/server/api/GetterService.js';
|
|
||||||
import { ApiError } from '../../error.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['notes'],
|
|
||||||
|
|
||||||
requireCredential: false,
|
|
||||||
|
|
||||||
res: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
noteIds: { type: 'array', items: { type: 'string', format: 'misskey:id' }, maxItems: 100, minItems: 1 },
|
|
||||||
},
|
|
||||||
required: ['noteIds'],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
|
||||||
constructor(
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -514,10 +514,7 @@ function react(): void {
|
||||||
misskeyApi('notes/reactions/create', {
|
misskeyApi('notes/reactions/create', {
|
||||||
noteId: appearNote.value.id,
|
noteId: appearNote.value.id,
|
||||||
reaction: reaction,
|
reaction: reaction,
|
||||||
}).then(() => {
|
|
||||||
// 別にthenを待たなくても良いかも(楽観的更新)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (appearNote.value.text && appearNote.value.text.length > 100 && (Date.now() - new Date(appearNote.value.createdAt).getTime() < 1000 * 3)) {
|
if (appearNote.value.text && appearNote.value.text.length > 100 && (Date.now() - new Date(appearNote.value.createdAt).getTime() < 1000 * 3)) {
|
||||||
claimAchievement('reactWithoutRead');
|
claimAchievement('reactWithoutRead');
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,14 +178,6 @@ rt {
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
|
|
||||||
/*
|
|
||||||
理屈は知らないけど、ここでbackgroundを設定しておかないと
|
|
||||||
スクロールコンテナーが少なくともChromeにおいて
|
|
||||||
main thread scrolling になってしまい、パフォーマンスが(多分)落ちる。
|
|
||||||
backgroundが透明だと裏側を描画しないといけなくなるとかそういう理由かもしれない
|
|
||||||
*/
|
|
||||||
background: var(--MI_THEME-bg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
._pageScrollableReversed {
|
._pageScrollableReversed {
|
||||||
|
|
|
@ -226,17 +226,13 @@ html,
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: clip;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
overscroll-behavior: none;
|
overscroll-behavior: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
|
||||||
/* NOTE: htmlにも overflow: clip を設定したいところだが、設定すると何故か少なくともChromeで html が main thread scrolling になりパフォーマンスが(多分)落ちる */
|
|
||||||
overflow: clip;
|
|
||||||
}
|
|
||||||
|
|
||||||
#misskey_app {
|
#misskey_app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -216,17 +216,13 @@ html,
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: clip;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
overscroll-behavior: none;
|
overscroll-behavior: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
|
||||||
/* NOTE: htmlにも overflow: clip を設定したいところだが、設定すると何故か少なくともChromeで html が main thread scrolling になりパフォーマンスが(多分)落ちる */
|
|
||||||
overflow: clip;
|
|
||||||
}
|
|
||||||
|
|
||||||
#misskey_app {
|
#misskey_app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -5,32 +5,12 @@
|
||||||
|
|
||||||
import { onUnmounted } from 'vue';
|
import { onUnmounted } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
|
||||||
import type { Ref, ShallowRef } from 'vue';
|
import type { Ref, ShallowRef } from 'vue';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
|
||||||
const noteEvents = new EventEmitter<{
|
export function useNoteCapture(props: {
|
||||||
reacted: Misskey.entities.Note;
|
|
||||||
unreacted: Misskey.entities.Note;
|
|
||||||
pollVoted: Misskey.entities.Note;
|
|
||||||
deleted: Misskey.entities.Note;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const capturedNoteIdMapForPolling = new Map<string, number>();
|
|
||||||
|
|
||||||
const POLLING_INTERVAL = 1000 * 10;
|
|
||||||
|
|
||||||
window.setInterval(() => {
|
|
||||||
const ids = [...capturedNoteIdMapForPolling.keys()];
|
|
||||||
if (ids.length === 0) return;
|
|
||||||
if (window.document.hidden) return;
|
|
||||||
|
|
||||||
console.log('Polling notes', ids);
|
|
||||||
}, POLLING_INTERVAL);
|
|
||||||
|
|
||||||
function pseudoNoteCapture(props: {
|
|
||||||
rootEl: ShallowRef<HTMLElement | undefined>;
|
rootEl: ShallowRef<HTMLElement | undefined>;
|
||||||
note: Ref<Misskey.entities.Note>;
|
note: Ref<Misskey.entities.Note>;
|
||||||
pureNote: Ref<Misskey.entities.Note>;
|
pureNote: Ref<Misskey.entities.Note>;
|
||||||
|
@ -38,34 +18,7 @@ function pseudoNoteCapture(props: {
|
||||||
}) {
|
}) {
|
||||||
const note = props.note;
|
const note = props.note;
|
||||||
const pureNote = props.pureNote;
|
const pureNote = props.pureNote;
|
||||||
|
const connection = $i && store.s.realtimeMode ? useStream() : null;
|
||||||
function onReacted(): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (capturedNoteIdMapForPolling.has(note.value.id)) {
|
|
||||||
capturedNoteIdMapForPolling.set(note.value.id, capturedNoteIdMapForPolling.get(note.value.id)! + 1);
|
|
||||||
} else {
|
|
||||||
capturedNoteIdMapForPolling.set(note.value.id, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
capturedNoteIdMapForPolling.set(note.value.id, capturedNoteIdMapForPolling.get(note.value.id)! - 1);
|
|
||||||
if (capturedNoteIdMapForPolling.get(note.value.id) === 0) {
|
|
||||||
capturedNoteIdMapForPolling.delete(note.value.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function realtimeNoteCapture(props: {
|
|
||||||
rootEl: ShallowRef<HTMLElement | undefined>;
|
|
||||||
note: Ref<Misskey.entities.Note>;
|
|
||||||
pureNote: Ref<Misskey.entities.Note>;
|
|
||||||
isDeletedRef: Ref<boolean>;
|
|
||||||
}): void {
|
|
||||||
const note = props.note;
|
|
||||||
const pureNote = props.pureNote;
|
|
||||||
const connection = useStream();
|
|
||||||
|
|
||||||
function onStreamNoteUpdated(noteData): void {
|
function onStreamNoteUpdated(noteData): void {
|
||||||
const { type, id, body } = noteData;
|
const { type, id, body } = noteData;
|
||||||
|
@ -132,13 +85,16 @@ function realtimeNoteCapture(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
function capture(withHandler = false): void {
|
function capture(withHandler = false): void {
|
||||||
|
if (connection) {
|
||||||
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
||||||
connection.send(window.document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id });
|
connection.send(window.document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id });
|
||||||
if (pureNote.value.id !== note.value.id) connection.send('s', { id: pureNote.value.id });
|
if (pureNote.value.id !== note.value.id) connection.send('s', { id: pureNote.value.id });
|
||||||
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function decapture(withHandler = false): void {
|
function decapture(withHandler = false): void {
|
||||||
|
if (connection) {
|
||||||
connection.send('un', {
|
connection.send('un', {
|
||||||
id: note.value.id,
|
id: note.value.id,
|
||||||
});
|
});
|
||||||
|
@ -149,29 +105,21 @@ function realtimeNoteCapture(props: {
|
||||||
}
|
}
|
||||||
if (withHandler) connection.off('noteUpdated', onStreamNoteUpdated);
|
if (withHandler) connection.off('noteUpdated', onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onStreamConnected() {
|
function onStreamConnected() {
|
||||||
capture(false);
|
capture(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
capture(true);
|
capture(true);
|
||||||
|
if (connection) {
|
||||||
connection.on('_connected_', onStreamConnected);
|
connection.on('_connected_', onStreamConnected);
|
||||||
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
decapture(true);
|
decapture(true);
|
||||||
|
if (connection) {
|
||||||
connection.off('_connected_', onStreamConnected);
|
connection.off('_connected_', onStreamConnected);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useNoteCapture(props: {
|
|
||||||
rootEl: ShallowRef<HTMLElement | undefined>;
|
|
||||||
note: Ref<Misskey.entities.Note>;
|
|
||||||
pureNote: Ref<Misskey.entities.Note>;
|
|
||||||
isDeletedRef: Ref<boolean>;
|
|
||||||
}) {
|
|
||||||
if ($i && store.s.realtimeMode) {
|
|
||||||
realtimeNoteCapture(props);
|
|
||||||
} else {
|
|
||||||
pseudoNoteCapture(props);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"name": "misskey-js",
|
"name": "misskey-js",
|
||||||
"version": "2025.3.2-beta.15",
|
"version": "2025.3.2-beta.14",
|
||||||
"description": "Misskey SDK for JavaScript",
|
"description": "Misskey SDK for JavaScript",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
|
|
Loading…
Reference in New Issue