- Sources: "free" (Creative Commons songs with media from github.com/UltraStar-Deluxe/songs) and "usdb" (usdb.animux.de with an account; audio/video via yt-dlp from the song's #VIDEO hints or YouTube links in the comments, covers from fanart.tv/YouTube) - Aggregated search (all sources in parallel, in-library flag), download queue into <library>/Downloads/<source>/<Artist - Title>, then rescan - Web UI in wwwroot (plain JS, no build): search, downloads with progress, library; phone first, dark mode, installable - Docker image with yt-dlp, ffmpeg and deno; library mounted writable - Tests for matching, USDB parsing and song rewriting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
4.4 KiB
C#
86 lines
4.4 KiB
C#
#region license
|
||
// This file is part of Vocaluxe.
|
||
//
|
||
// Vocaluxe is free software: you can redistribute it and/or modify
|
||
// it under the terms of the GNU General Public License as published by
|
||
// the Free Software Foundation, either version 3 of the License, or
|
||
// (at your option) any later version.
|
||
//
|
||
// Vocaluxe is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
// GNU General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU General Public License
|
||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||
#endregion
|
||
|
||
extern alias songserver;
|
||
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using NUnit.Framework;
|
||
using CSourceHelper = songserver::VocaluxeSongServer.Sources.CSourceHelper;
|
||
using CUsdbSongSource = songserver::VocaluxeSongServer.Sources.CUsdbSongSource;
|
||
using CYtDlp = songserver::VocaluxeSongServer.Sources.CYtDlp;
|
||
|
||
namespace Tests.SongServer
|
||
{
|
||
[TestFixture]
|
||
public class CSongSourcesTest
|
||
{
|
||
[Test]
|
||
public void TestNormalizeAndMatch()
|
||
{
|
||
Assert.That(CSourceHelper.Normalize("Beyoncé – Halo!"), Is.EqualTo("beyonce halo"));
|
||
Assert.That(CSourceHelper.Matches("halo beyonce", "Beyoncé - Halo"), Is.True);
|
||
Assert.That(CSourceHelper.Matches("hal", "Beyoncé - Halo"), Is.True, "prefix of a word");
|
||
Assert.That(CSourceHelper.Matches("queen", "Beyoncé - Halo"), Is.False);
|
||
Assert.That(CSourceHelper.SafeName("AC/DC: Back in Black?"), Is.EqualTo("AC_DC_ Back in Black_"));
|
||
}
|
||
|
||
[Test]
|
||
public void TestUsdbList()
|
||
{
|
||
// Shape of usdb.animux.de "link=list" with details=1 (sample and cover cells have no text)
|
||
const string html = @"<table>
|
||
<tr class=""list_tr1"" data-songid=""1234"" data-lastchange=""1700000000"">
|
||
<td><audio><source src=""x.mp3""></audio></td><td><img src=""data/cover/1234.jpg""></td>
|
||
<td><a href=""?link=byartist"">Queen</a></td><td><a href=""?link=detail&id=1234"">Don't Stop Me Now</a></td>
|
||
<td>Rock</td><td>1978</td><td>SingStar</td><td>Yes</td><td>English</td><td>someone</td><td>5</td><td>1000</td>
|
||
</tr>
|
||
<tr class=""list_tr2"" data-songid=""99""><td></td><td></td><td>ABBA</td><td>Waterloo</td><td></td><td></td></tr>
|
||
</table>";
|
||
var results = CUsdbSongSource.ParseList(html);
|
||
Assert.That(results.Select(r => r.SourceId), Is.EqualTo(new[] { "1234", "99" }));
|
||
Assert.That(results[0].Artist, Is.EqualTo("Queen"));
|
||
Assert.That(results[0].Title, Is.EqualTo("Don't Stop Me Now"));
|
||
Assert.That(results[0].Details, Does.Contain("1978"));
|
||
Assert.That(results[1].Title, Is.EqualTo("Waterloo"));
|
||
}
|
||
|
||
[Test]
|
||
public void TestVideoTagAndImages()
|
||
{
|
||
var hints = CUsdbSongSource.ParseVideoTag("v=dQw4w9WgXcQ,a=https://youtu.be/aaaaaaaaaaa,co=artist/123/cover.jpg,bg=12345.jpg,co-rotate=5");
|
||
Assert.That(hints.Video, Is.EqualTo("dQw4w9WgXcQ"));
|
||
Assert.That(CYtDlp.YouTubeId(hints.Audio!), Is.EqualTo("aaaaaaaaaaa"));
|
||
Assert.That(CUsdbSongSource.ImageUrl(hints.Cover!), Is.EqualTo("https://artist/123/cover.jpg"));
|
||
Assert.That(CUsdbSongSource.ImageUrl(hints.Background!), Is.EqualTo("https://assets.fanart.tv/fanart/12345.jpg"));
|
||
Assert.That(CUsdbSongSource.ImageUrl("https://images.fanart.tv/x.jpg"), Is.EqualTo("https://assets.fanart.tv/x.jpg"));
|
||
Assert.That(CUsdbSongSource.ParseVideoTag("Queen - Song.mp4").Video, Is.Null, "a plain file name is no hint");
|
||
|
||
Assert.That(CYtDlp.FindYouTubeIds("see <a href=\"https://www.youtube.com/watch?v=abcdefghijk&t=1\">x</a> or youtu.be/abcdefghijk and https://youtube.com/embed/ZZZZZZZZZZZ"),
|
||
Is.EqualTo(new[] { "abcdefghijk", "ZZZZZZZZZZZ" }));
|
||
}
|
||
|
||
[Test]
|
||
public void TestRewriteSong()
|
||
{
|
||
const string text = "#TITLE:Song\r\n#ARTIST:Band\r\n#MP3:Band - Song.mp3\r\n#VIDEO:v=dQw4w9WgXcQ,co=1.jpg\r\n#BPM:300\r\n: 0 4 5 La\r\nE\r\n";
|
||
var result = CUsdbSongSource.RewriteSong(text, new Dictionary<string, string?> { ["MP3"] = "audio.m4a", ["VIDEO"] = "video.mp4", ["COVER"] = null });
|
||
Assert.That(result, Is.EqualTo("#TITLE:Song\n#ARTIST:Band\n#BPM:300\n#MP3:audio.m4a\n#VIDEO:video.mp4\n: 0 4 5 La\nE\n"));
|
||
}
|
||
}
|
||
}
|