nonebot-plugin-osubot 6.23.1__py3-none-any.whl → 6.24.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nonebot-plugin-osubot might be problematic. Click here for more details.
- nonebot_plugin_osubot/api.py +7 -5
- nonebot_plugin_osubot/draw/bmap.py +19 -21
- nonebot_plugin_osubot/draw/bp.py +1 -1
- nonebot_plugin_osubot/draw/echarts.py +8 -2
- nonebot_plugin_osubot/draw/info.py +2 -0
- nonebot_plugin_osubot/draw/map.py +5 -2
- nonebot_plugin_osubot/draw/osu_preview.py +64 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/css/style.css +258 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/README.md +109 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js +3 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js.map +1 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js +3 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js.map +1 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/index.html +437 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/beatmap.js +211 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/hitobject.js +29 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/point.js +55 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/scroll.js +45 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/timingpoint.js +35 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/LegacyRandom.js +81 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/PalpableCatchHitObject.js +53 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/bananashower.js +33 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/catch.js +211 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/fruit.js +21 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/juicestream.js +176 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/hitnote.js +21 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/holdnote.js +37 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/mania.js +164 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/preview.js +61 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/bezier2.js +33 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/catmullcurve.js +34 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/centripetalcatmullrom.js +30 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/circumstancedcircle.js +47 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curve.js +25 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curvetype.js +17 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/equaldistancemulticurve.js +70 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/linearbezier.js +40 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/hitcircle.js +85 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/slider.js +120 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/spinner.js +56 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/standard.js +170 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/donkat.js +40 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/drumroll.js +34 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/shaker.js +58 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/taiko.js +120 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/js/util.js +61 -0
- nonebot_plugin_osubot/draw/osu_preview_templates/pic.html +115 -0
- nonebot_plugin_osubot/draw/score.py +4 -4
- nonebot_plugin_osubot/file.py +1 -12
- nonebot_plugin_osubot/mania/__init__.py +9 -10
- nonebot_plugin_osubot/matcher/bp_analyze.py +9 -9
- nonebot_plugin_osubot/matcher/guess.py +3 -3
- nonebot_plugin_osubot/matcher/map_convert.py +12 -7
- nonebot_plugin_osubot/matcher/preview.py +10 -3
- nonebot_plugin_osubot/matcher/recommend.py +7 -12
- nonebot_plugin_osubot/osufile/mods/AP.png +0 -0
- nonebot_plugin_osubot/osufile/mods/CL.png +0 -0
- nonebot_plugin_osubot/osufile/mods/DT.png +0 -0
- nonebot_plugin_osubot/osufile/mods/EZ.png +0 -0
- nonebot_plugin_osubot/osufile/mods/FI.png +0 -0
- nonebot_plugin_osubot/osufile/mods/FL.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HR.png +0 -0
- nonebot_plugin_osubot/osufile/mods/HT.png +0 -0
- nonebot_plugin_osubot/osufile/mods/MR.png +0 -0
- nonebot_plugin_osubot/osufile/mods/NC.png +0 -0
- nonebot_plugin_osubot/osufile/mods/NF.png +0 -0
- nonebot_plugin_osubot/osufile/mods/PF.png +0 -0
- nonebot_plugin_osubot/osufile/mods/RX.png +0 -0
- nonebot_plugin_osubot/osufile/mods/SD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/SO.png +0 -0
- nonebot_plugin_osubot/osufile/mods/TD.png +0 -0
- nonebot_plugin_osubot/osufile/mods/V2.png +0 -0
- nonebot_plugin_osubot/pp.py +7 -0
- nonebot_plugin_osubot/schema/__init__.py +0 -2
- nonebot_plugin_osubot/schema/beatmapsets.py +42 -0
- nonebot_plugin_osubot/schema/score.py +1 -0
- {nonebot_plugin_osubot-6.23.1.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/METADATA +2 -2
- {nonebot_plugin_osubot-6.23.1.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/RECORD +80 -39
- nonebot_plugin_osubot/schema/sayo_beatmap.py +0 -59
- {nonebot_plugin_osubot-6.23.1.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
function Taiko(osu)
|
|
2
|
+
{
|
|
3
|
+
Scroll.call(this, osu);
|
|
4
|
+
|
|
5
|
+
for (var i = 0; i < this.HitObjects.length; i++)
|
|
6
|
+
{
|
|
7
|
+
var hitObject = this.HitObjects[i];
|
|
8
|
+
hitObject.position.x = this.scrollAt(hitObject.time);
|
|
9
|
+
hitObject.endPosition.x = this.scrollAt(hitObject.endTime);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
Taiko.prototype = Object.create(Scroll.prototype, {
|
|
13
|
+
|
|
14
|
+
});
|
|
15
|
+
Taiko.prototype.constructor = Taiko;
|
|
16
|
+
Taiko.prototype.hitObjectTypes = {};
|
|
17
|
+
Taiko.ID = 1;
|
|
18
|
+
Beatmap.modes[Taiko.ID] = Taiko;
|
|
19
|
+
Taiko.DEFAULT_COLORS = [
|
|
20
|
+
'#eb452c',
|
|
21
|
+
'#438eac',
|
|
22
|
+
'#fcb806'
|
|
23
|
+
];
|
|
24
|
+
Taiko.DIAMETER = 56;
|
|
25
|
+
Taiko.prototype.calcX = function(x, scroll)
|
|
26
|
+
{
|
|
27
|
+
return (x - scroll) * 20 * (260) / 1000 / (this.SliderMultiplier * 8);
|
|
28
|
+
};
|
|
29
|
+
Taiko.prototype.update = function(ctx)
|
|
30
|
+
{
|
|
31
|
+
ctx.shadowColor = '#666';
|
|
32
|
+
ctx.lineCap = 'round';
|
|
33
|
+
ctx.lineJoin = 'round';
|
|
34
|
+
ctx.textAlign = 'center';
|
|
35
|
+
ctx.textBaseline = 'middle';
|
|
36
|
+
ctx.translate(160, 200);
|
|
37
|
+
};
|
|
38
|
+
Taiko.prototype.draw = function(time, ctx)
|
|
39
|
+
{
|
|
40
|
+
if (typeof this.tmp.first == 'undefined')
|
|
41
|
+
{
|
|
42
|
+
this.tmp.first = 0;
|
|
43
|
+
this.tmp.last = -1;
|
|
44
|
+
this.tmp.barLine = 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var scroll = this.scrollAt(time);
|
|
48
|
+
while (this.tmp.first < this.HitObjects.length &&
|
|
49
|
+
time > this.HitObjects[this.tmp.first].endTime)
|
|
50
|
+
{
|
|
51
|
+
this.tmp.first++;
|
|
52
|
+
}
|
|
53
|
+
while (this.tmp.last + 1 < this.HitObjects.length)
|
|
54
|
+
{
|
|
55
|
+
var hitObject = this.HitObjects[this.tmp.last + 1];
|
|
56
|
+
if (this.calcX(hitObject.position.x, scroll) > Beatmap.WIDTH)
|
|
57
|
+
{
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
this.tmp.last++;
|
|
61
|
+
}
|
|
62
|
+
while (this.tmp.barLine < this.barLines.length &&
|
|
63
|
+
this.calcX(this.barLines[this.tmp.barLine], scroll) < -Taiko.DIAMETER)
|
|
64
|
+
{
|
|
65
|
+
this.tmp.barLine++;
|
|
66
|
+
}
|
|
67
|
+
for (var i = this.tmp.barLine; i < this.barLines.length && this.calcX(this.barLines[i], scroll) < Beatmap.WIDTH; i++)
|
|
68
|
+
{
|
|
69
|
+
var barLine = this.calcX(this.barLines[i], scroll);
|
|
70
|
+
ctx.beginPath();
|
|
71
|
+
ctx.moveTo(barLine, -Taiko.DIAMETER);
|
|
72
|
+
ctx.lineTo(barLine, Taiko.DIAMETER);
|
|
73
|
+
ctx.strokeStyle = '#fff';
|
|
74
|
+
ctx.lineWidth = 1;
|
|
75
|
+
ctx.stroke();
|
|
76
|
+
}
|
|
77
|
+
for (var i = this.tmp.last; i >= this.tmp.first; i--)
|
|
78
|
+
{
|
|
79
|
+
var hitObject = this.HitObjects[i];
|
|
80
|
+
if (time > hitObject.endTime)
|
|
81
|
+
{
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
hitObject.draw(scroll, ctx);
|
|
85
|
+
}
|
|
86
|
+
ctx.clearRect(-160, -200, Taiko.DIAMETER * 2, 400);
|
|
87
|
+
};
|
|
88
|
+
Taiko.prototype.processBG = function(ctx)
|
|
89
|
+
{
|
|
90
|
+
var offset = - Taiko.DIAMETER;
|
|
91
|
+
//ctx.drawImage(ctx.canvas, -160, offset, ctx.canvas.width, ctx.canvas.height);
|
|
92
|
+
//ctx.beginPath();
|
|
93
|
+
//ctx.rect(0, 0, Beatmap.WIDTH, offset);
|
|
94
|
+
//ctx.fillStyle = '#000';
|
|
95
|
+
//ctx.fill();
|
|
96
|
+
|
|
97
|
+
// rail
|
|
98
|
+
ctx.beginPath();
|
|
99
|
+
ctx.rect(-160, offset, Beatmap.WIDTH, Taiko.DIAMETER * 2);
|
|
100
|
+
ctx.strokeStyle = '#ddd';
|
|
101
|
+
ctx.lineWidth = 8;
|
|
102
|
+
ctx.stroke();
|
|
103
|
+
ctx.fillStyle = '#000';
|
|
104
|
+
ctx.fill();
|
|
105
|
+
|
|
106
|
+
// drum
|
|
107
|
+
ctx.beginPath();
|
|
108
|
+
ctx.rect(-160, offset, Taiko.DIAMETER * 2, Taiko.DIAMETER * 2);
|
|
109
|
+
ctx.fillStyle = '#ff0080';
|
|
110
|
+
ctx.fill();
|
|
111
|
+
|
|
112
|
+
var border = 6;
|
|
113
|
+
ctx.beginPath();
|
|
114
|
+
ctx.arc(0, 0, Taiko.DIAMETER / 2, -Math.PI, Math.PI);
|
|
115
|
+
ctx.fillStyle = 'rgba(255,255,255,.2)';
|
|
116
|
+
ctx.fill();
|
|
117
|
+
ctx.strokeStyle = 'rgba(255,255,255,.2)';
|
|
118
|
+
ctx.lineWidth = border;
|
|
119
|
+
ctx.stroke();
|
|
120
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Math.hypot = Math.hypot || function()
|
|
2
|
+
{
|
|
3
|
+
var power = 0;
|
|
4
|
+
for (var i = 0; i < arguments.length; i++)
|
|
5
|
+
{
|
|
6
|
+
power += arguments[i] * arguments[i];
|
|
7
|
+
}
|
|
8
|
+
return Math.sqrt(power);
|
|
9
|
+
};
|
|
10
|
+
Math.lerp = Math.lerp || function(a, b, t)
|
|
11
|
+
{
|
|
12
|
+
if (a instanceof Point)
|
|
13
|
+
{
|
|
14
|
+
return new Point(Math.lerp(a.x, b.x, t), Math.lerp(a.y, b.y, t));
|
|
15
|
+
}
|
|
16
|
+
return a + (b - a) * t;
|
|
17
|
+
};
|
|
18
|
+
/** Calculate point C's direction by line AB
|
|
19
|
+
* @return {Number}
|
|
20
|
+
* 1 C is counter-clockwise to AB
|
|
21
|
+
* 0 C is parallel to AB
|
|
22
|
+
* -1 C is clockwise to AB
|
|
23
|
+
*/
|
|
24
|
+
Math.ccw = function(a, b, c)
|
|
25
|
+
{
|
|
26
|
+
var ret = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
|
|
27
|
+
if (ret > 0)
|
|
28
|
+
{
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
if (ret < 0)
|
|
32
|
+
{
|
|
33
|
+
return -1;
|
|
34
|
+
}
|
|
35
|
+
return 0;
|
|
36
|
+
};
|
|
37
|
+
Math.clamp = function(num, min, max) {
|
|
38
|
+
if (num < min) return min;
|
|
39
|
+
if (num > max) return max;
|
|
40
|
+
return num;
|
|
41
|
+
}
|
|
42
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Polyfill
|
|
43
|
+
if (!HTMLCanvasElement.prototype.toBlob)
|
|
44
|
+
{
|
|
45
|
+
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
|
|
46
|
+
value: function (callback, type, quality)
|
|
47
|
+
{
|
|
48
|
+
|
|
49
|
+
var binStr = atob(this.toDataURL(type, quality).split(',')[1]),
|
|
50
|
+
len = binStr.length,
|
|
51
|
+
arr = new Uint8Array(len);
|
|
52
|
+
|
|
53
|
+
for (var i = 0; i < len; i++)
|
|
54
|
+
{
|
|
55
|
+
arr[i] = binStr.charCodeAt(i);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
callback(new Blob([ arr ], { type: type || 'image/png' }));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
7
|
+
<meta name="robots" content="nofollow, noindex, noarchive">
|
|
8
|
+
<title>gif生成测试 网址后加#bid</title>
|
|
9
|
+
</head>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
<body class="h">
|
|
13
|
+
<img id="img"></img>
|
|
14
|
+
|
|
15
|
+
<script src="js/util.js"></script>
|
|
16
|
+
|
|
17
|
+
<script src="js/beatmap/beatmap.js"></script>
|
|
18
|
+
<script src="js/beatmap/timingpoint.js"></script>
|
|
19
|
+
<script src="js/beatmap/hitobject.js"></script>
|
|
20
|
+
<script src="js/beatmap/point.js"></script>
|
|
21
|
+
<script src="js/beatmap/scroll.js"></script>
|
|
22
|
+
|
|
23
|
+
<script src="js/standard/standard.js"></script>
|
|
24
|
+
<script src="js/standard/hitcircle.js"></script>
|
|
25
|
+
<script src="js/standard/slider.js"></script>
|
|
26
|
+
<script src="js/standard/curve/curve.js"></script>
|
|
27
|
+
<script src="js/standard/curve/equaldistancemulticurve.js"></script>
|
|
28
|
+
<script src="js/standard/curve/linearbezier.js"></script>
|
|
29
|
+
<script src="js/standard/curve/catmullcurve.js"></script>
|
|
30
|
+
<script src="js/standard/curve/curvetype.js"></script>
|
|
31
|
+
<script src="js/standard/curve/bezier2.js"></script>
|
|
32
|
+
<script src="js/standard/curve/centripetalcatmullrom.js"></script>
|
|
33
|
+
<script src="js/standard/curve/circumstancedcircle.js"></script>
|
|
34
|
+
<script src="js/standard/spinner.js"></script>
|
|
35
|
+
|
|
36
|
+
<script src="js/taiko/taiko.js"></script>
|
|
37
|
+
<script src="js/taiko/donkat.js"></script>
|
|
38
|
+
<script src="js/taiko/drumroll.js"></script>
|
|
39
|
+
<script src="js/taiko/shaker.js"></script>
|
|
40
|
+
|
|
41
|
+
<script src="js/catch/LegacyRandom.js"></script>
|
|
42
|
+
<script src="js/catch/catch.js"></script>
|
|
43
|
+
<script src="js/catch/fruit.js"></script>
|
|
44
|
+
<script src="js/catch/bananashower.js"></script>
|
|
45
|
+
<script src="js/catch/juicestream.js"></script>
|
|
46
|
+
<script src="js/catch/PalpableCatchHitObject.js"></script>
|
|
47
|
+
|
|
48
|
+
<script src="js/mania/mania.js"></script>
|
|
49
|
+
<script src="js/mania/hitnote.js"></script>
|
|
50
|
+
<script src="js/mania/holdnote.js"></script>
|
|
51
|
+
|
|
52
|
+
<script src="js/preview.js"></script>
|
|
53
|
+
<script src="gif.js/gif.js"></script>
|
|
54
|
+
|
|
55
|
+
<script>
|
|
56
|
+
const scaleValue = 0.2;
|
|
57
|
+
const durationValue = 10000;
|
|
58
|
+
const qualityValue = 10;
|
|
59
|
+
const timeSpanValue = 50;
|
|
60
|
+
|
|
61
|
+
const createImg = function () {
|
|
62
|
+
let preview = new Preview(scaleValue);
|
|
63
|
+
const osufile = {{ osu_file|tojson }};
|
|
64
|
+
preview.load(osufile, function () {
|
|
65
|
+
let actualStartTime;
|
|
66
|
+
const previewEndTime = preview.previewTime + durationValue;
|
|
67
|
+
if (previewEndTime <= preview.endTime) {
|
|
68
|
+
// 使用谱面预览时间
|
|
69
|
+
actualStartTime = preview.previewTime;
|
|
70
|
+
} else {
|
|
71
|
+
// 预览时间加上持续时间超过谱面结束时间,使用用户指定的开始时间
|
|
72
|
+
actualStartTime = preview.startTime;
|
|
73
|
+
}
|
|
74
|
+
const actualEndTime = durationValue === -1 ? preview.endTime : Math.min(actualStartTime + durationValue, preview.endTime);
|
|
75
|
+
let gif = new GIF({
|
|
76
|
+
workers: 4,
|
|
77
|
+
workerScript: './gif.js/gif.worker.js',
|
|
78
|
+
quality: qualityValue,
|
|
79
|
+
width: preview.screen.width * scaleValue,
|
|
80
|
+
height: preview.screen.height * scaleValue,
|
|
81
|
+
//transparent: "0x000000",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const totalFrames = Math.ceil((actualEndTime - actualStartTime) / timeSpanValue);
|
|
85
|
+
let currentFrame = 0;
|
|
86
|
+
|
|
87
|
+
// 添加帧
|
|
88
|
+
while (currentFrame <= totalFrames) {
|
|
89
|
+
const t = actualStartTime + currentFrame * timeSpanValue;
|
|
90
|
+
preview.at(t);
|
|
91
|
+
|
|
92
|
+
gif.addFrame(preview.ctx, {
|
|
93
|
+
copy: true,
|
|
94
|
+
delay: timeSpanValue
|
|
95
|
+
});
|
|
96
|
+
currentFrame++;
|
|
97
|
+
}
|
|
98
|
+
gif.on('finished', function (blob) {
|
|
99
|
+
const url = URL.createObjectURL(blob);
|
|
100
|
+
const img = document.createElement('img');
|
|
101
|
+
img.id = 'img';
|
|
102
|
+
img.src = url;
|
|
103
|
+
img.alt = '生成的GIF预览';
|
|
104
|
+
});
|
|
105
|
+
gif.render();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
window.addEventListener('hashchange', createImg);
|
|
110
|
+
|
|
111
|
+
createImg();
|
|
112
|
+
</script>
|
|
113
|
+
</body>
|
|
114
|
+
|
|
115
|
+
</html>
|
|
@@ -107,7 +107,7 @@ async def draw_score(
|
|
|
107
107
|
map_json = await task2
|
|
108
108
|
# 判断是否开启lazer模式
|
|
109
109
|
if source == "osu":
|
|
110
|
-
score = cal_score_info(is_lazer, score)
|
|
110
|
+
score = cal_score_info(is_lazer, score, source)
|
|
111
111
|
return await draw_score_pic(score, info, map_json, "", is_lazer, source)
|
|
112
112
|
|
|
113
113
|
|
|
@@ -180,7 +180,7 @@ async def get_score_data(
|
|
|
180
180
|
user_path.mkdir(parents=True, exist_ok=True)
|
|
181
181
|
# 判断是否开启lazer模式
|
|
182
182
|
if source == "osu":
|
|
183
|
-
score = cal_score_info(is_lazer, score)
|
|
183
|
+
score = cal_score_info(is_lazer, score, source)
|
|
184
184
|
return await draw_score_pic(score, info, map_json, grank, is_lazer, source)
|
|
185
185
|
|
|
186
186
|
|
|
@@ -795,10 +795,10 @@ def cal_legacy_rank(score_info: UnifiedScore, is_hidden: bool):
|
|
|
795
795
|
return "N/A"
|
|
796
796
|
|
|
797
797
|
|
|
798
|
-
def cal_score_info(is_lazer: bool, score_info: UnifiedScore) -> UnifiedScore:
|
|
798
|
+
def cal_score_info(is_lazer: bool, score_info: UnifiedScore, source: str = "osu") -> UnifiedScore:
|
|
799
799
|
if is_lazer:
|
|
800
800
|
score_info.legacy_total_score = score_info.total_score
|
|
801
|
-
if score_info.ruleset_id == 3 and not is_lazer:
|
|
801
|
+
if score_info.ruleset_id == 3 and not is_lazer and source != "ppysb":
|
|
802
802
|
score_info.accuracy = cal_legacy_acc(score_info.statistics)
|
|
803
803
|
if not is_lazer:
|
|
804
804
|
is_hidden = any(i in score_info.mods for i in (Mod(acronym="HD"), Mod(acronym="FL"), Mod(acronym="FI")))
|
nonebot_plugin_osubot/file.py
CHANGED
|
@@ -47,18 +47,6 @@ async def download_map(setid: int) -> Optional[Path]:
|
|
|
47
47
|
return filepath
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
async def download_tmp_osu(map_id):
|
|
51
|
-
url = f"https://osu.ppy.sh/osu/{map_id}"
|
|
52
|
-
logger.info(f"开始下载谱面: <{map_id}>")
|
|
53
|
-
req = await safe_async_get(url)
|
|
54
|
-
filename = f"{map_id}.osu"
|
|
55
|
-
filepath = map_path / filename
|
|
56
|
-
chunk = req.read()
|
|
57
|
-
with open(filepath, "wb") as f:
|
|
58
|
-
f.write(chunk)
|
|
59
|
-
return filepath
|
|
60
|
-
|
|
61
|
-
|
|
62
50
|
@auto_retry
|
|
63
51
|
async def download_osu(set_id, map_id):
|
|
64
52
|
url = [
|
|
@@ -71,6 +59,7 @@ async def download_osu(set_id, map_id):
|
|
|
71
59
|
if req := await get_first_response(url):
|
|
72
60
|
filename = f"{map_id}.osu"
|
|
73
61
|
filepath = map_path / str(set_id) / filename
|
|
62
|
+
filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
74
63
|
with open(filepath, "wb") as f:
|
|
75
64
|
f.write(req)
|
|
76
65
|
return filepath
|
|
@@ -25,7 +25,7 @@ from reamber.algorithms.playField.parts import (
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
from ..file import download_map
|
|
28
|
-
from ..schema import
|
|
28
|
+
from ..schema.beatmapsets import BeatmapSets
|
|
29
29
|
|
|
30
30
|
osu_path = Path() / "data" / "osu"
|
|
31
31
|
if not osu_path.exists():
|
|
@@ -39,7 +39,7 @@ class Options:
|
|
|
39
39
|
od: Optional[float]
|
|
40
40
|
set: Optional[int]
|
|
41
41
|
map: Optional[int] = None
|
|
42
|
-
|
|
42
|
+
beatmapsets: Optional[BeatmapSets] = None
|
|
43
43
|
nsv: bool = False
|
|
44
44
|
nln: bool = False
|
|
45
45
|
fln: bool = False
|
|
@@ -89,15 +89,14 @@ async def convert_mania_map(options: Options) -> Optional[Path]:
|
|
|
89
89
|
with ZipFile(osz_file.absolute()) as my_zip:
|
|
90
90
|
my_zip.extractall(path)
|
|
91
91
|
os.remove(osz_file)
|
|
92
|
-
if options.
|
|
93
|
-
for
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
if options.beatmapsets:
|
|
93
|
+
for file in path.rglob("*.osu"):
|
|
94
|
+
osu = OsuMap.read_file(str(file.absolute()))
|
|
95
|
+
if osu.beatmap_id == options.map:
|
|
96
|
+
audio_file_name = osu.audio_file_name
|
|
97
|
+
audio_name = osu.audio_file_name[:-4]
|
|
98
|
+
audio_type = osu.audio_file_name[-4:]
|
|
98
99
|
break
|
|
99
|
-
else:
|
|
100
|
-
raise Exception("小夜api有问题啊")
|
|
101
100
|
if options.rate:
|
|
102
101
|
if options.rate > 10:
|
|
103
102
|
options.rate = 10
|
|
@@ -42,7 +42,6 @@ async def _(event: Event, state: T_State):
|
|
|
42
42
|
f"在查找用户:{state['username']} {NGM[state['mode']]}模式 {lazer_mode}时 {str(e)}"
|
|
43
43
|
).finish(reply_to=True)
|
|
44
44
|
for score in score_ls:
|
|
45
|
-
# Filter mods outside of the iteration
|
|
46
45
|
if not state["is_lazer"] or state["source"] == "ppysb":
|
|
47
46
|
score.mods = [mod for mod in score.mods if mod.acronym != "CL"]
|
|
48
47
|
for mod in score.mods:
|
|
@@ -94,14 +93,15 @@ async def _(event: Event, state: T_State):
|
|
|
94
93
|
pp_data.append({"name": mod, "value": round(pp, 2)})
|
|
95
94
|
mapper_pp = defaultdict(int)
|
|
96
95
|
for num, i in enumerate(score_ls):
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
mapper_pp = mapper_pp[:9]
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
key = i.beatmap.creator if state["source"] == "ppysb" else i.beatmap.user_id
|
|
97
|
+
mapper_pp[key] += i.pp * 0.95**num
|
|
98
|
+
mapper_pp = sorted(mapper_pp.items(), key=lambda x: x[1], reverse=True)[:9]
|
|
99
|
+
if state["source"] == "ppysb":
|
|
100
|
+
mapper_pp_data = [{"name": mapper, "value": round(pp, 2)} for mapper, pp in mapper_pp]
|
|
101
|
+
else:
|
|
102
|
+
users = await get_users([i[0] for i in mapper_pp])
|
|
103
|
+
user_dic = {i.id: i.username for i in users}
|
|
104
|
+
mapper_pp_data = [{"name": user_dic.get(mapper, ""), "value": round(pp, 2)} for mapper, pp in mapper_pp]
|
|
105
105
|
if len(mapper_pp_data) > 20:
|
|
106
106
|
mapper_pp_data = mapper_pp_data[:20]
|
|
107
107
|
name = f"{state['username']} {NGM[state['mode']]} 模式 "
|
|
@@ -26,7 +26,7 @@ from ..exceptions import NetworkError
|
|
|
26
26
|
from ..database.models import UserData
|
|
27
27
|
from ..mania import generate_preview_pic
|
|
28
28
|
from ..api import safe_async_get, get_user_scores
|
|
29
|
-
from ..file import map_path,
|
|
29
|
+
from ..file import map_path, download_osu
|
|
30
30
|
from ..draw.catch_preview import draw_cath_preview
|
|
31
31
|
|
|
32
32
|
games: dict[str, NewScore] = {}
|
|
@@ -470,10 +470,10 @@ async def _(
|
|
|
470
470
|
chart_games[session_id] = selected_score
|
|
471
471
|
chart_set_timeout(matcher, session_id)
|
|
472
472
|
if mode == "3":
|
|
473
|
-
osu = await
|
|
473
|
+
osu = await download_osu(selected_score.beatmapset.id, selected_score.beatmap.id)
|
|
474
474
|
pic = await generate_preview_pic(osu)
|
|
475
475
|
elif mode == "1":
|
|
476
|
-
osu = await
|
|
476
|
+
osu = await download_osu(selected_score.beatmapset.id, selected_score.beatmap.id)
|
|
477
477
|
beatmap = parse_map(osu)
|
|
478
478
|
pic = map_to_image(beatmap)
|
|
479
479
|
else:
|
|
@@ -7,8 +7,9 @@ from nonebot import on_command, on_shell_command
|
|
|
7
7
|
from nonebot.exception import ParserExit, ActionFailed
|
|
8
8
|
from nonebot.params import CommandArg, ShellCommandArgv
|
|
9
9
|
|
|
10
|
-
from ..api import
|
|
10
|
+
from ..api import get_beatmapsets_info, osu_api
|
|
11
11
|
from ..mania import Options, convert_mania_map
|
|
12
|
+
from ..schema import Beatmap
|
|
12
13
|
|
|
13
14
|
parser = ArgumentParser("convert", description="变换mania谱面")
|
|
14
15
|
parser.add_argument("--set", type=int, help="要转换的谱面的setid")
|
|
@@ -37,9 +38,11 @@ async def _(argv: list[str] = ShellCommandArgv()):
|
|
|
37
38
|
return
|
|
38
39
|
options = Options(**vars(args))
|
|
39
40
|
if options.map:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
map_data = await osu_api("map", options.map)
|
|
42
|
+
mapinfo = Beatmap(**map_data)
|
|
43
|
+
beatmapsets_info = await get_beatmapsets_info(mapinfo.beatmapset_id)
|
|
44
|
+
options.set = mapinfo.beatmapset_id
|
|
45
|
+
options.beatmapsets = beatmapsets_info
|
|
43
46
|
if not options.set:
|
|
44
47
|
await UniMessage.text("请提供需要转换的谱面setid").finish(reply_to=True)
|
|
45
48
|
if options.nln and options.fln:
|
|
@@ -85,9 +88,11 @@ async def _(msg: Message = CommandArg()):
|
|
|
85
88
|
args = parser.parse_args(argv)
|
|
86
89
|
options = Options(**vars(args))
|
|
87
90
|
if options.map:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
map_data = await osu_api("map", options.map)
|
|
92
|
+
mapinfo = Beatmap(**map_data)
|
|
93
|
+
beatmapsets_info = await get_beatmapsets_info(mapinfo.beatmapset_id)
|
|
94
|
+
options.set = mapinfo.beatmapset_id
|
|
95
|
+
options.beatmapsets = beatmapsets_info
|
|
91
96
|
osz_path = await convert_mania_map(options)
|
|
92
97
|
if not osz_path:
|
|
93
98
|
await UniMessage.text("未找到该地图,请检查是否搞混了mapID与setID").finish(reply_to=True)
|
|
@@ -5,9 +5,10 @@ from nonebot_plugin_alconna import UniMessage
|
|
|
5
5
|
from ..utils import NGM
|
|
6
6
|
from ..api import osu_api
|
|
7
7
|
from .utils import split_msg
|
|
8
|
-
from ..file import
|
|
8
|
+
from ..file import download_osu
|
|
9
9
|
from ..exceptions import NetworkError
|
|
10
10
|
from ..mania import generate_preview_pic
|
|
11
|
+
from ..draw.osu_preview import draw_osu_preview
|
|
11
12
|
from ..draw.catch_preview import draw_cath_preview
|
|
12
13
|
from ..draw.taiko_preview import parse_map, map_to_image
|
|
13
14
|
|
|
@@ -24,7 +25,7 @@ async def _(state: T_State):
|
|
|
24
25
|
except NetworkError as e:
|
|
25
26
|
await UniMessage.text(f"查找map_id:{osu_id} 信息时 {str(e)}").finish(reply_to=True)
|
|
26
27
|
if state["mode"] == "3":
|
|
27
|
-
osu = await
|
|
28
|
+
osu = await download_osu(data["beatmapset_id"], int(osu_id))
|
|
28
29
|
if state["_prefix"]["command"][0] == "完整预览":
|
|
29
30
|
pic = await generate_preview_pic(osu, True)
|
|
30
31
|
else:
|
|
@@ -34,10 +35,16 @@ async def _(state: T_State):
|
|
|
34
35
|
pic = await draw_cath_preview(int(osu_id), data["beatmapset_id"], state["mods"])
|
|
35
36
|
await UniMessage.image(raw=pic).finish(reply_to=True)
|
|
36
37
|
elif state["mode"] == "1":
|
|
37
|
-
osu = await
|
|
38
|
+
osu = await download_osu(data["beatmapset_id"], int(osu_id))
|
|
38
39
|
beatmap = parse_map(osu)
|
|
39
40
|
pic = map_to_image(beatmap)
|
|
40
41
|
await UniMessage.image(raw=pic).finish(reply_to=True)
|
|
42
|
+
elif state["mode"] == "0":
|
|
43
|
+
pic = await draw_osu_preview(int(osu_id), data["beatmapset_id"])
|
|
44
|
+
msg = UniMessage.image(raw=pic) + UniMessage.text(
|
|
45
|
+
f"点击预览:\nhttps://beatmap.try-z.net/?b={osu_id}\nhttps://beatmap.try-z.net/dev/?b={osu_id}"
|
|
46
|
+
)
|
|
47
|
+
await msg.finish(reply_to=True)
|
|
41
48
|
elif not (0 <= int(state["mode"]) <= 3):
|
|
42
49
|
await UniMessage.text("模式应为0-3!\n0: std\n1:taiko\n2:ctb\n3: mania").finish()
|
|
43
50
|
else:
|
|
@@ -2,14 +2,14 @@ import re
|
|
|
2
2
|
from random import shuffle
|
|
3
3
|
|
|
4
4
|
from nonebot import on_command
|
|
5
|
-
from nonebot.log import logger
|
|
6
5
|
from nonebot.typing import T_State
|
|
7
6
|
from expiringdict import ExpiringDict
|
|
8
7
|
from nonebot.internal.matcher import Matcher
|
|
9
8
|
from nonebot_plugin_alconna import UniMessage
|
|
10
9
|
|
|
11
10
|
from .utils import split_msg
|
|
12
|
-
from ..api import get_recommend, update_recommend,
|
|
11
|
+
from ..api import get_recommend, update_recommend, osu_api
|
|
12
|
+
from ..schema import Beatmap
|
|
13
13
|
|
|
14
14
|
recommend = on_command("推荐", priority=11, block=True, aliases={"recommend", "推荐铺面", "推荐谱面"})
|
|
15
15
|
recommend_cache = ExpiringDict(1000, 60 * 60 * 12)
|
|
@@ -41,23 +41,18 @@ async def handle_recommend(state: T_State, matcher: type[Matcher]):
|
|
|
41
41
|
break
|
|
42
42
|
else:
|
|
43
43
|
await matcher.finish("今天已经没有可以推荐的图啦,明天再来吧")
|
|
44
|
+
return None
|
|
44
45
|
bid = int(re.findall("https://osu.ppy.sh/beatmaps/(.*)", recommend_map.mapLink)[0])
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if i.bid == bid:
|
|
49
|
-
bg = i.bg
|
|
50
|
-
break
|
|
51
|
-
else:
|
|
52
|
-
bg = ""
|
|
53
|
-
logger.error(f"出现问题: 有问题的是{bid}, {sid}")
|
|
46
|
+
map_data = await osu_api("map", bid)
|
|
47
|
+
map_info = Beatmap(**map_data)
|
|
48
|
+
sid = map_info.beatmapset_id
|
|
54
49
|
s = (
|
|
55
50
|
f"推荐的铺面是{recommend_map.mapName} ⭐{round(recommend_map.difficulty, 2)}\n{''.join(recommend_map.mod)}\n"
|
|
56
51
|
f"预计pp为{round(recommend_map.predictPP, 2)}\n提升概率为{round(recommend_map.passPercent * 100, 2)}%\n"
|
|
57
52
|
f"{recommend_map.mapLink}\nhttps://kitsu.moe/api/d/{sid}\n"
|
|
58
53
|
f"https://txy1.sayobot.cn/beatmaps/download/novideo/{sid}"
|
|
59
54
|
)
|
|
60
|
-
pic_url = f"https://
|
|
55
|
+
pic_url = f"https://osu.direct/api/media/background/{bid}"
|
|
61
56
|
return pic_url, s
|
|
62
57
|
|
|
63
58
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
nonebot_plugin_osubot/pp.py
CHANGED
|
@@ -3,6 +3,7 @@ import importlib.metadata
|
|
|
3
3
|
|
|
4
4
|
from rosu_pp_py import Beatmap, Strains, GameMode, Performance, PerformanceAttributes
|
|
5
5
|
|
|
6
|
+
from .exceptions import NetworkError
|
|
6
7
|
from .schema.score import UnifiedScore
|
|
7
8
|
|
|
8
9
|
is_v2 = importlib.metadata.version("pydantic").startswith("2")
|
|
@@ -10,6 +11,8 @@ is_v2 = importlib.metadata.version("pydantic").startswith("2")
|
|
|
10
11
|
|
|
11
12
|
def cal_pp(score: UnifiedScore, path: str, is_lazer: bool) -> PerformanceAttributes:
|
|
12
13
|
beatmap = Beatmap(path=path)
|
|
14
|
+
if beatmap.is_suspicious():
|
|
15
|
+
raise NetworkError("这似乎不是一个正常谱面 OAO")
|
|
13
16
|
convert_mode(score, beatmap)
|
|
14
17
|
c = Performance(
|
|
15
18
|
accuracy=score.accuracy,
|
|
@@ -31,6 +34,8 @@ def cal_pp(score: UnifiedScore, path: str, is_lazer: bool) -> PerformanceAttribu
|
|
|
31
34
|
|
|
32
35
|
def get_if_pp_ss_pp(score: UnifiedScore, path: str, is_lazer: bool) -> tuple:
|
|
33
36
|
beatmap = Beatmap(path=path)
|
|
37
|
+
if beatmap.is_suspicious():
|
|
38
|
+
return "nan", "nan"
|
|
34
39
|
convert_mode(score, beatmap)
|
|
35
40
|
total = beatmap.n_objects
|
|
36
41
|
passed = score.statistics.great + score.statistics.miss + score.statistics.ok + score.statistics.meh
|
|
@@ -62,6 +67,8 @@ def get_if_pp_ss_pp(score: UnifiedScore, path: str, is_lazer: bool) -> tuple:
|
|
|
62
67
|
|
|
63
68
|
def get_ss_pp(path: str, mods: int, is_lazer) -> PerformanceAttributes:
|
|
64
69
|
beatmap = Beatmap(path=path)
|
|
70
|
+
if beatmap.is_suspicious():
|
|
71
|
+
raise NetworkError("这似乎不是一个正常谱面 OAO")
|
|
65
72
|
c = Performance(accuracy=100, mods=mods, lazer=is_lazer)
|
|
66
73
|
ss_pp_info = c.calculate(beatmap)
|
|
67
74
|
return ss_pp_info
|