diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e1666b080..efb0d684aa 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 fd8aca868b..bdff7e38da 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 e19690209a..2f0c6fc1ee 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 0000000000..05e6cdfbcf
--- /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 88604a38a7..635b875ca1 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 5358b26ece..114ca5be8c 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 06995bc865..c692c0c4ff 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++;