Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/frontend/character.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ export const characters: { [characterId: string]: Character } =

export const loadCharacters = async (crispMode: boolean) => {

const response = await fetch("/api/characters/" + (crispMode ? "crisp" : "regular") + "?v=" + (window as any).EXPECTED_SERVER_VERSION)
const response = await fetch("/api/characters/" + (crispMode ? "crisp" : "regular") + "?v=" + window.EXPECTED_SERVER_VERSION)
const dto = await response.json()

Object.keys(characters).forEach(characterId => characters[characterId].setDto(dto[characterId]))
}
}
10 changes: 5 additions & 5 deletions src/frontend/components/chessboard-slot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { PropType } from 'vue'
import type { Socket } from 'socket.io-client'

import type { ChessboardStateDto, } from '../types'
import type { ChessboardStateDto } from '../types'

import { defineComponent, inject, Ref } from 'vue'

Expand All @@ -20,9 +20,8 @@ export default defineComponent({
},
data()
{
const chessboard: any | null = null
return {
chessboard,
chessboard: null as ChessboardInstance | null,
visible: false,
}
},
Expand Down Expand Up @@ -57,12 +56,13 @@ export default defineComponent({
{
if (!this.chessboardState) return
const chessboardElement = document.getElementById("chessboard")
if (!chessboardElement) return

const position = this.chessboardState
? (this.chessboardState.fenString || "start")
: "start"

this.chessboard = (window as any).Chessboard(chessboardElement, {
this.chessboard = window.Chessboard(chessboardElement, {
pieceTheme: 'chess/img/chesspieces/wikipedia/{piece}.png',
position,
orientation: this.chessboardState.blackUserID == this.myUserId ? "black" : "white",
Expand All @@ -86,7 +86,7 @@ export default defineComponent({
// if (colorOfMovedPiece != this.chessboardState.turn)
// return false
},
onDrop: (source: any, target: any) =>
onDrop: (source: string, target: string) =>
{
if (!this.chessboardState) return
if (this.chessboardState.blackUserID == this.myUserId
Expand Down
7 changes: 4 additions & 3 deletions src/frontend/components/numeric-value-control.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ const props = defineProps({
})

const count = ref(props.initialValue)
const emit = defineEmits(['value-changed'])
const emit = defineEmits<{
'value-changed': [value: number]
}>()

const emitValueChanged = () => {
console.log('emitValueChanged', count.value)
emit('value-changed', count.value)
}
const increment = () => {
Expand Down Expand Up @@ -60,4 +61,4 @@ const reset = () => {
class="value"
@click="reset">{{ count }}</button>
</div>
</template>
</template>
29 changes: 22 additions & 7 deletions src/frontend/components/voice-changer-control.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,38 @@ import { AudioProcessor } from '../utils';
import NumericValueControl from './numeric-value-control.vue';

const outboundAudioProcessor = inject('outboundAudioProcessor') as Ref<AudioProcessor>
const pitchShiftMin = -100
const pitchShiftMax = 200
const pitchFactorMin = 0.5
const pitchFactorMax = 2
const pitchShiftRange = pitchShiftMax - pitchShiftMin
const pitchFactorRange = pitchFactorMax - pitchFactorMin

// This component might be destroyed and recreated multiple times, so we need to
// get the current pitch factor from the audio processor.
// Also the audio processor might not be ready yet, so we need to use a default value.
const initialPitchFactor = outboundAudioProcessor.value?.getPitchFactor() ?? 1
const initialValue = Math.round((initialPitchFactor - 1) * 200)
const initialValue = Math.round(Math.min(
pitchShiftMax,
Math.max(
pitchShiftMin,
((initialPitchFactor - pitchFactorMin) / pitchFactorRange) * pitchShiftRange + pitchShiftMin,
),
))

function onPitchShiftChanged(value: number) {
console.log('onPitchShiftChanged', value, outboundAudioProcessor.value)
// convert value (-100~100) to pitch factor (0.5~1.5)
const pitchFactor = 0.5 + (value + 100) / 200
// Convert slider values (-100..200) to AudioProcessor pitch factors (0.5..2.0).
const pitchFactor = pitchFactorMin + ((value - pitchShiftMin) / pitchShiftRange) * pitchFactorRange
outboundAudioProcessor.value?.setPitchFactor(pitchFactor)
}

</script>

<template>
<NumericValueControl :min="-100" :max="200" :default="0" :initialValue="initialValue"
@value-changed="value => onPitchShiftChanged(value)"></NumericValueControl>
</template>
<NumericValueControl
:min="pitchShiftMin"
:max="pitchShiftMax"
:default="0"
:initialValue="initialValue"
@value-changed="onPitchShiftChanged"></NumericValueControl>
</template>
113 changes: 75 additions & 38 deletions src/frontend/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ import $ from "jquery";
import "jquery-ui/themes/base/all.css";

// needed to make $ and jQuery available globally for the jquery-ui plugins.
(window as any).$ = $;
(window as any).jQuery = $;
window.$ = $;
window.jQuery = $;

await import("jquery-ui/dist/jquery-ui.js");
await import("jquery-ui-touch-punch");
Expand Down Expand Up @@ -235,6 +235,59 @@ function setAppLanguage(code: string)
i18next.changeLanguage(code, setPageMetadata)
}

type PersistedSettingValues = {
uiTheme: string
isCoinSoundEnabled: boolean
language: string
bubbleOpacity: number
showNotifications: boolean
isLowQualityEnabled: boolean
isCrispModeEnabled: boolean
isIdleAnimationDisabled: boolean
isNameMentionSoundEnabled: boolean
customMentionSoundPattern: string
enableTextToSpeech: boolean
ttsVoiceURI: string
voiceVolume: number
}

type VerticalSliderConfig = {
selector: string
min: number
max: number
step: number
value: number
onSlide: (value: number) => void
}

function initializeVerticalSlider({ selector, min, max, step, value, onSlide }: VerticalSliderConfig)
{
$(selector).slider({
orientation: "vertical",
range: "min",
min,
max,
step,
value,
slide: (_event, ui) => {
onSlide(ui.value)
}
})
}

function makeResizable(target: string | HTMLElement, options?: JQueryUiResizableOptions)
{
$(target).resizable(options)
}

function makeVideoContainerResizable(target: string | HTMLElement)
{
makeResizable(target, {
aspectRatio: true,
resize: adjustNiconicoMessagesFontSize
})
}

const vueApp = createApp(defineComponent({
components: {
ChessboardSlot,
Expand Down Expand Up @@ -580,33 +633,28 @@ const vueApp = createApp(defineComponent({
}
}

// @ts-ignore
$( "#sound-effect-volume" ).slider({
orientation: "vertical",
range: "min",
initializeVerticalSlider({
selector: "#sound-effect-volume",
min: 0,
max: 1,
step: 0.01,
value: this.soundEffectVolume,
slide: ( event: any, ui: any ) => {
this.changeSoundEffectVolume(ui.value);
onSlide: (value) => {
this.changeSoundEffectVolume(value);
}
});
// @ts-ignore
$( "#voice-volume" ).slider({
orientation: "vertical",
range: "min",
initializeVerticalSlider({
selector: "#voice-volume",
min: 0,
max: 100,
step: 1,
value: this.voiceVolume,
slide: ( event: any, ui: any ) => {
this.changeVoiceVolume(ui.value);
onSlide: (value) => {
this.changeVoiceVolume(value);
}
});

// @ts-ignore
$( "#main-section" ).resizable({
makeResizable("#main-section", {
handles: "e"
})

Expand Down Expand Up @@ -910,11 +958,12 @@ const vueApp = createApp(defineComponent({
},
initializeSocket()
{
// @ts-ignore
this.socket = io({
const socketOptions = {
extraHeaders: {"private-user-id": this.myPrivateUserID},
closeOnBeforeunload: false,
});
} as Parameters<typeof io>[0]

this.socket = io(socketOptions);

const immanentizeConnection = async () =>
{
Expand Down Expand Up @@ -2751,7 +2800,6 @@ const vueApp = createApp(defineComponent({
rtcPeer.conn.addEventListener("iceconnectionstatechange", (ev) =>
{
const state = rtcPeer.conn!.iceConnectionState;
console.log("RTC Connection state", state)
logToServer(new Date() + " " + this.myUserID + " RTC Connection state " + state)

if (state == "connected")
Expand Down Expand Up @@ -2855,11 +2903,7 @@ const vueApp = createApp(defineComponent({
else
this.takeStream(slotId);

// @ts-ignore
$( "#video-container-" + slotId ).resizable({
aspectRatio: true,
resize: adjustNiconicoMessagesFontSize
})
makeVideoContainerResizable("#video-container-" + slotId)

if (this.slotVolume[slotId] === undefined)
this.slotVolume[slotId] = 1
Expand Down Expand Up @@ -3234,11 +3278,7 @@ const vueApp = createApp(defineComponent({
const stream = event.streams[0]
videoElement.srcObject = stream;

// @ts-ignore
$( "#video-container-" + streamSlotId ).resizable({
aspectRatio: true,
resize: adjustNiconicoMessagesFontSize
})
makeVideoContainerResizable("#video-container-" + streamSlotId)

if (this.inboundAudioProcessors[streamSlotId])
{
Expand Down Expand Up @@ -3521,8 +3561,7 @@ const vueApp = createApp(defineComponent({
this.checkBackgroundColor();
for (const knobElement of (document.getElementsByClassName("input-knob") as HTMLCollectionOf<HTMLInputElement>))
{
// @ts-ignore what's refresh from? can't find it in docs
knobElement.refresh()
knobElement.refresh?.()
}
this.isRedrawRequired = true
},
Expand All @@ -3535,11 +3574,11 @@ const vueApp = createApp(defineComponent({
this.storeSet('language');
this.setLanguage();
},
storeSet(itemName: string, value?: any)
storeSet<K extends keyof PersistedSettingValues>(itemName: K, value?: PersistedSettingValues[K])
{
// @ts-ignore
if (value != undefined) this[itemName] = value;
localStorage.setItem(itemName, this[itemName]);
const persistedSettings = this as unknown as PersistedSettingValues
if (value !== undefined) persistedSettings[itemName] = value;
localStorage.setItem(itemName, String(persistedSettings[itemName]));
},
handleBubbleOpacity()
{
Expand Down Expand Up @@ -3721,12 +3760,10 @@ const vueApp = createApp(defineComponent({

if (videoContainer.classList.contains("unpinned-video"))
{
// @ts-ignore
$(videoContainer).draggable()
}
else
{
// @ts-ignore
$(videoContainer).draggable("destroy")
// Reset 'top' and 'left' styles to snap the container back to its original position
videoContainer.setAttribute("style", "")
Expand Down
5 changes: 3 additions & 2 deletions src/frontend/rtcpeer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export type SendCallback = (type: string, msg: string | RTCIceCandidate) => void
export type ErrorCallback = (error: any, event: any) => void
export type RTCSignalType = "offer" | "answer" | "candidate"
export type SendCallback = (type: RTCSignalType, msg: string | RTCIceCandidate) => void
export type ErrorCallback = (error: unknown, event: Event) => void


export const defaultIceConfig: RTCConfiguration = {
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/tts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { i18n } from "i18next";
import { kanaToRomajiMap, kanjiToKanaMap, katakanaToHiragana } from "./japanese-tools";
import { debounceWithDelayedExecution, urlRegex } from "./utils";

const synth = new (window as any).Animalese('animalese.wav', function () { });
const synth = new window.Animalese('animalese.wav', function () { });

function speakAnimalese(text: string, pitch: number | null, volume: number) {
// replace every japanese character with a random roman letter
Expand Down
Loading