Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
330ea7d210 | |||
1edd173a29 | |||
98d873a7f9 | |||
09175b84df | |||
177e19632a | |||
8e6207f3e9 | |||
ff3a97f6cf | |||
b8e155ab40 | |||
b8e7df198d |
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,6 +1,16 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
12.18.0 (2020/02/20)
|
||||||
|
-------------------
|
||||||
|
### ✨Improvements
|
||||||
|
* 効果音設定を強化
|
||||||
|
* UIの調整
|
||||||
|
|
||||||
|
### 🐛Fixes
|
||||||
|
* ユーザープレビューが稀に画面上から消えなくなってしまう問題を修正
|
||||||
|
* ハッシュタグ検索が遅い問題を修正
|
||||||
|
|
||||||
12.17.0 (2020/02/20)
|
12.17.0 (2020/02/20)
|
||||||
-------------------
|
-------------------
|
||||||
### ✨Improvements
|
### ✨Improvements
|
||||||
|
@ -437,6 +437,7 @@ _sfx:
|
|||||||
notification: "通知"
|
notification: "通知"
|
||||||
chat: "チャット"
|
chat: "チャット"
|
||||||
chatBg: "チャット(バックグラウンド)"
|
chatBg: "チャット(バックグラウンド)"
|
||||||
|
antenna: "アンテナ受信"
|
||||||
|
|
||||||
_ago:
|
_ago:
|
||||||
unknown: "謎"
|
unknown: "謎"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||||
"version": "12.17.0",
|
"version": "12.18.0",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -565,9 +565,7 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const audio = new Audio(`/assets/sounds/${this.$store.state.device.sfxNotification}.mp3`);
|
this.$root.sound('notification');
|
||||||
audio.volume = this.$store.state.device.sfxVolume;
|
|
||||||
audio.play();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onMousedown(e) {
|
onMousedown(e) {
|
||||||
@ -628,18 +626,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.header-enter-active, .header-leave-active {
|
|
||||||
transition: opacity 0.5s, transform 0.5s !important;
|
|
||||||
}
|
|
||||||
.header-enter {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
.header-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-enter-active,
|
.nav-enter-active,
|
||||||
.nav-leave-active {
|
.nav-leave-active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
BIN
src/client/assets/sounds/syuilo/poi1.mp3
Normal file
BIN
src/client/assets/sounds/syuilo/poi1.mp3
Normal file
Binary file not shown.
BIN
src/client/assets/sounds/syuilo/poi2.mp3
Normal file
BIN
src/client/assets/sounds/syuilo/poi2.mp3
Normal file
Binary file not shown.
BIN
src/client/assets/sounds/syuilo/popo.mp3
Normal file
BIN
src/client/assets/sounds/syuilo/popo.mp3
Normal file
Binary file not shown.
BIN
src/client/assets/sounds/syuilo/triple.mp3
Normal file
BIN
src/client/assets/sounds/syuilo/triple.mp3
Normal file
Binary file not shown.
@ -53,11 +53,7 @@ export default Vue.extend({
|
|||||||
(this.$refs.tl as any).prepend(note);
|
(this.$refs.tl as any).prepend(note);
|
||||||
|
|
||||||
if (this.sound) {
|
if (this.sound) {
|
||||||
const audio = new Audio(note.userId === this.$store.state.i.id
|
this.$root.sound(note.userId === this.$store.state.i.id ? 'noteMy' : 'note');
|
||||||
? `/assets/sounds/${this.$store.state.device.sfxNoteMy}.mp3`
|
|
||||||
: `/assets/sounds/${this.$store.state.device.sfxNote}.mp3`);
|
|
||||||
audio.volume = this.$store.state.device.sfxVolume;
|
|
||||||
audio.play();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
u: null,
|
u: null,
|
||||||
show: false,
|
show: false,
|
||||||
|
closed: false,
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
};
|
};
|
||||||
@ -68,6 +69,7 @@ export default Vue.extend({
|
|||||||
{ userId: this.user };
|
{ userId: this.user };
|
||||||
|
|
||||||
this.$root.api('users/show', query).then(user => {
|
this.$root.api('users/show', query).then(user => {
|
||||||
|
if (this.closed) return;
|
||||||
this.u = user;
|
this.u = user;
|
||||||
this.show = true;
|
this.show = true;
|
||||||
});
|
});
|
||||||
@ -83,6 +85,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
|
this.closed = true;
|
||||||
this.show = false;
|
this.show = false;
|
||||||
if (this.$refs.content) (this.$refs.content as any).style.pointerEvents = 'none';
|
if (this.$refs.content) (this.$refs.content as any).style.pointerEvents = 'none';
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,15 @@ export default {
|
|||||||
self.hideTimer = setTimeout(self.close, 500);
|
self.hideTimer = setTimeout(self.close, 500);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.checkTimer = setInterval(() => {
|
|
||||||
if (!document.body.contains(el)) self.close();
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
document.body.appendChild(self.tag.$el);
|
document.body.appendChild(self.tag.$el);
|
||||||
|
|
||||||
|
self.checkTimer = setInterval(() => {
|
||||||
|
if (!document.body.contains(el)) {
|
||||||
|
clearTimeout(self.showTimer);
|
||||||
|
clearTimeout(self.hideTimer);
|
||||||
|
self.close();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
el.addEventListener('mouseover', () => {
|
el.addEventListener('mouseover', () => {
|
||||||
@ -66,9 +70,6 @@ export default {
|
|||||||
|
|
||||||
unbind(el, binding, vn) {
|
unbind(el, binding, vn) {
|
||||||
const self = el._userPreviewDirective_;
|
const self = el._userPreviewDirective_;
|
||||||
clearTimeout(self.showTimer);
|
|
||||||
clearTimeout(self.hideTimer);
|
|
||||||
clearInterval(self.checkTimer);
|
clearInterval(self.checkTimer);
|
||||||
self.close();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -189,6 +189,13 @@ os.init(async () => {
|
|||||||
if (cb) vm.$once('closed', cb);
|
if (cb) vm.$once('closed', cb);
|
||||||
(vm as any).focus();
|
(vm as any).focus();
|
||||||
},
|
},
|
||||||
|
sound(type: string) {
|
||||||
|
const sound = this.$store.state.device['sfx' + type.substr(0, 1).toUpperCase() + type.substr(1)];
|
||||||
|
if (sound == null) return;
|
||||||
|
const audio = new Audio(`/assets/sounds/${sound}.mp3`);
|
||||||
|
audio.volume = this.$store.state.device.sfxVolume;
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
router: router,
|
router: router,
|
||||||
render: createEl => createEl(App)
|
render: createEl => createEl(App)
|
||||||
@ -198,4 +205,96 @@ os.init(async () => {
|
|||||||
|
|
||||||
// マウント
|
// マウント
|
||||||
app.$mount('#app');
|
app.$mount('#app');
|
||||||
|
|
||||||
|
if (app.$store.getters.isSignedIn) {
|
||||||
|
const main = os.stream.useSharedConnection('main');
|
||||||
|
|
||||||
|
// 自分の情報が更新されたとき
|
||||||
|
main.on('meUpdated', i => {
|
||||||
|
app.$store.dispatch('mergeMe', i);
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllNotifications', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadNotification: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadNotification', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadNotification: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadMention', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMentions: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllUnreadMentions', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMentions: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadSpecifiedNote', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadSpecifiedNotes: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllUnreadSpecifiedNotes', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadSpecifiedNotes: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllMessagingMessages', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMessagingMessage: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadMessagingMessage', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadMessagingMessage: true
|
||||||
|
});
|
||||||
|
|
||||||
|
app.sound('chatBg');
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllAntennas', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadAntenna: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('unreadAntenna', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadAntenna: true
|
||||||
|
});
|
||||||
|
|
||||||
|
app.sound('antenna');
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('readAllAnnouncements', () => {
|
||||||
|
app.$store.dispatch('mergeMe', {
|
||||||
|
hasUnreadAnnouncement: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
main.on('clientSettingUpdated', x => {
|
||||||
|
app.$store.commit('settings/set', {
|
||||||
|
key: x.key,
|
||||||
|
value: x.value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// トークンが再生成されたとき
|
||||||
|
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
||||||
|
main.on('myTokenRegenerated', () => {
|
||||||
|
os.signout();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -3,7 +3,7 @@ import Vue from 'vue';
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
|
||||||
import initStore from './store';
|
import initStore from './store';
|
||||||
import { apiUrl, version, locale } from './config';
|
import { apiUrl, version } from './config';
|
||||||
import Progress from './scripts/loading';
|
import Progress from './scripts/loading';
|
||||||
|
|
||||||
import Stream from './scripts/stream';
|
import Stream from './scripts/stream';
|
||||||
@ -142,98 +142,6 @@ export default class MiOS extends EventEmitter {
|
|||||||
@autobind
|
@autobind
|
||||||
private initStream() {
|
private initStream() {
|
||||||
this.stream = new Stream(this);
|
this.stream = new Stream(this);
|
||||||
|
|
||||||
if (this.store.getters.isSignedIn) {
|
|
||||||
const main = this.stream.useSharedConnection('main');
|
|
||||||
|
|
||||||
// 自分の情報が更新されたとき
|
|
||||||
main.on('meUpdated', i => {
|
|
||||||
this.store.dispatch('mergeMe', i);
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('readAllNotifications', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadNotification: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('unreadNotification', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadNotification: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('unreadMention', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMentions: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('readAllUnreadMentions', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMentions: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('unreadSpecifiedNote', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadSpecifiedNotes: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('readAllUnreadSpecifiedNotes', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadSpecifiedNotes: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('readAllMessagingMessages', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMessagingMessage: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('unreadMessagingMessage', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadMessagingMessage: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const audio = new Audio(`/assets/sounds/${this.store.state.device.sfxChatBg}.mp3`);
|
|
||||||
audio.volume = this.store.state.device.sfxVolume;
|
|
||||||
audio.play();
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('readAllAntennas', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadAntenna: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('unreadAntenna', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadAntenna: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('readAllAnnouncements', () => {
|
|
||||||
this.store.dispatch('mergeMe', {
|
|
||||||
hasUnreadAnnouncement: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
main.on('clientSettingUpdated', x => {
|
|
||||||
this.store.commit('settings/set', {
|
|
||||||
key: x.key,
|
|
||||||
value: x.value
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// トークンが再生成されたとき
|
|
||||||
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
|
||||||
main.on('myTokenRegenerated', () => {
|
|
||||||
this.signout();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,7 +196,7 @@ export default Vue.extend({
|
|||||||
> button {
|
> button {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 8px 12px;
|
padding: 8px 16px;
|
||||||
border-radius: 32px;
|
border-radius: 32px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,10 +184,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onMessage(message) {
|
onMessage(message) {
|
||||||
// サウンドを再生する
|
this.$root.sound('chat');
|
||||||
const audio = new Audio(`/assets/sounds/${this.$store.state.device.sfxChat}.mp3`);
|
|
||||||
audio.volume = this.$store.state.device.sfxVolume;
|
|
||||||
audio.play();
|
|
||||||
|
|
||||||
const isBottom = this.isBottom();
|
const isBottom = this.isBottom();
|
||||||
|
|
||||||
|
@ -37,6 +37,11 @@
|
|||||||
<option v-for="sound in sounds" :value="sound" :key="sound">{{ sound || $t('none') }}</option>
|
<option v-for="sound in sounds" :value="sound" :key="sound">{{ sound || $t('none') }}</option>
|
||||||
<template #text><button class="_textButton" @click="listen(sfxChatBg)" v-if="sfxChatBg"><fa :icon="faPlay"/> {{ $t('listen') }}</button></template>
|
<template #text><button class="_textButton" @click="listen(sfxChatBg)" v-if="sfxChatBg"><fa :icon="faPlay"/> {{ $t('listen') }}</button></template>
|
||||||
</mk-select>
|
</mk-select>
|
||||||
|
<mk-select v-model="sfxAntenna">
|
||||||
|
<template #label>{{ $t('_sfx.antenna') }}</template>
|
||||||
|
<option v-for="sound in sounds" :value="sound" :key="sound">{{ sound || $t('none') }}</option>
|
||||||
|
<template #text><button class="_textButton" @click="listen(sfxAntenna)" v-if="sfxAntenna"><fa :icon="faPlay"/> {{ $t('listen') }}</button></template>
|
||||||
|
</mk-select>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -97,6 +102,10 @@ const sounds = [
|
|||||||
'syuilo/pope1',
|
'syuilo/pope1',
|
||||||
'syuilo/pope2',
|
'syuilo/pope2',
|
||||||
'syuilo/waon',
|
'syuilo/waon',
|
||||||
|
'syuilo/popo',
|
||||||
|
'syuilo/triple',
|
||||||
|
'syuilo/poi1',
|
||||||
|
'syuilo/poi2',
|
||||||
'aisha/1',
|
'aisha/1',
|
||||||
'aisha/2',
|
'aisha/2',
|
||||||
'aisha/3',
|
'aisha/3',
|
||||||
@ -196,6 +205,11 @@ export default Vue.extend({
|
|||||||
get() { return this.$store.state.device.sfxChatBg; },
|
get() { return this.$store.state.device.sfxChatBg; },
|
||||||
set(value) { this.$store.commit('device/set', { key: 'sfxChatBg', value }); }
|
set(value) { this.$store.commit('device/set', { key: 'sfxChatBg', value }); }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sfxAntenna: {
|
||||||
|
get() { return this.$store.state.device.sfxAntenna; },
|
||||||
|
set(value) { this.$store.commit('device/set', { key: 'sfxAntenna', value }); }
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -47,6 +47,7 @@ const defaultDeviceSettings = {
|
|||||||
sfxNotification: 'syuilo/pope2',
|
sfxNotification: 'syuilo/pope2',
|
||||||
sfxChat: 'syuilo/pope1',
|
sfxChat: 'syuilo/pope1',
|
||||||
sfxChatBg: 'syuilo/waon',
|
sfxChatBg: 'syuilo/waon',
|
||||||
|
sfxAntenna: 'syuilo/triple',
|
||||||
userData: {},
|
userData: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
3
src/misc/safe-for-sql.ts
Normal file
3
src/misc/safe-for-sql.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function safeForSql(text: string): boolean {
|
||||||
|
return /[\0\x08\x09\x1a\n\r"'\\\%]/g.test(text);
|
||||||
|
}
|
@ -3,6 +3,7 @@ import define from '../../define';
|
|||||||
import { fetchMeta } from '../../../../misc/fetch-meta';
|
import { fetchMeta } from '../../../../misc/fetch-meta';
|
||||||
import { Notes } from '../../../../models';
|
import { Notes } from '../../../../models';
|
||||||
import { Note } from '../../../../models/entities/note';
|
import { Note } from '../../../../models/entities/note';
|
||||||
|
import { safeForSql } from '../../../../misc/safe-for-sql';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要
|
トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要
|
||||||
@ -113,7 +114,7 @@ export default define(meta, async () => {
|
|||||||
for (let i = 0; i < range; i++) {
|
for (let i = 0; i < range; i++) {
|
||||||
countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note')
|
countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note')
|
||||||
.select('count(distinct note.userId)')
|
.select('count(distinct note.userId)')
|
||||||
.where(':tag = ANY(note.tags)', { tag: tag })
|
.where(`'{"${safeForSql(tag) ? tag : 'aichan_kawaii'}"}' <@ note.tags`)
|
||||||
.andWhere('note.createdAt < :lt', { lt: new Date(now.getTime() - (interval * i)) })
|
.andWhere('note.createdAt < :lt', { lt: new Date(now.getTime() - (interval * i)) })
|
||||||
.andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - (interval * (i + 1))) })
|
.andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - (interval * (i + 1))) })
|
||||||
.cache(60000) // 1 min
|
.cache(60000) // 1 min
|
||||||
@ -127,7 +128,7 @@ export default define(meta, async () => {
|
|||||||
|
|
||||||
const totalCounts = await Promise.all(hots.map(tag => Notes.createQueryBuilder('note')
|
const totalCounts = await Promise.all(hots.map(tag => Notes.createQueryBuilder('note')
|
||||||
.select('count(distinct note.userId)')
|
.select('count(distinct note.userId)')
|
||||||
.where(':tag = ANY(note.tags)', { tag: tag })
|
.where(`'{"${safeForSql(tag) ? tag : 'aichan_kawaii'}"}' <@ note.tags`)
|
||||||
.andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - rangeA) })
|
.andWhere('note.createdAt > :gt', { gt: new Date(now.getTime() - rangeA) })
|
||||||
.cache(60000 * 60) // 60 min
|
.cache(60000 * 60) // 60 min
|
||||||
.getRawOne()
|
.getRawOne()
|
||||||
|
@ -6,6 +6,7 @@ import { Notes } from '../../../../models';
|
|||||||
import { generateMuteQuery } from '../../common/generate-mute-query';
|
import { generateMuteQuery } from '../../common/generate-mute-query';
|
||||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets } from 'typeorm';
|
||||||
|
import { safeForSql } from '../../../../misc/safe-for-sql';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
@ -99,14 +100,16 @@ export default define(meta, async (ps, me) => {
|
|||||||
if (me) generateMuteQuery(query, me);
|
if (me) generateMuteQuery(query, me);
|
||||||
|
|
||||||
if (ps.tag) {
|
if (ps.tag) {
|
||||||
query.andWhere(':tag = ANY(note.tags)', { tag: ps.tag.toLowerCase() });
|
if (!safeForSql(ps.tag)) return;
|
||||||
|
query.andWhere(`'{"${ps.tag.toLowerCase()}"}' <@ note.tags`);
|
||||||
} else {
|
} else {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
query.andWhere(new Brackets(qb => {
|
query.andWhere(new Brackets(qb => {
|
||||||
for (const tags of ps.query!) {
|
for (const tags of ps.query!) {
|
||||||
qb.orWhere(new Brackets(qb => {
|
qb.orWhere(new Brackets(qb => {
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
qb.andWhere(`:tag${i} = ANY(note.tags)`, { [`tag${i}`]: tag.toLowerCase() });
|
if (!safeForSql(tag)) return;
|
||||||
|
qb.andWhere(`'{"${tag.toLowerCase()}"}' <@ note.tags`);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
Reference in New Issue
Block a user