Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
File renamed without changes.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"tslib": "^2.8.1",
"typescript": "^5.7.3",
"typescript-eslint": "^8.22.0",
"vite": "^6.1.6"
"vite": "^6.4.1"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.7.2",
Expand All @@ -68,6 +68,7 @@
"chart.js": "^4.4.7",
"dompurify": "^3.2.4",
"escape-goat": "^4.0.0",
"jszip": "^3.10.1",
"object-to-formdata": "^4.5.1",
"qrcode": "^1.5.4",
"query-string": "^9.1.1",
Expand Down
142 changes: 103 additions & 39 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/lib/api/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export enum ChartFormat {
Pec,
PhiZone,
Phigrim,
Milthm,
Unsupported,
}

Expand All @@ -25,6 +26,10 @@ export enum ChartLevel {
IN,
AT,
SP,
DZ,
SK,
CB,
CL,
}

export interface ChartDto {
Expand Down
81 changes: 57 additions & 24 deletions src/lib/components/SongSubmissionForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import RangeSlider from 'svelte-range-slider-pips';
import { superForm } from 'sveltekit-superforms';

import type { Bpm, ChartBundle, RpeJson } from '$lib/types';
import type { Bpm, ChartBundle, MilthmJson, RpeJson } from '$lib/types';

import { page } from '$app/state';
import Tag from '$lib/components/Tag.svelte';
Expand Down Expand Up @@ -75,32 +75,65 @@

$effect(() => {
(async () => {
const chart = await bundle.resources.chart.text();
const { BPMList, META }: RpeJson = JSON.parse(chart);
const chartText = await bundle.resources.chart.text();
const chartJson = JSON.parse(chartText);

$form.Title = bundle.metadata.title;
$form.Illustrator = bundle.metadata.illustrator ?? '';
$form.Offset = META.offset;

bpmList = BPMList;

let lastBpm = 0;
let lastBeat = 0;
let lastTimeSec = 0;
bpmList.forEach((bpm, i) => {
bpm.startBeat = toBeats(bpm.startTime);
bpm.startTimeSec =
i === 0 ? lastTimeSec : lastTimeSec + ((bpm.startBeat - lastBeat) / lastBpm) * 60;
lastBpm = bpm.bpm;
lastBeat = bpm.startBeat;
lastTimeSec = bpm.startTimeSec;
});

const bpmArr = bpmList.map((bpm) => bpm.bpm);
$form.MinBpm = Math.min(...bpmArr);
$form.MaxBpm = Math.max(...bpmArr);
if ($form.MinBpm === $form.MaxBpm) {
$form.Bpm = $form.MinBpm;

if ('META' in chartJson && 'BPMList' in chartJson) {
const { BPMList, META } = chartJson as RpeJson;
$form.Offset = META.offset;

bpmList = BPMList;

let lastBpm = 0;
let lastBeat = 0;
let lastTimeSec = 0;
bpmList.forEach((bpm, i) => {
bpm.startBeat = toBeats(bpm.startTime);
bpm.startTimeSec =
i === 0 ? lastTimeSec : lastTimeSec + ((bpm.startBeat - lastBeat) / lastBpm) * 60;
lastBpm = bpm.bpm;
lastBeat = bpm.startBeat;
lastTimeSec = bpm.startTimeSec;
});

const bpmArr = bpmList.map((bpm) => bpm.bpm);
$form.MinBpm = Math.min(...bpmArr);
$form.MaxBpm = Math.max(...bpmArr);
if ($form.MinBpm === $form.MaxBpm) {
$form.Bpm = $form.MinBpm;
}
} else if ('lines' in chartJson && 'meta' in chartJson) {
const { bpms, meta } = chartJson as MilthmJson;
$form.Offset = Math.round(meta.offset * 100);

bpmList = bpms.map((b) => ({
bpm: b.bpm,
startTime: b.time,
startBeat: 0,
startTimeSec: 0,
}));

let lastBpm = 0;
let lastBeat = 0;
let lastTimeSec = 0;
bpmList.forEach((bpm, i) => {
bpm.startBeat = toBeats(bpm.startTime);
bpm.startTimeSec =
i === 0 ? lastTimeSec : lastTimeSec + ((bpm.startBeat - lastBeat) / lastBpm) * 60;
lastBpm = bpm.bpm;
lastBeat = bpm.startBeat;
lastTimeSec = bpm.startTimeSec;
});

const bpmArr = bpmList.map((bpm) => bpm.bpm);
$form.MinBpm = Math.min(...bpmArr);
$form.MaxBpm = Math.max(...bpmArr);
if ($form.MinBpm === $form.MaxBpm) {
$form.Bpm = $form.MinBpm;
}
Comment on lines +90 to +136
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] There's significant code duplication between the RPE (lines 90-107) and Milthm (lines 119-136) chart processing branches. The BPM calculation logic is identical. Consider extracting this into a shared function to improve maintainability and reduce duplication.

Copilot uses AI. Check for mistakes.
}
})();
});
Expand Down
12 changes: 11 additions & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@ export const USER_LEVELS = [
{ exp: 100000, level: 10 },
];

export const LEVEL_TYPES = ['EZ', 'HD', 'IN', 'AT', 'SP'];
export const LEVEL_TYPES = [
'EZ',
'HD',
'IN',
'AT',
'SP',
'DZ',
'SK',
'CB',
'CL',
];

export const SONG_MATCH_SCORE_THRESHOLD = 8e3;

Expand Down
2 changes: 1 addition & 1 deletion src/lib/translations/en-US/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"song_preview": "Song Preview",
"tips": {
"audio": "MP3 / FLAC / WAV / OGG, no larger than 50 MB",
"chart": "Only charts made with PE / RPE are supported, no larger than 50 MB",
"chart": "Only charts created by PE / RPE / Rain Editor are supported, no larger than 50 MB",
"chart_level": "EZ / HD / IN / AT / SP / FM / Custom / ……",
"illustration": "JPG / JPEG / PNG / WEBP, no larger than 10 MB, 16:9, no smaller than 960×540",
"image": "JPG / JPEG / PNG / WEBP, no larger than 10 MB",
Expand Down
3 changes: 2 additions & 1 deletion src/lib/translations/en-US/studio.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"chart_submission": "Chart Submission",
"chart_submissions": "Chart Submissions",
"choose_chart": "Choose Chart",
"choose_chart_description": "Please select a compressed file (.pez or .zip) containing an RPE or PE chart. The file must include at least a chart file, an audio file, and an Illustration file.",
"choose_chart_description": "Only PE / RPE / Rain Editor created charts are supported, not larger than 50 MB",
"collaboration": "Collaboration",
"collaborations": "Collaborations",
"collection_admission": "Collection Admission",
Expand All @@ -30,6 +30,7 @@
},
"session": {
"chart_confirmation_notice": "Please verify the chart's performance and offset using PhiZone Player for this step. Once confirmed, click the \"Export\" button.",
"milthm_preview_not_supported": "Milthm chart preview is not supported yet",
"pci_description": "Your submission might be restricted or rejected due to copyright issues. Listed are resource records whose copyright may have been potentially infringed by your submission.",
"potential_copyright_infringements": "Potential Infringing Songs",
"potential_song_duplicates": "Potential Duplicate Songs",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/translations/ja-JP/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"song_preview": "曲目预览",
"tips": {
"audio": "50 MB 又は更に小さい MP3 / FLAC / WAV / OGG",
"chart": "仅支持 PE / RPE 创作的谱面,不大于 50 MB",
"chart": "仅支持 PE / RPE / Rain Editor 创作的谱面,不大于 50 MB",
"chart_level": "EZ / HD / IN / AT / SP / FM / Custom / ……",
"illustration": "10 MB 又は更に小さい JPG / JPEG / PN / WEBP、比は 16:9、解像度は960x540 未満でなければなりません",
"image": "10 MB 又は更に小さい JPG / JPEG / PNG / WEBP",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/translations/ja-JP/studio.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"chart_submission": "谱面稿件",
"chart_submissions": "谱面稿件",
"choose_chart": "选择谱面",
"choose_chart_description": "请在此处选择包含 RPE 或 PE 谱面的压缩包(.pez 或 .zip),并且须至少包含谱面、曲目、曲绘文件。",
"choose_chart_description": "PE / RPE / Rain Editor で作成された譜面のみ対応しています。50MB以下。",
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The translation key milthm_preview_not_supported is missing for the ja-JP locale. This key is used at line 943 in the new-submission page but is only defined in en-US and zh-CN translation files. Please add: "milthm_preview_not_supported": "Milthmの譜面プレビューはまだサポートされていません" after line 32 in the session section.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

"collaboration": "合作邀请",
"collaborations": "合作邀请",
"collection_admission": "合集收录申请",
Expand Down
9 changes: 7 additions & 2 deletions src/lib/translations/zh-CN/chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"1": "PhiEditer 谱面",
"2": "PhiZone 谱面",
"3": "Phigrim 谱面",
"4": "未受支持"
"4": "Milthm 谱面",
"5": "未受支持"
},
"gameplay": "游玩体验",
"highest_difficulty": "最高定数",
Expand All @@ -56,7 +57,11 @@
"1": "HD",
"2": "IN",
"3": "AT",
"4": "SP"
"4": "SP",
"5": "DZ",
"6": "SK",
"7": "CB",
"8": "CL"
},
"lowest_difficulty": "最低定数",
"lowest_note_count": "最低物量",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/translations/zh-CN/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"song_preview": "曲目预览",
"tips": {
"audio": "50 MB 或更小的 MP3 / FLAC / WAV / OGG",
"chart": "仅支持 PE / RPE 创作的谱面,不大于 50 MB",
"chart": "仅支持 PE / RPE / Rain Editor 创作的谱面,不大于 50 MB",
"chart_level": "EZ / HD / IN / AT / SP / FM / Custom / ……",
"illustration": "10 MB 或更小的 JPG / JPEG / PNG / WEBP,长宽比须为 16:9,分辨率不得低于 960×540",
"image": "10 MB 或更小的 JPG / JPEG / PNG / WEBP",
Expand Down
5 changes: 3 additions & 2 deletions src/lib/translations/zh-CN/studio.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"chart_submission": "谱面稿件",
"chart_submissions": "谱面稿件",
"choose_chart": "选择谱面",
"choose_chart_description": "请在此处选择包含 RPE 或 PE 谱面的压缩包(.pez 或 .zip),并且须至少包含谱面、曲目、曲绘文件。",
"choose_chart_description": "仅支持 PE / RPE / Rain Editor 创作的谱面,不大于 50 MB",
"collaboration": "合作邀请",
"collaborations": "合作邀请",
"collection_admission": "合集收录申请",
Expand All @@ -30,6 +30,7 @@
},
"session": {
"chart_confirmation_notice": "请在本步骤使用 PhiZone Player 确认谱面的表现情况与谱面延迟。如完成确认,请点击“导出”按钮。",
"milthm_preview_not_supported": "暂不支持Milthm谱面预览",
"pci_description": "你提交的稿件可能会因版权问题而受到限制或被退回。此处列出了你的稿件可能侵犯其版权的资源记录。",
"potential_copyright_infringements": "疑似侵权的曲目",
"potential_song_duplicates": "疑似重复的曲目",
Expand Down Expand Up @@ -128,4 +129,4 @@
"upload_chart": "上传谱面",
"upload_song": "上传曲目",
"view_guide": "查看指南"
}
}
2 changes: 1 addition & 1 deletion src/lib/translations/zh-TW/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
"song_preview": "曲目預覽",
"tips": {
"audio": "50 MB 或更小的 MP3 / FLAC / WAV / OGG",
"chart": "僅支援 PE / RPE 創作的譜面,不大於 50 MB",
"chart": "僅支援 PE / RPE / Rain Editor 創作的譜面,不大於 50 MB",
"chart_level": "EZ / HD / IN / AT / SP / FM / Custom / ……",
"illustration": "10 MB 或更小的 JPG / JPEG / PNG / WEBP,長寬比必須為 16:9,解析度不得低於 960×540",
"image": "10 MB 或更小的 JPG / JPEG / PNG / WEBP",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/translations/zh-TW/studio.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"chart_submission": "譜面稿件",
"chart_submissions": "譜面稿件",
"choose_chart": "选择谱面",
"choose_chart_description": "请在此处选择包含 RPE 或 PE 谱面的压缩包(.pez 或 .zip),并且须至少包含谱面、曲目、曲绘文件。",
"choose_chart_description": "僅支持 PE / RPE / Rain Editor 創作的譜面,不大於 50 MB",
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The translation key milthm_preview_not_supported is missing for the zh-TW locale. This key is used at line 943 in the new-submission page but is only defined in en-US and zh-CN translation files. Please add: "milthm_preview_not_supported": "暫不支援 Milthm 譜面預覽" after line 32 in the session section.

Copilot uses AI. Check for mistakes.
"collaboration": "合作邀請",
"collaborations": "合作邀請",
"collection_admission": "合集收錄申請",
Expand Down
15 changes: 15 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,18 @@ export interface RpeJson {
BPMList: Bpm[];
META: RpeMeta;
}

export interface MilthmMeta {
offset: number;
}

export interface MilthmBpm {
bpm: number;
time: [number, number, number];
}

export interface MilthmJson {
meta: MilthmMeta;
bpms: MilthmBpm[];
lines: unknown[];
}
10 changes: 10 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,16 @@ export const getLevelColor = (type: number | undefined) => {
return 'btn-primary';
case 3:
return '';
case 4:
return 'btn-accent';
case 5:
return 'btn-success';
case 6:
return 'btn-info';
case 7:
return 'btn-error';
case 8:
return '';
default:
return 'btn-accent';
}
Expand Down
5 changes: 3 additions & 2 deletions src/routes/(app)/studio/chart-submissions/new/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { createQuery } from '@tanstack/svelte-query';
import { superForm } from 'sveltekit-superforms';

import { browser } from '$app/environment';
import type { SongSubmissionDto } from '$lib/api';
import type { SongDto } from '$lib/api/song';

Expand Down Expand Up @@ -52,7 +53,7 @@
createQuery(
api.song.submission.listAll(
{ order: ['dateCreated'], desc: [true] },
{ enabled: !songSwitch },
{ enabled: browser && !songSwitch },
),
),
);
Expand Down Expand Up @@ -194,7 +195,7 @@
type="file"
id="file"
name="File"
accept=".json, .pec"
accept=".json, .pec, .zip"
class={`w-1/3 file:mr-4 file:py-2 file:border-0 file:btn ${
$errors.File
? 'input-error file:btn-error'
Expand Down
Loading