mirror of
https://git.boykissers.com/pawkey/pawkey-sk.git
synced 2025-12-20 04:04:16 +00:00
feat: add music to front page of instance (#6)
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class AddMusicFieldsToMeta1743894419864 implements MigrationInterface {
|
||||||
|
name = 'AddMusicFieldsToMeta1743894419864'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "musicSource" character varying(1024)`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "musicEnabled" boolean NOT NULL DEFAULT false`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "musicEnabled"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "musicSource"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -114,6 +114,8 @@ export class MetaEntityService {
|
|||||||
sidebarLogoUrl: instance.sidebarLogoUrl,
|
sidebarLogoUrl: instance.sidebarLogoUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
logoImageUrl: instance.logoImageUrl,
|
||||||
|
musicSource: instance.musicSource,
|
||||||
|
musicEnabled: instance.musicEnabled,
|
||||||
maxNoteTextLength: this.config.maxNoteLength,
|
maxNoteTextLength: this.config.maxNoteLength,
|
||||||
maxRemoteNoteTextLength: this.config.maxRemoteNoteLength,
|
maxRemoteNoteTextLength: this.config.maxRemoteNoteLength,
|
||||||
maxCwLength: this.config.maxCwLength,
|
maxCwLength: this.config.maxCwLength,
|
||||||
|
|||||||
@@ -142,6 +142,17 @@ export class MiMeta {
|
|||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
|
public musicSource: string | null;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public musicEnabled: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
public iconUrl: string | null;
|
public iconUrl: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
|
|||||||
@@ -321,6 +321,14 @@ export const packedMetaLiteSchema = {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
},
|
},
|
||||||
|
musicSource: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
musicEnabled: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
privacyPolicyUrl: {
|
privacyPolicyUrl: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
|
|||||||
@@ -453,6 +453,14 @@ export const meta = {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
},
|
},
|
||||||
|
musicSource: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
musicEnabled: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
translationTimeout: {
|
translationTimeout: {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
@@ -696,6 +704,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
app512IconUrl: instance.app512IconUrl,
|
app512IconUrl: instance.app512IconUrl,
|
||||||
sidebarLogoUrl: instance.sidebarLogoUrl,
|
sidebarLogoUrl: instance.sidebarLogoUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
|
musicSource: instance.musicSource,
|
||||||
|
musicEnabled: instance.musicEnabled,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
logoImageUrl: instance.logoImageUrl,
|
||||||
defaultLightTheme: instance.defaultLightTheme,
|
defaultLightTheme: instance.defaultLightTheme,
|
||||||
defaultDarkTheme: instance.defaultDarkTheme,
|
defaultDarkTheme: instance.defaultDarkTheme,
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ export const paramDef = {
|
|||||||
app512IconUrl: { type: 'string', nullable: true },
|
app512IconUrl: { type: 'string', nullable: true },
|
||||||
sidebarLogoUrl: { type: 'string', nullable: true },
|
sidebarLogoUrl: { type: 'string', nullable: true },
|
||||||
backgroundImageUrl: { type: 'string', nullable: true },
|
backgroundImageUrl: { type: 'string', nullable: true },
|
||||||
|
musicSource: { type: 'string', nullable: true },
|
||||||
|
musicEnabled: { type: 'boolean', nullable: false },
|
||||||
logoImageUrl: { type: 'string', nullable: true },
|
logoImageUrl: { type: 'string', nullable: true },
|
||||||
name: { type: 'string', nullable: true },
|
name: { type: 'string', nullable: true },
|
||||||
shortName: { type: 'string', nullable: true },
|
shortName: { type: 'string', nullable: true },
|
||||||
@@ -316,6 +318,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
set.backgroundImageUrl = ps.backgroundImageUrl;
|
set.backgroundImageUrl = ps.backgroundImageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.musicEnabled !== undefined) {
|
||||||
|
set.musicEnabled = ps.musicEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.musicSource !== undefined) {
|
||||||
|
set.musicSource = ps.musicSource;
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.logoImageUrl !== undefined) {
|
if (ps.logoImageUrl !== undefined) {
|
||||||
set.logoImageUrl = ps.logoImageUrl;
|
set.logoImageUrl = ps.logoImageUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="instance" :class="$style.root">
|
<div v-if="instance" :class="$style.root">
|
||||||
|
<PwVisitorMusic/>
|
||||||
<div :class="[$style.main, $style.panel]">
|
<div :class="[$style.main, $style.panel]">
|
||||||
<img :src="instance.sidebarLogoUrl || instance.iconUrl || '/apple-touch-icon.png'" alt="" :class="instance.sidebarLogoUrl ? $style.wideIcon : $style.mainIcon"/>
|
<img :src="instance.sidebarLogoUrl || instance.iconUrl || '/apple-touch-icon.png'" alt="" :class="instance.sidebarLogoUrl ? $style.wideIcon : $style.mainIcon"/>
|
||||||
<button class="_button _acrylic" :class="$style.mainMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
<button class="_button _acrylic" :class="$style.mainMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
||||||
@@ -61,6 +62,7 @@ import * as Misskey from 'misskey-js';
|
|||||||
import sanitizeHtml from '@/utility/sanitize-html.js';
|
import sanitizeHtml from '@/utility/sanitize-html.js';
|
||||||
import XSigninDialog from '@/components/MkSigninDialog.vue';
|
import XSigninDialog from '@/components/MkSigninDialog.vue';
|
||||||
import XSignupDialog from '@/components/MkSignupDialog.vue';
|
import XSignupDialog from '@/components/MkSignupDialog.vue';
|
||||||
|
import PwVisitorMusic from '@/components/PwVisitorMusic.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
|
|||||||
30
packages/frontend/src/components/PwVisitorMusic.vue
Normal file
30
packages/frontend/src/components/PwVisitorMusic.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<template v-if="instance">
|
||||||
|
<audio v-if="instance.musicEnabled" ref="audioRef" :src="instance.musicSource" loop></audio>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, onMounted, onUnmounted } from 'vue';
|
||||||
|
import { instance } from '@/instance.js';
|
||||||
|
|
||||||
|
const audioRef = ref<HTMLAudioElement | null>(null);
|
||||||
|
const hasPlayed = ref(false);
|
||||||
|
|
||||||
|
const playMusic = () => {
|
||||||
|
if (audioRef.value && !hasPlayed.value && instance.musicEnabled) {
|
||||||
|
audioRef.value.volume = 0.2;
|
||||||
|
audioRef.value.play().catch(() => {
|
||||||
|
// Ignore autoplay errors
|
||||||
|
});
|
||||||
|
hasPlayed.value = true;
|
||||||
|
document.removeEventListener('click', playMusic);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('click', playMusic);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('click', playMusic);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -54,6 +54,16 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<template #label>{{ i18n.ts.backgroundImageUrl }}</template>
|
<template #label>{{ i18n.ts.backgroundImageUrl }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
|
<MkSwitch v-model="musicEnabled">
|
||||||
|
<template #label>Enable Login Music</template>
|
||||||
|
<template #caption>Play music when users visit the login page</template>
|
||||||
|
</MkSwitch>
|
||||||
|
|
||||||
|
<MkInput v-model="musicSource" type="url">
|
||||||
|
<template #prefix><i class="ti ti-link"></i></template>
|
||||||
|
<template #label>Login Music URL</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
<FromSlot>
|
<FromSlot>
|
||||||
<template #label>{{ i18n.ts.defaultLike }}</template>
|
<template #label>{{ i18n.ts.defaultLike }}</template>
|
||||||
<MkCustomEmoji v-if="defaultLike.startsWith(':')" style="max-height: 3em; font-size: 1.1em;" :useOriginalSize="false" :name="defaultLike" :normal="true" :noStyle="true"/>
|
<MkCustomEmoji v-if="defaultLike.startsWith(':')" style="max-height: 3em; font-size: 1.1em;" :useOriginalSize="false" :name="defaultLike" :normal="true" :noStyle="true"/>
|
||||||
@@ -129,6 +139,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||||||
import { instance, fetchInstance } from '@/instance.js';
|
import { instance, fetchInstance } from '@/instance.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkColorInput from '@/components/MkColorInput.vue';
|
import MkColorInput from '@/components/MkColorInput.vue';
|
||||||
|
|
||||||
@@ -138,6 +149,8 @@ const app192IconUrl = ref<string | null>(null);
|
|||||||
const app512IconUrl = ref<string | null>(null);
|
const app512IconUrl = ref<string | null>(null);
|
||||||
const bannerUrl = ref<string | null>(null);
|
const bannerUrl = ref<string | null>(null);
|
||||||
const backgroundImageUrl = ref<string | null>(null);
|
const backgroundImageUrl = ref<string | null>(null);
|
||||||
|
const musicSource = ref<string | null>(null);
|
||||||
|
const musicEnabled = ref<boolean>(false);
|
||||||
const themeColor = ref<string | null>(null);
|
const themeColor = ref<string | null>(null);
|
||||||
const defaultLightTheme = ref<string | null>(null);
|
const defaultLightTheme = ref<string | null>(null);
|
||||||
const defaultDarkTheme = ref<string | null>(null);
|
const defaultDarkTheme = ref<string | null>(null);
|
||||||
@@ -157,6 +170,8 @@ async function init() {
|
|||||||
app512IconUrl.value = meta.app512IconUrl;
|
app512IconUrl.value = meta.app512IconUrl;
|
||||||
bannerUrl.value = meta.bannerUrl;
|
bannerUrl.value = meta.bannerUrl;
|
||||||
backgroundImageUrl.value = meta.backgroundImageUrl;
|
backgroundImageUrl.value = meta.backgroundImageUrl;
|
||||||
|
musicSource.value = meta.musicSource;
|
||||||
|
musicEnabled.value = meta.musicEnabled;
|
||||||
themeColor.value = meta.themeColor;
|
themeColor.value = meta.themeColor;
|
||||||
defaultLightTheme.value = meta.defaultLightTheme;
|
defaultLightTheme.value = meta.defaultLightTheme;
|
||||||
defaultDarkTheme.value = meta.defaultDarkTheme;
|
defaultDarkTheme.value = meta.defaultDarkTheme;
|
||||||
@@ -177,6 +192,8 @@ function save() {
|
|||||||
app512IconUrl: app512IconUrl.value,
|
app512IconUrl: app512IconUrl.value,
|
||||||
bannerUrl: bannerUrl.value,
|
bannerUrl: bannerUrl.value,
|
||||||
backgroundImageUrl: backgroundImageUrl.value,
|
backgroundImageUrl: backgroundImageUrl.value,
|
||||||
|
musicSource: musicSource.value,
|
||||||
|
musicEnabled: musicEnabled.value,
|
||||||
themeColor: themeColor.value === '' ? null : themeColor.value,
|
themeColor: themeColor.value === '' ? null : themeColor.value,
|
||||||
defaultLightTheme: defaultLightTheme.value === '' ? null : defaultLightTheme.value,
|
defaultLightTheme: defaultLightTheme.value === '' ? null : defaultLightTheme.value,
|
||||||
defaultDarkTheme: defaultDarkTheme.value === '' ? null : defaultDarkTheme.value,
|
defaultDarkTheme: defaultDarkTheme.value === '' ? null : defaultDarkTheme.value,
|
||||||
|
|||||||
Reference in New Issue
Block a user