This commit is contained in:
ju09279
2024-08-11 21:55:11 +02:00
commit c3c4de3c44
68 changed files with 5993 additions and 0 deletions

3
backend/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.vs/
bin/
obj/

135
backend/Program.cs Normal file
View File

@@ -0,0 +1,135 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMemoryCache();
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll",
policy =>
{
policy.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseCors("AllowAll");
app.MapGet("/ping", () => "pong");
// Define the API routes
app.MapGet("/api/v1/songs/{hash}", (string hash) =>
{
return Results.Ok(new { hash });
});
app.MapGet("/api/v1/songs/recent", (int? limit, int? offset) =>
{
var limitValue = limit ?? 100; // default to 10 if not provided
var offsetValue = offset ?? 0; // default to 0 if not provided
return Results.Json(Osudb.Instance.GetRecent(limitValue, offsetValue));
});
app.MapGet("/api/v1/songs/favorite", (int? limit, int? offset) =>
{
var limitValue = limit ?? 10; // default to 10 if not provided
var offsetValue = offset ?? 0; // default to 0 if not provided
return Results.Ok(new { Limit = limitValue, Offset = offsetValue, Message = "List of favorite songs" });
});
app.MapGet("/api/v1/songs/{hash}", (string hash) =>
{
return Results.Ok($"Details for song with hash {hash}");
});
app.MapGet("/api/v1/collections/", async (int? limit, int? offset, [FromServices] IMemoryCache cache) =>
{
const string cacheKey = "collections";
if (!cache.TryGetValue(cacheKey, out var collections))
{
collections = Osudb.Instance.GetCollections();
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromDays(1))
.SetAbsoluteExpiration(TimeSpan.FromDays(3));
cache.Set(cacheKey, collections, cacheEntryOptions);
}
return Results.Json(collections);
});
app.MapGet("/api/v1/collection/{index}", (int index) =>
{
return Results.Json(Osudb.Instance.GetCollection(index));
});
app.MapGet("/api/v1/audio/{*fileName}", async (string fileName, HttpContext context) =>
{
var decodedFileName = Uri.UnescapeDataString(fileName);
var filePath = Path.Combine(Osudb.osufolder, "Songs", decodedFileName);
if (!System.IO.File.Exists(filePath))
{
Console.WriteLine($"Not Found: {filePath}");
return Results.NotFound();
}
var fileExtension = Path.GetExtension(filePath).ToLowerInvariant();
var contentType = fileExtension switch
{
".mp3" => "audio/mpeg",
".wav" => "audio/wav",
".ogg" => "audio/ogg",
_ => "application/octet-stream",
};
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
return Results.Stream(fileStream, contentType, enableRangeProcessing: true);
});
app.MapGet("/api/v1/images/{*filename}", async (string filename) =>
{
var decodedFileName = Uri.UnescapeDataString(filename);
var filePath = Path.Combine(Osudb.osufolder, "Songs", decodedFileName);
if (!System.IO.File.Exists(filePath))
{
Console.WriteLine($"Not Found: {filePath}");
return Results.NotFound();
}
var fileExtension = Path.GetExtension(filePath).ToLowerInvariant();
var contentType = fileExtension switch
{
".jpg" or ".jpeg" => "image/jpeg",
".png" => "image/png",
".gif" => "image/gif",
".bmp" => "image/bmp",
".webp" => "image/webp",
_ => "application/octet-stream",
};
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, useAsync: true);
return Results.Stream(fileStream, contentType, filename);
});
app.Run();

View File

