Fixed type definition of SongCursorInfos fixed 'race conditions' in asset generation service removed hard coded cursor infos fixed tsc looking to build folders
This commit is contained in:
@@ -157,12 +157,6 @@ export async function generateSongAssets(
|
||||
eval(`import("cross-blob")`).then((module) => {
|
||||
Blob = module.default;
|
||||
});
|
||||
try {
|
||||
let e = require("canvas")
|
||||
console.log(e, "pass");
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
debug("" + sampleDir + " " + imageDir + " " + imageFormat);
|
||||
|
||||
if (!mode) {
|
||||
|
||||
@@ -5,12 +5,24 @@ import { generateSongAssets } from "src/assetsgenerator/generateImages_browserle
|
||||
|
||||
@Injectable()
|
||||
export class SongService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
// number is the song id
|
||||
private readonly assetCreationTasks: Map<number, Promise<void>>;
|
||||
constructor(private prisma: PrismaService) {
|
||||
this.assetCreationTasks = new Map();
|
||||
}
|
||||
|
||||
async createAssets(mxlPath: string, songId: number): Promise<void> {
|
||||
if (this.assetCreationTasks.has(songId)) {
|
||||
await this.assetCreationTasks.get(songId);
|
||||
this.assetCreationTasks.delete(songId);
|
||||
return;
|
||||
}
|
||||
// mxlPath can the path to an archive to an xml file or the path to the xml file directly
|
||||
// const generateSongAssets = (await import("src/assetsgenerator/generateImages_browserless.mjs")).default;
|
||||
return generateSongAssets(songId, mxlPath, "/data/cache/songs", "svg");
|
||||
this.assetCreationTasks.set(
|
||||
songId,
|
||||
generateSongAssets(songId, mxlPath, "/data/cache/songs", "svg"),
|
||||
);
|
||||
return await this.assetCreationTasks.get(songId);
|
||||
}
|
||||
|
||||
async songByArtist(data: number): Promise<Song[]> {
|
||||
|
||||
8440
front/API.ts
8440
front/API.ts
File diff suppressed because it is too large
Load Diff
@@ -16,8 +16,9 @@ export type ParitionMagicProps = {
|
||||
};
|
||||
|
||||
const getSVGURL = (songID: number) => {
|
||||
// return 'https://cdn.discordapp.com/attachments/717080637038788731/1162519992722530354/Short.mxl_1.svg?ex=653c3c1c&is=6529c71c&hm=1788e4abe532f4a2af8c24cae6dadcfde369eaf58322f051ecd1d9110d8b699a&';
|
||||
return 'https://cdn.discordapp.com/attachments/717080637038788731/1161704545785757816/4.svg?ex=653944ab&is=6526cfab&hm=2416ee2cb414cc42fa9de8af58b8db544479d35f13393d76f02e8d9fe27aff45&';
|
||||
return API.getPartitionSvgUrl(songID);
|
||||
return 'https://cdn.discordapp.com/attachments/717080637038788731/1162519992722530354/Short.mxl_1.svg?ex=653c3c1c&is=6529c71c&hm=1788e4abe532f4a2af8c24cae6dadcfde369eaf58322f051ecd1d9110d8b699a&';
|
||||
// return 'https://cdn.discordapp.com/attachments/717080637038788731/1161704545785757816/4.svg?ex=653944ab&is=6526cfab&hm=2416ee2cb414cc42fa9de8af58b8db544479d35f13393d76f02e8d9fe27aff45&';
|
||||
};
|
||||
|
||||
const SVGContainer = ({
|
||||
@@ -96,7 +97,7 @@ const PartitionMagic = ({ songID, onEndReached, onError, onReady }: ParitionMagi
|
||||
}
|
||||
}, [isLoading, isError]);
|
||||
|
||||
const transitionDuration = 75;
|
||||
const transitionDuration = 200;
|
||||
|
||||
getCursorToPlay(
|
||||
data?.cursors ?? [],
|
||||
@@ -144,6 +145,7 @@ const PartitionMagic = ({ songID, onEndReached, onError, onReady }: ParitionMagi
|
||||
left: `${partitionOffset.value * 100}%`,
|
||||
}}
|
||||
>
|
||||
{!isLoading && !isError && (
|
||||
<ImageBackground
|
||||
source={{ uri: getSVGURL(songID) }}
|
||||
onLoad={onReady}
|
||||
@@ -153,6 +155,7 @@ const PartitionMagic = ({ songID, onEndReached, onError, onReady }: ParitionMagi
|
||||
position: 'relative',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Animated.View>
|
||||
<Animated.View
|
||||
style={{
|
||||
|
||||
@@ -13,12 +13,15 @@ export const SongCursorInfosValidator = yup.object({
|
||||
height: yup.number().required(),
|
||||
timestamp: yup.number().required(),
|
||||
timing: yup.number().required(),
|
||||
note: yup
|
||||
.object({
|
||||
note: yup.number().required(),
|
||||
gain: yup.number().required(),
|
||||
duration: yup.number().required(),
|
||||
})
|
||||
notes: yup
|
||||
.array()
|
||||
.of(
|
||||
yup.object({
|
||||
note: yup.number().required(),
|
||||
gain: yup.number().required(),
|
||||
duration: yup.number().required(),
|
||||
})
|
||||
)
|
||||
.required(),
|
||||
})
|
||||
)
|
||||
@@ -39,11 +42,11 @@ export const SongCursorInfosHandler: ResponseHandler<
|
||||
height: cursor.height,
|
||||
timestamp: cursor.timestamp,
|
||||
timing: cursor.timing,
|
||||
note: {
|
||||
note: cursor.note.note,
|
||||
gain: cursor.note.gain,
|
||||
duration: cursor.note.duration,
|
||||
},
|
||||
notes: cursor.notes.map((n) => ({
|
||||
note: n.note,
|
||||
gain: n.gain,
|
||||
duration: n.duration,
|
||||
})),
|
||||
})),
|
||||
}),
|
||||
};
|
||||
@@ -55,11 +58,11 @@ export interface CursorInfoItem {
|
||||
height: number;
|
||||
timestamp: number;
|
||||
timing: number;
|
||||
note: {
|
||||
notes: {
|
||||
note: number;
|
||||
gain: number;
|
||||
duration: number;
|
||||
};
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface SongCursorInfos {
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
"metro.config.js",
|
||||
"jest.config.js",
|
||||
"app.config.ts",
|
||||
"*/*.test.tsx"
|
||||
"*/*.test.tsx",
|
||||
"web-build",
|
||||
"dist",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||
import { StackActions } from '@react-navigation/native';
|
||||
import React, { useEffect, useRef, useState, createContext, useReducer } from 'react';
|
||||
import { SafeAreaView, Platform, Animated } from 'react-native';
|
||||
import { SafeAreaView, Platform } from 'react-native';
|
||||
import Animated, {
|
||||
BounceIn,
|
||||
useSharedValue,
|
||||
withTiming,
|
||||
Easing,
|
||||
useAnimatedStyle,
|
||||
withSequence,
|
||||
withDelay,
|
||||
} from 'react-native-reanimated';
|
||||
import * as ScreenOrientation from 'expo-screen-orientation';
|
||||
import {
|
||||
Box,
|
||||
@@ -15,6 +24,7 @@ import {
|
||||
Icon,
|
||||
HStack,
|
||||
Image,
|
||||
PresenceTransition,
|
||||
} from 'native-base';
|
||||
import IconButton from '../components/IconButton';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
@@ -79,6 +89,27 @@ export const PianoCC = createContext<PianoCanvasContext>({
|
||||
messages: [],
|
||||
});
|
||||
|
||||
const infoCardInfos = [
|
||||
{
|
||||
icon: <Ionicons name="timer-outline" size={18} color="#6075F9" />,
|
||||
label: 'Last Score',
|
||||
id: 'lastScore',
|
||||
value: 60,
|
||||
},
|
||||
{
|
||||
icon: <Ionicons name="trophy-outline" size={18} color="#6075F9" />,
|
||||
label: 'Best Score',
|
||||
id: 'bestScore',
|
||||
value: 60,
|
||||
},
|
||||
{
|
||||
icon: <Ionicons name="bar-chart-outline" size={18} color="#6075F9" />,
|
||||
label: 'Level',
|
||||
id: 'level',
|
||||
value: 3,
|
||||
},
|
||||
] as const;
|
||||
|
||||
const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
const accessToken = useSelector((state: RootState) => state.user.accessToken);
|
||||
const navigation = useNavigation();
|
||||
@@ -92,7 +123,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
const [time, setTime] = useState(0);
|
||||
const [partitionRendered, setPartitionRendered] = useState(false); // Used to know when partitionview can render
|
||||
const [score, setScore] = useState(0); // Between 0 and 100
|
||||
const fadeAnim = useRef(new Animated.Value(0)).current;
|
||||
// const fadeAnim = useRef(new Animated.Value(0)).current;
|
||||
const musixml = useQuery(
|
||||
transformQuery(API.getSongMusicXML(songId), (data) => new TextDecoder().decode(data)),
|
||||
{ staleTime: Infinity }
|
||||
@@ -108,27 +139,14 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const infoCardInfos = [
|
||||
{
|
||||
icon: <Ionicons name="timer-outline" size={18} color="#6075F9" />,
|
||||
label: 'Last Score',
|
||||
id: 'lastScore',
|
||||
value: 60,
|
||||
},
|
||||
{
|
||||
icon: <Ionicons name="trophy-outline" size={18} color="#6075F9" />,
|
||||
label: 'Best Score',
|
||||
id: 'bestScore',
|
||||
value: 60,
|
||||
},
|
||||
{
|
||||
icon: <Ionicons name="bar-chart-outline" size={18} color="#6075F9" />,
|
||||
label: 'Level',
|
||||
id: 'level',
|
||||
value: 3,
|
||||
},
|
||||
] as const;
|
||||
const [streak, setStreak] = useState(0);
|
||||
const scoreMessageScale = useSharedValue(0);
|
||||
// this style should bounce in on enter and fade away
|
||||
const scoreMsgStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
transform: [{ scale: scoreMessageScale.value }],
|
||||
};
|
||||
});
|
||||
|
||||
const onPause = () => {
|
||||
stopwatch.pause();
|
||||
@@ -234,7 +252,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
type: 'noteTiming',
|
||||
data: NoteTiming.Missed,
|
||||
});
|
||||
messageColor = 'black';
|
||||
messageColor = 'white';
|
||||
} else if (data.type == 'timing' || data.type == 'duration') {
|
||||
formattedMessage = translate(data[data.type]);
|
||||
switch (data[data.type]) {
|
||||
@@ -324,12 +342,19 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (lastScoreMessage) {
|
||||
fadeAnim.setValue(1);
|
||||
Animated.timing(fadeAnim, {
|
||||
toValue: 0,
|
||||
duration: 3000,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
scoreMessageScale.value = withSequence(
|
||||
withTiming(1, {
|
||||
duration: 400,
|
||||
easing: Easing.elastic(3),
|
||||
}),
|
||||
withDelay(
|
||||
700,
|
||||
withTiming(0, {
|
||||
duration: 300,
|
||||
easing: Easing.out(Easing.cubic),
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [lastScoreMessage]);
|
||||
useEffect(() => {
|
||||
@@ -408,20 +433,24 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
<View>
|
||||
<Text fontSize={24}>{score}</Text>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
gap: 7,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Text fontSize={20}>Cool</Text>
|
||||
<Text fontSize={15} bold>
|
||||
x1
|
||||
</Text>
|
||||
</View>
|
||||
<Animated.View style={[scoreMsgStyle]}>
|
||||
<View
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
gap: 7,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Text fontSize={20} color={'white'}>
|
||||
{lastScoreMessage?.content}
|
||||
</Text>
|
||||
<Text fontSize={15} bold>
|
||||
{streak > 0 && `x${streak}`}
|
||||
</Text>
|
||||
</View>
|
||||
</Animated.View>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
@@ -531,7 +560,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
.padStart(2, '0')}`}
|
||||
</Text>
|
||||
<StarProgress
|
||||
value={60}
|
||||
value={score}
|
||||
max={100}
|
||||
starSteps={[50, 75, 90]}
|
||||
style={{
|
||||
@@ -541,7 +570,6 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
marginBottom: 10,
|
||||
}}
|
||||
/>
|
||||
<Text>2:30</Text>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
|
||||
Reference in New Issue
Block a user