enhance(client): RSSティッカーで表示順序をシャッフルできるように

This commit is contained in:
syuilo 2022-07-15 17:12:08 +09:00
parent 165c4b2c00
commit 6f45208ab6
7 changed files with 39 additions and 1 deletions

View File

@ -12,6 +12,7 @@ You should also include the user name that made the change.
## 12.x.x (unreleased) ## 12.x.x (unreleased)
### Improvements ### Improvements
- RSSティッカーで表示順序をシャッフルできるように @syuilo
### Bugfixes ### Bugfixes
- クライアントが起動しなくなることがある問題を修正 @syuilo - クライアントが起動しなくなることがある問題を修正 @syuilo

View File

@ -888,6 +888,7 @@ enableAutoSensitive: "自動NSFW判定"
enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。" enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。"
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。" activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。"
navbar: "ナビゲーションバー" navbar: "ナビゲーションバー"
shuffle: "シャッフル"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。" description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"

View File

@ -28,6 +28,9 @@
<MkInput v-model="statusbar.props.url" manual-save class="_formBlock" type="url"> <MkInput v-model="statusbar.props.url" manual-save class="_formBlock" type="url">
<template #label>URL</template> <template #label>URL</template>
</MkInput> </MkInput>
<MkSwitch v-model="statusbar.props.shuffle" class="_formBlock">
<template #label>{{ i18n.ts.shuffle }}</template>
</MkSwitch>
<MkInput v-model="statusbar.props.refreshIntervalSec" manual-save class="_formBlock" type="number"> <MkInput v-model="statusbar.props.refreshIntervalSec" manual-save class="_formBlock" type="number">
<template #label>{{ i18n.ts.refreshInterval }}</template> <template #label>{{ i18n.ts.refreshInterval }}</template>
</MkInput> </MkInput>
@ -100,6 +103,7 @@ watch(() => statusbar.type, () => {
if (statusbar.type === 'rss') { if (statusbar.type === 'rss') {
statusbar.name = 'NEWS'; statusbar.name = 'NEWS';
statusbar.props.url = 'http://feeds.afpbb.com/rss/afpbb/afpbbnews'; statusbar.props.url = 'http://feeds.afpbb.com/rss/afpbb/afpbbnews';
statusbar.props.shuffle = true;
statusbar.props.refreshIntervalSec = 120; statusbar.props.refreshIntervalSec = 120;
statusbar.props.display = 'marquee'; statusbar.props.display = 'marquee';
statusbar.props.marqueeDuration = 100; statusbar.props.marqueeDuration = 100;

View File

@ -0,0 +1,19 @@
/**
* ()
*/
export function shuffle<T extends any[]>(array: T): T {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex !== 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}

View File

@ -20,9 +20,11 @@ import { computed, defineAsyncComponent, ref, toRef, watch } from 'vue';
import MarqueeText from '@/components/marquee.vue'; import MarqueeText from '@/components/marquee.vue';
import * as os from '@/os'; import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval'; import { useInterval } from '@/scripts/use-interval';
import { shuffle } from '@/scripts/shuffle';
const props = defineProps<{ const props = defineProps<{
url?: string; url?: string;
shuffle?: boolean;
display?: 'marquee' | 'oneByOne'; display?: 'marquee' | 'oneByOne';
marqueeDuration?: number; marqueeDuration?: number;
marqueeReverse?: boolean; marqueeReverse?: boolean;
@ -37,6 +39,9 @@ let key = $ref(0);
const tick = () => { const tick = () => {
fetch(`/api/fetch-rss?url=${props.url}`, {}).then(res => { fetch(`/api/fetch-rss?url=${props.url}`, {}).then(res => {
res.json().then(feed => { res.json().then(feed => {
if (props.shuffle) {
shuffle(feed.items);
}
items.value = feed.items; items.value = feed.items;
fetching.value = false; fetching.value = false;
key++; key++;

View File

@ -10,7 +10,7 @@
}]" }]"
> >
<span class="name">{{ x.name }}</span> <span class="name">{{ x.name }}</span>
<XRss v-if="x.type === 'rss'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :url="x.props.url"/> <XRss v-if="x.type === 'rss'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :url="x.props.url" :shuffle="x.props.shuffle"/>
<XFederation v-else-if="x.type === 'federation'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :colored="x.props.colored"/> <XFederation v-else-if="x.type === 'federation'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :colored="x.props.colored"/>
<XUserList v-else-if="x.type === 'userList'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :user-list-id="x.props.userListId"/> <XUserList v-else-if="x.type === 'userList'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :user-list-id="x.props.userListId"/>
</div> </div>

View File

@ -26,6 +26,7 @@ import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os'; import * as os from '@/os';
import MkContainer from '@/components/ui/container.vue'; import MkContainer from '@/components/ui/container.vue';
import { useInterval } from '@/scripts/use-interval'; import { useInterval } from '@/scripts/use-interval';
import { shuffle } from '@/scripts/shuffle';
const name = 'rssTicker'; const name = 'rssTicker';
@ -34,6 +35,10 @@ const widgetPropsDef = {
type: 'string' as const, type: 'string' as const,
default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews', default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews',
}, },
shuffle: {
type: 'boolean' as const,
default: true,
},
refreshIntervalSec: { refreshIntervalSec: {
type: 'number' as const, type: 'number' as const,
default: 60, default: 60,
@ -80,6 +85,9 @@ let key = $ref(0);
const tick = () => { const tick = () => {
fetch(`/api/fetch-rss?url=${widgetProps.url}`, {}).then(res => { fetch(`/api/fetch-rss?url=${widgetProps.url}`, {}).then(res => {
res.json().then(feed => { res.json().then(feed => {
if (widgetProps.shuffle) {
shuffle(feed.items);
}
items.value = feed.items; items.value = feed.items;
fetching.value = false; fetching.value = false;
key++; key++;