From c77241a88320785e8a127d25a64abea29948bd9a Mon Sep 17 00:00:00 2001 From: Sean Du Date: Thu, 22 Jan 2026 08:20:13 +0800 Subject: [PATCH] Overhaul [1/n] Signed-off-by: Sean Du --- .gitignore | 5 - assets/.gitignore | 1 + assets/data.example.db | Bin 45056 -> 0 bytes .../{notes => beatmaps}/Live_0001.json | 0 .../{notes => beatmaps}/Live_0002.json | 0 .../{notes => beatmaps}/Live_0003.json | 0 .../{notes => beatmaps}/Live_0004.json | 0 .../{notes => beatmaps}/Live_0005.json | 0 .../{notes => beatmaps}/Live_0006.json | 0 .../{notes => beatmaps}/Live_0007.json | 0 .../{notes => beatmaps}/Live_0008.json | 0 .../{notes => beatmaps}/Live_0009.json | 0 .../{notes => beatmaps}/Live_0010.json | 0 .../{notes => beatmaps}/Live_0011.json | 0 .../{notes => beatmaps}/Live_0012.json | 0 .../{notes => beatmaps}/Live_0013.json | 0 .../{notes => beatmaps}/Live_0014.json | 0 .../{notes => beatmaps}/Live_0015.json | 0 .../{notes => beatmaps}/Live_0016.json | 0 .../{notes => beatmaps}/Live_0017.json | 0 .../{notes => beatmaps}/Live_0018.json | 0 .../{notes => beatmaps}/Live_0019.json | 0 .../{notes => beatmaps}/Live_0020.json | 0 .../{notes => beatmaps}/Live_0021.json | 0 .../{notes => beatmaps}/Live_0022.json | 0 .../{notes => beatmaps}/Live_0023.json | 0 .../{notes => beatmaps}/Live_0024.json | 0 .../{notes => beatmaps}/Live_0025.json | 0 .../{notes => beatmaps}/Live_0026.json | 0 .../{notes => beatmaps}/Live_0027.json | 0 .../{notes => beatmaps}/Live_0028.json | 0 .../{notes => beatmaps}/Live_0029.json | 0 .../{notes => beatmaps}/Live_0030.json | 0 .../{notes => beatmaps}/Live_0037.json | 0 .../{notes => beatmaps}/Live_0038.json | 0 .../{notes => beatmaps}/Live_0039.json | 0 .../{notes => beatmaps}/Live_0040.json | 0 .../{notes => beatmaps}/Live_0041.json | 0 .../{notes => beatmaps}/Live_0042.json | 0 .../{notes => beatmaps}/Live_0046.json | 0 .../{notes => beatmaps}/Live_0047.json | 0 .../{notes => beatmaps}/Live_0048.json | 0 .../{notes => beatmaps}/Live_0049.json | 0 .../{notes => beatmaps}/Live_0050.json | 0 .../{notes => beatmaps}/Live_0051.json | 0 .../{notes => beatmaps}/Live_0052.json | 0 .../{notes => beatmaps}/Live_0053.json | 0 .../{notes => beatmaps}/Live_0054.json | 0 .../{notes => beatmaps}/Live_0055.json | 0 .../{notes => beatmaps}/Live_0056.json | 0 .../{notes => beatmaps}/Live_0057.json | 0 .../{notes => beatmaps}/Live_0058.json | 0 .../{notes => beatmaps}/Live_0059.json | 0 .../{notes => beatmaps}/Live_0060.json | 0 .../{notes => beatmaps}/Live_0061.json | 0 .../{notes => beatmaps}/Live_0062.json | 0 .../{notes => beatmaps}/Live_0063.json | 0 .../{notes => beatmaps}/Live_0068.json | 0 .../{notes => beatmaps}/Live_0069.json | 0 .../{notes => beatmaps}/Live_0070.json | 0 .../{notes => beatmaps}/Live_0071.json | 0 .../{notes => beatmaps}/Live_0072.json | 0 .../{notes => beatmaps}/Live_0073.json | 0 .../{notes => beatmaps}/Live_0074.json | 0 .../{notes => beatmaps}/Live_0075.json | 0 .../{notes => beatmaps}/Live_0076.json | 0 .../{notes => beatmaps}/Live_0077.json | 0 .../{notes => beatmaps}/Live_0078.json | 0 .../{notes => beatmaps}/Live_0079.json | 0 .../{notes => beatmaps}/Live_0080.json | 0 .../{notes => beatmaps}/Live_0081.json | 0 .../{notes => beatmaps}/Live_0082.json | 0 .../{notes => beatmaps}/Live_0083.json | 0 .../{notes => beatmaps}/Live_0084.json | 0 .../{notes => beatmaps}/Live_0088.json | 0 .../{notes => beatmaps}/Live_0089.json | 0 .../{notes => beatmaps}/Live_0090.json | 0 .../{notes => beatmaps}/Live_0091.json | 0 .../{notes => beatmaps}/Live_0092.json | 0 .../{notes => beatmaps}/Live_0096.json | 0 .../{notes => beatmaps}/Live_0097.json | 0 .../{notes => beatmaps}/Live_0098.json | 0 .../{notes => beatmaps}/Live_0099.json | 0 .../{notes => beatmaps}/Live_0104.json | 0 .../{notes => beatmaps}/Live_0112.json | 0 .../{notes => beatmaps}/Live_0113.json | 0 .../{notes => beatmaps}/Live_0114.json | 0 .../{notes => beatmaps}/Live_0115.json | 0 .../{notes => beatmaps}/Live_0116.json | 0 .../{notes => beatmaps}/Live_0124.json | 0 .../{notes => beatmaps}/Live_0125.json | 0 .../{notes => beatmaps}/Live_0126.json | 0 .../{notes => beatmaps}/Live_0127.json | 0 .../{notes => beatmaps}/Live_0128.json | 0 .../{notes => beatmaps}/Live_0129.json | 0 .../{notes => beatmaps}/Live_0148.json | 0 .../{notes => beatmaps}/Live_0149.json | 0 .../{notes => beatmaps}/Live_0150.json | 0 .../{notes => beatmaps}/Live_0151.json | 0 .../{notes => beatmaps}/Live_0152.json | 0 .../{notes => beatmaps}/Live_0181.json | 0 .../{notes => beatmaps}/Live_0182.json | 0 .../{notes => beatmaps}/Live_0183.json | 0 .../{notes => beatmaps}/Live_0259.json | 0 .../{notes => beatmaps}/Live_0260.json | 0 .../{notes => beatmaps}/Live_0261.json | 0 .../{notes => beatmaps}/Live_0262.json | 0 .../{notes => beatmaps}/Live_0270.json | 0 .../{notes => beatmaps}/Live_0271.json | 0 .../{notes => beatmaps}/Live_0272.json | 0 .../{notes => beatmaps}/Live_0303.json | 0 .../{notes => beatmaps}/Live_0304.json | 0 .../{notes => beatmaps}/Live_0305.json | 0 .../{notes => beatmaps}/Live_0306.json | 0 .../{notes => beatmaps}/Live_0314.json | 0 .../{notes => beatmaps}/Live_0315.json | 0 .../{notes => beatmaps}/Live_0316.json | 0 .../{notes => beatmaps}/Live_0346.json | 0 .../{notes => beatmaps}/Live_0347.json | 0 .../{notes => beatmaps}/Live_0348.json | 0 .../{notes => beatmaps}/Live_0349.json | 0 .../{notes => beatmaps}/Live_0350.json | 0 .../{notes => beatmaps}/Live_0358.json | 0 .../{notes => beatmaps}/Live_0359.json | 0 .../{notes => beatmaps}/Live_0360.json | 0 .../{notes => beatmaps}/Live_0390.json | 0 .../{notes => beatmaps}/Live_0391.json | 0 .../{notes => beatmaps}/Live_0392.json | 0 .../{notes => beatmaps}/Live_0393.json | 0 .../{notes => beatmaps}/Live_0402.json | 0 .../{notes => beatmaps}/Live_0403.json | 0 .../{notes => beatmaps}/Live_0404.json | 0 .../{notes => beatmaps}/Live_0413.json | 0 .../{notes => beatmaps}/Live_0414.json | 0 .../{notes => beatmaps}/Live_0415.json | 0 .../{notes => beatmaps}/Live_0416.json | 0 .../{notes => beatmaps}/Live_0425.json | 0 .../{notes => beatmaps}/Live_0426.json | 0 .../{notes => beatmaps}/Live_0427.json | 0 .../{notes => beatmaps}/Live_0436.json | 0 .../{notes => beatmaps}/Live_0437.json | 0 .../{notes => beatmaps}/Live_0438.json | 0 .../{notes => beatmaps}/Live_0439.json | 0 .../{notes => beatmaps}/Live_0440.json | 0 .../{notes => beatmaps}/Live_0441.json | 0 .../{notes => beatmaps}/Live_0442.json | 0 .../{notes => beatmaps}/Live_0443.json | 0 .../{notes => beatmaps}/Live_0444.json | 0 .../{notes => beatmaps}/Live_0445.json | 0 .../{notes => beatmaps}/Live_0446.json | 0 .../{notes => beatmaps}/Live_0455.json | 0 .../{notes => beatmaps}/Live_0456.json | 0 .../{notes => beatmaps}/Live_0457.json | 0 .../{notes => beatmaps}/Live_0458.json | 0 .../{notes => beatmaps}/Live_0459.json | 0 .../{notes => beatmaps}/Live_0460.json | 0 .../{notes => beatmaps}/Live_0461.json | 0 .../{notes => beatmaps}/Live_0462.json | 0 .../{notes => beatmaps}/Live_0463.json | 0 .../{notes => beatmaps}/Live_0475.json | 0 .../{notes => beatmaps}/Live_0476.json | 0 .../{notes => beatmaps}/Live_0477.json | 0 .../{notes => beatmaps}/Live_0478.json | 0 .../{notes => beatmaps}/Live_0479.json | 0 .../{notes => beatmaps}/Live_0480.json | 0 .../{notes => beatmaps}/Live_0481.json | 0 .../{notes => beatmaps}/Live_0482.json | 0 .../{notes => beatmaps}/Live_0483.json | 0 .../{notes => beatmaps}/Live_0484.json | 0 .../{notes => beatmaps}/Live_0485.json | 0 .../{notes => beatmaps}/Live_0486.json | 0 .../{notes => beatmaps}/Live_0487.json | 0 .../{notes => beatmaps}/Live_0496.json | 0 .../{notes => beatmaps}/Live_0497.json | 0 .../{notes => beatmaps}/Live_0498.json | 0 .../{notes => beatmaps}/Live_0507.json | 0 .../{notes => beatmaps}/Live_0508.json | 0 .../{notes => beatmaps}/Live_0509.json | 0 .../{notes => beatmaps}/Live_0510.json | 0 .../{notes => beatmaps}/Live_0511.json | 0 .../{notes => beatmaps}/Live_0520.json | 0 .../{notes => beatmaps}/Live_0521.json | 0 .../{notes => beatmaps}/Live_0522.json | 0 .../{notes => beatmaps}/Live_0534.json | 0 .../{notes => beatmaps}/Live_0535.json | 0 .../{notes => beatmaps}/Live_0536.json | 0 .../{notes => beatmaps}/Live_0537.json | 0 .../{notes => beatmaps}/Live_0538.json | 0 .../{notes => beatmaps}/Live_0539.json | 0 .../{notes => beatmaps}/Live_0540.json | 0 .../{notes => beatmaps}/Live_0549.json | 0 .../{notes => beatmaps}/Live_0550.json | 0 .../{notes => beatmaps}/Live_0551.json | 0 .../{notes => beatmaps}/Live_0552.json | 0 .../{notes => beatmaps}/Live_0561.json | 0 .../{notes => beatmaps}/Live_0562.json | 0 .../{notes => beatmaps}/Live_0563.json | 0 .../{notes => beatmaps}/Live_0564.json | 0 .../{notes => beatmaps}/Live_0565.json | 0 .../{notes => beatmaps}/Live_0566.json | 0 .../{notes => beatmaps}/Live_0567.json | 0 .../{notes => beatmaps}/Live_0568.json | 0 .../{notes => beatmaps}/Live_0569.json | 0 .../{notes => beatmaps}/Live_0578.json | 0 .../{notes => beatmaps}/Live_0579.json | 0 .../{notes => beatmaps}/Live_0580.json | 0 .../{notes => beatmaps}/Live_0589.json | 0 .../{notes => beatmaps}/Live_0590.json | 0 .../{notes => beatmaps}/Live_0591.json | 0 .../{notes => beatmaps}/Live_0592.json | 0 .../{notes => beatmaps}/Live_0593.json | 0 .../{notes => beatmaps}/Live_0594.json | 0 .../{notes => beatmaps}/Live_0601.json | 0 .../{notes => beatmaps}/Live_0603.json | 0 .../{notes => beatmaps}/Live_0604.json | 0 .../{notes => beatmaps}/Live_0605.json | 0 .../{notes => beatmaps}/Live_0606.json | 0 .../{notes => beatmaps}/Live_0615.json | 0 .../{notes => beatmaps}/Live_0616.json | 0 .../{notes => beatmaps}/Live_0617.json | 0 .../{notes => beatmaps}/Live_0618.json | 0 .../{notes => beatmaps}/Live_0619.json | 0 .../{notes => beatmaps}/Live_0620.json | 0 .../{notes => beatmaps}/Live_0621.json | 0 .../{notes => beatmaps}/Live_0628.json | 0 .../{notes => beatmaps}/Live_0630.json | 0 .../{notes => beatmaps}/Live_0631.json | 0 .../{notes => beatmaps}/Live_0632.json | 0 .../{notes => beatmaps}/Live_0633.json | 0 .../{notes => beatmaps}/Live_0634.json | 0 .../{notes => beatmaps}/Live_0635.json | 0 .../{notes => beatmaps}/Live_0636.json | 0 .../{notes => beatmaps}/Live_0648.json | 0 .../{notes => beatmaps}/Live_0649.json | 0 .../{notes => beatmaps}/Live_0650.json | 0 .../{notes => beatmaps}/Live_0651.json | 0 .../{notes => beatmaps}/Live_0652.json | 0 .../{notes => beatmaps}/Live_0659.json | 0 .../{notes => beatmaps}/Live_0661.json | 0 .../{notes => beatmaps}/Live_0662.json | 0 .../{notes => beatmaps}/Live_0663.json | 0 .../{notes => beatmaps}/Live_0664.json | 0 .../{notes => beatmaps}/Live_0665.json | 0 .../{notes => beatmaps}/Live_0666.json | 0 .../{notes => beatmaps}/Live_0678.json | 0 .../{notes => beatmaps}/Live_0679.json | 0 .../{notes => beatmaps}/Live_0680.json | 0 .../{notes => beatmaps}/Live_0681.json | 0 .../{notes => beatmaps}/Live_0688.json | 0 .../{notes => beatmaps}/Live_0690.json | 0 .../{notes => beatmaps}/Live_0691.json | 0 .../{notes => beatmaps}/Live_0692.json | 0 .../{notes => beatmaps}/Live_0693.json | 0 .../{notes => beatmaps}/Live_0702.json | 0 .../{notes => beatmaps}/Live_0703.json | 0 .../{notes => beatmaps}/Live_0704.json | 0 .../{notes => beatmaps}/Live_0705.json | 0 .../{notes => beatmaps}/Live_0706.json | 0 .../{notes => beatmaps}/Live_0707.json | 0 .../{notes => beatmaps}/Live_0708.json | 0 .../{notes => beatmaps}/Live_0709.json | 0 .../{notes => beatmaps}/Live_0713.json | 0 .../{notes => beatmaps}/Live_0714.json | 0 .../{notes => beatmaps}/Live_0715.json | 0 .../{notes => beatmaps}/Live_0716.json | 0 .../{notes => beatmaps}/Live_0718.json | 0 .../{notes => beatmaps}/Live_0719.json | 0 .../{notes => beatmaps}/Live_0720.json | 0 .../{notes => beatmaps}/Live_0721.json | 0 .../{notes => beatmaps}/Live_0749.json | 0 .../{notes => beatmaps}/Live_0750.json | 0 .../{notes => beatmaps}/Live_0751.json | 0 .../{notes => beatmaps}/Live_0752.json | 0 .../{notes => beatmaps}/Live_0753.json | 0 .../{notes => beatmaps}/Live_0754.json | 0 .../{notes => beatmaps}/Live_0755.json | 0 .../{notes => beatmaps}/Live_0756.json | 0 .../{notes => beatmaps}/Live_0763.json | 0 .../{notes => beatmaps}/Live_0765.json | 0 .../{notes => beatmaps}/Live_0766.json | 0 .../{notes => beatmaps}/Live_0767.json | 0 .../{notes => beatmaps}/Live_0768.json | 0 .../{notes => beatmaps}/Live_0791.json | 0 .../{notes => beatmaps}/Live_0792.json | 0 .../{notes => beatmaps}/Live_0793.json | 0 .../{notes => beatmaps}/Live_0794.json | 0 .../{notes => beatmaps}/Live_0797.json | 0 .../{notes => beatmaps}/Live_0798.json | 0 .../{notes => beatmaps}/Live_0799.json | 0 .../{notes => beatmaps}/Live_0803.json | 0 .../{notes => beatmaps}/Live_0804.json | 0 .../{notes => beatmaps}/Live_0805.json | 0 .../{notes => beatmaps}/Live_0806.json | 0 .../{notes => beatmaps}/Live_0810.json | 0 .../{notes => beatmaps}/Live_0811.json | 0 .../{notes => beatmaps}/Live_0812.json | 0 .../{notes => beatmaps}/Live_0813.json | 0 .../{notes => beatmaps}/Live_0814.json | 0 .../{notes => beatmaps}/Live_0831.json | 0 .../{notes => beatmaps}/Live_0832.json | 0 .../{notes => beatmaps}/Live_0833.json | 0 .../{notes => beatmaps}/Live_0834.json | 0 .../{notes => beatmaps}/Live_0835.json | 0 .../{notes => beatmaps}/Live_0836.json | 0 .../{notes => beatmaps}/Live_0837.json | 0 .../{notes => beatmaps}/Live_0838.json | 0 .../{notes => beatmaps}/Live_0842.json | 0 .../{notes => beatmaps}/Live_0843.json | 0 .../{notes => beatmaps}/Live_0844.json | 0 .../{notes => beatmaps}/Live_0845.json | 0 .../{notes => beatmaps}/Live_0849.json | 0 .../{notes => beatmaps}/Live_0850.json | 0 .../{notes => beatmaps}/Live_0851.json | 0 .../{notes => beatmaps}/Live_0852.json | 0 .../{notes => beatmaps}/Live_0866.json | 0 .../{notes => beatmaps}/Live_0867.json | 0 .../{notes => beatmaps}/Live_0868.json | 0 .../{notes => beatmaps}/Live_0869.json | 0 .../{notes => beatmaps}/Live_0871.json | 0 .../{notes => beatmaps}/Live_0872.json | 0 .../{notes => beatmaps}/Live_0873.json | 0 .../{notes => beatmaps}/Live_0874.json | 0 .../{notes => beatmaps}/Live_s0361.json | 0 .../{notes => beatmaps}/Live_s0362.json | 0 .../{notes => beatmaps}/Live_s0363.json | 0 .../{notes => beatmaps}/Live_s0364.json | 0 .../{notes => beatmaps}/Live_s0365.json | 0 .../{notes => beatmaps}/Live_s0371.json | 0 .../{notes => beatmaps}/Live_s0372.json | 0 .../{notes => beatmaps}/Live_s0373.json | 0 .../{notes => beatmaps}/Live_s0374.json | 0 .../{notes => beatmaps}/Live_s0375.json | 0 .../{notes => beatmaps}/Live_s0376.json | 0 .../{notes => beatmaps}/Live_s0377.json | 0 .../{notes => beatmaps}/Live_s0378.json | 0 .../{notes => beatmaps}/Live_s0385.json | 0 .../{notes => beatmaps}/Live_s0386.json | 0 .../{notes => beatmaps}/Live_s0387.json | 0 .../{notes => beatmaps}/Live_s0388.json | 0 .../{notes => beatmaps}/Live_s0389.json | 0 .../{notes => beatmaps}/Live_s0390.json | 0 .../{notes => beatmaps}/Live_s0391.json | 0 .../{notes => beatmaps}/Live_s0392.json | 0 .../{notes => beatmaps}/Live_s0393.json | 0 .../{notes => beatmaps}/Live_s0394.json | 0 .../{notes => beatmaps}/Live_s0395.json | 0 .../{notes => beatmaps}/Live_s0396.json | 0 .../{notes => beatmaps}/Live_s0397.json | 0 .../{notes => beatmaps}/Live_s0398.json | 0 .../{notes => beatmaps}/Live_s0399.json | 0 .../{notes => beatmaps}/Live_s0400.json | 0 .../{notes => beatmaps}/Live_s0401.json | 0 .../{notes => beatmaps}/Live_s0402.json | 0 .../{notes => beatmaps}/Live_s0405.json | 0 .../{notes => beatmaps}/Live_s0406.json | 0 .../{notes => beatmaps}/Live_s0407.json | 0 .../{notes => beatmaps}/Live_s0408.json | 0 .../{notes => beatmaps}/Live_s0409.json | 0 .../{notes => beatmaps}/Live_s0410.json | 0 .../{notes => beatmaps}/Live_s0411.json | 0 .../{notes => beatmaps}/Live_s0412.json | 0 .../{notes => beatmaps}/Live_s0413.json | 0 .../{notes => beatmaps}/Live_s0414.json | 0 .../{notes => beatmaps}/Live_s0415.json | 0 .../{notes => beatmaps}/Live_s0416.json | 0 .../{notes => beatmaps}/Live_s0417.json | 0 .../{notes => beatmaps}/Live_s0418.json | 0 .../{notes => beatmaps}/Live_s0419.json | 0 .../{notes => beatmaps}/Live_s0420.json | 0 .../{notes => beatmaps}/Live_s0421.json | 0 .../{notes => beatmaps}/Live_s0432.json | 0 .../{notes => beatmaps}/Live_s0433.json | 0 .../{notes => beatmaps}/Live_s0434.json | 0 .../{notes => beatmaps}/Live_s0435.json | 0 .../{notes => beatmaps}/Live_s0436.json | 0 .../{notes => beatmaps}/Live_s0437.json | 0 .../{notes => beatmaps}/Live_s0438.json | 0 .../{notes => beatmaps}/Live_s0439.json | 0 .../{notes => beatmaps}/Live_s0440.json | 0 .../{notes => beatmaps}/Live_s0441.json | 0 .../{notes => beatmaps}/Live_s0442.json | 0 .../{notes => beatmaps}/Live_s0443.json | 0 .../{notes => beatmaps}/Live_s0444.json | 0 .../{notes => beatmaps}/Live_s0445.json | 0 .../{notes => beatmaps}/Live_s0446.json | 0 .../{notes => beatmaps}/Live_s0453.json | 0 .../{notes => beatmaps}/Live_s0454.json | 0 .../{notes => beatmaps}/Live_s0455.json | 0 .../{notes => beatmaps}/Live_s0456.json | 0 .../{notes => beatmaps}/Live_s0457.json | 0 .../{notes => beatmaps}/Live_s0458.json | 0 .../{notes => beatmaps}/Live_s0459.json | 0 .../{notes => beatmaps}/Live_s0460.json | 0 .../{notes => beatmaps}/Live_s0461.json | 0 .../{notes => beatmaps}/Live_s0462.json | 0 .../{notes => beatmaps}/Live_s0463.json | 0 .../{notes => beatmaps}/Live_s0464.json | 0 .../{notes => beatmaps}/Live_s0465.json | 0 .../{notes => beatmaps}/Live_s0466.json | 0 .../{notes => beatmaps}/Live_s0467.json | 0 .../{notes => beatmaps}/Live_s0468.json | 0 .../{notes => beatmaps}/Live_s0469.json | 0 .../{notes => beatmaps}/Live_s0470.json | 0 .../{notes => beatmaps}/Live_s0471.json | 0 .../{notes => beatmaps}/Live_s0472.json | 0 .../{notes => beatmaps}/Live_s0473.json | 0 .../{notes => beatmaps}/Live_s0482.json | 0 .../{notes => beatmaps}/Live_s0483.json | 0 .../{notes => beatmaps}/Live_s0484.json | 0 .../{notes => beatmaps}/Live_s0485.json | 0 .../{notes => beatmaps}/Live_s0486.json | 0 .../{notes => beatmaps}/Live_s0487.json | 0 .../{notes => beatmaps}/Live_s0488.json | 0 .../{notes => beatmaps}/Live_s0489.json | 0 .../{notes => beatmaps}/Live_s0490.json | 0 .../{notes => beatmaps}/Live_s0491.json | 0 .../{notes => beatmaps}/Live_s0492.json | 0 .../{notes => beatmaps}/Live_s0493.json | 0 .../{notes => beatmaps}/Live_s0494.json | 0 .../{notes => beatmaps}/Live_s0495.json | 0 .../{notes => beatmaps}/Live_s0496.json | 0 .../{notes => beatmaps}/Live_s0497.json | 0 .../{notes => beatmaps}/Live_s0498.json | 0 .../{notes => beatmaps}/Live_s0499.json | 0 .../{notes => beatmaps}/Live_s0500.json | 0 .../{notes => beatmaps}/Live_s0501.json | 0 .../{notes => beatmaps}/Live_s0502.json | 0 .../{notes => beatmaps}/Live_s0503.json | 0 .../{notes => beatmaps}/Live_s0504.json | 0 .../{notes => beatmaps}/Live_s0505.json | 0 .../{notes => beatmaps}/Live_s0506.json | 0 .../{notes => beatmaps}/Live_s0507.json | 0 .../{notes => beatmaps}/Live_s0508.json | 0 .../{notes => beatmaps}/Live_s0509.json | 0 .../{notes => beatmaps}/Live_s0510.json | 0 .../{notes => beatmaps}/Live_s0511.json | 0 .../{notes => beatmaps}/Live_s0512.json | 0 .../{notes => beatmaps}/Live_s0513.json | 0 .../{notes => beatmaps}/Live_s0514.json | 0 .../{notes => beatmaps}/Live_s0515.json | 0 .../{notes => beatmaps}/Live_s0516.json | 0 .../{notes => beatmaps}/Live_s0517.json | 0 .../{notes => beatmaps}/Live_s0518.json | 0 .../{notes => beatmaps}/Live_s0519.json | 0 .../{notes => beatmaps}/Live_s0520.json | 0 .../{notes => beatmaps}/Live_s0521.json | 0 .../{notes => beatmaps}/Live_s0522.json | 0 .../{notes => beatmaps}/Live_s0523.json | 0 .../{notes => beatmaps}/Live_s0524.json | 0 .../{notes => beatmaps}/Live_s0525.json | 0 .../{notes => beatmaps}/Live_s0526.json | 0 .../{notes => beatmaps}/Live_s0527.json | 0 .../{notes => beatmaps}/Live_s0528.json | 0 .../{notes => beatmaps}/Live_s0529.json | 0 .../{notes => beatmaps}/Live_s0530.json | 0 .../{notes => beatmaps}/Live_s0531.json | 0 .../{notes => beatmaps}/Live_s0532.json | 0 .../{notes => beatmaps}/Live_s0533.json | 0 .../{notes => beatmaps}/Live_s0534.json | 0 .../{notes => beatmaps}/Live_s0535.json | 0 .../{notes => beatmaps}/Live_s0536.json | 0 .../{notes => beatmaps}/Live_s0537.json | 0 .../{notes => beatmaps}/Live_s0538.json | 0 .../{notes => beatmaps}/Live_s0539.json | 0 .../{notes => beatmaps}/Live_s0551.json | 0 .../{notes => beatmaps}/Live_s0552.json | 0 .../{notes => beatmaps}/Live_s0553.json | 0 .../{notes => beatmaps}/Live_s0554.json | 0 .../{notes => beatmaps}/Live_s0555.json | 0 .../{notes => beatmaps}/Live_s0556.json | 0 .../{notes => beatmaps}/Live_s0557.json | 0 .../{notes => beatmaps}/Live_s0558.json | 0 .../{notes => beatmaps}/Live_s0559.json | 0 .../{notes => beatmaps}/Live_s0560.json | 0 .../{notes => beatmaps}/Live_s0561.json | 0 .../{notes => beatmaps}/Live_s0562.json | 0 .../{notes => beatmaps}/Live_s0563.json | 0 .../{notes => beatmaps}/Live_s0564.json | 0 .../{notes => beatmaps}/Live_s0565.json | 0 .../{notes => beatmaps}/Live_s0566.json | 0 .../{notes => beatmaps}/Live_s0567.json | 0 .../{notes => beatmaps}/Live_s0568.json | 0 .../{notes => beatmaps}/Live_s0569.json | 0 .../{notes => beatmaps}/Live_s0570.json | 0 .../{notes => beatmaps}/Live_s0571.json | 0 .../{notes => beatmaps}/Live_s0572.json | 0 .../{notes => beatmaps}/Live_s0573.json | 0 .../{notes => beatmaps}/Live_s0574.json | 0 .../{notes => beatmaps}/Live_s0575.json | 0 .../{notes => beatmaps}/Live_s0576.json | 0 .../{notes => beatmaps}/Live_s0577.json | 0 .../{notes => beatmaps}/Live_s0578.json | 0 .../{notes => beatmaps}/Live_s0579.json | 0 .../{notes => beatmaps}/Live_s0580.json | 0 .../{notes => beatmaps}/Live_s0581.json | 0 .../{notes => beatmaps}/Live_s0582.json | 0 .../{notes => beatmaps}/Live_s0583.json | 0 .../{notes => beatmaps}/Live_s0584.json | 0 .../{notes => beatmaps}/Live_s0585.json | 0 .../{notes => beatmaps}/Live_s0586.json | 0 .../{notes => beatmaps}/Live_s0587.json | 0 .../{notes => beatmaps}/Live_s0588.json | 0 .../{notes => beatmaps}/Live_s0589.json | 0 .../{notes => beatmaps}/Live_s0596.json | 0 .../{notes => beatmaps}/Live_s0597.json | 0 .../{notes => beatmaps}/Live_s0598.json | 0 .../{notes => beatmaps}/Live_s0599.json | 0 .../{notes => beatmaps}/Live_s0600.json | 0 .../{notes => beatmaps}/Live_s0601.json | 0 .../{notes => beatmaps}/Live_s0602.json | 0 .../{notes => beatmaps}/Live_s0603.json | 0 .../{notes => beatmaps}/Live_s0604.json | 0 .../{notes => beatmaps}/Live_s0605.json | 0 .../{notes => beatmaps}/Live_s0606.json | 0 .../{notes => beatmaps}/Live_s0607.json | 0 .../{notes => beatmaps}/Live_s0608.json | 0 .../{notes => beatmaps}/Live_s0609.json | 0 .../{notes => beatmaps}/Live_s0610.json | 0 .../{notes => beatmaps}/Live_s0611.json | 0 .../{notes => beatmaps}/Live_s0612.json | 0 .../{notes => beatmaps}/Live_s0613.json | 0 .../{notes => beatmaps}/Live_s0614.json | 0 .../{notes => beatmaps}/Live_s0615.json | 0 .../{notes => beatmaps}/Live_s0616.json | 0 .../{notes => beatmaps}/Live_s0617.json | 0 .../{notes => beatmaps}/Live_s0618.json | 0 .../{notes => beatmaps}/Live_s0619.json | 0 .../{notes => beatmaps}/Live_s0620.json | 0 .../{notes => beatmaps}/Live_s0621.json | 0 .../{notes => beatmaps}/Live_s0622.json | 0 .../{notes => beatmaps}/Live_s0623.json | 0 .../{notes => beatmaps}/Live_s0624.json | 0 .../{notes => beatmaps}/Live_s0625.json | 0 .../{notes => beatmaps}/Live_s0626.json | 0 .../{notes => beatmaps}/Live_s0627.json | 0 .../{notes => beatmaps}/Live_s0628.json | 0 .../{notes => beatmaps}/Live_s0629.json | 0 .../{notes => beatmaps}/Live_s0630.json | 0 .../{notes => beatmaps}/Live_s0631.json | 0 .../{notes => beatmaps}/Live_s0632.json | 0 .../{notes => beatmaps}/Live_s0633.json | 0 .../{notes => beatmaps}/Live_s0634.json | 0 .../{notes => beatmaps}/Live_s0641.json | 0 .../{notes => beatmaps}/Live_s0642.json | 0 .../{notes => beatmaps}/Live_s0643.json | 0 .../{notes => beatmaps}/Live_s0644.json | 0 .../{notes => beatmaps}/Live_s0645.json | 0 .../{notes => beatmaps}/Live_s0646.json | 0 .../{notes => beatmaps}/Live_s0647.json | 0 .../{notes => beatmaps}/Live_s0648.json | 0 .../{notes => beatmaps}/Live_s0649.json | 0 .../{notes => beatmaps}/Live_s0650.json | 0 .../{notes => beatmaps}/Live_s0651.json | 0 .../{notes => beatmaps}/Live_s0652.json | 0 .../{notes => beatmaps}/Live_s0653.json | 0 .../{notes => beatmaps}/Live_s0654.json | 0 .../{notes => beatmaps}/Live_s0655.json | 0 .../{notes => beatmaps}/Live_s0656.json | 0 .../{notes => beatmaps}/Live_s0657.json | 0 .../{notes => beatmaps}/Live_s0658.json | 0 .../{notes => beatmaps}/Live_s0659.json | 0 .../{notes => beatmaps}/Live_s0660.json | 0 .../{notes => beatmaps}/Live_s0661.json | 0 .../{notes => beatmaps}/Live_s0662.json | 0 .../{notes => beatmaps}/Live_s0663.json | 0 .../{notes => beatmaps}/Live_s0664.json | 0 .../{notes => beatmaps}/Live_s0665.json | 0 .../{notes => beatmaps}/Live_s0666.json | 0 .../{notes => beatmaps}/Live_s0667.json | 0 .../{notes => beatmaps}/Live_s0668.json | 0 .../{notes => beatmaps}/Live_s0669.json | 0 .../{notes => beatmaps}/Live_s0670.json | 0 .../{notes => beatmaps}/Live_s0671.json | 0 .../{notes => beatmaps}/Live_s0672.json | 0 .../{notes => beatmaps}/Live_s0673.json | 0 .../{notes => beatmaps}/Live_s0677.json | 0 .../{notes => beatmaps}/Live_s0678.json | 0 .../{notes => beatmaps}/Live_s0679.json | 0 .../{notes => beatmaps}/Live_s0680.json | 0 .../{notes => beatmaps}/Live_s0681.json | 0 .../{notes => beatmaps}/Live_s0682.json | 0 .../{notes => beatmaps}/Live_s0683.json | 0 .../{notes => beatmaps}/Live_s0684.json | 0 .../{notes => beatmaps}/Live_s0685.json | 0 .../{notes => beatmaps}/Live_s0686.json | 0 .../{notes => beatmaps}/Live_s0687.json | 0 .../{notes => beatmaps}/Live_s0688.json | 0 .../{notes => beatmaps}/Live_s0689.json | 0 .../{notes => beatmaps}/Live_s0690.json | 0 .../{notes => beatmaps}/Live_s0691.json | 0 .../{notes => beatmaps}/Live_s0692.json | 0 .../{notes => beatmaps}/Live_s0693.json | 0 .../{notes => beatmaps}/Live_s0694.json | 0 .../{notes => beatmaps}/Live_s0695.json | 0 .../{notes => beatmaps}/Live_s0696.json | 0 .../{notes => beatmaps}/Live_s0697.json | 0 .../{notes => beatmaps}/Live_s0698.json | 0 .../{notes => beatmaps}/Live_s0699.json | 0 .../{notes => beatmaps}/Live_s0700.json | 0 .../{notes => beatmaps}/Live_s0703.json | 0 .../{notes => beatmaps}/Live_s0704.json | 0 .../{notes => beatmaps}/Live_s0705.json | 0 .../{notes => beatmaps}/Live_s0706.json | 0 .../{notes => beatmaps}/Live_s0707.json | 0 .../{notes => beatmaps}/Live_s0708.json | 0 .../{notes => beatmaps}/Live_s0709.json | 0 .../{notes => beatmaps}/Live_s0710.json | 0 .../{notes => beatmaps}/Live_s0711.json | 0 .../{notes => beatmaps}/Live_s0712.json | 0 .../{notes => beatmaps}/Live_s0713.json | 0 .../{notes => beatmaps}/Live_s0714.json | 0 .../{notes => beatmaps}/Live_s0715.json | 0 .../{notes => beatmaps}/Live_s0716.json | 0 .../{notes => beatmaps}/Live_s0717.json | 0 .../{notes => beatmaps}/Live_s0718.json | 0 .../{notes => beatmaps}/Live_s0719.json | 0 .../{notes => beatmaps}/Live_s0720.json | 0 .../{notes => beatmaps}/Live_s0721.json | 0 .../{notes => beatmaps}/Live_s0722.json | 0 .../{notes => beatmaps}/Live_s0725.json | 0 .../{notes => beatmaps}/Live_s0726.json | 0 .../{notes => beatmaps}/Live_s0727.json | 0 .../{notes => beatmaps}/Live_s0728.json | 0 .../{notes => beatmaps}/Live_s0729.json | 0 .../{notes => beatmaps}/Live_s0730.json | 0 .../{notes => beatmaps}/Live_s0731.json | 0 .../{notes => beatmaps}/Live_s0732.json | 0 .../{notes => beatmaps}/Live_s0733.json | 0 .../{notes => beatmaps}/Live_s0734.json | 0 .../{notes => beatmaps}/Live_s0735.json | 0 .../{notes => beatmaps}/Live_s0736.json | 0 .../{notes => beatmaps}/Live_s0737.json | 0 .../{notes => beatmaps}/Live_s0738.json | 0 .../{notes => beatmaps}/Live_s0739.json | 0 .../{notes => beatmaps}/Live_s0740.json | 0 .../{notes => beatmaps}/Live_s0741.json | 0 .../{notes => beatmaps}/Live_s0742.json | 0 .../{notes => beatmaps}/Live_s0743.json | 0 .../{notes => beatmaps}/Live_s0744.json | 0 .../{notes => beatmaps}/Live_s0745.json | 0 .../{notes => beatmaps}/Live_s0746.json | 0 .../{notes => beatmaps}/Live_s0747.json | 0 .../{notes => beatmaps}/Live_s0748.json | 0 .../{notes => beatmaps}/Live_s0749.json | 0 .../{notes => beatmaps}/Live_s0750.json | 0 .../{notes => beatmaps}/Live_s0751.json | 0 .../{notes => beatmaps}/Live_s0764.json | 0 .../{notes => beatmaps}/Live_s0765.json | 0 .../{notes => beatmaps}/Live_s0766.json | 0 .../{notes => beatmaps}/Live_s0767.json | 0 .../{notes => beatmaps}/Live_s0768.json | 0 .../{notes => beatmaps}/Live_s0769.json | 0 .../{notes => beatmaps}/Live_s0770.json | 0 .../{notes => beatmaps}/Live_s0771.json | 0 .../{notes => beatmaps}/Live_s0772.json | 0 .../{notes => beatmaps}/Live_s0773.json | 0 .../{notes => beatmaps}/Live_s0774.json | 0 .../{notes => beatmaps}/Live_s0775.json | 0 .../{notes => beatmaps}/Live_s0776.json | 0 .../{notes => beatmaps}/Live_s0777.json | 0 .../{notes => beatmaps}/Live_s0778.json | 0 .../{notes => beatmaps}/Live_s0779.json | 0 .../{notes => beatmaps}/Live_s0780.json | 0 .../{notes => beatmaps}/Live_s0781.json | 0 .../{notes => beatmaps}/Live_s0782.json | 0 .../{notes => beatmaps}/Live_s0783.json | 0 .../{notes => beatmaps}/Live_s0784.json | 0 .../{notes => beatmaps}/Live_s0785.json | 0 .../{notes => beatmaps}/Live_s0786.json | 0 .../{notes => beatmaps}/Live_s0787.json | 0 .../{notes => beatmaps}/Live_s0788.json | 0 .../{notes => beatmaps}/Live_s0789.json | 0 .../{notes => beatmaps}/Live_s0790.json | 0 .../{notes => beatmaps}/Live_s0791.json | 0 .../{notes => beatmaps}/Live_s0792.json | 0 .../{notes => beatmaps}/Live_s0793.json | 0 .../{notes => beatmaps}/Live_s0794.json | 0 .../{notes => beatmaps}/Live_s0795.json | 0 .../{notes => beatmaps}/Live_s0802.json | 0 .../{notes => beatmaps}/Live_s0803.json | 0 .../{notes => beatmaps}/Live_s0804.json | 0 .../{notes => beatmaps}/Live_s0805.json | 0 .../{notes => beatmaps}/Live_s0806.json | 0 .../{notes => beatmaps}/Live_s0807.json | 0 .../{notes => beatmaps}/Live_s0808.json | 0 .../{notes => beatmaps}/Live_s0809.json | 0 .../{notes => beatmaps}/Live_s0810.json | 0 .../{notes => beatmaps}/Live_s0811.json | 0 .../{notes => beatmaps}/Live_s0812.json | 0 .../{notes => beatmaps}/Live_s0813.json | 0 .../{notes => beatmaps}/Live_s0814.json | 0 .../{notes => beatmaps}/Live_s0815.json | 0 .../{notes => beatmaps}/Live_s0816.json | 0 .../{notes => beatmaps}/Live_s0817.json | 0 .../{notes => beatmaps}/Live_s0818.json | 0 .../{notes => beatmaps}/Live_s0819.json | 0 .../{notes => beatmaps}/Live_s0820.json | 0 .../{notes => beatmaps}/Live_s0821.json | 0 .../{notes => beatmaps}/Live_s0822.json | 0 .../{notes => beatmaps}/Live_s0823.json | 0 .../{notes => beatmaps}/Live_s0824.json | 0 .../{notes => beatmaps}/Live_s0825.json | 0 .../{notes => beatmaps}/Live_s0826.json | 0 .../{notes => beatmaps}/Live_s0827.json | 0 .../{notes => beatmaps}/Live_s0828.json | 0 .../{notes => beatmaps}/Live_s0829.json | 0 .../{notes => beatmaps}/Live_s0830.json | 0 .../{notes => beatmaps}/Live_s0831.json | 0 .../{notes => beatmaps}/Live_s0832.json | 0 .../{notes => beatmaps}/Live_s0833.json | 0 .../{notes => beatmaps}/Live_s0834.json | 0 .../{notes => beatmaps}/Live_s0835.json | 0 .../{notes => beatmaps}/Live_s0836.json | 0 .../{notes => beatmaps}/Live_s0837.json | 0 .../{notes => beatmaps}/Live_s0838.json | 0 .../{notes => beatmaps}/Live_s0839.json | 0 .../{notes => beatmaps}/Live_s0840.json | 0 .../{notes => beatmaps}/Live_s0841.json | 0 .../{notes => beatmaps}/Live_s0842.json | 0 .../{notes => beatmaps}/Live_s0843.json | 0 .../{notes => beatmaps}/Live_s0844.json | 0 .../{notes => beatmaps}/Live_s0845.json | 0 .../{notes => beatmaps}/Live_s0846.json | 0 .../{notes => beatmaps}/Live_s0847.json | 0 .../{notes => beatmaps}/Live_s0848.json | 0 .../{notes => beatmaps}/Live_s0849.json | 0 .../{notes => beatmaps}/Live_s0850.json | 0 .../{notes => beatmaps}/Live_s0851.json | 0 .../{notes => beatmaps}/Live_s0852.json | 0 .../{notes => beatmaps}/Live_s0853.json | 0 .../{notes => beatmaps}/Live_s0854.json | 0 .../{notes => beatmaps}/Live_s0855.json | 0 .../{notes => beatmaps}/Live_s0856.json | 0 .../{notes => beatmaps}/Live_s0857.json | 0 .../{notes => beatmaps}/Live_s0858.json | 0 .../{notes => beatmaps}/Live_s0859.json | 0 .../{notes => beatmaps}/Live_s0860.json | 0 .../{notes => beatmaps}/Live_s0863.json | 0 .../{notes => beatmaps}/Live_s0864.json | 0 .../{notes => beatmaps}/Live_s0865.json | 0 .../{notes => beatmaps}/Live_s0866.json | 0 .../{notes => beatmaps}/Live_s0867.json | 0 .../{notes => beatmaps}/Live_s0868.json | 0 .../{notes => beatmaps}/Live_s0869.json | 0 .../{notes => beatmaps}/Live_s0870.json | 0 .../{notes => beatmaps}/Live_s0871.json | 0 .../{notes => beatmaps}/Live_s0872.json | 0 .../{notes => beatmaps}/Live_s0873.json | 0 .../{notes => beatmaps}/Live_s0874.json | 0 .../{notes => beatmaps}/Live_s0875.json | 0 .../{notes => beatmaps}/Live_s0876.json | 0 .../{notes => beatmaps}/Live_s0877.json | 0 .../{notes => beatmaps}/Live_s0878.json | 0 .../{notes => beatmaps}/Live_s0879.json | 0 .../{notes => beatmaps}/Live_s0880.json | 0 .../{notes => beatmaps}/Live_s0881.json | 0 .../{notes => beatmaps}/Live_s0882.json | 0 .../{notes => beatmaps}/Live_s0883.json | 0 .../{notes => beatmaps}/Live_s0884.json | 0 .../{notes => beatmaps}/Live_s0885.json | 0 .../{notes => beatmaps}/Live_s0886.json | 0 .../{notes => beatmaps}/Live_s0887.json | 0 .../{notes => beatmaps}/Live_s0888.json | 0 .../{notes => beatmaps}/Live_s0889.json | 0 .../{notes => beatmaps}/Live_s0890.json | 0 .../{notes => beatmaps}/Live_s0891.json | 0 .../{notes => beatmaps}/Live_s0892.json | 0 .../{notes => beatmaps}/Live_s0893.json | 0 .../{notes => beatmaps}/Live_s0894.json | 0 .../{notes => beatmaps}/Live_s0895.json | 0 .../{notes => beatmaps}/Live_s0896.json | 0 .../{notes => beatmaps}/Live_s0897.json | 0 .../{notes => beatmaps}/Live_s0898.json | 0 .../{notes => beatmaps}/Live_s0899.json | 0 .../{notes => beatmaps}/Live_s0900.json | 0 .../{notes => beatmaps}/Live_s0901.json | 0 .../{notes => beatmaps}/Live_s0902.json | 0 .../{notes => beatmaps}/Live_s0903.json | 0 .../{notes => beatmaps}/Live_s0904.json | 0 .../{notes => beatmaps}/Live_s0905.json | 0 .../{notes => beatmaps}/Live_s0906.json | 0 .../{notes => beatmaps}/Live_s0907.json | 0 .../{notes => beatmaps}/Live_s0908.json | 0 .../{notes => beatmaps}/Live_s0909.json | 0 .../{notes => beatmaps}/Live_s0910.json | 0 .../{notes => beatmaps}/Live_s0911.json | 0 .../{notes => beatmaps}/Live_s0912.json | 0 .../{notes => beatmaps}/Live_s0913.json | 0 .../{notes => beatmaps}/Live_s0914.json | 0 .../{notes => beatmaps}/Live_s0915.json | 0 .../{notes => beatmaps}/Live_s0916.json | 0 .../{notes => beatmaps}/Live_s0917.json | 0 .../{notes => beatmaps}/Live_s0918.json | 0 .../{notes => beatmaps}/Live_s0919.json | 0 .../{notes => beatmaps}/Live_s0920.json | 0 .../{notes => beatmaps}/Live_s0921.json | 0 .../{notes => beatmaps}/Live_s0922.json | 0 .../{notes => beatmaps}/Live_s0923.json | 0 .../{notes => beatmaps}/Live_s0924.json | 0 .../{notes => beatmaps}/Live_s0925.json | 0 .../{notes => beatmaps}/Live_s0926.json | 0 .../{notes => beatmaps}/Live_s0927.json | 0 .../{notes => beatmaps}/Live_s0928.json | 0 .../{notes => beatmaps}/Live_s0929.json | 0 .../{notes => beatmaps}/Live_s0930.json | 0 .../{notes => beatmaps}/Live_s0931.json | 0 .../{notes => beatmaps}/Live_s0932.json | 0 .../{notes => beatmaps}/Live_s0933.json | 0 .../{notes => beatmaps}/Live_s0934.json | 0 .../{notes => beatmaps}/Live_s0935.json | 0 .../{notes => beatmaps}/Live_s0936.json | 0 .../{notes => beatmaps}/Live_s0937.json | 0 .../{notes => beatmaps}/Live_s0938.json | 0 .../{notes => beatmaps}/Live_s0939.json | 0 .../{notes => beatmaps}/Live_s0940.json | 0 .../{notes => beatmaps}/Live_s0941.json | 0 .../{notes => beatmaps}/Live_s0942.json | 0 .../{notes => beatmaps}/Live_s0943.json | 0 .../{notes => beatmaps}/Live_s0944.json | 0 .../{notes => beatmaps}/Live_s0945.json | 0 .../{notes => beatmaps}/Live_s0946.json | 0 .../{notes => beatmaps}/Live_s0947.json | 0 .../{notes => beatmaps}/Live_s0948.json | 0 .../{notes => beatmaps}/Live_s0949.json | 0 .../{notes => beatmaps}/Live_s0950.json | 0 .../{notes => beatmaps}/Live_s0951.json | 0 .../{notes => beatmaps}/Live_s0952.json | 0 .../{notes => beatmaps}/Live_s0953.json | 0 .../{notes => beatmaps}/Live_s0954.json | 0 .../{notes => beatmaps}/Live_s0955.json | 0 .../{notes => beatmaps}/Live_s0956.json | 0 .../{notes => beatmaps}/Live_s0957.json | 0 .../{notes => beatmaps}/Live_s0958.json | 0 .../{notes => beatmaps}/Live_s0959.json | 0 .../{notes => beatmaps}/Live_s0960.json | 0 .../{notes => beatmaps}/Live_s0961.json | 0 .../{notes => beatmaps}/Live_s0962.json | 0 .../{notes => beatmaps}/Live_s0963.json | 0 .../{notes => beatmaps}/Live_s0964.json | 0 .../{notes => beatmaps}/Live_s0965.json | 0 .../{notes => beatmaps}/Live_s0966.json | 0 .../{notes => beatmaps}/Live_s0967.json | 0 .../{notes => beatmaps}/Live_s0968.json | 0 .../{notes => beatmaps}/Live_s0969.json | 0 .../{notes => beatmaps}/Live_s0970.json | 0 .../{notes => beatmaps}/Live_s0971.json | 0 .../{notes => beatmaps}/Live_s0972.json | 0 .../{notes => beatmaps}/Live_s0973.json | 0 .../{notes => beatmaps}/Live_s0974.json | 0 .../{notes => beatmaps}/Live_s0975.json | 0 .../{notes => beatmaps}/Live_s0976.json | 0 .../{notes => beatmaps}/Live_s0977.json | 0 .../{notes => beatmaps}/Live_s0978.json | 0 .../{notes => beatmaps}/Live_s0979.json | 0 .../{notes => beatmaps}/Live_s0980.json | 0 .../{notes => beatmaps}/Live_s0981.json | 0 .../{notes => beatmaps}/Live_s0982.json | 0 .../{notes => beatmaps}/Live_s0983.json | 0 .../{notes => beatmaps}/Live_s0984.json | 0 .../{notes => beatmaps}/Live_s0985.json | 0 .../{notes => beatmaps}/Live_s0986.json | 0 .../{notes => beatmaps}/Live_s0987.json | 0 .../{notes => beatmaps}/Live_s0988.json | 0 .../{notes => beatmaps}/Live_s0989.json | 0 .../{notes => beatmaps}/Live_s0990.json | 0 .../{notes => beatmaps}/Live_s0991.json | 0 .../{notes => beatmaps}/Live_s0992.json | 0 .../{notes => beatmaps}/Live_s0993.json | 0 .../{notes => beatmaps}/Live_s0994.json | 0 .../{notes => beatmaps}/Live_s0995.json | 0 .../{notes => beatmaps}/Live_s0996.json | 0 .../{notes => beatmaps}/Live_s0997.json | 0 .../{notes => beatmaps}/Live_s0998.json | 0 .../{notes => beatmaps}/Live_s0999.json | 0 .../{notes => beatmaps}/Live_s1000.json | 0 .../{notes => beatmaps}/Live_s1001.json | 0 .../{notes => beatmaps}/Live_s1002.json | 0 .../{notes => beatmaps}/Live_s1003.json | 0 .../{notes => beatmaps}/Live_s1004.json | 0 .../{notes => beatmaps}/Live_s1005.json | 0 .../{notes => beatmaps}/Live_s1006.json | 0 .../{notes => beatmaps}/Live_s1007.json | 0 .../{notes => beatmaps}/Live_s1008.json | 0 .../{notes => beatmaps}/Live_s1009.json | 0 .../{notes => beatmaps}/Live_s1010.json | 0 .../{notes => beatmaps}/Live_s1011.json | 0 .../{notes => beatmaps}/Live_s1012.json | 0 .../{notes => beatmaps}/Live_s1013.json | 0 .../{notes => beatmaps}/Live_s1014.json | 0 .../{notes => beatmaps}/Live_s1015.json | 0 .../{notes => beatmaps}/Live_s1016.json | 0 .../{notes => beatmaps}/Live_s1017.json | 0 .../{notes => beatmaps}/Live_s1018.json | 0 .../{notes => beatmaps}/Live_s1019.json | 0 .../{notes => beatmaps}/Live_s1020.json | 0 .../{notes => beatmaps}/Live_s1021.json | 0 .../{notes => beatmaps}/Live_s1022.json | 0 .../{notes => beatmaps}/Live_s1023.json | 0 .../{notes => beatmaps}/Live_s1024.json | 0 .../{notes => beatmaps}/Live_s1025.json | 0 .../{notes => beatmaps}/Live_s1026.json | 0 .../{notes => beatmaps}/Live_s1027.json | 0 .../{notes => beatmaps}/Live_s1028.json | 0 .../{notes => beatmaps}/Live_s1029.json | 0 .../{notes => beatmaps}/Live_s1030.json | 0 .../{notes => beatmaps}/Live_s1031.json | 0 .../{notes => beatmaps}/Live_s1032.json | 0 .../{notes => beatmaps}/Live_s1033.json | 0 .../{notes => beatmaps}/Live_s1034.json | 0 .../{notes => beatmaps}/Live_s1035.json | 0 .../{notes => beatmaps}/Live_s1036.json | 0 .../{notes => beatmaps}/Live_s1037.json | 0 .../{notes => beatmaps}/Live_s1038.json | 0 .../{notes => beatmaps}/Live_s1039.json | 0 .../{notes => beatmaps}/Live_s1040.json | 0 .../{notes => beatmaps}/Live_s1041.json | 0 .../{notes => beatmaps}/Live_s1042.json | 0 .../{notes => beatmaps}/Live_s1043.json | 0 .../{notes => beatmaps}/Live_s1044.json | 0 .../{notes => beatmaps}/Live_s1045.json | 0 .../{notes => beatmaps}/Live_s1046.json | 0 .../{notes => beatmaps}/Live_s1047.json | 0 .../{notes => beatmaps}/Live_s1048.json | 0 .../{notes => beatmaps}/Live_s1049.json | 0 .../{notes => beatmaps}/Live_s1050.json | 0 .../{notes => beatmaps}/Live_s1051.json | 0 .../{notes => beatmaps}/Live_s1052.json | 0 .../{notes => beatmaps}/Live_s1053.json | 0 .../{notes => beatmaps}/Live_s1054.json | 0 .../{notes => beatmaps}/Live_s1055.json | 0 .../{notes => beatmaps}/Live_s1056.json | 0 .../{notes => beatmaps}/Live_s1057.json | 0 .../{notes => beatmaps}/Live_s1058.json | 0 .../{notes => beatmaps}/Live_s1059.json | 0 .../{notes => beatmaps}/Live_s1060.json | 0 .../{notes => beatmaps}/Live_s1061.json | 0 .../{notes => beatmaps}/Live_s1062.json | 0 .../{notes => beatmaps}/Live_s1063.json | 0 .../{notes => beatmaps}/Live_s1064.json | 0 .../{notes => beatmaps}/Live_s1065.json | 0 .../{notes => beatmaps}/Live_s1066.json | 0 .../{notes => beatmaps}/Live_s1067.json | 0 .../{notes => beatmaps}/Live_s1068.json | 0 .../{notes => beatmaps}/Live_s1069.json | 0 .../{notes => beatmaps}/Live_s1070.json | 0 .../{notes => beatmaps}/Live_s1071.json | 0 .../{notes => beatmaps}/Live_s1072.json | 0 .../{notes => beatmaps}/Live_s1073.json | 0 .../{notes => beatmaps}/Live_s1074.json | 0 .../{notes => beatmaps}/Live_s1075.json | 0 .../{notes => beatmaps}/Live_s1076.json | 0 .../{notes => beatmaps}/Live_s1077.json | 0 .../{notes => beatmaps}/Live_s1078.json | 0 .../{notes => beatmaps}/Live_s1079.json | 0 .../{notes => beatmaps}/Live_s1080.json | 0 .../{notes => beatmaps}/Live_s1081.json | 0 .../{notes => beatmaps}/Live_s1082.json | 0 .../{notes => beatmaps}/Live_s1083.json | 0 .../{notes => beatmaps}/Live_s1084.json | 0 .../{notes => beatmaps}/Live_s1085.json | 0 .../{notes => beatmaps}/Live_s1086.json | 0 .../{notes => beatmaps}/Live_s1087.json | 0 .../{notes => beatmaps}/Live_s1088.json | 0 .../{notes => beatmaps}/Live_s1089.json | 0 .../{notes => beatmaps}/Live_s1090.json | 0 .../{notes => beatmaps}/Live_s1091.json | 0 .../{notes => beatmaps}/Live_s1092.json | 0 .../{notes => beatmaps}/Live_s1093.json | 0 .../{notes => beatmaps}/Live_s1094.json | 0 .../{notes => beatmaps}/Live_s1095.json | 0 .../{notes => beatmaps}/Live_s1096.json | 0 .../{notes => beatmaps}/Live_s1097.json | 0 .../{notes => beatmaps}/Live_s1098.json | 0 .../{notes => beatmaps}/Live_s1099.json | 0 .../{notes => beatmaps}/Live_s1100.json | 0 .../{notes => beatmaps}/Live_s1101.json | 0 .../{notes => beatmaps}/Live_s1102.json | 0 .../{notes => beatmaps}/Live_s1103.json | 0 .../{notes => beatmaps}/Live_s1104.json | 0 .../{notes => beatmaps}/Live_s1105.json | 0 .../{notes => beatmaps}/Live_s1106.json | 0 .../{notes => beatmaps}/Live_s1107.json | 0 .../{notes => beatmaps}/Live_s1108.json | 0 .../{notes => beatmaps}/Live_s1109.json | 0 .../{notes => beatmaps}/Live_s1110.json | 0 .../{notes => beatmaps}/Live_s1111.json | 0 .../{notes => beatmaps}/Live_s1112.json | 0 .../{notes => beatmaps}/Live_s1113.json | 0 .../{notes => beatmaps}/Live_s1114.json | 0 .../{notes => beatmaps}/Live_s1115.json | 0 .../{notes => beatmaps}/Live_s1116.json | 0 .../{notes => beatmaps}/Live_s1117.json | 0 .../{notes => beatmaps}/Live_s1118.json | 0 .../{notes => beatmaps}/Live_s1119.json | 0 .../{notes => beatmaps}/Live_s1120.json | 0 .../{notes => beatmaps}/Live_s1121.json | 0 .../{notes => beatmaps}/Live_s1122.json | 0 .../{notes => beatmaps}/Live_s1123.json | 0 .../{notes => beatmaps}/Live_s1124.json | 0 .../{notes => beatmaps}/Live_s1125.json | 0 .../{notes => beatmaps}/Live_s1126.json | 0 .../{notes => beatmaps}/Live_s1127.json | 0 .../{notes => beatmaps}/Live_s1128.json | 0 .../{notes => beatmaps}/Live_s1129.json | 0 .../{notes => beatmaps}/Live_s1130.json | 0 .../{notes => beatmaps}/Live_s1131.json | 0 .../{notes => beatmaps}/Live_s1132.json | 0 .../{notes => beatmaps}/Live_s1133.json | 0 .../{notes => beatmaps}/Live_s1134.json | 0 .../{notes => beatmaps}/Live_s1135.json | 0 .../{notes => beatmaps}/Live_s1136.json | 0 .../{notes => beatmaps}/Live_s1137.json | 0 .../{notes => beatmaps}/Live_s1138.json | 0 .../{notes => beatmaps}/Live_s1139.json | 0 .../{notes => beatmaps}/Live_s1140.json | 0 .../{notes => beatmaps}/Live_s1141.json | 0 .../{notes => beatmaps}/Live_s1142.json | 0 .../{notes => beatmaps}/Live_s1143.json | 0 .../{notes => beatmaps}/Live_s1144.json | 0 .../{notes => beatmaps}/Live_s1145.json | 0 .../{notes => beatmaps}/Live_s1146.json | 0 .../{notes => beatmaps}/Live_s1147.json | 0 .../{notes => beatmaps}/Live_s1148.json | 0 .../{notes => beatmaps}/Live_s1149.json | 0 .../{notes => beatmaps}/Live_s1150.json | 0 .../{notes => beatmaps}/Live_s1151.json | 0 .../{notes => beatmaps}/Live_s1152.json | 0 .../{notes => beatmaps}/Live_s1153.json | 0 .../{notes => beatmaps}/Live_s1154.json | 0 .../{notes => beatmaps}/Live_s1155.json | 0 .../{notes => beatmaps}/Live_s1156.json | 0 .../{notes => beatmaps}/Live_s1157.json | 0 .../{notes => beatmaps}/Live_s1158.json | 0 .../{notes => beatmaps}/Live_s1159.json | 0 .../{notes => beatmaps}/Live_s1160.json | 0 .../{notes => beatmaps}/Live_s1161.json | 0 .../{notes => beatmaps}/Live_s1162.json | 0 .../{notes => beatmaps}/Live_s1163.json | 0 .../{notes => beatmaps}/Live_s1164.json | 0 .../{notes => beatmaps}/Live_s1165.json | 0 .../{notes => beatmaps}/Live_s1166.json | 0 .../{notes => beatmaps}/Live_s1167.json | 0 .../{notes => beatmaps}/Live_s1168.json | 0 .../{notes => beatmaps}/Live_s1169.json | 0 .../{notes => beatmaps}/Live_s1170.json | 0 .../{notes => beatmaps}/Live_s1171.json | 0 .../{notes => beatmaps}/Live_s1172.json | 0 .../{notes => beatmaps}/Live_s1173.json | 0 .../{notes => beatmaps}/Live_s1174.json | 0 .../{notes => beatmaps}/Live_s1175.json | 0 .../{notes => beatmaps}/Live_s1176.json | 0 .../{notes => beatmaps}/Live_s1177.json | 0 .../{notes => beatmaps}/Live_s1178.json | 0 .../{notes => beatmaps}/Live_s1179.json | 0 .../{notes => beatmaps}/Live_s1180.json | 0 .../{notes => beatmaps}/Live_s1181.json | 0 .../{notes => beatmaps}/Live_s1182.json | 0 .../{notes => beatmaps}/Live_s1183.json | 0 .../{notes => beatmaps}/Live_s1184.json | 0 .../{notes => beatmaps}/Live_s1185.json | 0 .../{notes => beatmaps}/Live_s1186.json | 0 .../{notes => beatmaps}/Live_s1187.json | 0 .../{notes => beatmaps}/Live_s1188.json | 0 .../{notes => beatmaps}/Live_s1189.json | 0 .../{notes => beatmaps}/Live_s1190.json | 0 .../{notes => beatmaps}/Live_s1191.json | 0 .../{notes => beatmaps}/Live_s1192.json | 0 .../{notes => beatmaps}/Live_s1193.json | 0 .../{notes => beatmaps}/Live_s1194.json | 0 .../{notes => beatmaps}/Live_s1195.json | 0 .../{notes => beatmaps}/Live_s1196.json | 0 .../{notes => beatmaps}/Live_s1197.json | 0 .../{notes => beatmaps}/Live_s1198.json | 0 .../{notes => beatmaps}/Live_s1199.json | 0 .../{notes => beatmaps}/Live_s1200.json | 0 .../{notes => beatmaps}/Live_s1201.json | 0 .../{notes => beatmaps}/Live_s1202.json | 0 .../{notes => beatmaps}/Live_s1203.json | 0 .../{notes => beatmaps}/Live_s1204.json | 0 .../{notes => beatmaps}/Live_s1205.json | 0 .../{notes => beatmaps}/Live_s1206.json | 0 .../{notes => beatmaps}/Live_s1207.json | 0 .../{notes => beatmaps}/Live_s1208.json | 0 .../{notes => beatmaps}/Live_s1209.json | 0 .../{notes => beatmaps}/Live_s1210.json | 0 .../{notes => beatmaps}/Live_s1211.json | 0 .../{notes => beatmaps}/Live_s1212.json | 0 .../{notes => beatmaps}/Live_s1213.json | 0 .../{notes => beatmaps}/Live_s1214.json | 0 .../{notes => beatmaps}/Live_s1215.json | 0 .../{notes => beatmaps}/Live_s1216.json | 0 .../{notes => beatmaps}/Live_s1217.json | 0 .../{notes => beatmaps}/Live_s1218.json | 0 .../{notes => beatmaps}/Live_s1219.json | 0 .../{notes => beatmaps}/Live_s1220.json | 0 .../{notes => beatmaps}/Live_s1221.json | 0 .../{notes => beatmaps}/Live_s1222.json | 0 .../{notes => beatmaps}/Live_s1223.json | 0 .../{notes => beatmaps}/Live_s1224.json | 0 .../{notes => beatmaps}/Live_s1225.json | 0 .../{notes => beatmaps}/Live_s1226.json | 0 .../{notes => beatmaps}/Live_s1227.json | 0 .../{notes => beatmaps}/Live_s1228.json | 0 .../{notes => beatmaps}/Live_s1229.json | 0 .../{notes => beatmaps}/Live_s1230.json | 0 .../{notes => beatmaps}/Live_s1231.json | 0 .../{notes => beatmaps}/Live_s1232.json | 0 .../{notes => beatmaps}/Live_s1233.json | 0 .../{notes => beatmaps}/Live_s1234.json | 0 .../{notes => beatmaps}/Live_s1235.json | 0 .../{notes => beatmaps}/Live_s1236.json | 0 .../{notes => beatmaps}/Live_s1237.json | 0 .../{notes => beatmaps}/Live_s1238.json | 0 .../{notes => beatmaps}/Live_s1239.json | 0 .../{notes => beatmaps}/Live_s1240.json | 0 .../{notes => beatmaps}/Live_s1241.json | 0 .../{notes => beatmaps}/Live_s1242.json | 0 .../{notes => beatmaps}/Live_s1243.json | 0 .../{notes => beatmaps}/Live_s1244.json | 0 .../{notes => beatmaps}/Live_s1245.json | 0 .../{notes => beatmaps}/Live_s1246.json | 0 .../{notes => beatmaps}/Live_s1247.json | 0 .../{notes => beatmaps}/Live_s1248.json | 0 .../{notes => beatmaps}/Live_s1249.json | 0 .../{notes => beatmaps}/Live_s1250.json | 0 .../{notes => beatmaps}/Live_s1251.json | 0 .../{notes => beatmaps}/Live_s1252.json | 0 .../{notes => beatmaps}/Live_s1253.json | 0 .../{notes => beatmaps}/Live_s1254.json | 0 .../{notes => beatmaps}/Live_s1255.json | 0 .../{notes => beatmaps}/Live_s1256.json | 0 .../{notes => beatmaps}/Live_s1257.json | 0 .../{notes => beatmaps}/Live_s1258.json | 0 .../{notes => beatmaps}/Live_s1259.json | 0 .../{notes => beatmaps}/Live_s1260.json | 0 .../{notes => beatmaps}/Live_s1261.json | 0 .../{notes => beatmaps}/Live_s1262.json | 0 .../{notes => beatmaps}/Live_s1263.json | 0 .../{notes => beatmaps}/Live_s1264.json | 0 .../{notes => beatmaps}/Live_s1265.json | 0 .../{notes => beatmaps}/Live_s1266.json | 0 .../{notes => beatmaps}/Live_s1267.json | 0 .../{notes => beatmaps}/Live_s1268.json | 0 .../{notes => beatmaps}/Live_s1269.json | 0 .../{notes => beatmaps}/Live_s1270.json | 0 .../{notes => beatmaps}/Live_s1271.json | 0 .../{notes => beatmaps}/Live_s1272.json | 0 .../{notes => beatmaps}/Live_s1273.json | 0 .../{notes => beatmaps}/Live_s1274.json | 0 .../{notes => beatmaps}/Live_s1275.json | 0 .../{notes => beatmaps}/Live_s1276.json | 0 .../{notes => beatmaps}/Live_s1277.json | 0 .../{notes => beatmaps}/Live_s1278.json | 0 .../{notes => beatmaps}/Live_s1279.json | 0 .../{notes => beatmaps}/Live_s1280.json | 0 .../{notes => beatmaps}/Live_s1281.json | 0 .../{notes => beatmaps}/Live_s1282.json | 0 .../{notes => beatmaps}/Live_s1283.json | 0 .../{notes => beatmaps}/Live_s1284.json | 0 .../{notes => beatmaps}/Live_s1285.json | 0 .../{notes => beatmaps}/Live_s1286.json | 0 .../{notes => beatmaps}/Live_s1287.json | 0 .../{notes => beatmaps}/Live_s1288.json | 0 .../{notes => beatmaps}/Live_s1289.json | 0 .../{notes => beatmaps}/Live_s1290.json | 0 .../{notes => beatmaps}/Live_s1291.json | 0 .../{notes => beatmaps}/Live_s1292.json | 0 .../{notes => beatmaps}/Live_s1293.json | 0 .../{notes => beatmaps}/Live_s1294.json | 0 .../{notes => beatmaps}/Live_s1295.json | 0 .../{notes => beatmaps}/Live_s1296.json | 0 .../{notes => beatmaps}/Live_s1297.json | 0 .../{notes => beatmaps}/Live_s1298.json | 0 .../{notes => beatmaps}/Live_s1299.json | 0 .../{notes => beatmaps}/Live_s1300.json | 0 .../{notes => beatmaps}/Live_s1301.json | 0 .../{notes => beatmaps}/Live_s1302.json | 0 .../{notes => beatmaps}/Live_s1303.json | 0 .../{notes => beatmaps}/Live_s1304.json | 0 .../{notes => beatmaps}/Live_s1305.json | 0 .../{notes => beatmaps}/Live_s1306.json | 0 .../{notes => beatmaps}/Live_s1307.json | 0 .../{notes => beatmaps}/Live_s1308.json | 0 .../{notes => beatmaps}/Live_s1309.json | 0 .../{notes => beatmaps}/Live_s1310.json | 0 .../{notes => beatmaps}/Live_s1311.json | 0 .../{notes => beatmaps}/Live_s1312.json | 0 .../{notes => beatmaps}/Live_s1313.json | 0 .../{notes => beatmaps}/Live_s1314.json | 0 .../{notes => beatmaps}/Live_s1315.json | 0 .../{notes => beatmaps}/Live_s1316.json | 0 .../{notes => beatmaps}/Live_s1317.json | 0 .../{notes => beatmaps}/Live_s1318.json | 0 .../{notes => beatmaps}/Live_s1319.json | 0 .../{notes => beatmaps}/Live_s1320.json | 0 .../{notes => beatmaps}/Live_s1321.json | 0 .../{notes => beatmaps}/Live_s1322.json | 0 .../{notes => beatmaps}/Live_s1323.json | 0 .../{notes => beatmaps}/Live_s1324.json | 0 .../{notes => beatmaps}/Live_s1325.json | 0 .../{notes => beatmaps}/Live_s1326.json | 0 .../{notes => beatmaps}/Live_s1327.json | 0 .../{notes => beatmaps}/Live_s1328.json | 0 .../{notes => beatmaps}/Live_s1329.json | 0 .../{notes => beatmaps}/Live_s1330.json | 0 .../{notes => beatmaps}/Live_s1331.json | 0 .../{notes => beatmaps}/Live_s1332.json | 0 .../{notes => beatmaps}/Live_s1333.json | 0 .../{notes => beatmaps}/Live_s1334.json | 0 .../{notes => beatmaps}/Live_s1335.json | 0 .../{notes => beatmaps}/Live_s1336.json | 0 .../{notes => beatmaps}/Live_s1337.json | 0 .../{notes => beatmaps}/Live_s1338.json | 0 .../{notes => beatmaps}/Live_s1339.json | 0 .../{notes => beatmaps}/Live_s1340.json | 0 .../{notes => beatmaps}/Live_s1341.json | 0 .../{notes => beatmaps}/Live_s1342.json | 0 .../{notes => beatmaps}/Live_s1343.json | 0 .../{notes => beatmaps}/Live_s1344.json | 0 .../{notes => beatmaps}/Live_s1345.json | 0 .../{notes => beatmaps}/Live_s1346.json | 0 .../{notes => beatmaps}/Live_s1347.json | 0 .../{notes => beatmaps}/Live_s1348.json | 0 .../{notes => beatmaps}/Live_s1349.json | 0 .../{notes => beatmaps}/Live_s1350.json | 0 .../{notes => beatmaps}/Live_s1351.json | 0 .../{notes => beatmaps}/Live_s1352.json | 0 .../{notes => beatmaps}/Live_s1353.json | 0 .../{notes => beatmaps}/Live_s1354.json | 0 .../{notes => beatmaps}/Live_s1355.json | 0 .../{notes => beatmaps}/Live_s1356.json | 0 .../{notes => beatmaps}/Live_s1357.json | 0 .../{notes => beatmaps}/Live_s1358.json | 0 .../{notes => beatmaps}/Live_s1359.json | 0 .../{notes => beatmaps}/Live_s1360.json | 0 .../{notes => beatmaps}/Live_s1361.json | 0 .../{notes => beatmaps}/Live_s1362.json | 0 .../{notes => beatmaps}/Live_s1363.json | 0 .../{notes => beatmaps}/Live_s1364.json | 0 .../{notes => beatmaps}/Live_s1365.json | 0 .../{notes => beatmaps}/Live_s1366.json | 0 .../{notes => beatmaps}/Live_s1367.json | 0 .../{notes => beatmaps}/Live_s1368.json | 0 .../{notes => beatmaps}/Live_s1369.json | 0 .../{notes => beatmaps}/Live_s1370.json | 0 .../{notes => beatmaps}/Live_s1371.json | 0 .../{notes => beatmaps}/Live_s1372.json | 0 .../{notes => beatmaps}/Live_s1373.json | 0 .../{notes => beatmaps}/Live_s1374.json | 0 .../{notes => beatmaps}/Live_s1375.json | 0 .../{notes => beatmaps}/Live_s1376.json | 0 .../{notes => beatmaps}/Live_s1377.json | 0 .../{notes => beatmaps}/Live_s1378.json | 0 .../{notes => beatmaps}/Live_s1379.json | 0 .../{notes => beatmaps}/Live_s1380.json | 0 .../{notes => beatmaps}/Live_s1381.json | 0 .../{notes => beatmaps}/Live_s1382.json | 0 .../{notes => beatmaps}/Live_s1383.json | 0 .../{notes => beatmaps}/Live_s1384.json | 0 .../{notes => beatmaps}/Live_s1385.json | 0 .../{notes => beatmaps}/Live_s1386.json | 0 .../{notes => beatmaps}/Live_s1387.json | 0 .../{notes => beatmaps}/Live_s1388.json | 0 .../{notes => beatmaps}/Live_s1389.json | 0 .../{notes => beatmaps}/Live_s1390.json | 0 .../{notes => beatmaps}/Live_s1391.json | 0 .../{notes => beatmaps}/Live_s1392.json | 0 .../{notes => beatmaps}/Live_s1393.json | 0 .../{notes => beatmaps}/Live_s1394.json | 0 .../{notes => beatmaps}/Live_s1395.json | 0 .../{notes => beatmaps}/Live_s1396.json | 0 .../{notes => beatmaps}/Live_s1397.json | 0 .../{notes => beatmaps}/Live_s1398.json | 0 .../{notes => beatmaps}/Live_s1399.json | 0 .../{notes => beatmaps}/Live_s1400.json | 0 .../{notes => beatmaps}/Live_s1401.json | 0 .../{notes => beatmaps}/Live_s1402.json | 0 .../{notes => beatmaps}/Live_s1403.json | 0 .../{notes => beatmaps}/Live_s1404.json | 0 .../{notes => beatmaps}/Live_s1405.json | 0 .../{notes => beatmaps}/Live_s1406.json | 0 .../{notes => beatmaps}/Live_s1407.json | 0 .../{notes => beatmaps}/Live_s1408.json | 0 .../{notes => beatmaps}/Live_s1409.json | 0 .../{notes => beatmaps}/Live_s1410.json | 0 .../{notes => beatmaps}/Live_s1411.json | 0 .../{notes => beatmaps}/Live_s1412.json | 0 .../{notes => beatmaps}/Live_s1413.json | 0 .../{notes => beatmaps}/Live_s1414.json | 0 .../{notes => beatmaps}/Live_s1415.json | 0 .../{notes => beatmaps}/Live_s1416.json | 0 .../{notes => beatmaps}/Live_s1417.json | 0 .../{notes => beatmaps}/Live_s1418.json | 0 .../{notes => beatmaps}/Live_s1419.json | 0 .../{notes => beatmaps}/Live_s1420.json | 0 .../{notes => beatmaps}/Live_s1421.json | 0 .../{notes => beatmaps}/Live_s1422.json | 0 .../{notes => beatmaps}/Live_s1423.json | 0 .../{notes => beatmaps}/Live_s1424.json | 0 .../{notes => beatmaps}/Live_s1425.json | 0 .../{notes => beatmaps}/Live_s1426.json | 0 .../{notes => beatmaps}/Live_s1427.json | 0 .../{notes => beatmaps}/Live_s1428.json | 0 .../{notes => beatmaps}/Live_s1429.json | 0 .../{notes => beatmaps}/Live_s1430.json | 0 .../{notes => beatmaps}/Live_s1431.json | 0 .../{notes => beatmaps}/Live_s1432.json | 0 .../{notes => beatmaps}/Live_s1433.json | 0 .../{notes => beatmaps}/Live_s1434.json | 0 .../{notes => beatmaps}/Live_s1435.json | 0 .../{notes => beatmaps}/Live_s1436.json | 0 .../{notes => beatmaps}/Live_s1437.json | 0 .../{notes => beatmaps}/Live_s1438.json | 0 .../{notes => beatmaps}/Live_s1439.json | 0 .../{notes => beatmaps}/Live_s1440.json | 0 .../{notes => beatmaps}/Live_s1441.json | 0 .../{notes => beatmaps}/Live_s1442.json | 0 .../{notes => beatmaps}/Live_s1443.json | 0 .../{notes => beatmaps}/Live_s1444.json | 0 .../{notes => beatmaps}/Live_s1445.json | 0 .../{notes => beatmaps}/Live_s1446.json | 0 .../{notes => beatmaps}/Live_s1447.json | 0 .../{notes => beatmaps}/Live_s1448.json | 0 .../{notes => beatmaps}/Live_s1449.json | 0 .../{notes => beatmaps}/Live_s1450.json | 0 .../{notes => beatmaps}/Live_s1451.json | 0 .../{notes => beatmaps}/Live_s1452.json | 0 .../{notes => beatmaps}/Live_s1453.json | 0 .../{notes => beatmaps}/Live_s1454.json | 0 .../{notes => beatmaps}/Live_s1455.json | 0 .../{notes => beatmaps}/Live_s1456.json | 0 .../{notes => beatmaps}/Live_s1457.json | 0 .../{notes => beatmaps}/Live_s1458.json | 0 .../{notes => beatmaps}/Live_s1459.json | 0 .../{notes => beatmaps}/Live_s1460.json | 0 .../{notes => beatmaps}/Live_s1461.json | 0 .../{notes => beatmaps}/Live_s1462.json | 0 .../{notes => beatmaps}/Live_s1463.json | 0 .../{notes => beatmaps}/Live_s1464.json | 0 .../{notes => beatmaps}/Live_s1465.json | 0 .../{notes => beatmaps}/Live_s1466.json | 0 .../{notes => beatmaps}/Live_s1467.json | 0 .../{notes => beatmaps}/Live_s1468.json | 0 .../{notes => beatmaps}/Live_s1469.json | 0 .../{notes => beatmaps}/Live_s1470.json | 0 .../{notes => beatmaps}/Live_s1471.json | 0 .../{notes => beatmaps}/Live_s1472.json | 0 .../{notes => beatmaps}/Live_s1473.json | 0 .../{notes => beatmaps}/Live_s1474.json | 0 .../{notes => beatmaps}/Live_s1475.json | 0 .../{notes => beatmaps}/Live_s1476.json | 0 .../{notes => beatmaps}/Live_s1477.json | 0 .../{notes => beatmaps}/Live_s1478.json | 0 .../{notes => beatmaps}/Live_s1479.json | 0 .../{notes => beatmaps}/Live_s1480.json | 0 .../{notes => beatmaps}/Live_s1481.json | 0 .../{notes => beatmaps}/Live_s1482.json | 0 .../{notes => beatmaps}/Live_s1483.json | 0 .../{notes => beatmaps}/Live_s1484.json | 0 .../{notes => beatmaps}/Live_s1485.json | 0 .../{notes => beatmaps}/Live_s1486.json | 0 .../{notes => beatmaps}/Live_s1487.json | 0 .../{notes => beatmaps}/Live_s1488.json | 0 .../{notes => beatmaps}/Live_s1489.json | 0 .../{notes => beatmaps}/Live_s1490.json | 0 .../{notes => beatmaps}/Live_s1491.json | 0 .../{notes => beatmaps}/Live_s1492.json | 0 .../{notes => beatmaps}/Live_s1493.json | 0 .../{notes => beatmaps}/Live_s1494.json | 0 .../{notes => beatmaps}/Live_s1495.json | 0 .../{notes => beatmaps}/Live_s1496.json | 0 .../{notes => beatmaps}/Live_s1497.json | 0 .../{notes => beatmaps}/Live_s1498.json | 0 .../{notes => beatmaps}/Live_s1499.json | 0 .../{notes => beatmaps}/Live_s1500.json | 0 .../{notes => beatmaps}/Live_s1501.json | 0 .../{notes => beatmaps}/Live_s1502.json | 0 .../{notes => beatmaps}/Live_s1503.json | 0 .../{notes => beatmaps}/Live_s1504.json | 0 .../{notes => beatmaps}/Live_s1505.json | 0 .../{notes => beatmaps}/Live_s1506.json | 0 .../{notes => beatmaps}/Live_s1507.json | 0 .../{notes => beatmaps}/Live_s1508.json | 0 .../{notes => beatmaps}/Live_s1509.json | 0 .../{notes => beatmaps}/Live_s1510.json | 0 .../{notes => beatmaps}/Live_s1511.json | 0 .../{notes => beatmaps}/Live_s1512.json | 0 .../{notes => beatmaps}/Live_s1513.json | 0 .../{notes => beatmaps}/Live_s1514.json | 0 .../{notes => beatmaps}/Live_s1515.json | 0 .../{notes => beatmaps}/Live_s1516.json | 0 .../{notes => beatmaps}/Live_s1517.json | 0 .../{notes => beatmaps}/Live_s1518.json | 0 .../{notes => beatmaps}/Live_s1519.json | 0 .../{notes => beatmaps}/Live_s1520.json | 0 .../{notes => beatmaps}/Live_s1521.json | 0 .../{notes => beatmaps}/Live_s1522.json | 0 .../{notes => beatmaps}/Live_s1523.json | 0 .../{notes => beatmaps}/Live_s1524.json | 0 .../{notes => beatmaps}/Live_s1525.json | 0 .../{notes => beatmaps}/Live_s1526.json | 0 .../{notes => beatmaps}/Live_s1527.json | 0 .../{notes => beatmaps}/Live_s1528.json | 0 .../{notes => beatmaps}/Live_s1529.json | 0 .../{notes => beatmaps}/Live_s1530.json | 0 .../{notes => beatmaps}/Live_s1531.json | 0 .../{notes => beatmaps}/Live_s1532.json | 0 .../{notes => beatmaps}/Live_s1533.json | 0 .../{notes => beatmaps}/Live_s1534.json | 0 .../{notes => beatmaps}/Live_s1535.json | 0 .../{notes => beatmaps}/Live_s1536.json | 0 .../{notes => beatmaps}/Live_s1537.json | 0 .../{notes => beatmaps}/Live_s1538.json | 0 .../{notes => beatmaps}/Live_s1539.json | 0 .../{notes => beatmaps}/Live_s1540.json | 0 .../{notes => beatmaps}/Live_s1541.json | 0 .../{notes => beatmaps}/Live_s1542.json | 0 .../{notes => beatmaps}/Live_s1543.json | 0 .../{notes => beatmaps}/Live_s1544.json | 0 .../{notes => beatmaps}/Live_s1545.json | 0 .../{notes => beatmaps}/Live_s1546.json | 0 .../{notes => beatmaps}/Live_s1547.json | 0 .../{notes => beatmaps}/Live_s1548.json | 0 .../{notes => beatmaps}/Live_s1549.json | 0 .../{notes => beatmaps}/Live_s1550.json | 0 .../{notes => beatmaps}/Live_s1551.json | 0 .../{notes => beatmaps}/Live_s1552.json | 0 .../{notes => beatmaps}/Live_s1553.json | 0 .../{notes => beatmaps}/Live_s1554.json | 0 .../{notes => beatmaps}/Live_s1555.json | 0 .../{notes => beatmaps}/Live_s1556.json | 0 .../{notes => beatmaps}/Live_s1557.json | 0 .../{notes => beatmaps}/Live_s1558.json | 0 .../{notes => beatmaps}/Live_s1559.json | 0 .../{notes => beatmaps}/Live_s1560.json | 0 .../{notes => beatmaps}/Live_s1561.json | 0 .../{notes => beatmaps}/Live_s1562.json | 0 .../{notes => beatmaps}/Live_s1563.json | 0 .../{notes => beatmaps}/Live_s1564.json | 0 .../{notes => beatmaps}/Live_s1565.json | 0 .../{notes => beatmaps}/Live_s1566.json | 0 .../{notes => beatmaps}/Live_s1567.json | 0 .../{notes => beatmaps}/Live_s1568.json | 0 .../{notes => beatmaps}/Live_s1569.json | 0 .../{notes => beatmaps}/Live_s1570.json | 0 .../{notes => beatmaps}/Live_s1571.json | 0 .../{notes => beatmaps}/Live_s1572.json | 0 .../{notes => beatmaps}/Live_s1573.json | 0 .../{notes => beatmaps}/Live_s1574.json | 0 .../{notes => beatmaps}/Live_s1575.json | 0 .../{notes => beatmaps}/Live_s1576.json | 0 .../{notes => beatmaps}/Live_s1577.json | 0 .../{notes => beatmaps}/Live_s1578.json | 0 .../{notes => beatmaps}/Live_s1579.json | 0 .../{notes => beatmaps}/Live_s1580.json | 0 .../{notes => beatmaps}/Live_s1581.json | 0 .../{notes => beatmaps}/Live_s1582.json | 0 .../{notes => beatmaps}/Live_s1583.json | 0 .../{notes => beatmaps}/Live_s1584.json | 0 .../{notes => beatmaps}/Live_s1585.json | 0 .../{notes => beatmaps}/Live_s1586.json | 0 .../{notes => beatmaps}/Live_s1587.json | 0 .../{notes => beatmaps}/Live_s1588.json | 0 .../{notes => beatmaps}/Live_s1589.json | 0 .../{notes => beatmaps}/Live_s1590.json | 0 .../{notes => beatmaps}/Live_s1591.json | 0 .../{notes => beatmaps}/Live_s1592.json | 0 .../{notes => beatmaps}/Live_s1593.json | 0 .../{notes => beatmaps}/Live_s1594.json | 0 .../{notes => beatmaps}/Live_s1595.json | 0 .../{notes => beatmaps}/Live_s1596.json | 0 .../{notes => beatmaps}/Live_s1597.json | 0 .../{notes => beatmaps}/Live_s1598.json | 0 .../{notes => beatmaps}/Live_s1599.json | 0 .../{notes => beatmaps}/Live_s1600.json | 0 .../{notes => beatmaps}/Live_s1601.json | 0 .../{notes => beatmaps}/Live_s1602.json | 0 .../{notes => beatmaps}/Live_s1603.json | 0 .../{notes => beatmaps}/Live_s1604.json | 0 .../{notes => beatmaps}/Live_s1605.json | 0 .../{notes => beatmaps}/Live_s1606.json | 0 .../{notes => beatmaps}/Live_s1607.json | 0 .../{notes => beatmaps}/Live_s1608.json | 0 .../{notes => beatmaps}/Live_s1609.json | 0 .../{notes => beatmaps}/Live_s1610.json | 0 .../{notes => beatmaps}/Live_s1611.json | 0 .../{notes => beatmaps}/Live_s1613.json | 0 .../{notes => beatmaps}/Live_s1614.json | 0 .../{notes => beatmaps}/Live_s1615.json | 0 .../{notes => beatmaps}/Live_s1616.json | 0 .../{notes => beatmaps}/Live_s1617.json | 0 .../{notes => beatmaps}/Live_s1618.json | 0 .../{notes => beatmaps}/Live_s1619.json | 0 .../{notes => beatmaps}/Live_s1622.json | 0 .../{notes => beatmaps}/Live_s1623.json | 0 .../{notes => beatmaps}/Live_s1625.json | 0 .../{notes => beatmaps}/Live_s1626.json | 0 .../{notes => beatmaps}/Live_s1627.json | 0 .../{notes => beatmaps}/Live_s1630.json | 0 .../{notes => beatmaps}/Live_s1631.json | 0 .../{notes => beatmaps}/Live_s1632.json | 0 .../{notes => beatmaps}/Live_s1633.json | 0 .../{notes => beatmaps}/Live_s1634.json | 0 .../{notes => beatmaps}/Live_s1635.json | 0 .../{notes => beatmaps}/Live_s1636.json | 0 .../{notes => beatmaps}/Live_s1637.json | 0 .../{notes => beatmaps}/Live_s1638.json | 0 .../{notes => beatmaps}/Live_s1639.json | 0 .../{notes => beatmaps}/Live_s1640.json | 0 .../{notes => beatmaps}/Live_s1641.json | 0 .../{notes => beatmaps}/Live_s1642.json | 0 .../{notes => beatmaps}/Live_s1643.json | 0 .../{notes => beatmaps}/Live_s1644.json | 0 .../{notes => beatmaps}/Live_s1646.json | 0 .../{notes => beatmaps}/Live_s1647.json | 0 .../{notes => beatmaps}/Live_s1648.json | 0 .../{notes => beatmaps}/Live_s1649.json | 0 .../{notes => beatmaps}/Live_s1650.json | 0 .../{notes => beatmaps}/Live_s1651.json | 0 .../{notes => beatmaps}/Live_s1652.json | 0 .../{notes => beatmaps}/Live_s1655.json | 0 .../{notes => beatmaps}/Live_s1656.json | 0 .../{notes => beatmaps}/Live_s1658.json | 0 .../{notes => beatmaps}/Live_s1659.json | 0 .../{notes => beatmaps}/Live_s1660.json | 0 .../{notes => beatmaps}/Live_s1663.json | 0 .../{notes => beatmaps}/Live_s1664.json | 0 .../{notes => beatmaps}/Live_s1665.json | 0 .../{notes => beatmaps}/Live_s1666.json | 0 .../{notes => beatmaps}/Live_s1667.json | 0 .../{notes => beatmaps}/Live_s1668.json | 0 .../{notes => beatmaps}/Live_s1670.json | 0 .../{notes => beatmaps}/Live_s1671.json | 0 .../{notes => beatmaps}/Live_s1672.json | 0 .../{notes => beatmaps}/Live_s1673.json | 0 .../{notes => beatmaps}/Live_s1674.json | 0 .../{notes => beatmaps}/Live_s1675.json | 0 .../{notes => beatmaps}/Live_s1676.json | 0 .../{notes => beatmaps}/Live_s1679.json | 0 .../{notes => beatmaps}/Live_s1680.json | 0 .../{notes => beatmaps}/Live_s1682.json | 0 .../{notes => beatmaps}/Live_s1683.json | 0 .../{notes => beatmaps}/Live_s1684.json | 0 .../{notes => beatmaps}/Live_s1687.json | 0 .../{notes => beatmaps}/Live_s1688.json | 0 .../{notes => beatmaps}/Live_s1689.json | 0 .../{notes => beatmaps}/Live_s1690.json | 0 .../{notes => beatmaps}/Live_s1691.json | 0 .../{notes => beatmaps}/Live_s1692.json | 0 .../{notes => beatmaps}/Live_s1693.json | 0 .../{notes => beatmaps}/Live_s1694.json | 0 .../{notes => beatmaps}/Live_s1695.json | 0 .../{notes => beatmaps}/Live_s1696.json | 0 .../{notes => beatmaps}/Live_s1697.json | 0 .../{notes => beatmaps}/Live_s1698.json | 0 .../{notes => beatmaps}/Live_s1699.json | 0 .../{notes => beatmaps}/Live_s1700.json | 0 .../{notes => beatmaps}/Live_s1701.json | 0 .../{notes => beatmaps}/Live_s1702.json | 0 .../{notes => beatmaps}/Live_s1703.json | 0 .../{notes => beatmaps}/Live_s1704.json | 0 .../{notes => beatmaps}/Live_s1705.json | 0 .../{notes => beatmaps}/Live_s1706.json | 0 .../{notes => beatmaps}/Live_s1708.json | 0 .../{notes => beatmaps}/Live_s1709.json | 0 .../{notes => beatmaps}/Live_s1710.json | 0 .../{notes => beatmaps}/Live_s1711.json | 0 .../{notes => beatmaps}/Live_s1712.json | 0 .../{notes => beatmaps}/Live_s1713.json | 0 .../{notes => beatmaps}/Live_s1714.json | 0 .../{notes => beatmaps}/Live_s1715.json | 0 .../{notes => beatmaps}/Live_s1716.json | 0 .../{notes => beatmaps}/Live_s1717.json | 0 .../{notes => beatmaps}/Live_s1718.json | 0 .../{notes => beatmaps}/Live_s1719.json | 0 .../{notes => beatmaps}/Live_s1720.json | 0 .../{notes => beatmaps}/Live_s1721.json | 0 .../{notes => beatmaps}/Live_s1722.json | 0 .../{notes => beatmaps}/Live_s1723.json | 0 .../{notes => beatmaps}/Live_s1724.json | 0 .../{notes => beatmaps}/Live_s1725.json | 0 .../{notes => beatmaps}/Live_s1726.json | 0 .../{notes => beatmaps}/Live_s1727.json | 0 .../{notes => beatmaps}/Live_s1728.json | 0 .../{notes => beatmaps}/Live_s1729.json | 0 .../{notes => beatmaps}/Live_s1730.json | 0 .../{notes => beatmaps}/Live_s1731.json | 0 .../{notes => beatmaps}/Live_s1732.json | 0 .../{notes => beatmaps}/Live_s1733.json | 0 .../{notes => beatmaps}/Live_s1734.json | 0 .../{notes => beatmaps}/Live_s1735.json | 0 .../{notes => beatmaps}/Live_s1736.json | 0 .../{notes => beatmaps}/Live_s1737.json | 0 .../{notes => beatmaps}/Live_s1738.json | 0 .../{notes => beatmaps}/Live_s1739.json | 0 .../{notes => beatmaps}/Live_s1740.json | 0 .../{notes => beatmaps}/Live_s1741.json | 0 .../{notes => beatmaps}/Live_s1742.json | 0 .../{notes => beatmaps}/Live_s1743.json | 0 .../{notes => beatmaps}/Live_s1744.json | 0 .../{notes => beatmaps}/Live_s1745.json | 0 .../{notes => beatmaps}/Live_s1746.json | 0 .../{notes => beatmaps}/Live_s1747.json | 0 .../{notes => beatmaps}/Live_s1748.json | 0 .../{notes => beatmaps}/Live_s1749.json | 0 .../{notes => beatmaps}/Live_s1750.json | 0 .../{notes => beatmaps}/Live_s1751.json | 0 .../{notes => beatmaps}/Live_s1752.json | 0 .../{notes => beatmaps}/Live_s1753.json | 0 .../{notes => beatmaps}/Live_s1754.json | 0 .../{notes => beatmaps}/Live_s1755.json | 0 .../{notes => beatmaps}/Live_s1756.json | 0 .../{notes => beatmaps}/Live_s1757.json | 0 .../{notes => beatmaps}/Live_s1758.json | 0 .../{notes => beatmaps}/Live_s1759.json | 0 .../{notes => beatmaps}/Live_s1760.json | 0 .../{notes => beatmaps}/Live_s1761.json | 0 .../{notes => beatmaps}/Live_s1762.json | 0 .../{notes => beatmaps}/Live_s1763.json | 0 .../{notes => beatmaps}/Live_s1764.json | 0 .../{notes => beatmaps}/Live_s1765.json | 0 .../{notes => beatmaps}/Live_s1766.json | 0 .../{notes => beatmaps}/Live_s1767.json | 0 .../{notes => beatmaps}/Live_s1768.json | 0 .../{notes => beatmaps}/Live_s1769.json | 0 .../{notes => beatmaps}/Live_s1770.json | 0 .../{notes => beatmaps}/Live_s1771.json | 0 .../{notes => beatmaps}/Live_s1772.json | 0 .../{notes => beatmaps}/Live_s1773.json | 0 .../{notes => beatmaps}/Live_s1774.json | 0 .../{notes => beatmaps}/Live_s1775.json | 0 .../{notes => beatmaps}/Live_s1776.json | 0 .../{notes => beatmaps}/Live_s1777.json | 0 .../{notes => beatmaps}/Live_s1778.json | 0 .../{notes => beatmaps}/Live_s1779.json | 0 .../{notes => beatmaps}/Live_s1780.json | 0 .../{notes => beatmaps}/Live_s1781.json | 0 .../{notes => beatmaps}/Live_s1782.json | 0 .../{notes => beatmaps}/Live_s1783.json | 0 .../{notes => beatmaps}/Live_s1784.json | 0 .../{notes => beatmaps}/Live_s1785.json | 0 .../{notes => beatmaps}/Live_s1786.json | 0 .../{notes => beatmaps}/Live_s1787.json | 0 .../{notes => beatmaps}/Live_s1788.json | 0 .../{notes => beatmaps}/Live_s1789.json | 0 .../{notes => beatmaps}/Live_s1790.json | 0 .../{notes => beatmaps}/Live_s1791.json | 0 .../{notes => beatmaps}/Live_s1792.json | 0 .../{notes => beatmaps}/Live_s1793.json | 0 .../{notes => beatmaps}/Live_s1794.json | 0 .../{notes => beatmaps}/Live_s1795.json | 0 .../{notes => beatmaps}/Live_s1796.json | 0 .../{notes => beatmaps}/Live_s1797.json | 0 .../{notes => beatmaps}/Live_s1798.json | 0 .../{notes => beatmaps}/Live_s1799.json | 0 .../{notes => beatmaps}/Live_s1800.json | 0 .../{notes => beatmaps}/Live_s1801.json | 0 .../{notes => beatmaps}/Live_s1802.json | 0 .../{notes => beatmaps}/Live_s1803.json | 0 .../{notes => beatmaps}/Live_s1804.json | 0 .../{notes => beatmaps}/Live_s1805.json | 0 .../{notes => beatmaps}/Live_s1806.json | 0 .../{notes => beatmaps}/Live_s1807.json | 0 .../{notes => beatmaps}/Live_s1808.json | 0 .../{notes => beatmaps}/Live_s1809.json | 0 .../{notes => beatmaps}/Live_s1810.json | 0 .../{notes => beatmaps}/Live_s1811.json | 0 .../{notes => beatmaps}/Live_s1812.json | 0 .../{notes => beatmaps}/Live_s1813.json | 0 .../{notes => beatmaps}/Live_s1814.json | 0 .../{notes => beatmaps}/Live_s1815.json | 0 .../{notes => beatmaps}/Live_s1816.json | 0 .../{notes => beatmaps}/Live_s1817.json | 0 .../{notes => beatmaps}/Live_s1818.json | 0 .../{notes => beatmaps}/Live_s1819.json | 0 .../{notes => beatmaps}/Live_s1820.json | 0 .../{notes => beatmaps}/Live_s1821.json | 0 .../{notes => beatmaps}/Live_s1822.json | 0 .../{notes => beatmaps}/Live_s1823.json | 0 .../{notes => beatmaps}/Live_s1824.json | 0 .../{notes => beatmaps}/Live_s1825.json | 0 .../{notes => beatmaps}/Live_s1826.json | 0 .../{notes => beatmaps}/Live_s1827.json | 0 .../{notes => beatmaps}/Live_s1828.json | 0 .../{notes => beatmaps}/Live_s1829.json | 0 .../{notes => beatmaps}/Live_s1830.json | 0 .../{notes => beatmaps}/Live_s1831.json | 0 .../{notes => beatmaps}/Live_s1832.json | 0 .../{notes => beatmaps}/Live_s1833.json | 0 .../{notes => beatmaps}/Live_s1834.json | 0 .../{notes => beatmaps}/Live_s1835.json | 0 .../{notes => beatmaps}/Live_s1836.json | 0 .../{notes => beatmaps}/Live_s1837.json | 0 .../{notes => beatmaps}/Live_s1838.json | 0 .../{notes => beatmaps}/Live_s1839.json | 0 .../{notes => beatmaps}/Live_s1840.json | 0 .../{notes => beatmaps}/Live_s1841.json | 0 .../{notes => beatmaps}/Live_s1842.json | 0 .../{notes => beatmaps}/Live_s1843.json | 0 .../{notes => beatmaps}/Live_s1844.json | 0 .../{notes => beatmaps}/Live_s1845.json | 0 .../{notes => beatmaps}/Live_s1846.json | 0 .../{notes => beatmaps}/Live_s1847.json | 0 .../{notes => beatmaps}/Live_s1848.json | 0 .../{notes => beatmaps}/Live_s1849.json | 0 .../{notes => beatmaps}/Live_s1850.json | 0 .../{notes => beatmaps}/Live_s1851.json | 0 .../{notes => beatmaps}/Live_s1852.json | 0 .../{notes => beatmaps}/Live_s1853.json | 0 .../{notes => beatmaps}/Live_s1854.json | 0 .../{notes => beatmaps}/Live_s1855.json | 0 .../{notes => beatmaps}/Live_s1856.json | 0 .../{notes => beatmaps}/Live_s1857.json | 0 .../{notes => beatmaps}/Live_s1858.json | 0 .../{notes => beatmaps}/Live_s1859.json | 0 .../{notes => beatmaps}/Live_s1860.json | 0 .../{notes => beatmaps}/Live_s1861.json | 0 .../{notes => beatmaps}/Live_s1862.json | 0 .../{notes => beatmaps}/Live_s1863.json | 0 .../{notes => beatmaps}/Live_s1864.json | 0 .../{notes => beatmaps}/Live_s1865.json | 0 .../{notes => beatmaps}/Live_s1866.json | 0 .../{notes => beatmaps}/Live_s1867.json | 0 .../{notes => beatmaps}/Live_s1868.json | 0 .../{notes => beatmaps}/Live_s1869.json | 0 .../{notes => beatmaps}/Live_s1870.json | 0 .../{notes => beatmaps}/Live_s1871.json | 0 .../{notes => beatmaps}/Live_s1872.json | 0 .../{notes => beatmaps}/Live_s1873.json | 0 .../{notes => beatmaps}/Live_s1874.json | 0 .../{notes => beatmaps}/Live_s1875.json | 0 .../{notes => beatmaps}/Live_s1876.json | 0 .../{notes => beatmaps}/Live_s1877.json | 0 .../{notes => beatmaps}/Live_s1878.json | 0 .../{notes => beatmaps}/Live_s1879.json | 0 .../{notes => beatmaps}/Live_s1880.json | 0 .../{notes => beatmaps}/Live_s1881.json | 0 .../{notes => beatmaps}/Live_s1882.json | 0 .../{notes => beatmaps}/Live_s1883.json | 0 .../{notes => beatmaps}/Live_s1884.json | 0 .../{notes => beatmaps}/Live_s1885.json | 0 .../{notes => beatmaps}/Live_s1886.json | 0 .../{notes => beatmaps}/Live_s1887.json | 0 .../{notes => beatmaps}/Live_s1888.json | 0 .../{notes => beatmaps}/Live_s1889.json | 0 .../{notes => beatmaps}/Live_s1890.json | 0 .../{notes => beatmaps}/Live_s1891.json | 0 .../{notes => beatmaps}/Live_s1892.json | 0 .../{notes => beatmaps}/Live_s1893.json | 0 .../{notes => beatmaps}/Live_s1894.json | 0 .../{notes => beatmaps}/Live_s1895.json | 0 .../{notes => beatmaps}/Live_s1896.json | 0 .../{notes => beatmaps}/Live_s1897.json | 0 .../{notes => beatmaps}/Live_s1898.json | 0 .../{notes => beatmaps}/Live_s1899.json | 0 .../{notes => beatmaps}/Live_s1900.json | 0 .../{notes => beatmaps}/Live_s1901.json | 0 .../{notes => beatmaps}/Live_s1902.json | 0 .../{notes => beatmaps}/Live_s1903.json | 0 .../{notes => beatmaps}/Live_s1904.json | 0 .../{notes => beatmaps}/Live_s1905.json | 0 .../{notes => beatmaps}/Live_s1906.json | 0 .../{notes => beatmaps}/Live_s1907.json | 0 .../{notes => beatmaps}/Live_s1908.json | 0 .../{notes => beatmaps}/Live_s1909.json | 0 .../{notes => beatmaps}/Live_s1910.json | 0 .../{notes => beatmaps}/Live_s1911.json | 0 .../{notes => beatmaps}/Live_s1912.json | 0 .../{notes => beatmaps}/Live_s1913.json | 0 .../{notes => beatmaps}/Live_s1914.json | 0 .../{notes => beatmaps}/Live_s1915.json | 0 .../{notes => beatmaps}/Live_s1916.json | 0 .../{notes => beatmaps}/Live_s1917.json | 0 .../{notes => beatmaps}/Live_s1918.json | 0 .../{notes => beatmaps}/Live_s1919.json | 0 .../{notes => beatmaps}/Live_s1920.json | 0 .../{notes => beatmaps}/Live_s1921.json | 0 .../{notes => beatmaps}/Live_s1922.json | 0 .../{notes => beatmaps}/Live_s1923.json | 0 .../{notes => beatmaps}/Live_s1924.json | 0 .../{notes => beatmaps}/Live_s1925.json | 0 .../{notes => beatmaps}/Live_s1926.json | 0 .../{notes => beatmaps}/Live_s1927.json | 0 .../{notes => beatmaps}/Live_s1928.json | 0 .../{notes => beatmaps}/Live_s1929.json | 0 .../{notes => beatmaps}/Live_s1930.json | 0 .../{notes => beatmaps}/Live_s1931.json | 0 .../{notes => beatmaps}/Live_s1932.json | 0 .../{notes => beatmaps}/Live_s1933.json | 0 .../{notes => beatmaps}/Live_s1934.json | 0 .../{notes => beatmaps}/Live_s1935.json | 0 .../{notes => beatmaps}/Live_s1936.json | 0 .../{notes => beatmaps}/Live_s1937.json | 0 .../{notes => beatmaps}/Live_s1938.json | 0 .../{notes => beatmaps}/Live_s1939.json | 0 .../{notes => beatmaps}/Live_s1940.json | 0 .../{notes => beatmaps}/Live_s1941.json | 0 .../{notes => beatmaps}/Live_s1942.json | 0 .../{notes => beatmaps}/Live_s1943.json | 0 .../{notes => beatmaps}/Live_s1944.json | 0 .../{notes => beatmaps}/Live_s1945.json | 0 .../{notes => beatmaps}/Live_s1946.json | 0 .../{notes => beatmaps}/Live_s1947.json | 0 .../{notes => beatmaps}/Live_s1948.json | 0 .../{notes => beatmaps}/Live_s1949.json | 0 .../{notes => beatmaps}/Live_s1950.json | 0 .../{notes => beatmaps}/Live_s1951.json | 0 .../{notes => beatmaps}/Live_s1952.json | 0 .../{notes => beatmaps}/Live_s1953.json | 0 .../{notes => beatmaps}/Live_s1954.json | 0 .../{notes => beatmaps}/Live_s1955.json | 0 .../{notes => beatmaps}/Live_s1956.json | 0 .../{notes => beatmaps}/Live_s1957.json | 0 .../{notes => beatmaps}/Live_s1958.json | 0 .../{notes => beatmaps}/Live_s1959.json | 0 .../{notes => beatmaps}/Live_s1960.json | 0 .../{notes => beatmaps}/Live_s1961.json | 0 .../{notes => beatmaps}/Live_s1962.json | 0 .../{notes => beatmaps}/Live_s1963.json | 0 .../{notes => beatmaps}/Live_s1964.json | 0 .../{notes => beatmaps}/Live_s1965.json | 0 .../{notes => beatmaps}/Live_s1966.json | 0 .../{notes => beatmaps}/Live_s1967.json | 0 .../{notes => beatmaps}/Live_s1968.json | 0 .../{notes => beatmaps}/Live_s1969.json | 0 .../{notes => beatmaps}/Live_s1970.json | 0 .../{notes => beatmaps}/Live_s1971.json | 0 .../{notes => beatmaps}/Live_s1972.json | 0 .../{notes => beatmaps}/Live_s1973.json | 0 .../{notes => beatmaps}/Live_s1974.json | 0 .../{notes => beatmaps}/Live_s1975.json | 0 .../{notes => beatmaps}/Live_s1976.json | 0 .../{notes => beatmaps}/Live_s1977.json | 0 .../{notes => beatmaps}/Live_s1978.json | 0 .../{notes => beatmaps}/Live_s1979.json | 0 .../{notes => beatmaps}/Live_s1980.json | 0 .../{notes => beatmaps}/Live_s1981.json | 0 .../{notes => beatmaps}/Live_s1982.json | 0 .../{notes => beatmaps}/Live_s1983.json | 0 .../{notes => beatmaps}/Live_s1984.json | 0 .../{notes => beatmaps}/Live_s1985.json | 0 .../{notes => beatmaps}/Live_s1986.json | 0 .../{notes => beatmaps}/Live_s1987.json | 0 .../{notes => beatmaps}/Live_s1988.json | 0 .../{notes => beatmaps}/Live_s1989.json | 0 .../{notes => beatmaps}/Live_s1990.json | 0 .../{notes => beatmaps}/Live_s1991.json | 0 .../{notes => beatmaps}/Live_s1992.json | 0 .../{notes => beatmaps}/Live_s1993.json | 0 .../{notes => beatmaps}/Live_s1994.json | 0 .../{notes => beatmaps}/Live_s1995.json | 0 .../{notes => beatmaps}/Live_s1996.json | 0 .../{notes => beatmaps}/Live_s1997.json | 0 .../{notes => beatmaps}/Live_s1998.json | 0 .../{notes => beatmaps}/Live_s1999.json | 0 .../{notes => beatmaps}/Live_s2000.json | 0 .../{notes => beatmaps}/Live_s20001.json | 0 .../{notes => beatmaps}/Live_s20002.json | 0 .../{notes => beatmaps}/Live_s20003.json | 0 .../{notes => beatmaps}/Live_s20004.json | 0 .../{notes => beatmaps}/Live_s20005.json | 0 .../{notes => beatmaps}/Live_s20006.json | 0 .../{notes => beatmaps}/Live_s20007.json | 0 .../{notes => beatmaps}/Live_s20008.json | 0 .../{notes => beatmaps}/Live_s20009.json | 0 .../{notes => beatmaps}/Live_s2001.json | 0 .../{notes => beatmaps}/Live_s20010.json | 0 .../{notes => beatmaps}/Live_s20011.json | 0 .../{notes => beatmaps}/Live_s20012.json | 0 .../{notes => beatmaps}/Live_s20013.json | 0 .../{notes => beatmaps}/Live_s20014.json | 0 .../{notes => beatmaps}/Live_s20015.json | 0 .../{notes => beatmaps}/Live_s2002.json | 0 .../{notes => beatmaps}/Live_s2003.json | 0 .../{notes => beatmaps}/Live_s2004.json | 0 .../{notes => beatmaps}/Live_s2005.json | 0 .../{notes => beatmaps}/Live_s2006.json | 0 .../{notes => beatmaps}/Live_s2007.json | 0 .../{notes => beatmaps}/Live_s2008.json | 0 .../{notes => beatmaps}/Live_s2009.json | 0 .../{notes => beatmaps}/Live_s2010.json | 0 .../{notes => beatmaps}/Live_s2011.json | 0 .../{notes => beatmaps}/Live_s2012.json | 0 .../{notes => beatmaps}/Live_s2013.json | 0 .../{notes => beatmaps}/Live_s2014.json | 0 .../{notes => beatmaps}/Live_s2015.json | 0 .../{notes => beatmaps}/Live_s2016.json | 0 .../{notes => beatmaps}/Live_s2017.json | 0 .../{notes => beatmaps}/Live_s2018.json | 0 .../{notes => beatmaps}/Live_s2019.json | 0 .../{notes => beatmaps}/Live_s2020.json | 0 .../{notes => beatmaps}/Live_s2021.json | 0 .../{notes => beatmaps}/Live_s2022.json | 0 .../{notes => beatmaps}/Live_s2023.json | 0 .../{notes => beatmaps}/Live_s2024.json | 0 .../{notes => beatmaps}/Live_s2025.json | 0 .../{notes => beatmaps}/Live_s2026.json | 0 .../{notes => beatmaps}/Live_s2027.json | 0 .../{notes => beatmaps}/Live_s2028.json | 0 .../{notes => beatmaps}/Live_s2029.json | 0 .../{notes => beatmaps}/Live_s2030.json | 0 .../{notes => beatmaps}/Live_s2031.json | 0 .../{notes => beatmaps}/Live_s2032.json | 0 .../{notes => beatmaps}/Live_s2033.json | 0 .../{notes => beatmaps}/Live_s2034.json | 0 .../{notes => beatmaps}/Live_s2035.json | 0 .../{notes => beatmaps}/Live_s2036.json | 0 .../{notes => beatmaps}/Live_s2037.json | 0 .../{notes => beatmaps}/Live_s2038.json | 0 .../{notes => beatmaps}/Live_s2039.json | 0 .../{notes => beatmaps}/Live_s2040.json | 0 .../{notes => beatmaps}/Live_s2041.json | 0 .../{notes => beatmaps}/Live_s2042.json | 0 .../{notes => beatmaps}/Live_s2043.json | 0 .../{notes => beatmaps}/Live_s2044.json | 0 config/config.go | 32 +- .../handler/{album.go => album/seriesall.go} | 53 +- internal/handler/announce/checkstate.go | 29 + .../{announce.go => announce/index.go} | 24 +- internal/handler/api.go | 1324 ----------------- internal/handler/api/album/album.go | 17 + internal/handler/api/album/all.go | 70 + internal/handler/api/api.go | 125 ++ internal/handler/api/award/award.go | 17 + internal/handler/api/award/info.go | 49 + internal/handler/api/background/background.go | 17 + internal/handler/api/background/info.go | 49 + internal/handler/api/banner/banner.go | 13 + internal/handler/api/banner/list.go | 76 + internal/handler/api/challenge/challenge.go | 15 + internal/handler/api/challenge/info.go | 16 + internal/handler/api/costume/costume.go | 13 + internal/handler/api/costume/list.go | 19 + .../api/eventscenario/eventscenario.go | 17 + internal/handler/api/eventscenario/status.go | 80 + internal/handler/api/exchange/exchange.go | 17 + internal/handler/api/exchange/owningpoint.go | 37 + internal/handler/api/item/item.go | 13 + internal/handler/api/item/list.go | 13 + internal/handler/api/live/live.go | 19 + internal/handler/api/live/schedule.go | 57 + internal/handler/api/live/status.go | 64 + internal/handler/api/liveicon/info.go | 19 + internal/handler/api/liveicon/liveicon.go | 13 + internal/handler/api/livese/info.go | 19 + internal/handler/api/livese/livese.go | 13 + internal/handler/api/login/login.go | 17 + internal/handler/api/login/topinfo.go | 44 + internal/handler/api/login/topinfoonce.go | 39 + internal/handler/api/marathon/info.go | 17 + internal/handler/api/marathon/marathon.go | 13 + internal/handler/api/multiunit/multiunit.go | 17 + .../handler/api/multiunit/scenariostatus.go | 62 + internal/handler/api/museum/info.go | 51 + internal/handler/api/museum/museum.go | 17 + internal/handler/api/navigation/navigation.go | 15 + .../handler/api/navigation/specialcutin.go | 19 + internal/handler/api/notice/marquee.go | 20 + internal/handler/api/notice/notice.go | 13 + internal/handler/api/payment/payment.go | 13 + internal/handler/api/payment/productlist.go | 31 + internal/handler/api/profile/cardranking.go | 26 + internal/handler/api/profile/info.go | 188 +++ internal/handler/api/profile/livecnt.go | 38 + internal/handler/api/profile/profile.go | 21 + internal/handler/api/scenario/scenario.go | 17 + internal/handler/api/scenario/status.go | 37 + internal/handler/api/stamp/info.go | 13 + internal/handler/api/stamp/stamp.go | 13 + internal/handler/api/subscenario/status.go | 38 + .../handler/api/subscenario/subscenario.go | 17 + internal/handler/api/unit/accessoryall.go | 43 + internal/handler/api/unit/all.go | 38 + internal/handler/api/unit/deckinfo.go | 55 + .../handler/api/unit/removableskillinfo.go | 76 + internal/handler/api/unit/supporterall.go | 19 + internal/handler/api/unit/unit.go | 25 + internal/handler/api/user/getnavi.go | 33 + internal/handler/api/user/info.go | 58 + internal/handler/api/user/user.go | 19 + internal/handler/award.go | 33 - internal/handler/award/set.go | 37 + internal/handler/background.go | 33 - internal/handler/background/set.go | 37 + internal/handler/download.go | 196 --- internal/handler/download/additional.go | 58 + internal/handler/download/batch.go | 55 + internal/handler/download/event.go | 25 + internal/handler/download/update.go | 72 + internal/handler/download/url.go | 48 + internal/handler/event.go | 32 - internal/handler/event/list.go | 45 + internal/handler/gdpr.go | 26 - internal/handler/gdpr/get.go | 30 + internal/handler/ghome/account/active.go | 27 + internal/handler/ghome/account/initialize.go | 50 + internal/handler/ghome/account/login.go | 248 +++ internal/handler/ghome/account/loginauto.go | 83 ++ internal/handler/ghome/account/reportrole.go | 33 + internal/handler/ghome/basic/getcode.go | 33 + .../handler/ghome/basic/getproductlist.go | 29 + internal/handler/ghome/basic/handshake.go | 60 + internal/handler/ghome/basic/loginarea.go | 26 + internal/handler/ghome/basic/publickey.go | 45 + internal/handler/ghome/ghome.go | 8 + internal/handler/ghome/guest/status.go | 29 + internal/handler/ghome/misc/agreement.go | 25 + internal/handler/ghome/misc/integration.go | 26 + internal/handler/ghome/misc/report.go | 16 + internal/handler/handler.go | 27 +- .../handler/{lbonus.go => lbonus/execute.go} | 52 +- internal/handler/live/gameover.go | 25 + internal/handler/live/partylist.go | 29 + internal/handler/{live.go => live/play.go} | 379 +---- internal/handler/live/precisescore.go | 111 ++ internal/handler/live/reward.go | 213 +++ internal/handler/login.go | 62 - internal/handler/login/authkey.go | 66 + internal/handler/login/login.go | 88 ++ internal/handler/multiunit.go | 33 - internal/handler/multiunit/scenariostartup.go | 37 + .../handler/{museum.go => museum/info.go} | 36 +- internal/handler/notice.go | 61 - internal/handler/notice/friendgreeting.go | 30 + internal/handler/notice/friendvariety.go | 30 + .../handler/notice/usergreetinghistory.go | 31 + internal/handler/payment.go | 37 - internal/handler/payment/productlist.go | 44 + internal/handler/personalnotice.go | 29 - internal/handler/personalnotice/get.go | 35 + internal/handler/private.go | 495 ------ internal/handler/profile.go | 33 - internal/handler/profile/register.go | 37 + internal/handler/scenario.go | 48 - internal/handler/scenario/reward.go | 29 + internal/handler/scenario/startup.go | 37 + internal/handler/subscenario.go | 48 - internal/handler/subscenario/reward.go | 29 + internal/handler/subscenario/startup.go | 37 + internal/handler/tos.go | 27 - internal/handler/tos/check.go | 31 + internal/handler/unit.go | 275 ---- internal/handler/unit/deck.go | 129 ++ internal/handler/unit/deckname.go | 49 + internal/handler/unit/favorite.go | 25 + .../handler/unit/removableskillequipment.go | 57 + internal/handler/unit/setdisplayrank.go | 25 + internal/handler/unit/wearaccessory.go | 57 + internal/handler/user.go | 81 - internal/handler/user/changename.go | 47 + internal/handler/user/changenavi.go | 36 + internal/handler/user/setnotificationtoken.go | 25 + internal/handler/user/userinfo.go | 72 + internal/handler/userinfo.go | 77 - internal/handler/webui/login.go | 61 + internal/handler/webui/logout.go | 26 + .../handler/{webui.go => webui/upload.go} | 77 +- internal/handler/webui/webui.go | 28 + internal/middleware/authkey.go | 54 - internal/middleware/common.go | 74 +- internal/middleware/login.go | 45 - internal/middleware/multipart.go | 34 - internal/model/album.go | 35 - internal/model/announce.go | 14 - internal/model/authkey.go | 14 - internal/model/award.go | 28 - internal/model/background.go | 28 - internal/model/costume.go | 21 - internal/model/download.go | 102 -- internal/model/event.go | 20 - internal/model/exchange.go | 20 - internal/model/lbonus.go | 84 -- internal/model/multiunit.go | 55 - internal/model/museum.go | 40 - internal/model/navigation.go | 14 - internal/model/notice.go | 58 - internal/model/payment.go | 154 -- internal/model/personalnotice.go | 18 - internal/model/scenario.go | 98 -- internal/model/topinfo.go | 78 - internal/model/tos.go | 16 - internal/model/unit.go | 316 ---- internal/model/user.go | 48 - internal/model/user/useraccessorywear.go | 12 + internal/model/user/userdeck.go | 14 + internal/model/user/userdeckunit.go | 25 + internal/model/user/userkey.go | 11 + internal/model/user/userpref.go | 18 + internal/model/user/users.go | 15 + internal/model/user/userunit.go | 34 + internal/model/user/userunitskillequip.go | 12 + internal/router/router.go | 201 ++- internal/schema/album/seriesall.go | 24 + internal/schema/announce/checkstate.go | 12 + internal/schema/api/album/all.go | 20 + internal/{model => schema/api}/api.go | 12 +- internal/schema/api/award/info.go | 18 + internal/schema/api/background/info.go | 18 + .../banner.go => schema/api/banner/list.go} | 17 +- .../api/challenge/info.go} | 5 +- internal/schema/api/costume/list.go | 18 + internal/schema/api/eventscenario/status.go | 31 + internal/schema/api/exchange/owningpoint.go | 17 + internal/schema/api/live/schedule.go | 45 + internal/schema/api/live/status.go | 44 + internal/schema/api/liveicon/info.go | 12 + internal/schema/api/livese/info.go | 12 + internal/schema/api/login/topinfo.go | 39 + internal/schema/api/login/topinfoonce.go | 34 + .../api/marathon/info.go} | 5 +- .../schema/api/multiunit/scenariostatus.go | 27 + internal/schema/api/museum/info.go | 23 + .../schema/api/navigation/specialcutin.go | 12 + internal/schema/api/notice/marquee.go | 13 + internal/schema/api/payment/productlist.go | 120 ++ internal/schema/api/profile/cardranking.go | 8 + .../tools.go => schema/api/profile/info.go} | 96 +- internal/schema/api/profile/livecnt.go | 13 + internal/schema/api/scenario/status.go | 17 + internal/schema/api/subscenario/status.go | 18 + internal/schema/api/unit/accessoryall.go | 30 + internal/schema/api/unit/all.go | 75 + internal/schema/api/unit/deckinfo.go | 49 + .../schema/api/unit/removableskillinfo.go | 41 + internal/schema/api/unit/supporterall.go | 17 + internal/schema/api/user/getnavi.go | 17 + .../userinfo.go => schema/api/user/info.go} | 27 +- .../{model/profile.go => schema/award/set.go} | 5 +- internal/schema/background/set.go | 7 + internal/schema/download/additional.go | 23 + internal/schema/download/batch.go | 20 + internal/schema/download/event.go | 7 + internal/schema/download/update.go | 24 + internal/schema/download/url.go | 19 + internal/schema/event/list.go | 17 + .../{model/gdpr.go => schema/gdpr/get.go} | 18 +- internal/schema/ghome/account.go | 104 ++ internal/schema/ghome/basic.go | 47 + internal/schema/ghome/guest.go | 14 + internal/schema/ghome/misc.go | 21 + internal/schema/lbonus/execute.go | 103 ++ internal/schema/live/gameover.go | 7 + internal/schema/live/play.go | 84 ++ internal/schema/live/precisescore.go | 48 + .../{model/live.go => schema/live/reward.go} | 328 +--- internal/schema/login/authkey.go | 12 + internal/{model => schema/login}/login.go | 12 +- internal/schema/multiunit/scenariostartup.go | 22 + internal/schema/museum/info.go | 23 + internal/schema/notice/friendgreeting.go | 13 + internal/schema/notice/friendvariety.go | 13 + internal/schema/notice/usergreetinghistory.go | 14 + internal/schema/payment/productlist.go | 19 + internal/schema/personalnotice/get.go | 16 + internal/schema/profile/register.go | 7 + internal/schema/scenario/startup.go | 22 + .../subscenario/startup.go} | 31 +- internal/schema/tos/check.go | 14 + internal/schema/unit/deck.go | 26 + internal/schema/unit/deckname.go | 11 + internal/schema/unit/favorite.go | 7 + .../schema/unit/removableskillequipment.go | 34 + internal/schema/unit/setdisplayrank.go | 7 + internal/schema/unit/wearaccessory.go | 34 + internal/schema/user/changename.go | 13 + internal/schema/user/changenavi.go | 7 + internal/schema/user/setnotificationtoken.go | 7 + internal/schema/user/userinfo.go | 20 + internal/{model => schema/webui}/webui.go | 3 +- internal/session/session.go | 49 +- internal/startup/database.go | 18 + internal/startup/startup.go | 6 + .../{tools/init.go => startup/userdata.go} | 82 +- internal/utils/utils.go | 8 - main.go | 11 +- pkg/db/db.go | 22 +- pkg/db/leveldb.go | 12 +- {internal => pkg}/tools/tools.go | 1 - pkg/utils/utils.go | 13 +- {assets/static => static}/.gitignore | 0 {assets/static => static}/css/base.css | 0 {assets/static => static}/css/layui.css | 0 .../css/ll-perfect-scrollbar.css | 0 .../css/perfect-scrollbar.css | 0 {assets/static => static}/css/style.css | 0 {assets/static => static}/css/window.css | 0 {assets/static => static}/font/iconfont.eot | Bin {assets/static => static}/font/iconfont.svg | 0 {assets/static => static}/font/iconfont.ttf | Bin {assets/static => static}/font/iconfont.woff | Bin {assets/static => static}/font/iconfont.woff2 | Bin .../images/15047550942873.jpg | Bin .../images/15047551059201.jpg | Bin .../images/15047551145790.jpg | Bin .../images/15047551242040.jpg | Bin .../images/15047553374283.jpg | Bin .../images/15047553496606.jpg | Bin .../images/15047553611357.jpg | Bin .../images/15047553728636.jpg | Bin .../images/15047553849518.jpg | Bin .../images/15047553982300.jpg | Bin .../images/15047554108052.jpg | Bin .../images/15047554203428.jpg | Bin .../images/15047554315307.jpg | Bin .../images/15047554481319.jpg | Bin .../images/15047554596230.jpg | Bin .../images/15047554774569.jpg | Bin .../images/15047554922924.jpg | Bin .../images/15047555087747.jpg | Bin .../images/15047555219572.jpg | Bin .../images/15047555411780.jpg | Bin .../images/15047555499746.jpg | Bin .../images/15047555585712.jpg | Bin .../images/15047555704112.jpg | Bin .../images/15047555798773.jpg | Bin .../images/15047555888980.jpg | Bin .../images/15088959186072.jpg | Bin .../images/15107324142966.png | Bin .../images/15141856059568.jpg | Bin .../images/15141862776588.jpg | Bin .../images/15141862946556.jpg | Bin .../images/15141863126912.jpg | Bin .../images/15141863229129.jpg | Bin .../images/15141863365919.jpg | Bin .../images/15141863483422.jpg | Bin .../images/15141863639911.jpg | Bin .../images/15141863772178.jpg | Bin .../images/15141864261972.jpg | Bin .../images/15141864584520.jpg | Bin .../images/15141864695842.jpg | Bin .../images/15141864804128.jpg | Bin .../images/15141864889884.jpg | Bin .../images/15141865055652.jpg | Bin .../images/15141865133555.jpg | Bin .../images/15141865196092.jpg | Bin .../images/15238681581968.png | Bin .../images/15238694807202.png | Bin .../images/15238694919055.png | Bin .../images/15238695116848.png | Bin .../images/15238695303404.png | Bin .../images/15238695455400.png | Bin .../images/15238695587056.png | Bin .../images/15238695641197.png | Bin .../images/15238701747409.png | Bin .../images/15238702168776.png | Bin .../images/admin/ic_launcher.png | Bin .../static => static}/images/admin/top-bg.jpg | Bin .../images/admin/top-bg_2.jpg | Bin {assets/static => static}/images/bg-left.png | Bin {assets/static => static}/images/bg-right.png | Bin static/images/favicon.ico | Bin 0 -> 48710 bytes .../images/list-content-bg-on.png | Bin .../images/list-content-bg.png | Bin .../static => static}/images/title-banner.png | Bin {assets/static => static}/js/button.js | 0 {assets/static => static}/js/layui.js | 0 .../js/perfect-scrollbar.min.js | 0 .../templates/admin/card.html | 2 +- .../templates/admin/index.html | 2 +- .../templates/admin/login.html | 2 +- .../templates/admin/nav/css.html | 3 +- .../templates/admin/nav/footer.html | 2 +- .../templates/admin/nav/header.html | 2 +- .../templates/admin/nav/side.html | 0 .../templates/admin/upload.html | 2 +- .../templates/common/announce.html | 0 .../templates/common/manga.html | 0 2267 files changed, 7158 insertions(+), 5583 deletions(-) create mode 100644 assets/.gitignore delete mode 100644 assets/data.example.db rename assets/serverdata/{notes => beatmaps}/Live_0001.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0002.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0003.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0004.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0005.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0006.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0007.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0008.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0009.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0010.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0011.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0012.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0013.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0014.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0015.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0016.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0017.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0018.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0019.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0020.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0021.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0022.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0023.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0024.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0025.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0026.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0027.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0028.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0029.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0030.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0037.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0038.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0039.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0040.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0041.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0042.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0046.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0047.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0048.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0049.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0050.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0051.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0052.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0053.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0054.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0055.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0056.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0057.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0058.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0059.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0060.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0061.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0062.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0063.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0068.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0069.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0070.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0071.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0072.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0073.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0074.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0075.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0076.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0077.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0078.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0079.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0080.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0081.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0082.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0083.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0084.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0088.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0089.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0090.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0091.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0092.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0096.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0097.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0098.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0099.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0104.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0112.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0113.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0114.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0115.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0116.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0124.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0125.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0126.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0127.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0128.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0129.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0148.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0149.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0150.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0151.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0152.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0181.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0182.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0183.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0259.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0260.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0261.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0262.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0270.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0271.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0272.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0303.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0304.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0305.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0306.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0314.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0315.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0316.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0346.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0347.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0348.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0349.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0350.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0358.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0359.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0360.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0390.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0391.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0392.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0393.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0402.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0403.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0404.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0413.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0414.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0415.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0416.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0425.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0426.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0427.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0436.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0437.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0438.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0439.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0440.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0441.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0442.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0443.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0444.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0445.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0446.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0455.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0456.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0457.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0458.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0459.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0460.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0461.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0462.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0463.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0475.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0476.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0477.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0478.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0479.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0480.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0481.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0482.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0483.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0484.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0485.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0486.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0487.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0496.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0497.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0498.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0507.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0508.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0509.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0510.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0511.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0520.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0521.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0522.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0534.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0535.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0536.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0537.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0538.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0539.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0540.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0549.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0550.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0551.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0552.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0561.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0562.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0563.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0564.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0565.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0566.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0567.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0568.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0569.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0578.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0579.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0580.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0589.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0590.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0591.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0592.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0593.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0594.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0601.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0603.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0604.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0605.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0606.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0615.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0616.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0617.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0618.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0619.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0620.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0621.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0628.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0630.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0631.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0632.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0633.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0634.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0635.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0636.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0648.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0649.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0650.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0651.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0652.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0659.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0661.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0662.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0663.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0664.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0665.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0666.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0678.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0679.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0680.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0681.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0688.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0690.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0691.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0692.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0693.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0702.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0703.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0704.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0705.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0706.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0707.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0708.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0709.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0713.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0714.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0715.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0716.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0718.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0719.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0720.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0721.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0749.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0750.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0751.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0752.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0753.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0754.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0755.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0756.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0763.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0765.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0766.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0767.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0768.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0791.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0792.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0793.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0794.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0797.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0798.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0799.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0803.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0804.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0805.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0806.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0810.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0811.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0812.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0813.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0814.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0831.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0832.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0833.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0834.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0835.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0836.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0837.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0838.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0842.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0843.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0844.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0845.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0849.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0850.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0851.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0852.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0866.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0867.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0868.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0869.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0871.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0872.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0873.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_0874.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0361.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0362.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0363.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0364.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0365.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0371.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0372.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0373.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0374.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0375.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0376.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0377.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0378.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0385.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0386.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0387.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0388.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0389.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0390.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0391.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0392.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0393.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0394.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0395.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0396.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0397.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0398.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0399.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0400.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0401.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0402.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0405.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0406.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0407.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0408.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0409.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0410.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0411.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0412.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0413.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0414.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0415.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0416.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0417.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0418.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0419.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0420.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0421.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0432.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0433.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0434.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0435.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0436.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0437.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0438.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0439.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0440.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0441.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0442.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0443.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0444.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0445.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0446.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0453.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0454.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0455.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0456.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0457.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0458.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0459.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0460.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0461.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0462.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0463.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0464.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0465.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0466.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0467.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0468.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0469.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0470.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0471.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0472.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0473.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0482.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0483.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0484.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0485.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0486.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0487.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0488.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0489.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0490.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0491.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0492.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0493.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0494.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0495.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0496.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0497.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0498.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0499.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0500.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0501.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0502.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0503.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0504.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0505.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0506.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0507.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0508.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0509.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0510.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0511.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0512.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0513.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0514.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0515.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0516.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0517.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0518.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0519.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0520.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0521.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0522.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0523.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0524.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0525.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0526.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0527.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0528.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0529.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0530.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0531.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0532.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0533.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0534.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0535.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0536.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0537.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0538.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0539.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0551.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0552.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0553.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0554.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0555.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0556.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0557.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0558.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0559.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0560.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0561.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0562.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0563.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0564.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0565.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0566.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0567.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0568.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0569.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0570.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0571.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0572.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0573.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0574.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0575.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0576.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0577.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0578.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0579.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0580.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0581.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0582.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0583.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0584.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0585.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0586.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0587.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0588.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0589.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0596.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0597.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0598.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0599.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0600.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0601.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0602.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0603.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0604.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0605.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0606.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0607.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0608.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0609.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0610.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0611.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0612.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0613.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0614.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0615.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0616.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0617.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0618.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0619.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0620.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0621.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0622.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0623.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0624.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0625.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0626.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0627.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0628.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0629.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0630.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0631.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0632.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0633.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0634.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0641.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0642.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0643.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0644.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0645.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0646.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0647.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0648.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0649.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0650.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0651.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0652.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0653.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0654.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0655.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0656.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0657.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0658.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0659.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0660.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0661.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0662.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0663.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0664.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0665.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0666.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0667.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0668.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0669.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0670.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0671.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0672.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0673.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0677.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0678.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0679.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0680.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0681.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0682.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0683.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0684.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0685.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0686.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0687.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0688.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0689.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0690.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0691.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0692.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0693.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0694.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0695.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0696.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0697.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0698.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0699.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0700.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0703.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0704.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0705.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0706.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0707.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0708.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0709.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0710.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0711.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0712.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0713.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0714.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0715.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0716.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0717.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0718.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0719.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0720.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0721.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0722.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0725.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0726.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0727.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0728.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0729.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0730.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0731.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0732.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0733.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0734.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0735.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0736.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0737.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0738.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0739.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0740.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0741.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0742.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0743.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0744.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0745.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0746.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0747.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0748.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0749.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0750.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0751.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0764.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0765.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0766.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0767.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0768.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0769.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0770.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0771.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0772.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0773.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0774.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0775.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0776.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0777.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0778.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0779.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0780.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0781.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0782.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0783.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0784.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0785.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0786.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0787.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0788.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0789.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0790.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0791.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0792.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0793.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0794.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0795.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0802.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0803.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0804.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0805.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0806.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0807.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0808.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0809.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0810.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0811.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0812.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0813.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0814.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0815.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0816.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0817.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0818.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0819.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0820.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0821.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0822.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0823.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0824.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0825.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0826.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0827.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0828.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0829.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0830.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0831.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0832.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0833.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0834.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0835.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0836.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0837.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0838.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0839.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0840.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0841.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0842.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0843.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0844.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0845.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0846.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0847.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0848.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0849.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0850.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0851.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0852.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0853.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0854.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0855.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0856.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0857.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0858.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0859.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0860.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0863.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0864.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0865.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0866.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0867.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0868.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0869.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0870.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0871.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0872.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0873.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0874.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0875.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0876.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0877.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0878.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0879.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0880.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0881.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0882.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0883.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0884.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0885.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0886.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0887.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0888.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0889.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0890.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0891.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0892.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0893.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0894.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0895.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0896.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0897.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0898.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0899.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0900.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0901.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0902.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0903.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0904.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0905.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0906.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0907.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0908.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0909.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0910.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0911.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0912.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0913.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0914.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0915.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0916.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0917.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0918.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0919.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0920.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0921.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0922.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0923.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0924.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0925.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0926.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0927.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0928.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0929.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0930.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0931.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0932.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0933.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0934.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0935.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0936.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0937.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0938.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0939.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0940.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0941.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0942.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0943.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0944.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0945.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0946.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0947.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0948.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0949.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0950.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0951.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0952.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0953.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0954.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0955.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0956.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0957.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0958.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0959.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0960.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0961.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0962.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0963.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0964.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0965.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0966.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0967.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0968.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0969.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0970.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0971.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0972.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0973.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0974.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0975.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0976.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0977.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0978.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0979.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0980.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0981.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0982.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0983.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0984.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0985.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0986.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0987.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0988.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0989.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0990.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0991.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0992.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0993.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0994.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0995.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0996.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0997.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0998.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s0999.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1000.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1001.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1002.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1003.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1004.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1005.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1006.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1007.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1008.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1009.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1010.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1011.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1012.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1013.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1014.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1015.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1016.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1017.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1018.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1019.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1020.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1021.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1022.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1023.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1024.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1025.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1026.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1027.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1028.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1029.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1030.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1031.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1032.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1033.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1034.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1035.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1036.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1037.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1038.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1039.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1040.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1041.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1042.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1043.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1044.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1045.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1046.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1047.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1048.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1049.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1050.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1051.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1052.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1053.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1054.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1055.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1056.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1057.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1058.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1059.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1060.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1061.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1062.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1063.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1064.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1065.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1066.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1067.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1068.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1069.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1070.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1071.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1072.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1073.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1074.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1075.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1076.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1077.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1078.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1079.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1080.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1081.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1082.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1083.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1084.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1085.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1086.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1087.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1088.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1089.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1090.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1091.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1092.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1093.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1094.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1095.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1096.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1097.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1098.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1099.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1100.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1101.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1102.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1103.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1104.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1105.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1106.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1107.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1108.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1109.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1110.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1111.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1112.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1113.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1114.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1115.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1116.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1117.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1118.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1119.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1120.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1121.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1122.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1123.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1124.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1125.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1126.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1127.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1128.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1129.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1130.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1131.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1132.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1133.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1134.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1135.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1136.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1137.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1138.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1139.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1140.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1141.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1142.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1143.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1144.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1145.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1146.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1147.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1148.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1149.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1150.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1151.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1152.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1153.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1154.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1155.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1156.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1157.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1158.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1159.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1160.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1161.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1162.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1163.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1164.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1165.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1166.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1167.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1168.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1169.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1170.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1171.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1172.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1173.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1174.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1175.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1176.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1177.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1178.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1179.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1180.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1181.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1182.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1183.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1184.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1185.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1186.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1187.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1188.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1189.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1190.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1191.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1192.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1193.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1194.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1195.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1196.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1197.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1198.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1199.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1200.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1201.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1202.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1203.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1204.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1205.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1206.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1207.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1208.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1209.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1210.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1211.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1212.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1213.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1214.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1215.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1216.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1217.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1218.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1219.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1220.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1221.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1222.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1223.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1224.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1225.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1226.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1227.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1228.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1229.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1230.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1231.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1232.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1233.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1234.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1235.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1236.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1237.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1238.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1239.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1240.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1241.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1242.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1243.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1244.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1245.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1246.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1247.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1248.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1249.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1250.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1251.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1252.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1253.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1254.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1255.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1256.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1257.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1258.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1259.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1260.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1261.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1262.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1263.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1264.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1265.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1266.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1267.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1268.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1269.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1270.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1271.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1272.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1273.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1274.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1275.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1276.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1277.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1278.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1279.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1280.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1281.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1282.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1283.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1284.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1285.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1286.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1287.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1288.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1289.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1290.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1291.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1292.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1293.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1294.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1295.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1296.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1297.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1298.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1299.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1300.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1301.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1302.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1303.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1304.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1305.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1306.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1307.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1308.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1309.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1310.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1311.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1312.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1313.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1314.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1315.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1316.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1317.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1318.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1319.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1320.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1321.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1322.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1323.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1324.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1325.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1326.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1327.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1328.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1329.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1330.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1331.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1332.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1333.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1334.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1335.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1336.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1337.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1338.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1339.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1340.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1341.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1342.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1343.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1344.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1345.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1346.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1347.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1348.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1349.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1350.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1351.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1352.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1353.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1354.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1355.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1356.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1357.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1358.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1359.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1360.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1361.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1362.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1363.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1364.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1365.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1366.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1367.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1368.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1369.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1370.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1371.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1372.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1373.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1374.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1375.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1376.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1377.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1378.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1379.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1380.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1381.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1382.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1383.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1384.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1385.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1386.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1387.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1388.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1389.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1390.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1391.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1392.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1393.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1394.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1395.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1396.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1397.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1398.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1399.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1400.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1401.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1402.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1403.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1404.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1405.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1406.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1407.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1408.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1409.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1410.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1411.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1412.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1413.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1414.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1415.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1416.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1417.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1418.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1419.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1420.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1421.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1422.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1423.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1424.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1425.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1426.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1427.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1428.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1429.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1430.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1431.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1432.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1433.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1434.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1435.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1436.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1437.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1438.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1439.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1440.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1441.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1442.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1443.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1444.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1445.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1446.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1447.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1448.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1449.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1450.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1451.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1452.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1453.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1454.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1455.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1456.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1457.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1458.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1459.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1460.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1461.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1462.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1463.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1464.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1465.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1466.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1467.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1468.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1469.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1470.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1471.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1472.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1473.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1474.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1475.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1476.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1477.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1478.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1479.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1480.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1481.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1482.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1483.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1484.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1485.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1486.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1487.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1488.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1489.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1490.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1491.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1492.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1493.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1494.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1495.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1496.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1497.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1498.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1499.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1500.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1501.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1502.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1503.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1504.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1505.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1506.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1507.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1508.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1509.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1510.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1511.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1512.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1513.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1514.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1515.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1516.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1517.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1518.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1519.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1520.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1521.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1522.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1523.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1524.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1525.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1526.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1527.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1528.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1529.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1530.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1531.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1532.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1533.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1534.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1535.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1536.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1537.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1538.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1539.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1540.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1541.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1542.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1543.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1544.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1545.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1546.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1547.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1548.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1549.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1550.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1551.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1552.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1553.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1554.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1555.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1556.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1557.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1558.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1559.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1560.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1561.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1562.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1563.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1564.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1565.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1566.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1567.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1568.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1569.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1570.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1571.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1572.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1573.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1574.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1575.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1576.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1577.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1578.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1579.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1580.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1581.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1582.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1583.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1584.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1585.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1586.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1587.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1588.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1589.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1590.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1591.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1592.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1593.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1594.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1595.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1596.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1597.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1598.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1599.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1600.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1601.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1602.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1603.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1604.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1605.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1606.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1607.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1608.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1609.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1610.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1611.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1613.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1614.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1615.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1616.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1617.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1618.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1619.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1622.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1623.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1625.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1626.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1627.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1630.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1631.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1632.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1633.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1634.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1635.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1636.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1637.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1638.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1639.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1640.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1641.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1642.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1643.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1644.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1646.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1647.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1648.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1649.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1650.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1651.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1652.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1655.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1656.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1658.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1659.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1660.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1663.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1664.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1665.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1666.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1667.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1668.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1670.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1671.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1672.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1673.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1674.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1675.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1676.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1679.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1680.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1682.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1683.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1684.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1687.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1688.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1689.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1690.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1691.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1692.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1693.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1694.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1695.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1696.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1697.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1698.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1699.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1700.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1701.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1702.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1703.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1704.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1705.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1706.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1708.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1709.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1710.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1711.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1712.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1713.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1714.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1715.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1716.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1717.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1718.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1719.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1720.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1721.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1722.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1723.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1724.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1725.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1726.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1727.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1728.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1729.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1730.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1731.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1732.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1733.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1734.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1735.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1736.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1737.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1738.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1739.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1740.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1741.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1742.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1743.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1744.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1745.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1746.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1747.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1748.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1749.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1750.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1751.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1752.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1753.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1754.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1755.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1756.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1757.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1758.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1759.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1760.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1761.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1762.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1763.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1764.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1765.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1766.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1767.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1768.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1769.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1770.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1771.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1772.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1773.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1774.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1775.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1776.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1777.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1778.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1779.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1780.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1781.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1782.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1783.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1784.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1785.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1786.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1787.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1788.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1789.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1790.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1791.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1792.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1793.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1794.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1795.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1796.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1797.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1798.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1799.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1800.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1801.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1802.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1803.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1804.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1805.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1806.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1807.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1808.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1809.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1810.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1811.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1812.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1813.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1814.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1815.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1816.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1817.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1818.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1819.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1820.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1821.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1822.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1823.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1824.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1825.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1826.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1827.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1828.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1829.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1830.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1831.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1832.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1833.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1834.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1835.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1836.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1837.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1838.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1839.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1840.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1841.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1842.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1843.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1844.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1845.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1846.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1847.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1848.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1849.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1850.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1851.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1852.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1853.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1854.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1855.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1856.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1857.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1858.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1859.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1860.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1861.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1862.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1863.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1864.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1865.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1866.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1867.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1868.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1869.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1870.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1871.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1872.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1873.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1874.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1875.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1876.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1877.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1878.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1879.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1880.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1881.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1882.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1883.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1884.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1885.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1886.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1887.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1888.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1889.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1890.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1891.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1892.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1893.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1894.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1895.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1896.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1897.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1898.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1899.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1900.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1901.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1902.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1903.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1904.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1905.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1906.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1907.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1908.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1909.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1910.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1911.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1912.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1913.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1914.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1915.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1916.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1917.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1918.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1919.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1920.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1921.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1922.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1923.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1924.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1925.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1926.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1927.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1928.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1929.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1930.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1931.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1932.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1933.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1934.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1935.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1936.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1937.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1938.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1939.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1940.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1941.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1942.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1943.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1944.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1945.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1946.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1947.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1948.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1949.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1950.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1951.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1952.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1953.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1954.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1955.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1956.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1957.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1958.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1959.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1960.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1961.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1962.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1963.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1964.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1965.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1966.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1967.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1968.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1969.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1970.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1971.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1972.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1973.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1974.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1975.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1976.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1977.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1978.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1979.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1980.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1981.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1982.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1983.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1984.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1985.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1986.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1987.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1988.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1989.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1990.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1991.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1992.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1993.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1994.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1995.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1996.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1997.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1998.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s1999.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2000.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20001.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20002.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20003.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20004.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20005.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20006.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20007.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20008.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20009.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2001.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20010.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20011.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20012.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20013.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20014.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s20015.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2002.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2003.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2004.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2005.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2006.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2007.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2008.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2009.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2010.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2011.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2012.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2013.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2014.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2015.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2016.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2017.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2018.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2019.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2020.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2021.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2022.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2023.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2024.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2025.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2026.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2027.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2028.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2029.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2030.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2031.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2032.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2033.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2034.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2035.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2036.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2037.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2038.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2039.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2040.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2041.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2042.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2043.json (100%) rename assets/serverdata/{notes => beatmaps}/Live_s2044.json (100%) rename internal/handler/{album.go => album/seriesall.go} (56%) create mode 100644 internal/handler/announce/checkstate.go rename internal/handler/{announce.go => announce/index.go} (58%) delete mode 100644 internal/handler/api.go create mode 100644 internal/handler/api/album/album.go create mode 100644 internal/handler/api/album/all.go create mode 100644 internal/handler/api/api.go create mode 100644 internal/handler/api/award/award.go create mode 100644 internal/handler/api/award/info.go create mode 100644 internal/handler/api/background/background.go create mode 100644 internal/handler/api/background/info.go create mode 100644 internal/handler/api/banner/banner.go create mode 100644 internal/handler/api/banner/list.go create mode 100644 internal/handler/api/challenge/challenge.go create mode 100644 internal/handler/api/challenge/info.go create mode 100644 internal/handler/api/costume/costume.go create mode 100644 internal/handler/api/costume/list.go create mode 100644 internal/handler/api/eventscenario/eventscenario.go create mode 100644 internal/handler/api/eventscenario/status.go create mode 100644 internal/handler/api/exchange/exchange.go create mode 100644 internal/handler/api/exchange/owningpoint.go create mode 100644 internal/handler/api/item/item.go create mode 100644 internal/handler/api/item/list.go create mode 100644 internal/handler/api/live/live.go create mode 100644 internal/handler/api/live/schedule.go create mode 100644 internal/handler/api/live/status.go create mode 100644 internal/handler/api/liveicon/info.go create mode 100644 internal/handler/api/liveicon/liveicon.go create mode 100644 internal/handler/api/livese/info.go create mode 100644 internal/handler/api/livese/livese.go create mode 100644 internal/handler/api/login/login.go create mode 100644 internal/handler/api/login/topinfo.go create mode 100644 internal/handler/api/login/topinfoonce.go create mode 100644 internal/handler/api/marathon/info.go create mode 100644 internal/handler/api/marathon/marathon.go create mode 100644 internal/handler/api/multiunit/multiunit.go create mode 100644 internal/handler/api/multiunit/scenariostatus.go create mode 100644 internal/handler/api/museum/info.go create mode 100644 internal/handler/api/museum/museum.go create mode 100644 internal/handler/api/navigation/navigation.go create mode 100644 internal/handler/api/navigation/specialcutin.go create mode 100644 internal/handler/api/notice/marquee.go create mode 100644 internal/handler/api/notice/notice.go create mode 100644 internal/handler/api/payment/payment.go create mode 100644 internal/handler/api/payment/productlist.go create mode 100644 internal/handler/api/profile/cardranking.go create mode 100644 internal/handler/api/profile/info.go create mode 100644 internal/handler/api/profile/livecnt.go create mode 100644 internal/handler/api/profile/profile.go create mode 100644 internal/handler/api/scenario/scenario.go create mode 100644 internal/handler/api/scenario/status.go create mode 100644 internal/handler/api/stamp/info.go create mode 100644 internal/handler/api/stamp/stamp.go create mode 100644 internal/handler/api/subscenario/status.go create mode 100644 internal/handler/api/subscenario/subscenario.go create mode 100644 internal/handler/api/unit/accessoryall.go create mode 100644 internal/handler/api/unit/all.go create mode 100644 internal/handler/api/unit/deckinfo.go create mode 100644 internal/handler/api/unit/removableskillinfo.go create mode 100644 internal/handler/api/unit/supporterall.go create mode 100644 internal/handler/api/unit/unit.go create mode 100644 internal/handler/api/user/getnavi.go create mode 100644 internal/handler/api/user/info.go create mode 100644 internal/handler/api/user/user.go delete mode 100644 internal/handler/award.go create mode 100644 internal/handler/award/set.go delete mode 100644 internal/handler/background.go create mode 100644 internal/handler/background/set.go delete mode 100644 internal/handler/download.go create mode 100644 internal/handler/download/additional.go create mode 100644 internal/handler/download/batch.go create mode 100644 internal/handler/download/event.go create mode 100644 internal/handler/download/update.go create mode 100644 internal/handler/download/url.go delete mode 100644 internal/handler/event.go create mode 100644 internal/handler/event/list.go delete mode 100644 internal/handler/gdpr.go create mode 100644 internal/handler/gdpr/get.go create mode 100644 internal/handler/ghome/account/active.go create mode 100644 internal/handler/ghome/account/initialize.go create mode 100644 internal/handler/ghome/account/login.go create mode 100644 internal/handler/ghome/account/loginauto.go create mode 100644 internal/handler/ghome/account/reportrole.go create mode 100644 internal/handler/ghome/basic/getcode.go create mode 100644 internal/handler/ghome/basic/getproductlist.go create mode 100644 internal/handler/ghome/basic/handshake.go create mode 100644 internal/handler/ghome/basic/loginarea.go create mode 100644 internal/handler/ghome/basic/publickey.go create mode 100644 internal/handler/ghome/ghome.go create mode 100644 internal/handler/ghome/guest/status.go create mode 100644 internal/handler/ghome/misc/agreement.go create mode 100644 internal/handler/ghome/misc/integration.go create mode 100644 internal/handler/ghome/misc/report.go rename internal/handler/{lbonus.go => lbonus/execute.go} (72%) create mode 100644 internal/handler/live/gameover.go create mode 100644 internal/handler/live/partylist.go rename internal/handler/{live.go => live/play.go} (54%) create mode 100644 internal/handler/live/precisescore.go create mode 100644 internal/handler/live/reward.go delete mode 100644 internal/handler/login.go create mode 100644 internal/handler/login/authkey.go create mode 100644 internal/handler/login/login.go delete mode 100644 internal/handler/multiunit.go create mode 100644 internal/handler/multiunit/scenariostartup.go rename internal/handler/{museum.go => museum/info.go} (55%) delete mode 100644 internal/handler/notice.go create mode 100644 internal/handler/notice/friendgreeting.go create mode 100644 internal/handler/notice/friendvariety.go create mode 100644 internal/handler/notice/usergreetinghistory.go delete mode 100644 internal/handler/payment.go create mode 100644 internal/handler/payment/productlist.go delete mode 100644 internal/handler/personalnotice.go create mode 100644 internal/handler/personalnotice/get.go delete mode 100644 internal/handler/private.go delete mode 100644 internal/handler/profile.go create mode 100644 internal/handler/profile/register.go delete mode 100644 internal/handler/scenario.go create mode 100644 internal/handler/scenario/reward.go create mode 100644 internal/handler/scenario/startup.go delete mode 100644 internal/handler/subscenario.go create mode 100644 internal/handler/subscenario/reward.go create mode 100644 internal/handler/subscenario/startup.go delete mode 100644 internal/handler/tos.go create mode 100644 internal/handler/tos/check.go delete mode 100644 internal/handler/unit.go create mode 100644 internal/handler/unit/deck.go create mode 100644 internal/handler/unit/deckname.go create mode 100644 internal/handler/unit/favorite.go create mode 100644 internal/handler/unit/removableskillequipment.go create mode 100644 internal/handler/unit/setdisplayrank.go create mode 100644 internal/handler/unit/wearaccessory.go delete mode 100644 internal/handler/user.go create mode 100644 internal/handler/user/changename.go create mode 100644 internal/handler/user/changenavi.go create mode 100644 internal/handler/user/setnotificationtoken.go create mode 100644 internal/handler/user/userinfo.go delete mode 100644 internal/handler/userinfo.go create mode 100644 internal/handler/webui/login.go create mode 100644 internal/handler/webui/logout.go rename internal/handler/{webui.go => webui/upload.go} (72%) create mode 100644 internal/handler/webui/webui.go delete mode 100644 internal/middleware/authkey.go delete mode 100644 internal/middleware/login.go delete mode 100644 internal/middleware/multipart.go delete mode 100644 internal/model/album.go delete mode 100644 internal/model/announce.go delete mode 100644 internal/model/authkey.go delete mode 100644 internal/model/award.go delete mode 100644 internal/model/background.go delete mode 100644 internal/model/costume.go delete mode 100644 internal/model/download.go delete mode 100644 internal/model/event.go delete mode 100644 internal/model/exchange.go delete mode 100644 internal/model/lbonus.go delete mode 100644 internal/model/multiunit.go delete mode 100644 internal/model/museum.go delete mode 100644 internal/model/navigation.go delete mode 100644 internal/model/notice.go delete mode 100644 internal/model/payment.go delete mode 100644 internal/model/personalnotice.go delete mode 100644 internal/model/scenario.go delete mode 100644 internal/model/topinfo.go delete mode 100644 internal/model/tos.go delete mode 100644 internal/model/unit.go delete mode 100644 internal/model/user.go create mode 100644 internal/model/user/useraccessorywear.go create mode 100644 internal/model/user/userdeck.go create mode 100644 internal/model/user/userdeckunit.go create mode 100644 internal/model/user/userkey.go create mode 100644 internal/model/user/userpref.go create mode 100644 internal/model/user/users.go create mode 100644 internal/model/user/userunit.go create mode 100644 internal/model/user/userunitskillequip.go create mode 100644 internal/schema/album/seriesall.go create mode 100644 internal/schema/announce/checkstate.go create mode 100644 internal/schema/api/album/all.go rename internal/{model => schema/api}/api.go (51%) create mode 100644 internal/schema/api/award/info.go create mode 100644 internal/schema/api/background/info.go rename internal/{model/banner.go => schema/api/banner/list.go} (66%) rename internal/{model/marathon.go => schema/api/challenge/info.go} (67%) create mode 100644 internal/schema/api/costume/list.go create mode 100644 internal/schema/api/eventscenario/status.go create mode 100644 internal/schema/api/exchange/owningpoint.go create mode 100644 internal/schema/api/live/schedule.go create mode 100644 internal/schema/api/live/status.go create mode 100644 internal/schema/api/liveicon/info.go create mode 100644 internal/schema/api/livese/info.go create mode 100644 internal/schema/api/login/topinfo.go create mode 100644 internal/schema/api/login/topinfoonce.go rename internal/{model/challenge.go => schema/api/marathon/info.go} (67%) create mode 100644 internal/schema/api/multiunit/scenariostatus.go create mode 100644 internal/schema/api/museum/info.go create mode 100644 internal/schema/api/navigation/specialcutin.go create mode 100644 internal/schema/api/notice/marquee.go create mode 100644 internal/schema/api/payment/productlist.go create mode 100644 internal/schema/api/profile/cardranking.go rename internal/{model/tools.go => schema/api/profile/info.go} (71%) create mode 100644 internal/schema/api/profile/livecnt.go create mode 100644 internal/schema/api/scenario/status.go create mode 100644 internal/schema/api/subscenario/status.go create mode 100644 internal/schema/api/unit/accessoryall.go create mode 100644 internal/schema/api/unit/all.go create mode 100644 internal/schema/api/unit/deckinfo.go create mode 100644 internal/schema/api/unit/removableskillinfo.go create mode 100644 internal/schema/api/unit/supporterall.go create mode 100644 internal/schema/api/user/getnavi.go rename internal/{model/userinfo.go => schema/api/user/info.go} (79%) rename internal/{model/profile.go => schema/award/set.go} (65%) create mode 100644 internal/schema/background/set.go create mode 100644 internal/schema/download/additional.go create mode 100644 internal/schema/download/batch.go create mode 100644 internal/schema/download/event.go create mode 100644 internal/schema/download/update.go create mode 100644 internal/schema/download/url.go create mode 100644 internal/schema/event/list.go rename internal/{model/gdpr.go => schema/gdpr/get.go} (62%) create mode 100644 internal/schema/ghome/account.go create mode 100644 internal/schema/ghome/basic.go create mode 100644 internal/schema/ghome/guest.go create mode 100644 internal/schema/ghome/misc.go create mode 100644 internal/schema/lbonus/execute.go create mode 100644 internal/schema/live/gameover.go create mode 100644 internal/schema/live/play.go create mode 100644 internal/schema/live/precisescore.go rename internal/{model/live.go => schema/live/reward.go} (61%) create mode 100644 internal/schema/login/authkey.go rename internal/{model => schema/login}/login.go (63%) create mode 100644 internal/schema/multiunit/scenariostartup.go create mode 100644 internal/schema/museum/info.go create mode 100644 internal/schema/notice/friendgreeting.go create mode 100644 internal/schema/notice/friendvariety.go create mode 100644 internal/schema/notice/usergreetinghistory.go create mode 100644 internal/schema/payment/productlist.go create mode 100644 internal/schema/personalnotice/get.go create mode 100644 internal/schema/profile/register.go create mode 100644 internal/schema/scenario/startup.go rename internal/{model/subscenario.go => schema/subscenario/startup.go} (55%) create mode 100644 internal/schema/tos/check.go create mode 100644 internal/schema/unit/deck.go create mode 100644 internal/schema/unit/deckname.go create mode 100644 internal/schema/unit/favorite.go create mode 100644 internal/schema/unit/removableskillequipment.go create mode 100644 internal/schema/unit/setdisplayrank.go create mode 100644 internal/schema/unit/wearaccessory.go create mode 100644 internal/schema/user/changename.go create mode 100644 internal/schema/user/changenavi.go create mode 100644 internal/schema/user/setnotificationtoken.go create mode 100644 internal/schema/user/userinfo.go rename internal/{model => schema/webui}/webui.go (82%) create mode 100644 internal/startup/database.go create mode 100644 internal/startup/startup.go rename internal/{tools/init.go => startup/userdata.go} (55%) rename {internal => pkg}/tools/tools.go (99%) rename {assets/static => static}/.gitignore (100%) rename {assets/static => static}/css/base.css (100%) rename {assets/static => static}/css/layui.css (100%) rename {assets/static => static}/css/ll-perfect-scrollbar.css (100%) rename {assets/static => static}/css/perfect-scrollbar.css (100%) rename {assets/static => static}/css/style.css (100%) rename {assets/static => static}/css/window.css (100%) rename {assets/static => static}/font/iconfont.eot (100%) rename {assets/static => static}/font/iconfont.svg (100%) rename {assets/static => static}/font/iconfont.ttf (100%) rename {assets/static => static}/font/iconfont.woff (100%) rename {assets/static => static}/font/iconfont.woff2 (100%) rename {assets/static => static}/images/15047550942873.jpg (100%) rename {assets/static => static}/images/15047551059201.jpg (100%) rename {assets/static => static}/images/15047551145790.jpg (100%) rename {assets/static => static}/images/15047551242040.jpg (100%) rename {assets/static => static}/images/15047553374283.jpg (100%) rename {assets/static => static}/images/15047553496606.jpg (100%) rename {assets/static => static}/images/15047553611357.jpg (100%) rename {assets/static => static}/images/15047553728636.jpg (100%) rename {assets/static => static}/images/15047553849518.jpg (100%) rename {assets/static => static}/images/15047553982300.jpg (100%) rename {assets/static => static}/images/15047554108052.jpg (100%) rename {assets/static => static}/images/15047554203428.jpg (100%) rename {assets/static => static}/images/15047554315307.jpg (100%) rename {assets/static => static}/images/15047554481319.jpg (100%) rename {assets/static => static}/images/15047554596230.jpg (100%) rename {assets/static => static}/images/15047554774569.jpg (100%) rename {assets/static => static}/images/15047554922924.jpg (100%) rename {assets/static => static}/images/15047555087747.jpg (100%) rename {assets/static => static}/images/15047555219572.jpg (100%) rename {assets/static => static}/images/15047555411780.jpg (100%) rename {assets/static => static}/images/15047555499746.jpg (100%) rename {assets/static => static}/images/15047555585712.jpg (100%) rename {assets/static => static}/images/15047555704112.jpg (100%) rename {assets/static => static}/images/15047555798773.jpg (100%) rename {assets/static => static}/images/15047555888980.jpg (100%) rename {assets/static => static}/images/15088959186072.jpg (100%) rename {assets/static => static}/images/15107324142966.png (100%) rename {assets/static => static}/images/15141856059568.jpg (100%) rename {assets/static => static}/images/15141862776588.jpg (100%) rename {assets/static => static}/images/15141862946556.jpg (100%) rename {assets/static => static}/images/15141863126912.jpg (100%) rename {assets/static => static}/images/15141863229129.jpg (100%) rename {assets/static => static}/images/15141863365919.jpg (100%) rename {assets/static => static}/images/15141863483422.jpg (100%) rename {assets/static => static}/images/15141863639911.jpg (100%) rename {assets/static => static}/images/15141863772178.jpg (100%) rename {assets/static => static}/images/15141864261972.jpg (100%) rename {assets/static => static}/images/15141864584520.jpg (100%) rename {assets/static => static}/images/15141864695842.jpg (100%) rename {assets/static => static}/images/15141864804128.jpg (100%) rename {assets/static => static}/images/15141864889884.jpg (100%) rename {assets/static => static}/images/15141865055652.jpg (100%) rename {assets/static => static}/images/15141865133555.jpg (100%) rename {assets/static => static}/images/15141865196092.jpg (100%) rename {assets/static => static}/images/15238681581968.png (100%) rename {assets/static => static}/images/15238694807202.png (100%) rename {assets/static => static}/images/15238694919055.png (100%) rename {assets/static => static}/images/15238695116848.png (100%) rename {assets/static => static}/images/15238695303404.png (100%) rename {assets/static => static}/images/15238695455400.png (100%) rename {assets/static => static}/images/15238695587056.png (100%) rename {assets/static => static}/images/15238695641197.png (100%) rename {assets/static => static}/images/15238701747409.png (100%) rename {assets/static => static}/images/15238702168776.png (100%) rename {assets/static => static}/images/admin/ic_launcher.png (100%) rename {assets/static => static}/images/admin/top-bg.jpg (100%) rename {assets/static => static}/images/admin/top-bg_2.jpg (100%) rename {assets/static => static}/images/bg-left.png (100%) rename {assets/static => static}/images/bg-right.png (100%) create mode 100644 static/images/favicon.ico rename {assets/static => static}/images/list-content-bg-on.png (100%) rename {assets/static => static}/images/list-content-bg.png (100%) rename {assets/static => static}/images/title-banner.png (100%) rename {assets/static => static}/js/button.js (100%) rename {assets/static => static}/js/layui.js (100%) rename {assets/static => static}/js/perfect-scrollbar.min.js (100%) rename {assets/static => static}/templates/admin/card.html (98%) rename {assets/static => static}/templates/admin/index.html (98%) rename {assets/static => static}/templates/admin/login.html (99%) rename {assets/static => static}/templates/admin/nav/css.html (90%) rename {assets/static => static}/templates/admin/nav/footer.html (91%) rename {assets/static => static}/templates/admin/nav/header.html (98%) rename {assets/static => static}/templates/admin/nav/side.html (100%) rename {assets/static => static}/templates/admin/upload.html (99%) rename {assets/static => static}/templates/common/announce.html (100%) rename {assets/static => static}/templates/common/manga.html (100%) diff --git a/.gitignore b/.gitignore index 2af6173..6b262b6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,5 @@ config.json data temp -assets/data.db -assets/dictionary_zh_k.db -assets/masterdata.db -assets/userdata - .idea .vscode diff --git a/assets/.gitignore b/assets/.gitignore new file mode 100644 index 0000000..1e4c958 --- /dev/null +++ b/assets/.gitignore @@ -0,0 +1 @@ +data.db diff --git a/assets/data.example.db b/assets/data.example.db deleted file mode 100644 index 14321c4ca857be6ceb5a9a2a8c289b7be9ee81a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45056 zcmeI&O>f&a7zc2vd2!+(NwHzjDH!J*+Mw;SVd$aQWnQZd#$2aOZJ;@6s?0cq_2NkK z+cD{i4cLbou)Ka@XqvXizjyfeblc@S>(dYXx328Z+uhSX{qiqSvAq71wtukq+uq}yC)>Yl z{l59@#vdCRKZp$i5cuB<49X?rlVknri1}?gV(pRDk7&r+;-}RM={XIl?@-Izd3tJA znEt5$BYgb71)zjVb(bd^@$+&kY9$LwjXU`H)%25%UvsE%4 zJ<_koGB(?BXcPtE*cwthw7mT1?QDek;$?zN+gcpy?PttJ`NMvxWE>vqKT;WGn>t;q zFHk*YcPks4QnE}~GRb6H3cNCCw}&G7I8(0|L@Z{3f0IZ_b1ofFx9FJVGOwteHj8?$ zJ+?yI@8;_T1DZP|y^_Q#x)O_IJ3M7Zxr)5R<;~405uGkBide^|>D`h9`G)e>5GotY zU4~z{=rHqnI>c7nj?;id-d}9WjCgCvj7UexQ+7+)j8ICJ$%x`)@NDK==dRt!g(c7S zZIAc9X}+FL2)PtbZ03Y|J=`c6$H)4+gEUliwv=J12Q~}BR?C+OUS4b_qwS#`w$(%@ z&&+SCt$LGuHW_x?>2|`P@85csOwlNVHRMSWG3k&ds^=Wo(mY@Jv8T;k+O&@(8j{{vqqwJ=m|c5^tT`1+~bi5GP;wgFJCsJWy0%S1b*fr(6ggx7=-)@nLZfoejLb< z(?c-8w4N#0SG_<0uX=z1Rwwb2tWV=D
  • 登录
  • 相册
  • 编队
  • 饰品
  • 宝石
  • Live
  • 个人信息设置
  • 官方漫画

    • @@ -19,18 +17,6 @@ func AnnounceIndex(ctx *gin.Context) { }) } -func AnnounceCheckState(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - resp := model.AnnounceResp{ - ResponseData: model.AnnounceRes{ - HasUnreadAnnounce: false, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(resp) +func init() { + router.AddHandler("webview.php", "GET", "/announce/index", index) } diff --git a/internal/handler/api.go b/internal/handler/api.go deleted file mode 100644 index 4fbc377..0000000 --- a/internal/handler/api.go +++ /dev/null @@ -1,1324 +0,0 @@ -package handler - -import ( - "encoding/json" - "fmt" - "honoka-chan/config" - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "honoka-chan/internal/tools" - "honoka-chan/internal/utils" - honokautils "honoka-chan/pkg/utils" - "net/http" - "strconv" - "strings" - "time" - - "github.com/gin-gonic/gin" -) - -type EventRes struct { - EventScenarioId int `xorm:"event_scenario_id"` - Chapter int `xorm:"chapter"` - ChapterAsset string `xorm:"chapter_asset"` - OpenDate string `xorm:"open_date"` -} - -type MultiRes struct { - MultiUnitScenarioId int `xorm:"multi_unit_scenario_id"` - Chapter int `xorm:"chapter"` - MultiUnitScenarioBtnAsset string `xorm:"multi_unit_scenario_btn_asset"` - OpenDate string `xorm:"open_date"` -} - -type MuseumRes struct { - MuseumContentsId int `xorm:"museum_contents_id"` - SmileBuff int `xorm:"smile_buff"` - PureBuff int `xorm:"pure_buff"` - CoolBuff int `xorm:"cool_buff"` -} - -func Api(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - apiReq := []model.ApiReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &apiReq) - if ss.CheckErr(err) { - return - } - - results := []any{} - for _, v := range apiReq { - // fmt.Println(v) - // fmt.Println(v.Module, v.Action) - - switch v.Module { - case "login": - switch v.Action { - case "topInfo": - // key = "login_topinfo_result" - topInfoResp := model.TopInfoResp{ - Result: model.TopInfoRes{ - FriendActionCnt: 0, - FriendGreetCnt: 0, - FriendVarietyCnt: 0, - FriendNewCnt: 0, - PresentCnt: 0, - SecretBoxBadgeFlag: false, - ServerDatetime: time.Now().Format("2006-01-02 15:04:05"), - ServerTimestamp: time.Now().Unix(), - NoticeFriendDatetime: time.Now().Format("2006-01-02 15:04:05"), - NoticeMailDatetime: "2000-01-01 12:00:00", - FriendsApprovalWaitCnt: 0, - FriendsRequestCnt: 0, - IsTodayBirthday: false, - LicenseInfo: model.TopInfoLicenseInfo{ - LicenseList: []any{}, - LicensedInfo: []any{}, - ExpiredInfo: []any{}, - BadgeFlag: false, - }, - UsingBuffInfo: []any{}, - IsKlabIDTaskFlag: false, - KlabIDTaskCanSync: false, - HasUnreadAnnounce: false, - ExchangeBadgeCnt: []int{0, 0, 0}, - AdFlag: false, - HasAdReward: false, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, topInfoResp) - case "topInfoOnce": - // key = "login_topinfo_once_result" - topInfoOnceResp := model.TopInfoOnceResp{ - Result: model.TopInfoOnceRes{ - NewAchievementCnt: 0, - UnaccomplishedAchievementCnt: 0, - LiveDailyRewardExist: false, - TrainingEnergy: 10, - TrainingEnergyMax: 10, - Notification: model.TopInfoOnceNotification{ - Push: false, - Lp: false, - UpdateInfo: false, - Campaign: false, - Live: false, - Lbonus: false, - Event: false, - Secretbox: false, - Birthday: true, - }, - OpenArena: true, - CostumeStatus: true, - OpenAccessory: true, - ArenaSiSkillUniqueCheck: true, - OpenV98: true, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, topInfoOnceResp) - default: - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "live": - switch v.Action { - case "liveStatus": - // key = "live_status_result" - var liveDifficultyId []int - normalLives := []model.NormalLiveStatusList{} - err = ss.MainEng.Table("normal_live_m").Cols("live_difficulty_id").OrderBy("live_difficulty_id ASC").Find(&liveDifficultyId) - if ss.CheckErr(err) { - return - } - for _, id := range liveDifficultyId { - normalLive := model.NormalLiveStatusList{ - LiveDifficultyID: id, - Status: 1, - HiScore: 0, - HiComboCount: 0, - ClearCnt: 0, - AchievedGoalIDList: []int{}, - } - normalLives = append(normalLives, normalLive) - } - - specialLives := []model.SpecialLiveStatusList{} - err = ss.MainEng.Table("special_live_m").Cols("live_difficulty_id").OrderBy("live_difficulty_id ASC").Find(&liveDifficultyId) - if ss.CheckErr(err) { - return - } - for _, id := range liveDifficultyId { - specialLive := model.SpecialLiveStatusList{ - LiveDifficultyID: id, - Status: 1, - HiScore: 0, - HiComboCount: 0, - ClearCnt: 0, - AchievedGoalIDList: []int{}, - } - specialLives = append(specialLives, specialLive) - } - - LiveStatusResp := model.LiveStatusResp{ - Result: model.LiveStatusRes{ - NormalLiveStatusList: normalLives, - SpecialLiveStatusList: specialLives, - TrainingLiveStatusList: []model.TrainingLiveStatusList{}, - MarathonLiveStatusList: []any{}, - FreeLiveStatusList: []any{}, - CanResumeLive: false, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, LiveStatusResp) - case "schedule": - // key = "live_list_result" - var liveDifficultyId []int - specialLives := []model.SpecialLiveStatusList{} - err = ss.MainEng.Table("special_live_m").Cols("live_difficulty_id").OrderBy("live_difficulty_id ASC").Find(&liveDifficultyId) - if ss.CheckErr(err) { - return - } - for _, id := range liveDifficultyId { - specialLive := model.SpecialLiveStatusList{ - LiveDifficultyID: id, - Status: 1, - HiScore: 0, - HiComboCount: 0, - ClearCnt: 0, - AchievedGoalIDList: []int{}, - } - specialLives = append(specialLives, specialLive) - } - - livesList := []model.LiveList{} - for _, v := range specialLives { - livesList = append(livesList, model.LiveList{ - LiveDifficultyID: v.LiveDifficultyID, - StartDate: "2023-01-01 00:00:00", - EndDate: "2037-01-01 00:00:00", - IsRandom: false, - }) - } - liveListResp := model.LiveScheduleResp{ - Result: model.LiveScheduleRes{ - EventList: []any{}, - LiveList: livesList, - LimitedBonusList: []any{}, - LimitedBonusCommonList: []model.LimitedBonusCommonList{}, // 特效道具 - RandomLiveList: []model.RandomLiveList{}, // 随机歌曲 - FreeLiveList: []any{}, - TrainingLiveList: []model.TrainingLiveList{}, // 挑战歌曲 - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, liveListResp) - default: - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "unit": - switch v.Action { - case "unitAll": - // key = "unit_list_result" - unitsData := []model.Active{} - err = ss.MainEng.Table("common_unit_m").Find(&unitsData) - if ss.CheckErr(err) { - return - } - - userUnits := []model.Active{} - err = ss.UserEng.Table("user_unit_m").Where("user_id = ?", ctx.GetString("userid")).Find(&userUnits) - if ss.CheckErr(err) { - return - } - unitsData = append(unitsData, userUnits...) - - unitListResp := model.UnitAllResp{ - Result: model.UnitAllRes{ - Active: unitsData, - Waiting: []model.Waiting{}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, unitListResp) - case "deckInfo": - // key = "unit_deck_result" - userDeck := []model.UserDeckData{} - err = ss.UserEng.Table("user_deck_m").Where("user_id = ?", ctx.GetString("userid")).Asc("deck_id").Find(&userDeck) - if ss.CheckErr(err) { - return - } - - unitDeckInfo := []model.UnitDeckInfoRes{} - for _, deck := range userDeck { - deckUnit := []model.UnitDeckData{} - err = ss.UserEng.Table("deck_unit_m").Where("user_deck_id = ?", deck.ID).Asc("position").Find(&deckUnit) - if ss.CheckErr(err) { - return - } - - oUids := []model.UnitOwningUserIds{} - for _, unit := range deckUnit { - oUids = append(oUids, model.UnitOwningUserIds{ - Position: unit.Position, - UnitOwningUserID: unit.UnitOwningUserID, - }) - } - - mainFlag := false - if deck.MainFlag == 1 { - mainFlag = true - } - unitDeckInfo = append(unitDeckInfo, model.UnitDeckInfoRes{ - UnitDeckID: deck.DeckID, - MainFlag: mainFlag, - DeckName: deck.DeckName, - UnitOwningUserIds: oUids, - }) - } - unitDeckResp := model.UnitDeckInfoResp{ - Result: unitDeckInfo, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, unitDeckResp) - case "supporterAll": - // key = "unit_support_result" - unitSupportResp := model.UnitSupportResp{ - Result: model.UnitSupportRes{ - UnitSupportList: []model.UnitSupportList{}, - }, // 练习道具 - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, unitSupportResp) - case "removableSkillInfo": - // key = "owning_equip_result" - var skillEquipCount []model.SkillEquipCount - err := ss.UserEng.Table("skill_equip_m").Where("user_id = ?", ctx.GetString("userid")).Select("unit_removable_skill_id,COUNT(*) AS ct"). - GroupBy("unit_removable_skill_id").Find(&skillEquipCount) - if ss.CheckErr(err) { - return - } - - var rmSkillIds []int - err = ss.MainEng.Table("unit_removable_skill_m").Where("effect_range = 1").Cols("unit_removable_skill_id").Find(&rmSkillIds) - if ss.CheckErr(err) { - return - } - - owingInfo := []model.OwningInfo{} - for _, id := range rmSkillIds { - info := model.OwningInfo{ - UnitRemovableSkillID: id, - TotalAmount: 9, - EquippedAmount: 0, - InsertDate: "2023-01-01 12:00:00", - } - for _, sk := range skillEquipCount { - if id == sk.UnitRemovableSkillId { - info.EquippedAmount = sk.Count - break - } - } - owingInfo = append(owingInfo, info) - } - - var unitOwningIds []int - err = ss.UserEng.Table("skill_equip_m").Where("user_id = ?", ctx.GetString("userid")).Cols("unit_owning_user_id").GroupBy("unit_owning_user_id").Find(&unitOwningIds) - if ss.CheckErr(err) { - return - } - - equipInfo := map[int]any{} - for _, v := range unitOwningIds { - detail := []model.SkillEquipDetail{} - err = ss.UserEng.Table("skill_equip_m").Where("user_id = ? AND unit_owning_user_id = ?", ctx.GetString("userid"), v). - Cols("unit_removable_skill_id").Find(&detail) - if ss.CheckErr(err) { - return - } - - equipInfo[v] = model.SkillEquipList{ - UnitOwningUserID: v, - Detail: detail, - } - } - - rmSkillResp := model.RemovableSkillResp{ - Result: model.RemovableSkillRes{ - OwningInfo: owingInfo, - EquipmentInfo: equipInfo, - }, // 宝石 - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, rmSkillResp) - case "accessoryAll": - // key = "unit_accessory_result" - accessoryList := []model.AccessoryList{} - err := ss.MainEng.Table("common_accessory_m").Find(&accessoryList) - if ss.CheckErr(err) { - return - } - for k := range accessoryList { - accessoryList[k].NextExp = 0 - accessoryList[k].Level = 8 - accessoryList[k].MaxLevel = 8 - accessoryList[k].RankUpCount = 4 - accessoryList[k].FavoriteFlag = true - } - wearingInfo := []model.WearingInfo{} - err = ss.UserEng.Table("accessory_wear_m").Where("user_id = ?", ctx.GetString("userid")).Find(&wearingInfo) - if ss.CheckErr(err) { - return - } - unitAccResp := model.UnitAccessoryAllResp{ - Result: model.UnitAccessoryAllResult{ - AccessoryList: accessoryList, - WearingInfo: wearingInfo, - EspecialCreateFlag: false, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, unitAccResp) - default: - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "costume": - if v.Action == "costumeList" { - // key = "costume_list_result" - costumeListResp := model.CostumeListResp{ - Result: model.CostumeListRes{ - CostumeList: []model.CostumeList{}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, costumeListResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "album": - if v.Action == "albumAll" { - // key = "album_unit_result" - albumLists := []model.AlbumResult{} - unitList := []AlbumRes{} - err = ss.MainEng.Table("unit_m").Cols("unit_id,rarity").OrderBy("unit_id ASC").Find(&unitList) - if ss.CheckErr(err) { - return - } - - for _, unit := range unitList { - albumList := model.AlbumResult{ - RankMaxFlag: true, - LoveMaxFlag: true, - RankLevelMaxFlag: true, - AllMaxFlag: true, - FavoritePoint: 1000, - } - albumList.UnitID = unit.UnitId - if unit.Rarity != 4 { - albumList.SignFlag = false - switch unit.Rarity { - case 1: - albumList.HighestLovePerUnit = 50 - albumList.TotalLove = 50 - case 2: - albumList.HighestLovePerUnit = 200 - albumList.TotalLove = 200 - case 3: - albumList.HighestLovePerUnit = 500 - albumList.TotalLove = 500 - case 5: - albumList.HighestLovePerUnit = 750 - albumList.TotalLove = 750 - } - } else { - albumList.HighestLovePerUnit = 1000 - albumList.TotalLove = 1000 - - // IsSigned - albumList.SignFlag = utils.IsSigned(unit.UnitId) - } - albumLists = append(albumLists, albumList) - } - - albumResp := model.AlbumResp{ - Result: albumLists, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, albumResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "scenario": - if v.Action == "scenarioStatus" { - // key = "scenario_status_result" - var scenarioIds []int - scenarioLists := []model.ScenarioStatusList{} - err = ss.MainEng.Table("scenario_m").Cols("scenario_id").OrderBy("scenario_id ASC").Find(&scenarioIds) - if ss.CheckErr(err) { - return - } - - for _, id := range scenarioIds { - scenarioLists = append(scenarioLists, model.ScenarioStatusList{ - ScenarioID: id, - Status: 2, - }) - } - scenarioResp := model.ScenarioStatusResp{ - Result: model.ScenarioStatusRes{ - ScenarioStatusList: scenarioLists, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, scenarioResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "subscenario": - if v.Action == "subscenarioStatus" { - // key = "subscenario_status_result" - var subScenarioIds []int - subScenarioLists := []model.SubscenarioStatusList{} - err = ss.MainEng.Table("subscenario_m").Cols("subscenario_id").OrderBy("subscenario_id ASC").Find(&subScenarioIds) - if ss.CheckErr(err) { - return - } - - for _, id := range subScenarioIds { - subScenarioLists = append(subScenarioLists, model.SubscenarioStatusList{ - SubscenarioID: id, - Status: 2, - }) - } - subScenarioResp := model.SubscenarioStatusResp{ - Result: model.SubscenarioStatusRes{ - SubscenarioStatusList: subScenarioLists, - UnlockedSubscenarioIds: []any{}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, subScenarioResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "eventscenario": - if v.Action == "status" { - // key = "event_scenario_result" - var eventIds []int - eventsList := []model.EventScenarioList{} - err = ss.MainEng.Table("event_scenario_m").Cols("event_id").GroupBy("event_id").OrderBy("event_id DESC").Find(&eventIds) - if ss.CheckErr(err) { - return - } - - for _, id := range eventIds { - eventRes := []EventRes{} - chapsList := []model.EventScenarioChapterList{} - err = ss.MainEng.Table("event_scenario_m").Where("event_id = ?", id).Cols("event_scenario_id,chapter,chapter_asset,open_date"). - OrderBy("chapter DESC").Find(&eventRes) - if ss.CheckErr(err) { - return - } - - for _, res := range eventRes { - chapList := model.EventScenarioChapterList{ - EventScenarioID: res.EventScenarioId, - Chapter: res.Chapter, - ChapterAsset: res.ChapterAsset, - Status: 2, - OpenFlashFlag: 0, - IsReward: false, - CostType: 1000, - ItemID: 1200, - Amount: 1, - } - chapsList = append(chapsList, chapList) - } - - eventList := model.EventScenarioList{ - EventID: id, - OpenDate: strings.ReplaceAll(eventRes[0].OpenDate, "/", "-"), - ChapterList: chapsList, - } - - // HACK event_scenario_btn_asset - switch id { - case 10001: - eventList.EventScenarioBtnAsset = "assets/image/ui/eventscenario/38_se_ba_t.png" - case 221: - eventList.EventScenarioBtnAsset = "assets/image/ui/eventscenario/215_se_ba_t.png" - default: - eventList.EventScenarioBtnAsset = fmt.Sprintf("assets/image/ui/eventscenario/%d_se_ba_t.png", id) - } - - eventsList = append(eventsList, eventList) - } - eventScenarioResp := model.EventScenarioStatusResp{ - Result: model.EventScenarioStatusRes{ - EventScenarioList: eventsList, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, eventScenarioResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "multiunit": - if v.Action == "multiunitscenarioStatus" { - // key = "multi_unit_scenario_result" - var multiIds []int - multiUnitsList := []model.MultiUnitScenarioStatusList{} - err = ss.MainEng.Table("multi_unit_scenario_m").Cols("multi_unit_id").GroupBy("multi_unit_id").OrderBy("multi_unit_id ASC").Find(&multiIds) - if ss.CheckErr(err) { - return - } - - for _, id := range multiIds { - multiRes := MultiRes{} - _, err = ss.MainEng.Table("multi_unit_scenario_m"). - Join("LEFT", "multi_unit_scenario_open_m", "multi_unit_scenario_m.multi_unit_id = multi_unit_scenario_open_m.multi_unit_id"). - Cols("multi_unit_scenario_btn_asset,open_date,multi_unit_scenario_id,chapter"). - Where("multi_unit_scenario_m.multi_unit_id = ?", id).Get(&multiRes) - if ss.CheckErr(err) { - return - } - - multiUnitsList = append(multiUnitsList, model.MultiUnitScenarioStatusList{ - MultiUnitID: id, - Status: 2, - MultiUnitScenarioBtnAsset: multiRes.MultiUnitScenarioBtnAsset, - OpenDate: strings.ReplaceAll(multiRes.OpenDate, "/", "-"), - ChapterList: []model.MultiUnitScenarioChapterList{ - { - MultiUnitScenarioID: multiRes.MultiUnitScenarioId, - Chapter: multiRes.Chapter, - Status: 2, - }, - }, - }) - } - unitsResp := model.MultiUnitScenarioStatusResp{ - Result: model.MultiUnitScenarioStatusRes{ - MultiUnitScenarioStatusList: multiUnitsList, - UnlockedMultiUnitScenarioIds: []any{}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, unitsResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "payment": - if v.Action == "productList" { - // key = "product_result" - productResp := model.ProductListResp{ - Result: model.ProductListRes{ - RestrictionInfo: model.RestrictionInfo{ - Restricted: false, - }, - UnderAgeInfo: model.UnderAgeInfo{ - BirthSet: false, - HasLimit: false, - LimitAmount: nil, - MonthUsed: 0, - }, - SnsProductList: []model.SnsProductList{}, - ProductList: []model.ProductList{}, - SubscriptionList: []model.SubscriptionList{}, - ShowPointShop: false, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, productResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "banner": - if v.Action == "bannerList" { - // key = "banner_result" - bannerResp := model.BannerListResp{ - Result: model.BannerListRes{ - TimeLimit: "2037-12-31 23:59:59", - BannerList: []model.BannerList{ - { - BannerType: 1, - TargetID: 1743, - AssetPath: "assets/image/secretbox/icon/s_ba_1718_1.png", - FixedFlag: false, - BackSide: false, - BannerID: 101151, - StartDate: "2013-04-15 00:00:00", - EndDate: "2037-12-31 23:59:59", - AddUnitStartDate: "2022-01-01 00:00:00", - }, - { - BannerType: 1, - TargetID: 1741, - AssetPath: "assets/image/secretbox/icon/s_ba_1719_1.png", - FixedFlag: false, - BackSide: false, - BannerID: 101150, - StartDate: "2013-04-15 00:00:00", - EndDate: "2037-12-31 23:59:59", - AddUnitStartDate: "2022-01-01 00:00:00", - }, - { - BannerType: 1, - TargetID: 1740, - AssetPath: "assets/image/secretbox/icon/s_ba_1720_1.png", - FixedFlag: false, - BackSide: false, - BannerID: 101149, - StartDate: "2013-04-15 00:00:00", - EndDate: "2037-12-31 23:59:59", - AddUnitStartDate: "2022-01-01 00:00:00", - }, - { - BannerType: 1, - TargetID: 1739, - AssetPath: "assets/image/secretbox/icon/s_ba_1721_1.png", - FixedFlag: false, - BackSide: false, - BannerID: 101144, - StartDate: "2013-04-15 00:00:00", - EndDate: "2037-12-31 23:59:59", - AddUnitStartDate: "2022-01-01 00:00:00", - }, - { - BannerType: 2, - TargetID: 1, - AssetPath: "assets/image/webview/wv_ba_01.png", - WebviewURL: "/manga", - FixedFlag: false, - BackSide: true, - BannerID: 200001, - StartDate: "2016-10-15 15:00:00", - EndDate: "2037-12-31 23:59:59", - }, - }, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, bannerResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "notice": - if v.Action == "noticeMarquee" { - // key = "item_marquee_result" - marqueeResp := model.NoticeMarqueeResp{ - Result: model.NoticeMarqueeRes{ - ItemCount: 0, - MarqueeList: []any{}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, marqueeResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "user": - switch v.Action { - case "getNavi": - // key = "user_intro_result" - var uId, oId int - _, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Cols("user_id,unit_owning_user_id").Get(&uId, &oId) - if ss.CheckErr(err) { - return - } - - userIntroResp := model.UserNaviResp{ - Result: model.UserNaviRes{ - User: model.User{ - UserID: uId, - UnitOwningUserID: oId, - }, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, userIntroResp) - case "userInfo": - userId, err := strconv.Atoi(ctx.GetString("userid")) - if ss.CheckErr(err) { - return - } - - pref := tools.UserPref{} - exists, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", userId).Get(&pref) - if ss.CheckErr(err) { - return - } - if !exists { - ctx.String(http.StatusForbidden, ErrorMsg) - return - } - - userInfoResp := model.ApiUserInfoResp{ - Result: model.UserInfo{ - UserID: userId, - Name: pref.UserName, - Level: config.Conf.UserPrefs.Level, - Exp: config.Conf.UserPrefs.ExpNumerator, - PreviousExp: 0, - NextExp: config.Conf.UserPrefs.ExpDenominator, - GameCoin: config.Conf.UserPrefs.GameCoin, - SnsCoin: config.Conf.UserPrefs.SnsCoin, - FreeSnsCoin: config.Conf.UserPrefs.SnsCoin, - PaidSnsCoin: 0, - SocialPoint: 1438395, - UnitMax: 5000, - WaitingUnitMax: 1000, - EnergyMax: config.Conf.UserPrefs.EnergyMax, - EnergyFullTime: "2023-03-20 03:58:55", - LicenseLiveEnergyRecoverlyTime: 60, - EnergyFullNeedTime: 0, - OverMaxEnergy: config.Conf.UserPrefs.OverMaxEnergy, - TrainingEnergy: 100, - TrainingEnergyMax: 100, - FriendMax: 99, - InviteCode: config.Conf.UserPrefs.InviteCode, - InsertDate: "2015-08-10 18:58:30", - UpdateDate: "2018-08-09 18:13:12", - TutorialState: -1, - DiamondCoin: 0, - CrystalCoin: 0, - LpRecoveryItem: []model.LpRecoveryItem{}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, userInfoResp) - default: - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "navigation": - if v.Action == "specialCutin" { - // key = "special_cutin_result" - cutinResp := model.SpecialCutinResp{ - Result: model.SpecialCutinRes{ - SpecialCutinList: []any{}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, cutinResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "award": - if v.Action == "awardInfo" { - // key = "award_result" - var aIdList []int - err := ss.MainEng.Table("award_m").Cols("award_id").Find(&aIdList) - if ss.CheckErr(err) { - return - } - - var aId int - _, err = ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Cols("award_id").Get(&aId) - if ss.CheckErr(err) { - return - } - - awardsList := []model.AwardInfo{} - for _, id := range aIdList { - isSet := false - if id == aId { - isSet = true - } - awardsList = append(awardsList, model.AwardInfo{ - AwardID: id, - IsSet: isSet, - InsertDate: time.Now().Format("2006-01-02 03:04:05"), - }) - } - - awardResp := model.AwardInfoResp{ - Result: model.AwardInfoRes{ - AwardInfo: awardsList, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, awardResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "background": - if v.Action == "backgroundInfo" { - // key = "background_result" - var bIdList []int - err := ss.MainEng.Table("background_m").Cols("background_id").Find(&bIdList) - if ss.CheckErr(err) { - return - } - - var bId int - _, err = ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Cols("background_id").Get(&bId) - if ss.CheckErr(err) { - return - } - - backgroundsList := []model.BackgroundInfo{} - for _, id := range bIdList { - isSet := false - if id == bId { - isSet = true - } - backgroundsList = append(backgroundsList, model.BackgroundInfo{ - BackgroundID: id, - IsSet: isSet, - InsertDate: time.Now().Format("2006-01-02 03:04:05"), - }) - } - - backgroundResp := model.BackgroundInfoResp{ - Result: model.BackgroundInfoRes{ - BackgroundInfo: backgroundsList, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, backgroundResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "stamp": - if v.Action == "stampInfo" { - // key = "stamp_result" - stampResp := honokautils.ReadAllText("assets/serverdata/stamp.json") - var mStampResp any - err = json.Unmarshal([]byte(stampResp), &mStampResp) - if ss.CheckErr(err) { - return - } - results = append(results, mStampResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "exchange": - if v.Action == "owningPoint" { - // key = "exchange_point_result" - var exchangeIds []int - exPointsList := []model.ExchangePointList{} - err = ss.MainEng.Table("exchange_point_m").Cols("exchange_point_id").OrderBy("exchange_point_id ASC").Find(&exchangeIds) - if ss.CheckErr(err) { - return - } - - for _, id := range exchangeIds { - exPointsList = append(exPointsList, model.ExchangePointList{ - Rarity: id, - ExchangePoint: 9999, - }) - } - exPointsResp := model.ExchangePointResp{ - Result: model.ExchangePointRes{ - ExchangePointList: exPointsList, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, exPointsResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "livese": - if v.Action == "liveseInfo" { - // key = "live_se_result" - liveSeResp := model.LiveSeInfoResp{ - Result: model.LiveSeInfoRes{ - LiveSeList: []int{1, 2, 3}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, liveSeResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "liveicon": - if v.Action == "liveiconInfo" { - // key = "live_icon_result" - liveIconResp := model.LiveIconInfoResp{ - Result: model.LiveIconInfoRes{ - LiveNotesIconList: []int{1, 2, 3}, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, liveIconResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "item": - if v.Action == "list" { - // key = "item_list_result" - itemResp := honokautils.ReadAllText("assets/serverdata/item.json") - var mItemResp any - err = json.Unmarshal([]byte(itemResp), &mItemResp) - if ss.CheckErr(err) { - return - } - results = append(results, mItemResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "marathon": - if v.Action == "marathonInfo" { - // key = "marathon_result" - marathonResp := model.MarathonInfoResp{ - Result: []any{}, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, marathonResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "challenge": - if v.Action == "challengeInfo" { - // key = "challenge_result" - challengeResp := model.ChallengeInfoResp{ - Result: []any{}, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, challengeResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "museum": - if v.Action == "info" { - // key = "museum_result" - museumRes := []MuseumRes{} - var museumIds []int - var smileBuff, pureBuff, coolBuff int - err = ss.MainEng.Table("museum_contents_m").Cols("museum_contents_id,smile_buff,pure_buff,cool_buff"). - OrderBy("museum_contents_id ASC").Find(&museumRes) - if ss.CheckErr(err) { - return - } - - for _, res := range museumRes { - smileBuff += res.SmileBuff - pureBuff += res.PureBuff - coolBuff += res.CoolBuff - museumIds = append(museumIds, res.MuseumContentsId) - } - museumInfoResp := model.MuseumInfoResp{ - Result: model.MuseumInfoRes{ - MuseumInfo: model.Museum{ - Parameter: model.MuseumParameter{ - Smile: smileBuff, - Pure: pureBuff, - Cool: coolBuff, - }, - ContentsIDList: museumIds, - }, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, museumInfoResp) - } else { - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - case "profile": - switch v.Action { - case "liveCnt": - // key = "profile_livecnt_result" - difficultyResp := model.DifficultyResp{ - Result: []model.DifficultyRes{ - { - Difficulty: 1, - ClearCnt: 315, - }, - { - Difficulty: 2, - ClearCnt: 310, - }, - { - Difficulty: 3, - ClearCnt: 314, - }, - { - Difficulty: 4, - ClearCnt: 455, - }, - { - Difficulty: 6, - ClearCnt: 233, - }, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, difficultyResp) - case "cardRanking": - // key = "profile_card_ranking_result" - var result []any - love := honokautils.ReadAllText("assets/serverdata/love.json") - err := json.Unmarshal([]byte(love), &result) - if ss.CheckErr(err) { - return - } - - loveResp := model.LoveResp{ - Result: result, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, loveResp) - case "profileInfo": - // key = "profile_info_result" - pref := tools.UserPref{} - exists, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Get(&pref) - if ss.CheckErr(err) { - return - } - if !exists { - ctx.String(http.StatusForbidden, ErrorMsg) - return - } - - commonUnit, err := ss.MainEng.Table("common_unit_m").Count() - if ss.CheckErr(err) { - return - } - userUnit, err := ss.UserEng.Table("user_unit_m").Where("user_id = ?", ctx.GetString("userid")).Count() - if ss.CheckErr(err) { - return - } - - unitData := model.UnitData{} - exists, err = ss.MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", pref.UnitOwningUserID).Get(&unitData) - if ss.CheckErr(err) { - return - } - - isCommon := true - if !exists { - _, err = ss.UserEng.Table("user_unit_m"). - Where("unit_owning_user_id = ? AND user_id = ?", pref.UnitOwningUserID, ctx.GetString("userid")).Get(&unitData) - if ss.CheckErr(err) { - return - } - isCommon = false - } - - var attrId, maxHp, baseSmile, basePure, baseCool int - var smileMax, pureMax, coolMax int - if isCommon { - // 公共卡片仅为100级属性 - _, err = ss.MainEng.Table("unit_m").Where("unit_id = ?", unitData.UnitID). - Cols("attribute_id,hp_max,smile_max,pure_max,cool_max").Get(&attrId, &maxHp, &baseSmile, &basePure, &baseCool) - utils.CheckErr(err) - - // 偷懒起见不计算饰品、宝石、回忆画廊等属性加成 - smileMax = baseSmile - pureMax = basePure - coolMax = baseCool - // } else { - // // 用户卡片需要根据等级计算属性 - // // TODO - } - - var accessoryOwningId, accessoryId, exp int - _, err = ss.UserEng.Table("accessory_wear_m").Where("unit_owning_user_id = ? AND user_id = ?", pref.UnitOwningUserID, ctx.GetString("userid")). - Cols("accessory_owning_user_id").Get(&accessoryOwningId) - if ss.CheckErr(err) { - return - } - _, err = ss.MainEng.Table("common_accessory_m").Where("accessory_owning_user_id = ?", accessoryOwningId). - Cols("accessory_id,exp").Get(&accessoryId, &exp) - if ss.CheckErr(err) { - return - } - accessoryInfo := model.AccessoryInfo{ - AccessoryOwningUserID: accessoryOwningId, - AccessoryID: accessoryId, - Exp: exp, - NextExp: 0, - Level: 8, - MaxLevel: 8, - RankUpCount: 4, - FavoriteFlag: true, - } - - removeSkillIds := []int{} - err = ss.UserEng.Table("skill_equip_m").Where("unit_owning_user_id = ? AND user_id = ?", pref.UnitOwningUserID, ctx.GetString("userid")). - Cols("unit_removable_skill_id").Find(&removeSkillIds) - if ss.CheckErr(err) { - return - } - - userId, err := strconv.Atoi(config.Conf.UserPrefs.InviteCode) - if ss.CheckErr(err) { - return - } - - profileResp := model.ProfileResp{ - Result: model.ProfileRes{ - UserInfo: model.ProfileUserInfo{ - UserID: userId, - Name: pref.UserName, - Level: config.Conf.UserPrefs.Level, - CostMax: 100, - UnitMax: 5000, - EnergyMax: config.Conf.UserPrefs.EnergyMax, - FriendMax: 99, - UnitCnt: int(commonUnit + userUnit), - InviteCode: config.Conf.UserPrefs.InviteCode, - ElapsedTimeFromLogin: "14\u5c0f\u65f6\u524d", - Introduction: pref.UserDesc, - }, - CenterUnitInfo: model.CenterUnitInfo{ - UnitOwningUserID: unitData.UnitOwningUserID, - UnitID: unitData.UnitID, - Exp: unitData.Exp, - NextExp: unitData.NextExp, - Level: unitData.Level, - LevelLimitID: unitData.LevelLimitID, - MaxLevel: unitData.MaxLevel, - Rank: unitData.Rank, - MaxRank: unitData.MaxRank, - Love: unitData.Love, - MaxLove: unitData.MaxLove, - UnitSkillLevel: unitData.UnitSkillLevel, - MaxHp: unitData.MaxHp, - FavoriteFlag: unitData.FavoriteFlag, - DisplayRank: unitData.DisplayRank, - UnitSkillExp: unitData.UnitSkillExp, - UnitRemovableSkillCapacity: unitData.UnitRemovableSkillCapacity, - Attribute: attrId, - Smile: baseSmile, - Cute: basePure, - Cool: baseCool, - IsLoveMax: unitData.IsLoveMax, - IsLevelMax: unitData.IsLevelMax, - IsRankMax: unitData.IsRankMax, - IsSigned: unitData.IsSigned, - IsSkillLevelMax: unitData.IsSkillLevelMax, - SettingAwardID: pref.AwardID, - RemovableSkillIds: removeSkillIds, - AccessoryInfo: accessoryInfo, - Costume: model.Costume{}, - TotalSmile: smileMax, - TotalCute: pureMax, - TotalCool: coolMax, - TotalHp: maxHp, - }, - NaviUnitInfo: model.NaviUnitInfo{ - UnitOwningUserID: unitData.UnitOwningUserID, - UnitID: unitData.UnitID, - Exp: unitData.Exp, - NextExp: unitData.NextExp, - Level: unitData.Level, - MaxLevel: unitData.MaxLevel, - LevelLimitID: unitData.LevelLimitID, - Rank: unitData.Rank, - MaxRank: unitData.MaxRank, - Love: unitData.Love, - MaxLove: unitData.MaxLove, - UnitSkillExp: unitData.UnitSkillExp, - UnitSkillLevel: unitData.UnitSkillLevel, - MaxHp: unitData.MaxHp, - UnitRemovableSkillCapacity: unitData.UnitRemovableSkillCapacity, - FavoriteFlag: unitData.FavoriteFlag, - DisplayRank: unitData.DisplayRank, - IsLoveMax: unitData.IsLoveMax, - IsLevelMax: unitData.IsLevelMax, - IsRankMax: unitData.IsRankMax, - IsSigned: unitData.IsSigned, - IsSkillLevelMax: unitData.IsSkillLevelMax, - IsRemovableSkillCapacityMax: unitData.IsRemovableSkillCapacityMax, - InsertDate: "2016-10-11 10:33:03", - TotalSmile: smileMax, - TotalCute: pureMax, - TotalCool: coolMax, - TotalHp: maxHp, - RemovableSkillIds: removeSkillIds, - }, - IsAlliance: false, - FriendStatus: 0, - SettingAwardID: 113, - SettingBackgroundID: 143, - }, - Status: 200, - CommandNum: false, - TimeStamp: time.Now().Unix(), - } - results = append(results, profileResp) - default: - err = fmt.Errorf("unimplemented: %s", v.Module+":"+v.Action) - } - default: - err = fmt.Errorf("unimplemented: %s", v.Module) - } - } - - if ss.CheckErr(err) { - return - } - - apiResp := model.ApiResp{ - ResponseData: results, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(apiResp) -} diff --git a/internal/handler/api/album/album.go b/internal/handler/api/album/album.go new file mode 100644 index 0000000..3cd8eac --- /dev/null +++ b/internal/handler/api/album/album.go @@ -0,0 +1,17 @@ +package album + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func AlbumApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "albumAll": + res, err = albumAll(ctx) + default: + err = fmt.Errorf("unimplemented action: album: %s", action) + } + return res, err +} diff --git a/internal/handler/api/album/all.go b/internal/handler/api/album/all.go new file mode 100644 index 0000000..4ddfbd0 --- /dev/null +++ b/internal/handler/api/album/all.go @@ -0,0 +1,70 @@ +package album + +import ( + "honoka-chan/internal/schema/api/album" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func albumAll(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + albumLists := []album.UnitList{} + var unitList []struct { + UnitId int `xorm:"unit_id"` + Rarity int `xorm:"rarity"` + } + err = ss.MainEng.Table("unit_m").Cols("unit_id,rarity").OrderBy("unit_id ASC").Find(&unitList) + if err != nil { + return nil, err + } + + for _, unit := range unitList { + albumList := album.UnitList{ + RankMaxFlag: true, + LoveMaxFlag: true, + RankLevelMaxFlag: true, + AllMaxFlag: true, + FavoritePoint: 1000, + } + albumList.UnitID = unit.UnitId + if unit.Rarity != 4 { + albumList.SignFlag = false + switch unit.Rarity { + case 1: + albumList.HighestLovePerUnit = 50 + albumList.TotalLove = 50 + case 2: + albumList.HighestLovePerUnit = 200 + albumList.TotalLove = 200 + case 3: + albumList.HighestLovePerUnit = 500 + albumList.TotalLove = 500 + case 5: + albumList.HighestLovePerUnit = 750 + albumList.TotalLove = 750 + } + } else { + albumList.HighestLovePerUnit = 1000 + albumList.TotalLove = 1000 + + // IsSigned + albumList.SignFlag, err = ss.MainEng.Table("unit_sign_asset_m").Where("unit_id = ?", unit.UnitId).Exist() + if err != nil { + return nil, err + } + } + albumLists = append(albumLists, albumList) + } + + res = album.AllResp{ + Result: albumLists, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/api.go b/internal/handler/api/api.go new file mode 100644 index 0000000..7e92f22 --- /dev/null +++ b/internal/handler/api/api.go @@ -0,0 +1,125 @@ +package api + +import ( + "encoding/json" + "fmt" + "honoka-chan/internal/handler/api/album" + "honoka-chan/internal/handler/api/award" + "honoka-chan/internal/handler/api/background" + "honoka-chan/internal/handler/api/banner" + "honoka-chan/internal/handler/api/challenge" + "honoka-chan/internal/handler/api/costume" + "honoka-chan/internal/handler/api/eventscenario" + "honoka-chan/internal/handler/api/exchange" + "honoka-chan/internal/handler/api/item" + "honoka-chan/internal/handler/api/live" + "honoka-chan/internal/handler/api/liveicon" + "honoka-chan/internal/handler/api/livese" + "honoka-chan/internal/handler/api/login" + "honoka-chan/internal/handler/api/marathon" + "honoka-chan/internal/handler/api/multiunit" + "honoka-chan/internal/handler/api/museum" + "honoka-chan/internal/handler/api/navigation" + "honoka-chan/internal/handler/api/notice" + "honoka-chan/internal/handler/api/payment" + "honoka-chan/internal/handler/api/profile" + "honoka-chan/internal/handler/api/scenario" + "honoka-chan/internal/handler/api/stamp" + "honoka-chan/internal/handler/api/subscenario" + "honoka-chan/internal/handler/api/unit" + "honoka-chan/internal/handler/api/user" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + apischema "honoka-chan/internal/schema/api" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func api(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + apiReq := []apischema.ApiReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &apiReq) + if ss.CheckErr(err) { + return + } + + var result any + var results []any + for _, v := range apiReq { + // fmt.Println(v.Module, v.Action) + switch v.Module { + case "album": + result, err = album.AlbumApi(ctx, v.Action) + case "award": + result, err = award.AwardApi(ctx, v.Action) + case "background": + result, err = background.BackgroundApi(ctx, v.Action) + case "banner": + result, err = banner.BannerApi(v.Action) + case "challenge": + result, err = challenge.ChallengeApi(v.Action) + case "costume": + result, err = costume.CostumeApi(v.Action) + case "eventscenario": + result, err = eventscenario.EventScenarioApi(ctx, v.Action) + case "exchange": + result, err = exchange.ExchangeApi(ctx, v.Action) + case "item": + result, err = item.ItemApi(v.Action) + case "live": + result, err = live.LiveApi(ctx, v.Action) + case "liveicon": + result, err = liveicon.LiveIconApi(v.Action) + case "livese": + result, err = livese.LiveSeApi(v.Action) + case "login": + result, err = login.LoginApi(v.Action) + case "marathon": + result, err = marathon.MarathonApi(v.Action) + case "multiunit": + result, err = multiunit.MultiUnitApi(ctx, v.Action) + case "museum": + result, err = museum.MuseumApi(ctx, v.Action) + case "navigation": + result, err = navigation.NavigationApi(v.Action) + case "notice": + result, err = notice.NoticeApi(v.Action) + case "payment": + result, err = payment.PaymentApi(v.Action) + case "profile": + result, err = profile.ProfileApi(ctx, v.Action) + case "scenario": + result, err = scenario.ScenarioApi(ctx, v.Action) + case "stamp": + result, err = stamp.StampApi(v.Action) + case "subscenario": + result, err = subscenario.SubscenarioApi(ctx, v.Action) + case "unit": + result, err = unit.UnitApi(ctx, v.Action) + case "user": + result, err = user.UserApi(ctx, v.Action) + default: + err = fmt.Errorf("unimplemented api module: %s", v.Module) + } + + if ss.CheckErr(err) { + return + } + results = append(results, result) + } + + apiResp := apischema.ApiResp{ + ResponseData: results, + ReleaseInfo: []any{}, + StatusCode: 200, + } + + ss.Respond(apiResp) +} + +func init() { + router.AddHandler("main.php", "POST", "/api", middleware.Common, api) +} diff --git a/internal/handler/api/award/award.go b/internal/handler/api/award/award.go new file mode 100644 index 0000000..42e65d4 --- /dev/null +++ b/internal/handler/api/award/award.go @@ -0,0 +1,17 @@ +package award + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func AwardApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "awardInfo": + res, err = awardInfo(ctx) + default: + err = fmt.Errorf("unimplemented action: award: %s", action) + } + return res, err +} diff --git a/internal/handler/api/award/info.go b/internal/handler/api/award/info.go new file mode 100644 index 0000000..c68c27b --- /dev/null +++ b/internal/handler/api/award/info.go @@ -0,0 +1,49 @@ +package award + +import ( + "honoka-chan/internal/schema/api/award" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func awardInfo(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var awardList []int + err = ss.MainEng.Table("award_m").Cols("award_id").Find(&awardList) + if ss.CheckErr(err) { + return + } + + var awardID int + _, err = ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Cols("award_id").Get(&awardID) + if ss.CheckErr(err) { + return + } + + awardsList := []award.Info{} + for _, id := range awardList { + isSet := false + if id == awardID { + isSet = true + } + awardsList = append(awardsList, award.Info{ + AwardID: id, + IsSet: isSet, + InsertDate: time.Now().Format("2006-01-02 03:04:05"), + }) + } + + res = award.InfoResp{ + Result: award.InfoData{ + AwardInfo: awardsList, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/background/background.go b/internal/handler/api/background/background.go new file mode 100644 index 0000000..371020c --- /dev/null +++ b/internal/handler/api/background/background.go @@ -0,0 +1,17 @@ +package background + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func BackgroundApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "backgroundInfo": + res, err = backgroundInfo(ctx) + default: + err = fmt.Errorf("unimplemented action: background: %s", action) + } + return res, err +} diff --git a/internal/handler/api/background/info.go b/internal/handler/api/background/info.go new file mode 100644 index 0000000..453a603 --- /dev/null +++ b/internal/handler/api/background/info.go @@ -0,0 +1,49 @@ +package background + +import ( + "honoka-chan/internal/schema/api/background" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func backgroundInfo(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var backgroundList []int + err = ss.MainEng.Table("background_m").Cols("background_id").Find(&backgroundList) + if ss.CheckErr(err) { + return + } + + var backgroundID int + _, err = ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Cols("background_id").Get(&backgroundID) + if ss.CheckErr(err) { + return + } + + backgroundsList := []background.Info{} + for _, id := range backgroundList { + isSet := false + if id == backgroundID { + isSet = true + } + backgroundsList = append(backgroundsList, background.Info{ + BackgroundID: id, + IsSet: isSet, + InsertDate: time.Now().Format("2006-01-02 03:04:05"), + }) + } + + res = background.InfoResp{ + Result: background.InfoData{ + BackgroundInfo: backgroundsList, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/banner/banner.go b/internal/handler/api/banner/banner.go new file mode 100644 index 0000000..08900ec --- /dev/null +++ b/internal/handler/api/banner/banner.go @@ -0,0 +1,13 @@ +package banner + +import "fmt" + +func BannerApi(action string) (res any, err error) { + switch action { + case "bannerList": + res, err = bannerList() + default: + err = fmt.Errorf("unimplemented action: banner: %s", action) + } + return res, err +} diff --git a/internal/handler/api/banner/list.go b/internal/handler/api/banner/list.go new file mode 100644 index 0000000..80c8f60 --- /dev/null +++ b/internal/handler/api/banner/list.go @@ -0,0 +1,76 @@ +package banner + +import ( + "honoka-chan/internal/schema/api/banner" + "time" +) + +func bannerList() (res any, err error) { + res = banner.ListResp{ + Result: banner.ListData{ + TimeLimit: "2037-12-31 23:59:59", + BannerList: []banner.BannerList{ + { + BannerType: 1, + TargetID: 1743, + AssetPath: "assets/image/secretbox/icon/s_ba_1718_1.png", + FixedFlag: false, + BackSide: false, + BannerID: 101151, + StartDate: "2013-04-15 00:00:00", + EndDate: "2037-12-31 23:59:59", + AddUnitStartDate: "2022-01-01 00:00:00", + }, + { + BannerType: 1, + TargetID: 1741, + AssetPath: "assets/image/secretbox/icon/s_ba_1719_1.png", + FixedFlag: false, + BackSide: false, + BannerID: 101150, + StartDate: "2013-04-15 00:00:00", + EndDate: "2037-12-31 23:59:59", + AddUnitStartDate: "2022-01-01 00:00:00", + }, + { + BannerType: 1, + TargetID: 1740, + AssetPath: "assets/image/secretbox/icon/s_ba_1720_1.png", + FixedFlag: false, + BackSide: false, + BannerID: 101149, + StartDate: "2013-04-15 00:00:00", + EndDate: "2037-12-31 23:59:59", + AddUnitStartDate: "2022-01-01 00:00:00", + }, + { + BannerType: 1, + TargetID: 1739, + AssetPath: "assets/image/secretbox/icon/s_ba_1721_1.png", + FixedFlag: false, + BackSide: false, + BannerID: 101144, + StartDate: "2013-04-15 00:00:00", + EndDate: "2037-12-31 23:59:59", + AddUnitStartDate: "2022-01-01 00:00:00", + }, + { + BannerType: 2, + TargetID: 1, + AssetPath: "assets/image/webview/wv_ba_01.png", + WebviewURL: "/manga", + FixedFlag: false, + BackSide: true, + BannerID: 200001, + StartDate: "2016-10-15 15:00:00", + EndDate: "2037-12-31 23:59:59", + }, + }, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/challenge/challenge.go b/internal/handler/api/challenge/challenge.go new file mode 100644 index 0000000..24f0828 --- /dev/null +++ b/internal/handler/api/challenge/challenge.go @@ -0,0 +1,15 @@ +package challenge + +import ( + "fmt" +) + +func ChallengeApi(action string) (res any, err error) { + switch action { + case "challengeInfo": + res, err = challengeInfo() + default: + err = fmt.Errorf("unimplemented action: challenge: %s", action) + } + return res, err +} diff --git a/internal/handler/api/challenge/info.go b/internal/handler/api/challenge/info.go new file mode 100644 index 0000000..94ebe05 --- /dev/null +++ b/internal/handler/api/challenge/info.go @@ -0,0 +1,16 @@ +package challenge + +import ( + "honoka-chan/internal/schema/api/challenge" + "time" +) + +func challengeInfo() (res any, err error) { + res = challenge.InfoResp{ + Result: []any{}, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + return res, err +} diff --git a/internal/handler/api/costume/costume.go b/internal/handler/api/costume/costume.go new file mode 100644 index 0000000..63885eb --- /dev/null +++ b/internal/handler/api/costume/costume.go @@ -0,0 +1,13 @@ +package costume + +import "fmt" + +func CostumeApi(action string) (res any, err error) { + switch action { + case "costumeList": + res, err = costumeList() + default: + err = fmt.Errorf("unimplemented action: costume: %s", action) + } + return res, err +} diff --git a/internal/handler/api/costume/list.go b/internal/handler/api/costume/list.go new file mode 100644 index 0000000..7a2f99d --- /dev/null +++ b/internal/handler/api/costume/list.go @@ -0,0 +1,19 @@ +package costume + +import ( + "honoka-chan/internal/schema/api/costume" + "time" +) + +func costumeList() (res any, err error) { + res = costume.ListResp{ + Result: costume.ListData{ + CostumeList: []costume.CostumeList{}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/eventscenario/eventscenario.go b/internal/handler/api/eventscenario/eventscenario.go new file mode 100644 index 0000000..f690b17 --- /dev/null +++ b/internal/handler/api/eventscenario/eventscenario.go @@ -0,0 +1,17 @@ +package eventscenario + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func EventScenarioApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "status": + res, err = eventScenarioStatus(ctx) + default: + err = fmt.Errorf("unimplemented action: costume: %s", action) + } + return res, err +} diff --git a/internal/handler/api/eventscenario/status.go b/internal/handler/api/eventscenario/status.go new file mode 100644 index 0000000..d1f313e --- /dev/null +++ b/internal/handler/api/eventscenario/status.go @@ -0,0 +1,80 @@ +package eventscenario + +import ( + "fmt" + "honoka-chan/internal/schema/api/eventscenario" + "honoka-chan/internal/session" + "strings" + "time" + + "github.com/gin-gonic/gin" +) + +func eventScenarioStatus(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var eventID []int + eventsList := []eventscenario.EventScenarioList{} + err = ss.MainEng.Table("event_scenario_m").Cols("event_id").GroupBy("event_id").OrderBy("event_id DESC").Find(&eventID) + if ss.CheckErr(err) { + return + } + + for _, id := range eventID { + var eventRes []struct { + EventScenarioId int `xorm:"event_scenario_id"` + Chapter int `xorm:"chapter"` + ChapterAsset string `xorm:"chapter_asset"` + OpenDate string `xorm:"open_date"` + } + chapsList := []eventscenario.ChapterList{} + err = ss.MainEng.Table("event_scenario_m").Where("event_id = ?", id).Cols("event_scenario_id,chapter,chapter_asset,open_date"). + OrderBy("chapter DESC").Find(&eventRes) + if ss.CheckErr(err) { + return + } + + for _, res := range eventRes { + chapList := eventscenario.ChapterList{ + EventScenarioID: res.EventScenarioId, + Chapter: res.Chapter, + ChapterAsset: res.ChapterAsset, + Status: 2, + OpenFlashFlag: 0, + IsReward: false, + CostType: 1000, + ItemID: 1200, + Amount: 1, + } + chapsList = append(chapsList, chapList) + } + + event := eventscenario.EventScenarioList{ + EventID: id, + OpenDate: strings.ReplaceAll(eventRes[0].OpenDate, "/", "-"), + ChapterList: chapsList, + } + + // HACK event_scenario_btn_asset + switch id { + case 10001: + event.EventScenarioBtnAsset = "assets/image/ui/eventscenario/38_se_ba_t.png" + case 221: + event.EventScenarioBtnAsset = "assets/image/ui/eventscenario/215_se_ba_t.png" + default: + event.EventScenarioBtnAsset = fmt.Sprintf("assets/image/ui/eventscenario/%d_se_ba_t.png", id) + } + + eventsList = append(eventsList, event) + } + res = eventscenario.StatusResp{ + Result: eventscenario.StatusData{ + EventScenarioList: eventsList, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/exchange/exchange.go b/internal/handler/api/exchange/exchange.go new file mode 100644 index 0000000..d262aea --- /dev/null +++ b/internal/handler/api/exchange/exchange.go @@ -0,0 +1,17 @@ +package exchange + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func ExchangeApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "owningPoint": + res, err = owningPoint(ctx) + default: + err = fmt.Errorf("unimplemented action: exchange: %s", action) + } + return res, err +} diff --git a/internal/handler/api/exchange/owningpoint.go b/internal/handler/api/exchange/owningpoint.go new file mode 100644 index 0000000..d17077e --- /dev/null +++ b/internal/handler/api/exchange/owningpoint.go @@ -0,0 +1,37 @@ +package exchange + +import ( + "honoka-chan/internal/schema/api/exchange" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func owningPoint(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var exchangeID []int + exPointsList := []exchange.ExchangePointList{} + err = ss.MainEng.Table("exchange_point_m").Cols("exchange_point_id").OrderBy("exchange_point_id ASC").Find(&exchangeID) + if ss.CheckErr(err) { + return + } + + for _, id := range exchangeID { + exPointsList = append(exPointsList, exchange.ExchangePointList{ + Rarity: id, + ExchangePoint: 9999, + }) + } + res = exchange.OwningPointResp{ + Result: exchange.OwningPointData{ + ExchangePointList: exPointsList, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/item/item.go b/internal/handler/api/item/item.go new file mode 100644 index 0000000..d23065b --- /dev/null +++ b/internal/handler/api/item/item.go @@ -0,0 +1,13 @@ +package item + +import "fmt" + +func ItemApi(action string) (res any, err error) { + switch action { + case "list": + res, err = itemList() + default: + err = fmt.Errorf("unimplemented action: item: %s", action) + } + return res, err +} diff --git a/internal/handler/api/item/list.go b/internal/handler/api/item/list.go new file mode 100644 index 0000000..64a6611 --- /dev/null +++ b/internal/handler/api/item/list.go @@ -0,0 +1,13 @@ +package item + +import ( + "encoding/json" + honokautils "honoka-chan/pkg/utils" +) + +func itemList() (res any, err error) { + itemResp := honokautils.ReadAllText("assets/serverdata/item.json") + err = json.Unmarshal([]byte(itemResp), &res) + + return res, err +} diff --git a/internal/handler/api/live/live.go b/internal/handler/api/live/live.go new file mode 100644 index 0000000..f06b872 --- /dev/null +++ b/internal/handler/api/live/live.go @@ -0,0 +1,19 @@ +package live + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func LiveApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "liveStatus": + res, err = liveStatus(ctx) + case "schedule": + res, err = liveSchedule(ctx) + default: + err = fmt.Errorf("unimplemented action: live: %s", action) + } + return res, err +} diff --git a/internal/handler/api/live/schedule.go b/internal/handler/api/live/schedule.go new file mode 100644 index 0000000..7ef5e6f --- /dev/null +++ b/internal/handler/api/live/schedule.go @@ -0,0 +1,57 @@ +package live + +import ( + "honoka-chan/internal/schema/api/live" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func liveSchedule(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var liveDifficultyID []int + specialLives := []live.SpecialLiveStatusList{} + err = ss.MainEng.Table("special_live_m").Cols("live_difficulty_id").OrderBy("live_difficulty_id ASC").Find(&liveDifficultyID) + if ss.CheckErr(err) { + return + } + for _, id := range liveDifficultyID { + specialLive := live.SpecialLiveStatusList{ + LiveDifficultyID: id, + Status: 1, + HiScore: 0, + HiComboCount: 0, + ClearCnt: 0, + AchievedGoalIDList: []int{}, + } + specialLives = append(specialLives, specialLive) + } + + livesList := []live.LiveList{} + for _, v := range specialLives { + livesList = append(livesList, live.LiveList{ + LiveDifficultyID: v.LiveDifficultyID, + StartDate: "2023-01-01 00:00:00", + EndDate: "2037-01-01 00:00:00", + IsRandom: false, + }) + } + res = live.ScheduleResp{ + Result: live.ScheduleData{ + EventList: []any{}, + LiveList: livesList, + LimitedBonusList: []any{}, + LimitedBonusCommonList: []live.LimitedBonusCommonList{}, // 特效道具 + RandomLiveList: []live.RandomLiveList{}, // 随机歌曲 + FreeLiveList: []any{}, + TrainingLiveList: []live.TrainingLiveList{}, // 挑战歌曲 + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/live/status.go b/internal/handler/api/live/status.go new file mode 100644 index 0000000..1531833 --- /dev/null +++ b/internal/handler/api/live/status.go @@ -0,0 +1,64 @@ +package live + +import ( + "honoka-chan/internal/schema/api/live" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func liveStatus(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var liveDifficultyID []int + normalLives := []live.NormalLiveStatusList{} + err = ss.MainEng.Table("normal_live_m").Cols("live_difficulty_id").OrderBy("live_difficulty_id ASC").Find(&liveDifficultyID) + if ss.CheckErr(err) { + return + } + for _, id := range liveDifficultyID { + normalLive := live.NormalLiveStatusList{ + LiveDifficultyID: id, + Status: 1, + HiScore: 0, + HiComboCount: 0, + ClearCnt: 0, + AchievedGoalIDList: []int{}, + } + normalLives = append(normalLives, normalLive) + } + + specialLives := []live.SpecialLiveStatusList{} + err = ss.MainEng.Table("special_live_m").Cols("live_difficulty_id").OrderBy("live_difficulty_id ASC").Find(&liveDifficultyID) + if ss.CheckErr(err) { + return + } + for _, id := range liveDifficultyID { + specialLive := live.SpecialLiveStatusList{ + LiveDifficultyID: id, + Status: 1, + HiScore: 0, + HiComboCount: 0, + ClearCnt: 0, + AchievedGoalIDList: []int{}, + } + specialLives = append(specialLives, specialLive) + } + + res = live.StatusResp{ + Result: live.StatusData{ + NormalLiveStatusList: normalLives, + SpecialLiveStatusList: specialLives, + TrainingLiveStatusList: []live.TrainingLiveStatusList{}, + MarathonLiveStatusList: []any{}, + FreeLiveStatusList: []any{}, + CanResumeLive: false, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/liveicon/info.go b/internal/handler/api/liveicon/info.go new file mode 100644 index 0000000..6d2a2de --- /dev/null +++ b/internal/handler/api/liveicon/info.go @@ -0,0 +1,19 @@ +package liveicon + +import ( + "honoka-chan/internal/schema/api/liveicon" + "time" +) + +func liveIconInfo() (res any, err error) { + res = liveicon.InfoResp{ + Result: liveicon.InfoData{ + LiveNotesIconList: []int{1, 2, 3}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/liveicon/liveicon.go b/internal/handler/api/liveicon/liveicon.go new file mode 100644 index 0000000..33bf93a --- /dev/null +++ b/internal/handler/api/liveicon/liveicon.go @@ -0,0 +1,13 @@ +package liveicon + +import "fmt" + +func LiveIconApi(action string) (res any, err error) { + switch action { + case "liveiconInfo": + res, err = liveIconInfo() + default: + err = fmt.Errorf("unimplemented action: liveicon: %s", action) + } + return res, err +} diff --git a/internal/handler/api/livese/info.go b/internal/handler/api/livese/info.go new file mode 100644 index 0000000..9b8ad46 --- /dev/null +++ b/internal/handler/api/livese/info.go @@ -0,0 +1,19 @@ +package livese + +import ( + "honoka-chan/internal/schema/api/livese" + "time" +) + +func LiveSeInfo() (res any, err error) { + res = livese.InfoResp{ + Result: livese.InfoData{ + LiveSeList: []int{1, 2, 3}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/livese/livese.go b/internal/handler/api/livese/livese.go new file mode 100644 index 0000000..f681a9d --- /dev/null +++ b/internal/handler/api/livese/livese.go @@ -0,0 +1,13 @@ +package livese + +import "fmt" + +func LiveSeApi(action string) (res any, err error) { + switch action { + case "liveseInfo": + res, err = LiveSeInfo() + default: + err = fmt.Errorf("unimplemented action: livese: %s", action) + } + return res, err +} diff --git a/internal/handler/api/login/login.go b/internal/handler/api/login/login.go new file mode 100644 index 0000000..5ea6f16 --- /dev/null +++ b/internal/handler/api/login/login.go @@ -0,0 +1,17 @@ +package login + +import ( + "fmt" +) + +func LoginApi(action string) (res any, err error) { + switch action { + case "topInfo": + res, err = loginTopInfo() + case "topInfoOnce": + res, err = loginTopInfoOnce() + default: + err = fmt.Errorf("unimplemented action: login: %s", action) + } + return res, err +} diff --git a/internal/handler/api/login/topinfo.go b/internal/handler/api/login/topinfo.go new file mode 100644 index 0000000..48f6ba7 --- /dev/null +++ b/internal/handler/api/login/topinfo.go @@ -0,0 +1,44 @@ +package login + +import ( + "honoka-chan/internal/schema/api/login" + "time" +) + +func loginTopInfo() (res any, err error) { + res = login.TopInfoResp{ + Result: login.TopInfoData{ + FriendActionCnt: 0, + FriendGreetCnt: 0, + FriendVarietyCnt: 0, + FriendNewCnt: 0, + PresentCnt: 0, + SecretBoxBadgeFlag: false, + ServerDatetime: time.Now().Format("2006-01-02 15:04:05"), + ServerTimestamp: time.Now().Unix(), + NoticeFriendDatetime: time.Now().Format("2006-01-02 15:04:05"), + NoticeMailDatetime: "2000-01-01 12:00:00", + FriendsApprovalWaitCnt: 0, + FriendsRequestCnt: 0, + IsTodayBirthday: false, + LicenseInfo: login.LicenseInfo{ + LicenseList: []any{}, + LicensedInfo: []any{}, + ExpiredInfo: []any{}, + BadgeFlag: false, + }, + UsingBuffInfo: []any{}, + IsKlabIDTaskFlag: false, + KlabIDTaskCanSync: false, + HasUnreadAnnounce: false, + ExchangeBadgeCnt: []int{0, 0, 0}, + AdFlag: false, + HasAdReward: false, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/login/topinfoonce.go b/internal/handler/api/login/topinfoonce.go new file mode 100644 index 0000000..73f9578 --- /dev/null +++ b/internal/handler/api/login/topinfoonce.go @@ -0,0 +1,39 @@ +package login + +import ( + "honoka-chan/internal/schema/api/login" + "time" +) + +func loginTopInfoOnce() (res any, err error) { + res = login.TopInfoOnceResp{ + Result: login.TopInfoOnceData{ + NewAchievementCnt: 0, + UnaccomplishedAchievementCnt: 0, + LiveDailyRewardExist: false, + TrainingEnergy: 10, + TrainingEnergyMax: 10, + Notification: login.Notification{ + Push: false, + Lp: false, + UpdateInfo: false, + Campaign: false, + Live: false, + Lbonus: false, + Event: false, + Secretbox: false, + Birthday: true, + }, + OpenArena: true, + CostumeStatus: true, + OpenAccessory: true, + ArenaSiSkillUniqueCheck: true, + OpenV98: true, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/marathon/info.go b/internal/handler/api/marathon/info.go new file mode 100644 index 0000000..55a1859 --- /dev/null +++ b/internal/handler/api/marathon/info.go @@ -0,0 +1,17 @@ +package marathon + +import ( + "honoka-chan/internal/schema/api/marathon" + "time" +) + +func marathonInfo() (res any, err error) { + res = marathon.InfoResp{ + Result: []any{}, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/marathon/marathon.go b/internal/handler/api/marathon/marathon.go new file mode 100644 index 0000000..69f9939 --- /dev/null +++ b/internal/handler/api/marathon/marathon.go @@ -0,0 +1,13 @@ +package marathon + +import "fmt" + +func MarathonApi(action string) (res any, err error) { + switch action { + case "marathonInfo": + res, err = marathonInfo() + default: + err = fmt.Errorf("unimplemented action: marathon: %s", action) + } + return res, err +} diff --git a/internal/handler/api/multiunit/multiunit.go b/internal/handler/api/multiunit/multiunit.go new file mode 100644 index 0000000..349b80d --- /dev/null +++ b/internal/handler/api/multiunit/multiunit.go @@ -0,0 +1,17 @@ +package multiunit + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func MultiUnitApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "multiunitscenarioStatus": + res, err = MultiUnitScenarioStatus(ctx) + default: + err = fmt.Errorf("unimplemented action: multiunit: %s", action) + } + return res, err +} diff --git a/internal/handler/api/multiunit/scenariostatus.go b/internal/handler/api/multiunit/scenariostatus.go new file mode 100644 index 0000000..2af2205 --- /dev/null +++ b/internal/handler/api/multiunit/scenariostatus.go @@ -0,0 +1,62 @@ +package multiunit + +import ( + "honoka-chan/internal/schema/api/multiunit" + "honoka-chan/internal/session" + "strings" + "time" + + "github.com/gin-gonic/gin" +) + +func MultiUnitScenarioStatus(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var statusID []int + multiUnitsList := []multiunit.StatusList{} + err = ss.MainEng.Table("multi_unit_scenario_m").Cols("multi_unit_id").GroupBy("multi_unit_id").OrderBy("multi_unit_id ASC").Find(&statusID) + if ss.CheckErr(err) { + return + } + + for _, id := range statusID { + var multiRes struct { + MultiUnitScenarioId int `xorm:"multi_unit_scenario_id"` + Chapter int `xorm:"chapter"` + MultiUnitScenarioBtnAsset string `xorm:"multi_unit_scenario_btn_asset"` + OpenDate string `xorm:"open_date"` + } + _, err = ss.MainEng.Table("multi_unit_scenario_m"). + Join("LEFT", "multi_unit_scenario_open_m", "multi_unit_scenario_m.multi_unit_id = multi_unit_scenario_open_m.multi_unit_id"). + Cols("multi_unit_scenario_btn_asset,open_date,multi_unit_scenario_id,chapter"). + Where("multi_unit_scenario_m.multi_unit_id = ?", id).Get(&multiRes) + if ss.CheckErr(err) { + return + } + + multiUnitsList = append(multiUnitsList, multiunit.StatusList{ + MultiUnitID: id, + Status: 2, + MultiUnitScenarioBtnAsset: multiRes.MultiUnitScenarioBtnAsset, + OpenDate: strings.ReplaceAll(multiRes.OpenDate, "/", "-"), + ChapterList: []multiunit.ChapterList{ + { + MultiUnitScenarioID: multiRes.MultiUnitScenarioId, + Chapter: multiRes.Chapter, + Status: 2, + }, + }, + }) + } + res = multiunit.StatusResp{ + Result: multiunit.StatusData{ + MultiUnitScenarioStatusList: multiUnitsList, + UnlockedMultiUnitScenarioIds: []any{}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/museum/info.go b/internal/handler/api/museum/info.go new file mode 100644 index 0000000..ea4746d --- /dev/null +++ b/internal/handler/api/museum/info.go @@ -0,0 +1,51 @@ +package museum + +import ( + "honoka-chan/internal/schema/api/museum" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func museumInfo(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var museumRes []struct { + MuseumContentsId int `xorm:"museum_contents_id"` + SmileBuff int `xorm:"smile_buff"` + PureBuff int `xorm:"pure_buff"` + CoolBuff int `xorm:"cool_buff"` + } + var museumID []int + var smileBuff, pureBuff, coolBuff int + err = ss.MainEng.Table("museum_contents_m").Cols("museum_contents_id,smile_buff,pure_buff,cool_buff"). + OrderBy("museum_contents_id ASC").Find(&museumRes) + if ss.CheckErr(err) { + return + } + + for _, res := range museumRes { + smileBuff += res.SmileBuff + pureBuff += res.PureBuff + coolBuff += res.CoolBuff + museumID = append(museumID, res.MuseumContentsId) + } + res = museum.InfoResp{ + Result: museum.InfoData{ + MuseumInfo: museum.Info{ + Parameter: museum.Parameter{ + Smile: smileBuff, + Pure: pureBuff, + Cool: coolBuff, + }, + ContentsIDList: museumID, + }, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/museum/museum.go b/internal/handler/api/museum/museum.go new file mode 100644 index 0000000..53f436e --- /dev/null +++ b/internal/handler/api/museum/museum.go @@ -0,0 +1,17 @@ +package museum + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func MuseumApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "info": + res, err = museumInfo(ctx) + default: + err = fmt.Errorf("unimplemented action: museum: %s", action) + } + return res, err +} diff --git a/internal/handler/api/navigation/navigation.go b/internal/handler/api/navigation/navigation.go new file mode 100644 index 0000000..64d9767 --- /dev/null +++ b/internal/handler/api/navigation/navigation.go @@ -0,0 +1,15 @@ +package navigation + +import ( + "fmt" +) + +func NavigationApi(action string) (res any, err error) { + switch action { + case "specialCutin": + res, err = SpecialCutin() + default: + err = fmt.Errorf("unimplemented action: navigation: %s", action) + } + return res, err +} diff --git a/internal/handler/api/navigation/specialcutin.go b/internal/handler/api/navigation/specialcutin.go new file mode 100644 index 0000000..2834177 --- /dev/null +++ b/internal/handler/api/navigation/specialcutin.go @@ -0,0 +1,19 @@ +package navigation + +import ( + "honoka-chan/internal/schema/api/navigation" + "time" +) + +func SpecialCutin() (res any, err error) { + res = navigation.SpecialCutinResp{ + Result: navigation.SpecialCutinData{ + SpecialCutinList: []any{}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/notice/marquee.go b/internal/handler/api/notice/marquee.go new file mode 100644 index 0000000..a037ba1 --- /dev/null +++ b/internal/handler/api/notice/marquee.go @@ -0,0 +1,20 @@ +package notice + +import ( + "honoka-chan/internal/schema/api/notice" + "time" +) + +func noticeMarquee() (res any, err error) { + res = notice.MarqueeResp{ + Result: notice.MarqueeData{ + ItemCount: 0, + MarqueeList: []any{}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/notice/notice.go b/internal/handler/api/notice/notice.go new file mode 100644 index 0000000..327fa3f --- /dev/null +++ b/internal/handler/api/notice/notice.go @@ -0,0 +1,13 @@ +package notice + +import "fmt" + +func NoticeApi(action string) (res any, err error) { + switch action { + case "noticeMarquee": + res, err = noticeMarquee() + default: + err = fmt.Errorf("unimplemented action: notice: %s", action) + } + return res, err +} diff --git a/internal/handler/api/payment/payment.go b/internal/handler/api/payment/payment.go new file mode 100644 index 0000000..a2ca6cc --- /dev/null +++ b/internal/handler/api/payment/payment.go @@ -0,0 +1,13 @@ +package payment + +import "fmt" + +func PaymentApi(action string) (res any, err error) { + switch action { + case "productList": + res, err = productList() + default: + err = fmt.Errorf("unimplemented action: payment: %s", action) + } + return res, err +} diff --git a/internal/handler/api/payment/productlist.go b/internal/handler/api/payment/productlist.go new file mode 100644 index 0000000..3b6a400 --- /dev/null +++ b/internal/handler/api/payment/productlist.go @@ -0,0 +1,31 @@ +package payment + +import ( + "honoka-chan/internal/schema/api/payment" + "time" +) + +func productList() (res any, err error) { + res = payment.ProductListResp{ + Result: payment.ProductListData{ + RestrictionInfo: payment.RestrictionInfo{ + Restricted: false, + }, + UnderAgeInfo: payment.UnderAgeInfo{ + BirthSet: false, + HasLimit: false, + LimitAmount: nil, + MonthUsed: 0, + }, + SnsProductList: []payment.SnsProduct{}, + ProductList: []payment.Product{}, + SubscriptionList: []payment.Subscription{}, + ShowPointShop: false, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/profile/cardranking.go b/internal/handler/api/profile/cardranking.go new file mode 100644 index 0000000..4b88bb3 --- /dev/null +++ b/internal/handler/api/profile/cardranking.go @@ -0,0 +1,26 @@ +package profile + +import ( + "encoding/json" + "honoka-chan/internal/schema/api/profile" + honokautils "honoka-chan/pkg/utils" + "time" +) + +func cardRanking() (res any, err error) { + var result []any + love := honokautils.ReadAllText("assets/serverdata/love.json") + err = json.Unmarshal([]byte(love), &result) + if err != nil { + return nil, err + } + + res = profile.CardRankingResp{ + Result: result, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/profile/info.go b/internal/handler/api/profile/info.go new file mode 100644 index 0000000..a11812b --- /dev/null +++ b/internal/handler/api/profile/info.go @@ -0,0 +1,188 @@ +package profile + +import ( + "honoka-chan/internal/model/user" + "honoka-chan/internal/schema/api/profile" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func profileInfo(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + pref := user.UserPref{} + _, err = ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Get(&pref) + if err != nil { + return nil, err + } + + commonUnit, err := ss.MainEng.Table("common_unit_m").Count() + if err != nil { + return nil, err + } + + userUnit, err := ss.UserEng.Table("user_unit").Where("user_id = ?", ss.UserID).Count() + if err != nil { + return nil, err + } + + unitData := profile.UnitData{} + exists, err := ss.MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", pref.UnitOwningUserID).Get(&unitData) + if err != nil { + return nil, err + } + + isCommon := true + if !exists { + _, err = ss.UserEng.Table("user_unit"). + Where("unit_owning_user_id = ? AND user_id = ?", pref.UnitOwningUserID, ss.UserID).Get(&unitData) + if err != nil { + return nil, err + } + isCommon = false + } + + var attrId, maxHp, baseSmile, basePure, baseCool int + var smileMax, pureMax, coolMax int + if isCommon { + // 公共卡片仅为100级属性 + _, err = ss.MainEng.Table("unit_m").Where("unit_id = ?", unitData.UnitID). + Cols("attribute_id,hp_max,smile_max,pure_max,cool_max").Get(&attrId, &maxHp, &baseSmile, &basePure, &baseCool) + if err != nil { + return nil, err + } + + // 偷懒起见不计算饰品、宝石、回忆画廊等属性加成 + smileMax = baseSmile + pureMax = basePure + coolMax = baseCool + // } else { + // // 用户卡片需要根据等级计算属性 + // // TODO + } + + var accessoryOwningId, accessoryId, exp int + _, err = ss.UserEng.Table("user_accessory_wear").Where("unit_owning_user_id = ? AND user_id = ?", pref.UnitOwningUserID, ss.UserID). + Cols("accessory_owning_user_id").Get(&accessoryOwningId) + if err != nil { + return nil, err + } + _, err = ss.MainEng.Table("common_accessory_m").Where("accessory_owning_user_id = ?", accessoryOwningId). + Cols("accessory_id,exp").Get(&accessoryId, &exp) + if err != nil { + return nil, err + } + accessoryInfo := profile.AccessoryInfo{ + AccessoryOwningUserID: accessoryOwningId, + AccessoryID: accessoryId, + Exp: exp, + NextExp: 0, + Level: 8, + MaxLevel: 8, + RankUpCount: 4, + FavoriteFlag: true, + } + + removeSkillIds := []int{} + err = ss.UserEng.Table("user_unit_skill_equip").Where("unit_owning_user_id = ? AND user_id = ?", pref.UnitOwningUserID, ss.UserID). + Cols("unit_removable_skill_id").Find(&removeSkillIds) + if err != nil { + return nil, err + } + + res = profile.InfoResp{ + Result: profile.InfoData{ + UserInfo: profile.UserInfo{ + UserID: pref.UserID, + Name: pref.UserName, + Level: pref.UserLevel, + CostMax: 100, + UnitMax: 5000, + EnergyMax: 417, + FriendMax: 99, + UnitCnt: int(commonUnit + userUnit), + InviteCode: pref.InviteCode, + ElapsedTimeFromLogin: "14\u5c0f\u65f6\u524d", + Introduction: pref.UserDesc, + }, + CenterUnitInfo: profile.CenterUnitInfo{ + UnitOwningUserID: unitData.UnitOwningUserID, + UnitID: unitData.UnitID, + Exp: unitData.Exp, + NextExp: unitData.NextExp, + Level: unitData.Level, + LevelLimitID: unitData.LevelLimitID, + MaxLevel: unitData.MaxLevel, + Rank: unitData.Rank, + MaxRank: unitData.MaxRank, + Love: unitData.Love, + MaxLove: unitData.MaxLove, + UnitSkillLevel: unitData.UnitSkillLevel, + MaxHp: unitData.MaxHp, + FavoriteFlag: unitData.FavoriteFlag, + DisplayRank: unitData.DisplayRank, + UnitSkillExp: unitData.UnitSkillExp, + UnitRemovableSkillCapacity: unitData.UnitRemovableSkillCapacity, + Attribute: attrId, + Smile: baseSmile, + Cute: basePure, + Cool: baseCool, + IsLoveMax: unitData.IsLoveMax, + IsLevelMax: unitData.IsLevelMax, + IsRankMax: unitData.IsRankMax, + IsSigned: unitData.IsSigned, + IsSkillLevelMax: unitData.IsSkillLevelMax, + SettingAwardID: pref.AwardID, + RemovableSkillIds: removeSkillIds, + AccessoryInfo: accessoryInfo, + Costume: profile.Costume{}, + TotalSmile: smileMax, + TotalCute: pureMax, + TotalCool: coolMax, + TotalHp: maxHp, + }, + NaviUnitInfo: profile.NaviUnitInfo{ + UnitOwningUserID: unitData.UnitOwningUserID, + UnitID: unitData.UnitID, + Exp: unitData.Exp, + NextExp: unitData.NextExp, + Level: unitData.Level, + MaxLevel: unitData.MaxLevel, + LevelLimitID: unitData.LevelLimitID, + Rank: unitData.Rank, + MaxRank: unitData.MaxRank, + Love: unitData.Love, + MaxLove: unitData.MaxLove, + UnitSkillExp: unitData.UnitSkillExp, + UnitSkillLevel: unitData.UnitSkillLevel, + MaxHp: unitData.MaxHp, + UnitRemovableSkillCapacity: unitData.UnitRemovableSkillCapacity, + FavoriteFlag: unitData.FavoriteFlag, + DisplayRank: unitData.DisplayRank, + IsLoveMax: unitData.IsLoveMax, + IsLevelMax: unitData.IsLevelMax, + IsRankMax: unitData.IsRankMax, + IsSigned: unitData.IsSigned, + IsSkillLevelMax: unitData.IsSkillLevelMax, + IsRemovableSkillCapacityMax: unitData.IsRemovableSkillCapacityMax, + InsertDate: "2016-10-11 10:33:03", + TotalSmile: smileMax, + TotalCute: pureMax, + TotalCool: coolMax, + TotalHp: maxHp, + RemovableSkillIds: removeSkillIds, + }, + IsAlliance: false, + FriendStatus: 0, + SettingAwardID: pref.AwardID, + SettingBackgroundID: pref.BackgroundID, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/profile/livecnt.go b/internal/handler/api/profile/livecnt.go new file mode 100644 index 0000000..357bba6 --- /dev/null +++ b/internal/handler/api/profile/livecnt.go @@ -0,0 +1,38 @@ +package profile + +import ( + "honoka-chan/internal/schema/api/profile" + "time" +) + +func liveCnt() (res any, err error) { + res = profile.LiveCntResp{ + Result: []profile.LiveCntData{ + { + Difficulty: 1, + ClearCnt: 315, + }, + { + Difficulty: 2, + ClearCnt: 310, + }, + { + Difficulty: 3, + ClearCnt: 314, + }, + { + Difficulty: 4, + ClearCnt: 455, + }, + { + Difficulty: 6, + ClearCnt: 233, + }, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/profile/profile.go b/internal/handler/api/profile/profile.go new file mode 100644 index 0000000..5454534 --- /dev/null +++ b/internal/handler/api/profile/profile.go @@ -0,0 +1,21 @@ +package profile + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func ProfileApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "cardRanking": + res, err = cardRanking() + case "liveCnt": + res, err = liveCnt() + case "profileInfo": + res, err = profileInfo(ctx) + default: + err = fmt.Errorf("unimplemented action: profile: %s", action) + } + return res, err +} diff --git a/internal/handler/api/scenario/scenario.go b/internal/handler/api/scenario/scenario.go new file mode 100644 index 0000000..894cd38 --- /dev/null +++ b/internal/handler/api/scenario/scenario.go @@ -0,0 +1,17 @@ +package scenario + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func ScenarioApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "scenarioStatus": + res, err = scenarioStatus(ctx) + default: + err = fmt.Errorf("unimplemented action: scenario: %s", action) + } + return res, err +} diff --git a/internal/handler/api/scenario/status.go b/internal/handler/api/scenario/status.go new file mode 100644 index 0000000..c821475 --- /dev/null +++ b/internal/handler/api/scenario/status.go @@ -0,0 +1,37 @@ +package scenario + +import ( + "honoka-chan/internal/schema/api/scenario" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func scenarioStatus(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var scenarioID []int + scenarioLists := []scenario.StatusList{} + err = ss.MainEng.Table("scenario_m").Cols("scenario_id").OrderBy("scenario_id ASC").Find(&scenarioID) + if ss.CheckErr(err) { + return + } + + for _, id := range scenarioID { + scenarioLists = append(scenarioLists, scenario.StatusList{ + ScenarioID: id, + Status: 2, + }) + } + res = scenario.StatusResp{ + Result: scenario.StatusData{ + ScenarioStatusList: scenarioLists, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/stamp/info.go b/internal/handler/api/stamp/info.go new file mode 100644 index 0000000..4744701 --- /dev/null +++ b/internal/handler/api/stamp/info.go @@ -0,0 +1,13 @@ +package stamp + +import ( + "encoding/json" + honokautils "honoka-chan/pkg/utils" +) + +func stampInfo() (res any, err error) { + stampResp := honokautils.ReadAllText("assets/serverdata/stamp.json") + err = json.Unmarshal([]byte(stampResp), &res) + + return res, err +} diff --git a/internal/handler/api/stamp/stamp.go b/internal/handler/api/stamp/stamp.go new file mode 100644 index 0000000..b971070 --- /dev/null +++ b/internal/handler/api/stamp/stamp.go @@ -0,0 +1,13 @@ +package stamp + +import "fmt" + +func StampApi(action string) (res any, err error) { + switch action { + case "stampInfo": + res, err = stampInfo() + default: + err = fmt.Errorf("unimplemented action: stamp: %s", action) + } + return res, err +} diff --git a/internal/handler/api/subscenario/status.go b/internal/handler/api/subscenario/status.go new file mode 100644 index 0000000..8d28fa2 --- /dev/null +++ b/internal/handler/api/subscenario/status.go @@ -0,0 +1,38 @@ +package subscenario + +import ( + "honoka-chan/internal/schema/api/subscenario" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func subscenarioStatus(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var subScenarioID []int + subScenarioLists := []subscenario.StatusList{} + err = ss.MainEng.Table("subscenario_m").Cols("subscenario_id").OrderBy("subscenario_id ASC").Find(&subScenarioID) + if ss.CheckErr(err) { + return + } + + for _, id := range subScenarioID { + subScenarioLists = append(subScenarioLists, subscenario.StatusList{ + SubscenarioID: id, + Status: 2, + }) + } + res = subscenario.StatusResp{ + Result: subscenario.StatusData{ + SubscenarioStatusList: subScenarioLists, + UnlockedSubscenarioIds: []any{}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/subscenario/subscenario.go b/internal/handler/api/subscenario/subscenario.go new file mode 100644 index 0000000..c69347c --- /dev/null +++ b/internal/handler/api/subscenario/subscenario.go @@ -0,0 +1,17 @@ +package subscenario + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func SubscenarioApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "subscenarioStatus": + res, err = subscenarioStatus(ctx) + default: + err = fmt.Errorf("unimplemented action: subscenario: %s", action) + } + return res, err +} diff --git a/internal/handler/api/unit/accessoryall.go b/internal/handler/api/unit/accessoryall.go new file mode 100644 index 0000000..29395f0 --- /dev/null +++ b/internal/handler/api/unit/accessoryall.go @@ -0,0 +1,43 @@ +package unit + +import ( + "honoka-chan/internal/schema/api/unit" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func unitAccessoryAll(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + accessoryList := []unit.AccessoryList{} + err = ss.MainEng.Table("common_accessory_m").Find(&accessoryList) + if ss.CheckErr(err) { + return + } + for k := range accessoryList { + accessoryList[k].NextExp = 0 + accessoryList[k].Level = 8 + accessoryList[k].MaxLevel = 8 + accessoryList[k].RankUpCount = 4 + accessoryList[k].FavoriteFlag = true + } + wearingInfo := []unit.WearingInfo{} + err = ss.UserEng.Table("user_accessory_wear").Where("user_id = ?", ss.UserID).Find(&wearingInfo) + if ss.CheckErr(err) { + return + } + res = unit.AccessoryAllResp{ + Result: unit.AccessoryAllData{ + AccessoryList: accessoryList, + WearingInfo: wearingInfo, + EspecialCreateFlag: false, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/unit/all.go b/internal/handler/api/unit/all.go new file mode 100644 index 0000000..4649331 --- /dev/null +++ b/internal/handler/api/unit/all.go @@ -0,0 +1,38 @@ +package unit + +import ( + "honoka-chan/internal/schema/api/unit" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func unitAll(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + unitsData := []unit.Active{} + err = ss.MainEng.Table("common_unit_m").Find(&unitsData) + if ss.CheckErr(err) { + return + } + + userUnits := []unit.Active{} + err = ss.UserEng.Table("user_unit").Where("user_id = ?", ss.UserID).Find(&userUnits) + if ss.CheckErr(err) { + return + } + unitsData = append(unitsData, userUnits...) + + res = unit.AllResp{ + Result: unit.AllData{ + Active: unitsData, + Waiting: []unit.Waiting{}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/unit/deckinfo.go b/internal/handler/api/unit/deckinfo.go new file mode 100644 index 0000000..3ac93f8 --- /dev/null +++ b/internal/handler/api/unit/deckinfo.go @@ -0,0 +1,55 @@ +package unit + +import ( + "honoka-chan/internal/schema/api/unit" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func unitDeckInfo(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + userDeck := []unit.UserDeckData{} + err = ss.UserEng.Table("user_deck").Where("user_id = ?", ss.UserID).Asc("deck_id").Find(&userDeck) + if ss.CheckErr(err) { + return + } + + unitDeckInfo := []unit.DeckInfoData{} + for _, deck := range userDeck { + deckUnit := []unit.UnitDeckData{} + err = ss.UserEng.Table("user_deck_unit").Where("user_deck_id = ?", deck.ID).Asc("position").Find(&deckUnit) + if ss.CheckErr(err) { + return + } + + oUID := []unit.UnitOwningUserIds{} + for _, u := range deckUnit { + oUID = append(oUID, unit.UnitOwningUserIds{ + Position: u.Position, + UnitOwningUserID: u.UnitOwningUserID, + }) + } + + mainFlag := false + if deck.MainFlag == 1 { + mainFlag = true + } + unitDeckInfo = append(unitDeckInfo, unit.DeckInfoData{ + UnitDeckID: deck.DeckID, + MainFlag: mainFlag, + DeckName: deck.DeckName, + UnitOwningUserIds: oUID, + }) + } + res = unit.DeckInfoResp{ + Result: unitDeckInfo, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/unit/removableskillinfo.go b/internal/handler/api/unit/removableskillinfo.go new file mode 100644 index 0000000..99d49a6 --- /dev/null +++ b/internal/handler/api/unit/removableskillinfo.go @@ -0,0 +1,76 @@ +package unit + +import ( + "honoka-chan/internal/schema/api/unit" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func unitRemovableSkillInfo(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var skillEquipCount []unit.SkillEquipCount + err = ss.UserEng.Table("user_unit_skill_equip").Where("user_id = ?", ss.UserID).Select("unit_removable_skill_id,COUNT(*) AS ct"). + GroupBy("unit_removable_skill_id").Find(&skillEquipCount) + if ss.CheckErr(err) { + return + } + + var rmSkillIds []int + err = ss.MainEng.Table("unit_removable_skill_m").Where("effect_range = 1").Cols("unit_removable_skill_id").Find(&rmSkillIds) + if ss.CheckErr(err) { + return + } + + owingInfo := []unit.OwningInfo{} + for _, id := range rmSkillIds { + info := unit.OwningInfo{ + UnitRemovableSkillID: id, + TotalAmount: 9, + EquippedAmount: 0, + InsertDate: "2023-01-01 12:00:00", + } + for _, sk := range skillEquipCount { + if id == sk.UnitRemovableSkillId { + info.EquippedAmount = sk.Count + break + } + } + owingInfo = append(owingInfo, info) + } + + var unitOwningIds []int + err = ss.UserEng.Table("user_unit_skill_equip").Where("user_id = ?", ss.UserID).Cols("unit_owning_user_id").GroupBy("unit_owning_user_id").Find(&unitOwningIds) + if ss.CheckErr(err) { + return + } + + equipInfo := map[int]any{} + for _, v := range unitOwningIds { + detail := []unit.SkillEquipDetail{} + err = ss.UserEng.Table("user_unit_skill_equip").Where("user_id = ? AND unit_owning_user_id = ?", ss.UserID, v). + Cols("unit_removable_skill_id").Find(&detail) + if ss.CheckErr(err) { + return + } + + equipInfo[v] = unit.SkillEquipList{ + UnitOwningUserID: v, + Detail: detail, + } + } + + res = unit.RemovableSkillInfoResp{ + Result: unit.RemovableSkillInfoData{ + OwningInfo: owingInfo, + EquipmentInfo: equipInfo, + }, // 宝石 + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/unit/supporterall.go b/internal/handler/api/unit/supporterall.go new file mode 100644 index 0000000..9b6fb61 --- /dev/null +++ b/internal/handler/api/unit/supporterall.go @@ -0,0 +1,19 @@ +package unit + +import ( + "honoka-chan/internal/schema/api/unit" + "time" +) + +func unitSupporterAll() (res any, err error) { + res = unit.SupporterAllResp{ + Result: unit.SupporterAllData{ + UnitSupportList: []unit.SupporterList{}, + }, // 练习道具 + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/unit/unit.go b/internal/handler/api/unit/unit.go new file mode 100644 index 0000000..2ed19fa --- /dev/null +++ b/internal/handler/api/unit/unit.go @@ -0,0 +1,25 @@ +package unit + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func UnitApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "accessoryAll": + res, err = unitAccessoryAll(ctx) + case "deckInfo": + res, err = unitDeckInfo(ctx) + case "removableSkillInfo": + res, err = unitRemovableSkillInfo(ctx) + case "supporterAll": + res, err = unitSupporterAll() + case "unitAll": + res, err = unitAll(ctx) + default: + err = fmt.Errorf("unimplemented action: unit: %s", action) + } + return res, err +} diff --git a/internal/handler/api/user/getnavi.go b/internal/handler/api/user/getnavi.go new file mode 100644 index 0000000..9520705 --- /dev/null +++ b/internal/handler/api/user/getnavi.go @@ -0,0 +1,33 @@ +package user + +import ( + "honoka-chan/internal/schema/api/user" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func userGetNavi(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + var uID, oID int + _, err = ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Cols("user_id,unit_owning_user_id").Get(&uID, &oID) + if ss.CheckErr(err) { + return + } + + res = user.GetNaviResp{ + Result: user.GetNaviData{ + User: user.User{ + UserID: uID, + UnitOwningUserID: oID, + }, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/user/info.go b/internal/handler/api/user/info.go new file mode 100644 index 0000000..67c6d8e --- /dev/null +++ b/internal/handler/api/user/info.go @@ -0,0 +1,58 @@ +package user + +import ( + "honoka-chan/internal/model/user" + userapischema "honoka-chan/internal/schema/api/user" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func userInfo(ctx *gin.Context) (res any, err error) { + ss := session.Get(ctx) + + pref := user.UserPref{} + _, err = ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Get(&pref) + if err != nil { + return nil, err + } + + res = userapischema.InfoResp{ + Result: userapischema.UserInfo{ + UserID: ss.UserID, + Name: pref.UserName, + Level: pref.UserLevel, + Exp: 1089696, + PreviousExp: 0, + NextExp: 1207185, + GameCoin: 999999999, + SnsCoin: 100000, + FreeSnsCoin: 50000, + PaidSnsCoin: 50000, + SocialPoint: 1438395, + UnitMax: 5000, + WaitingUnitMax: 1000, + EnergyMax: 417, + EnergyFullTime: "2023-03-20 03:58:55", + LicenseLiveEnergyRecoverlyTime: 60, + EnergyFullNeedTime: 0, + OverMaxEnergy: 417, + TrainingEnergy: 100, + TrainingEnergyMax: 100, + FriendMax: 99, + InviteCode: pref.InviteCode, + InsertDate: "2015-08-10 18:58:30", + UpdateDate: "2018-08-09 18:13:12", + TutorialState: -1, + DiamondCoin: 0, + CrystalCoin: 0, + LpRecoveryItem: []userapischema.LpRecoveryItem{}, + }, + Status: 200, + CommandNum: false, + TimeStamp: time.Now().Unix(), + } + + return res, err +} diff --git a/internal/handler/api/user/user.go b/internal/handler/api/user/user.go new file mode 100644 index 0000000..f2cddc1 --- /dev/null +++ b/internal/handler/api/user/user.go @@ -0,0 +1,19 @@ +package user + +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func UserApi(ctx *gin.Context, action string) (res any, err error) { + switch action { + case "getNavi": + res, err = userGetNavi(ctx) + case "userInfo": + res, err = userInfo(ctx) + default: + err = fmt.Errorf("unimplemented action: user: %s", action) + } + return res, err +} diff --git a/internal/handler/award.go b/internal/handler/award.go deleted file mode 100644 index 78b344a..0000000 --- a/internal/handler/award.go +++ /dev/null @@ -1,33 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "honoka-chan/internal/tools" - - "github.com/gin-gonic/gin" - "github.com/tidwall/gjson" -) - -func AwardSet(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - req := gjson.Parse(ctx.PostForm("request_data")) - pref := tools.UserPref{ - AwardID: int(req.Get("award_id").Int()), - } - - _, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref) - if ss.CheckErr(err) { - return - } - - awardResp := model.AwardSetResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(awardResp) -} diff --git a/internal/handler/award/set.go b/internal/handler/award/set.go new file mode 100644 index 0000000..f554d10 --- /dev/null +++ b/internal/handler/award/set.go @@ -0,0 +1,37 @@ +package award + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/award" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" +) + +func set(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + reqData := gjson.Parse(ctx.MustGet("request_data").(string)) + pref := user.UserPref{ + AwardID: int(reqData.Get("award_id").Int()), + } + + _, err := ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Update(&pref) + if ss.CheckErr(err) { + return + } + + ss.Respond(award.SetResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/award/set", middleware.Common, set) +} diff --git a/internal/handler/background.go b/internal/handler/background.go deleted file mode 100644 index 646b082..0000000 --- a/internal/handler/background.go +++ /dev/null @@ -1,33 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "honoka-chan/internal/tools" - - "github.com/gin-gonic/gin" - "github.com/tidwall/gjson" -) - -func BackgroundSet(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - req := gjson.Parse(ctx.PostForm("request_data")) - pref := tools.UserPref{ - BackgroundID: int(req.Get("background_id").Int()), - } - - _, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref) - if ss.CheckErr(err) { - return - } - - backgroundResp := model.BackgroundSetResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(backgroundResp) -} diff --git a/internal/handler/background/set.go b/internal/handler/background/set.go new file mode 100644 index 0000000..4cfca5a --- /dev/null +++ b/internal/handler/background/set.go @@ -0,0 +1,37 @@ +package background + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/background" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" +) + +func set(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + reqData := gjson.Parse(ctx.MustGet("request_data").(string)) + pref := user.UserPref{ + BackgroundID: int(reqData.Get("background_id").Int()), + } + + _, err := ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Update(&pref) + if ss.CheckErr(err) { + return + } + + ss.Respond(background.SetResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/background/set", middleware.Common, set) +} diff --git a/internal/handler/download.go b/internal/handler/download.go deleted file mode 100644 index f0e38a8..0000000 --- a/internal/handler/download.go +++ /dev/null @@ -1,196 +0,0 @@ -package handler - -import ( - "encoding/json" - "fmt" - "honoka-chan/config" - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "io" - "net/http" - "strings" - - "github.com/gin-gonic/gin" - "xorm.io/builder" -) - -type PkgInfo struct { - Id int `xorm:"pkg_id"` - Order int `xorm:"pkg_order"` - Size int `xorm:"pkg_size"` -} - -func DownloadAdditional(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - downloadReq := model.AdditionalReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq) - if ss.CheckErr(err) { - return - } - - pkgList := []model.AdditionalRes{} - pkgType, pkgId := downloadReq.PackageType, downloadReq.PackageID - var pkgInfo []PkgInfo - err = ss.MainEng.Table("download_m").Where("pkg_type = ? AND pkg_id = ? AND pkg_os = ?", pkgType, pkgId, downloadReq.TargetOs). - Cols("pkg_id,pkg_order,pkg_size"). - OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo) - if ss.CheckErr(err) { - return - } - - for _, pkg := range pkgInfo { - pkgList = append(pkgList, model.AdditionalRes{ - Size: pkg.Size, - URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", - config.Conf.Settings.CdnServer, downloadReq.TargetOs, pkgType, pkg.Id, pkg.Order), - }) - } - - addResp := model.AdditionalResp{ - ResponseData: pkgList, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(addResp) -} - -func DownloadBatch(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - downloadReq := model.BatchReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq) - if ss.CheckErr(err) { - return - } - - pkgList := []model.BatchRes{} - if downloadReq.ClientVersion == config.PackageVersion { - pkgType := downloadReq.PackageType - var pkgInfo []PkgInfo - err := ss.MainEng.Table("download_m").Where(builder.NotIn("pkg_id", downloadReq.ExcludedPackageIds)).Where("pkg_type = ? AND pkg_os = ?", pkgType, downloadReq.Os). - Cols("pkg_id,pkg_order,pkg_size"). - OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo) - if ss.CheckErr(err) { - return - } - - for _, pkg := range pkgInfo { - pkgList = append(pkgList, model.BatchRes{ - Size: pkg.Size, - URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", - config.Conf.Settings.CdnServer, downloadReq.Os, pkgType, pkg.Id, pkg.Order), - }) - } - } - - batchResp := model.BatchResp{ - ResponseData: pkgList, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(batchResp) -} - -func DownloadUpdate(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - downloadReq := model.UpdateReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq) - if ss.CheckErr(err) { - return - } - - pkgList := []model.UpdateRes{} - if downloadReq.ExternalVersion != config.PackageVersion { - pkgType := 99 - var pkgInfo []PkgInfo - err := ss.MainEng.Table("download_m").Where("pkg_type = ? AND pkg_os = ?", pkgType, downloadReq.TargetOs). - Cols("pkg_id,pkg_order,pkg_size"). - OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo) - if ss.CheckErr(err) { - return - } - - for _, pkg := range pkgInfo { - pkgList = append(pkgList, model.UpdateRes{ - Size: pkg.Size, - URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", - config.Conf.Settings.CdnServer, downloadReq.TargetOs, pkgType, pkg.Id, pkg.Order), - Version: config.PackageVersion, - }) - } - - patchFileUrl := fmt.Sprintf("%s/%s/archives/99_0_115.zip", - config.Conf.Settings.CdnServer, downloadReq.TargetOs) - resp, err := http.Get(patchFileUrl) - if err == nil { - res, err := io.ReadAll(resp.Body) - if err == nil { - pkgList = append(pkgList, model.UpdateRes{ - Size: len(res), - URL: patchFileUrl, - Version: config.PackageVersion, - }) - } - defer resp.Body.Close() - } - } - - updateResp := model.UpdateResp{ - ResponseData: pkgList, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(updateResp) -} - -func DownloadUrl(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - downloadReq := model.UrlReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &downloadReq) - if ss.CheckErr(err) { - return - } - - cdnServer := config.Conf.Settings.BackupCdnServer - if cdnServer == "" { - cdnServer = config.Conf.Settings.CdnServer - } - - urlList := []string{} - for _, v := range downloadReq.PathList { - urlList = append(urlList, fmt.Sprintf("%s/%s/extracted/%s", - cdnServer, downloadReq.Os, strings.ReplaceAll(v, "\\", ""))) - } - urlResp := model.UrlResp{ - ResponseData: model.UrlRes{ - UrlList: urlList, - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(urlResp) -} - -func DownloadEvent(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - eventResp := model.EventResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(eventResp) -} diff --git a/internal/handler/download/additional.go b/internal/handler/download/additional.go new file mode 100644 index 0000000..59930a8 --- /dev/null +++ b/internal/handler/download/additional.go @@ -0,0 +1,58 @@ +package download + +import ( + "encoding/json" + "fmt" + "honoka-chan/config" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/download" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +type PkgInfo struct { + Id int `xorm:"pkg_id"` + Order int `xorm:"pkg_order"` + Size int `xorm:"pkg_size"` +} + +func additional(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + downloadReq := download.AdditionalReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &downloadReq) + if ss.CheckErr(err) { + return + } + + pkgList := []download.AdditionalData{} + pkgType, pkgId := downloadReq.PackageType, downloadReq.PackageID + var pkgInfo []PkgInfo + err = ss.MainEng.Table("download_m").Where("pkg_type = ? AND pkg_id = ? AND pkg_os = ?", pkgType, pkgId, downloadReq.TargetOs). + Cols("pkg_id,pkg_order,pkg_size"). + OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo) + if ss.CheckErr(err) { + return + } + + for _, pkg := range pkgInfo { + pkgList = append(pkgList, download.AdditionalData{ + Size: pkg.Size, + URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", + config.Conf.Settings.CdnServer, downloadReq.TargetOs, pkgType, pkg.Id, pkg.Order), + }) + } + + ss.Respond(download.AdditionalResp{ + ResponseData: pkgList, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/download/additional", middleware.Common, additional) +} diff --git a/internal/handler/download/batch.go b/internal/handler/download/batch.go new file mode 100644 index 0000000..2de4f15 --- /dev/null +++ b/internal/handler/download/batch.go @@ -0,0 +1,55 @@ +package download + +import ( + "encoding/json" + "fmt" + "honoka-chan/config" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/download" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" + "xorm.io/builder" +) + +func batch(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + downloadReq := download.BatchReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &downloadReq) + if ss.CheckErr(err) { + return + } + + pkgList := []download.BatchData{} + if downloadReq.ClientVersion == config.PackageVersion { + pkgType := downloadReq.PackageType + var pkgInfo []PkgInfo + err := ss.MainEng.Table("download_m").Where(builder.NotIn("pkg_id", downloadReq.ExcludedPackageIds)).Where("pkg_type = ? AND pkg_os = ?", pkgType, downloadReq.Os). + Cols("pkg_id,pkg_order,pkg_size"). + OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo) + if ss.CheckErr(err) { + return + } + + for _, pkg := range pkgInfo { + pkgList = append(pkgList, download.BatchData{ + Size: pkg.Size, + URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", + config.Conf.Settings.CdnServer, downloadReq.Os, pkgType, pkg.Id, pkg.Order), + }) + } + } + + ss.Respond(download.BatchResp{ + ResponseData: pkgList, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/download/batch", middleware.Common, batch) +} diff --git a/internal/handler/download/event.go b/internal/handler/download/event.go new file mode 100644 index 0000000..2bcea28 --- /dev/null +++ b/internal/handler/download/event.go @@ -0,0 +1,25 @@ +package download + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/download" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func event(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(download.EventResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/download/event", middleware.Common, event) +} diff --git a/internal/handler/download/update.go b/internal/handler/download/update.go new file mode 100644 index 0000000..c04ea2a --- /dev/null +++ b/internal/handler/download/update.go @@ -0,0 +1,72 @@ +package download + +import ( + "encoding/json" + "fmt" + "honoka-chan/config" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/download" + "honoka-chan/internal/session" + "io" + "net/http" + + "github.com/gin-gonic/gin" +) + +func update(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + downloadReq := download.UpdateReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &downloadReq) + if ss.CheckErr(err) { + return + } + + pkgList := []download.UpdateData{} + if downloadReq.ExternalVersion != config.PackageVersion { + pkgType := 99 + var pkgInfo []PkgInfo + err := ss.MainEng.Table("download_m").Where("pkg_type = ? AND pkg_os = ?", pkgType, downloadReq.TargetOs). + Cols("pkg_id,pkg_order,pkg_size"). + OrderBy("pkg_id ASC, pkg_order ASC").Find(&pkgInfo) + if ss.CheckErr(err) { + return + } + + for _, pkg := range pkgInfo { + pkgList = append(pkgList, download.UpdateData{ + Size: pkg.Size, + URL: fmt.Sprintf("%s/%s/archives/%d_%d_%d.zip", + config.Conf.Settings.CdnServer, downloadReq.TargetOs, pkgType, pkg.Id, pkg.Order), + Version: config.PackageVersion, + }) + } + + patchFileURL := fmt.Sprintf("%s/%s/archives/99_0_115.zip", + config.Conf.Settings.CdnServer, downloadReq.TargetOs) + resp, err := http.Get(patchFileURL) + if err == nil { + res, err := io.ReadAll(resp.Body) + if err == nil { + pkgList = append(pkgList, download.UpdateData{ + Size: len(res), + URL: patchFileURL, + Version: config.PackageVersion, + }) + } + defer resp.Body.Close() + } + } + + ss.Respond(download.UpdateResp{ + ResponseData: pkgList, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/download/update", middleware.Common, update) +} diff --git a/internal/handler/download/url.go b/internal/handler/download/url.go new file mode 100644 index 0000000..e1d9a25 --- /dev/null +++ b/internal/handler/download/url.go @@ -0,0 +1,48 @@ +package download + +import ( + "encoding/json" + "fmt" + "honoka-chan/config" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/download" + "honoka-chan/internal/session" + "strings" + + "github.com/gin-gonic/gin" +) + +func url(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + downloadReq := download.UrlReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &downloadReq) + if ss.CheckErr(err) { + return + } + + cdnServer := config.Conf.Settings.BackupCdnServer + if cdnServer == "" { + cdnServer = config.Conf.Settings.CdnServer + } + + urlList := []string{} + for _, v := range downloadReq.PathList { + urlList = append(urlList, fmt.Sprintf("%s/%s/extracted/%s", + cdnServer, downloadReq.Os, strings.ReplaceAll(v, "\\", ""))) + } + + ss.Respond(download.UrlResp{ + ResponseData: download.UrlData{ + UrlList: urlList, + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/download/url", middleware.Common, url) +} diff --git a/internal/handler/event.go b/internal/handler/event.go deleted file mode 100644 index c04a8eb..0000000 --- a/internal/handler/event.go +++ /dev/null @@ -1,32 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "time" - - "github.com/gin-gonic/gin" -) - -func EventList(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - targets := []model.TargetList{} - for i := range 6 { - targets = append(targets, model.TargetList{ - Position: i + 1, - IsDisplayable: false, - }) - } - eventsResp := model.EventsResp{ - ResponseData: model.EventsRes{ - TargetList: targets, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(eventsResp) -} diff --git a/internal/handler/event/list.go b/internal/handler/event/list.go new file mode 100644 index 0000000..c521881 --- /dev/null +++ b/internal/handler/event/list.go @@ -0,0 +1,45 @@ +package event + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/event" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func list(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + targets := []event.TargetList{} + for i := range 6 { + targets = append(targets, event.TargetList{ + Position: i + 1, + IsDisplayable: false, + }) + } + + // ss.Respond(event.ListResp{ + // ResponseData: map[string]int{ + // "error_code": 10004, + // }, + // ReleaseInfo: []any{}, + // StatusCode: 600, + // }) + + ss.Respond(event.ListResp{ + ResponseData: event.ListData{ + TargetList: targets, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/event/eventList", middleware.Common, list) +} diff --git a/internal/handler/gdpr.go b/internal/handler/gdpr.go deleted file mode 100644 index 195ed9c..0000000 --- a/internal/handler/gdpr.go +++ /dev/null @@ -1,26 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "time" - - "github.com/gin-gonic/gin" -) - -func Gdpr(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - gdprResp := model.GdprResp{ - ResponseData: model.GdprRes{ - EnableGdpr: true, - IsEea: false, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(gdprResp) -} diff --git a/internal/handler/gdpr/get.go b/internal/handler/gdpr/get.go new file mode 100644 index 0000000..4454860 --- /dev/null +++ b/internal/handler/gdpr/get.go @@ -0,0 +1,30 @@ +package gdpr + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/gdpr" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func get(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(gdpr.GetResp{ + ResponseData: gdpr.GetData{ + EnableGdpr: true, + IsEea: false, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/gdpr/get", middleware.Common, get) +} diff --git a/internal/handler/ghome/account/active.go b/internal/handler/ghome/account/active.go new file mode 100644 index 0000000..e95e0d7 --- /dev/null +++ b/internal/handler/ghome/account/active.go @@ -0,0 +1,27 @@ +package account + +import ( + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func active(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + ss.Respond(ghome.ActiveResp{ + Code: 0, + Msg: "ok", + Data: ghome.ActiveData{ + Message: "ok", + Result: 0, + }, + }) +} + +func init() { + router.AddHandler("v1", "POST", "/account/active", active) +} diff --git a/internal/handler/ghome/account/initialize.go b/internal/handler/ghome/account/initialize.go new file mode 100644 index 0000000..f8973dc --- /dev/null +++ b/internal/handler/ghome/account/initialize.go @@ -0,0 +1,50 @@ +package account + +import ( + "encoding/base64" + "encoding/json" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-think/openssl" +) + +func initialize(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + initData := ghome.InitializeData{ + BrandLogo: "http://gskd.sdo.com/ghome/ztc/logo/og/logo_xhdpi.png", + BrandName: "盛趣游戏", + ForceShowAgreement: 1, + GreportLogLevel: "off", + LogLevel: "off", + LoginButton: []string{"official"}, + LoginIcon: []any{}, + NeedFloatWindowPermission: 1, + NewDeviceIDServer: strings.ToUpper(openssl.Md5ToString(ss.GetDeviceID())), + ShowGuestConfirm: 1, + VoicetipButton: 1, + } + data, err := json.Marshal(initData) + if ss.CheckErr(err) { + return + } + encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), ss.GetRandKey()[0:24], openssl.PKCS7_PADDING) + if ss.CheckErr(err) { + return + } + + ss.Respond(ghome.InitializeResp{ + Code: 0, + Msg: "ok", + Data: base64.StdEncoding.EncodeToString(encryptedData), + }) +} + +func init() { + router.AddHandler("v1", "POST", "/account/initialize", initialize) +} diff --git a/internal/handler/ghome/account/login.go b/internal/handler/ghome/account/login.go new file mode 100644 index 0000000..8f2f9d5 --- /dev/null +++ b/internal/handler/ghome/account/login.go @@ -0,0 +1,248 @@ +package account + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/api/profile" + "honoka-chan/internal/schema/api/unit" + ghomeschema "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + honokautils "honoka-chan/pkg/utils" + "net/url" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-think/openssl" +) + +func login(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + data, err := ctx.GetRawData() + if ss.CheckErr(err) { + return + } + + data, err = base64.StdEncoding.DecodeString(string(data)) + if ss.CheckErr(err) { + return + } + + randKey := ss.GetRandKey() + decryptedData, err := openssl.Des3ECBDecrypt(data, randKey[0:24], openssl.PKCS7_PADDING) + if ss.CheckErr(err) { + return + } + + queryStr, _ := url.QueryUnescape(string(decryptedData)) + params, _ := url.ParseQuery(queryStr) + phone, password := params.Get("phone"), params.Get("password") + + var userID int + var pass, autoKey, ticket string + _, err = ss.UserEng.Table("users").Cols("password,autokey,ticket,user_id"). + Where("phone = ?", phone).Get(&pass, &autoKey, &ticket, &userID) + if ss.CheckErr(err) { + return + } + + loginData := ghomeschema.LoginData{} + loginCode := 0 + loginMsg := "ok" + loginTime := time.Now().Unix() + if pass == "" { + // 未注册 - 自动注册 + // 检查是否 userID 已经注册 + userID, _ = checkUserID(ss, int(loginTime)) + + pass = openssl.Md5ToString(password) + autoKey = "AUTO" + strings.ToUpper(honokautils.RandomStr(32)) + ticket = fmt.Sprintf("9999999%d%d", userID, userID) + + userData := user.Users{ + Phone: phone, + Password: pass, + Autokey: autoKey, + Ticket: ticket, + UserID: userID, + LastLoginTime: loginTime, + } + _, err = ss.UserEng.Table("users").Insert(&userData) + if ss.CheckErr(err) { + return + } + + // 方便起见初始化 userid 和 key 一样 + // 注意:user_key 表中的 key 是上文生成的用于登录的 userid,而 userid 则是用于 Authorize Token 生成用的 + userKey := user.UserKey{ + UserID: userID, + Key: userID, + } + _, err = ss.UserEng.Table("user_key").Insert(&userKey) + if ss.CheckErr(err) { + return + } + + // 检查用户配置 + exists, err := ss.UserEng.Table("user_pref").Where("user_id = ?", userID).Exist() + if ss.CheckErr(err) { + return + } + + if !exists { + // 默认中心成员 + var unitOwningUserID int + _, err = ss.MainEng.Table("common_unit_m").Cols("unit_owning_user_id").Where("unit_id = ?", 31).Get(&unitOwningUserID) + if ss.CheckErr(err) { + return + } + + userPref := user.UserPref{ + UserID: userID, + AwardID: 1, // 音乃木坂学生 + BackgroundID: 1, // 初始背景 + UnitOwningUserID: unitOwningUserID, + UserName: "音乃木坂学生", + UserLevel: 1, + UserDesc: "你好。", + InviteCode: strconv.Itoa(userID), + UpdateTime: time.Now().Unix(), + } + _, err = ss.UserEng.Table("user_pref").Insert(&userPref) + if ss.CheckErr(err) { + return + } + } + + // 检查用户卡组配置 + exists, err = ss.UserEng.Table("user_deck").Where("user_id = ?", userID).Exist() + if ss.CheckErr(err) { + return + } + + if !exists { + // 默认队伍 + userDeck := unit.UserDeckData{ + DeckID: 1, + MainFlag: 1, + DeckName: "队伍A", + UserID: userID, + InsertDate: time.Now().Unix(), + } + _, err = ss.UserEng.Table("user_deck").Insert(&userDeck) + userDeckID := userDeck.ID + + // 默认卡组 - 仆光 + unitID := []int{} + err = ss.MainEng.Table("unit_m").Cols("unit_id").Where("album_series_id = ?", 615).Find(&unitID) + if ss.CheckErr(err) { + return + } + + unitData := []profile.UnitData{} + err = ss.MainEng.Table("common_unit_m").In("unit_id", unitID).Find(&unitData) + if ss.CheckErr(err) { + return + } + + position := 1 + for _, u := range unitData { + unitDeckData := unit.UnitDeckData{ + UserDeckID: userDeckID, + UnitOwningUserID: u.UnitOwningUserID, + UnitID: u.UnitID, + Position: position, + Level: 100, + LevelLimitID: 1, + DisplayRank: 2, + Love: 1000, + UnitSkillLevel: 8, + IsRankMax: true, + IsLoveMax: true, + IsLevelMax: true, + IsSigned: u.IsSigned, + BeforeLove: 1000, + MaxLove: 1000, + InsertData: time.Now().Unix(), + } + _, err = ss.UserEng.Table("user_deck_unit").Insert(&unitDeckData) + if ss.CheckErr(err) { + return + } + + position++ + } + } + + loginData.Autokey = autoKey + loginData.HasRealInfo = 1 + loginData.Message = "ok" + loginData.RealInfoForce = 1 + loginData.Ticket = ticket + loginData.UserAttribute = "0" + loginData.UserID = userID + } else { + // 已注册 - 检查密码 + if pass != openssl.Md5ToString(password) { + loginCode = 31 + loginMsg = "账号不存在或者密码有误!" + } else { + userData := user.Users{ + Autokey: autoKey, + Ticket: ticket, + LastLoginTime: loginTime, + } + _, err = ss.UserEng.Table("users").Where("user_id = ?", userID).Update(&userData) + if ss.CheckErr(err) { + return + } + + loginData.Autokey = autoKey // 注意:更换设备(deviceId 发生变化)应重新生成 autokey + loginData.HasRealInfo = 1 + loginData.Message = "ok" + loginData.RealInfoForce = 1 + loginData.Ticket = fmt.Sprintf("9999999%d%d", userID, loginTime) // 实际登录用的密码(每次登录都会重新生成新的) + loginData.UserAttribute = "0" + loginData.UserID = userID // 实际登录用的账号 + } + } + + data, err = json.Marshal(loginData) + if ss.CheckErr(err) { + return + } + encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING) + if ss.CheckErr(err) { + return + } + + ss.Respond(ghomeschema.LoginResp{ + Code: loginCode, + Msg: loginMsg, + Data: base64.StdEncoding.EncodeToString(encryptedData), + }) +} + +func checkUserID(ss *session.Session, userID int) (int, bool) { + exist, err := ss.UserEng.Table("users").Where("user_id = ?", userID).Exist() + if ss.CheckErr(err) { + return 0, false + } + + if exist { + userID = int(time.Now().Unix()) + return checkUserID(ss, userID) + } + + return userID, true +} + +func init() { + router.AddHandler("v1", "POST", "/account/login", login) +} diff --git a/internal/handler/ghome/account/loginauto.go b/internal/handler/ghome/account/loginauto.go new file mode 100644 index 0000000..ce1bb2a --- /dev/null +++ b/internal/handler/ghome/account/loginauto.go @@ -0,0 +1,83 @@ +package account + +import ( + "encoding/base64" + "encoding/json" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + "net/url" + + "github.com/gin-gonic/gin" + "github.com/go-think/openssl" +) + +func loginAuto(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + data, err := ctx.GetRawData() + if ss.CheckErr(err) { + return + } + + data, err = base64.StdEncoding.DecodeString(string(data)) + if ss.CheckErr(err) { + return + } + + randKey := ss.GetRandKey() + decryptedData, err := openssl.Des3ECBDecrypt(data, randKey[0:24], openssl.PKCS7_PADDING) + if ss.CheckErr(err) { + return + } + + queryStr, _ := url.QueryUnescape(string(decryptedData)) + params, _ := url.ParseQuery(queryStr) + autoKey := params.Get("autokey") + + var uid, ticket string + _, err = ss.UserEng.Table("users").Cols("user_id,ticket").Where("autokey = ?", autoKey).Get(&uid, &ticket) + if ss.CheckErr(err) { + return + } + + loginAutoData := ghome.LoginAutoData{} + loginAutoCode := 0 + loginAutoMsg := "ok" + if uid != "" { + loginAutoData = ghome.LoginAutoData{ + Result: loginAutoCode, + Message: loginAutoMsg, + Autokey: autoKey, + UserId: uid, + Ticket: ticket, + } + } else { + loginAutoCode = 31 + loginAutoMsg = "账号不存在或者登陆状态已过期!" + loginAutoData = ghome.LoginAutoData{ + Result: loginAutoCode, + Message: loginAutoMsg, + } + } + + data, err = json.Marshal(loginAutoData) + if ss.CheckErr(err) { + return + } + encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING) + if ss.CheckErr(err) { + return + } + + ss.Respond(ghome.LoginAutoResp{ + Code: loginAutoCode, + Msg: loginAutoMsg, + Data: base64.StdEncoding.EncodeToString(encryptedData), + }) +} + +func init() { + router.AddHandler("v1", "POST", "/account/loginauto", loginAuto) +} diff --git a/internal/handler/ghome/account/reportrole.go b/internal/handler/ghome/account/reportrole.go new file mode 100644 index 0000000..515a1ba --- /dev/null +++ b/internal/handler/ghome/account/reportrole.go @@ -0,0 +1,33 @@ +package account + +import ( + "encoding/base64" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" + "github.com/go-think/openssl" +) + +func reportRole(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + randKey := ss.GetRandKey() + token := `{"message":"ok"}` + encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), randKey[0:24], openssl.PKCS7_PADDING) + if ss.CheckErr(err) { + return + } + + ss.Respond(ghome.ReportRoleResp{ + Code: 0, + Msg: "ok", + Data: base64.StdEncoding.EncodeToString(encryptedToken), + }) +} + +func init() { + router.AddHandler("v1", "POST", "/account/reportRole", reportRole) +} diff --git a/internal/handler/ghome/basic/getcode.go b/internal/handler/ghome/basic/getcode.go new file mode 100644 index 0000000..9241671 --- /dev/null +++ b/internal/handler/ghome/basic/getcode.go @@ -0,0 +1,33 @@ +package basic + +import ( + "encoding/json" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func getCode(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + codeArray := `{"codeArray":[{"btntext":"好的","code":"-10264022","msg_from":2,"text":"","title":"短信验证码被阻止","type":1},{"btntext":"","code":"-10869623","msg_from":2,"text":"","title":"网络连接失败,无法一键登录","type":2},{"btntext":"","code":"10298300","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298311","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298312","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298313","msg_from":2,"text":"","title":"","type":1},{"btntext":"","code":"10298321","msg_from":2,"text":"","title":"","type":3},{"btntext":"","code":"10298322","msg_from":2,"text":"","title":"","type":3}],"codeVersion":"1.0.5"}` + getCodeData := map[string]any{} + err := json.Unmarshal([]byte(codeArray), &getCodeData) + if ss.CheckErr(err) { + return + } + + ss.Respond(ghome.GetCodeResp{ + Code: 0, + Msg: "ok", + Data: getCodeData, + }) +} + +func init() { + router.AddHandler("v1", "GET", "/basic/getcode", getCode) + router.AddHandler("v1", "POST", "/basic/getcode", getCode) +} diff --git a/internal/handler/ghome/basic/getproductlist.go b/internal/handler/ghome/basic/getproductlist.go new file mode 100644 index 0000000..2930d17 --- /dev/null +++ b/internal/handler/ghome/basic/getproductlist.go @@ -0,0 +1,29 @@ +package basic + +import ( + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func getProductList(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + getProductListData := ghome.GetProductListData{ + Message: []string{}, + Result: 0, + } + + ss.Respond(ghome.GetProductListResp{ + Code: 1, + Msg: "ok", + Data: getProductListData, + }) +} + +func init() { + router.AddHandler("v1", "POST", "/basic/getProductList", getProductList) +} diff --git a/internal/handler/ghome/basic/handshake.go b/internal/handler/ghome/basic/handshake.go new file mode 100644 index 0000000..7a5b69c --- /dev/null +++ b/internal/handler/ghome/basic/handshake.go @@ -0,0 +1,60 @@ +package basic + +import ( + "encoding/base64" + "fmt" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + "honoka-chan/pkg/db" + "honoka-chan/pkg/encrypt" + honokautils "honoka-chan/pkg/utils" + "net/url" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-think/openssl" +) + +func handshake(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + data, err := ctx.GetRawData() + if ss.CheckErr(err) { + return + } + + data, err = base64.StdEncoding.DecodeString(string(data)) + if ss.CheckErr(err) { + return + } + + decryptedData := encrypt.RSADecrypt(data) + + params, _ := url.ParseQuery(string(decryptedData)) + + randKey := []byte(params.Get("randkey")) + deviceID := ss.GetDeviceID() + + err = db.Ldb.Set([]byte(deviceID), randKey) + if ss.CheckErr(err) { + return + } + + token := fmt.Sprintf(`{"message":"ok","result":0,"token":"%s"}`, strings.ToUpper(honokautils.RandomStr(33))) + encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), randKey[0:24], openssl.PKCS7_PADDING) + if ss.CheckErr(err) { + return + } + + ss.Respond(ghome.HandshakeResp{ + Code: 0, + Msg: "ok", + Data: base64.StdEncoding.EncodeToString(encryptedToken), + }) +} + +func init() { + router.AddHandler("v1", "POST", "/basic/handshake", handshake) +} diff --git a/internal/handler/ghome/basic/loginarea.go b/internal/handler/ghome/basic/loginarea.go new file mode 100644 index 0000000..81ff233 --- /dev/null +++ b/internal/handler/ghome/basic/loginarea.go @@ -0,0 +1,26 @@ +package basic + +import ( + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func loginArea(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + ss.Respond(ghome.LoginAreaResp{ + Code: 0, + Msg: "ok", + Data: ghome.LoginAreaData{ + UserID: ctx.PostForm("userid"), + }, + }) +} + +func init() { + router.AddHandler("v1", "POST", "/basic/loginarea", loginArea) +} diff --git a/internal/handler/ghome/basic/publickey.go b/internal/handler/ghome/basic/publickey.go new file mode 100644 index 0000000..14258f6 --- /dev/null +++ b/internal/handler/ghome/basic/publickey.go @@ -0,0 +1,45 @@ +package basic + +import ( + "encoding/base64" + "encoding/pem" + "honoka-chan/config" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + honokautils "honoka-chan/pkg/utils" + + "github.com/gin-gonic/gin" +) + +func publicKey(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + publicKeyCode := 0 + publicKeyMsg := "ok" + publicKeyData := ghome.PublicKeyData{ + Result: publicKeyCode, + Message: publicKeyMsg, + } + + publicKey := honokautils.ReadAllText(config.PublicKeyPath) + block, _ := pem.Decode([]byte(publicKey)) + if block == nil || block.Type != "PUBLIC KEY" { + publicKeyMsg = "公钥读取失败!" + publicKeyCode = 31 + } else { + publicKeyData.Key = base64.StdEncoding.EncodeToString(block.Bytes) + publicKeyData.Method = "rsa" + } + + ss.Respond(ghome.PublicKeyResp{ + Code: publicKeyCode, + Msg: publicKeyMsg, + Data: publicKeyData, + }) +} + +func init() { + router.AddHandler("v1", "POST", "/basic/publickey", publicKey) +} diff --git a/internal/handler/ghome/ghome.go b/internal/handler/ghome/ghome.go new file mode 100644 index 0000000..a85bcaf --- /dev/null +++ b/internal/handler/ghome/ghome.go @@ -0,0 +1,8 @@ +package ghome + +import ( + _ "honoka-chan/internal/handler/ghome/account" + _ "honoka-chan/internal/handler/ghome/basic" + _ "honoka-chan/internal/handler/ghome/guest" + _ "honoka-chan/internal/handler/ghome/misc" +) diff --git a/internal/handler/ghome/guest/status.go b/internal/handler/ghome/guest/status.go new file mode 100644 index 0000000..018cc23 --- /dev/null +++ b/internal/handler/ghome/guest/status.go @@ -0,0 +1,29 @@ +package guest + +import ( + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func status(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + ss.Respond(ghome.GuestStatusResp{ + Code: 0, + Msg: "ok", + Data: ghome.GuestStatusData{ + Disablead: 1, + Loginswitch: 1, + Message: "ok", + Result: 0, + }, + }) +} + +func init() { + router.AddHandler("v1", "POST", "/guest/status", status) +} diff --git a/internal/handler/ghome/misc/agreement.go b/internal/handler/ghome/misc/agreement.go new file mode 100644 index 0000000..249e50e --- /dev/null +++ b/internal/handler/ghome/misc/agreement.go @@ -0,0 +1,25 @@ +package misc + +import ( + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func agreement(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + ss.Respond(ghome.AgreementResp{ + ReturnCode: 0, + ErrorType: 0, + ReturnMessage: "", + Data: ghome.AgreementData{}, + }) +} + +func init() { + router.AddHandler("/", "GET", "/agreement/all", agreement) +} diff --git a/internal/handler/ghome/misc/integration.go b/internal/handler/ghome/misc/integration.go new file mode 100644 index 0000000..336a4bb --- /dev/null +++ b/internal/handler/ghome/misc/integration.go @@ -0,0 +1,26 @@ +package misc + +import ( + "honoka-chan/internal/router" + "honoka-chan/internal/schema/ghome" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func appReport(ctx *gin.Context) { + ss := session.New(ctx) + defer ss.Finalize() + + ss.Respond(ghome.AppReportResp{ + Code: 0, + Msg: "", + Data: ghome.AppReportData{ + NeedReport: 0, + }, + }) +} + +func init() { + router.AddHandler("/", "GET", "/integration/appReport/initialize", appReport) +} diff --git a/internal/handler/ghome/misc/report.go b/internal/handler/ghome/misc/report.go new file mode 100644 index 0000000..669a6c5 --- /dev/null +++ b/internal/handler/ghome/misc/report.go @@ -0,0 +1,16 @@ +package misc + +import ( + "honoka-chan/internal/router" + "net/http" + + "github.com/gin-gonic/gin" +) + +func report(ctx *gin.Context) { + ctx.Status(http.StatusOK) +} + +func init() { + router.AddHandler("/", "POST", "/report/ge/app", report) +} diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 6e390f8..da5eb86 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -1,5 +1,28 @@ package handler -var ( - ErrorMsg = `{"code":20001,"message":""}` +import ( + _ "honoka-chan/internal/handler/album" + _ "honoka-chan/internal/handler/announce" + _ "honoka-chan/internal/handler/api" + _ "honoka-chan/internal/handler/award" + _ "honoka-chan/internal/handler/background" + _ "honoka-chan/internal/handler/download" + _ "honoka-chan/internal/handler/event" + _ "honoka-chan/internal/handler/gdpr" + _ "honoka-chan/internal/handler/ghome" + _ "honoka-chan/internal/handler/lbonus" + _ "honoka-chan/internal/handler/live" + _ "honoka-chan/internal/handler/login" + _ "honoka-chan/internal/handler/multiunit" + _ "honoka-chan/internal/handler/museum" + _ "honoka-chan/internal/handler/notice" + _ "honoka-chan/internal/handler/payment" + _ "honoka-chan/internal/handler/personalnotice" + _ "honoka-chan/internal/handler/profile" + _ "honoka-chan/internal/handler/scenario" + _ "honoka-chan/internal/handler/subscenario" + _ "honoka-chan/internal/handler/tos" + _ "honoka-chan/internal/handler/unit" + _ "honoka-chan/internal/handler/user" + _ "honoka-chan/internal/handler/webui" ) diff --git a/internal/handler/lbonus.go b/internal/handler/lbonus/execute.go similarity index 72% rename from internal/handler/lbonus.go rename to internal/handler/lbonus/execute.go index 35dde43..626d817 100644 --- a/internal/handler/lbonus.go +++ b/internal/handler/lbonus/execute.go @@ -1,15 +1,17 @@ -package handler +package lbonus import ( - "honoka-chan/internal/model" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/lbonus" "honoka-chan/internal/session" "time" "github.com/gin-gonic/gin" ) -func LBonusExecute(ctx *gin.Context) { - ss := session.New(ctx) +func execute(ctx *gin.Context) { + ss := session.Get(ctx) defer ss.Finalize() weeks := map[string]int{ @@ -33,7 +35,7 @@ func LBonusExecute(ctx *gin.Context) { d2 := d1.AddDate(0, 1, -1) // fmt.Println(d2) - weeksList := []model.LbDays{} + weeksList := []lbonus.Day{} for c := d1; ; c = c.AddDate(0, 0, 1) { _, _, rd := c.Date() received := false @@ -41,14 +43,14 @@ func LBonusExecute(ctx *gin.Context) { received = true } rw := weeks[c.Weekday().String()] - weeksList = append(weeksList, model.LbDays{ + weeksList = append(weeksList, lbonus.Day{ Day: rd, DayOfTheWeek: rw, SpecialDay: false, SpecialImageAsset: "", Received: received, AdReceived: false, - Item: model.LbDayItem{ + Item: lbonus.Item{ ItemID: 4, AddType: 3001, Amount: 1, @@ -70,18 +72,18 @@ func LBonusExecute(ctx *gin.Context) { d2 = d1.AddDate(0, 1, -1) // fmt.Println(d2) - nextWeeksList := []model.LbDays{} + nextWeeksList := []lbonus.Day{} for c := d1; ; c = c.AddDate(0, 0, 1) { _, _, rd := c.Date() rw := weeks[c.Weekday().String()] - nextWeeksList = append(nextWeeksList, model.LbDays{ + nextWeeksList = append(nextWeeksList, lbonus.Day{ Day: rd, DayOfTheWeek: rw, SpecialDay: false, SpecialImageAsset: "", Received: false, AdReceived: false, - Item: model.LbDayItem{ + Item: lbonus.Item{ ItemID: 4, AddType: 3001, Amount: 1, @@ -92,26 +94,26 @@ func LBonusExecute(ctx *gin.Context) { } } - LbRes := model.LbResp{ - ResponseData: model.LbRes{ + resp := lbonus.ExecuteResp{ + ResponseData: lbonus.ExecuteData{ Sheets: []any{}, - CalendarInfo: model.CalendarInfo{ + CalendarInfo: lbonus.CalendarInfo{ CurrentDate: time.Now().Format("2006-01-02 03:04:05"), - CurrentMonth: model.LbMonth{ + CurrentMonth: lbonus.Month{ Year: y, Month: int(cm), Days: weeksList, }, - NextMonth: model.LbMonth{ + NextMonth: lbonus.Month{ Year: y, Month: int(m), Days: nextWeeksList, }, }, - TotalLoginInfo: model.TotalLoginInfo{ + TotalLoginInfo: lbonus.TotalLoginInfo{ LoginCount: 2626, RemainingCount: 74, - Reward: []model.Reward{ + Reward: []lbonus.Reward{ { ItemID: 5, AddType: 1000, @@ -120,8 +122,8 @@ func LBonusExecute(ctx *gin.Context) { }, }, LicenseLbonusList: []any{}, - ClassSystem: model.LbClassSystem{ - RankInfo: model.LbRankInfo{ + ClassSystem: lbonus.ClassSystem{ + RankInfo: lbonus.RankInfo{ BeforeClassRankID: 10, AfterClassRankID: 10, RankUpDate: "2020-02-12 11:57:15", @@ -131,17 +133,17 @@ func LBonusExecute(ctx *gin.Context) { IsVisible: true, }, StartDashSheets: []any{}, - EffortPoint: []model.EffortPoint{ + EffortPoint: []lbonus.EffortPoint{ { LiveEffortPointBoxSpecID: 5, Capacity: 4000000, Before: 1400116, After: 1400116, - Rewards: []model.Rewards{}, + Rewards: []lbonus.Rewards{}, }, }, LimitedEffortBox: []any{}, - MuseumInfo: model.Museum{}, + MuseumInfo: lbonus.Museum{}, ServerTimestamp: time.Now().Unix(), PresentCnt: 0, }, @@ -149,5 +151,9 @@ func LBonusExecute(ctx *gin.Context) { StatusCode: 200, } - ss.Respond(LbRes) + ss.Respond(resp) +} + +func init() { + router.AddHandler("main.php", "POST", "/lbonus/execute", middleware.Common, execute) } diff --git a/internal/handler/live/gameover.go b/internal/handler/live/gameover.go new file mode 100644 index 0000000..b19413f --- /dev/null +++ b/internal/handler/live/gameover.go @@ -0,0 +1,25 @@ +package live + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/live" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func gameOver(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(live.GameOverResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/live/gameover", middleware.Common, gameOver) +} diff --git a/internal/handler/live/partylist.go b/internal/handler/live/partylist.go new file mode 100644 index 0000000..1f6660c --- /dev/null +++ b/internal/handler/live/partylist.go @@ -0,0 +1,29 @@ +package live + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/session" + honokautils "honoka-chan/pkg/utils" + + "github.com/gin-gonic/gin" +) + +func partyList(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + data := honokautils.ReadAllText("assets/serverdata/partylist.json") + var partyResp map[string]any + err := json.Unmarshal([]byte(data), &partyResp) + if ss.CheckErr(err) { + return + } + + ss.Respond(partyResp) +} + +func init() { + router.AddHandler("main.php", "POST", "/live/partyList", middleware.Common, partyList) +} diff --git a/internal/handler/live.go b/internal/handler/live/play.go similarity index 54% rename from internal/handler/live.go rename to internal/handler/live/play.go index 747ad8e..f2d1e6c 100644 --- a/internal/handler/live.go +++ b/internal/handler/live/play.go @@ -1,10 +1,11 @@ -package handler +package live import ( "encoding/json" "fmt" - "honoka-chan/config" - "honoka-chan/internal/model" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/live" "honoka-chan/internal/session" "honoka-chan/pkg/db" honokautils "honoka-chan/pkg/utils" @@ -16,26 +17,12 @@ import ( "github.com/tidwall/gjson" ) -func PartyList(ctx *gin.Context) { - ss := session.New(ctx) +func play(ctx *gin.Context) { + ss := session.Get(ctx) defer ss.Finalize() - data := honokautils.ReadAllText("assets/serverdata/partylist.json") - var partyResp map[string]any - err := json.Unmarshal([]byte(data), &partyResp) - if ss.CheckErr(err) { - return - } - - ss.Respond(partyResp) -} - -func PlayLive(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - playReq := model.PlayReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &playReq) + playReq := live.PlayReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &playReq) if ss.CheckErr(err) { return } @@ -48,8 +35,8 @@ func PlayLive(ctx *gin.Context) { deckId := playReq.UnitDeckID // Save Deck Id for /live/reward - key := "live_deck_" + ctx.GetString("userid") - err = db.DB.Set([]byte(key), []byte(strconv.Itoa(deckId))) + key := "live_deck_" + strconv.Itoa(ss.UserID) + err = db.Ldb.Set([]byte(key), []byte(strconv.Itoa(deckId))) if ss.CheckErr(err) { return } @@ -67,32 +54,32 @@ func PlayLive(ctx *gin.Context) { // fmt.Println(notes_setting_asset) // fmt.Println(c_rank_score, b_rank_score, a_rank_score, s_rank_score) - notes := []model.NotesList{} - // fmt.Println("./assets/notes/" + notes_setting_asset) - notes_list := honokautils.ReadAllText("./assets/serverdata/notes/" + notes_setting_asset) + notes := []live.NotesList{} + // fmt.Println("./assets/serverdata/beatmaps/" + notes_setting_asset) + notes_list := honokautils.ReadAllText("./assets/serverdata/beatmaps/" + notes_setting_asset) err = json.Unmarshal([]byte(notes_list), ¬es) if ss.CheckErr(err) { return } - ranks := []model.RankInfo{} - ranks = append(ranks, model.RankInfo{ + ranks := []live.RankInfo{} + ranks = append(ranks, live.RankInfo{ Rank: 5, RankMin: 0, RankMax: c_rank_score, - }, model.RankInfo{ + }, live.RankInfo{ Rank: 4, RankMin: c_rank_score + 1, RankMax: b_rank_score, - }, model.RankInfo{ + }, live.RankInfo{ Rank: 3, RankMin: b_rank_score + 1, RankMax: a_rank_score, - }, model.RankInfo{ + }, live.RankInfo{ Rank: 2, RankMin: a_rank_score + 1, RankMax: s_rank_score, - }, model.RankInfo{ + }, live.RankInfo{ Rank: 1, RankMin: s_rank_score + 1, RankMax: 0, @@ -101,14 +88,14 @@ func PlayLive(ctx *gin.Context) { // ss.UserEng.ShowSQL(true) // ss.MainEng.ShowSQL(true) owningIdList := []int{} - err = ss.UserEng.Table("deck_unit_m").Join("LEFT", "user_deck_m", "deck_unit_m.user_deck_id = user_deck_m.id"). - Where("user_id = ? AND deck_id = ?", ctx.GetString("userid"), deckId).Cols("unit_owning_user_id"). - OrderBy("deck_unit_m.position ASC").Find(&owningIdList) + err = ss.UserEng.Table("user_deck_unit").Join("LEFT", "user_deck", "user_deck_unit.user_deck_id = user_deck.id"). + Where("user_id = ? AND deck_id = ?", ss.UserID, deckId).Cols("unit_owning_user_id"). + OrderBy("user_deck_unit.position ASC").Find(&owningIdList) if ss.CheckErr(err) { return } - unitList := []model.UnitList{} + unitList := []live.UnitList{} var totalSmile, totalPure, totalCool, maxLove float64 var totalHp int for _, owningId := range owningIdList { @@ -131,7 +118,7 @@ func PlayLive(ctx *gin.Context) { } } else { // 用户卡片暂时固定为满级350级 - exists, err := ss.UserEng.Table("user_unit_m").Where("unit_owning_user_id = ?", owningId).Cols("unit_id").Get(&uId) + exists, err := ss.UserEng.Table("user_unit").Where("unit_owning_user_id = ?", owningId).Cols("unit_id").Get(&uId) if ss.CheckErr(err) { return } @@ -168,7 +155,7 @@ func PlayLive(ctx *gin.Context) { // 饰品属性加成(满级) var accessoryOwningId int - _, err = ss.UserEng.Table("accessory_wear_m").Where("unit_owning_user_id = ?", owningId). + _, err = ss.UserEng.Table("user_accessory_wear").Where("unit_owning_user_id = ?", owningId). Cols("accessory_owning_user_id").Get(&accessoryOwningId) if ss.CheckErr(err) { return @@ -221,7 +208,7 @@ func PlayLive(ctx *gin.Context) { // 宝石加成(满级) removableSkillIds := []int{} - err = ss.UserEng.Table("skill_equip_m").Where("unit_owning_user_id = ? AND user_id = ?", owningId, ctx.GetString("userid")). + err = ss.UserEng.Table("user_unit_skill_equip").Where("unit_owning_user_id = ? AND user_id = ?", owningId, ss.UserID). Cols("unit_removable_skill_id").Find(&removableSkillIds) if ss.CheckErr(err) { return @@ -289,9 +276,9 @@ func PlayLive(ctx *gin.Context) { // 主唱技能加成 var myCenterUnitId int - _, err = ss.UserEng.Table("deck_unit_m").Join("LEFT", "user_deck_m", "deck_unit_m.user_deck_id = user_deck_m.id"). - Where("user_deck_m.deck_id = ? AND user_deck_m.user_id = ? AND deck_unit_m.position = 5", playReq.UnitDeckID, ctx.GetString("userid")). - Cols("deck_unit_m.unit_id").Get(&myCenterUnitId) + _, err = ss.UserEng.Table("user_deck_unit").Join("LEFT", "user_deck", "user_deck_unit.user_deck_id = user_deck.id"). + Where("user_deck.deck_id = ? AND user_deck.user_id = ? AND user_deck_unit.position = 5", playReq.UnitDeckID, ss.UserID). + Cols("user_deck_unit.unit_id").Get(&myCenterUnitId) if ss.CheckErr(err) { return } @@ -421,7 +408,7 @@ func PlayLive(ctx *gin.Context) { fixedCoolMax := int(coolMax) // fmt.Println("单卡属性:", fixedSmileMax, fixedPureMax, fixedCoolMax) - unitList = append(unitList, model.UnitList{ + unitList = append(unitList, live.UnitList{ Smile: fixedSmileMax, Cute: fixedPureMax, Cool: fixedCoolMax, @@ -434,16 +421,16 @@ func PlayLive(ctx *gin.Context) { fixedTotalCool := int(math.Ceil(totalCool)) // fmt.Println("全卡组属性:", fixedTotalSmile, fixedTotalPure, fixedTotalCool) - lives := []model.PlayLiveList{} - lives = append(lives, model.PlayLiveList{ - LiveInfo: model.LiveInfo{ + lives := []live.PlayLiveList{} + lives = append(lives, live.PlayLiveList{ + LiveInfo: live.LiveInfo{ LiveDifficultyID: difficultyId, IsRandom: false, AcFlag: ac_flag, SwingFlag: swing_flag, NotesList: notes, }, - DeckInfo: model.DeckInfo{ + DeckInfo: live.DeckInfo{ UnitDeckID: deckId, TotalSmile: fixedTotalSmile, TotalCute: fixedTotalPure, @@ -454,8 +441,8 @@ func PlayLive(ctx *gin.Context) { }, }) - playResp := model.PlayResp{ - ResponseData: model.PlayRes{ + playResp := live.PlayResp{ + ResponseData: live.PlayData{ RankInfo: ranks, EnergyFullTime: "2023-03-20 01:28:55", OverMaxEnergy: 0, @@ -474,296 +461,6 @@ func PlayLive(ctx *gin.Context) { ss.Respond(playResp) } -func GameOver(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - overResp := model.GameOverResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(overResp) -} - -func PlayScore(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - playScoreReq := model.PlayScoreReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &playScoreReq) - if ss.CheckErr(err) { - return - } - - tDifficultyId := playScoreReq.LiveDifficultyID - difficultyId, err := strconv.Atoi(tDifficultyId) - if ss.CheckErr(err) { - return - } - - // Song type: normal / special - // sqlite3 doesn't support FULL OUTER JOIN so use UNION ALL here. - sql := `SELECT notes_setting_asset,c_rank_score,b_rank_score,a_rank_score,s_rank_score,ac_flag,swing_flag FROM live_setting_m WHERE live_setting_id IN (SELECT live_setting_id FROM normal_live_m WHERE live_difficulty_id = ? UNION ALL SELECT live_setting_id FROM special_live_m WHERE live_difficulty_id = ?)` - var notes_setting_asset string - var c_rank_score, b_rank_score, a_rank_score, s_rank_score, ac_flag, swing_flag int - err = ss.MainEng.DB().QueryRow(sql, difficultyId, difficultyId).Scan(¬es_setting_asset, &c_rank_score, &b_rank_score, &a_rank_score, &s_rank_score, &ac_flag, &swing_flag) - if ss.CheckErr(err) { - return - } - - // fmt.Println(notes_setting_asset) - // fmt.Println(c_rank_score, b_rank_score, a_rank_score, s_rank_score) - - notes := []model.NotesList{} - // fmt.Println("./assets/notes/" + notes_setting_asset) - notes_list := honokautils.ReadAllText("./assets/serverdata/notes/" + notes_setting_asset) - err = json.Unmarshal([]byte(notes_list), ¬es) - if ss.CheckErr(err) { - return - } - - ranks := []model.RankInfo{} - ranks = append(ranks, model.RankInfo{ - Rank: 5, - RankMin: 0, - RankMax: c_rank_score, - }, model.RankInfo{ - Rank: 4, - RankMin: c_rank_score + 1, - RankMax: b_rank_score, - }, model.RankInfo{ - Rank: 3, - RankMin: b_rank_score + 1, - RankMax: a_rank_score, - }, model.RankInfo{ - Rank: 2, - RankMin: a_rank_score + 1, - RankMax: s_rank_score, - }, model.RankInfo{ - Rank: 1, - RankMin: s_rank_score + 1, - RankMax: 0, - }) - - playResp := model.PlayScoreResp{ - ResponseData: model.PlayScoreRes{ - On: model.On{ - HasRecord: false, - LiveInfo: model.LiveInfo{ - LiveDifficultyID: difficultyId, - IsRandom: false, - AcFlag: ac_flag, - SwingFlag: swing_flag, - NotesList: notes, - }, - }, - Off: model.Off{ - HasRecord: false, - LiveInfo: model.LiveInfo{ - LiveDifficultyID: difficultyId, - IsRandom: false, - AcFlag: ac_flag, - SwingFlag: swing_flag, - NotesList: notes, - }, - }, - RankInfo: ranks, - CanActivateEffect: true, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(playResp) -} - -func PlayReward(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - playRewardReq := model.PlayRewardReq{} - err := json.Unmarshal([]byte(ctx.GetString("request_data")), &playRewardReq) - if ss.CheckErr(err) { - return - } - - difficultyId := playRewardReq.LiveDifficultyID - - // Song type: normal / special - // sqlite3 doesn't support FULL OUTER JOIN so use UNION ALL here. - sql := `SELECT c_rank_score,b_rank_score,a_rank_score,s_rank_score,c_rank_combo,b_rank_combo,a_rank_combo,s_rank_combo,ac_flag,swing_flag FROM live_setting_m WHERE live_setting_id IN (SELECT live_setting_id FROM normal_live_m WHERE live_difficulty_id = ? UNION ALL SELECT live_setting_id FROM special_live_m WHERE live_difficulty_id = ?)` - var c_rank_score, b_rank_score, a_rank_score, s_rank_score, c_rank_combo, b_rank_combo, a_rank_combo, s_rank_combo, ac_flag, swing_flag int - err = ss.MainEng.DB().QueryRow(sql, difficultyId, difficultyId).Scan(&c_rank_score, &b_rank_score, &a_rank_score, &s_rank_score, &c_rank_combo, &b_rank_combo, &a_rank_combo, &s_rank_combo, &ac_flag, &swing_flag) - if ss.CheckErr(err) { - return - } - - key := "live_deck_" + ctx.GetString("userid") - deckId, err := db.DB.Get([]byte(key)) - if ss.CheckErr(err) { - return - } - unitsList := []model.PlayRewardUnitList{} - err = ss.UserEng.Table("deck_unit_m").Join("LEFT", "user_deck_m", "deck_unit_m.user_deck_id = user_deck_m.id"). - Where("user_id = ? AND deck_id = ?", ctx.GetString("userid"), string(deckId)).Find(&unitsList) - if ss.CheckErr(err) { - return - } - - totalScore := playRewardReq.ScoreSmile + playRewardReq.ScoreCool + playRewardReq.ScoreCute - playResp := model.RewardResp{ - ResponseData: model.RewardRes{ - LiveInfo: []model.RewardLiveInfo{ - { - LiveDifficultyID: difficultyId, - IsRandom: false, - AcFlag: ac_flag, - SwingFlag: swing_flag, - }, - }, - TotalLove: 0, - IsHighScore: true, - HiScore: totalScore, - BaseRewardInfo: model.BaseRewardInfo{ - PlayerExp: 0, - PlayerExpUnitMax: model.PlayerExpUnitMax{ - Before: 0, - After: 0, - }, - PlayerExpFriendMax: model.PlayerExpFriendMax{ - Before: 99, - After: 99, - }, - PlayerExpLpMax: model.PlayerExpLpMax{ - Before: config.Conf.UserPrefs.EnergyMax, - After: config.Conf.UserPrefs.EnergyMax, - }, - GameCoin: 0, - GameCoinRewardBoxFlag: false, - SocialPoint: 0, - }, - RewardUnitList: model.RewardUnitList{ - LiveClear: []model.LiveClear{}, - LiveRank: []model.LiveRank{}, - LiveCombo: []any{}, - }, - UnlockedSubscenarioIds: []any{}, - UnlockedMultiUnitScenarioIds: []any{}, - EffortPoint: []model.EffortPoint{}, - IsEffortPointVisible: false, - LimitedEffortBox: []any{}, - UnitList: unitsList, - BeforeUserInfo: model.BeforeUserInfo{ - Level: config.Conf.UserPrefs.Level, - Exp: config.Conf.UserPrefs.ExpNumerator, - PreviousExp: 0, - NextExp: config.Conf.UserPrefs.ExpDenominator, - GameCoin: config.Conf.UserPrefs.GameCoin, - SnsCoin: config.Conf.UserPrefs.SnsCoin, - FreeSnsCoin: config.Conf.UserPrefs.SnsCoin, - PaidSnsCoin: 0, - SocialPoint: 1438165, - UnitMax: 5000, - WaitingUnitMax: 1000, - CurrentEnergy: config.Conf.UserPrefs.EnergyMax, - EnergyMax: config.Conf.UserPrefs.EnergyMax, - TrainingEnergy: 9, - TrainingEnergyMax: 10, - EnergyFullTime: "2023-03-20 01:28:55", - LicenseLiveEnergyRecoverlyTime: 60, - FriendMax: 99, - TutorialState: -1, - OverMaxEnergy: config.Conf.UserPrefs.OverMaxEnergy, - UnlockRandomLiveMuse: 1, - UnlockRandomLiveAqours: 1, - }, - AfterUserInfo: model.AfterUserInfo{ - Level: config.Conf.UserPrefs.Level, - Exp: config.Conf.UserPrefs.ExpNumerator, - PreviousExp: 0, - NextExp: config.Conf.UserPrefs.ExpDenominator, - GameCoin: config.Conf.UserPrefs.GameCoin, - SnsCoin: config.Conf.UserPrefs.SnsCoin, - FreeSnsCoin: config.Conf.UserPrefs.SnsCoin, - PaidSnsCoin: 0, - SocialPoint: 1438375, - UnitMax: 5000, - WaitingUnitMax: 1000, - CurrentEnergy: config.Conf.UserPrefs.EnergyMax, - EnergyMax: config.Conf.UserPrefs.EnergyMax, - TrainingEnergy: 9, - TrainingEnergyMax: 10, - EnergyFullTime: "2023-03-20 01:28:55", - LicenseLiveEnergyRecoverlyTime: 60, - FriendMax: 99, - TutorialState: -1, - OverMaxEnergy: config.Conf.UserPrefs.OverMaxEnergy, - UnlockRandomLiveMuse: 1, - UnlockRandomLiveAqours: 1, - }, - NextLevelInfo: []model.NextLevelInfo{ - { - Level: config.Conf.UserPrefs.Level, - FromExp: config.Conf.UserPrefs.ExpNumerator, - }, - }, - GoalAccompInfo: model.GoalAccompInfo{ - AchievedIds: []any{}, - Rewards: []any{}, - }, - SpecialRewardInfo: []any{}, - EventInfo: []any{}, - DailyRewardInfo: []any{}, - CanSendFriendRequest: false, - UsingBuffInfo: []any{}, - ClassSystem: model.ClassSystem{ - RankInfo: model.RewardRankInfo{ - BeforeClassRankID: 10, - AfterClassRankID: 10, - RankUpDate: "2020-02-12 11:57:15", - }, - CompleteFlag: false, - IsOpened: true, - IsVisible: true, - }, - AccomplishedAchievementList: []model.AccomplishedAchievementList{}, - UnaccomplishedAchievementCnt: 0, - AddedAchievementList: []any{}, - MuseumInfo: model.Museum{}, - UnitSupportList: []model.RewardUnitSupportList{}, - ServerTimestamp: time.Now().Unix(), - PresentCnt: 0, - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - if playRewardReq.MaxCombo > s_rank_combo { - playResp.ResponseData.ComboRank = 1 - } else if playRewardReq.MaxCombo > a_rank_combo { - playResp.ResponseData.ComboRank = 2 - } else if playRewardReq.MaxCombo > b_rank_combo { - playResp.ResponseData.ComboRank = 3 - } else if playRewardReq.MaxCombo > c_rank_combo { - playResp.ResponseData.ComboRank = 4 - } else { - playResp.ResponseData.ComboRank = 5 - } - - if totalScore > s_rank_score { - playResp.ResponseData.Rank = 1 - } else if totalScore > a_rank_score { - playResp.ResponseData.Rank = 2 - } else if totalScore > b_rank_score { - playResp.ResponseData.Rank = 3 - } else if totalScore > c_rank_score { - playResp.ResponseData.Rank = 4 - } else { - playResp.ResponseData.Rank = 5 - } - - ss.Respond(playResp) +func init() { + router.AddHandler("main.php", "POST", "/live/play", middleware.Common, play) } diff --git a/internal/handler/live/precisescore.go b/internal/handler/live/precisescore.go new file mode 100644 index 0000000..9ec6362 --- /dev/null +++ b/internal/handler/live/precisescore.go @@ -0,0 +1,111 @@ +package live + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/live" + "honoka-chan/internal/session" + honokautils "honoka-chan/pkg/utils" + "strconv" + "time" + + "github.com/gin-gonic/gin" +) + +func preciseScore(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + playScoreReq := live.PlayScoreReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &playScoreReq) + if ss.CheckErr(err) { + return + } + + tDifficultyId := playScoreReq.LiveDifficultyID + difficultyId, err := strconv.Atoi(tDifficultyId) + if ss.CheckErr(err) { + return + } + + // Song type: normal / special + // sqlite3 doesn't support FULL OUTER JOIN so use UNION ALL here. + sql := `SELECT notes_setting_asset,c_rank_score,b_rank_score,a_rank_score,s_rank_score,ac_flag,swing_flag FROM live_setting_m WHERE live_setting_id IN (SELECT live_setting_id FROM normal_live_m WHERE live_difficulty_id = ? UNION ALL SELECT live_setting_id FROM special_live_m WHERE live_difficulty_id = ?)` + var notes_setting_asset string + var c_rank_score, b_rank_score, a_rank_score, s_rank_score, ac_flag, swing_flag int + err = ss.MainEng.DB().QueryRow(sql, difficultyId, difficultyId).Scan(¬es_setting_asset, &c_rank_score, &b_rank_score, &a_rank_score, &s_rank_score, &ac_flag, &swing_flag) + if ss.CheckErr(err) { + return + } + + // fmt.Println(notes_setting_asset) + // fmt.Println(c_rank_score, b_rank_score, a_rank_score, s_rank_score) + + notes := []live.NotesList{} + // fmt.Println("./assets/serverdata/beatmaps/" + notes_setting_asset) + notes_list := honokautils.ReadAllText("./assets/serverdata/beatmaps/" + notes_setting_asset) + err = json.Unmarshal([]byte(notes_list), ¬es) + if ss.CheckErr(err) { + return + } + + ranks := []live.RankInfo{} + ranks = append(ranks, live.RankInfo{ + Rank: 5, + RankMin: 0, + RankMax: c_rank_score, + }, live.RankInfo{ + Rank: 4, + RankMin: c_rank_score + 1, + RankMax: b_rank_score, + }, live.RankInfo{ + Rank: 3, + RankMin: b_rank_score + 1, + RankMax: a_rank_score, + }, live.RankInfo{ + Rank: 2, + RankMin: a_rank_score + 1, + RankMax: s_rank_score, + }, live.RankInfo{ + Rank: 1, + RankMin: s_rank_score + 1, + RankMax: 0, + }) + + playResp := live.PreciseScoreResp{ + ResponseData: live.PreciseScoreData{ + On: live.On{ + HasRecord: false, + LiveInfo: live.LiveInfo{ + LiveDifficultyID: difficultyId, + IsRandom: false, + AcFlag: ac_flag, + SwingFlag: swing_flag, + NotesList: notes, + }, + }, + Off: live.Off{ + HasRecord: false, + LiveInfo: live.LiveInfo{ + LiveDifficultyID: difficultyId, + IsRandom: false, + AcFlag: ac_flag, + SwingFlag: swing_flag, + NotesList: notes, + }, + }, + RankInfo: ranks, + CanActivateEffect: true, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + } + + ss.Respond(playResp) +} + +func init() { + router.AddHandler("main.php", "POST", "/live/preciseScore", middleware.Common, preciseScore) +} diff --git a/internal/handler/live/reward.go b/internal/handler/live/reward.go new file mode 100644 index 0000000..5d4f9bc --- /dev/null +++ b/internal/handler/live/reward.go @@ -0,0 +1,213 @@ +package live + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/live" + "honoka-chan/internal/session" + "honoka-chan/pkg/db" + "strconv" + "time" + + "github.com/gin-gonic/gin" +) + +func reward(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + playRewardReq := live.RewardReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &playRewardReq) + if ss.CheckErr(err) { + return + } + + difficultyId := playRewardReq.LiveDifficultyID + + // Song type: normal / special + // sqlite3 doesn't support FULL OUTER JOIN so use UNION ALL here. + sql := `SELECT c_rank_score,b_rank_score,a_rank_score,s_rank_score,c_rank_combo,b_rank_combo,a_rank_combo,s_rank_combo,ac_flag,swing_flag FROM live_setting_m WHERE live_setting_id IN (SELECT live_setting_id FROM normal_live_m WHERE live_difficulty_id = ? UNION ALL SELECT live_setting_id FROM special_live_m WHERE live_difficulty_id = ?)` + var c_rank_score, b_rank_score, a_rank_score, s_rank_score, c_rank_combo, b_rank_combo, a_rank_combo, s_rank_combo, ac_flag, swing_flag int + err = ss.MainEng.DB().QueryRow(sql, difficultyId, difficultyId).Scan(&c_rank_score, &b_rank_score, &a_rank_score, &s_rank_score, &c_rank_combo, &b_rank_combo, &a_rank_combo, &s_rank_combo, &ac_flag, &swing_flag) + if ss.CheckErr(err) { + return + } + + key := "live_deck_" + strconv.Itoa(ss.UserID) + deckId, err := db.Ldb.Get([]byte(key)) + if ss.CheckErr(err) { + return + } + unitsList := []live.PlayRewardUnitList{} + err = ss.UserEng.Table("user_deck_unit").Join("LEFT", "user_deck", "user_deck_unit.user_deck_id = user_deck.id"). + Where("user_id = ? AND deck_id = ?", ss.UserID, string(deckId)).Find(&unitsList) + if ss.CheckErr(err) { + return + } + + pref := user.UserPref{} + _, err = ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Get(&pref) + if ss.CheckErr(err) { + return + } + + totalScore := playRewardReq.ScoreSmile + playRewardReq.ScoreCool + playRewardReq.ScoreCute + playResp := live.RewardResp{ + ResponseData: live.RewardData{ + LiveInfo: []live.RewardLiveInfo{ + { + LiveDifficultyID: difficultyId, + IsRandom: false, + AcFlag: ac_flag, + SwingFlag: swing_flag, + }, + }, + TotalLove: 0, + IsHighScore: true, + HiScore: totalScore, + BaseRewardInfo: live.BaseRewardInfo{ + PlayerExp: 0, + PlayerExpUnitMax: live.PlayerExpUnitMax{ + Before: 0, + After: 0, + }, + PlayerExpFriendMax: live.PlayerExpFriendMax{ + Before: 99, + After: 99, + }, + PlayerExpLpMax: live.PlayerExpLpMax{ + Before: 417, + After: 417, + }, + GameCoin: 0, + GameCoinRewardBoxFlag: false, + SocialPoint: 0, + }, + RewardUnitList: live.RewardUnitList{ + LiveClear: []live.LiveClear{}, + LiveRank: []live.LiveRank{}, + LiveCombo: []any{}, + }, + UnlockedSubscenarioIds: []any{}, + UnlockedMultiUnitScenarioIds: []any{}, + EffortPoint: []live.EffortPoint{}, + IsEffortPointVisible: false, + LimitedEffortBox: []any{}, + UnitList: unitsList, + BeforeUserInfo: live.BeforeUserInfo{ + Level: pref.UserLevel, + Exp: 1089696, + PreviousExp: 0, + NextExp: 1207185, + GameCoin: 999999999, + SnsCoin: 10000, + FreeSnsCoin: 50000, + PaidSnsCoin: 50000, + SocialPoint: 1438165, + UnitMax: 5000, + WaitingUnitMax: 1000, + CurrentEnergy: 417, + EnergyMax: 417, + TrainingEnergy: 9, + TrainingEnergyMax: 10, + EnergyFullTime: "2023-03-20 01:28:55", + LicenseLiveEnergyRecoverlyTime: 60, + FriendMax: 99, + TutorialState: -1, + OverMaxEnergy: 417, + UnlockRandomLiveMuse: 1, + UnlockRandomLiveAqours: 1, + }, + AfterUserInfo: live.AfterUserInfo{ + Level: pref.UserLevel, + Exp: 1089696, + PreviousExp: 0, + NextExp: 1207185, + GameCoin: 999999999, + SnsCoin: 100000, + FreeSnsCoin: 50000, + PaidSnsCoin: 50000, + SocialPoint: 1438375, + UnitMax: 5000, + WaitingUnitMax: 1000, + CurrentEnergy: 417, + EnergyMax: 417, + TrainingEnergy: 9, + TrainingEnergyMax: 10, + EnergyFullTime: "2023-03-20 01:28:55", + LicenseLiveEnergyRecoverlyTime: 60, + FriendMax: 99, + TutorialState: -1, + OverMaxEnergy: 417, + UnlockRandomLiveMuse: 1, + UnlockRandomLiveAqours: 1, + }, + NextLevelInfo: []live.NextLevelInfo{ + { + Level: pref.UserLevel, + FromExp: 1089696, + }, + }, + GoalAccompInfo: live.GoalAccompInfo{ + AchievedIds: []any{}, + Rewards: []any{}, + }, + SpecialRewardInfo: []any{}, + EventInfo: []any{}, + DailyRewardInfo: []any{}, + CanSendFriendRequest: false, + UsingBuffInfo: []any{}, + ClassSystem: live.ClassSystem{ + RankInfo: live.RewardRankInfo{ + BeforeClassRankID: 10, + AfterClassRankID: 10, + RankUpDate: "2020-02-12 11:57:15", + }, + CompleteFlag: false, + IsOpened: true, + IsVisible: true, + }, + AccomplishedAchievementList: []live.AccomplishedAchievementList{}, + UnaccomplishedAchievementCnt: 0, + AddedAchievementList: []any{}, + MuseumInfo: live.Museum{}, + UnitSupportList: []live.RewardUnitSupportList{}, + ServerTimestamp: time.Now().Unix(), + PresentCnt: 0, + }, + ReleaseInfo: []any{}, + StatusCode: 200, + } + + if playRewardReq.MaxCombo > s_rank_combo { + playResp.ResponseData.ComboRank = 1 + } else if playRewardReq.MaxCombo > a_rank_combo { + playResp.ResponseData.ComboRank = 2 + } else if playRewardReq.MaxCombo > b_rank_combo { + playResp.ResponseData.ComboRank = 3 + } else if playRewardReq.MaxCombo > c_rank_combo { + playResp.ResponseData.ComboRank = 4 + } else { + playResp.ResponseData.ComboRank = 5 + } + + if totalScore > s_rank_score { + playResp.ResponseData.Rank = 1 + } else if totalScore > a_rank_score { + playResp.ResponseData.Rank = 2 + } else if totalScore > b_rank_score { + playResp.ResponseData.Rank = 3 + } else if totalScore > c_rank_score { + playResp.ResponseData.Rank = 4 + } else { + playResp.ResponseData.Rank = 5 + } + + ss.Respond(playResp) +} + +func init() { + router.AddHandler("main.php", "POST", "/live/reward", middleware.Common, reward) +} diff --git a/internal/handler/login.go b/internal/handler/login.go deleted file mode 100644 index 5910bb9..0000000 --- a/internal/handler/login.go +++ /dev/null @@ -1,62 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "honoka-chan/pkg/db" - "strconv" - "time" - - "github.com/gin-gonic/gin" -) - -func AuthKey(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - authResp := model.AuthKeyResp{ - ResponseData: model.AuthKeyRes{ - AuthorizeToken: ctx.GetString("authorize_token"), - DummyToken: ctx.GetString("dummy_token"), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(authResp) -} - -func Login(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - loginKey := ctx.GetString("login_key") - var userId int - exists, err := ss.UserEng.Table("user_key").Where("key = ?", loginKey).Cols("userid").Get(&userId) - if ss.CheckErr(err) { - return - } - - if !exists || userId == 0 { - userId = 9999999 - } - ctx.Set("userid", userId) - - err = db.DB.Set([]byte(strconv.Itoa(userId)), []byte(ctx.GetString("authorize_token"))) - if ss.CheckErr(err) { - return - } - - loginResp := model.LoginResp{ - ResponseData: model.LoginRes{ - AuthorizeToken: ctx.GetString("authorize_token"), - UserId: userId, - ServerTimestamp: time.Now().Unix(), - AdultFlag: 2, - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(loginResp) -} diff --git a/internal/handler/login/authkey.go b/internal/handler/login/authkey.go new file mode 100644 index 0000000..dc2f310 --- /dev/null +++ b/internal/handler/login/authkey.go @@ -0,0 +1,66 @@ +package login + +import ( + "encoding/base64" + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + loginschema "honoka-chan/internal/schema/login" + "honoka-chan/internal/session" + "honoka-chan/pkg/db" + "honoka-chan/pkg/encrypt" + honokautils "honoka-chan/pkg/utils" + + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" +) + +func authKey(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + reqData := gjson.Parse(ctx.MustGet("request_data").(string)) + dummyToken, err := base64.StdEncoding.DecodeString(reqData.Get("dummy_token").String()) + if ss.CheckErr(err) { + return + } + dummyTokenDecrypted := encrypt.RSADecrypt(dummyToken) + + // aesKey := dummyTokenDecrypted[0:16] + // authData, err := base64.StdEncoding.DecodeString(reqData.Get("auth_data").String()) + // if ss.CheckErr(err) { + // return + // } + // authDataDecrypted := encrypt.AESCBCDecrypt(authData, aesKey)[16:] + // fmt.Println(string(authDataDecrypted)) + + clientToken := base64.StdEncoding.EncodeToString(dummyTokenDecrypted) + serverToken := base64.StdEncoding.EncodeToString([]byte(honokautils.RandomStr(32))) + authorizeToken := base64.StdEncoding.EncodeToString([]byte(honokautils.RandomStr(32))) + + authJson, err := json.Marshal(map[string]any{ + "client_token": clientToken, + "server_token": serverToken, + }) + if ss.CheckErr(err) { + return + } + + err = db.Ldb.Set([]byte(authorizeToken), authJson) + if ss.CheckErr(err) { + return + } + + ss.Respond(loginschema.AuthKeyResp{ + ResponseData: loginschema.AuthKeyData{ + AuthorizeToken: authorizeToken, + DummyToken: serverToken, + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/login/authkey", middleware.Common, authKey) +} diff --git a/internal/handler/login/login.go b/internal/handler/login/login.go new file mode 100644 index 0000000..cce9ef4 --- /dev/null +++ b/internal/handler/login/login.go @@ -0,0 +1,88 @@ +package login + +import ( + "encoding/base64" + "errors" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + loginschema "honoka-chan/internal/schema/login" + "honoka-chan/internal/session" + "honoka-chan/pkg/db" + "honoka-chan/pkg/encrypt" + honokautils "honoka-chan/pkg/utils" + "strconv" + "time" + + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" +) + +func login(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + authData, err := db.Ldb.Get([]byte(ctx.MustGet("token").(string))) + if ss.CheckErr(err) { + return + } + + clientToken, err := base64.StdEncoding.DecodeString(gjson.Get(string(authData), "client_token").String()) + if ss.CheckErr(err) { + return + } + serverToken, err := base64.StdEncoding.DecodeString(gjson.Get(string(authData), "server_token").String()) + if ss.CheckErr(err) { + return + } + + xmcKey := honokautils.XOR(clientToken, serverToken) + aesKey := xmcKey[0:16] + + reqData := gjson.Parse(ctx.MustGet("request_data").(string)) + key, err := base64.StdEncoding.DecodeString(reqData.Get("login_key").String()) + if ss.CheckErr(err) { + return + } + loginKey := encrypt.AESCBCDecrypt(key, aesKey)[16:] + // fmt.Println("loginKey", string(loginKey)) + + // password, err := base64.StdEncoding.DecodeString(reqData.Get("login_passwd").String()) + // if ss.CheckErr(err) { + // return + // } + // loginPasswd := encrypt.AESCBCDecrypt(password, aesKey)[16:] + // fmt.Println("loginPasswd", string(loginPasswd)) + + authorizeToken := base64.StdEncoding.EncodeToString([]byte(honokautils.RandomStr(32))) + + var userID int // 需要更新为字符串 + exists, err := ss.UserEng.Table("user_key").Where("key = ?", string(loginKey)).Cols("user_id").Get(&userID) + if ss.CheckErr(err) { + return + } + + if !exists || userID == 0 { + ss.Abort(errors.New("invalid user")) + return + } + + err = db.Ldb.Set([]byte(strconv.Itoa(userID)), []byte(authorizeToken)) + if ss.CheckErr(err) { + return + } + + ss.Respond(loginschema.LoginResp{ + ResponseData: loginschema.LoginData{ + AuthorizeToken: authorizeToken, + UserId: userID, + ServerTimestamp: time.Now().Unix(), + AdultFlag: 2, + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/login/login", middleware.Common, login) +} diff --git a/internal/handler/multiunit.go b/internal/handler/multiunit.go deleted file mode 100644 index 14c46d2..0000000 --- a/internal/handler/multiunit.go +++ /dev/null @@ -1,33 +0,0 @@ -package handler - -import ( - "encoding/json" - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "time" - - "github.com/gin-gonic/gin" -) - -func MultiUnitStartUp(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - startReq := model.MultiUnitStartUpReq{} - err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq) - if ss.CheckErr(err) { - return - } - - startResp := model.MultiUnitStartUpResp{ - ResponseData: model.MultiUnitStartUpRes{ - MultiUnitScenarioID: startReq.MultiUnitScenarioID, - ScenarioAdjustment: 50, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(startResp) -} diff --git a/internal/handler/multiunit/scenariostartup.go b/internal/handler/multiunit/scenariostartup.go new file mode 100644 index 0000000..b9d2817 --- /dev/null +++ b/internal/handler/multiunit/scenariostartup.go @@ -0,0 +1,37 @@ +package multiunit + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/multiunit" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func scenarioStartup(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + startReq := multiunit.ScenarioStartUpReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &startReq) + if ss.CheckErr(err) { + return + } + + ss.Respond(multiunit.ScenarioStartUpResp{ + ResponseData: multiunit.ScenarioStartUpData{ + MultiUnitScenarioID: startReq.MultiUnitScenarioID, + ScenarioAdjustment: 50, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/multiunit/scenarioStartup", middleware.Common, scenarioStartup) +} diff --git a/internal/handler/museum.go b/internal/handler/museum/info.go similarity index 55% rename from internal/handler/museum.go rename to internal/handler/museum/info.go index 4c8d1fd..ff09cf8 100644 --- a/internal/handler/museum.go +++ b/internal/handler/museum/info.go @@ -1,25 +1,25 @@ -package handler +package museum import ( - "honoka-chan/internal/model" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/museum" "honoka-chan/internal/session" "time" "github.com/gin-gonic/gin" ) -type MuseumContent struct { - MuseumContentsId int `xorm:"museum_contents_id"` - SmileBuff int `xorm:"smile_buff"` - PureBuff int `xorm:"pure_buff"` - CoolBuff int `xorm:"cool_buff"` -} - -func MuseumInfo(ctx *gin.Context) { - ss := session.New(ctx) +func info(ctx *gin.Context) { + ss := session.Get(ctx) defer ss.Finalize() - var contents []MuseumContent + var contents []struct { + MuseumContentsId int `xorm:"museum_contents_id"` + SmileBuff int `xorm:"smile_buff"` + PureBuff int `xorm:"pure_buff"` + CoolBuff int `xorm:"cool_buff"` + } err := ss.MainEng.Table("museum_contents_m").Cols("museum_contents_id,smile_buff,pure_buff,cool_buff").Find(&contents) if ss.CheckErr(err) { return @@ -33,10 +33,10 @@ func MuseumInfo(ctx *gin.Context) { coolBuff += content.CoolBuff contentsList = append(contentsList, content.MuseumContentsId) } - museumResp := model.MuseumResp{ - ResponseData: model.MuseumRes{ - MuseumInfo: model.Museum{ - Parameter: model.MuseumParameter{ + museumResp := museum.InfoResp{ + ResponseData: museum.InfoData{ + MuseumInfo: museum.Museum{ + Parameter: museum.Parameter{ Smile: smileBuff, Pure: pureBuff, Cool: coolBuff, @@ -51,3 +51,7 @@ func MuseumInfo(ctx *gin.Context) { ss.Respond(museumResp) } + +func init() { + router.AddHandler("main.php", "POST", "/museum/info", middleware.Common, info) +} diff --git a/internal/handler/notice.go b/internal/handler/notice.go deleted file mode 100644 index 591bd38..0000000 --- a/internal/handler/notice.go +++ /dev/null @@ -1,61 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "time" - - "github.com/gin-gonic/gin" -) - -func NoticeFriendVariety(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - noticeResp := model.NoticeFriendVarietyResp{ - ResponseData: model.NoticeFriendVarietyRes{ - ItemCount: 1, - NoticeList: []any{}, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(noticeResp) -} - -func NoticeFriendGreeting(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - noticeResp := model.NoticeFriendGreetingResp{ - ResponseData: model.NoticeFriendGreetingRes{ - NextId: 0, - NoticeList: []any{}, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(noticeResp) -} - -func NoticeUserGreeting(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - noticeResp := model.NoticeUserGreetingResp{ - ResponseData: model.NoticeUserGreetingRes{ - ItemCount: 0, - HasNext: false, - NoticeList: []any{}, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(noticeResp) -} diff --git a/internal/handler/notice/friendgreeting.go b/internal/handler/notice/friendgreeting.go new file mode 100644 index 0000000..edac7b8 --- /dev/null +++ b/internal/handler/notice/friendgreeting.go @@ -0,0 +1,30 @@ +package notice + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/notice" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func friendGreeting(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(notice.FriendGreetingResp{ + ResponseData: notice.FriendGreetingData{ + NextId: 0, + NoticeList: []any{}, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/notice/noticeFriendGreeting", middleware.Common, friendGreeting) +} diff --git a/internal/handler/notice/friendvariety.go b/internal/handler/notice/friendvariety.go new file mode 100644 index 0000000..16bb8b3 --- /dev/null +++ b/internal/handler/notice/friendvariety.go @@ -0,0 +1,30 @@ +package notice + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/notice" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func friendVariety(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(notice.FriendVarietyResp{ + ResponseData: notice.FriendVarietyData{ + ItemCount: 1, + NoticeList: []any{}, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/notice/noticeFriendVariety", middleware.Common, friendVariety) +} diff --git a/internal/handler/notice/usergreetinghistory.go b/internal/handler/notice/usergreetinghistory.go new file mode 100644 index 0000000..2bd9ec8 --- /dev/null +++ b/internal/handler/notice/usergreetinghistory.go @@ -0,0 +1,31 @@ +package notice + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/notice" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func userGreetingHistory(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(notice.UserGreetingResp{ + ResponseData: notice.UserGreetingData{ + ItemCount: 0, + HasNext: false, + NoticeList: []any{}, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/notice/noticeUserGreetingHistory", middleware.Common, userGreetingHistory) +} diff --git a/internal/handler/payment.go b/internal/handler/payment.go deleted file mode 100644 index c9de73b..0000000 --- a/internal/handler/payment.go +++ /dev/null @@ -1,37 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "time" - - "github.com/gin-gonic/gin" -) - -func ProductList(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - prodReesp := model.ProductResp{ - ResponseData: model.ProductRes{ - RestrictionInfo: model.RestrictionInfo{ - Restricted: false, - }, - UnderAgeInfo: model.UnderAgeInfo{ - BirthSet: true, - HasLimit: false, - LimitAmount: nil, - MonthUsed: 0, - }, - SnsProductList: []any{}, - ProductList: []any{}, - SubscriptionList: []any{}, - ShowPointShop: true, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(prodReesp) -} diff --git a/internal/handler/payment/productlist.go b/internal/handler/payment/productlist.go new file mode 100644 index 0000000..740fe69 --- /dev/null +++ b/internal/handler/payment/productlist.go @@ -0,0 +1,44 @@ +package payment + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + paymentapischema "honoka-chan/internal/schema/api/payment" + "honoka-chan/internal/schema/payment" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func productList(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + prodResp := payment.ProductListResp{ + ResponseData: payment.ProductListData{ + RestrictionInfo: paymentapischema.RestrictionInfo{ + Restricted: false, + }, + UnderAgeInfo: paymentapischema.UnderAgeInfo{ + BirthSet: true, + HasLimit: false, + LimitAmount: nil, + MonthUsed: 0, + }, + SnsProductList: []any{}, + ProductList: []any{}, + SubscriptionList: []any{}, + ShowPointShop: true, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + } + + ss.Respond(prodResp) +} + +func init() { + router.AddHandler("main.php", "POST", "/payment/productList", middleware.Common, productList) +} diff --git a/internal/handler/personalnotice.go b/internal/handler/personalnotice.go deleted file mode 100644 index 11263ad..0000000 --- a/internal/handler/personalnotice.go +++ /dev/null @@ -1,29 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "time" - - "github.com/gin-gonic/gin" -) - -func PersonalNotice(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - noticeResp := model.PersonalNoticeResp{ - ResponseData: model.PersonalNoticeRes{ - HasNotice: false, - NoticeID: 0, - Type: 0, - Title: "", - Contents: "", - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(noticeResp) -} diff --git a/internal/handler/personalnotice/get.go b/internal/handler/personalnotice/get.go new file mode 100644 index 0000000..f1c1410 --- /dev/null +++ b/internal/handler/personalnotice/get.go @@ -0,0 +1,35 @@ +package personalnotice + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/personalnotice" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func get(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + noticeResp := personalnotice.GetResp{ + ResponseData: personalnotice.GetData{ + HasNotice: false, + NoticeID: 0, + Type: 0, + Title: "", + Contents: "", + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + } + + ss.Respond(noticeResp) +} + +func init() { + router.AddHandler("main.php", "POST", "/personalnotice/get", middleware.Common, get) +} diff --git a/internal/handler/private.go b/internal/handler/private.go deleted file mode 100644 index c246000..0000000 --- a/internal/handler/private.go +++ /dev/null @@ -1,495 +0,0 @@ -package handler - -import ( - "encoding/base64" - "encoding/json" - "fmt" - "honoka-chan/config" - "honoka-chan/internal/tools" - "honoka-chan/internal/utils" - "honoka-chan/pkg/db" - "honoka-chan/pkg/encrypt" - honokautils "honoka-chan/pkg/utils" - "io" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/gin-gonic/gin" - "github.com/go-think/openssl" -) - -type LoginResp struct { - Activation int `json:"activation"` - Autokey string `json:"autokey"` - CaptchaParams string `json:"captchaParams"` - CheckCodeGUID string `json:"checkCodeGuid"` - CheckCodeURL string `json:"checkCodeUrl"` - HasExtendAccs int `json:"hasExtendAccs"` - HasRealInfo int `json:"has_realInfo"` - ImagecodeType int `json:"imagecodeType"` - IsNewUser int `json:"isNewUser"` - Message string `json:"message"` - NextAction int `json:"nextAction"` - PromptMsg string `json:"prompt_msg"` - RealInfoNotification string `json:"realInfoNotification"` - RealInfoForce int `json:"realInfo_force"` - RealInfoForcePay int `json:"realInfo_force_pay"` - RealInfoStatus int `json:"realInfo_status"` - RealInfoStatusPay int `json:"realInfo_status_pay"` - Result int `json:"result"` - SdgHeight int `json:"sdg_height"` - SdgWidth int `json:"sdg_width"` - Ticket string `json:"ticket"` - UserAttribute string `json:"userAttribute"` - Userid string `json:"userid"` -} - -type LoginAutoResp struct { - Result int `json:"result"` - Message string `json:"message"` - Autokey string `json:"autokey"` - UserId string `json:"userid"` - Ticket string `json:"ticket"` -} - -type InitializeResp struct { - BrandLogo string `json:"brand_logo"` - BrandName string `json:"brand_name"` - DaoyuClientid string `json:"daoyu_clientid"` - DaoyuDownloadURL string `json:"daoyu_download_url"` - DeviceFeature string `json:"device_feature"` - DisplayThirdaccout int `json:"display_thirdaccout"` - ForceShowAgreement int `json:"force_show_agreement"` - GreportLogLevel string `json:"greport_log_level"` - GuestEnable int `json:"guest_enable"` - IsMatch int `json:"is_match"` - LogLevel string `json:"log_level"` - LoginButton []string `json:"login_button"` - LoginIcon []any `json:"login_icon"` - LoginLimitEnable int `json:"login_limit_enable"` - NeedFloatWindowPermission int `json:"need_float_window_permission"` - NewDeviceIDServer string `json:"new_device_id_server"` - QqAppID string `json:"qq_appId"` - QqKey string `json:"qq_key"` - ShowGuestConfirm int `json:"show_guest_confirm"` - VoicetipButton int `json:"voicetip_button"` - VoicetipOne string `json:"voicetip_one"` - VoicetipTwo string `json:"voicetip_two"` - WegameAppid string `json:"wegame_appid"` - WegameAppkey string `json:"wegame_appkey"` - WegameClientid string `json:"wegame_clientid"` - WegameCompanyID string `json:"wegame_companyId"` - WegameLoginURL string `json:"wegame_loginUrl"` - WeiboAppKey string `json:"weibo_appKey"` - WeiboRedirectURL string `json:"weibo_redirectUrl"` - WeixinAppID string `json:"weixin_appId"` - WeixinKey string `json:"weixin_key"` -} - -func Active(ctx *gin.Context) { - // body, err := io.ReadAll(ctx.Request.Body) - // utils.CheckErr(err) - // defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, `{ "code": 0, "msg": "ok", "data": { "message": "ok", "result": 0 } }`) -} - -func PublicKey(ctx *gin.Context) { - publicKey := honokautils.ReadAllText(config.PublicKeyPath) - publicKey = strings.ReplaceAll(publicKey, "\n", "") - publicKey = strings.ReplaceAll(publicKey, "-----BEGIN PUBLIC KEY-----", "") - publicKey = strings.ReplaceAll(publicKey, "-----END PUBLIC KEY-----", "") - publicKey = strings.ReplaceAll(publicKey, "/", "\\/") - // fmt.Println(publicKey) - resp := fmt.Sprintf(`{ "code": 0, "msg": "", "data": { "result": 0, "message": "ok", "key": "%s", "method": "rsa" } }`, publicKey) - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func Handshake(ctx *gin.Context) { - body, err := io.ReadAll(ctx.Request.Body) - utils.CheckErr(err) - defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - - body64, err := base64.StdEncoding.DecodeString(string(body)) - utils.CheckErr(err) - decryptedBody := encrypt.RSADecrypt(body64) - // fmt.Println(decryptedBody) - // fmt.Println(string(decryptedBody)) - - params, err := url.ParseQuery(string(decryptedBody)) - utils.CheckErr(err) - randKey := params.Get("randkey") - deviceId := ctx.Request.Header.Get("X-DEVICEID") - // fmt.Println(randKey) - // fmt.Println(deviceId) - - err = db.DB.Set([]byte(deviceId), []byte(randKey)) - utils.CheckErr(err) - - token := strings.ToUpper(honokautils.RandomStr(33)) - token = fmt.Sprintf(`{"message":"ok","result":0,"token":"%s"}`, token) - encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), []byte(randKey)[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - encryptedToken64 := base64.StdEncoding.EncodeToString(encryptedToken) - // fmt.Println(encryptedToken64) - - resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedToken64) - - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func Initialize(ctx *gin.Context) { - // body, err := io.ReadAll(ctx.Request.Body) - // utils.CheckErr(err) - // defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - - // body64, err := base64.StdEncoding.DecodeString(string(body)) - // utils.CheckErr(err) - // fmt.Println(string(body64)) - - deviceId := ctx.Request.Header.Get("X-DEVICEID") - randKey, err := db.DB.Get([]byte(deviceId)) - utils.CheckErr(err) - // decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING) - // utils.CheckErr(err) - // fmt.Println(string(decryptedBody)) - - initResp := InitializeResp{ - BrandLogo: "http://gskd.sdo.com/ghome/ztc/logo/og/logo_xhdpi.png", - BrandName: "盛趣游戏", - ForceShowAgreement: 1, - GreportLogLevel: "off", - LogLevel: "off", - LoginButton: []string{"official"}, - LoginIcon: []any{}, - NeedFloatWindowPermission: 1, - NewDeviceIDServer: strings.ToUpper(openssl.Md5ToString(deviceId)), - ShowGuestConfirm: 1, - VoicetipButton: 1, - } - data, err := json.Marshal(initResp) - utils.CheckErr(err) - encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData) - // fmt.Println(encryptedToken64) - - resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedData64) - - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func GetCode(ctx *gin.Context) { - resp := `{ "code": 0, "msg": "ok", "data": { "codeArray": [ { "btntext": "好的", "code": "-10264022", "msg_from": 2, "text": "", "title": "短信验证码被阻止", "type": 1 }, { "btntext": " ", "code": "-10869623", "msg_from": 2, "text": "", "title": "网络连接失败,无法一键登录", "type": 2 }, { "btntext": " ", "code": "10298300", "msg_from": 2, "text": "", "title": " ", "type": 3 }, { "btntext": "", "code": "10298311", "msg_from": 2, "text": "", "title": "", "type": 3 }, { "btntext": " ", "code": "10298312", "msg_from": 2, "text": "", "title": " ", "type": 3 }, { "btntext": " ", "code": "10298313", "msg_from": 2, "text": "", "title": " ", "type": 1 }, { "btntext": " ", "code": "10298321", "msg_from": 2, "text": "", "title": " ", "type": 3 }, { "btntext": " ", "code": "10298322", "msg_from": 2, "text": "", "title": " ", "type": 3 } ], "codeVersion": "1.0.5" } }` - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func LoginAuto(ctx *gin.Context) { - body, err := io.ReadAll(ctx.Request.Body) - utils.CheckErr(err) - defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - - body64, err := base64.StdEncoding.DecodeString(string(body)) - utils.CheckErr(err) - // fmt.Println(string(body64)) - - deviceId := ctx.Request.Header.Get("X-DEVICEID") - randKey, err := db.DB.Get([]byte(deviceId)) - utils.CheckErr(err) - - decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - queryStr := string(decryptedBody) - // fmt.Println(queryStr) - - params, err := url.ParseQuery(queryStr) - utils.CheckErr(err) - autoKey := params.Get("autokey") - // fmt.Println(autoKey) - if autoKey == "" { - ctx.String(http.StatusForbidden, ErrorMsg) - return - } - - var userId, ticket string - _, err = db.UserEng.Table("users").Cols("userid,ticket").Where("autokey = ?", autoKey).Get(&userId, &ticket) - utils.CheckErr(err) - - var resp string - if userId != "" { - autoResp := LoginAutoResp{ - Result: 0, - Message: "ok", - Autokey: autoKey, - UserId: userId, - Ticket: ticket, - } - data, err := json.Marshal(autoResp) - // fmt.Println(string(data)) - utils.CheckErr(err) - encryptedData, err := openssl.Des3ECBEncrypt(data, randKey[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData) - // fmt.Println(encryptedData64) - - resp = fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedData64) - } else { - data := `{"message":"账号不存在或者登陆状态已过期!","result":31}` - encryptedData, err := openssl.Des3ECBEncrypt([]byte(data), randKey[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData) - // fmt.Println(encryptedData64) - - resp = fmt.Sprintf(`{ "code": 31, "msg": "账号不存在或者登陆状态已过期!", "data": "%s" }`, encryptedData64) - } - - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func LoginArea(ctx *gin.Context) { - userId := ctx.PostForm("userid") - if userId != "" { - // fmt.Println(userId) - resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": { "userid": "%s" } }`, userId) - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) - } -} - -func AccountLogin(ctx *gin.Context) { - body, err := io.ReadAll(ctx.Request.Body) - utils.CheckErr(err) - defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - - body64, err := base64.StdEncoding.DecodeString(string(body)) - utils.CheckErr(err) - // fmt.Println(string(body64)) - - deviceId := ctx.Request.Header.Get("X-DEVICEID") - randKey, err := db.DB.Get([]byte(deviceId)) - utils.CheckErr(err) - - decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - queryStr, err := url.QueryUnescape(string(decryptedBody)) - utils.CheckErr(err) - - params, err := url.ParseQuery(queryStr) - utils.CheckErr(err) - - phone, password := params.Get("phone"), params.Get("password") - if phone == "" || password == "" { - ctx.String(http.StatusForbidden, ErrorMsg) - return - } - - // sql := `CREATE TABLE "users" ( - // "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - // "phone" TEXT, - // "password" TEXT, - // "autokey" TEXT, - // "ticket" TEXT, - // "userid" INTEGER, - // "last_login_time" INTEGER - // ); - // CREATE TABLE "user_key" ( - // "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - // "userid" INTEGER, - // "key" INTEGER - // );` - var pass, autoKey, ticket, userId string - _, err = db.UserEng.Table("users").Cols("password,autokey,ticket,userid").Where("phone = ?", phone). - Get(&pass, &autoKey, &ticket, &userId) - utils.CheckErr(err) - - loginResp := LoginResp{} - loginCode := 0 - loginMsg := "ok" - loginTime := time.Now().Unix() - if pass == "" { - // 未注册 - 自动注册 - session := db.UserEng.NewSession() - defer session.Close() - - // 开始会话 - if err = session.Begin(); err != nil { - session.Rollback() - panic(err) - } - - pass = openssl.Md5ToString(password) - autoKey = "AUTO" + strings.ToUpper(honokautils.RandomStr(32)) - userId = strconv.Itoa(int(loginTime)) - ticket = "9999999" + userId + userId - userStmt, err := session.DB().Prepare("INSERT INTO users(phone,password,autokey,ticket,userid,last_login_time) VALUES (?,?,?,?,?,?)") - if err != nil { - session.Rollback() - panic(err) - } - defer userStmt.Close() - - _, err = userStmt.Exec(phone, pass, autoKey, ticket, userId, loginTime) - if err != nil { - session.Rollback() - panic(err) - } - // id, _ := res.LastInsertId() - // fmt.Println("LastInsertId:", id) - - keyStmt, err := session.DB().Prepare("INSERT INTO user_key(userid,key) VALUES(?,?)") - if err != nil { - session.Rollback() - panic(err) - } - // 方便起见初始化 userid 和 key 一样 - // 注意:user_key 表中的 key 是上文生成的用于登录的 userid,而 userid 则是用于 Authorize Token 生成用的 - _, err = keyStmt.Exec(userId, userId) - if err != nil { - session.Rollback() - panic(err) - } - - // 结束会话 - if err = session.Commit(); err != nil { - session.Rollback() - panic(err) - } - - tools.InitUserData(int(loginTime)) - - // Login Response - loginResp.Autokey = autoKey - loginResp.HasRealInfo = 1 - loginResp.Message = "ok" - loginResp.RealInfoForce = 1 - loginResp.Ticket = ticket - loginResp.UserAttribute = "0" - loginResp.Userid = userId - } else { - // 已注册 - if openssl.Md5ToString(password) == pass { - // 密码正确 - // Login Response - loginResp.Autokey = autoKey // 注意:更换设备(deviceId 发生变化)应重新生成 autokey - loginResp.HasRealInfo = 1 - loginResp.Message = "ok" - loginResp.RealInfoForce = 1 - loginResp.Ticket = "9999999" + userId + strconv.Itoa(int(loginTime)) // 实际登录用的密码(每次登录都会重新生成新的) - loginResp.UserAttribute = "0" - loginResp.Userid = userId // 实际登录用的账号 - - // 更新信息 - userStmt, err := db.UserEng.DB().Prepare("UPDATE users SET autokey=?,ticket=?,last_login_time=? WHERE userid=?") - utils.CheckErr(err) - defer userStmt.Close() - - _, err = userStmt.Exec(autoKey, ticket, loginTime, userId) - utils.CheckErr(err) - // aff, _ := res.RowsAffected() - // fmt.Println("RowsAffected:", aff) - } else { - // 密码错误 - loginCode = 31 - loginMsg = "账号不存在或者密码有误!" - } - } - - data, err := json.Marshal(loginResp) - utils.CheckErr(err) - // fmt.Println(string(data)) - encryptedData, err := openssl.Des3ECBEncrypt(data, randKey[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - encryptedData64 := base64.StdEncoding.EncodeToString(encryptedData) - // fmt.Println(encryptedToken64) - - resp := fmt.Sprintf(`{ "code": %d, "msg": "%s", "data": "%s" }`, loginCode, loginMsg, encryptedData64) - - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func ReportRole(ctx *gin.Context) { - // body, err := io.ReadAll(ctx.Request.Body) - // utils.CheckErr(err) - // defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - - // body64, err := base64.StdEncoding.DecodeString(string(body)) - // utils.CheckErr(err) - // fmt.Println(string(body64)) - - deviceId := ctx.Request.Header.Get("X-DEVICEID") - randKey, err := db.DB.Get([]byte(deviceId)) - utils.CheckErr(err) - - // decryptedBody, err := openssl.Des3ECBDecrypt(body64, randKey[0:24], openssl.PKCS7_PADDING) - // utils.CheckErr(err) - // fmt.Println(string(decryptedBody)) - - // decrypted, err := url.QueryUnescape(string(decryptedBody)) - // utils.CheckErr(err) - // fmt.Println(decrypted) - - // Unable to decrypt server data - token := `{"message":"Hello, world!"}` - encryptedToken, err := openssl.Des3ECBEncrypt([]byte(token), randKey[0:24], openssl.PKCS7_PADDING) - utils.CheckErr(err) - encryptedToken64 := base64.StdEncoding.EncodeToString(encryptedToken) - // fmt.Println(encryptedToken64) - - resp := fmt.Sprintf(`{ "code": 0, "msg": "ok", "data": "%s" }`, encryptedToken64) - - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func GetProductList(ctx *gin.Context) { - resp := `{ "code": 0, "msg": "ok", "data": { "message": [ ], "result": 0 } }` - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func GuestStatus(ctx *gin.Context) { - resp := `{"code":0,"msg":"ok","data":{"disablead":1,"loginswitch":1,"message":"ok","result":0}}` - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func ReportLog(ctx *gin.Context) { - // body, err := io.ReadAll(ctx.Request.Body) - // utils.CheckErr(err) - // defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, "") -} - -func ReportApp(ctx *gin.Context) { - // body, err := io.ReadAll(ctx.Request.Body) - // utils.CheckErr(err) - // defer ctx.Request.Body.Close() - // fmt.Println(string(body)) - resp := `{ "code": 0, "msg": "", "data": { "needReport": 0 } }` - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} - -func Agreement(ctx *gin.Context) { - resp := `{ "return_code": 0, "error_type": 0, "return_message": "", "data": { } }` - ctx.Header("Content-Type", "text/html;charset=utf-8") - ctx.String(http.StatusOK, resp) -} diff --git a/internal/handler/profile.go b/internal/handler/profile.go deleted file mode 100644 index 24053b7..0000000 --- a/internal/handler/profile.go +++ /dev/null @@ -1,33 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "honoka-chan/internal/tools" - - "github.com/gin-gonic/gin" - "github.com/tidwall/gjson" -) - -func ProfileRegister(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - req := gjson.Parse(ctx.PostForm("request_data")) - pref := tools.UserPref{ - UserDesc: req.Get("introduction").String(), - } - - _, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref) - if ss.CheckErr(err) { - return - } - - profileResp := model.ProfileRegisterResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(profileResp) -} diff --git a/internal/handler/profile/register.go b/internal/handler/profile/register.go new file mode 100644 index 0000000..79b9771 --- /dev/null +++ b/internal/handler/profile/register.go @@ -0,0 +1,37 @@ +package profile + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/profile" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" +) + +func register(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + req := gjson.Parse(ctx.PostForm("request_data")) + pref := user.UserPref{ + UserDesc: req.Get("introduction").String(), + } + + _, err := ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Update(&pref) + if ss.CheckErr(err) { + return + } + + ss.Respond(profile.RegisterResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/profile/profileRegister", middleware.Common, register) +} diff --git a/internal/handler/scenario.go b/internal/handler/scenario.go deleted file mode 100644 index 5d03dbd..0000000 --- a/internal/handler/scenario.go +++ /dev/null @@ -1,48 +0,0 @@ -package handler - -import ( - "encoding/json" - "honoka-chan/internal/model" - "honoka-chan/internal/session" - honokautils "honoka-chan/pkg/utils" - "time" - - "github.com/gin-gonic/gin" -) - -func ScenarioStartup(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - startReq := model.ScenarioReq{} - err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq) - if ss.CheckErr(err) { - return - } - - startResp := model.ScenarioResp{ - ResponseData: model.ScenarioRes{ - ScenarioID: startReq.ScenarioID, - ScenarioAdjustment: 50, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(startResp) -} - -func ScenarioReward(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - data := honokautils.ReadAllText("assets/serverdata/reward.json") - var resp map[string]any - err := json.Unmarshal([]byte(data), &resp) - if ss.CheckErr(err) { - return - } - - ss.Respond(resp) -} diff --git a/internal/handler/scenario/reward.go b/internal/handler/scenario/reward.go new file mode 100644 index 0000000..6dc11c2 --- /dev/null +++ b/internal/handler/scenario/reward.go @@ -0,0 +1,29 @@ +package scenario + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/session" + honokautils "honoka-chan/pkg/utils" + + "github.com/gin-gonic/gin" +) + +func reward(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + data := honokautils.ReadAllText("assets/serverdata/reward.json") + var resp map[string]any + err := json.Unmarshal([]byte(data), &resp) + if ss.CheckErr(err) { + return + } + + ss.Respond(resp) +} + +func init() { + router.AddHandler("main.php", "POST", "/scenario/reward", middleware.Common, reward) +} diff --git a/internal/handler/scenario/startup.go b/internal/handler/scenario/startup.go new file mode 100644 index 0000000..377b14d --- /dev/null +++ b/internal/handler/scenario/startup.go @@ -0,0 +1,37 @@ +package scenario + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/scenario" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func startup(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + startReq := scenario.StartUpReq{} + err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq) + if ss.CheckErr(err) { + return + } + + ss.Respond(scenario.StartUpResp{ + ResponseData: scenario.StartUpData{ + ScenarioID: startReq.ScenarioID, + ScenarioAdjustment: 50, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/scenario/startup", middleware.Common, startup) +} diff --git a/internal/handler/subscenario.go b/internal/handler/subscenario.go deleted file mode 100644 index b5ddaba..0000000 --- a/internal/handler/subscenario.go +++ /dev/null @@ -1,48 +0,0 @@ -package handler - -import ( - "encoding/json" - "honoka-chan/internal/model" - "honoka-chan/internal/session" - honokautils "honoka-chan/pkg/utils" - "time" - - "github.com/gin-gonic/gin" -) - -func SubScenarioStartup(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - startReq := model.SubScenarioReq{} - err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &startReq) - if ss.CheckErr(err) { - return - } - - startResp := model.SubScenarioResp{ - ResponseData: model.SubScenarioRes{ - SubscenarioID: startReq.SubscenarioID, - ScenarioAdjustment: 50, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(startResp) -} - -func SubScenarioReward(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - data := honokautils.ReadAllText("assets/serverdata/subreward.json") - var resp map[string]any - err := json.Unmarshal([]byte(data), &resp) - if ss.CheckErr(err) { - return - } - - ss.Respond(resp) -} diff --git a/internal/handler/subscenario/reward.go b/internal/handler/subscenario/reward.go new file mode 100644 index 0000000..84ff1f3 --- /dev/null +++ b/internal/handler/subscenario/reward.go @@ -0,0 +1,29 @@ +package subscenario + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/session" + honokautils "honoka-chan/pkg/utils" + + "github.com/gin-gonic/gin" +) + +func reward(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + data := honokautils.ReadAllText("assets/serverdata/subreward.json") + var resp map[string]any + err := json.Unmarshal([]byte(data), &resp) + if ss.CheckErr(err) { + return + } + + ss.Respond(resp) +} + +func init() { + router.AddHandler("main.php", "POST", "/subscenario/reward", middleware.Common, reward) +} diff --git a/internal/handler/subscenario/startup.go b/internal/handler/subscenario/startup.go new file mode 100644 index 0000000..5d242b1 --- /dev/null +++ b/internal/handler/subscenario/startup.go @@ -0,0 +1,37 @@ +package subscenario + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/subscenario" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func startup(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + startReq := subscenario.StartUpReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &startReq) + if ss.CheckErr(err) { + return + } + + ss.Respond(subscenario.StartUpResp{ + ResponseData: subscenario.StartUpData{ + SubscenarioID: startReq.SubscenarioID, + ScenarioAdjustment: 50, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/subscenario/startup", middleware.Common, startup) +} diff --git a/internal/handler/tos.go b/internal/handler/tos.go deleted file mode 100644 index 54e4474..0000000 --- a/internal/handler/tos.go +++ /dev/null @@ -1,27 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "time" - - "github.com/gin-gonic/gin" -) - -func TosCheck(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - tosResp := model.TosResp{ - ResponseData: model.TosRes{ - TosID: 1, - TosType: 1, - IsAgreed: true, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(tosResp) -} diff --git a/internal/handler/tos/check.go b/internal/handler/tos/check.go new file mode 100644 index 0000000..d970071 --- /dev/null +++ b/internal/handler/tos/check.go @@ -0,0 +1,31 @@ +package tos + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/tos" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func check(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(tos.CheckResp{ + ResponseData: tos.CheckData{ + TosID: 1, + TosType: 1, + IsAgreed: true, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/tos/tosCheck", middleware.Common, check) +} diff --git a/internal/handler/unit.go b/internal/handler/unit.go deleted file mode 100644 index b05e372..0000000 --- a/internal/handler/unit.go +++ /dev/null @@ -1,275 +0,0 @@ -package handler - -import ( - "encoding/json" - "errors" - "fmt" - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "net/http" - "strconv" - "time" - - "github.com/gin-gonic/gin" -) - -func SetDisplayRank(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - dispResp := model.SetDisplayRankResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(dispResp) -} - -func SetDeck(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - userId, err := strconv.Atoi(ctx.GetString("userid")) - if ss.CheckErr(err) { - return - } - - deckReq := model.UnitDeckReq{} - err = json.Unmarshal([]byte(ctx.PostForm("request_data")), &deckReq) - if ss.CheckErr(err) { - return - } - - // 原有队伍信息 - var userDeckId []int - err = ss.UserEng.Table("user_deck_m").Cols("id").Where("user_id = ?", userId).Find(&userDeckId) - if ss.CheckErr(err) { - return - } - - // 删除全部原有队伍成员 - _, err = ss.UserEng.Table("deck_unit_m").In("user_deck_id", userDeckId).Delete() - if ss.CheckErr(err) { - return - } - - // 删除全部原有队伍 - _, err = ss.UserEng.Table("user_deck_m").In("id", userDeckId).Delete() - if ss.CheckErr(err) { - return - } - - // 遍历新队伍 - for _, deck := range deckReq.UnitDeckList { - // 新队伍信息 - userDeck := model.UserDeckData{ - DeckID: deck.UnitDeckID, - MainFlag: deck.MainFlag, - DeckName: deck.DeckName, - UserID: userId, - InsertDate: time.Now().Unix(), - } - _, err = ss.UserEng.Table("user_deck_m").Insert(&userDeck) - if ss.CheckErr(err) { - return - } - userDeckId := userDeck.ID - // fmt.Println("新队伍 ID:", userDeckId) - - // 队伍成员信息 - for _, unit := range deck.UnitDeckDetail { - // 成员信息 - newUnitData := model.UnitData{} - exists, err := ss.UserEng.Table("user_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Exist() - if ss.CheckErr(err) { - return - } - if exists { - // fmt.Println("新成员为用户增加成员") - _, err = ss.UserEng.Table("user_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Get(&newUnitData) - if ss.CheckErr(err) { - return - } - } else { - exists, err := ss.MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Exist() - if ss.CheckErr(err) { - return - } - if exists { - // fmt.Println("新成员为公共成员") - _, err = ss.MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", unit.UnitOwningUserID).Get(&newUnitData) - if ss.CheckErr(err) { - return - } - } else { - // fmt.Println("新成员不存在") - err = errors.New("新成员不存在") - } - if ss.CheckErr(err) { - return - } - } - // fmt.Println("新的成员信息:", newUnitData) - - // 插入新成员信息 - newUnitDeckData := model.UnitDeckData{} - b, err := json.Marshal(newUnitData) - if ss.CheckErr(err) { - return - } - err = json.Unmarshal(b, &newUnitDeckData) - if ss.CheckErr(err) { - return - } - newUnitDeckData.BeforeLove = newUnitDeckData.MaxLove - newUnitDeckData.Position = unit.Position - newUnitDeckData.UserDeckID = userDeckId - newUnitDeckData.InsertData = time.Now().Unix() - - _, err = ss.UserEng.Table("deck_unit_m").Insert(&newUnitDeckData) - if ss.CheckErr(err) { - return - } - } - } - - dispResp := model.SetDeckResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(dispResp) -} - -func SetDeckName(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - userId, err := strconv.Atoi(ctx.GetString("userid")) - if ss.CheckErr(err) { - return - } - - deckReq := model.DeckNameReq{} - err = json.Unmarshal([]byte(ctx.PostForm("request_data")), &deckReq) - if ss.CheckErr(err) { - return - } - - exists, err := ss.UserEng.Table("user_deck_m").Where("user_id = ? AND deck_id = ?", userId, deckReq.UnitDeckID).Exist() - if ss.CheckErr(err) { - return - } - if !exists { - ctx.String(http.StatusForbidden, ErrorMsg) - return - } - userDeck := model.UserDeckData{ - DeckName: deckReq.DeckName, - } - _, err = ss.UserEng.Table("user_deck_m").Update(&userDeck, &model.UserDeckData{ - UserID: userId, - DeckID: deckReq.UnitDeckID, - }) - if ss.CheckErr(err) { - return - } - - dispResp := model.SetDeckResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(dispResp) -} - -func WearAccessory(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - req := model.WearAccessoryReq{} - err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &req) - if ss.CheckErr(err) { - return - } - - // 取下饰品 - for _, v := range req.Remove { - fmt.Println("Remove:", v.AccessoryOwningUserID, v.UnitOwningUserID) - _, err := ss.UserEng.Table("accessory_wear_m"). - Where("accessory_owning_user_id = ? AND unit_owning_user_id = ? AND user_id = ?", v.AccessoryOwningUserID, v.UnitOwningUserID, ctx.GetString("userid")). - Delete() - if ss.CheckErr(err) { - return - } - } - - // 佩戴饰品 - for _, v := range req.Wear { - fmt.Println("Wear:", v.AccessoryOwningUserID, v.UnitOwningUserID) - data := model.AccessoryWearData{ - AccessoryOwningUserID: v.AccessoryOwningUserID, - UnitOwningUserID: v.UnitOwningUserID, - UserId: ctx.GetString("userid"), - } - _, err := ss.UserEng.Table("accessory_wear_m").Insert(&data) - if ss.CheckErr(err) { - return - } - } - - wearResp := model.AwardSetResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(wearResp) -} - -func RemoveSkillEquip(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - req := model.SkillEquipReq{} - err := json.Unmarshal([]byte(ctx.PostForm("request_data")), &req) - if ss.CheckErr(err) { - return - } - - // 取下宝石 - for _, v := range req.Remove { - fmt.Println("Remove:", v.UnitOwningUserID, v.UnitRemovableSkillID) - _, err := ss.UserEng.Table("skill_equip_m"). - Where("unit_removable_skill_id = ? AND unit_owning_user_id = ? AND user_id = ?", v.UnitRemovableSkillID, v.UnitOwningUserID, ctx.GetString("userid")). - Delete() - if ss.CheckErr(err) { - return - } - } - - // 佩戴宝石 - for _, v := range req.Equip { - fmt.Println("Equip:", v.UnitOwningUserID, v.UnitRemovableSkillID) - data := model.SkillEquipData{ - UnitRemovableSkillId: v.UnitRemovableSkillID, - UnitOwningUserID: v.UnitOwningUserID, - UserId: ctx.GetString("userid"), - } - _, err := ss.UserEng.Table("skill_equip_m").Insert(&data) - if ss.CheckErr(err) { - return - } - } - - wearResp := model.AwardSetResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(wearResp) -} diff --git a/internal/handler/unit/deck.go b/internal/handler/unit/deck.go new file mode 100644 index 0000000..2e8ce6c --- /dev/null +++ b/internal/handler/unit/deck.go @@ -0,0 +1,129 @@ +package unit + +import ( + "encoding/json" + "errors" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + profileapischema "honoka-chan/internal/schema/api/profile" + unitapischema "honoka-chan/internal/schema/api/unit" + "honoka-chan/internal/schema/unit" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func deck(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + deckReq := unit.DeckReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &deckReq) + if ss.CheckErr(err) { + return + } + + // 原有队伍信息 + var userDeckID []int + err = ss.UserEng.Table("user_deck").Cols("id").Where("user_id = ?", ss.UserID).Find(&userDeckID) + if ss.CheckErr(err) { + return + } + + // 删除全部原有队伍成员 + _, err = ss.UserEng.Table("user_deck_unit").In("user_deck_id", userDeckID).Delete() + if ss.CheckErr(err) { + return + } + + // 删除全部原有队伍 + _, err = ss.UserEng.Table("user_deck").In("id", userDeckID).Delete() + if ss.CheckErr(err) { + return + } + + // 遍历新队伍 + for _, deck := range deckReq.UnitDeckList { + // 新队伍信息 + userDeck := unitapischema.UserDeckData{ + DeckID: deck.UnitDeckID, + MainFlag: deck.MainFlag, + DeckName: deck.DeckName, + UserID: ss.UserID, + InsertDate: time.Now().Unix(), + } + _, err = ss.UserEng.Table("user_deck").Insert(&userDeck) + if ss.CheckErr(err) { + return + } + userDeckId := userDeck.ID + // fmt.Println("新队伍 ID:", userDeckId) + + // 队伍成员信息 + for _, u := range deck.UnitDeckDetail { + // 成员信息 + newUnitData := profileapischema.UnitData{} + exists, err := ss.UserEng.Table("user_unit").Where("unit_owning_user_id = ?", u.UnitOwningUserID).Exist() + if ss.CheckErr(err) { + return + } + if exists { + // fmt.Println("新成员为用户增加成员") + _, err = ss.UserEng.Table("user_unit").Where("unit_owning_user_id = ?", u.UnitOwningUserID).Get(&newUnitData) + if ss.CheckErr(err) { + return + } + } else { + exists, err := ss.MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", u.UnitOwningUserID).Exist() + if ss.CheckErr(err) { + return + } + if exists { + // fmt.Println("新成员为公共成员") + _, err = ss.MainEng.Table("common_unit_m").Where("unit_owning_user_id = ?", u.UnitOwningUserID).Get(&newUnitData) + if ss.CheckErr(err) { + return + } + } else { + // fmt.Println("新成员不存在") + err = errors.New("新成员不存在") + } + if ss.CheckErr(err) { + return + } + } + // fmt.Println("新的成员信息:", newUnitData) + + // 插入新成员信息 + newUnitDeckData := unitapischema.UnitDeckData{} + b, err := json.Marshal(newUnitData) + if ss.CheckErr(err) { + return + } + err = json.Unmarshal(b, &newUnitDeckData) + if ss.CheckErr(err) { + return + } + newUnitDeckData.BeforeLove = newUnitDeckData.MaxLove + newUnitDeckData.Position = u.Position + newUnitDeckData.UserDeckID = userDeckId + newUnitDeckData.InsertData = time.Now().Unix() + + _, err = ss.UserEng.Table("user_deck_unit").Insert(&newUnitDeckData) + if ss.CheckErr(err) { + return + } + } + } + + ss.Respond(unit.DeckResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/unit/deck", middleware.Common, deck) +} diff --git a/internal/handler/unit/deckname.go b/internal/handler/unit/deckname.go new file mode 100644 index 0000000..16b1f4e --- /dev/null +++ b/internal/handler/unit/deckname.go @@ -0,0 +1,49 @@ +package unit + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + unitapischema "honoka-chan/internal/schema/api/unit" + "honoka-chan/internal/schema/unit" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func deckName(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + deckReq := unit.DeckNameReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &deckReq) + if ss.CheckErr(err) { + return + } + + _, err = ss.UserEng.Table("user_deck").Where("user_id = ? AND deck_id = ?", ss.UserID, deckReq.UnitDeckID).Exist() + if ss.CheckErr(err) { + return + } + + userDeck := unitapischema.UserDeckData{ + DeckName: deckReq.DeckName, + } + _, err = ss.UserEng.Table("user_deck").Update(&userDeck, &unitapischema.UserDeckData{ + UserID: ss.UserID, + DeckID: deckReq.UnitDeckID, + }) + if ss.CheckErr(err) { + return + } + + ss.Respond(unit.DeckResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/unit/deckName", middleware.Common, deckName) +} diff --git a/internal/handler/unit/favorite.go b/internal/handler/unit/favorite.go new file mode 100644 index 0000000..e767718 --- /dev/null +++ b/internal/handler/unit/favorite.go @@ -0,0 +1,25 @@ +package unit + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/unit" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func favorite(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(unit.FavoriteResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/unit/favorite", middleware.Common, favorite) +} diff --git a/internal/handler/unit/removableskillequipment.go b/internal/handler/unit/removableskillequipment.go new file mode 100644 index 0000000..818b193 --- /dev/null +++ b/internal/handler/unit/removableskillequipment.go @@ -0,0 +1,57 @@ +package unit + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/unit" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func removableSkillEquipment(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + req := unit.RemovableSkillEquipmentReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &req) + if ss.CheckErr(err) { + return + } + + // 取下宝石 + for _, v := range req.Remove { + // fmt.Println("Remove:", v.UnitOwningUserID, v.UnitRemovableSkillID) + _, err := ss.UserEng.Table("user_unit_skill_equip"). + Where("unit_removable_skill_id = ? AND unit_owning_user_id = ? AND user_id = ?", v.UnitRemovableSkillID, v.UnitOwningUserID, ss.UserID). + Delete() + if ss.CheckErr(err) { + return + } + } + + // 佩戴宝石 + for _, v := range req.Equip { + // fmt.Println("Equip:", v.UnitOwningUserID, v.UnitRemovableSkillID) + data := unit.RemovableSkillEquipmentData{ + UnitRemovableSkillId: v.UnitRemovableSkillID, + UnitOwningUserID: v.UnitOwningUserID, + UserID: ss.UserID, + } + _, err := ss.UserEng.Table("user_unit_skill_equip").Insert(&data) + if ss.CheckErr(err) { + return + } + } + + ss.Respond(unit.RemovableSkillEquipmentResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/unit/removableSkillEquipment", middleware.Common, removableSkillEquipment) +} diff --git a/internal/handler/unit/setdisplayrank.go b/internal/handler/unit/setdisplayrank.go new file mode 100644 index 0000000..5c7fcf4 --- /dev/null +++ b/internal/handler/unit/setdisplayrank.go @@ -0,0 +1,25 @@ +package unit + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/unit" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func setDisplayRank(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(unit.SetDisplayRankResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/unit/setDisplayRank", middleware.Common, setDisplayRank) +} diff --git a/internal/handler/unit/wearaccessory.go b/internal/handler/unit/wearaccessory.go new file mode 100644 index 0000000..98dfe70 --- /dev/null +++ b/internal/handler/unit/wearaccessory.go @@ -0,0 +1,57 @@ +package unit + +import ( + "encoding/json" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/unit" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func wearAccessory(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + req := unit.WearAccessoryReq{} + err := json.Unmarshal([]byte(ctx.MustGet("request_data").(string)), &req) + if ss.CheckErr(err) { + return + } + + // 取下饰品 + for _, v := range req.Remove { + // fmt.Println("Remove:", v.AccessoryOwningUserID, v.UnitOwningUserID) + _, err := ss.UserEng.Table("user_accessory_wear"). + Where("accessory_owning_user_id = ? AND unit_owning_user_id = ? AND user_id = ?", v.AccessoryOwningUserID, v.UnitOwningUserID, ss.UserID). + Delete() + if ss.CheckErr(err) { + return + } + } + + // 佩戴饰品 + for _, v := range req.Wear { + // fmt.Println("Wear:", v.AccessoryOwningUserID, v.UnitOwningUserID) + data := unit.WearAccessoryData{ + AccessoryOwningUserID: v.AccessoryOwningUserID, + UnitOwningUserID: v.UnitOwningUserID, + UserID: ss.UserID, + } + _, err := ss.UserEng.Table("user_accessory_wear").Insert(&data) + if ss.CheckErr(err) { + return + } + } + + ss.Respond(unit.WearAccessoryResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/unit/wearAccessory", middleware.Common, wearAccessory) +} diff --git a/internal/handler/user.go b/internal/handler/user.go deleted file mode 100644 index 6f1dbad..0000000 --- a/internal/handler/user.go +++ /dev/null @@ -1,81 +0,0 @@ -package handler - -import ( - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "honoka-chan/internal/tools" - "net/http" - "time" - - "github.com/gin-gonic/gin" - "github.com/tidwall/gjson" -) - -func SetNotificationToken(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - notifResp := model.NotificationResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(notifResp) -} - -func ChangeNavi(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - req := gjson.Parse(ctx.PostForm("request_data")) - pref := tools.UserPref{ - UnitOwningUserID: int(req.Get("unit_owning_user_id").Int()), - } - _, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref) - if ss.CheckErr(err) { - return - } - - naviResp := model.UserNaviChangeResp{ - ResponseData: []any{}, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(naviResp) -} - -func ChangeName(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - req := gjson.Parse(ctx.PostForm("request_data")) - var oldName string - exists, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Cols("user_name").Get(&oldName) - if ss.CheckErr(err) { - return - } - if !exists { - ctx.String(http.StatusForbidden, ErrorMsg) - return - } - pref := tools.UserPref{ - UserName: req.Get("name").String(), - } - _, err = ss.UserEng.Table("user_preference_m").Where("user_id = ?", ctx.GetString("userid")).Update(&pref) - if ss.CheckErr(err) { - return - } - nameResp := model.UserNameChangeResp{ - ResponseData: model.UserNameChangeRes{ - BeforeName: oldName, - AfterName: req.Get("name").String(), - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(nameResp) -} diff --git a/internal/handler/user/changename.go b/internal/handler/user/changename.go new file mode 100644 index 0000000..cf81e9f --- /dev/null +++ b/internal/handler/user/changename.go @@ -0,0 +1,47 @@ +package user + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + userschema "honoka-chan/internal/schema/user" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" +) + +func changeName(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + req := gjson.Parse(ctx.MustGet("request_data").(string)) + var oldName string + _, err := ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Cols("user_name").Get(&oldName) + if ss.CheckErr(err) { + return + } + + pref := user.UserPref{ + UserName: req.Get("name").String(), + } + _, err = ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Update(&pref) + if ss.CheckErr(err) { + return + } + + ss.Respond(userschema.ChangeNameResp{ + ResponseData: userschema.ChangeNameData{ + BeforeName: oldName, + AfterName: req.Get("name").String(), + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/user/changeName", middleware.Common, changeName) +} diff --git a/internal/handler/user/changenavi.go b/internal/handler/user/changenavi.go new file mode 100644 index 0000000..b150b99 --- /dev/null +++ b/internal/handler/user/changenavi.go @@ -0,0 +1,36 @@ +package user + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + userschema "honoka-chan/internal/schema/user" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" +) + +func changeNavi(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + req := gjson.Parse(ctx.MustGet("request_data").(string)) + pref := user.UserPref{ + UnitOwningUserID: int(req.Get("unit_owning_user_id").Int()), + } + _, err := ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Update(&pref) + if ss.CheckErr(err) { + return + } + + ss.Respond(userschema.ChangeNaviResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/user/changeNavi", middleware.Common, changeNavi) +} diff --git a/internal/handler/user/setnotificationtoken.go b/internal/handler/user/setnotificationtoken.go new file mode 100644 index 0000000..d1e7c81 --- /dev/null +++ b/internal/handler/user/setnotificationtoken.go @@ -0,0 +1,25 @@ +package user + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/user" + "honoka-chan/internal/session" + + "github.com/gin-gonic/gin" +) + +func setNotificationToken(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + ss.Respond(user.SetNotificationTokenResp{ + ResponseData: []any{}, + ReleaseInfo: []any{}, + StatusCode: 200, + }) +} + +func init() { + router.AddHandler("main.php", "POST", "/user/setNotificationToken", middleware.Common, setNotificationToken) +} diff --git a/internal/handler/user/userinfo.go b/internal/handler/user/userinfo.go new file mode 100644 index 0000000..7673d64 --- /dev/null +++ b/internal/handler/user/userinfo.go @@ -0,0 +1,72 @@ +package user + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/model/user" + "honoka-chan/internal/router" + userapischema "honoka-chan/internal/schema/api/user" + userschema "honoka-chan/internal/schema/user" + "honoka-chan/internal/session" + "time" + + "github.com/gin-gonic/gin" +) + +func userInfo(ctx *gin.Context) { + ss := session.Get(ctx) + defer ss.Finalize() + + pref := user.UserPref{} + _, err := ss.UserEng.Table("user_pref").Where("user_id = ?", ss.UserID).Get(&pref) + if ss.CheckErr(err) { + return + } + + userResp := userschema.UserInfoResp{ + ResponseData: userschema.UserInfoData{ + User: userapischema.UserInfo{ + UserID: ss.UserID, + Name: pref.UserName, + Level: pref.UserLevel, + Exp: 1089696, + PreviousExp: 0, + NextExp: 1207185, + GameCoin: 112124104, + SnsCoin: 100000, + FreeSnsCoin: 50000, + PaidSnsCoin: 50000, + SocialPoint: 999999999, + UnitMax: 5000, + WaitingUnitMax: 1000, + EnergyMax: 417, + EnergyFullTime: "2023-03-20 03:58:55", + LicenseLiveEnergyRecoverlyTime: 60, + EnergyFullNeedTime: 0, + OverMaxEnergy: 0, + TrainingEnergy: 100, + TrainingEnergyMax: 100, + FriendMax: 99, + InviteCode: pref.InviteCode, + InsertDate: "2015-08-10 18:58:30", + UpdateDate: "2018-08-09 18:13:12", + TutorialState: -1, + DiamondCoin: 0, + CrystalCoin: 0, + LpRecoveryItem: []userapischema.LpRecoveryItem{}, + }, + Birth: userschema.Birth{ + BirthMonth: 10, + BirthDay: 18, + }, + ServerTimestamp: time.Now().Unix(), + }, + ReleaseInfo: []any{}, + StatusCode: 200, + } + + ss.Respond(userResp) +} + +func init() { + router.AddHandler("main.php", "POST", "/user/userInfo", middleware.Common, userInfo) +} diff --git a/internal/handler/userinfo.go b/internal/handler/userinfo.go deleted file mode 100644 index 245cc13..0000000 --- a/internal/handler/userinfo.go +++ /dev/null @@ -1,77 +0,0 @@ -package handler - -import ( - "honoka-chan/config" - "honoka-chan/internal/model" - "honoka-chan/internal/session" - "honoka-chan/internal/tools" - "net/http" - "strconv" - "time" - - "github.com/gin-gonic/gin" -) - -func UserInfo(ctx *gin.Context) { - ss := session.New(ctx) - defer ss.Finalize() - - userId, err := strconv.Atoi(ctx.GetString("userid")) - if ss.CheckErr(err) { - return - } - - pref := tools.UserPref{} - exists, err := ss.UserEng.Table("user_preference_m").Where("user_id = ?", userId).Get(&pref) - if ss.CheckErr(err) { - return - } - if !exists { - ctx.String(http.StatusForbidden, ErrorMsg) - return - } - - userResp := model.UserInfoResp{ - ResponseData: model.UserInfoRes{ - User: model.UserInfo{ - UserID: userId, - Name: pref.UserName, - Level: config.Conf.UserPrefs.Level, - Exp: config.Conf.UserPrefs.ExpNumerator, - PreviousExp: 0, - NextExp: config.Conf.UserPrefs.ExpDenominator, - GameCoin: config.Conf.UserPrefs.GameCoin, - SnsCoin: config.Conf.UserPrefs.SnsCoin, - FreeSnsCoin: config.Conf.UserPrefs.SnsCoin, - PaidSnsCoin: 0, - SocialPoint: 1438395, - UnitMax: 5000, - WaitingUnitMax: 1000, - EnergyMax: config.Conf.UserPrefs.EnergyMax, - EnergyFullTime: "2023-03-20 03:58:55", - LicenseLiveEnergyRecoverlyTime: 60, - EnergyFullNeedTime: 0, - OverMaxEnergy: config.Conf.UserPrefs.OverMaxEnergy, - TrainingEnergy: 100, - TrainingEnergyMax: 100, - FriendMax: 99, - InviteCode: config.Conf.UserPrefs.InviteCode, - InsertDate: "2015-08-10 18:58:30", - UpdateDate: "2018-08-09 18:13:12", - TutorialState: -1, - DiamondCoin: 0, - CrystalCoin: 0, - LpRecoveryItem: []model.LpRecoveryItem{}, - }, - Birth: model.Birth{ - BirthMonth: 10, - BirthDay: 18, - }, - ServerTimestamp: time.Now().Unix(), - }, - ReleaseInfo: []any{}, - StatusCode: 200, - } - - ss.Respond(userResp) -} diff --git a/internal/handler/webui/login.go b/internal/handler/webui/login.go new file mode 100644 index 0000000..4622641 --- /dev/null +++ b/internal/handler/webui/login.go @@ -0,0 +1,61 @@ +package webui + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/webui" + "honoka-chan/internal/utils" + "honoka-chan/pkg/db" + "net/http" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" + "github.com/go-think/openssl" +) + +func login(ctx *gin.Context) { + area := ctx.PostForm("area") + user := ctx.PostForm("user") + pass := ctx.PostForm("pass") + if area == "" || user == "" || pass == "" { + ctx.JSON(http.StatusOK, webui.Msg{ + Code: 1, + Message: "参数不完整!", + Redirect: "", + }) + return + } + + userName := " " + area + "-" + user + var userId int + exists, err := db.UserEng.Table("users").Where("phone = ? AND password = ?", userName, openssl.Md5ToString(pass)).Cols("user_id").Get(&userId) + utils.CheckErr(err) + if !exists { + ctx.JSON(http.StatusOK, webui.Msg{ + Code: 1, + Message: "账号不存在或者密码有误!", + Redirect: "", + }) + return + } + + session := sessions.Default(ctx) + session.Options(sessions.Options{ + MaxAge: 3600 * 24, + }) + session.Set("userid", userId) + session.Save() + + ctx.JSON(http.StatusOK, webui.Msg{ + Code: 0, + Message: "登录成功!", + Redirect: "/admin/index", + }) +} + +func init() { + router.AddHandler("admin", "GET", "/login", middleware.WebAuth, func(ctx *gin.Context) { + ctx.HTML(http.StatusOK, "admin/login.html", gin.H{}) + }) + router.AddHandler("admin", "POST", "/login", middleware.WebAuth, login) +} diff --git a/internal/handler/webui/logout.go b/internal/handler/webui/logout.go new file mode 100644 index 0000000..9b7ca37 --- /dev/null +++ b/internal/handler/webui/logout.go @@ -0,0 +1,26 @@ +package webui + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "net/http" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" +) + +func logout(ctx *gin.Context) { + session := sessions.Default(ctx) + session.Clear() + session.Options(sessions.Options{ + Path: "/admin", + MaxAge: -1, + }) + session.Save() + + ctx.Redirect(http.StatusFound, "/admin/login") +} + +func init() { + router.AddHandler("admin", "GET", "/logout", middleware.WebAuth, logout) +} diff --git a/internal/handler/webui.go b/internal/handler/webui/upload.go similarity index 72% rename from internal/handler/webui.go rename to internal/handler/webui/upload.go index 8d9b62e..27a3381 100644 --- a/internal/handler/webui.go +++ b/internal/handler/webui/upload.go @@ -1,19 +1,20 @@ -package handler +package webui import ( "encoding/csv" - "honoka-chan/internal/model" + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "honoka-chan/internal/schema/api/profile" "honoka-chan/internal/utils" "honoka-chan/pkg/db" "net/http" "os" "path" "strconv" + "strings" "time" - "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" - "github.com/go-think/openssl" ) type ErrMsg struct { @@ -21,59 +22,7 @@ type ErrMsg struct { Msg string `json:"msg"` } -func WebLogin(ctx *gin.Context) { - area := ctx.PostForm("area") - user := ctx.PostForm("user") - pass := ctx.PostForm("pass") - if area == "" || user == "" || pass == "" { - ctx.JSON(http.StatusOK, model.Msg{ - Code: 1, - Message: "参数不完整!", - Redirect: "", - }) - return - } - - userName := " " + area + "-" + user - var userId int - exists, err := db.UserEng.Table("users").Where("phone = ? AND password = ?", userName, openssl.Md5ToString(pass)).Cols("userid").Get(&userId) - utils.CheckErr(err) - if !exists { - ctx.JSON(http.StatusOK, model.Msg{ - Code: 1, - Message: "账号不存在或者密码有误!", - Redirect: "", - }) - return - } - - session := sessions.Default(ctx) - session.Options(sessions.Options{ - MaxAge: 3600 * 24, - }) - session.Set("userid", userId) - session.Save() - - ctx.JSON(http.StatusOK, model.Msg{ - Code: 0, - Message: "登录成功!", - Redirect: "/admin/index", - }) -} - -func WebLogout(ctx *gin.Context) { - session := sessions.Default(ctx) - session.Clear() - session.Options(sessions.Options{ - Path: "/admin", - MaxAge: -1, - }) - session.Save() - - ctx.Redirect(http.StatusFound, "/admin/login") -} - -func Upload(ctx *gin.Context) { +func upload(ctx *gin.Context) { file, err := ctx.FormFile("file") utils.CheckErr(err) @@ -155,7 +104,7 @@ func Upload(ctx *gin.Context) { skillExp = 29900 } - unitData := model.UnitData{ + unitData := profile.UnitData{ UserID: ctx.GetInt("userid"), UnitID: unitId, Exp: unitExp + diffExp, @@ -182,7 +131,7 @@ func Upload(ctx *gin.Context) { InsertDate: time.Now().Format("2006-01-02 03:04:05"), } - _, err = session.Table("user_unit_m").Insert(&unitData) + _, err = session.Table("user_unit").Insert(&unitData) if err != nil { session.Rollback() panic(err) @@ -196,3 +145,13 @@ func Upload(ctx *gin.Context) { ctx.JSON(http.StatusOK, ErrMsg{Error: 0, Msg: "上传成功!"}) } + +func init() { + router.AddHandler("admin", "GET", "/upload", middleware.WebAuth, func(ctx *gin.Context) { + ctx.HTML(http.StatusOK, "admin/upload.html", gin.H{ + "menu": 1, + "url": strings.Split(ctx.Request.URL.String(), "?")[0], + }) + }) + router.AddHandler("admin", "POST", "/upload", middleware.WebAuth, upload) +} diff --git a/internal/handler/webui/webui.go b/internal/handler/webui/webui.go new file mode 100644 index 0000000..289c329 --- /dev/null +++ b/internal/handler/webui/webui.go @@ -0,0 +1,28 @@ +package webui + +import ( + "honoka-chan/internal/middleware" + "honoka-chan/internal/router" + "net/http" + "strings" + + "github.com/gin-gonic/gin" +) + +func card(ctx *gin.Context) { + ctx.HTML(http.StatusOK, "admin/card.html", gin.H{ + "menu": 1, + "url": strings.Split(ctx.Request.URL.String(), "?")[0], + }) +} + +func index(ctx *gin.Context) { + ctx.HTML(http.StatusOK, "admin/index.html", gin.H{ + "url": strings.Split(ctx.Request.URL.String(), "?")[0], + }) +} + +func init() { + router.AddHandler("admin", "GET", "/card", middleware.WebAuth, card) + router.AddHandler("admin", "GET", "/index", middleware.WebAuth, index) +} diff --git a/internal/middleware/authkey.go b/internal/middleware/authkey.go deleted file mode 100644 index 446e187..0000000 --- a/internal/middleware/authkey.go +++ /dev/null @@ -1,54 +0,0 @@ -package middleware - -import ( - "encoding/base64" - "encoding/json" - "fmt" - "honoka-chan/internal/utils" - "honoka-chan/pkg/db" - "honoka-chan/pkg/encrypt" - honokautils "honoka-chan/pkg/utils" - "time" - - "github.com/gin-gonic/gin" - "github.com/tidwall/gjson" -) - -func AuthKey(ctx *gin.Context) { - req := gjson.Parse(ctx.PostForm("request_data")) - tDummyToken, err := base64.StdEncoding.DecodeString(req.Get("dummy_token").String()) - utils.CheckErr(err) - dummyToken := encrypt.RSADecrypt(tDummyToken) - - // aesKey := dummyToken[0:16] - // tAuthData, err := base64.StdEncoding.DecodeString(req.Get("auth_data").String()) - // utils.CheckErr(err) - // authData := utils.Sub16(encrypt.AES_CBC_Decrypt(tAuthData, aesKey)) - // fmt.Println(string(authData)) - - clientToken := base64.StdEncoding.EncodeToString(dummyToken) - serverToken := base64.StdEncoding.EncodeToString([]byte(honokautils.RandomStr(32))) - authorizeToken := base64.StdEncoding.EncodeToString([]byte(honokautils.RandomStr(32))) - - ctx.Set("dummy_token", serverToken) - ctx.Set("authorize_token", authorizeToken) - - authJson, err := json.Marshal(map[string]any{ - "client_token": clientToken, - "server_token": serverToken, - }) - utils.CheckErr(err) - err = db.DB.Set([]byte(authorizeToken), authJson) - utils.CheckErr(err) - - nonce := ctx.GetInt("nonce") - nonce++ - ctx.Set("nonce", nonce) - - authorize := fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&nonce=%d&requestTimeStamp=%d", time.Now().Unix(), nonce, ctx.GetInt64("req_time")) - - ctx.Header("user_id", "") - ctx.Header("authorize", authorize) - - ctx.Next() -} diff --git a/internal/middleware/common.go b/internal/middleware/common.go index d6c1247..d5ebec5 100644 --- a/internal/middleware/common.go +++ b/internal/middleware/common.go @@ -2,8 +2,7 @@ package middleware import ( "fmt" - "honoka-chan/internal/utils" - "honoka-chan/pkg/db" + "honoka-chan/internal/session" "net/http" "net/url" "strconv" @@ -12,64 +11,49 @@ import ( "github.com/gin-gonic/gin" ) -var ( - ErrorMsg = `{"code":20001,"message":""}` -) - -func CheckErr(err error) { +func CheckErr(ctx *gin.Context, err error) bool { if err != nil { - panic(err) + ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ + "code": 20001, + "message": err.Error(), + }) } + return err != nil } func Common(ctx *gin.Context) { - ctx.Set("req_time", time.Now().Unix()) - - authorize := ctx.Request.Header.Get("Authorize") - if authorize == "" { - ctx.String(http.StatusForbidden, ErrorMsg) - ctx.Abort() + reqData := "" + if form, err := ctx.MultipartForm(); err == nil { + if v, ok := form.Value["request_data"]; ok && len(v) > 0 { + reqData = v[0] + } } - ctx.Set("authorize", authorize) + if reqData == "" { + reqData = ctx.PostForm("request_data") + } + ctx.Set("request_data", reqData) + uid := ctx.GetHeader("User-ID") + ctx.Set("userid", uid) + + ss := session.New(ctx) + ctx.Set("session", ss) + + authorize := ctx.GetHeader("Authorize") params, err := url.ParseQuery(authorize) - utils.CheckErr(err) + if CheckErr(ctx, err) { + return + } - nonce, err := strconv.Atoi(params.Get("nonce")) - utils.CheckErr(err) + nonce, _ := strconv.Atoi(params.Get("nonce")) nonce++ ctx.Set("nonce", nonce) token := params.Get("token") ctx.Set("token", token) - if ctx.Request.URL.String() == "/main.php/login/authkey" || - ctx.Request.URL.String() == "/main.php/login/login" { - // 特殊请求 - fmt.Println("========") - } else { - userId := ctx.Request.Header.Get("User-ID") - if userId == "" { - ctx.String(http.StatusForbidden, ErrorMsg) - ctx.Abort() - } - ctx.Set("userid", userId) - - rToken, err := db.DB.Get([]byte(userId)) - utils.CheckErr(err) - if token != string(rToken) { - ctx.String(http.StatusForbidden, ErrorMsg) - ctx.Abort() - } - - if !db.MatchTokenUid(token, userId) { - ctx.String(http.StatusForbidden, ErrorMsg) - ctx.Abort() - } - - ctx.Header("user_id", userId) - ctx.Header("authorize", fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", time.Now().Unix(), token, nonce, userId, time.Now().Unix())) - } + ctx.Header("user_id", uid) + ctx.Header("authorize", fmt.Sprintf("consumerKey=lovelive_test&timeStamp=%d&version=1.1&token=%s&nonce=%d&user_id=%s&requestTimeStamp=%d", time.Now().Unix(), token, nonce, uid, time.Now().Unix())) ctx.Header("Content-Type", "application/json; charset=utf-8") ctx.Header("X-Powered-By", "KLab Native APP Platform") diff --git a/internal/middleware/login.go b/internal/middleware/login.go deleted file mode 100644 index 92068e6..0000000 --- a/internal/middleware/login.go +++ /dev/null @@ -1,45 +0,0 @@ -package middleware - -import ( - "encoding/base64" - "honoka-chan/internal/utils" - "honoka-chan/pkg/db" - "honoka-chan/pkg/encrypt" - honokautils "honoka-chan/pkg/utils" - - "github.com/gin-gonic/gin" - "github.com/tidwall/gjson" -) - -func Login(ctx *gin.Context) { - authData, err := db.DB.Get([]byte(ctx.GetString("token"))) - utils.CheckErr(err) - - clientToken, err := base64.StdEncoding.DecodeString(gjson.Get(string(authData), "client_token").String()) - utils.CheckErr(err) - serverToken, err := base64.StdEncoding.DecodeString(gjson.Get(string(authData), "server_token").String()) - utils.CheckErr(err) - - xmcKey := honokautils.SliceXor(clientToken, serverToken) - aesKey := xmcKey[0:16] - - req := gjson.Parse(ctx.GetString("request_data")) - tKey, err := base64.StdEncoding.DecodeString(req.Get("login_key").String()) - utils.CheckErr(err) - loginKey := honokautils.Sub16(encrypt.AESCBCDecrypt(tKey, aesKey)) - ctx.Set("login_key", string(loginKey)) - - tPasswd, err := base64.StdEncoding.DecodeString(req.Get("login_passwd").String()) - utils.CheckErr(err) - loginPasswd := honokautils.Sub16(encrypt.AESCBCDecrypt(tPasswd, aesKey)) - ctx.Set("login_passwd", string(loginPasswd)) - - nonce := ctx.GetInt("nonce") - nonce++ - ctx.Set("nonce", nonce) - - authorizeToken := base64.StdEncoding.EncodeToString([]byte(honokautils.RandomStr(32))) - ctx.Set("authorize_token", authorizeToken) - - ctx.Next() -} diff --git a/internal/middleware/multipart.go b/internal/middleware/multipart.go deleted file mode 100644 index 7327b63..0000000 --- a/internal/middleware/multipart.go +++ /dev/null @@ -1,34 +0,0 @@ -package middleware - -import ( - "honoka-chan/internal/utils" - "io" - "mime/multipart" - "strings" - - "github.com/gin-gonic/gin" -) - -func ParseMultipartForm(ctx *gin.Context) { - // I don't know why mime.ParseMediaType() is failed - // mime.ParseMediaType(ctx.Request.Header.Get("Content-Type")) - boundary := strings.ReplaceAll(ctx.Request.Header.Get("Content-Type"), "multipart/form-data; boundary=", "") - - var reqData []byte - mReader := multipart.NewReader(ctx.Request.Body, boundary) - for { - part, err := mReader.NextPart() - if err == io.EOF { - break - } - utils.CheckErr(err) - - data, err := io.ReadAll(part) - utils.CheckErr(err) - - reqData = data - } - ctx.Set("request_data", string(reqData)) - - ctx.Next() -} diff --git a/internal/model/album.go b/internal/model/album.go deleted file mode 100644 index 64207f3..0000000 --- a/internal/model/album.go +++ /dev/null @@ -1,35 +0,0 @@ -package model - -// AlbumResult ... -type AlbumResult struct { - UnitID int `json:"unit_id"` - RankMaxFlag bool `json:"rank_max_flag"` - LoveMaxFlag bool `json:"love_max_flag"` - RankLevelMaxFlag bool `json:"rank_level_max_flag"` - AllMaxFlag bool `json:"all_max_flag"` - HighestLovePerUnit int `json:"highest_love_per_unit"` - TotalLove int `json:"total_love"` - FavoritePoint int `json:"favorite_point"` - SignFlag bool `json:"sign_flag"` -} - -// AlbumResp ... -type AlbumResp struct { - Result []AlbumResult `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// AlbumSeriesRes ... -type AlbumSeriesRes struct { - SeriesID int `json:"series_id"` - UnitList []AlbumResult `json:"unit_list"` -} - -// AlbumSeriesResp ... -type AlbumSeriesResp struct { - ResponseData []AlbumSeriesRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} diff --git a/internal/model/announce.go b/internal/model/announce.go deleted file mode 100644 index e164268..0000000 --- a/internal/model/announce.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// AnnounceResp ... -type AnnounceResp struct { - ResponseData AnnounceRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// AnnounceRes ... -type AnnounceRes struct { - HasUnreadAnnounce bool `json:"has_unread_announce"` - ServerTimestamp int64 `json:"server_timestamp"` -} diff --git a/internal/model/authkey.go b/internal/model/authkey.go deleted file mode 100644 index da97f47..0000000 --- a/internal/model/authkey.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// AuthKeyRes ... -type AuthKeyRes struct { - AuthorizeToken string `json:"authorize_token"` - DummyToken string `json:"dummy_token"` -} - -// AuthKeyResp ... -type AuthKeyResp struct { - ResponseData AuthKeyRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} diff --git a/internal/model/award.go b/internal/model/award.go deleted file mode 100644 index 8b988b9..0000000 --- a/internal/model/award.go +++ /dev/null @@ -1,28 +0,0 @@ -package model - -// AwardSetResp ... -type AwardSetResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// AwardInfo ... -type AwardInfo struct { - AwardID int `json:"award_id"` - IsSet bool `json:"is_set"` - InsertDate string `json:"insert_date"` -} - -// AwardInfoRes ... -type AwardInfoRes struct { - AwardInfo []AwardInfo `json:"award_info"` -} - -// AwardInfoResp ... -type AwardInfoResp struct { - Result AwardInfoRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/background.go b/internal/model/background.go deleted file mode 100644 index 29cb9d2..0000000 --- a/internal/model/background.go +++ /dev/null @@ -1,28 +0,0 @@ -package model - -// BackgroundSetResp ... -type BackgroundSetResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// BackgroundInfo ... -type BackgroundInfo struct { - BackgroundID int `json:"background_id"` - IsSet bool `json:"is_set"` - InsertDate string `json:"insert_date"` -} - -// BackgroundInfoRes ... -type BackgroundInfoRes struct { - BackgroundInfo []BackgroundInfo `json:"background_info"` -} - -// BackgroundInfoResp ... -type BackgroundInfoResp struct { - Result BackgroundInfoRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/costume.go b/internal/model/costume.go deleted file mode 100644 index 9ce14b7..0000000 --- a/internal/model/costume.go +++ /dev/null @@ -1,21 +0,0 @@ -package model - -// CostumeList ... -type CostumeList struct { - UnitID int `json:"unit_id"` - IsRankMax bool `json:"is_rank_max"` - IsSigned bool `json:"is_signed"` -} - -// CostumeListRes ... -type CostumeListRes struct { - CostumeList []CostumeList `json:"costume_list"` -} - -// CostumeListResp ... -type CostumeListResp struct { - Result CostumeListRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/download.go b/internal/model/download.go deleted file mode 100644 index a21984b..0000000 --- a/internal/model/download.go +++ /dev/null @@ -1,102 +0,0 @@ -package model - -// AdditionalReq ... -type AdditionalReq struct { - Module string `json:"module"` - Mgd int `json:"mgd"` - Action string `json:"action"` - TimeStamp int `json:"timeStamp"` - PackageID int `json:"package_id"` - TargetOs string `json:"target_os"` - PackageType int `json:"package_type"` - CommandNum string `json:"commandNum"` -} - -// AdditionalRes ... -type AdditionalRes struct { - Size int `json:"size"` - URL string `json:"url"` -} - -// AdditionalResp ... -type AdditionalResp struct { - ResponseData []AdditionalRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// BatchReq ... -type BatchReq struct { - ClientVersion string `json:"client_version"` - Os string `json:"os"` - PackageType int `json:"package_type"` - ExcludedPackageIds []int `json:"excluded_package_ids"` - CommandNum string `json:"commandNum"` -} - -// BatchRes ... -type BatchRes struct { - Size int `json:"size"` - URL string `json:"url"` -} - -// BatchResp ... -type BatchResp struct { - ResponseData []BatchRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// UpdateReq ... -type UpdateReq struct { - Module string `json:"module"` - TargetOs string `json:"target_os"` - InstallVersion string `json:"install_version"` - TimeStamp int `json:"timeStamp"` - Action string `json:"action"` - PackageList []any `json:"package_list"` - CommandNum string `json:"commandNum"` - ExternalVersion string `json:"external_version"` -} - -// UpdateRes ... -type UpdateRes struct { - Size int `json:"size"` - URL string `json:"url"` - Version string `json:"version"` -} - -// UpdateResp ... -type UpdateResp struct { - ResponseData []UpdateRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// UrlReq ... -type UrlReq struct { - Module string `json:"module"` - Os string `json:"os"` - Mgd int `json:"mgd"` - PathList []string `json:"path_list"` - Action string `json:"action"` -} - -// UrlRes ... -type UrlRes struct { - UrlList []string `json:"url_list"` -} - -// UrlResp ... -type UrlResp struct { - ResponseData UrlRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// EventResp ... -type EventResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} diff --git a/internal/model/event.go b/internal/model/event.go deleted file mode 100644 index 49417ea..0000000 --- a/internal/model/event.go +++ /dev/null @@ -1,20 +0,0 @@ -package model - -// EventsResp ... -type EventsResp struct { - ResponseData EventsRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// EventsRes ... -type EventsRes struct { - TargetList []TargetList `json:"target_list"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// TargetList ... -type TargetList struct { - Position int `json:"position"` - IsDisplayable bool `json:"is_displayable"` -} diff --git a/internal/model/exchange.go b/internal/model/exchange.go deleted file mode 100644 index 4861be1..0000000 --- a/internal/model/exchange.go +++ /dev/null @@ -1,20 +0,0 @@ -package model - -// ExchangePointList ... -type ExchangePointList struct { - Rarity int `json:"rarity"` - ExchangePoint int `json:"exchange_point"` -} - -// ExchangePointRes ... -type ExchangePointRes struct { - ExchangePointList []ExchangePointList `json:"exchange_point_list"` -} - -// ExchangePointResp ... -type ExchangePointResp struct { - Result ExchangePointRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/lbonus.go b/internal/model/lbonus.go deleted file mode 100644 index 3456a4c..0000000 --- a/internal/model/lbonus.go +++ /dev/null @@ -1,84 +0,0 @@ -package model - -// LbDayItem ... -type LbDayItem struct { - ItemID int `json:"item_id"` - AddType int `json:"add_type"` - Amount int `json:"amount"` -} - -// LbDays ... -type LbDays struct { - Day int `json:"day"` - DayOfTheWeek int `json:"day_of_the_week"` - SpecialDay bool `json:"special_day"` - SpecialImageAsset string `json:"special_image_asset"` - Received bool `json:"received"` - AdReceived bool `json:"ad_received"` - Item LbDayItem `json:"item"` -} - -// LbMonth ... -type LbMonth struct { - Year int `json:"year"` - Month int `json:"month"` - Days []LbDays `json:"days"` -} - -// CalendarInfo ... -type CalendarInfo struct { - CurrentDate string `json:"current_date"` - CurrentMonth LbMonth `json:"current_month"` - NextMonth LbMonth `json:"next_month"` -} - -// Reward ... -type Reward struct { - ItemID int `json:"item_id"` - AddType int `json:"add_type"` - Amount int `json:"amount"` -} - -// TotalLoginInfo ... -type TotalLoginInfo struct { - LoginCount int `json:"login_count"` - RemainingCount int `json:"remaining_count"` - Reward []Reward `json:"reward"` -} - -// LbRankInfo ... -type LbRankInfo struct { - BeforeClassRankID int `json:"before_class_rank_id"` - AfterClassRankID int `json:"after_class_rank_id"` - RankUpDate string `json:"rank_up_date"` -} - -// LbClassSystem ... -type LbClassSystem struct { - RankInfo LbRankInfo `json:"rank_info"` - CompleteFlag bool `json:"complete_flag"` - IsOpened bool `json:"is_opened"` - IsVisible bool `json:"is_visible"` -} - -// LbRes ... -type LbRes struct { - Sheets []any `json:"sheets"` - CalendarInfo CalendarInfo `json:"calendar_info"` - TotalLoginInfo TotalLoginInfo `json:"total_login_info"` - LicenseLbonusList []any `json:"license_lbonus_list"` - ClassSystem LbClassSystem `json:"class_system"` - StartDashSheets []any `json:"start_dash_sheets"` - EffortPoint []EffortPoint `json:"effort_point"` - LimitedEffortBox []any `json:"limited_effort_box"` - MuseumInfo Museum `json:"museum_info"` - ServerTimestamp int64 `json:"server_timestamp"` - PresentCnt int `json:"present_cnt"` -} - -// LbResp ... -type LbResp struct { - ResponseData LbRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} diff --git a/internal/model/multiunit.go b/internal/model/multiunit.go deleted file mode 100644 index f9d9bc0..0000000 --- a/internal/model/multiunit.go +++ /dev/null @@ -1,55 +0,0 @@ -package model - -// MultiUnitScenarioChapterList ... -type MultiUnitScenarioChapterList struct { - MultiUnitScenarioID int `json:"multi_unit_scenario_id"` - Chapter int `json:"chapter"` - Status int `json:"status"` -} - -// MultiUnitScenarioStatusList ... -type MultiUnitScenarioStatusList struct { - MultiUnitID int `json:"multi_unit_id"` - Status int `json:"status"` - MultiUnitScenarioBtnAsset string `json:"multi_unit_scenario_btn_asset"` - OpenDate string `json:"open_date"` - ChapterList []MultiUnitScenarioChapterList `json:"chapter_list"` -} - -// MultiUnitScenarioStatusRes ... -type MultiUnitScenarioStatusRes struct { - MultiUnitScenarioStatusList []MultiUnitScenarioStatusList `json:"multi_unit_scenario_status_list"` - UnlockedMultiUnitScenarioIds []any `json:"unlocked_multi_unit_scenario_ids"` -} - -// MultiUnitScenarioStatusResp ... -type MultiUnitScenarioStatusResp struct { - Result MultiUnitScenarioStatusRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// MultiUnitStartUpResp ... -type MultiUnitStartUpResp struct { - ResponseData MultiUnitStartUpRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// MultiUnitStartUpRes ... -type MultiUnitStartUpRes struct { - MultiUnitScenarioID int `json:"multi_unit_scenario_id"` - ScenarioAdjustment int `json:"scenario_adjustment"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// MultiUnitStartUpReq ... -type MultiUnitStartUpReq struct { - Module string `json:"module"` - Action string `json:"action"` - TimeStamp int `json:"timeStamp"` - Mgd int `json:"mgd"` - MultiUnitScenarioID int `json:"multi_unit_scenario_id"` - CommandNum string `json:"commandNum"` -} diff --git a/internal/model/museum.go b/internal/model/museum.go deleted file mode 100644 index 6db77cc..0000000 --- a/internal/model/museum.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// MuseumResp ... -type MuseumResp struct { - ResponseData MuseumRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// MuseumParameter ... -type MuseumParameter struct { - Smile int `json:"smile"` - Pure int `json:"pure"` - Cool int `json:"cool"` -} - -// Museum ... -type Museum struct { - Parameter MuseumParameter `json:"parameter"` - ContentsIDList []int `json:"contents_id_list"` -} - -// MuseumRes ... -type MuseumRes struct { - MuseumInfo Museum `json:"museum_info"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// MuseumInfoRes ... -type MuseumInfoRes struct { - MuseumInfo Museum `json:"museum_info"` -} - -// MuseumInfoResp ... -type MuseumInfoResp struct { - Result MuseumInfoRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/navigation.go b/internal/model/navigation.go deleted file mode 100644 index 366c099..0000000 --- a/internal/model/navigation.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// SpecialCutinRes ... -type SpecialCutinRes struct { - SpecialCutinList []any `json:"special_cutin_list"` -} - -// SpecialCutinResp ... -type SpecialCutinResp struct { - Result SpecialCutinRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/notice.go b/internal/model/notice.go deleted file mode 100644 index 7e56681..0000000 --- a/internal/model/notice.go +++ /dev/null @@ -1,58 +0,0 @@ -package model - -// NoticeFriendVarietyResp ... -type NoticeFriendVarietyResp struct { - ResponseData NoticeFriendVarietyRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// NoticeFriendVarietyRes ... -type NoticeFriendVarietyRes struct { - ItemCount int `json:"item_count"` - NoticeList []any `json:"notice_list"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// NoticeFriendGreetingResp ... -type NoticeFriendGreetingResp struct { - ResponseData NoticeFriendGreetingRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// NoticeFriendGreetingRes ... -type NoticeFriendGreetingRes struct { - NextId int `json:"next_id"` - NoticeList []any `json:"notice_list"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// NoticeUserGreetingResp ... -type NoticeUserGreetingResp struct { - ResponseData NoticeUserGreetingRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// NoticeUserGreetingRes ... -type NoticeUserGreetingRes struct { - ItemCount int `json:"item_count"` - HasNext bool `json:"has_next"` - NoticeList []any `json:"notice_list"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// NoticeMarqueeRes ... -type NoticeMarqueeRes struct { - ItemCount int `json:"item_count"` - MarqueeList []any `json:"marquee_list"` -} - -// NoticeMarqueeResp ... -type NoticeMarqueeResp struct { - Result NoticeMarqueeRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/payment.go b/internal/model/payment.go deleted file mode 100644 index d7cd36c..0000000 --- a/internal/model/payment.go +++ /dev/null @@ -1,154 +0,0 @@ -package model - -// RestrictionInfo ... -type RestrictionInfo struct { - Restricted bool `json:"restricted"` -} - -// UnderAgeInfo ... -type UnderAgeInfo struct { - BirthSet bool `json:"birth_set"` - HasLimit bool `json:"has_limit"` - LimitAmount any `json:"limit_amount"` - MonthUsed int `json:"month_used"` -} - -// SnsProductItemList ... -type SnsProductItemList struct { - ItemID int `json:"item_id"` - AddType int `json:"add_type"` - Amount int `json:"amount"` - IsFreebie bool `json:"is_freebie"` -} - -// SnsProductList ... -type SnsProductList struct { - ProductID string `json:"product_id"` - Name string `json:"name"` - Price int `json:"price"` - CanBuy bool `json:"can_buy"` - ProductType int `json:"product_type"` - ItemList []SnsProductItemList `json:"item_list"` -} - -// ProductItemList ... -type ProductItemList struct { - ItemID int `json:"item_id"` - AddType int `json:"add_type"` - Amount int `json:"amount"` - IsFreebie bool `json:"is_freebie"` - IsRankMax bool `json:"is_rank_max,omitempty"` -} - -// LimitStatus ... -type LimitStatus struct { - TermStartDate string `json:"term_start_date"` - RemainingTime string `json:"remaining_time"` - RemainingCount int `json:"remaining_count"` -} - -// ProductList ... -type ProductList struct { - ProductID string `json:"product_id"` - Name string `json:"name"` - BannerImgAsset string `json:"banner_img_asset"` - Price int `json:"price"` - CanBuy bool `json:"can_buy"` - ProductType int `json:"product_type"` - AnnounceURL string `json:"announce_url"` - ConfirmURL string `json:"confirm_url"` - ItemList []ProductItemList `json:"item_list"` - LimitStatus LimitStatus `json:"limit_status"` -} - -// SubscriptionItemList ... -type SubscriptionItemList struct { - ItemID int `json:"item_id"` - AddType int `json:"add_type"` - Amount int `json:"amount"` - IsFreebie bool `json:"is_freebie"` -} - -// RewardList ... -type RewardList struct { - ItemID int `json:"item_id"` - AddType int `json:"add_type"` - Amount int `json:"amount"` -} - -// Items ... -type Items struct { - Seq int `json:"seq"` - RewardList []RewardList `json:"reward_list"` -} - -// LicenseInfo ... -type LicenseInfo struct { - Name string `json:"name"` - Items []Items `json:"items"` -} - -// UserStatus ... -type UserStatus struct { - IsLicensed bool `json:"is_licensed"` -} - -// SubscriptionStatus ... -type SubscriptionStatus struct { - LicenseID int `json:"license_id"` - LicenseType int `json:"license_type"` - LicenseInfo LicenseInfo `json:"license_info,omitempty"` - UserStatus UserStatus `json:"user_status"` - PurchaseCount int `json:"purchase_count"` - BadgeFlag bool `json:"badge_flag"` -} - -// SubscriptionList ... -type SubscriptionList struct { - ProductID string `json:"product_id"` - Name string `json:"name"` - BannerImgAsset string `json:"banner_img_asset"` - Price int `json:"price"` - CanBuy bool `json:"can_buy"` - ProductType int `json:"product_type"` - ProductURL string `json:"product_url"` - ItemList []SubscriptionItemList `json:"item_list"` - LimitStatus LimitStatus `json:"limit_status"` - SubscriptionStatus SubscriptionStatus `json:"subscription_status"` -} - -// ProductListRes ... -type ProductListRes struct { - RestrictionInfo RestrictionInfo `json:"restriction_info"` - UnderAgeInfo UnderAgeInfo `json:"under_age_info"` - SnsProductList []SnsProductList `json:"sns_product_list"` - ProductList []ProductList `json:"product_list"` - SubscriptionList []SubscriptionList `json:"subscription_list"` - ShowPointShop bool `json:"show_point_shop"` -} - -// ProductListResp ... -type ProductListResp struct { - Result ProductListRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// ProductResp ... -type ProductResp struct { - ResponseData ProductRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// ProductRes ... -type ProductRes struct { - RestrictionInfo RestrictionInfo `json:"restriction_info"` - UnderAgeInfo UnderAgeInfo `json:"under_age_info"` - SnsProductList []any `json:"sns_product_list"` - ProductList []any `json:"product_list"` - SubscriptionList []any `json:"subscription_list"` - ShowPointShop bool `json:"show_point_shop"` - ServerTimestamp int64 `json:"server_timestamp"` -} diff --git a/internal/model/personalnotice.go b/internal/model/personalnotice.go deleted file mode 100644 index 9c22c6d..0000000 --- a/internal/model/personalnotice.go +++ /dev/null @@ -1,18 +0,0 @@ -package model - -// PersonalNoticeResp ... -type PersonalNoticeResp struct { - ResponseData PersonalNoticeRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// PersonalNoticeRes ... -type PersonalNoticeRes struct { - HasNotice bool `json:"has_notice"` - NoticeID int `json:"notice_id"` - Type int `json:"type"` - Title string `json:"title"` - Contents string `json:"contents"` - ServerTimestamp int64 `json:"server_timestamp"` -} diff --git a/internal/model/scenario.go b/internal/model/scenario.go deleted file mode 100644 index 9e55a56..0000000 --- a/internal/model/scenario.go +++ /dev/null @@ -1,98 +0,0 @@ -package model - -// ScenarioStatusList ... -type ScenarioStatusList struct { - ScenarioID int `json:"scenario_id"` - Status int `json:"status"` -} - -// ScenarioStatusRes ... -type ScenarioStatusRes struct { - ScenarioStatusList []ScenarioStatusList `json:"scenario_status_list"` -} - -// ScenarioStatusResp ... -type ScenarioStatusResp struct { - Result ScenarioStatusRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// SubscenarioStatusList ... -type SubscenarioStatusList struct { - SubscenarioID int `json:"subscenario_id"` - Status int `json:"status"` -} - -// SubscenarioStatusRes ... -type SubscenarioStatusRes struct { - SubscenarioStatusList []SubscenarioStatusList `json:"subscenario_status_list"` - UnlockedSubscenarioIds []any `json:"unlocked_subscenario_ids"` -} - -// SubscenarioStatusResp ... -type SubscenarioStatusResp struct { - Result SubscenarioStatusRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// EventScenarioChapterList ... -type EventScenarioChapterList struct { - EventScenarioID int `json:"event_scenario_id"` - Chapter int `json:"chapter"` - ChapterAsset string `json:"chapter_asset,omitempty"` - Status int `json:"status"` - OpenFlashFlag int `json:"open_flash_flag"` - IsReward bool `json:"is_reward"` - CostType int `json:"cost_type"` - ItemID int `json:"item_id"` - Amount int `json:"amount"` -} - -// EventScenarioList ... -type EventScenarioList struct { - EventID int `json:"event_id"` - EventScenarioBtnAsset string `json:"event_scenario_btn_asset"` - OpenDate string `json:"open_date"` - ChapterList []EventScenarioChapterList `json:"chapter_list"` -} - -// EventScenarioStatusRes ... -type EventScenarioStatusRes struct { - EventScenarioList []EventScenarioList `json:"event_scenario_list"` -} - -// EventScenarioStatusResp ... -type EventScenarioStatusResp struct { - Result EventScenarioStatusRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// ScenarioResp ... -type ScenarioResp struct { - ResponseData ScenarioRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// ScenarioRes ... -type ScenarioRes struct { - ScenarioID int `json:"scenario_id"` - ScenarioAdjustment int `json:"scenario_adjustment"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// ScenarioReq ... -type ScenarioReq struct { - Module string `json:"module"` - Action string `json:"action"` - TimeStamp int `json:"timeStamp"` - Mgd int `json:"mgd"` - CommandNum string `json:"commandNum"` - ScenarioID int `json:"scenario_id"` -} diff --git a/internal/model/topinfo.go b/internal/model/topinfo.go deleted file mode 100644 index 0f4935b..0000000 --- a/internal/model/topinfo.go +++ /dev/null @@ -1,78 +0,0 @@ -package model - -// TopInfoLicenseInfo ... -type TopInfoLicenseInfo struct { - LicenseList []any `json:"license_list"` - LicensedInfo []any `json:"licensed_info"` - ExpiredInfo []any `json:"expired_info"` - BadgeFlag bool `json:"badge_flag"` -} - -// TopInfoRes ... -type TopInfoRes struct { - FriendActionCnt int `json:"friend_action_cnt"` - FriendGreetCnt int `json:"friend_greet_cnt"` - FriendVarietyCnt int `json:"friend_variety_cnt"` - FriendNewCnt int `json:"friend_new_cnt"` - PresentCnt int `json:"present_cnt"` - SecretBoxBadgeFlag bool `json:"secret_box_badge_flag"` - ServerDatetime string `json:"server_datetime"` - ServerTimestamp int64 `json:"server_timestamp"` - NoticeFriendDatetime string `json:"notice_friend_datetime"` - NoticeMailDatetime string `json:"notice_mail_datetime"` - FriendsApprovalWaitCnt int `json:"friends_approval_wait_cnt"` - FriendsRequestCnt int `json:"friends_request_cnt"` - IsTodayBirthday bool `json:"is_today_birthday"` - LicenseInfo TopInfoLicenseInfo `json:"license_info"` - UsingBuffInfo []any `json:"using_buff_info"` - IsKlabIDTaskFlag bool `json:"is_klab_id_task_flag"` - KlabIDTaskCanSync bool `json:"klab_id_task_can_sync"` - HasUnreadAnnounce bool `json:"has_unread_announce"` - ExchangeBadgeCnt []int `json:"exchange_badge_cnt"` - AdFlag bool `json:"ad_flag"` - HasAdReward bool `json:"has_ad_reward"` -} - -// TopInfoResp ... -type TopInfoResp struct { - Result TopInfoRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// TopInfoOnceNotification ... -type TopInfoOnceNotification struct { - Push bool `json:"push"` - Lp bool `json:"lp"` - UpdateInfo bool `json:"update_info"` - Campaign bool `json:"campaign"` - Live bool `json:"live"` - Lbonus bool `json:"lbonus"` - Event bool `json:"event"` - Secretbox bool `json:"secretbox"` - Birthday bool `json:"birthday"` -} - -// TopInfoOnceRes ... -type TopInfoOnceRes struct { - NewAchievementCnt int `json:"new_achievement_cnt"` - UnaccomplishedAchievementCnt int `json:"unaccomplished_achievement_cnt"` - LiveDailyRewardExist bool `json:"live_daily_reward_exist"` - TrainingEnergy int `json:"training_energy"` - TrainingEnergyMax int `json:"training_energy_max"` - Notification TopInfoOnceNotification `json:"notification"` - OpenArena bool `json:"open_arena"` - CostumeStatus bool `json:"costume_status"` - OpenAccessory bool `json:"open_accessory"` - ArenaSiSkillUniqueCheck bool `json:"arena_si_skill_unique_check"` - OpenV98 bool `json:"open_v98"` -} - -// TopInfoOnceResp ... -type TopInfoOnceResp struct { - Result TopInfoOnceRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/model/tos.go b/internal/model/tos.go deleted file mode 100644 index d692f90..0000000 --- a/internal/model/tos.go +++ /dev/null @@ -1,16 +0,0 @@ -package model - -// TosResp ... -type TosResp struct { - ResponseData TosRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// TosResp ... -type TosRes struct { - TosID int `json:"tos_id"` - TosType int `json:"tos_type"` - IsAgreed bool `json:"is_agreed"` - ServerTimestamp int64 `json:"server_timestamp"` -} diff --git a/internal/model/unit.go b/internal/model/unit.go deleted file mode 100644 index a8754b1..0000000 --- a/internal/model/unit.go +++ /dev/null @@ -1,316 +0,0 @@ -package model - -// AccessoryList ... -type AccessoryList struct { - AccessoryOwningUserID int `json:"accessory_owning_user_id" xorm:"accessory_owning_user_id"` - AccessoryID int `json:"accessory_id" xorm:"accessory_id"` - Exp int `json:"exp" xorm:"exp"` - NextExp int `json:"next_exp" xorm:"-"` - Level int `json:"level" xorm:"-"` - MaxLevel int `json:"max_level" xorm:"-"` - RankUpCount int `json:"rank_up_count" xorm:"-"` - FavoriteFlag bool `json:"favorite_flag" xorm:"-"` -} - -// WearingInfo -type WearingInfo struct { - UnitOwningUserID int `json:"unit_owning_user_id" xorm:"unit_owning_user_id"` - AccessoryOwningUserID int `json:"accessory_owning_user_id" xorm:"accessory_owning_user_id"` -} - -// UnitAccessoryAllResult ... -type UnitAccessoryAllResult struct { - AccessoryList []AccessoryList `json:"accessory_list"` - WearingInfo []WearingInfo `json:"wearing_info"` - EspecialCreateFlag bool `json:"especial_create_flag"` -} - -// UnitAccessoryAllResp ... -type UnitAccessoryAllResp struct { - Result UnitAccessoryAllResult `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// WearAccessoryReq ... -type WearAccessoryReq struct { - Module string `json:"module"` - Remove []Remove `json:"remove"` - Action string `json:"action"` - TimeStamp int `json:"timeStamp"` - Wear []Wear `json:"wear"` - Mgd int `json:"mgd"` - CommandNum string `json:"commandNum"` -} - -// Remove ... -type Remove struct { - AccessoryOwningUserID int `json:"accessory_owning_user_id"` - UnitOwningUserID int `json:"unit_owning_user_id"` -} - -// Wear ... -type Wear struct { - AccessoryOwningUserID int `json:"accessory_owning_user_id"` - UnitOwningUserID int `json:"unit_owning_user_id"` -} - -// AccessoryWearData ... -type AccessoryWearData struct { - Id int `xorm:"id pk autoincr"` - AccessoryOwningUserID int `xorm:"accessory_owning_user_id"` - UnitOwningUserID int `xorm:"unit_owning_user_id"` - UserId string `xorm:"user_id"` -} - -// AccessoryWearResp ... -type AccessoryWearResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// SkillEquipReq ... -type SkillEquipReq struct { - Module string `json:"module"` - Remove []SkillRemove `json:"remove"` - Action string `json:"action"` - TimeStamp int `json:"timeStamp"` - Equip []SkillEquip `json:"equip"` - Mgd int `json:"mgd"` - CommandNum string `json:"commandNum"` -} - -// SkillRemove ... -type SkillRemove struct { - UnitRemovableSkillID int `json:"unit_removable_skill_id"` - UnitOwningUserID int `json:"unit_owning_user_id"` -} - -// SkillEquip ... -type SkillEquip struct { - UnitRemovableSkillID int `json:"unit_removable_skill_id"` - UnitOwningUserID int `json:"unit_owning_user_id"` -} - -// SkillEquipCount ... -type SkillEquipCount struct { - UnitRemovableSkillId int `xorm:"unit_removable_skill_id"` - Count int `xorm:"ct"` -} - -// SkillEquipData ... -type SkillEquipData struct { - Id int `xorm:"id pk autoincr"` - UnitRemovableSkillId int `xorm:"unit_removable_skill_id"` - UnitOwningUserID int `xorm:"unit_owning_user_id"` - UserId string `xorm:"user_id"` -} - -// SkillEquipDetail ... -type SkillEquipDetail struct { - UnitRemovableSkillID int `json:"unit_removable_skill_id" xorm:"unit_removable_skill_id"` -} - -// SkillEquipList ... -type SkillEquipList struct { - UnitOwningUserID int `json:"unit_owning_user_id"` - Detail []SkillEquipDetail `json:"detail"` -} - -// SkillEquipResp ... -type SkillEquipResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// SetDisplayRankResp ... -type SetDisplayRankResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// SetDeckResp ... -type SetDeckResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// Costume ... -type Costume struct { - UnitID int `json:"unit_id"` - IsRankMax bool `json:"is_rank_max"` - IsSigned bool `json:"is_signed"` -} - -// Active ... -type Active struct { - UnitOwningUserID int `xorm:"unit_owning_user_id pk autoincr" json:"unit_owning_user_id"` - UserID int `xorm:"user_id" json:"-"` - UnitID int `xorm:"unit_id" json:"unit_id"` - Exp int `xorm:"exp" json:"exp"` - NextExp int `xorm:"next_exp" json:"next_exp"` - Level int `xorm:"level" json:"level"` - MaxLevel int `xorm:"max_level" json:"max_level"` - LevelLimitID int `xorm:"level_limit_id" json:"level_limit_id"` - Rank int `xorm:"rank" json:"rank"` - MaxRank int `xorm:"max_rank" json:"max_rank"` - Love int `xorm:"love" json:"love"` - MaxLove int `xorm:"max_love" json:"max_love"` - UnitSkillExp int `xorm:"unit_skill_exp" json:"unit_skill_exp"` - UnitSkillLevel int `xorm:"unit_skill_level" json:"unit_skill_level"` - MaxHp int `xorm:"max_hp" json:"max_hp"` - UnitRemovableSkillCapacity int `xorm:"unit_removable_skill_capacity" json:"unit_removable_skill_capacity"` - FavoriteFlag bool `xorm:"favorite_flag" json:"favorite_flag"` - DisplayRank int `xorm:"display_rank" json:"display_rank"` - IsRankMax bool `xorm:"is_rank_max" json:"is_rank_max"` - IsLoveMax bool `xorm:"is_love_max" json:"is_love_max"` - IsLevelMax bool `xorm:"is_level_max" json:"is_level_max"` - IsSigned bool `xorm:"is_signed" json:"is_signed"` - IsSkillLevelMax bool `xorm:"is_skill_level_max" json:"is_skill_level_max"` - IsRemovableSkillCapacityMax bool `xorm:"is_removable_skill_capacity_max" json:"is_removable_skill_capacity_max"` - InsertDate string `xorm:"insert_date" json:"insert_date"` - // Costume Costume `json:"costume,omitempty"` -} - -// Waiting ... -type Waiting struct { - UnitOwningUserID int64 `json:"unit_owning_user_id"` - UnitID int `json:"unit_id"` - Exp int `json:"exp"` - NextExp int `json:"next_exp"` - Level int `json:"level"` - MaxLevel int `json:"max_level"` - LevelLimitID int `json:"level_limit_id"` - Rank int `json:"rank"` - MaxRank int `json:"max_rank"` - Love int `json:"love"` - MaxLove int `json:"max_love"` - UnitSkillExp int `json:"unit_skill_exp"` - UnitSkillLevel int `json:"unit_skill_level"` - MaxHp int `json:"max_hp"` - UnitRemovableSkillCapacity int `json:"unit_removable_skill_capacity"` - FavoriteFlag bool `json:"favorite_flag"` - DisplayRank int `json:"display_rank"` - IsRankMax bool `json:"is_rank_max"` - IsLoveMax bool `json:"is_love_max"` - IsLevelMax bool `json:"is_level_max"` - IsSigned bool `json:"is_signed"` - IsSkillLevelMax bool `json:"is_skill_level_max"` - IsRemovableSkillCapacityMax bool `json:"is_removable_skill_capacity_max"` - InsertDate string `json:"insert_date"` -} - -// UnitAllRes ... -type UnitAllRes struct { - Active []Active `json:"active"` - Waiting []Waiting `json:"waiting"` -} - -// UnitAllResp ... -type UnitAllResp struct { - Result UnitAllRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// UnitOwningUserIds ... -type UnitOwningUserIds struct { - Position int `json:"position"` - UnitOwningUserID int `json:"unit_owning_user_id"` -} - -// UnitDeckInfoRes ... -type UnitDeckInfoRes struct { - UnitDeckID int `json:"unit_deck_id"` - MainFlag bool `json:"main_flag"` - DeckName string `json:"deck_name"` - UnitOwningUserIds []UnitOwningUserIds `json:"unit_owning_user_ids"` -} - -// UnitDeckInfoResp ... -type UnitDeckInfoResp struct { - Result []UnitDeckInfoRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// UnitSupportList ... -type UnitSupportList struct { - UnitID int `json:"unit_id"` - Amount int `json:"amount"` -} - -// UnitSupportRes ... -type UnitSupportRes struct { - UnitSupportList []UnitSupportList `json:"unit_support_list"` -} - -// UnitSupportResp ... -type UnitSupportResp struct { - Result UnitSupportRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// OwningInfo ... -type OwningInfo struct { - UnitRemovableSkillID int `json:"unit_removable_skill_id"` - TotalAmount int `json:"total_amount"` - EquippedAmount int `json:"equipped_amount"` - InsertDate string `json:"insert_date"` -} - -// RemovableSkillRes ... -type RemovableSkillRes struct { - OwningInfo []OwningInfo `json:"owning_info"` - EquipmentInfo map[int]any `json:"equipment_info"` -} - -// RemovableSkillResp ... -type RemovableSkillResp struct { - Result RemovableSkillRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// UnitDeckReq ... -type UnitDeckReq struct { - Module string `json:"module"` - UnitDeckList []UnitDeckList `json:"unit_deck_list"` - Action string `json:"action"` - Mgd int `json:"mgd"` -} - -// UnitDeckDetail ... -type UnitDeckDetail struct { - Position int `json:"position"` - UnitOwningUserID int `json:"unit_owning_user_id"` -} - -// UnitDeckList ... -type UnitDeckList struct { - UnitDeckDetail []UnitDeckDetail `json:"unit_deck_detail"` - UnitDeckID int `json:"unit_deck_id"` - MainFlag int `json:"main_flag"` - DeckName string `json:"deck_name"` -} - -// DeckNameReq ... -type DeckNameReq struct { - Module string `json:"module"` - UnitDeckID int `json:"unit_deck_id"` - Action string `json:"action"` - TimeStamp int `json:"timeStamp"` - Mgd int `json:"mgd"` - CommandNum string `json:"commandNum"` - DeckName string `json:"deck_name"` -} diff --git a/internal/model/user.go b/internal/model/user.go deleted file mode 100644 index d2b2db2..0000000 --- a/internal/model/user.go +++ /dev/null @@ -1,48 +0,0 @@ -package model - -// UserNaviResp ... -type UserNaviChangeResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// UserNameChangeResp ... -type UserNameChangeResp struct { - ResponseData UserNameChangeRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// UserNameChangeRes ... -type UserNameChangeRes struct { - BeforeName string `json:"before_name"` - AfterName string `json:"after_name"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// User ... -type User struct { - UserID int `json:"user_id"` - UnitOwningUserID int `json:"unit_owning_user_id"` -} - -// UserNaviRes ... -type UserNaviRes struct { - User User `json:"user"` -} - -// UserNaviResp ... -type UserNaviResp struct { - Result UserNaviRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// NotificationResp ... -type NotificationResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} diff --git a/internal/model/user/useraccessorywear.go b/internal/model/user/useraccessorywear.go new file mode 100644 index 0000000..507054c --- /dev/null +++ b/internal/model/user/useraccessorywear.go @@ -0,0 +1,12 @@ +package user + +type UserAccessoryWear struct { + ID int `xorm:"id pk autoincr"` + AccessoryOwningUserID int `xorm:"accessory_owning_user_id"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UserID int `xorm:"user_id"` +} + +func (u *UserAccessoryWear) TableName() string { + return "user_accessory_wear" +} diff --git a/internal/model/user/userdeck.go b/internal/model/user/userdeck.go new file mode 100644 index 0000000..f981652 --- /dev/null +++ b/internal/model/user/userdeck.go @@ -0,0 +1,14 @@ +package user + +type UserDeck struct { + ID int `xorm:"id pk autoincr"` + DeckID int `xorm:"deck_id"` + DeckName string `xorm:"deck_name"` + MainFlag int `xorm:"main_flag"` + UserID int `xorm:"user_id"` + InsertDate int64 `xorm:"insert_date"` +} + +func (u *UserDeck) TableName() string { + return "user_deck" +} diff --git a/internal/model/user/userdeckunit.go b/internal/model/user/userdeckunit.go new file mode 100644 index 0000000..dc08a5d --- /dev/null +++ b/internal/model/user/userdeckunit.go @@ -0,0 +1,25 @@ +package user + +type UserDeckUnit struct { + ID int `xorm:"id pk autoincr"` + UserDeckID int `xorm:"user_deck_id"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UnitID int `xorm:"unit_id"` + Position int `xorm:"position"` + Level int `xorm:"level"` + LevelLimitID int `xorm:"level_limit_id"` + DisplayRank int `xorm:"display_rank"` + Love int `xorm:"love"` + UnitSkillLevel int `xorm:"unit_skill_level"` + IsRankMax int `xorm:"is_rank_max"` + IsLoveMax int `xorm:"is_love_max"` + IsLevelMax int `xorm:"is_level_max"` + IsSigned int `xorm:"is_signed"` + BeforeLove int `xorm:"before_love"` + MaxLove int `xorm:"max_love"` + InsertDate int64 `xorm:"insert_date"` +} + +func (u *UserDeckUnit) TableName() string { + return "user_deck_unit" +} diff --git a/internal/model/user/userkey.go b/internal/model/user/userkey.go new file mode 100644 index 0000000..c2d8a26 --- /dev/null +++ b/internal/model/user/userkey.go @@ -0,0 +1,11 @@ +package user + +type UserKey struct { + ID int `xorm:"id pk autoincr"` + UserID int `xorm:"user_id"` + Key int `xorm:"key"` +} + +func (UserKey) TableName() string { + return "user_key" +} diff --git a/internal/model/user/userpref.go b/internal/model/user/userpref.go new file mode 100644 index 0000000..289c0af --- /dev/null +++ b/internal/model/user/userpref.go @@ -0,0 +1,18 @@ +package user + +type UserPref struct { + ID int `xorm:"id pk autoincr"` + UserID int `xorm:"user_id"` + AwardID int `xorm:"award_id"` + BackgroundID int `xorm:"background_id"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UserName string `xorm:"user_name"` + UserLevel int `xorm:"user_level"` + UserDesc string `xorm:"user_desc"` + InviteCode string `xorm:"invite_code"` + UpdateTime int64 `xorm:"update_time"` +} + +func (UserPref) TableName() string { + return "user_pref" +} diff --git a/internal/model/user/users.go b/internal/model/user/users.go new file mode 100644 index 0000000..8dd269a --- /dev/null +++ b/internal/model/user/users.go @@ -0,0 +1,15 @@ +package user + +type Users struct { + ID int `xorm:"id pk autoincr"` + Phone string `xorm:"phone"` + Password string `xorm:"password"` + Autokey string `xorm:"autokey"` + Ticket string `xorm:"ticket"` + UserID int `xorm:"user_id"` + LastLoginTime int64 `xorm:"last_login_time"` +} + +func (Users) TableName() string { + return "users" +} diff --git a/internal/model/user/userunit.go b/internal/model/user/userunit.go new file mode 100644 index 0000000..6ce3a31 --- /dev/null +++ b/internal/model/user/userunit.go @@ -0,0 +1,34 @@ +package user + +type UserUnit struct { + ID int `xorm:"id pk autoincr"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UserID int `xorm:"user_id"` + UnitID int `xorm:"unit_id"` + Exp int `xorm:"exp"` + NextExp int `xorm:"next_exp"` + Level int `xorm:"level"` + MaxLevel int `xorm:"max_level"` + LevelLimitID int `xorm:"level_limit_id"` + Rank int `xorm:"rank"` + MaxRank int `xorm:"max_rank"` + Love int `xorm:"love"` + MaxLove int `xorm:"max_love"` + UnitSkillExp int `xorm:"unit_skill_exp"` + UnitSkillLevel int `xorm:"unit_skill_level"` + MaxHp int `xorm:"max_hp"` + UnitRemovableSkillCapacity int `xorm:"unit_removable_skill_capacity"` + FavoriteFlag int `xorm:"favorite_flag"` + DisplayRank int `xorm:"display_rank"` + IsRankMax int `xorm:"is_rank_max"` + IsLoveMax int `xorm:"is_love_max"` + IsLevelMax int `xorm:"is_level_max"` + IsSigned int `xorm:"is_signed"` + IsSkillLevelMax int `xorm:"is_skill_level_max"` + IsRemovableSkillCapacityMax int `xorm:"is_removable_skill_capacity_max"` + InsertDate string `xorm:"insert_date"` +} + +func (UserUnit) TableName() string { + return "user_unit" +} diff --git a/internal/model/user/userunitskillequip.go b/internal/model/user/userunitskillequip.go new file mode 100644 index 0000000..dcfd59f --- /dev/null +++ b/internal/model/user/userunitskillequip.go @@ -0,0 +1,12 @@ +package user + +type UserUnitSkillEquip struct { + ID int `xorm:"id pk autoincr"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UnitRemovableSkillID int `xorm:"unit_removable_skill_id"` + UserID int `xorm:"user_id"` +} + +func (UserUnitSkillEquip) TableName() string { + return "user_unit_skill_equip" +} diff --git a/internal/router/router.go b/internal/router/router.go index c02ced5..7a4c37d 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -1,8 +1,7 @@ +// Modified from https://github.com/arina999999997/elichika/blob/463b37a0d69dbe68fff7112fe87105cfb2e260d6/router/router.go package router import ( - "honoka-chan/internal/handler" - "honoka-chan/internal/middleware" "net/http" "os" "path/filepath" @@ -13,12 +12,79 @@ import ( "github.com/gin-gonic/gin" ) +type HandlerInfo struct { + Method string + Path string + Handlers []gin.HandlerFunc +} +type SpecialGroupSetup = func(*gin.RouterGroup) +type GroupInfo struct { + InitialHandlers []gin.HandlerFunc + Handlers map[string]HandlerInfo + SpecialSetups []SpecialGroupSetup +} + +var ( + groups = map[string]*GroupInfo{} + templates []string +) + +func initGroup(g string) { + _, exist := groups[g] + if exist { + return + } + groups[g] = &GroupInfo{ + InitialHandlers: []gin.HandlerFunc{}, + Handlers: map[string]HandlerInfo{}, + SpecialSetups: []SpecialGroupSetup{}, + } +} + +func (g *GroupInfo) AddInitialHandler(handler gin.HandlerFunc) { + g.InitialHandlers = append(g.InitialHandlers, handler) +} + +func (g *GroupInfo) AddHandler(method, path string, handlers ...gin.HandlerFunc) { + _, exist := g.Handlers[method+path] + if exist { + panic("Multiple handler for path and method: " + method + " " + path) + } + g.Handlers[method+path] = HandlerInfo{ + Method: method, + Path: path, + Handlers: handlers, + } +} + +func (g *GroupInfo) AddSpecialSetup(specialGroupSetup SpecialGroupSetup) { + g.SpecialSetups = append(g.SpecialSetups, specialGroupSetup) +} + +func AddInitialHandler(group string, handler gin.HandlerFunc) { + initGroup(group) + groups[group].AddInitialHandler(handler) +} +func AddHandler(group, method, path string, handlers ...gin.HandlerFunc) { + initGroup(group) + groups[group].AddHandler(method, path, handlers...) +} + +func AddSpecialSetup(group string, specialGroupSetup SpecialGroupSetup) { + initGroup(group) + groups[group].AddSpecialSetup(specialGroupSetup) +} + +func AddTemplates(path string) { + templates = append(templates, path) +} + func SifRouter(r *gin.Engine) { // Static - r.Static("/static", "assets/static") + r.Static("/static", "static") var files []string - _ = filepath.Walk("assets/static/templates", func(path string, info os.FileInfo, err error) error { + _ = filepath.Walk("static/templates", func(path string, info os.FileInfo, err error) error { if strings.HasSuffix(path, ".html") { files = append(files, path) } @@ -26,116 +92,37 @@ func SifRouter(r *gin.Engine) { }) r.LoadHTMLFiles(files...) + // favicon + r.StaticFile("/favicon.ico", "static/images/favicon.ico") + // session store := cookie.NewStore([]byte("llsif")) r.Use(sessions.Sessions("llsif", store)) - // / - r.Any("/", func(ctx *gin.Context) { - ctx.String(http.StatusOK, "Hello, world!") - }) - - // Private APIs - v1 := r.Group("v1") - { - v1.GET("/basic/getcode", handler.GetCode) - v1.POST("/account/active", handler.Active) - v1.POST("/account/initialize", handler.Initialize) - v1.POST("/account/loginauto", handler.LoginAuto) - v1.POST("/account/login", handler.AccountLogin) - v1.POST("/account/reportRole", handler.ReportRole) - v1.POST("/basic/getcode", handler.GetCode) - v1.POST("/basic/getProductList", handler.GetProductList) - v1.POST("/basic/handshake", handler.Handshake) - v1.POST("/basic/loginarea", handler.LoginArea) - v1.POST("/basic/publickey", handler.PublicKey) - v1.POST("/guest/status", handler.GuestStatus) - } - r.GET("/agreement/all", handler.Agreement) - r.GET("/integration/appReport/initialize", handler.ReportApp) - r.POST("/report/ge/app", handler.ReportLog) - // Private APIs - - // Server APIs - m := r.Group("main.php").Use(middleware.Common) - { - m.POST("/album/seriesAll", middleware.ParseMultipartForm, handler.AlbumSeriesAll) - m.POST("/announce/checkState", middleware.ParseMultipartForm, handler.AnnounceCheckState) - m.POST("/api", middleware.ParseMultipartForm, handler.Api) - m.POST("/award/set", handler.AwardSet) - m.POST("/background/set", handler.BackgroundSet) - m.POST("/download/additional", middleware.ParseMultipartForm, handler.DownloadAdditional) - m.POST("/download/batch", middleware.ParseMultipartForm, handler.DownloadBatch) - m.POST("/download/event", middleware.ParseMultipartForm, handler.DownloadEvent) - m.POST("/download/getUrl", middleware.ParseMultipartForm, handler.DownloadUrl) - m.POST("/download/update", middleware.ParseMultipartForm, handler.DownloadUpdate) - m.POST("/event/eventList", middleware.ParseMultipartForm, handler.EventList) - m.POST("/gdpr/get", middleware.ParseMultipartForm, handler.Gdpr) - m.POST("/lbonus/execute", handler.LBonusExecute) - m.POST("/live/gameover", handler.GameOver) - m.POST("/live/partyList", handler.PartyList) - m.POST("/live/play", middleware.ParseMultipartForm, handler.PlayLive) - m.POST("/live/preciseScore", middleware.ParseMultipartForm, handler.PlayScore) - m.POST("/live/reward", middleware.ParseMultipartForm, handler.PlayReward) - m.POST("/login/authkey", middleware.AuthKey, handler.AuthKey) - m.POST("/login/login", middleware.ParseMultipartForm, middleware.Login, handler.Login) - m.POST("/multiunit/scenarioStartup", handler.MultiUnitStartUp) - m.POST("/museum/info", middleware.ParseMultipartForm, handler.MuseumInfo) - m.POST("/notice/noticeFriendGreeting", middleware.ParseMultipartForm, handler.NoticeFriendGreeting) - m.POST("/notice/noticeFriendVariety", middleware.ParseMultipartForm, handler.NoticeFriendVariety) - m.POST("/notice/noticeUserGreetingHistory", handler.NoticeUserGreeting) - m.POST("/payment/productList", middleware.ParseMultipartForm, handler.ProductList) - m.POST("/personalnotice/get", middleware.ParseMultipartForm, handler.PersonalNotice) - m.POST("/profile/profileRegister", handler.ProfileRegister) - m.POST("/scenario/reward", handler.ScenarioReward) - m.POST("/scenario/startup", handler.ScenarioStartup) - m.POST("/subscenario/reward", handler.SubScenarioStartup) - m.POST("/subscenario/startup", handler.SubScenarioStartup) - m.POST("/tos/tosCheck", middleware.ParseMultipartForm, handler.TosCheck) - m.POST("/unit/deck", handler.SetDeck) - m.POST("/unit/deckName", handler.SetDeckName) - m.POST("/unit/favorite", handler.SetDisplayRank) - m.POST("/unit/removableSkillEquipment", handler.RemoveSkillEquip) - m.POST("/unit/setDisplayRank", handler.SetDisplayRank) - m.POST("/unit/wearAccessory", handler.WearAccessory) - m.POST("/user/changeName", handler.ChangeName) - m.POST("/user/changeNavi", handler.ChangeNavi) - m.POST("/user/setNotificationToken", handler.SetNotificationToken) - m.POST("/user/userInfo", middleware.ParseMultipartForm, handler.UserInfo) - } - r.GET("/webview.php/announce/index", handler.AnnounceIndex) - // Server APIs - - // Manga + // manga r.GET("/manga", func(ctx *gin.Context) { ctx.HTML(http.StatusOK, "common/manga.html", gin.H{}) }) - // WebUI - w := r.Group("admin").Use(middleware.WebAuth) - { - w.GET("/index", func(ctx *gin.Context) { - ctx.HTML(http.StatusOK, "admin/index.html", gin.H{ - "url": strings.Split(ctx.Request.URL.String(), "?")[0], - }) - }) - w.GET("/login", func(ctx *gin.Context) { - ctx.HTML(http.StatusOK, "admin/login.html", gin.H{}) - }) - w.POST("/login", handler.WebLogin) - w.GET("/logout", handler.WebLogout) - w.GET("/card", func(ctx *gin.Context) { - ctx.HTML(http.StatusOK, "admin/card.html", gin.H{ - "menu": 1, - "url": strings.Split(ctx.Request.URL.String(), "?")[0], - }) - }) - w.GET("/upload", func(ctx *gin.Context) { - ctx.HTML(http.StatusOK, "admin/upload.html", gin.H{ - "menu": 1, - "url": strings.Split(ctx.Request.URL.String(), "?")[0], - }) - }) - w.POST("/upload", handler.Upload) + // router + for groupPath, groupInfo := range groups { + groupApi := r.Group(groupPath, groupInfo.InitialHandlers...) + for _, handlerInfo := range groupInfo.Handlers { + switch handlerInfo.Method { + case "POST": + groupApi.POST(handlerInfo.Path, handlerInfo.Handlers...) + case "GET": + groupApi.GET(handlerInfo.Path, handlerInfo.Handlers...) + case "PUT": + groupApi.PUT(handlerInfo.Path, handlerInfo.Handlers...) + case "DELETE": + groupApi.DELETE(handlerInfo.Path, handlerInfo.Handlers...) + default: + panic("Must be GET, POST, PUT or DELETE") + } + } + for _, specialSetup := range groupInfo.SpecialSetups { + specialSetup(groupApi) + } } } diff --git a/internal/schema/album/seriesall.go b/internal/schema/album/seriesall.go new file mode 100644 index 0000000..ee7789a --- /dev/null +++ b/internal/schema/album/seriesall.go @@ -0,0 +1,24 @@ +package album + +type UnitList struct { + UnitID int `json:"unit_id"` + RankMaxFlag bool `json:"rank_max_flag"` + LoveMaxFlag bool `json:"love_max_flag"` + RankLevelMaxFlag bool `json:"rank_level_max_flag"` + AllMaxFlag bool `json:"all_max_flag"` + HighestLovePerUnit int `json:"highest_love_per_unit"` + TotalLove int `json:"total_love"` + FavoritePoint int `json:"favorite_point"` + SignFlag bool `json:"sign_flag"` +} + +type SeriesAllData struct { + SeriesID int `json:"series_id"` + UnitList []UnitList `json:"unit_list"` +} + +type SeriesAllResp struct { + ResponseData []SeriesAllData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/announce/checkstate.go b/internal/schema/announce/checkstate.go new file mode 100644 index 0000000..97bec02 --- /dev/null +++ b/internal/schema/announce/checkstate.go @@ -0,0 +1,12 @@ +package announce + +type CheckStateData struct { + HasUnreadAnnounce bool `json:"has_unread_announce"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type CheckStateDataResp struct { + ResponseData CheckStateData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/api/album/all.go b/internal/schema/api/album/all.go new file mode 100644 index 0000000..a92ce37 --- /dev/null +++ b/internal/schema/api/album/all.go @@ -0,0 +1,20 @@ +package album + +type UnitList struct { + UnitID int `json:"unit_id"` + RankMaxFlag bool `json:"rank_max_flag"` + LoveMaxFlag bool `json:"love_max_flag"` + RankLevelMaxFlag bool `json:"rank_level_max_flag"` + AllMaxFlag bool `json:"all_max_flag"` + HighestLovePerUnit int `json:"highest_love_per_unit"` + TotalLove int `json:"total_love"` + FavoritePoint int `json:"favorite_point"` + SignFlag bool `json:"sign_flag"` +} + +type AllResp struct { + Result []UnitList `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/model/api.go b/internal/schema/api/api.go similarity index 51% rename from internal/model/api.go rename to internal/schema/api/api.go index 5648bf2..3f89557 100644 --- a/internal/model/api.go +++ b/internal/schema/api/api.go @@ -1,23 +1,13 @@ -package model +package api -// ApiReq ... type ApiReq struct { Module string `json:"module"` Action string `json:"action"` Timestamp int64 `json:"timeStamp"` } -// ApiResp ... type ApiResp struct { ResponseData any `json:"response_data"` ReleaseInfo any `json:"release_info"` StatusCode int `json:"status_code"` } - -// ApiUserInfoResp ... -type ApiUserInfoResp struct { - Result UserInfo `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} diff --git a/internal/schema/api/award/info.go b/internal/schema/api/award/info.go new file mode 100644 index 0000000..47e3f2a --- /dev/null +++ b/internal/schema/api/award/info.go @@ -0,0 +1,18 @@ +package award + +type Info struct { + AwardID int `json:"award_id"` + IsSet bool `json:"is_set"` + InsertDate string `json:"insert_date"` +} + +type InfoData struct { + AwardInfo []Info `json:"award_info"` +} + +type InfoResp struct { + Result InfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/background/info.go b/internal/schema/api/background/info.go new file mode 100644 index 0000000..d974c1c --- /dev/null +++ b/internal/schema/api/background/info.go @@ -0,0 +1,18 @@ +package background + +type Info struct { + BackgroundID int `json:"background_id"` + IsSet bool `json:"is_set"` + InsertDate string `json:"insert_date"` +} + +type InfoData struct { + BackgroundInfo []Info `json:"background_info"` +} + +type InfoResp struct { + Result InfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/model/banner.go b/internal/schema/api/banner/list.go similarity index 66% rename from internal/model/banner.go rename to internal/schema/api/banner/list.go index fa3b703..99c48d8 100644 --- a/internal/model/banner.go +++ b/internal/schema/api/banner/list.go @@ -1,6 +1,5 @@ -package model +package banner -// BannerList ... type BannerList struct { BannerType int `json:"banner_type"` TargetID int `json:"target_id"` @@ -14,16 +13,14 @@ type BannerList struct { WebviewURL string `json:"webview_url,omitempty"` } -// BannerListRes ... -type BannerListRes struct { +type ListData struct { TimeLimit string `json:"time_limit"` BannerList []BannerList `json:"banner_list"` } -// BannerListResp ... -type BannerListResp struct { - Result BannerListRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` +type ListResp struct { + Result ListData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` } diff --git a/internal/model/marathon.go b/internal/schema/api/challenge/info.go similarity index 67% rename from internal/model/marathon.go rename to internal/schema/api/challenge/info.go index 3d11058..871b584 100644 --- a/internal/model/marathon.go +++ b/internal/schema/api/challenge/info.go @@ -1,7 +1,6 @@ -package model +package challenge -// MarathonInfoResp ... -type MarathonInfoResp struct { +type InfoResp struct { Result []any `json:"result"` Status int `json:"status"` CommandNum bool `json:"commandNum"` diff --git a/internal/schema/api/costume/list.go b/internal/schema/api/costume/list.go new file mode 100644 index 0000000..db6b372 --- /dev/null +++ b/internal/schema/api/costume/list.go @@ -0,0 +1,18 @@ +package costume + +type CostumeList struct { + UnitID int `json:"unit_id"` + IsRankMax bool `json:"is_rank_max"` + IsSigned bool `json:"is_signed"` +} + +type ListData struct { + CostumeList []CostumeList `json:"costume_list"` +} + +type ListResp struct { + Result ListData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/eventscenario/status.go b/internal/schema/api/eventscenario/status.go new file mode 100644 index 0000000..901c31b --- /dev/null +++ b/internal/schema/api/eventscenario/status.go @@ -0,0 +1,31 @@ +package eventscenario + +type ChapterList struct { + EventScenarioID int `json:"event_scenario_id"` + Chapter int `json:"chapter"` + ChapterAsset string `json:"chapter_asset,omitempty"` + Status int `json:"status"` + OpenFlashFlag int `json:"open_flash_flag"` + IsReward bool `json:"is_reward"` + CostType int `json:"cost_type"` + ItemID int `json:"item_id"` + Amount int `json:"amount"` +} + +type EventScenarioList struct { + EventID int `json:"event_id"` + EventScenarioBtnAsset string `json:"event_scenario_btn_asset"` + OpenDate string `json:"open_date"` + ChapterList []ChapterList `json:"chapter_list"` +} + +type StatusData struct { + EventScenarioList []EventScenarioList `json:"event_scenario_list"` +} + +type StatusResp struct { + Result StatusData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/exchange/owningpoint.go b/internal/schema/api/exchange/owningpoint.go new file mode 100644 index 0000000..33526a6 --- /dev/null +++ b/internal/schema/api/exchange/owningpoint.go @@ -0,0 +1,17 @@ +package exchange + +type ExchangePointList struct { + Rarity int `json:"rarity"` + ExchangePoint int `json:"exchange_point"` +} + +type OwningPointData struct { + ExchangePointList []ExchangePointList `json:"exchange_point_list"` +} + +type OwningPointResp struct { + Result OwningPointData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/live/schedule.go b/internal/schema/api/live/schedule.go new file mode 100644 index 0000000..96f02c1 --- /dev/null +++ b/internal/schema/api/live/schedule.go @@ -0,0 +1,45 @@ +package live + +type LiveList struct { + LiveDifficultyID int `json:"live_difficulty_id"` + StartDate string `json:"start_date"` + EndDate string `json:"end_date"` + IsRandom bool `json:"is_random"` +} + +type LimitedBonusCommonList struct { + LiveType int `json:"live_type"` + LimitedBonusType int `json:"limited_bonus_type"` + LimitedBonusValue int `json:"limited_bonus_value"` + StartDate string `json:"start_date"` + EndDate string `json:"end_date"` +} + +type RandomLiveList struct { + AttributeID int `json:"attribute_id"` + StartDate string `json:"start_date"` + EndDate string `json:"end_date"` +} + +type TrainingLiveList struct { + LiveDifficultyID int `json:"live_difficulty_id"` + StartDate string `json:"start_date"` + IsRandom bool `json:"is_random"` +} + +type ScheduleData struct { + EventList []any `json:"event_list"` + LiveList []LiveList `json:"live_list"` + LimitedBonusList []any `json:"limited_bonus_list"` + LimitedBonusCommonList []LimitedBonusCommonList `json:"limited_bonus_common_list"` + RandomLiveList []RandomLiveList `json:"random_live_list"` + FreeLiveList []any `json:"free_live_list"` + TrainingLiveList []TrainingLiveList `json:"training_live_list"` +} + +type ScheduleResp struct { + Result ScheduleData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/live/status.go b/internal/schema/api/live/status.go new file mode 100644 index 0000000..a98dae4 --- /dev/null +++ b/internal/schema/api/live/status.go @@ -0,0 +1,44 @@ +package live + +type NormalLiveStatusList struct { + LiveDifficultyID int `json:"live_difficulty_id"` + Status int `json:"status"` + HiScore int `json:"hi_score"` + HiComboCount int `json:"hi_combo_count"` + ClearCnt int `json:"clear_cnt"` + AchievedGoalIDList []int `json:"achieved_goal_id_list"` +} + +type SpecialLiveStatusList struct { + LiveDifficultyID int `json:"live_difficulty_id"` + Status int `json:"status"` + HiScore int `json:"hi_score"` + HiComboCount int `json:"hi_combo_count"` + ClearCnt int `json:"clear_cnt"` + AchievedGoalIDList []int `json:"achieved_goal_id_list"` +} + +type TrainingLiveStatusList struct { + LiveDifficultyID int `json:"live_difficulty_id"` + Status int `json:"status"` + HiScore int `json:"hi_score"` + HiComboCount int `json:"hi_combo_count"` + ClearCnt int `json:"clear_cnt"` + AchievedGoalIDList []int `json:"achieved_goal_id_list"` +} + +type StatusData struct { + NormalLiveStatusList []NormalLiveStatusList `json:"normal_live_status_list"` + SpecialLiveStatusList []SpecialLiveStatusList `json:"special_live_status_list"` + TrainingLiveStatusList []TrainingLiveStatusList `json:"training_live_status_list"` + MarathonLiveStatusList []any `json:"marathon_live_status_list"` + FreeLiveStatusList []any `json:"free_live_status_list"` + CanResumeLive bool `json:"can_resume_live"` +} + +type StatusResp struct { + Result StatusData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/liveicon/info.go b/internal/schema/api/liveicon/info.go new file mode 100644 index 0000000..288b736 --- /dev/null +++ b/internal/schema/api/liveicon/info.go @@ -0,0 +1,12 @@ +package liveicon + +type InfoData struct { + LiveNotesIconList []int `json:"live_notes_icon_list"` +} + +type InfoResp struct { + Result InfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/livese/info.go b/internal/schema/api/livese/info.go new file mode 100644 index 0000000..f89c785 --- /dev/null +++ b/internal/schema/api/livese/info.go @@ -0,0 +1,12 @@ +package livese + +type InfoData struct { + LiveSeList []int `json:"live_se_list"` +} + +type InfoResp struct { + Result InfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/login/topinfo.go b/internal/schema/api/login/topinfo.go new file mode 100644 index 0000000..49ab7f9 --- /dev/null +++ b/internal/schema/api/login/topinfo.go @@ -0,0 +1,39 @@ +package login + +type LicenseInfo struct { + LicenseList []any `json:"license_list"` + LicensedInfo []any `json:"licensed_info"` + ExpiredInfo []any `json:"expired_info"` + BadgeFlag bool `json:"badge_flag"` +} + +type TopInfoData struct { + FriendActionCnt int `json:"friend_action_cnt"` + FriendGreetCnt int `json:"friend_greet_cnt"` + FriendVarietyCnt int `json:"friend_variety_cnt"` + FriendNewCnt int `json:"friend_new_cnt"` + PresentCnt int `json:"present_cnt"` + SecretBoxBadgeFlag bool `json:"secret_box_badge_flag"` + ServerDatetime string `json:"server_datetime"` + ServerTimestamp int64 `json:"server_timestamp"` + NoticeFriendDatetime string `json:"notice_friend_datetime"` + NoticeMailDatetime string `json:"notice_mail_datetime"` + FriendsApprovalWaitCnt int `json:"friends_approval_wait_cnt"` + FriendsRequestCnt int `json:"friends_request_cnt"` + IsTodayBirthday bool `json:"is_today_birthday"` + LicenseInfo LicenseInfo `json:"license_info"` + UsingBuffInfo []any `json:"using_buff_info"` + IsKlabIDTaskFlag bool `json:"is_klab_id_task_flag"` + KlabIDTaskCanSync bool `json:"klab_id_task_can_sync"` + HasUnreadAnnounce bool `json:"has_unread_announce"` + ExchangeBadgeCnt []int `json:"exchange_badge_cnt"` + AdFlag bool `json:"ad_flag"` + HasAdReward bool `json:"has_ad_reward"` +} + +type TopInfoResp struct { + Result TopInfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/login/topinfoonce.go b/internal/schema/api/login/topinfoonce.go new file mode 100644 index 0000000..45dc9d9 --- /dev/null +++ b/internal/schema/api/login/topinfoonce.go @@ -0,0 +1,34 @@ +package login + +type Notification struct { + Push bool `json:"push"` + Lp bool `json:"lp"` + UpdateInfo bool `json:"update_info"` + Campaign bool `json:"campaign"` + Live bool `json:"live"` + Lbonus bool `json:"lbonus"` + Event bool `json:"event"` + Secretbox bool `json:"secretbox"` + Birthday bool `json:"birthday"` +} + +type TopInfoOnceData struct { + NewAchievementCnt int `json:"new_achievement_cnt"` + UnaccomplishedAchievementCnt int `json:"unaccomplished_achievement_cnt"` + LiveDailyRewardExist bool `json:"live_daily_reward_exist"` + TrainingEnergy int `json:"training_energy"` + TrainingEnergyMax int `json:"training_energy_max"` + Notification Notification `json:"notification"` + OpenArena bool `json:"open_arena"` + CostumeStatus bool `json:"costume_status"` + OpenAccessory bool `json:"open_accessory"` + ArenaSiSkillUniqueCheck bool `json:"arena_si_skill_unique_check"` + OpenV98 bool `json:"open_v98"` +} + +type TopInfoOnceResp struct { + Result TopInfoOnceData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/model/challenge.go b/internal/schema/api/marathon/info.go similarity index 67% rename from internal/model/challenge.go rename to internal/schema/api/marathon/info.go index 5e561f9..83d03df 100644 --- a/internal/model/challenge.go +++ b/internal/schema/api/marathon/info.go @@ -1,7 +1,6 @@ -package model +package marathon -// ChallengeInfoResp ... -type ChallengeInfoResp struct { +type InfoResp struct { Result []any `json:"result"` Status int `json:"status"` CommandNum bool `json:"commandNum"` diff --git a/internal/schema/api/multiunit/scenariostatus.go b/internal/schema/api/multiunit/scenariostatus.go new file mode 100644 index 0000000..2889f01 --- /dev/null +++ b/internal/schema/api/multiunit/scenariostatus.go @@ -0,0 +1,27 @@ +package multiunit + +type ChapterList struct { + MultiUnitScenarioID int `json:"multi_unit_scenario_id"` + Chapter int `json:"chapter"` + Status int `json:"status"` +} + +type StatusList struct { + MultiUnitID int `json:"multi_unit_id"` + Status int `json:"status"` + MultiUnitScenarioBtnAsset string `json:"multi_unit_scenario_btn_asset"` + OpenDate string `json:"open_date"` + ChapterList []ChapterList `json:"chapter_list"` +} + +type StatusData struct { + MultiUnitScenarioStatusList []StatusList `json:"multi_unit_scenario_status_list"` + UnlockedMultiUnitScenarioIds []any `json:"unlocked_multi_unit_scenario_ids"` +} + +type StatusResp struct { + Result StatusData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/museum/info.go b/internal/schema/api/museum/info.go new file mode 100644 index 0000000..f19e2fb --- /dev/null +++ b/internal/schema/api/museum/info.go @@ -0,0 +1,23 @@ +package museum + +type Parameter struct { + Smile int `json:"smile"` + Pure int `json:"pure"` + Cool int `json:"cool"` +} + +type Info struct { + Parameter Parameter `json:"parameter"` + ContentsIDList []int `json:"contents_id_list"` +} + +type InfoData struct { + MuseumInfo Info `json:"museum_info"` +} + +type InfoResp struct { + Result InfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/navigation/specialcutin.go b/internal/schema/api/navigation/specialcutin.go new file mode 100644 index 0000000..54b4528 --- /dev/null +++ b/internal/schema/api/navigation/specialcutin.go @@ -0,0 +1,12 @@ +package navigation + +type SpecialCutinData struct { + SpecialCutinList []any `json:"special_cutin_list"` +} + +type SpecialCutinResp struct { + Result SpecialCutinData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/notice/marquee.go b/internal/schema/api/notice/marquee.go new file mode 100644 index 0000000..d597faf --- /dev/null +++ b/internal/schema/api/notice/marquee.go @@ -0,0 +1,13 @@ +package notice + +type MarqueeData struct { + ItemCount int `json:"item_count"` + MarqueeList []any `json:"marquee_list"` +} + +type MarqueeResp struct { + Result MarqueeData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/payment/productlist.go b/internal/schema/api/payment/productlist.go new file mode 100644 index 0000000..9f7cf49 --- /dev/null +++ b/internal/schema/api/payment/productlist.go @@ -0,0 +1,120 @@ +package payment + +type RestrictionInfo struct { + Restricted bool `json:"restricted"` +} + +type UnderAgeInfo struct { + BirthSet bool `json:"birth_set"` + HasLimit bool `json:"has_limit"` + LimitAmount any `json:"limit_amount"` + MonthUsed int `json:"month_used"` +} + +type SnsProductItem struct { + ItemID int `json:"item_id"` + AddType int `json:"add_type"` + Amount int `json:"amount"` + IsFreebie bool `json:"is_freebie"` +} + +type SnsProduct struct { + ProductID string `json:"product_id"` + Name string `json:"name"` + Price int `json:"price"` + CanBuy bool `json:"can_buy"` + ProductType int `json:"product_type"` + ItemList []SnsProductItem `json:"item_list"` +} + +type ProductItem struct { + ItemID int `json:"item_id"` + AddType int `json:"add_type"` + Amount int `json:"amount"` + IsFreebie bool `json:"is_freebie"` + IsRankMax bool `json:"is_rank_max,omitempty"` +} + +type LimitStatus struct { + TermStartDate string `json:"term_start_date"` + RemainingTime string `json:"remaining_time"` + RemainingCount int `json:"remaining_count"` +} + +type Product struct { + ProductID string `json:"product_id"` + Name string `json:"name"` + BannerImgAsset string `json:"banner_img_asset"` + Price int `json:"price"` + CanBuy bool `json:"can_buy"` + ProductType int `json:"product_type"` + AnnounceURL string `json:"announce_url"` + ConfirmURL string `json:"confirm_url"` + ItemList []ProductItem `json:"item_list"` + LimitStatus LimitStatus `json:"limit_status"` +} + +type SubscriptionItem struct { + ItemID int `json:"item_id"` + AddType int `json:"add_type"` + Amount int `json:"amount"` + IsFreebie bool `json:"is_freebie"` +} + +type LicenseReward struct { + ItemID int `json:"item_id"` + AddType int `json:"add_type"` + Amount int `json:"amount"` +} + +type LicenseItem struct { + Seq int `json:"seq"` + RewardList []LicenseReward `json:"reward_list"` +} + +type LicenseInfo struct { + Name string `json:"name"` + Items []LicenseItem `json:"items"` +} + +type UserStatus struct { + IsLicensed bool `json:"is_licensed"` +} + +type SubscriptionStatus struct { + LicenseID int `json:"license_id"` + LicenseType int `json:"license_type"` + LicenseInfo LicenseInfo `json:"license_info,omitempty"` + UserStatus UserStatus `json:"user_status"` + PurchaseCount int `json:"purchase_count"` + BadgeFlag bool `json:"badge_flag"` +} + +type Subscription struct { + ProductID string `json:"product_id"` + Name string `json:"name"` + BannerImgAsset string `json:"banner_img_asset"` + Price int `json:"price"` + CanBuy bool `json:"can_buy"` + ProductType int `json:"product_type"` + ProductURL string `json:"product_url"` + ItemList []SubscriptionItem `json:"item_list"` + LimitStatus LimitStatus `json:"limit_status"` + SubscriptionStatus SubscriptionStatus `json:"subscription_status"` +} + +type ProductListData struct { + RestrictionInfo RestrictionInfo `json:"restriction_info"` + UnderAgeInfo UnderAgeInfo `json:"under_age_info"` + SnsProductList []SnsProduct `json:"sns_product_list"` + ProductList []Product `json:"product_list"` + SubscriptionList []Subscription `json:"subscription_list"` + ShowPointShop bool `json:"show_point_shop"` +} + +type ProductListResp struct { + Result ProductListData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/profile/cardranking.go b/internal/schema/api/profile/cardranking.go new file mode 100644 index 0000000..a06965d --- /dev/null +++ b/internal/schema/api/profile/cardranking.go @@ -0,0 +1,8 @@ +package profile + +type CardRankingResp struct { + Result []any `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/model/tools.go b/internal/schema/api/profile/info.go similarity index 71% rename from internal/model/tools.go rename to internal/schema/api/profile/info.go index 089720d..a53faab 100644 --- a/internal/model/tools.go +++ b/internal/schema/api/profile/info.go @@ -1,6 +1,5 @@ -package model +package profile -// UnitData ... type UnitData struct { UnitOwningUserID int `xorm:"unit_owning_user_id pk autoincr" json:"unit_owning_user_id"` UserID int `xorm:"user_id" json:"-"` @@ -29,60 +28,6 @@ type UnitData struct { InsertDate string `xorm:"insert_date" json:"insert_date"` } -// UserDeckData ... -type UserDeckData struct { - ID int `xorm:"id pk autoincr"` - DeckID int `xorm:"deck_id"` - MainFlag int `xorm:"main_flag"` - DeckName string `xorm:"deck_name"` - UserID int `xorm:"user_id"` - InsertDate int64 `xorm:"insert_date"` -} - -// UnitDeckData ... -type UnitDeckData struct { - ID int `xorm:"id pk autoincr" json:"-"` - UserDeckID int `xorm:"user_deck_id" json:"-"` - UnitOwningUserID int `xorm:"unit_owning_user_id" json:"unit_owning_user_id"` - UnitID int `xorm:"unit_id" json:"unit_id"` - Position int `xorm:"position" json:"position"` - Level int `xorm:"level" json:"level"` - LevelLimitID int `xorm:"level_limit_id" json:"level_limit_id"` - DisplayRank int `xorm:"display_rank" json:"display_rank"` - Love int `xorm:"love" json:"love"` - UnitSkillLevel int `xorm:"unit_skill_level" json:"unit_skill_level"` - IsRankMax bool `xorm:"is_rank_max" json:"is_rank_max"` - IsLoveMax bool `xorm:"is_love_max" json:"is_love_max"` - IsLevelMax bool `xorm:"is_level_max" json:"is_level_max"` - IsSigned bool `xorm:"is_signed" json:"is_signed"` - BeforeLove int `xorm:"before_love" json:"before_love"` - MaxLove int `xorm:"max_love" json:"max_love"` - InsertData int64 `xorm:"insert_date" json:"-"` -} - -// DifficultyRes ... -type DifficultyRes struct { - Difficulty int `json:"difficulty"` - ClearCnt int `json:"clear_cnt"` -} - -// DifficultyResp ... -type DifficultyResp struct { - Result []DifficultyRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// LoveResp ... -type LoveResp struct { - Result []any `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// AccessoryInfo ... type AccessoryInfo struct { AccessoryOwningUserID int `json:"accessory_owning_user_id"` AccessoryID int `json:"accessory_id"` @@ -94,8 +39,13 @@ type AccessoryInfo struct { FavoriteFlag bool `json:"favorite_flag"` } -// ProfileUserInfo ... -type ProfileUserInfo struct { +type Costume struct { + UnitID int `json:"unit_id"` + IsRankMax bool `json:"is_rank_max"` + IsSigned bool `json:"is_signed"` +} + +type UserInfo struct { UserID int `json:"user_id"` Name string `json:"name"` Level int `json:"level"` @@ -109,7 +59,6 @@ type ProfileUserInfo struct { Introduction string `json:"introduction"` } -// CenterUnitInfo ... type CenterUnitInfo struct { UnitOwningUserID int `json:"unit_owning_user_id"` UnitID int `json:"unit_id"` @@ -147,7 +96,6 @@ type CenterUnitInfo struct { TotalHp int `json:"total_hp"` } -// NaviUnitInfo ... type NaviUnitInfo struct { UnitOwningUserID int `json:"unit_owning_user_id"` UnitID int `json:"unit_id"` @@ -180,21 +128,19 @@ type NaviUnitInfo struct { RemovableSkillIds []int `json:"removable_skill_ids"` } -// ProfileRes ... -type ProfileRes struct { - UserInfo ProfileUserInfo `json:"user_info"` - CenterUnitInfo CenterUnitInfo `json:"center_unit_info"` - NaviUnitInfo NaviUnitInfo `json:"navi_unit_info"` - IsAlliance bool `json:"is_alliance"` - FriendStatus int `json:"friend_status"` - SettingAwardID int `json:"setting_award_id"` - SettingBackgroundID int `json:"setting_background_id"` +type InfoData struct { + UserInfo UserInfo `json:"user_info"` + CenterUnitInfo CenterUnitInfo `json:"center_unit_info"` + NaviUnitInfo NaviUnitInfo `json:"navi_unit_info"` + IsAlliance bool `json:"is_alliance"` + FriendStatus int `json:"friend_status"` + SettingAwardID int `json:"setting_award_id"` + SettingBackgroundID int `json:"setting_background_id"` } -// ProfileResp ... -type ProfileResp struct { - Result ProfileRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` +type InfoResp struct { + Result InfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` } diff --git a/internal/schema/api/profile/livecnt.go b/internal/schema/api/profile/livecnt.go new file mode 100644 index 0000000..8c35e0b --- /dev/null +++ b/internal/schema/api/profile/livecnt.go @@ -0,0 +1,13 @@ +package profile + +type LiveCntData struct { + Difficulty int `json:"difficulty"` + ClearCnt int `json:"clear_cnt"` +} + +type LiveCntResp struct { + Result []LiveCntData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/scenario/status.go b/internal/schema/api/scenario/status.go new file mode 100644 index 0000000..ffff05e --- /dev/null +++ b/internal/schema/api/scenario/status.go @@ -0,0 +1,17 @@ +package scenario + +type StatusList struct { + ScenarioID int `json:"scenario_id"` + Status int `json:"status"` +} + +type StatusData struct { + ScenarioStatusList []StatusList `json:"scenario_status_list"` +} + +type StatusResp struct { + Result StatusData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/subscenario/status.go b/internal/schema/api/subscenario/status.go new file mode 100644 index 0000000..1a5486b --- /dev/null +++ b/internal/schema/api/subscenario/status.go @@ -0,0 +1,18 @@ +package subscenario + +type StatusList struct { + SubscenarioID int `json:"subscenario_id"` + Status int `json:"status"` +} + +type StatusData struct { + SubscenarioStatusList []StatusList `json:"subscenario_status_list"` + UnlockedSubscenarioIds []any `json:"unlocked_subscenario_ids"` +} + +type StatusResp struct { + Result StatusData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/unit/accessoryall.go b/internal/schema/api/unit/accessoryall.go new file mode 100644 index 0000000..1773f94 --- /dev/null +++ b/internal/schema/api/unit/accessoryall.go @@ -0,0 +1,30 @@ +package unit + +type AccessoryList struct { + AccessoryOwningUserID int `json:"accessory_owning_user_id" xorm:"accessory_owning_user_id"` + AccessoryID int `json:"accessory_id" xorm:"accessory_id"` + Exp int `json:"exp" xorm:"exp"` + NextExp int `json:"next_exp" xorm:"-"` + Level int `json:"level" xorm:"-"` + MaxLevel int `json:"max_level" xorm:"-"` + RankUpCount int `json:"rank_up_count" xorm:"-"` + FavoriteFlag bool `json:"favorite_flag" xorm:"-"` +} + +type WearingInfo struct { + UnitOwningUserID int `json:"unit_owning_user_id" xorm:"unit_owning_user_id"` + AccessoryOwningUserID int `json:"accessory_owning_user_id" xorm:"accessory_owning_user_id"` +} + +type AccessoryAllData struct { + AccessoryList []AccessoryList `json:"accessory_list"` + WearingInfo []WearingInfo `json:"wearing_info"` + EspecialCreateFlag bool `json:"especial_create_flag"` +} + +type AccessoryAllResp struct { + Result AccessoryAllData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/unit/all.go b/internal/schema/api/unit/all.go new file mode 100644 index 0000000..2d58003 --- /dev/null +++ b/internal/schema/api/unit/all.go @@ -0,0 +1,75 @@ +package unit + +type Costume struct { + UnitID int `json:"unit_id"` + IsRankMax bool `json:"is_rank_max"` + IsSigned bool `json:"is_signed"` +} + +type Active struct { + UnitOwningUserID int `xorm:"unit_owning_user_id pk autoincr" json:"unit_owning_user_id"` + UserID int `xorm:"user_id" json:"-"` + UnitID int `xorm:"unit_id" json:"unit_id"` + Exp int `xorm:"exp" json:"exp"` + NextExp int `xorm:"next_exp" json:"next_exp"` + Level int `xorm:"level" json:"level"` + MaxLevel int `xorm:"max_level" json:"max_level"` + LevelLimitID int `xorm:"level_limit_id" json:"level_limit_id"` + Rank int `xorm:"rank" json:"rank"` + MaxRank int `xorm:"max_rank" json:"max_rank"` + Love int `xorm:"love" json:"love"` + MaxLove int `xorm:"max_love" json:"max_love"` + UnitSkillExp int `xorm:"unit_skill_exp" json:"unit_skill_exp"` + UnitSkillLevel int `xorm:"unit_skill_level" json:"unit_skill_level"` + MaxHp int `xorm:"max_hp" json:"max_hp"` + UnitRemovableSkillCapacity int `xorm:"unit_removable_skill_capacity" json:"unit_removable_skill_capacity"` + FavoriteFlag bool `xorm:"favorite_flag" json:"favorite_flag"` + DisplayRank int `xorm:"display_rank" json:"display_rank"` + IsRankMax bool `xorm:"is_rank_max" json:"is_rank_max"` + IsLoveMax bool `xorm:"is_love_max" json:"is_love_max"` + IsLevelMax bool `xorm:"is_level_max" json:"is_level_max"` + IsSigned bool `xorm:"is_signed" json:"is_signed"` + IsSkillLevelMax bool `xorm:"is_skill_level_max" json:"is_skill_level_max"` + IsRemovableSkillCapacityMax bool `xorm:"is_removable_skill_capacity_max" json:"is_removable_skill_capacity_max"` + InsertDate string `xorm:"insert_date" json:"insert_date"` + // Costume Costume `json:"costume"` +} + +type Waiting struct { + UnitOwningUserID int64 `json:"unit_owning_user_id"` + UnitID int `json:"unit_id"` + Exp int `json:"exp"` + NextExp int `json:"next_exp"` + Level int `json:"level"` + MaxLevel int `json:"max_level"` + LevelLimitID int `json:"level_limit_id"` + Rank int `json:"rank"` + MaxRank int `json:"max_rank"` + Love int `json:"love"` + MaxLove int `json:"max_love"` + UnitSkillExp int `json:"unit_skill_exp"` + UnitSkillLevel int `json:"unit_skill_level"` + MaxHp int `json:"max_hp"` + UnitRemovableSkillCapacity int `json:"unit_removable_skill_capacity"` + FavoriteFlag bool `json:"favorite_flag"` + DisplayRank int `json:"display_rank"` + IsRankMax bool `json:"is_rank_max"` + IsLoveMax bool `json:"is_love_max"` + IsLevelMax bool `json:"is_level_max"` + IsSigned bool `json:"is_signed"` + IsSkillLevelMax bool `json:"is_skill_level_max"` + IsRemovableSkillCapacityMax bool `json:"is_removable_skill_capacity_max"` + InsertDate string `json:"insert_date"` +} + +type AllData struct { + Active []Active `json:"active"` + Waiting []Waiting `json:"waiting"` +} + +type AllResp struct { + Result AllData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/unit/deckinfo.go b/internal/schema/api/unit/deckinfo.go new file mode 100644 index 0000000..a434b0a --- /dev/null +++ b/internal/schema/api/unit/deckinfo.go @@ -0,0 +1,49 @@ +package unit + +type UserDeckData struct { + ID int `xorm:"id pk autoincr"` + DeckID int `xorm:"deck_id"` + MainFlag int `xorm:"main_flag"` + DeckName string `xorm:"deck_name"` + UserID int `xorm:"user_id"` + InsertDate int64 `xorm:"insert_date"` +} + +type UnitDeckData struct { + ID int `xorm:"id pk autoincr" json:"-"` + UserDeckID int `xorm:"user_deck_id" json:"-"` + UnitOwningUserID int `xorm:"unit_owning_user_id" json:"unit_owning_user_id"` + UnitID int `xorm:"unit_id" json:"unit_id"` + Position int `xorm:"position" json:"position"` + Level int `xorm:"level" json:"level"` + LevelLimitID int `xorm:"level_limit_id" json:"level_limit_id"` + DisplayRank int `xorm:"display_rank" json:"display_rank"` + Love int `xorm:"love" json:"love"` + UnitSkillLevel int `xorm:"unit_skill_level" json:"unit_skill_level"` + IsRankMax bool `xorm:"is_rank_max" json:"is_rank_max"` + IsLoveMax bool `xorm:"is_love_max" json:"is_love_max"` + IsLevelMax bool `xorm:"is_level_max" json:"is_level_max"` + IsSigned bool `xorm:"is_signed" json:"is_signed"` + BeforeLove int `xorm:"before_love" json:"before_love"` + MaxLove int `xorm:"max_love" json:"max_love"` + InsertData int64 `xorm:"insert_date" json:"-"` +} + +type UnitOwningUserIds struct { + Position int `json:"position"` + UnitOwningUserID int `json:"unit_owning_user_id"` +} + +type DeckInfoData struct { + UnitDeckID int `json:"unit_deck_id"` + MainFlag bool `json:"main_flag"` + DeckName string `json:"deck_name"` + UnitOwningUserIds []UnitOwningUserIds `json:"unit_owning_user_ids"` +} + +type DeckInfoResp struct { + Result []DeckInfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/unit/removableskillinfo.go b/internal/schema/api/unit/removableskillinfo.go new file mode 100644 index 0000000..8ed7891 --- /dev/null +++ b/internal/schema/api/unit/removableskillinfo.go @@ -0,0 +1,41 @@ +package unit + +type SkillEquipCount struct { + UnitRemovableSkillId int `xorm:"unit_removable_skill_id"` + Count int `xorm:"ct"` +} + +type SkillEquipData struct { + Id int `xorm:"id pk autoincr"` + UnitRemovableSkillId int `xorm:"unit_removable_skill_id"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UserId string `xorm:"user_id"` +} + +type SkillEquipDetail struct { + UnitRemovableSkillID int `json:"unit_removable_skill_id" xorm:"unit_removable_skill_id"` +} + +type SkillEquipList struct { + UnitOwningUserID int `json:"unit_owning_user_id"` + Detail []SkillEquipDetail `json:"detail"` +} + +type OwningInfo struct { + UnitRemovableSkillID int `json:"unit_removable_skill_id"` + TotalAmount int `json:"total_amount"` + EquippedAmount int `json:"equipped_amount"` + InsertDate string `json:"insert_date"` +} + +type RemovableSkillInfoData struct { + OwningInfo []OwningInfo `json:"owning_info"` + EquipmentInfo map[int]any `json:"equipment_info"` +} + +type RemovableSkillInfoResp struct { + Result RemovableSkillInfoData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/unit/supporterall.go b/internal/schema/api/unit/supporterall.go new file mode 100644 index 0000000..40947a5 --- /dev/null +++ b/internal/schema/api/unit/supporterall.go @@ -0,0 +1,17 @@ +package unit + +type SupporterList struct { + UnitID int `json:"unit_id"` + Amount int `json:"amount"` +} + +type SupporterAllData struct { + UnitSupportList []SupporterList `json:"unit_support_list"` +} + +type SupporterAllResp struct { + Result SupporterAllData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/schema/api/user/getnavi.go b/internal/schema/api/user/getnavi.go new file mode 100644 index 0000000..73f3b06 --- /dev/null +++ b/internal/schema/api/user/getnavi.go @@ -0,0 +1,17 @@ +package user + +type User struct { + UserID int `json:"user_id"` + UnitOwningUserID int `json:"unit_owning_user_id"` +} + +type GetNaviData struct { + User User `json:"user"` +} + +type GetNaviResp struct { + Result GetNaviData `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` +} diff --git a/internal/model/userinfo.go b/internal/schema/api/user/info.go similarity index 79% rename from internal/model/userinfo.go rename to internal/schema/api/user/info.go index 1600e1a..ee85867 100644 --- a/internal/model/userinfo.go +++ b/internal/schema/api/user/info.go @@ -1,26 +1,10 @@ -package model +package user -// UserInfoResp ... -type UserInfoResp struct { - ResponseData UserInfoRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// UserInfoRes ... -type UserInfoRes struct { - User UserInfo `json:"user"` - Birth Birth `json:"birth"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// LpRecoveryItem ... type LpRecoveryItem struct { ItemID int `json:"item_id"` Amount int `json:"amount"` } -// UserInfo ... type UserInfo struct { UserID int `json:"user_id"` Name string `json:"name"` @@ -52,8 +36,9 @@ type UserInfo struct { LpRecoveryItem []LpRecoveryItem `json:"lp_recovery_item"` } -// Birth ... -type Birth struct { - BirthMonth int `json:"birth_month"` - BirthDay int `json:"birth_day"` +type InfoResp struct { + Result UserInfo `json:"result"` + Status int `json:"status"` + CommandNum bool `json:"commandNum"` + TimeStamp int64 `json:"timeStamp"` } diff --git a/internal/model/profile.go b/internal/schema/award/set.go similarity index 65% rename from internal/model/profile.go rename to internal/schema/award/set.go index 648ca81..f70b6e8 100644 --- a/internal/model/profile.go +++ b/internal/schema/award/set.go @@ -1,7 +1,6 @@ -package model +package award -// AwardSetResp ... -type ProfileRegisterResp struct { +type SetResp struct { ResponseData []any `json:"response_data"` ReleaseInfo []any `json:"release_info"` StatusCode int `json:"status_code"` diff --git a/internal/schema/background/set.go b/internal/schema/background/set.go new file mode 100644 index 0000000..9b4be09 --- /dev/null +++ b/internal/schema/background/set.go @@ -0,0 +1,7 @@ +package background + +type SetResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/download/additional.go b/internal/schema/download/additional.go new file mode 100644 index 0000000..4fe32f9 --- /dev/null +++ b/internal/schema/download/additional.go @@ -0,0 +1,23 @@ +package download + +type AdditionalReq struct { + Module string `json:"module"` + Mgd int `json:"mgd"` + Action string `json:"action"` + TimeStamp int `json:"timeStamp"` + PackageID int `json:"package_id"` + TargetOs string `json:"target_os"` + PackageType int `json:"package_type"` + CommandNum string `json:"commandNum"` +} + +type AdditionalData struct { + Size int `json:"size"` + URL string `json:"url"` +} + +type AdditionalResp struct { + ResponseData []AdditionalData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/download/batch.go b/internal/schema/download/batch.go new file mode 100644 index 0000000..ea440cf --- /dev/null +++ b/internal/schema/download/batch.go @@ -0,0 +1,20 @@ +package download + +type BatchReq struct { + ClientVersion string `json:"client_version"` + Os string `json:"os"` + PackageType int `json:"package_type"` + ExcludedPackageIds []int `json:"excluded_package_ids"` + CommandNum string `json:"commandNum"` +} + +type BatchData struct { + Size int `json:"size"` + URL string `json:"url"` +} + +type BatchResp struct { + ResponseData []BatchData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/download/event.go b/internal/schema/download/event.go new file mode 100644 index 0000000..e8fb6c7 --- /dev/null +++ b/internal/schema/download/event.go @@ -0,0 +1,7 @@ +package download + +type EventResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/download/update.go b/internal/schema/download/update.go new file mode 100644 index 0000000..8e9b61c --- /dev/null +++ b/internal/schema/download/update.go @@ -0,0 +1,24 @@ +package download + +type UpdateReq struct { + Module string `json:"module"` + TargetOs string `json:"target_os"` + InstallVersion string `json:"install_version"` + TimeStamp int `json:"timeStamp"` + Action string `json:"action"` + PackageList []any `json:"package_list"` + CommandNum string `json:"commandNum"` + ExternalVersion string `json:"external_version"` +} + +type UpdateData struct { + Size int `json:"size"` + URL string `json:"url"` + Version string `json:"version"` +} + +type UpdateResp struct { + ResponseData []UpdateData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/download/url.go b/internal/schema/download/url.go new file mode 100644 index 0000000..120515c --- /dev/null +++ b/internal/schema/download/url.go @@ -0,0 +1,19 @@ +package download + +type UrlReq struct { + Module string `json:"module"` + Os string `json:"os"` + Mgd int `json:"mgd"` + PathList []string `json:"path_list"` + Action string `json:"action"` +} + +type UrlData struct { + UrlList []string `json:"url_list"` +} + +type UrlResp struct { + ResponseData UrlData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/event/list.go b/internal/schema/event/list.go new file mode 100644 index 0000000..634bc58 --- /dev/null +++ b/internal/schema/event/list.go @@ -0,0 +1,17 @@ +package event + +type TargetList struct { + Position int `json:"position"` + IsDisplayable bool `json:"is_displayable"` +} + +type ListData struct { + TargetList []TargetList `json:"target_list"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type ListResp struct { + ResponseData any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/model/gdpr.go b/internal/schema/gdpr/get.go similarity index 62% rename from internal/model/gdpr.go rename to internal/schema/gdpr/get.go index aba4095..08096a4 100644 --- a/internal/model/gdpr.go +++ b/internal/schema/gdpr/get.go @@ -1,15 +1,13 @@ -package model +package gdpr -// GdprResp ... -type GdprResp struct { - ResponseData GdprRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// GdprRes ... -type GdprRes struct { +type GetData struct { EnableGdpr bool `json:"enable_gdpr"` IsEea bool `json:"is_eea"` ServerTimestamp int64 `json:"server_timestamp"` } + +type GetResp struct { + ResponseData GetData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/ghome/account.go b/internal/schema/ghome/account.go new file mode 100644 index 0000000..994b1b2 --- /dev/null +++ b/internal/schema/ghome/account.go @@ -0,0 +1,104 @@ +package ghome + +type ActiveData struct { + Message string `json:"message"` + Result int `json:"result"` +} + +type ActiveResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data ActiveData `json:"data"` +} + +type InitializeData struct { + BrandLogo string `json:"brand_logo"` + BrandName string `json:"brand_name"` + DaoyuClientid string `json:"daoyu_clientid"` + DaoyuDownloadURL string `json:"daoyu_download_url"` + DeviceFeature string `json:"device_feature"` + DisplayThirdaccout int `json:"display_thirdaccout"` + ForceShowAgreement int `json:"force_show_agreement"` + GreportLogLevel string `json:"greport_log_level"` + GuestEnable int `json:"guest_enable"` + IsMatch int `json:"is_match"` + LogLevel string `json:"log_level"` + LoginButton []string `json:"login_button"` + LoginIcon []any `json:"login_icon"` + LoginLimitEnable int `json:"login_limit_enable"` + NeedFloatWindowPermission int `json:"need_float_window_permission"` + NewDeviceIDServer string `json:"new_device_id_server"` + QqAppID string `json:"qq_appId"` + QqKey string `json:"qq_key"` + ShowGuestConfirm int `json:"show_guest_confirm"` + VoicetipButton int `json:"voicetip_button"` + VoicetipOne string `json:"voicetip_one"` + VoicetipTwo string `json:"voicetip_two"` + WegameAppid string `json:"wegame_appid"` + WegameAppkey string `json:"wegame_appkey"` + WegameClientid string `json:"wegame_clientid"` + WegameCompanyID string `json:"wegame_companyId"` + WegameLoginURL string `json:"wegame_loginUrl"` + WeiboAppKey string `json:"weibo_appKey"` + WeiboRedirectURL string `json:"weibo_redirectUrl"` + WeixinAppID string `json:"weixin_appId"` + WeixinKey string `json:"weixin_key"` +} + +type InitializeResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data string `json:"data"` +} + +type LoginData struct { + Activation int `json:"activation"` + Autokey string `json:"autokey"` + CaptchaParams string `json:"captchaParams"` + CheckCodeGUID string `json:"checkCodeGuid"` + CheckCodeURL string `json:"checkCodeUrl"` + HasExtendAccs int `json:"hasExtendAccs"` + HasRealInfo int `json:"has_realInfo"` + ImagecodeType int `json:"imagecodeType"` + IsNewUser int `json:"isNewUser"` + Message string `json:"message"` + NextAction int `json:"nextAction"` + PromptMsg string `json:"prompt_msg"` + RealInfoNotification string `json:"realInfoNotification"` + RealInfoForce int `json:"realInfo_force"` + RealInfoForcePay int `json:"realInfo_force_pay"` + RealInfoStatus int `json:"realInfo_status"` + RealInfoStatusPay int `json:"realInfo_status_pay"` + Result int `json:"result"` + SdgHeight int `json:"sdg_height"` + SdgWidth int `json:"sdg_width"` + Ticket string `json:"ticket"` + UserAttribute string `json:"userAttribute"` + UserID int `json:"userid"` +} + +type LoginResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data string `json:"data"` +} + +type LoginAutoData struct { + Result int `json:"result"` + Message string `json:"message"` + Autokey string `json:"autokey,omitempty"` + UserId string `json:"userid,omitempty"` + Ticket string `json:"ticket,omitempty"` +} + +type LoginAutoResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data string `json:"data"` +} + +type ReportRoleResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data string `json:"data"` +} diff --git a/internal/schema/ghome/basic.go b/internal/schema/ghome/basic.go new file mode 100644 index 0000000..5a63354 --- /dev/null +++ b/internal/schema/ghome/basic.go @@ -0,0 +1,47 @@ +package ghome + +type GetCodeResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data map[string]any `json:"data"` +} + +type GetProductListResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data GetProductListData `json:"data"` +} + +type GetProductListData struct { + Message []string `json:"message"` + Result int `json:"result"` +} + +type HandshakeResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data string `json:"data"` +} + +type LoginAreaData struct { + UserID string `json:"userid"` +} + +type LoginAreaResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data LoginAreaData `json:"data"` +} + +type PublicKeyData struct { + Result int `json:"result"` + Message string `json:"message"` + Key string `json:"key,omitempty"` + Method string `json:"method,omitempty"` +} + +type PublicKeyResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data PublicKeyData `json:"data"` +} diff --git a/internal/schema/ghome/guest.go b/internal/schema/ghome/guest.go new file mode 100644 index 0000000..718d3ec --- /dev/null +++ b/internal/schema/ghome/guest.go @@ -0,0 +1,14 @@ +package ghome + +type GuestStatusData struct { + Disablead int `json:"disablead"` + Loginswitch int `json:"loginswitch"` + Message string `json:"message"` + Result int `json:"result"` +} + +type GuestStatusResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data GuestStatusData `json:"data"` +} diff --git a/internal/schema/ghome/misc.go b/internal/schema/ghome/misc.go new file mode 100644 index 0000000..bfd6093 --- /dev/null +++ b/internal/schema/ghome/misc.go @@ -0,0 +1,21 @@ +package ghome + +type AgreementData struct { +} + +type AgreementResp struct { + ReturnCode int `json:"return_code"` + ErrorType int `json:"error_type"` + ReturnMessage string `json:"return_message"` + Data AgreementData `json:"data"` +} + +type AppReportData struct { + NeedReport int `json:"needReport"` +} + +type AppReportResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data AppReportData `json:"data"` +} diff --git a/internal/schema/lbonus/execute.go b/internal/schema/lbonus/execute.go new file mode 100644 index 0000000..2a54da3 --- /dev/null +++ b/internal/schema/lbonus/execute.go @@ -0,0 +1,103 @@ +package lbonus + +type Item struct { + ItemID int `json:"item_id"` + AddType int `json:"add_type"` + Amount int `json:"amount"` +} + +type Day struct { + Day int `json:"day"` + DayOfTheWeek int `json:"day_of_the_week"` + SpecialDay bool `json:"special_day"` + SpecialImageAsset string `json:"special_image_asset"` + Received bool `json:"received"` + AdReceived bool `json:"ad_received"` + Item Item `json:"item"` +} + +type Month struct { + Year int `json:"year"` + Month int `json:"month"` + Days []Day `json:"days"` +} + +type CalendarInfo struct { + CurrentDate string `json:"current_date"` + CurrentMonth Month `json:"current_month"` + NextMonth Month `json:"next_month"` +} + +type Reward struct { + ItemID int `json:"item_id"` + AddType int `json:"add_type"` + Amount int `json:"amount"` +} + +type TotalLoginInfo struct { + LoginCount int `json:"login_count"` + RemainingCount int `json:"remaining_count"` + Reward []Reward `json:"reward"` +} + +type RankInfo struct { + BeforeClassRankID int `json:"before_class_rank_id"` + AfterClassRankID int `json:"after_class_rank_id"` + RankUpDate string `json:"rank_up_date"` +} + +type ClassSystem struct { + RankInfo RankInfo `json:"rank_info"` + CompleteFlag bool `json:"complete_flag"` + IsOpened bool `json:"is_opened"` + IsVisible bool `json:"is_visible"` +} + +type Rewards struct { + Rarity int `json:"rarity"` + ItemID int `json:"item_id"` + AddType int `json:"add_type"` + Amount int `json:"amount"` + ItemCategoryID int `json:"item_category_id"` + RewardBoxFlag bool `json:"reward_box_flag"` + InsertDate string `json:"insert_date"` +} + +type EffortPoint struct { + LiveEffortPointBoxSpecID int `json:"live_effort_point_box_spec_id"` + Capacity int `json:"capacity"` + Before int `json:"before"` + After int `json:"after"` + Rewards []Rewards `json:"rewards"` +} + +type Parameter struct { + Smile int `json:"smile"` + Pure int `json:"pure"` + Cool int `json:"cool"` +} + +type Museum struct { + Parameter Parameter `json:"parameter"` + ContentsIDList []int `json:"contents_id_list"` +} + +type ExecuteData struct { + Sheets []any `json:"sheets"` + CalendarInfo CalendarInfo `json:"calendar_info"` + TotalLoginInfo TotalLoginInfo `json:"total_login_info"` + LicenseLbonusList []any `json:"license_lbonus_list"` + ClassSystem ClassSystem `json:"class_system"` + StartDashSheets []any `json:"start_dash_sheets"` + EffortPoint []EffortPoint `json:"effort_point"` + LimitedEffortBox []any `json:"limited_effort_box"` + MuseumInfo Museum `json:"museum_info"` + ServerTimestamp int64 `json:"server_timestamp"` + PresentCnt int `json:"present_cnt"` +} + +type ExecuteResp struct { + ResponseData ExecuteData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/live/gameover.go b/internal/schema/live/gameover.go new file mode 100644 index 0000000..b5efd81 --- /dev/null +++ b/internal/schema/live/gameover.go @@ -0,0 +1,7 @@ +package live + +type GameOverResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/live/play.go b/internal/schema/live/play.go new file mode 100644 index 0000000..dac4b14 --- /dev/null +++ b/internal/schema/live/play.go @@ -0,0 +1,84 @@ +package live + +type PlayReq struct { + Module string `json:"module"` + PartyUserID int64 `json:"party_user_id"` + Action string `json:"action"` + Mgd int `json:"mgd"` + IsTraining bool `json:"is_training"` + UnitDeckID int `json:"unit_deck_id"` + LiveDifficultyID string `json:"live_difficulty_id"` + TimeStamp int `json:"timeStamp"` + LpFactor int `json:"lp_factor"` + CommandNum string `json:"commandNum"` +} + +type RankInfo struct { + Rank int `json:"rank"` + RankMin int `json:"rank_min"` + RankMax int `json:"rank_max"` +} + +type NotesList struct { + TimingSec float64 `json:"timing_sec"` + NotesAttribute int `json:"notes_attribute"` + NotesLevel int `json:"notes_level"` + Effect int `json:"effect"` + EffectValue float64 `json:"effect_value"` + Position int `json:"position"` +} + +type LiveInfo struct { + LiveDifficultyID int `json:"live_difficulty_id"` + IsRandom bool `json:"is_random"` + AcFlag int `json:"ac_flag"` + SwingFlag int `json:"swing_flag"` + NotesList []NotesList `json:"notes_list"` +} + +type Costume struct { + UnitID int `json:"unit_id"` + IsRankMax bool `json:"is_rank_max"` + IsSigned bool `json:"is_signed"` +} + +type UnitList struct { + Smile int `json:"smile"` + Cute int `json:"cute"` + Cool int `json:"cool"` + // Costume Costume `json:"costume"` +} + +type DeckInfo struct { + UnitDeckID int `json:"unit_deck_id"` + TotalSmile int `json:"total_smile"` + TotalCute int `json:"total_cute"` + TotalCool int `json:"total_cool"` + TotalHp int `json:"total_hp"` + PreparedHpDamage int `json:"prepared_hp_damage"` + UnitList []UnitList `json:"unit_list"` +} + +type PlayLiveList struct { + LiveInfo LiveInfo `json:"live_info"` + DeckInfo DeckInfo `json:"deck_info"` +} + +type PlayData struct { + RankInfo []RankInfo `json:"rank_info"` + EnergyFullTime string `json:"energy_full_time"` + OverMaxEnergy int `json:"over_max_energy"` + AvailableLiveResume bool `json:"available_live_resume"` + LiveList []PlayLiveList `json:"live_list"` + IsMarathonEvent bool `json:"is_marathon_event"` + MarathonEventID any `json:"marathon_event_id"` + NoSkill bool `json:"no_skill"` + CanActivateEffect bool `json:"can_activate_effect"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type PlayResp struct { + ResponseData PlayData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/live/precisescore.go b/internal/schema/live/precisescore.go new file mode 100644 index 0000000..b24e70b --- /dev/null +++ b/internal/schema/live/precisescore.go @@ -0,0 +1,48 @@ +package live + +type PlayScoreReq struct { + Module string `json:"module"` + Action string `json:"action"` + TimeStamp int64 `json:"timeStamp"` + Mgd int `json:"mgd"` + LiveDifficultyID string `json:"live_difficulty_id"` + CommandNum string `json:"commandNum"` +} + +type On struct { + HasRecord bool `json:"has_record"` + LiveInfo LiveInfo `json:"live_info"` + RandomSeed any `json:"random_seed"` + MaxCombo any `json:"max_combo"` + UpdateDate any `json:"update_date"` + PreciseList any `json:"precise_list"` + DeckInfo any `json:"deck_info"` + TapAdjust any `json:"tap_adjust"` + CanReplay bool `json:"can_replay"` +} + +type Off struct { + HasRecord bool `json:"has_record"` + LiveInfo LiveInfo `json:"live_info"` + RandomSeed any `json:"random_seed"` + MaxCombo any `json:"max_combo"` + UpdateDate any `json:"update_date"` + PreciseList any `json:"precise_list"` + DeckInfo any `json:"deck_info"` + TapAdjust any `json:"tap_adjust"` + CanReplay bool `json:"can_replay"` +} + +type PreciseScoreData struct { + On On `json:"on"` + Off Off `json:"off"` + RankInfo []RankInfo `json:"rank_info"` + CanActivateEffect bool `json:"can_activate_effect"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type PreciseScoreResp struct { + ResponseData PreciseScoreData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/model/live.go b/internal/schema/live/reward.go similarity index 61% rename from internal/model/live.go rename to internal/schema/live/reward.go index 1f06270..bece48f 100644 --- a/internal/model/live.go +++ b/internal/schema/live/reward.go @@ -1,257 +1,6 @@ -package model +package live -// GameOverResp ... -type GameOverResp struct { - ResponseData []any `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// NormalLiveStatusList ... -type NormalLiveStatusList struct { - LiveDifficultyID int `json:"live_difficulty_id"` - Status int `json:"status"` - HiScore int `json:"hi_score"` - HiComboCount int `json:"hi_combo_count"` - ClearCnt int `json:"clear_cnt"` - AchievedGoalIDList []int `json:"achieved_goal_id_list"` -} - -// SpecialLiveStatusList ... -type SpecialLiveStatusList struct { - LiveDifficultyID int `json:"live_difficulty_id"` - Status int `json:"status"` - HiScore int `json:"hi_score"` - HiComboCount int `json:"hi_combo_count"` - ClearCnt int `json:"clear_cnt"` - AchievedGoalIDList []int `json:"achieved_goal_id_list"` -} - -// TrainingLiveStatusList ... -type TrainingLiveStatusList struct { - LiveDifficultyID int `json:"live_difficulty_id"` - Status int `json:"status"` - HiScore int `json:"hi_score"` - HiComboCount int `json:"hi_combo_count"` - ClearCnt int `json:"clear_cnt"` - AchievedGoalIDList []int `json:"achieved_goal_id_list"` -} - -// LiveStatusRes ... -type LiveStatusRes struct { - NormalLiveStatusList []NormalLiveStatusList `json:"normal_live_status_list"` - SpecialLiveStatusList []SpecialLiveStatusList `json:"special_live_status_list"` - TrainingLiveStatusList []TrainingLiveStatusList `json:"training_live_status_list"` - MarathonLiveStatusList []any `json:"marathon_live_status_list"` - FreeLiveStatusList []any `json:"free_live_status_list"` - CanResumeLive bool `json:"can_resume_live"` -} - -// LiveStatusResp ... -type LiveStatusResp struct { - Result LiveStatusRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// LiveList ... -type LiveList struct { - LiveDifficultyID int `json:"live_difficulty_id"` - StartDate string `json:"start_date"` - EndDate string `json:"end_date"` - IsRandom bool `json:"is_random"` -} - -// LimitedBonusCommonList ... -type LimitedBonusCommonList struct { - LiveType int `json:"live_type"` - LimitedBonusType int `json:"limited_bonus_type"` - LimitedBonusValue int `json:"limited_bonus_value"` - StartDate string `json:"start_date"` - EndDate string `json:"end_date"` -} - -// RandomLiveList ... -type RandomLiveList struct { - AttributeID int `json:"attribute_id"` - StartDate string `json:"start_date"` - EndDate string `json:"end_date"` -} - -// TrainingLiveList ... -type TrainingLiveList struct { - LiveDifficultyID int `json:"live_difficulty_id"` - StartDate string `json:"start_date"` - IsRandom bool `json:"is_random"` -} - -// LiveScheduleRes ... -type LiveScheduleRes struct { - EventList []any `json:"event_list"` - LiveList []LiveList `json:"live_list"` - LimitedBonusList []any `json:"limited_bonus_list"` - LimitedBonusCommonList []LimitedBonusCommonList `json:"limited_bonus_common_list"` - RandomLiveList []RandomLiveList `json:"random_live_list"` - FreeLiveList []any `json:"free_live_list"` - TrainingLiveList []TrainingLiveList `json:"training_live_list"` -} - -// LiveScheduleResp ... -type LiveScheduleResp struct { - Result LiveScheduleRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// PlayReq ... -type PlayReq struct { - Module string `json:"module"` - PartyUserID int64 `json:"party_user_id"` - Action string `json:"action"` - Mgd int `json:"mgd"` - IsTraining bool `json:"is_training"` - UnitDeckID int `json:"unit_deck_id"` - LiveDifficultyID string `json:"live_difficulty_id"` - TimeStamp int `json:"timeStamp"` - LpFactor int `json:"lp_factor"` - CommandNum string `json:"commandNum"` -} - -// RankInfo ... -type RankInfo struct { - Rank int `json:"rank"` - RankMin int `json:"rank_min"` - RankMax int `json:"rank_max"` -} - -// NotesList ... -type NotesList struct { - TimingSec float64 `json:"timing_sec"` - NotesAttribute int `json:"notes_attribute"` - NotesLevel int `json:"notes_level"` - Effect int `json:"effect"` - EffectValue float64 `json:"effect_value"` - Position int `json:"position"` -} - -// LiveInfo ... -type LiveInfo struct { - LiveDifficultyID int `json:"live_difficulty_id"` - IsRandom bool `json:"is_random"` - AcFlag int `json:"ac_flag"` - SwingFlag int `json:"swing_flag"` - NotesList []NotesList `json:"notes_list"` -} - -// PlayCostume ... -type PlayCostume struct { - UnitID int `json:"unit_id"` - IsRankMax bool `json:"is_rank_max"` - IsSigned bool `json:"is_signed"` -} - -// UnitList ... -type UnitList struct { - Smile int `json:"smile"` - Cute int `json:"cute"` - Cool int `json:"cool"` - Costume PlayCostume `json:"costume,omitempty"` -} - -// DeckInfo ... -type DeckInfo struct { - UnitDeckID int `json:"unit_deck_id"` - TotalSmile int `json:"total_smile"` - TotalCute int `json:"total_cute"` - TotalCool int `json:"total_cool"` - TotalHp int `json:"total_hp"` - PreparedHpDamage int `json:"prepared_hp_damage"` - UnitList []UnitList `json:"unit_list"` -} - -// PlayLiveList ... -type PlayLiveList struct { - LiveInfo LiveInfo `json:"live_info"` - DeckInfo DeckInfo `json:"deck_info"` -} - -// PlayRes ... -type PlayRes struct { - RankInfo []RankInfo `json:"rank_info"` - EnergyFullTime string `json:"energy_full_time"` - OverMaxEnergy int `json:"over_max_energy"` - AvailableLiveResume bool `json:"available_live_resume"` - LiveList []PlayLiveList `json:"live_list"` - IsMarathonEvent bool `json:"is_marathon_event"` - MarathonEventID any `json:"marathon_event_id"` - NoSkill bool `json:"no_skill"` - CanActivateEffect bool `json:"can_activate_effect"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// PlayResp ... -type PlayResp struct { - ResponseData PlayRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// PlayScoreReq ... -type PlayScoreReq struct { - Module string `json:"module"` - Action string `json:"action"` - TimeStamp int64 `json:"timeStamp"` - Mgd int `json:"mgd"` - LiveDifficultyID string `json:"live_difficulty_id"` - CommandNum string `json:"commandNum"` -} - -// On ... -type On struct { - HasRecord bool `json:"has_record"` - LiveInfo LiveInfo `json:"live_info"` - RandomSeed any `json:"random_seed"` - MaxCombo any `json:"max_combo"` - UpdateDate any `json:"update_date"` - PreciseList any `json:"precise_list"` - DeckInfo any `json:"deck_info"` - TapAdjust any `json:"tap_adjust"` - CanReplay bool `json:"can_replay"` -} - -// Off ... -type Off struct { - HasRecord bool `json:"has_record"` - LiveInfo LiveInfo `json:"live_info"` - RandomSeed any `json:"random_seed"` - MaxCombo any `json:"max_combo"` - UpdateDate any `json:"update_date"` - PreciseList any `json:"precise_list"` - DeckInfo any `json:"deck_info"` - TapAdjust any `json:"tap_adjust"` - CanReplay bool `json:"can_replay"` -} - -// PlayScoreRes ... -type PlayScoreRes struct { - On On `json:"on"` - Off Off `json:"off"` - RankInfo []RankInfo `json:"rank_info"` - CanActivateEffect bool `json:"can_activate_effect"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// PlayScoreResp ... -type PlayScoreResp struct { - ResponseData PlayScoreRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// PlayRewardReq ... -type PlayRewardReq struct { +type RewardReq struct { Module string `json:"module"` Action string `json:"action"` GoodCnt int `json:"good_cnt"` @@ -275,14 +24,12 @@ type PlayRewardReq struct { ScoreCool int `json:"score_cool"` } -// Icon ... type Icon struct { SlideID int `json:"slide_id"` JustID int `json:"just_id"` NormalID int `json:"normal_id"` } -// LiveSetting ... type LiveSetting struct { StringSize int `json:"string_size"` PreciseScoreAutoUpdateFlag bool `json:"precise_score_auto_update_flag"` @@ -296,7 +43,6 @@ type LiveSetting struct { CutinType int `json:"cutin_type"` } -// PreciseList ... type PreciseList struct { Effect int `json:"effect"` Count int `json:"count"` @@ -307,20 +53,17 @@ type PreciseList struct { IsSame bool `json:"is_same"` } -// BackgroundScore ... type BackgroundScore struct { Smile int `json:"smile"` Cute int `json:"cute"` Cool int `json:"cool"` } -// TriggerLog ... type TriggerLog struct { ActivationRate int `json:"activation_rate"` Position int `json:"position"` } -// PreciseScoreLog ... type PreciseScoreLog struct { LiveSetting LiveSetting `json:"live_setting"` TapAdjust int `json:"tap_adjust"` @@ -333,7 +76,6 @@ type PreciseScoreLog struct { RandomSeed int `json:"random_seed"` } -// RewardLiveInfo ... type RewardLiveInfo struct { LiveDifficultyID int `json:"live_difficulty_id"` IsRandom bool `json:"is_random"` @@ -341,25 +83,21 @@ type RewardLiveInfo struct { SwingFlag int `json:"swing_flag"` } -// PlayerExpUnitMax ... type PlayerExpUnitMax struct { Before int `json:"before"` After int `json:"after"` } -// PlayerExpFriendMax ... type PlayerExpFriendMax struct { Before int `json:"before"` After int `json:"after"` } -// PlayerExpLpMax ... type PlayerExpLpMax struct { Before int `json:"before"` After int `json:"after"` } -// BaseRewardInfo ... type BaseRewardInfo struct { PlayerExp int `json:"player_exp"` PlayerExpUnitMax PlayerExpUnitMax `json:"player_exp_unit_max"` @@ -370,7 +108,6 @@ type BaseRewardInfo struct { SocialPoint int `json:"social_point"` } -// LiveClear ... type LiveClear struct { AddType int `json:"add_type"` Amount int `json:"amount"` @@ -399,7 +136,6 @@ type LiveClear struct { RemovableSkillIds []any `json:"removable_skill_ids"` } -// LiveRank ... type LiveRank struct { AddType int `json:"add_type"` Amount int `json:"amount"` @@ -428,14 +164,12 @@ type LiveRank struct { RemovableSkillIds []any `json:"removable_skill_ids"` } -// RewardUnitList ... type RewardUnitList struct { LiveClear []LiveClear `json:"live_clear"` LiveRank []LiveRank `json:"live_rank"` LiveCombo []any `json:"live_combo"` } -// Rewards ... type Rewards struct { Rarity int `json:"rarity"` ItemID int `json:"item_id"` @@ -446,7 +180,6 @@ type Rewards struct { InsertDate string `json:"insert_date"` } -// EffortPoint ... type EffortPoint struct { LiveEffortPointBoxSpecID int `json:"live_effort_point_box_spec_id"` Capacity int `json:"capacity"` @@ -455,7 +188,6 @@ type EffortPoint struct { Rewards []Rewards `json:"rewards"` } -// PlayRewardUnitList ... type PlayRewardUnitList struct { ID int `xorm:"id pk autoincr" json:"-"` UserDeckID int `xorm:"user_deck_id" json:"-"` @@ -476,7 +208,6 @@ type PlayRewardUnitList struct { InsertData int64 `xorm:"insert_date" json:"-"` } -// BeforeUserInfo ... type BeforeUserInfo struct { Level int `json:"level"` Exp int `json:"exp"` @@ -502,7 +233,6 @@ type BeforeUserInfo struct { UnlockRandomLiveAqours int `json:"unlock_random_live_aqours"` } -// AfterUserInfo ... type AfterUserInfo struct { Level int `json:"level"` Exp int `json:"exp"` @@ -528,26 +258,22 @@ type AfterUserInfo struct { UnlockRandomLiveAqours int `json:"unlock_random_live_aqours"` } -// NextLevelInfo ... type NextLevelInfo struct { Level int `json:"level"` FromExp int `json:"from_exp"` } -// GoalAccompInfo ... type GoalAccompInfo struct { AchievedIds []any `json:"achieved_ids"` Rewards []any `json:"rewards"` } -// RewardRankInfo ... type RewardRankInfo struct { BeforeClassRankID int `json:"before_class_rank_id"` AfterClassRankID int `json:"after_class_rank_id"` RankUpDate string `json:"rank_up_date"` } -// ClassSystem ... type ClassSystem struct { RankInfo RewardRankInfo `json:"rank_info"` CompleteFlag bool `json:"complete_flag"` @@ -555,7 +281,6 @@ type ClassSystem struct { IsVisible bool `json:"is_visible"` } -// PlayRewardList ... type PlayRewardList struct { ItemID int `json:"item_id"` AddType int `json:"add_type"` @@ -564,7 +289,6 @@ type PlayRewardList struct { RewardBoxFlag bool `json:"reward_box_flag"` } -// AccomplishedAchievementList ... type AccomplishedAchievementList struct { AchievementID int `json:"achievement_id"` Count int `json:"count"` @@ -580,14 +304,23 @@ type AccomplishedAchievementList struct { RewardList []PlayRewardList `json:"reward_list"` } -// RewardUnitSupportList ... +type Parameter struct { + Smile int `json:"smile"` + Pure int `json:"pure"` + Cool int `json:"cool"` +} + +type Museum struct { + Parameter Parameter `json:"parameter"` + ContentsIDList []int `json:"contents_id_list"` +} + type RewardUnitSupportList struct { UnitID int `json:"unit_id"` Amount int `json:"amount"` } -// RewardRes ... -type RewardRes struct { +type RewardData struct { LiveInfo []RewardLiveInfo `json:"live_info"` Rank int `json:"rank"` ComboRank int `json:"combo_rank"` @@ -621,35 +354,8 @@ type RewardRes struct { PresentCnt int `json:"present_cnt"` } -// RewardResp ... type RewardResp struct { - ResponseData RewardRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// LiveSeInfoRes ... -type LiveSeInfoRes struct { - LiveSeList []int `json:"live_se_list"` -} - -// LiveSeInfoResp ... -type LiveSeInfoResp struct { - Result LiveSeInfoRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` -} - -// LiveIconInfoRes ... -type LiveIconInfoRes struct { - LiveNotesIconList []int `json:"live_notes_icon_list"` -} - -// LiveIconInfoResp ... -type LiveIconInfoResp struct { - Result LiveIconInfoRes `json:"result"` - Status int `json:"status"` - CommandNum bool `json:"commandNum"` - TimeStamp int64 `json:"timeStamp"` + ResponseData RewardData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` } diff --git a/internal/schema/login/authkey.go b/internal/schema/login/authkey.go new file mode 100644 index 0000000..1fb9264 --- /dev/null +++ b/internal/schema/login/authkey.go @@ -0,0 +1,12 @@ +package login + +type AuthKeyData struct { + AuthorizeToken string `json:"authorize_token"` + DummyToken string `json:"dummy_token"` +} + +type AuthKeyResp struct { + ResponseData AuthKeyData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/model/login.go b/internal/schema/login/login.go similarity index 63% rename from internal/model/login.go rename to internal/schema/login/login.go index 074c406..caf39f4 100644 --- a/internal/model/login.go +++ b/internal/schema/login/login.go @@ -1,7 +1,6 @@ -package model +package login -// LoginRes ... -type LoginRes struct { +type LoginData struct { AuthorizeToken string `json:"authorize_token"` UserId int `json:"user_id"` ReviewVersion string `json:"review_version"` @@ -11,9 +10,8 @@ type LoginRes struct { AdultFlag int `json:"adult_flag"` } -// LoginResp ... type LoginResp struct { - ResponseData LoginRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` + ResponseData LoginData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` } diff --git a/internal/schema/multiunit/scenariostartup.go b/internal/schema/multiunit/scenariostartup.go new file mode 100644 index 0000000..ec30c4a --- /dev/null +++ b/internal/schema/multiunit/scenariostartup.go @@ -0,0 +1,22 @@ +package multiunit + +type ScenarioStartUpReq struct { + Module string `json:"module"` + Action string `json:"action"` + TimeStamp int `json:"timeStamp"` + Mgd int `json:"mgd"` + MultiUnitScenarioID int `json:"multi_unit_scenario_id"` + CommandNum string `json:"commandNum"` +} + +type ScenarioStartUpData struct { + MultiUnitScenarioID int `json:"multi_unit_scenario_id"` + ScenarioAdjustment int `json:"scenario_adjustment"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type ScenarioStartUpResp struct { + ResponseData ScenarioStartUpData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/museum/info.go b/internal/schema/museum/info.go new file mode 100644 index 0000000..e170521 --- /dev/null +++ b/internal/schema/museum/info.go @@ -0,0 +1,23 @@ +package museum + +type Parameter struct { + Smile int `json:"smile"` + Pure int `json:"pure"` + Cool int `json:"cool"` +} + +type Museum struct { + Parameter Parameter `json:"parameter"` + ContentsIDList []int `json:"contents_id_list"` +} + +type InfoData struct { + MuseumInfo Museum `json:"museum_info"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type InfoResp struct { + ResponseData InfoData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/notice/friendgreeting.go b/internal/schema/notice/friendgreeting.go new file mode 100644 index 0000000..2bb1972 --- /dev/null +++ b/internal/schema/notice/friendgreeting.go @@ -0,0 +1,13 @@ +package notice + +type FriendGreetingData struct { + NextId int `json:"next_id"` + NoticeList []any `json:"notice_list"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type FriendGreetingResp struct { + ResponseData FriendGreetingData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/notice/friendvariety.go b/internal/schema/notice/friendvariety.go new file mode 100644 index 0000000..ab08a93 --- /dev/null +++ b/internal/schema/notice/friendvariety.go @@ -0,0 +1,13 @@ +package notice + +type FriendVarietyData struct { + ItemCount int `json:"item_count"` + NoticeList []any `json:"notice_list"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type FriendVarietyResp struct { + ResponseData FriendVarietyData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/notice/usergreetinghistory.go b/internal/schema/notice/usergreetinghistory.go new file mode 100644 index 0000000..76620e4 --- /dev/null +++ b/internal/schema/notice/usergreetinghistory.go @@ -0,0 +1,14 @@ +package notice + +type UserGreetingData struct { + ItemCount int `json:"item_count"` + HasNext bool `json:"has_next"` + NoticeList []any `json:"notice_list"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type UserGreetingResp struct { + ResponseData UserGreetingData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/payment/productlist.go b/internal/schema/payment/productlist.go new file mode 100644 index 0000000..97edcce --- /dev/null +++ b/internal/schema/payment/productlist.go @@ -0,0 +1,19 @@ +package payment + +import "honoka-chan/internal/schema/api/payment" + +type ProductListData struct { + RestrictionInfo payment.RestrictionInfo `json:"restriction_info"` + UnderAgeInfo payment.UnderAgeInfo `json:"under_age_info"` + SnsProductList []any `json:"sns_product_list"` + ProductList []any `json:"product_list"` + SubscriptionList []any `json:"subscription_list"` + ShowPointShop bool `json:"show_point_shop"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type ProductListResp struct { + ResponseData ProductListData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/personalnotice/get.go b/internal/schema/personalnotice/get.go new file mode 100644 index 0000000..37c43cd --- /dev/null +++ b/internal/schema/personalnotice/get.go @@ -0,0 +1,16 @@ +package personalnotice + +type GetData struct { + HasNotice bool `json:"has_notice"` + NoticeID int `json:"notice_id"` + Type int `json:"type"` + Title string `json:"title"` + Contents string `json:"contents"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type GetResp struct { + ResponseData GetData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/profile/register.go b/internal/schema/profile/register.go new file mode 100644 index 0000000..8f339f0 --- /dev/null +++ b/internal/schema/profile/register.go @@ -0,0 +1,7 @@ +package profile + +type RegisterResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/scenario/startup.go b/internal/schema/scenario/startup.go new file mode 100644 index 0000000..c99925f --- /dev/null +++ b/internal/schema/scenario/startup.go @@ -0,0 +1,22 @@ +package scenario + +type StartUpReq struct { + Module string `json:"module"` + Action string `json:"action"` + TimeStamp int `json:"timeStamp"` + Mgd int `json:"mgd"` + CommandNum string `json:"commandNum"` + ScenarioID int `json:"scenario_id"` +} + +type StartUpData struct { + ScenarioID int `json:"scenario_id"` + ScenarioAdjustment int `json:"scenario_adjustment"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type StartUpResp struct { + ResponseData StartUpData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/model/subscenario.go b/internal/schema/subscenario/startup.go similarity index 55% rename from internal/model/subscenario.go rename to internal/schema/subscenario/startup.go index da7488d..01eeb8c 100644 --- a/internal/model/subscenario.go +++ b/internal/schema/subscenario/startup.go @@ -1,21 +1,6 @@ -package model +package subscenario -// SubScenarioResp ... -type SubScenarioResp struct { - ResponseData SubScenarioRes `json:"response_data"` - ReleaseInfo []any `json:"release_info"` - StatusCode int `json:"status_code"` -} - -// SubScenarioRes ... -type SubScenarioRes struct { - SubscenarioID int `json:"subscenario_id"` - ScenarioAdjustment int `json:"scenario_adjustment"` - ServerTimestamp int64 `json:"server_timestamp"` -} - -// SubScenarioReq ... -type SubScenarioReq struct { +type StartUpReq struct { Module string `json:"module"` Action string `json:"action"` TimeStamp int `json:"timeStamp"` @@ -23,3 +8,15 @@ type SubScenarioReq struct { Mgd int `json:"mgd"` CommandNum string `json:"commandNum"` } + +type StartUpData struct { + SubscenarioID int `json:"subscenario_id"` + ScenarioAdjustment int `json:"scenario_adjustment"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type StartUpResp struct { + ResponseData StartUpData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/tos/check.go b/internal/schema/tos/check.go new file mode 100644 index 0000000..01bcadf --- /dev/null +++ b/internal/schema/tos/check.go @@ -0,0 +1,14 @@ +package tos + +type CheckData struct { + TosID int `json:"tos_id"` + TosType int `json:"tos_type"` + IsAgreed bool `json:"is_agreed"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type CheckResp struct { + ResponseData CheckData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/unit/deck.go b/internal/schema/unit/deck.go new file mode 100644 index 0000000..3a0e422 --- /dev/null +++ b/internal/schema/unit/deck.go @@ -0,0 +1,26 @@ +package unit + +type UnitDeckDetail struct { + Position int `json:"position"` + UnitOwningUserID int `json:"unit_owning_user_id"` +} + +type UnitDeckList struct { + UnitDeckDetail []UnitDeckDetail `json:"unit_deck_detail"` + UnitDeckID int `json:"unit_deck_id"` + MainFlag int `json:"main_flag"` + DeckName string `json:"deck_name"` +} + +type DeckReq struct { + Module string `json:"module"` + UnitDeckList []UnitDeckList `json:"unit_deck_list"` + Action string `json:"action"` + Mgd int `json:"mgd"` +} + +type DeckResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/unit/deckname.go b/internal/schema/unit/deckname.go new file mode 100644 index 0000000..9e78c53 --- /dev/null +++ b/internal/schema/unit/deckname.go @@ -0,0 +1,11 @@ +package unit + +type DeckNameReq struct { + Module string `json:"module"` + UnitDeckID int `json:"unit_deck_id"` + Action string `json:"action"` + TimeStamp int `json:"timeStamp"` + Mgd int `json:"mgd"` + CommandNum string `json:"commandNum"` + DeckName string `json:"deck_name"` +} diff --git a/internal/schema/unit/favorite.go b/internal/schema/unit/favorite.go new file mode 100644 index 0000000..8af1193 --- /dev/null +++ b/internal/schema/unit/favorite.go @@ -0,0 +1,7 @@ +package unit + +type FavoriteResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/unit/removableskillequipment.go b/internal/schema/unit/removableskillequipment.go new file mode 100644 index 0000000..761319a --- /dev/null +++ b/internal/schema/unit/removableskillequipment.go @@ -0,0 +1,34 @@ +package unit + +type SkillRemove struct { + UnitRemovableSkillID int `json:"unit_removable_skill_id"` + UnitOwningUserID int `json:"unit_owning_user_id"` +} + +type SkillEquip struct { + UnitRemovableSkillID int `json:"unit_removable_skill_id"` + UnitOwningUserID int `json:"unit_owning_user_id"` +} + +type RemovableSkillEquipmentReq struct { + Module string `json:"module"` + Remove []SkillRemove `json:"remove"` + Action string `json:"action"` + TimeStamp int `json:"timeStamp"` + Equip []SkillEquip `json:"equip"` + Mgd int `json:"mgd"` + CommandNum string `json:"commandNum"` +} + +type RemovableSkillEquipmentData struct { + Id int `xorm:"id pk autoincr"` + UnitRemovableSkillId int `xorm:"unit_removable_skill_id"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UserID int `xorm:"user_id"` +} + +type RemovableSkillEquipmentResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/unit/setdisplayrank.go b/internal/schema/unit/setdisplayrank.go new file mode 100644 index 0000000..2c9c542 --- /dev/null +++ b/internal/schema/unit/setdisplayrank.go @@ -0,0 +1,7 @@ +package unit + +type SetDisplayRankResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/unit/wearaccessory.go b/internal/schema/unit/wearaccessory.go new file mode 100644 index 0000000..e12debd --- /dev/null +++ b/internal/schema/unit/wearaccessory.go @@ -0,0 +1,34 @@ +package unit + +type AccessoryRemove struct { + AccessoryOwningUserID int `json:"accessory_owning_user_id"` + UnitOwningUserID int `json:"unit_owning_user_id"` +} + +type AccessoryWear struct { + AccessoryOwningUserID int `json:"accessory_owning_user_id"` + UnitOwningUserID int `json:"unit_owning_user_id"` +} + +type WearAccessoryReq struct { + Module string `json:"module"` + Remove []AccessoryRemove `json:"remove"` + Action string `json:"action"` + TimeStamp int `json:"timeStamp"` + Wear []AccessoryWear `json:"wear"` + Mgd int `json:"mgd"` + CommandNum string `json:"commandNum"` +} + +type WearAccessoryData struct { + Id int `xorm:"id pk autoincr"` + AccessoryOwningUserID int `xorm:"accessory_owning_user_id"` + UnitOwningUserID int `xorm:"unit_owning_user_id"` + UserID int `xorm:"user_id"` +} + +type WearAccessoryResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/user/changename.go b/internal/schema/user/changename.go new file mode 100644 index 0000000..0c3f5e5 --- /dev/null +++ b/internal/schema/user/changename.go @@ -0,0 +1,13 @@ +package user + +type ChangeNameData struct { + BeforeName string `json:"before_name"` + AfterName string `json:"after_name"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type ChangeNameResp struct { + ResponseData ChangeNameData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/user/changenavi.go b/internal/schema/user/changenavi.go new file mode 100644 index 0000000..58259da --- /dev/null +++ b/internal/schema/user/changenavi.go @@ -0,0 +1,7 @@ +package user + +type ChangeNaviResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/user/setnotificationtoken.go b/internal/schema/user/setnotificationtoken.go new file mode 100644 index 0000000..c390276 --- /dev/null +++ b/internal/schema/user/setnotificationtoken.go @@ -0,0 +1,7 @@ +package user + +type SetNotificationTokenResp struct { + ResponseData []any `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/schema/user/userinfo.go b/internal/schema/user/userinfo.go new file mode 100644 index 0000000..fb1fa10 --- /dev/null +++ b/internal/schema/user/userinfo.go @@ -0,0 +1,20 @@ +package user + +import "honoka-chan/internal/schema/api/user" + +type Birth struct { + BirthMonth int `json:"birth_month"` + BirthDay int `json:"birth_day"` +} + +type UserInfoData struct { + User user.UserInfo `json:"user"` + Birth Birth `json:"birth"` + ServerTimestamp int64 `json:"server_timestamp"` +} + +type UserInfoResp struct { + ResponseData UserInfoData `json:"response_data"` + ReleaseInfo []any `json:"release_info"` + StatusCode int `json:"status_code"` +} diff --git a/internal/model/webui.go b/internal/schema/webui/webui.go similarity index 82% rename from internal/model/webui.go rename to internal/schema/webui/webui.go index fd2bc09..cea8d63 100644 --- a/internal/model/webui.go +++ b/internal/schema/webui/webui.go @@ -1,6 +1,5 @@ -package model +package webui -// Msg ... type Msg struct { Code int `json:"code"` Message string `json:"message"` diff --git a/internal/session/session.go b/internal/session/session.go index 57de59f..e69a39e 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -2,17 +2,24 @@ package session import ( "encoding/json" + "errors" + "honoka-chan/internal/model/user" "honoka-chan/internal/utils" "honoka-chan/pkg/db" + "log" "github.com/gin-gonic/gin" "xorm.io/xorm" ) type Session struct { - Ctx *gin.Context + Ctx *gin.Context + MainEng *xorm.Session UserEng *xorm.Session + + UserID int + UserPref user.UserPref } func New(ctx *gin.Context) *Session { @@ -21,23 +28,39 @@ func New(ctx *gin.Context) *Session { } ss.MainEng = db.MainEng.NewSession() - ss.UserEng = db.UserEng.NewSession() ss.UserEng.Begin() + userID := ctx.GetString("userid") + if userID != "" { + exist, err := ss.UserEng.Table("user_pref").Where("user_id = ?", userID).Get(&ss.UserPref) + if ss.CheckErr(err) { + return nil + } + if !exist { + ss.Abort(errors.New("user not exist!")) + return nil + } + ss.UserID = ss.UserPref.UserID + } + return ss } +func Get(ctx *gin.Context) *Session { + return ctx.MustGet("session").(*Session) +} + func (ss *Session) Finalize() { ss.MainEng.Close() - - ss.UserEng.Commit() + if ss.CheckErr(ss.UserEng.Commit()) { + return + } ss.UserEng.Close() } func (ss *Session) Abort(err error) { ss.MainEng.Close() - ss.UserEng.Rollback() ss.UserEng.Close() @@ -47,16 +70,28 @@ func (ss *Session) Abort(err error) { func (ss *Session) CheckErr(err error) bool { if err != nil { + log.Println(err.Error()) ss.Abort(err) return true } return false } +func (ss *Session) GetDeviceID() string { + return ss.Ctx.Request.Header.Get("X-DEVICEID") +} + +func (ss *Session) GetRandKey() []byte { + key, err := db.Ldb.Get([]byte(ss.GetDeviceID())) + if ss.CheckErr(err) { + return nil + } + return key +} + func (ss *Session) Respond(resp any) { data, err := json.Marshal(resp) - if err != nil { - ss.Abort(err) + if ss.CheckErr(err) { return } diff --git a/internal/startup/database.go b/internal/startup/database.go new file mode 100644 index 0000000..22ffb27 --- /dev/null +++ b/internal/startup/database.go @@ -0,0 +1,18 @@ +package startup + +import ( + "honoka-chan/internal/model/user" + "honoka-chan/pkg/db" +) + +func CreateTable() { + // db.UserEng.ShowSQL(true) + db.UserEng.Sync2(new(user.Users)) + db.UserEng.Sync2(new(user.UserKey)) + db.UserEng.Sync2(new(user.UserPref)) + db.UserEng.Sync2(new(user.UserAccessoryWear)) + db.UserEng.Sync2(new(user.UserDeck)) + db.UserEng.Sync2(new(user.UserUnit)) + db.UserEng.Sync2(new(user.UserDeckUnit)) + db.UserEng.Sync2(new(user.UserUnitSkillEquip)) +} diff --git a/internal/startup/startup.go b/internal/startup/startup.go new file mode 100644 index 0000000..d5e98b5 --- /dev/null +++ b/internal/startup/startup.go @@ -0,0 +1,6 @@ +package startup + +func StartUp() { + CreateTable() + InitUserData(0) +} diff --git a/internal/tools/init.go b/internal/startup/userdata.go similarity index 55% rename from internal/tools/init.go rename to internal/startup/userdata.go index 1d24fe7..63442c4 100644 --- a/internal/tools/init.go +++ b/internal/startup/userdata.go @@ -1,45 +1,32 @@ -package tools +package startup import ( "fmt" - "honoka-chan/internal/model" + "honoka-chan/internal/model/user" + "honoka-chan/internal/schema/api/profile" + "honoka-chan/internal/schema/api/unit" "honoka-chan/internal/utils" "honoka-chan/pkg/db" + "strconv" "time" ) -type UserData struct { - ID int `xorm:"id pk autoincr"` - Phone string `xorm:"phone"` - Password string `xorm:"password"` - Autokey string `xorm:"autokey"` - Ticket string `xorm:"ticket"` - UserID int `xorm:"userid"` - LastLoginTime int64 `xorm:"last_login_time"` -} - -type UserPref struct { - ID int `xorm:"id pk autoincr"` - UserID int `xorm:"user_id"` - AwardID int `xorm:"award_id"` - BackgroundID int `xorm:"background_id"` - UnitOwningUserID int `xorm:"unit_owning_user_id"` - UserName string `xorm:"user_name"` - UserLevel int `xorm:"user_level"` - UserDesc string `xorm:"user_desc"` - UpdateTime int64 `xorm:"update_time"` -} - func InitUserData(userId int) { - userList := []UserData{} + userList := []user.Users{} if userId != 0 { - err := db.UserEng.Table("users").Where("userid = ?", userId).Find(&userList) + err := db.UserEng.Table("users").Where("user_id = ?", userId).Find(&userList) utils.CheckErr(err) } else { err := db.UserEng.Table("users").Asc("id").Find(&userList) utils.CheckErr(err) } + // 同步用户表 + // db.UserEng.ShowSQL(true) + // db.UserEng.Table("user_info_m").Sync2(new(user.UserInfo)) + // db.UserEng.Table("user_pref").Sync2(new(UserPref)) + + // 开始会话 session := db.UserEng.NewSession() defer session.Close() @@ -47,9 +34,9 @@ func InitUserData(userId int) { panic(err) } - for _, user := range userList { + for _, u := range userList { // 检查用户配置 - exists, err := db.UserEng.Table("user_preference_m").Where("user_id = ?", user.UserID).Exist() + exists, err := db.UserEng.Table("user_pref").Where("user_id = ?", u.UserID).Exist() utils.CheckErr(err) if !exists { @@ -57,38 +44,42 @@ func InitUserData(userId int) { var oId int _, err = db.MainEng.Table("common_unit_m").Cols("unit_owning_user_id").Where("unit_id = ?", 31).Get(&oId) utils.CheckErr(err) - fmt.Println("Center UnitOwningUserID:", oId) - userPref := UserPref{ - UserID: user.UserID, + fmt.Println("Center UnitOwningUserId:", oId) + userPref := user.UserPref{ + UserID: u.UserID, AwardID: 1, // 音乃木坂学生 BackgroundID: 1, // 初始背景 UnitOwningUserID: oId, UserName: "音乃木坂学生", UserLevel: 1, UserDesc: "你好。", + InviteCode: strconv.Itoa(u.UserID), UpdateTime: time.Now().Unix(), } - _, err = session.Table("user_preference_m").Insert(&userPref) + _, err = session.Table("user_pref").Insert(&userPref) utils.CheckErr(err) - // fmt.Println("UserPref ID", userPref.ID) + // fmt.Println("UserPref Id", userPref.Id) } + // 检查用户信息 + exists, err = db.UserEng.Table("user_info_m").Where("user_id = ?", u.UserID).Exist() + // 检查用户卡组配置 - exists, err = db.UserEng.Table("user_deck_m").Where("user_id = ?", user.UserID).Asc("deck_id").Exist() + exists, err = db.UserEng.Table("user_deck").Where("user_id = ?", u.UserID).Asc("deck_id").Exist() utils.CheckErr(err) // fmt.Println("UserDeck exists:", exists) if !exists { - userDeck := model.UserDeckData{ + userDeck := unit.UserDeckData{ DeckID: 1, MainFlag: 1, DeckName: "队伍A", - UserID: user.UserID, + UserID: u.UserID, InsertDate: time.Now().Unix(), } // 默认队伍 - _, err = session.Table("user_deck_m").Insert(&userDeck) + _, err = session.Table("user_deck").Insert(&userDeck) if err != nil { session.Rollback() panic(err) @@ -104,7 +95,7 @@ func InitUserData(userId int) { panic(err) } - unitData := []model.UnitData{} + unitData := []profile.UnitData{} err = db.MainEng.Table("common_unit_m").In("unit_id", unitIds).Find(&unitData) if err != nil { session.Rollback() @@ -113,11 +104,11 @@ func InitUserData(userId int) { // fmt.Println(unitData) position := 1 - for _, unit := range unitData { - unitDeckData := model.UnitDeckData{ + for _, u := range unitData { + unitDeckData := unit.UnitDeckData{ UserDeckID: userDeckId, - UnitOwningUserID: unit.UnitOwningUserID, - UnitID: unit.UnitID, + UnitOwningUserID: u.UnitOwningUserID, + UnitID: u.UnitID, Position: position, Level: 100, LevelLimitID: 1, @@ -127,21 +118,22 @@ func InitUserData(userId int) { IsRankMax: true, IsLoveMax: true, IsLevelMax: true, - IsSigned: unit.IsSigned, + IsSigned: u.IsSigned, BeforeLove: 1000, MaxLove: 1000, InsertData: time.Now().Unix(), } - _, err = session.Table("deck_unit_m").Insert(&unitDeckData) + _, err = session.Table("user_deck_unit").Insert(&unitDeckData) if err != nil { session.Rollback() panic(err) } - // fmt.Println("New DeckUnit:", unitDeckData.ID) + // fmt.Println("New DeckUnit:", unitDeckData.Id) position++ } + // 结束会话 if err = session.Commit(); err != nil { panic(err) } diff --git a/internal/utils/utils.go b/internal/utils/utils.go index b3a89b3..ae42f9c 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -2,7 +2,6 @@ package utils import ( "encoding/base64" - "honoka-chan/pkg/db" "honoka-chan/pkg/encrypt" ) @@ -12,13 +11,6 @@ func CheckErr(err error) { } } -func IsSigned(unitId int) bool { - exists, err := db.MainEng.Table("unit_sign_asset_m").Where("unit_id = ?", unitId).Exist() - CheckErr(err) - - return exists -} - func GenXMS(resp []byte) string { return base64.StdEncoding.EncodeToString(encrypt.RSASignSHA1(resp)) } diff --git a/main.go b/main.go index 665ef8b..0df3c91 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,9 @@ package main import ( "honoka-chan/config" + _ "honoka-chan/internal/handler" "honoka-chan/internal/router" - _ "honoka-chan/internal/tools" + "honoka-chan/internal/startup" "honoka-chan/pkg/db" "log" "os" @@ -14,6 +15,12 @@ import ( ) func main() { + // 初始化配置 + config.InitConfig() + + // 初始化数据库表和用户数据 + startup.StartUp() + // 处理系统信号,确保程序退出时关闭数据库 signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) @@ -21,7 +28,7 @@ func main() { go func() { <-signalChan log.Println("Shutting down...") - db.DB.Close() + db.Ldb.Close() os.Exit(0) }() diff --git a/pkg/db/db.go b/pkg/db/db.go index c25a9e7..5a4bd22 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -2,30 +2,22 @@ package db import ( "fmt" - "honoka-chan/pkg/utils" - "os" _ "modernc.org/sqlite" "xorm.io/xorm" ) var ( - DB *Instance + Ldb *LdbInstance - ExampleDb = "assets/data.example.db" - MainDb = "assets/main.db" - UserDb = "assets/data.db" - MainEng *xorm.Engine - UserEng *xorm.Engine + MainDb = "assets/main.db" + UserDb = "assets/data.db" + MainEng *xorm.Engine + UserEng *xorm.Engine ) func init() { - DB = GetInstance() - - _, err := os.Stat(UserDb) - if err != nil { - utils.WriteAllText(UserDb, utils.ReadAllText(ExampleDb)) - } + Ldb = GetLdbInstance() eng, err := xorm.NewEngine("sqlite", MainDb) if err != nil { @@ -53,7 +45,7 @@ func init() { } func MatchTokenUid(token, uid string) bool { - res, err := DB.Get([]byte(uid)) + res, err := Ldb.Get([]byte(uid)) if err != nil { fmt.Println(err) return false diff --git a/pkg/db/leveldb.go b/pkg/db/leveldb.go index b2d8e51..6d8ac69 100644 --- a/pkg/db/leveldb.go +++ b/pkg/db/leveldb.go @@ -11,13 +11,13 @@ var ( once sync.Once ) -type Instance struct { +type LdbInstance struct { db *leveldb.DB mu sync.Mutex } -func GetInstance() *Instance { - in := Instance{} +func GetLdbInstance() *LdbInstance { + in := LdbInstance{} once.Do(func() { var err error in.db, err = leveldb.OpenFile("./data/honoka-chan.db", nil) @@ -28,7 +28,7 @@ func GetInstance() *Instance { return &in } -func (in *Instance) Close() error { +func (in *LdbInstance) Close() error { in.mu.Lock() defer in.mu.Unlock() if in.db != nil { @@ -37,7 +37,7 @@ func (in *Instance) Close() error { return nil } -func (in *Instance) Get(key []byte) ([]byte, error) { +func (in *LdbInstance) Get(key []byte) ([]byte, error) { if len(key) == 0 { return nil, errors.New("empty key") } @@ -50,7 +50,7 @@ func (in *Instance) Get(key []byte) ([]byte, error) { return res, nil } -func (in *Instance) Set(key, value []byte) error { +func (in *LdbInstance) Set(key, value []byte) error { if len(key) == 0 { return errors.New("empty key") } diff --git a/internal/tools/tools.go b/pkg/tools/tools.go similarity index 99% rename from internal/tools/tools.go rename to pkg/tools/tools.go index a0960ee..ab288a7 100644 --- a/internal/tools/tools.go +++ b/pkg/tools/tools.go @@ -1,7 +1,6 @@ package tools func init() { - InitUserData(0) // eng, err := xorm.NewEngine("sqlite", "assets/masterdata.db") // utils.CheckErr(err) diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index e7eb4de..8af2a4d 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -38,13 +38,14 @@ func WriteAllText(path, text string) { _ = os.WriteFile(path, []byte(text), 0644) } -func SliceXor(s1, s2 []byte) (res []byte) { - for k, b := range s1 { - newBt := b ^ s2[k] - res = append(res, newBt) - } +func XOR(s1, s2 []byte) []byte { + n := min(len(s1), len(s2)) - return + res := make([]byte, n) + for i, b := range s1[:n] { + res[i] = b ^ s2[i] + } + return res } func Sub16(str []byte) []byte { diff --git a/assets/static/.gitignore b/static/.gitignore similarity index 100% rename from assets/static/.gitignore rename to static/.gitignore diff --git a/assets/static/css/base.css b/static/css/base.css similarity index 100% rename from assets/static/css/base.css rename to static/css/base.css diff --git a/assets/static/css/layui.css b/static/css/layui.css similarity index 100% rename from assets/static/css/layui.css rename to static/css/layui.css diff --git a/assets/static/css/ll-perfect-scrollbar.css b/static/css/ll-perfect-scrollbar.css similarity index 100% rename from assets/static/css/ll-perfect-scrollbar.css rename to static/css/ll-perfect-scrollbar.css diff --git a/assets/static/css/perfect-scrollbar.css b/static/css/perfect-scrollbar.css similarity index 100% rename from assets/static/css/perfect-scrollbar.css rename to static/css/perfect-scrollbar.css diff --git a/assets/static/css/style.css b/static/css/style.css similarity index 100% rename from assets/static/css/style.css rename to static/css/style.css diff --git a/assets/static/css/window.css b/static/css/window.css similarity index 100% rename from assets/static/css/window.css rename to static/css/window.css diff --git a/assets/static/font/iconfont.eot b/static/font/iconfont.eot similarity index 100% rename from assets/static/font/iconfont.eot rename to static/font/iconfont.eot diff --git a/assets/static/font/iconfont.svg b/static/font/iconfont.svg similarity index 100% rename from assets/static/font/iconfont.svg rename to static/font/iconfont.svg diff --git a/assets/static/font/iconfont.ttf b/static/font/iconfont.ttf similarity index 100% rename from assets/static/font/iconfont.ttf rename to static/font/iconfont.ttf diff --git a/assets/static/font/iconfont.woff b/static/font/iconfont.woff similarity index 100% rename from assets/static/font/iconfont.woff rename to static/font/iconfont.woff diff --git a/assets/static/font/iconfont.woff2 b/static/font/iconfont.woff2 similarity index 100% rename from assets/static/font/iconfont.woff2 rename to static/font/iconfont.woff2 diff --git a/assets/static/images/15047550942873.jpg b/static/images/15047550942873.jpg similarity index 100% rename from assets/static/images/15047550942873.jpg rename to static/images/15047550942873.jpg diff --git a/assets/static/images/15047551059201.jpg b/static/images/15047551059201.jpg similarity index 100% rename from assets/static/images/15047551059201.jpg rename to static/images/15047551059201.jpg diff --git a/assets/static/images/15047551145790.jpg b/static/images/15047551145790.jpg similarity index 100% rename from assets/static/images/15047551145790.jpg rename to static/images/15047551145790.jpg diff --git a/assets/static/images/15047551242040.jpg b/static/images/15047551242040.jpg similarity index 100% rename from assets/static/images/15047551242040.jpg rename to static/images/15047551242040.jpg diff --git a/assets/static/images/15047553374283.jpg b/static/images/15047553374283.jpg similarity index 100% rename from assets/static/images/15047553374283.jpg rename to static/images/15047553374283.jpg diff --git a/assets/static/images/15047553496606.jpg b/static/images/15047553496606.jpg similarity index 100% rename from assets/static/images/15047553496606.jpg rename to static/images/15047553496606.jpg diff --git a/assets/static/images/15047553611357.jpg b/static/images/15047553611357.jpg similarity index 100% rename from assets/static/images/15047553611357.jpg rename to static/images/15047553611357.jpg diff --git a/assets/static/images/15047553728636.jpg b/static/images/15047553728636.jpg similarity index 100% rename from assets/static/images/15047553728636.jpg rename to static/images/15047553728636.jpg diff --git a/assets/static/images/15047553849518.jpg b/static/images/15047553849518.jpg similarity index 100% rename from assets/static/images/15047553849518.jpg rename to static/images/15047553849518.jpg diff --git a/assets/static/images/15047553982300.jpg b/static/images/15047553982300.jpg similarity index 100% rename from assets/static/images/15047553982300.jpg rename to static/images/15047553982300.jpg diff --git a/assets/static/images/15047554108052.jpg b/static/images/15047554108052.jpg similarity index 100% rename from assets/static/images/15047554108052.jpg rename to static/images/15047554108052.jpg diff --git a/assets/static/images/15047554203428.jpg b/static/images/15047554203428.jpg similarity index 100% rename from assets/static/images/15047554203428.jpg rename to static/images/15047554203428.jpg diff --git a/assets/static/images/15047554315307.jpg b/static/images/15047554315307.jpg similarity index 100% rename from assets/static/images/15047554315307.jpg rename to static/images/15047554315307.jpg diff --git a/assets/static/images/15047554481319.jpg b/static/images/15047554481319.jpg similarity index 100% rename from assets/static/images/15047554481319.jpg rename to static/images/15047554481319.jpg diff --git a/assets/static/images/15047554596230.jpg b/static/images/15047554596230.jpg similarity index 100% rename from assets/static/images/15047554596230.jpg rename to static/images/15047554596230.jpg diff --git a/assets/static/images/15047554774569.jpg b/static/images/15047554774569.jpg similarity index 100% rename from assets/static/images/15047554774569.jpg rename to static/images/15047554774569.jpg diff --git a/assets/static/images/15047554922924.jpg b/static/images/15047554922924.jpg similarity index 100% rename from assets/static/images/15047554922924.jpg rename to static/images/15047554922924.jpg diff --git a/assets/static/images/15047555087747.jpg b/static/images/15047555087747.jpg similarity index 100% rename from assets/static/images/15047555087747.jpg rename to static/images/15047555087747.jpg diff --git a/assets/static/images/15047555219572.jpg b/static/images/15047555219572.jpg similarity index 100% rename from assets/static/images/15047555219572.jpg rename to static/images/15047555219572.jpg diff --git a/assets/static/images/15047555411780.jpg b/static/images/15047555411780.jpg similarity index 100% rename from assets/static/images/15047555411780.jpg rename to static/images/15047555411780.jpg diff --git a/assets/static/images/15047555499746.jpg b/static/images/15047555499746.jpg similarity index 100% rename from assets/static/images/15047555499746.jpg rename to static/images/15047555499746.jpg diff --git a/assets/static/images/15047555585712.jpg b/static/images/15047555585712.jpg similarity index 100% rename from assets/static/images/15047555585712.jpg rename to static/images/15047555585712.jpg diff --git a/assets/static/images/15047555704112.jpg b/static/images/15047555704112.jpg similarity index 100% rename from assets/static/images/15047555704112.jpg rename to static/images/15047555704112.jpg diff --git a/assets/static/images/15047555798773.jpg b/static/images/15047555798773.jpg similarity index 100% rename from assets/static/images/15047555798773.jpg rename to static/images/15047555798773.jpg diff --git a/assets/static/images/15047555888980.jpg b/static/images/15047555888980.jpg similarity index 100% rename from assets/static/images/15047555888980.jpg rename to static/images/15047555888980.jpg diff --git a/assets/static/images/15088959186072.jpg b/static/images/15088959186072.jpg similarity index 100% rename from assets/static/images/15088959186072.jpg rename to static/images/15088959186072.jpg diff --git a/assets/static/images/15107324142966.png b/static/images/15107324142966.png similarity index 100% rename from assets/static/images/15107324142966.png rename to static/images/15107324142966.png diff --git a/assets/static/images/15141856059568.jpg b/static/images/15141856059568.jpg similarity index 100% rename from assets/static/images/15141856059568.jpg rename to static/images/15141856059568.jpg diff --git a/assets/static/images/15141862776588.jpg b/static/images/15141862776588.jpg similarity index 100% rename from assets/static/images/15141862776588.jpg rename to static/images/15141862776588.jpg diff --git a/assets/static/images/15141862946556.jpg b/static/images/15141862946556.jpg similarity index 100% rename from assets/static/images/15141862946556.jpg rename to static/images/15141862946556.jpg diff --git a/assets/static/images/15141863126912.jpg b/static/images/15141863126912.jpg similarity index 100% rename from assets/static/images/15141863126912.jpg rename to static/images/15141863126912.jpg diff --git a/assets/static/images/15141863229129.jpg b/static/images/15141863229129.jpg similarity index 100% rename from assets/static/images/15141863229129.jpg rename to static/images/15141863229129.jpg diff --git a/assets/static/images/15141863365919.jpg b/static/images/15141863365919.jpg similarity index 100% rename from assets/static/images/15141863365919.jpg rename to static/images/15141863365919.jpg diff --git a/assets/static/images/15141863483422.jpg b/static/images/15141863483422.jpg similarity index 100% rename from assets/static/images/15141863483422.jpg rename to static/images/15141863483422.jpg diff --git a/assets/static/images/15141863639911.jpg b/static/images/15141863639911.jpg similarity index 100% rename from assets/static/images/15141863639911.jpg rename to static/images/15141863639911.jpg diff --git a/assets/static/images/15141863772178.jpg b/static/images/15141863772178.jpg similarity index 100% rename from assets/static/images/15141863772178.jpg rename to static/images/15141863772178.jpg diff --git a/assets/static/images/15141864261972.jpg b/static/images/15141864261972.jpg similarity index 100% rename from assets/static/images/15141864261972.jpg rename to static/images/15141864261972.jpg diff --git a/assets/static/images/15141864584520.jpg b/static/images/15141864584520.jpg similarity index 100% rename from assets/static/images/15141864584520.jpg rename to static/images/15141864584520.jpg diff --git a/assets/static/images/15141864695842.jpg b/static/images/15141864695842.jpg similarity index 100% rename from assets/static/images/15141864695842.jpg rename to static/images/15141864695842.jpg diff --git a/assets/static/images/15141864804128.jpg b/static/images/15141864804128.jpg similarity index 100% rename from assets/static/images/15141864804128.jpg rename to static/images/15141864804128.jpg diff --git a/assets/static/images/15141864889884.jpg b/static/images/15141864889884.jpg similarity index 100% rename from assets/static/images/15141864889884.jpg rename to static/images/15141864889884.jpg diff --git a/assets/static/images/15141865055652.jpg b/static/images/15141865055652.jpg similarity index 100% rename from assets/static/images/15141865055652.jpg rename to static/images/15141865055652.jpg diff --git a/assets/static/images/15141865133555.jpg b/static/images/15141865133555.jpg similarity index 100% rename from assets/static/images/15141865133555.jpg rename to static/images/15141865133555.jpg diff --git a/assets/static/images/15141865196092.jpg b/static/images/15141865196092.jpg similarity index 100% rename from assets/static/images/15141865196092.jpg rename to static/images/15141865196092.jpg diff --git a/assets/static/images/15238681581968.png b/static/images/15238681581968.png similarity index 100% rename from assets/static/images/15238681581968.png rename to static/images/15238681581968.png diff --git a/assets/static/images/15238694807202.png b/static/images/15238694807202.png similarity index 100% rename from assets/static/images/15238694807202.png rename to static/images/15238694807202.png diff --git a/assets/static/images/15238694919055.png b/static/images/15238694919055.png similarity index 100% rename from assets/static/images/15238694919055.png rename to static/images/15238694919055.png diff --git a/assets/static/images/15238695116848.png b/static/images/15238695116848.png similarity index 100% rename from assets/static/images/15238695116848.png rename to static/images/15238695116848.png diff --git a/assets/static/images/15238695303404.png b/static/images/15238695303404.png similarity index 100% rename from assets/static/images/15238695303404.png rename to static/images/15238695303404.png diff --git a/assets/static/images/15238695455400.png b/static/images/15238695455400.png similarity index 100% rename from assets/static/images/15238695455400.png rename to static/images/15238695455400.png diff --git a/assets/static/images/15238695587056.png b/static/images/15238695587056.png similarity index 100% rename from assets/static/images/15238695587056.png rename to static/images/15238695587056.png diff --git a/assets/static/images/15238695641197.png b/static/images/15238695641197.png similarity index 100% rename from assets/static/images/15238695641197.png rename to static/images/15238695641197.png diff --git a/assets/static/images/15238701747409.png b/static/images/15238701747409.png similarity index 100% rename from assets/static/images/15238701747409.png rename to static/images/15238701747409.png diff --git a/assets/static/images/15238702168776.png b/static/images/15238702168776.png similarity index 100% rename from assets/static/images/15238702168776.png rename to static/images/15238702168776.png diff --git a/assets/static/images/admin/ic_launcher.png b/static/images/admin/ic_launcher.png similarity index 100% rename from assets/static/images/admin/ic_launcher.png rename to static/images/admin/ic_launcher.png diff --git a/assets/static/images/admin/top-bg.jpg b/static/images/admin/top-bg.jpg similarity index 100% rename from assets/static/images/admin/top-bg.jpg rename to static/images/admin/top-bg.jpg diff --git a/assets/static/images/admin/top-bg_2.jpg b/static/images/admin/top-bg_2.jpg similarity index 100% rename from assets/static/images/admin/top-bg_2.jpg rename to static/images/admin/top-bg_2.jpg diff --git a/assets/static/images/bg-left.png b/static/images/bg-left.png similarity index 100% rename from assets/static/images/bg-left.png rename to static/images/bg-left.png diff --git a/assets/static/images/bg-right.png b/static/images/bg-right.png similarity index 100% rename from assets/static/images/bg-right.png rename to static/images/bg-right.png diff --git a/static/images/favicon.ico b/static/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dd176a944573b6f048154e76e7b7361b0c29ecfd GIT binary patch literal 48710 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 i&2WI2#;3K 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 -{{ end }} \ No newline at end of file +{{ end }} diff --git a/assets/static/templates/admin/index.html b/static/templates/admin/index.html similarity index 98% rename from assets/static/templates/admin/index.html rename to static/templates/admin/index.html index c9b7d91..8605b5e 100644 --- a/assets/static/templates/admin/index.html +++ b/static/templates/admin/index.html @@ -24,4 +24,4 @@ -{{ end }} \ No newline at end of file +{{ end }} diff --git a/assets/static/templates/admin/login.html b/static/templates/admin/login.html similarity index 99% rename from assets/static/templates/admin/login.html rename to static/templates/admin/login.html index c63a72d..64070d3 100644 --- a/assets/static/templates/admin/login.html +++ b/static/templates/admin/login.html @@ -110,4 +110,4 @@ -{{ end }} \ No newline at end of file +{{ end }} diff --git a/assets/static/templates/admin/nav/css.html b/static/templates/admin/nav/css.html similarity index 90% rename from assets/static/templates/admin/nav/css.html rename to static/templates/admin/nav/css.html index 872a4fe..8c7c1ba 100644 --- a/assets/static/templates/admin/nav/css.html +++ b/static/templates/admin/nav/css.html @@ -1,4 +1,5 @@ {{ define "admin/nav/css.html" }} + -{{ end }} \ No newline at end of file +{{ end }} diff --git a/assets/static/templates/admin/nav/footer.html b/static/templates/admin/nav/footer.html similarity index 91% rename from assets/static/templates/admin/nav/footer.html rename to static/templates/admin/nav/footer.html index e235608..e6eb0c1 100644 --- a/assets/static/templates/admin/nav/footer.html +++ b/static/templates/admin/nav/footer.html @@ -2,4 +2,4 @@ -{{ end }} \ No newline at end of file +{{ end }} diff --git a/assets/static/templates/admin/nav/header.html b/static/templates/admin/nav/header.html similarity index 98% rename from assets/static/templates/admin/nav/header.html rename to static/templates/admin/nav/header.html index b047469..4157f3d 100644 --- a/assets/static/templates/admin/nav/header.html +++ b/static/templates/admin/nav/header.html @@ -20,4 +20,4 @@
    -{{ end }} \ No newline at end of file +{{ end }} diff --git a/assets/static/templates/admin/nav/side.html b/static/templates/admin/nav/side.html similarity index 100% rename from assets/static/templates/admin/nav/side.html rename to static/templates/admin/nav/side.html diff --git a/assets/static/templates/admin/upload.html b/static/templates/admin/upload.html similarity index 99% rename from assets/static/templates/admin/upload.html rename to static/templates/admin/upload.html index 90092d8..0c60c9c 100644 --- a/assets/static/templates/admin/upload.html +++ b/static/templates/admin/upload.html @@ -84,4 +84,4 @@ -{{ end }} \ No newline at end of file +{{ end }} diff --git a/assets/static/templates/common/announce.html b/static/templates/common/announce.html similarity index 100% rename from assets/static/templates/common/announce.html rename to static/templates/common/announce.html diff --git a/assets/static/templates/common/manga.html b/static/templates/common/manga.html similarity index 100% rename from assets/static/templates/common/manga.html rename to static/templates/common/manga.html