diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e1666b08..efb0d684a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ You should also include the user name that made the change.
## 12.x.x (unreleased)
### Improvements
+- RSSティッカーで表示順序をシャッフルできるように @syuilo
### Bugfixes
- クライアントが起動しなくなることがある問題を修正 @syuilo
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index fd8aca868..bdff7e38d 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -888,6 +888,7 @@ enableAutoSensitive: "自動NSFW判定"
enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。"
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。"
navbar: "ナビゲーションバー"
+shuffle: "シャッフル"
_sensitiveMediaDetection:
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"
diff --git a/packages/client/src/pages/settings/statusbars.statusbar.vue b/packages/client/src/pages/settings/statusbars.statusbar.vue
index e19690209..2f0c6fc1e 100644
--- a/packages/client/src/pages/settings/statusbars.statusbar.vue
+++ b/packages/client/src/pages/settings/statusbars.statusbar.vue
@@ -28,6 +28,9 @@
URL
+
+ {{ i18n.ts.shuffle }}
+
{{ i18n.ts.refreshInterval }}
@@ -100,6 +103,7 @@ watch(() => statusbar.type, () => {
if (statusbar.type === 'rss') {
statusbar.name = 'NEWS';
statusbar.props.url = 'http://feeds.afpbb.com/rss/afpbb/afpbbnews';
+ statusbar.props.shuffle = true;
statusbar.props.refreshIntervalSec = 120;
statusbar.props.display = 'marquee';
statusbar.props.marqueeDuration = 100;
diff --git a/packages/client/src/scripts/shuffle.ts b/packages/client/src/scripts/shuffle.ts
new file mode 100644
index 000000000..05e6cdfbc
--- /dev/null
+++ b/packages/client/src/scripts/shuffle.ts
@@ -0,0 +1,19 @@
+/**
+ * 配列をシャッフル (破壊的)
+ */
+export function shuffle(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;
+}
diff --git a/packages/client/src/ui/_common_/statusbar-rss.vue b/packages/client/src/ui/_common_/statusbar-rss.vue
index 88604a38a..635b875ca 100644
--- a/packages/client/src/ui/_common_/statusbar-rss.vue
+++ b/packages/client/src/ui/_common_/statusbar-rss.vue
@@ -20,9 +20,11 @@ import { computed, defineAsyncComponent, ref, toRef, watch } from 'vue';
import MarqueeText from '@/components/marquee.vue';
import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
+import { shuffle } from '@/scripts/shuffle';
const props = defineProps<{
url?: string;
+ shuffle?: boolean;
display?: 'marquee' | 'oneByOne';
marqueeDuration?: number;
marqueeReverse?: boolean;
@@ -37,6 +39,9 @@ let key = $ref(0);
const tick = () => {
fetch(`/api/fetch-rss?url=${props.url}`, {}).then(res => {
res.json().then(feed => {
+ if (props.shuffle) {
+ shuffle(feed.items);
+ }
items.value = feed.items;
fetching.value = false;
key++;
diff --git a/packages/client/src/ui/_common_/statusbars.vue b/packages/client/src/ui/_common_/statusbars.vue
index 5358b26ec..114ca5be8 100644
--- a/packages/client/src/ui/_common_/statusbars.vue
+++ b/packages/client/src/ui/_common_/statusbars.vue
@@ -10,7 +10,7 @@
}]"
>
{{ x.name }}
-
+
diff --git a/packages/client/src/widgets/rss-ticker.vue b/packages/client/src/widgets/rss-ticker.vue
index 06995bc86..c692c0c4f 100644
--- a/packages/client/src/widgets/rss-ticker.vue
+++ b/packages/client/src/widgets/rss-ticker.vue
@@ -26,6 +26,7 @@ import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os';
import MkContainer from '@/components/ui/container.vue';
import { useInterval } from '@/scripts/use-interval';
+import { shuffle } from '@/scripts/shuffle';
const name = 'rssTicker';
@@ -34,6 +35,10 @@ const widgetPropsDef = {
type: 'string' as const,
default: 'http://feeds.afpbb.com/rss/afpbb/afpbbnews',
},
+ shuffle: {
+ type: 'boolean' as const,
+ default: true,
+ },
refreshIntervalSec: {
type: 'number' as const,
default: 60,
@@ -80,6 +85,9 @@ let key = $ref(0);
const tick = () => {
fetch(`/api/fetch-rss?url=${widgetProps.url}`, {}).then(res => {
res.json().then(feed => {
+ if (widgetProps.shuffle) {
+ shuffle(feed.items);
+ }
items.value = feed.items;
fetching.value = false;
key++;