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
|
||||
=========
|
||||
|
||||
12.18.0 (2020/02/20)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
* 効果音設定を強化
|
||||
* UIの調整
|
||||
|
||||
### 🐛Fixes
|
||||
* ユーザープレビューが稀に画面上から消えなくなってしまう問題を修正
|
||||
* ハッシュタグ検索が遅い問題を修正
|
||||
|
||||
12.17.0 (2020/02/20)
|
||||
-------------------
|
||||
### ✨Improvements
|
||||
|
@ -437,6 +437,7 @@ _sfx:
|
||||
notification: "通知"
|
||||
chat: "チャット"
|
||||
chatBg: "チャット(バックグラウンド)"
|
||||
antenna: "アンテナ受信"
|
||||
|
||||
_ago:
|
||||
unknown: "謎"
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||
"version": "12.17.0",
|
||||
"version": "12.18.0",
|
||||
"codename": "indigo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -565,9 +565,7 @@ export default Vue.extend({
|
||||
});
|
||||
}
|
||||
|
||||
const audio = new Audio(`/assets/sounds/${this.$store.state.device.sfxNotification}.mp3`);
|
||||
audio.volume = this.$store.state.device.sfxVolume;
|
||||
audio.play();
|
||||
this.$root.sound('notification');
|
||||
},
|
||||
|
||||
onMousedown(e) {
|
||||
@ -628,18 +626,6 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<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-leave-active {
|
||||
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);
|
||||
|
||||
if (this.sound) {
|
||||
const audio = new Audio(note.userId === this.$store.state.i.id
|
||||
? `/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();
|
||||
this.$root.sound(note.userId === this.$store.state.i.id ? 'noteMy' : 'note');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -53,6 +53,7 @@ export default Vue.extend({
|
||||
return {
|
||||
u: null,
|
||||
show: false,
|
||||
closed: false,
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
@ -68,6 +69,7 @@ export default Vue.extend({
|
||||
{ userId: this.user };
|
||||
|
||||
this.$root.api('users/show', query).then(user => {
|
||||
if (this.closed) return;
|
||||
this.u = user;
|
||||
this.show = true;
|
||||
});
|
||||
@ -83,6 +85,7 @@ export default Vue.extend({
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.closed = true;
|
||||
this.show = false;
|
||||
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.checkTimer = setInterval(() => {
|
||||
if (!document.body.contains(el)) self.close();
|
||||
}, 1000);
|
||||
|
||||
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', () => {
|
||||
@ -66,9 +70,6 @@ export default {
|
||||
|
||||
unbind(el, binding, vn) {
|
||||
const self = el._userPreviewDirective_;
|
||||
clearTimeout(self.showTimer);
|
||||
clearTimeout(self.hideTimer);
|
||||
clearInterval(self.checkTimer);
|
||||
self.close();
|
||||
}
|
||||
};
|
||||
|
@ -189,6 +189,13 @@ os.init(async () => {
|
||||
if (cb) vm.$once('closed', cb);
|
||||
(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,
|
||||
render: createEl => createEl(App)
|
||||
@ -198,4 +205,96 @@ os.init(async () => {
|
||||
|
||||
// マウント
|
||||
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 initStore from './store';
|
||||
import { apiUrl, version, locale } from './config';
|
||||
import { apiUrl, version } from './config';
|
||||
import Progress from './scripts/loading';
|
||||
|
||||
import Stream from './scripts/stream';
|
||||
@ -142,98 +142,6 @@ export default class MiOS extends EventEmitter {
|
||||
@autobind
|
||||
private initStream() {
|
||||
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 {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
padding: 8px 12px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 32px;
|
||||
}
|
||||
}
|
||||
|
@ -184,10 +184,7 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
onMessage(message) {
|
||||
// サウンドを再生する
|
||||
const audio = new Audio(`/assets/sounds/${this.$store.state.device.sfxChat}.mp3`);
|
||||
audio.volume = this.$store.state.device.sfxVolume;
|
||||
audio.play();
|
||||
this.$root.sound('chat');
|
||||
|
||||
const isBottom = this.isBottom();
|
||||
|
||||
|
@ -37,6 +37,11 @@
|
||||
<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>
|
||||
</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>
|
||||
</section>
|
||||
|
||||
@ -97,6 +102,10 @@ const sounds = [
|
||||
'syuilo/pope1',
|
||||
'syuilo/pope2',
|
||||
'syuilo/waon',
|
||||
'syuilo/popo',
|
||||
'syuilo/triple',
|
||||
'syuilo/poi1',
|
||||
'syuilo/poi2',
|
||||
'aisha/1',
|
||||
'aisha/2',
|
||||
'aisha/3',
|
||||
@ -196,6 +205,11 @@ export default Vue.extend({
|
||||
get() { return this.$store.state.device.sfxChatBg; },
|
||||
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: {
|
||||
|
@ -47,6 +47,7 @@ const defaultDeviceSettings = {
|
||||
sfxNotification: 'syuilo/pope2',
|
||||
sfxChat: 'syuilo/pope1',
|
||||
sfxChatBg: 'syuilo/waon',
|
||||
sfxAntenna: 'syuilo/triple',
|
||||
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 { Notes } from '../../../../models';
|
||||
import { Note } from '../../../../models/entities/note';
|
||||
import { safeForSql } from '../../../../misc/safe-for-sql';
|
||||
|
||||
/*
|
||||
トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要
|
||||
@ -113,7 +114,7 @@ export default define(meta, async () => {
|
||||
for (let i = 0; i < range; i++) {
|
||||
countPromises.push(Promise.all(hots.map(tag => Notes.createQueryBuilder('note')
|
||||
.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 > :gt', { gt: new Date(now.getTime() - (interval * (i + 1))) })
|
||||
.cache(60000) // 1 min
|
||||
@ -127,7 +128,7 @@ export default define(meta, async () => {
|
||||
|
||||
const totalCounts = await Promise.all(hots.map(tag => Notes.createQueryBuilder('note')
|
||||
.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) })
|
||||
.cache(60000 * 60) // 60 min
|
||||
.getRawOne()
|
||||
|
@ -6,6 +6,7 @@ import { Notes } from '../../../../models';
|
||||
import { generateMuteQuery } from '../../common/generate-mute-query';
|
||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query';
|
||||
import { Brackets } from 'typeorm';
|
||||
import { safeForSql } from '../../../../misc/safe-for-sql';
|
||||
|
||||
export const meta = {
|
||||
desc: {
|
||||
@ -99,14 +100,16 @@ export default define(meta, async (ps, me) => {
|
||||
if (me) generateMuteQuery(query, me);
|
||||
|
||||
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 {
|
||||
let i = 0;
|
||||
query.andWhere(new Brackets(qb => {
|
||||
for (const tags of ps.query!) {
|
||||
qb.orWhere(new Brackets(qb => {
|
||||
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++;
|
||||
}
|
||||
}));
|
||||
|
Reference in New Issue
Block a user