Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
2fcc3bb1ea | |||
2e680c3d1e | |||
af0a0ef41b | |||
bbfccb0bbf | |||
c89eb5d69f | |||
ebde84214e | |||
03fbae7b6d | |||
f90e9596d4 | |||
944f9524e2 | |||
c61050244e | |||
90337adbbc | |||
7b67e41c5b |
@ -70,7 +70,7 @@ common:
|
||||
donation: "Dotacje"
|
||||
nav: "Nawigacja"
|
||||
tips: "Wskazówki"
|
||||
hashtags: "ハッシュタグ"
|
||||
hashtags: "Hashtagi"
|
||||
deck:
|
||||
widgets: "Widżety"
|
||||
home: "Strona główna"
|
||||
@ -226,8 +226,8 @@ common/views/widgets/posts-monitor.vue:
|
||||
title: "Wykres wpisów"
|
||||
toggle: "Przełącz widok"
|
||||
common/views/widgets/hashtags.vue:
|
||||
title: "ハッシュタグ"
|
||||
count: "{}人が投稿"
|
||||
title: "Hashtagi"
|
||||
count: "Wspomniany przez {} użytkowników"
|
||||
common/views/widgets/server.vue:
|
||||
title: "Informacje o serwerze"
|
||||
toggle: "Przełącz widok"
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "2.37.3",
|
||||
"clientVersion": "1.0.6453",
|
||||
"version": "2.37.4",
|
||||
"clientVersion": "1.0.6465",
|
||||
"codename": "nighthike",
|
||||
"main": "./built/index.js",
|
||||
"private": true,
|
||||
|
@ -49,7 +49,8 @@ export default Vue.extend({
|
||||
polylinePoints: '',
|
||||
polygonPoints: '',
|
||||
headX: null,
|
||||
headY: null
|
||||
headY: null,
|
||||
clock: null
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -59,6 +60,12 @@ export default Vue.extend({
|
||||
},
|
||||
created() {
|
||||
this.draw();
|
||||
|
||||
// Vueが何故かWatchを発動させない場合があるので
|
||||
this.clock = setInterval(this.draw, 1000);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.clock);
|
||||
},
|
||||
methods: {
|
||||
draw() {
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
<div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'">
|
||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||
<div v-else>
|
||||
<transition-group v-else tag="div" name="chart">
|
||||
<div v-for="stat in stats" :key="stat.tag">
|
||||
<div class="tag">
|
||||
<router-link :to="`/tags/${ stat.tag }`" :title="stat.tag">#{{ stat.tag }}</router-link>
|
||||
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
<x-chart class="chart" :src="stat.chart"/>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</mk-widget-container>
|
||||
</div>
|
||||
@ -74,6 +74,14 @@ root(isDark)
|
||||
margin-right 4px
|
||||
|
||||
> div
|
||||
.chart-enter
|
||||
.chart-leave-to
|
||||
opacity 0
|
||||
transform translateY(-30px)
|
||||
|
||||
> *
|
||||
transition transform .3s ease, opacity .3s ease
|
||||
|
||||
> div
|
||||
display flex
|
||||
align-items center
|
||||
|
@ -1,13 +1,24 @@
|
||||
import Note from '../../../../models/note';
|
||||
|
||||
/*
|
||||
トレンドに載るためには「『直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上』のハッシュタグの上位5位以内に入る」ことが必要
|
||||
ユニーク投稿数とはそのハッシュタグと投稿ユーザーのペアのカウントで、例えば同じユーザーが複数回同じハッシュタグを投稿してもそのハッシュタグのユニーク投稿数は1とカウントされる
|
||||
*/
|
||||
|
||||
const rangeA = 1000 * 60 * 30; // 30分
|
||||
const rangeB = 1000 * 60 * 120; // 2時間
|
||||
const coefficient = 1.5; // 「n倍」の部分
|
||||
const requiredUsers = 3; // 最低何人がそのタグを投稿している必要があるか
|
||||
|
||||
/**
|
||||
* Get trends of hashtags
|
||||
*/
|
||||
module.exports = () => new Promise(async (res, rej) => {
|
||||
//#region 1. 直近Aの内に投稿されたハッシュタグ(とユーザーのペア)を集計
|
||||
const data = await Note.aggregate([{
|
||||
$match: {
|
||||
createdAt: {
|
||||
$gt: new Date(Date.now() - 1000 * 60 * 60)
|
||||
$gt: new Date(Date.now() - rangeA)
|
||||
},
|
||||
tags: {
|
||||
$exists: true,
|
||||
@ -26,13 +37,15 @@ module.exports = () => new Promise(async (res, rej) => {
|
||||
userId: any;
|
||||
}
|
||||
}>;
|
||||
//#endregion
|
||||
|
||||
if (data.length == 0) {
|
||||
return res([]);
|
||||
}
|
||||
|
||||
const tags = [];
|
||||
let tags = [];
|
||||
|
||||
// カウント
|
||||
data.map(x => x._id).forEach(x => {
|
||||
const i = tags.findIndex(tag => tag.name == x.tags);
|
||||
if (i != -1) {
|
||||
@ -45,11 +58,34 @@ module.exports = () => new Promise(async (res, rej) => {
|
||||
}
|
||||
});
|
||||
|
||||
const hots = tags
|
||||
// 最低要求投稿者数を下回るならカットする
|
||||
tags = tags.filter(tag => tag.count >= requiredUsers);
|
||||
|
||||
//#region 2. 1で取得したそれぞれのタグについて、「直近a分間のユニーク投稿数が今からa分前~今からb分前の間のユニーク投稿数のn倍以上」かどうかを判定する
|
||||
const hotsPromises = tags.map(async tag => {
|
||||
const passedCount = (await Note.distinct('userId', {
|
||||
tags: tag.name,
|
||||
createdAt: {
|
||||
$lt: new Date(Date.now() - rangeA),
|
||||
$gt: new Date(Date.now() - rangeB)
|
||||
}
|
||||
}) as any).length;
|
||||
|
||||
if (tag.count > (passedCount * coefficient)) {
|
||||
return tag;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
//#endregion
|
||||
|
||||
const hots = (await Promise.all(hotsPromises))
|
||||
.filter(x => x != null)
|
||||
.sort((a, b) => b.count - a.count)
|
||||
.map(tag => tag.name)
|
||||
.slice(0, 5);
|
||||
|
||||
//#region 2で話題と判定されたタグそれぞれについて過去の投稿数グラフを取得する
|
||||
const countPromises: Array<Promise<any[]>> = [];
|
||||
|
||||
const range = 20;
|
||||
@ -75,6 +111,7 @@ module.exports = () => new Promise(async (res, rej) => {
|
||||
$gt: new Date(Date.now() - (interval * range))
|
||||
}
|
||||
})));
|
||||
//#endregion
|
||||
|
||||
const stats = hots.map((tag, i) => ({
|
||||
tag,
|
||||
|
Reference in New Issue
Block a user