@@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:45205",
"sslPort": 44305
}
},
"profiles": {
"shitweb": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7254;http://localhost:5153",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
backend/appsettings.json Normal file
View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

216
backend/osudb.cs Normal file
View File

@@ -0,0 +1,216 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using OsuParsers.Beatmaps;
using OsuParsers.Database;
using OsuParsers.Database.Objects;
using System.Collections;
using System.Net;
using System.Text.RegularExpressions;
public class Osudb
{
private static Osudb instance = null;
private static readonly object padlock = new object();
public static string osufolder { get; private set; }
public static OsuDatabase osuDatabase { get; private set; }
public static CollectionDatabase CollectionDb { get; private set; }
static Osudb()
{
var key = Registry.GetValue(
@"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\osu\shell\open\command",
"",
null
);
if (key != null)
{
string[] keyparts = key.ToString().Split('"');
osufolder = Path.GetDirectoryName(keyparts[1]);
Parse(osufolder);
}
else throw new Exception("Osu not Installed... ");
}
static void Parse(string filepath)
{
string file = "/osu!.db";
if (File.Exists(filepath + file))
{
using (FileStream fileStream = new FileStream(filepath + file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize: 4096, useAsync: true))
{
Console.WriteLine($"Parsing {file}");
osuDatabase = OsuParsers.Decoders.DatabaseDecoder.DecodeOsu($"{filepath}{file}");
Console.WriteLine($"Parsed {file}");
}
}
file = "/collection.db";
if (File.Exists(filepath + file))
{
using (FileStream fileStream = new FileStream(filepath + file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize: 4096, useAsync: true))
{
Console.WriteLine($"Parsing {file}");
CollectionDb = OsuParsers.Decoders.DatabaseDecoder.DecodeCollection($"{filepath}{file}");
Console.WriteLine($"Parsed {file}");
}
}
}
public static Osudb Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Osudb();
}
return instance;
}
}
}
public DbBeatmap GetBeatmapbyHash(string Hash)
{
if (Hash == null || osuDatabase == null)
{
return null;
}
return osuDatabase.Beatmaps.FirstOrDefault(beatmap => beatmap.MD5Hash == Hash);
}
public static OsuParsers.Database.Objects.Collection GetCollectionbyName(string name) {
return CollectionDb.Collections.FirstOrDefault(collection => collection.Name == name);
}
public static OsuParsers.Database.Objects.Collection GetCollectionbyIndex(int index)
{
return CollectionDb.Collections.ElementAtOrDefault(index);
}
public Collection GetCollection(int index) {
var collection = GetCollectionbyIndex(index);
if (collection == null) { return null; }
List<Song> songs = new List<Song>();
var activeId = 0;
collection.MD5Hashes.ForEach(hash =>
{
var beatmap = GetBeatmapbyHash(hash);
if (beatmap == null) { return; }
if (activeId == beatmap.BeatmapSetId) { return; }
activeId = beatmap.BeatmapSetId;
//todo
string img = getBG(beatmap.FolderName, beatmap.FileName);
songs.Add(new Song(hash: beatmap.MD5Hash, name: beatmap.Title, artist: beatmap.Artist, length: beatmap.TotalTime, url: $"{beatmap.FolderName}/{beatmap.AudioFileName}" , previewimage: img, mapper: beatmap.Creator));
});
return new Collection(collection.Name, songs.Count, songs);
}
public List<CollectionPreview> GetCollections()
{
List<CollectionPreview> collections = new List<CollectionPreview>();
for (int i = 0; i < CollectionDb.Collections.Count; i++) {
var collection = CollectionDb.Collections[i];
var beatmap = GetBeatmapbyHash(collection.MD5Hashes.FirstOrDefault());
//todo
string img = getBG(beatmap.FolderName, beatmap.FileName);
collections.Add(new CollectionPreview(index: i, name: collection.Name, previewimage: img, length: collection.Count));
};
return collections;
}
public List<Song> GetRecent(int limit, int offset)
{
var recent = new List<Song>();
if(limit > 100 && limit < 0) {
limit = 100;
}
var size = osuDatabase.Beatmaps.Count -1;
for (int i = size - offset; i > size - offset - limit; i--)
{
var beatmap = osuDatabase.Beatmaps.ElementAt(i);
if (beatmap == null) {
continue;
}
string img = getBG(beatmap.FolderName, beatmap.FileName);
recent.Add(new Song(
name: beatmap.FileName,
hash: beatmap.MD5Hash,
artist: beatmap.Artist,
length: beatmap.TotalTime,
url: $"{beatmap.FolderName}/{beatmap.AudioFileName}",
previewimage: img,
mapper: beatmap.Creator));
}
return recent;
}
public List<Song> GetFavorites()
{
var recent = new List<Song>();
/*
osuDatabase.Beatmaps.ForEach(beatmap =>
{
Console.WriteLine(beatmap.LastModifiedTime);
});
*/
return null;
}
private static string getBG(string songfolder, string diff)
{
string folderpath = Path.Combine(songfolder, diff);
string filepath = Path.Combine(osufolder, "Songs", folderpath);
if (File.Exists(filepath))
{
string fileContents = File.ReadAllText($@"{filepath}"); // Read the contents of the file
string pattern = @"\d+,\d+,""(?<image_filename>[^""]+\.[a-zA-Z]+)"",\d+,\d+";
Match match = Regex.Match(fileContents, pattern);
if (match.Success)
{
string background = match.Groups["image_filename"].Value;
return Path.Combine(songfolder, background);
}
pattern = @"\d+,\d+,""(?<image_filename>[^""]+\.[a-zA-Z]+)""";
match = Regex.Match(fileContents, pattern);
if (match.Success)
{
string background = match.Groups["image_filename"].Value;
return Path.Combine(songfolder, background);
}
}
return null;
}
}

13
backend/shitweb.csproj Normal file
View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OsuParsers" Version="1.7.1" />
</ItemGroup>
</Project>

25
backend/shitweb.sln Normal file
View File

@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34322.80
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "shitweb", "shitweb.csproj", "{A81ACB49-5C0C-42D5-88DA-3BC7E256F859}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A81ACB49-5C0C-42D5-88DA-3BC7E256F859}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A81ACB49-5C0C-42D5-88DA-3BC7E256F859}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A81ACB49-5C0C-42D5-88DA-3BC7E256F859}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A81ACB49-5C0C-42D5-88DA-3BC7E256F859}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A5EA63AB-B1DD-4171-922C-D01C758AD544}
EndGlobalSection
EndGlobal

40
backend/types.cs Normal file
View File

@@ -0,0 +1,40 @@
public class Song{
public string hash {get; set;}
public string name {get; set;}
public string artist {get; set;}
public int length {get; set;}
public string url { get; set; }
public string previewimage {get; set;}
public string mapper {get; set;}
public Song(string hash, string name, string artist, int length, string url, string previewimage, string mapper) {
this.hash = hash; this.name = name; this.artist = artist; this.length = length; this.url = url; this.previewimage = previewimage; this.mapper = mapper;
}
}
public class CollectionPreview{
public int index { get; set;}
public string name {get; set;}
public int length {get; set;}
public string previewimage {get; set;}
private CollectionPreview() { }
public CollectionPreview(int index, string name, string previewimage, int length) {
this.index = index; this.name = name; this.previewimage = previewimage; this.length = length;
}
}
public class Collection{
public string name {get; set;}
public int length {get; set;}
public List<Song> songs { get; set;}
private Collection() { }
public Collection(string name, int length, List<Song> songs) {
this.name = name; this.length = length; this.songs = songs;
}
}