mirror of
https://github.com/real-zony/ZonyLrcToolsX.git
synced 2025-09-05 21:16:52 +00:00
Compare commits
53 Commits
Alpha.2022
...
ZonyLrcToo
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6c25483f1e | ||
![]() |
b64f83d56b | ||
![]() |
6ad154a62b | ||
![]() |
32adab68b6 | ||
![]() |
ba91108ca4 | ||
![]() |
f597e24ff7 | ||
![]() |
d453d520d4 | ||
![]() |
9f254aae8e | ||
![]() |
c9fa0de95f | ||
![]() |
6d7ee04b74 | ||
![]() |
f519eb1251 | ||
![]() |
85f325b300 | ||
![]() |
140043db79 | ||
![]() |
c583a9c278 | ||
![]() |
8385f6f118 | ||
![]() |
be4380c744 | ||
![]() |
87f6a98668 | ||
![]() |
83fcc91fb8 | ||
![]() |
b4c229ccca | ||
![]() |
71302c7262 | ||
![]() |
1bec50e409 | ||
![]() |
f7cae8062c | ||
![]() |
c73f0d8eea | ||
![]() |
fe7c9115d5 | ||
![]() |
e13fb47aeb | ||
![]() |
32891d4208 | ||
![]() |
770d246787 | ||
![]() |
589151a77d | ||
![]() |
65af048f72 | ||
![]() |
99fd3b5021 | ||
![]() |
e4420e749a | ||
![]() |
5f22dafb1e | ||
![]() |
c2d8ee4341 | ||
![]() |
6a4435eb0d | ||
![]() |
346e07e9e7 | ||
![]() |
efdb3e8441 | ||
![]() |
0438433284 | ||
![]() |
d34a830660 | ||
![]() |
975f61a8e7 | ||
![]() |
8ba78c2681 | ||
![]() |
019bdb571c | ||
![]() |
a2aeed021d | ||
![]() |
0e8d361ed9 | ||
![]() |
c3b381a5f7 | ||
![]() |
8acba586b0 | ||
![]() |
5905d4b384 | ||
![]() |
2ad771e62e | ||
![]() |
403d7b151d | ||
![]() |
5c8c9af9ab | ||
![]() |
bfd23fc14e | ||
![]() |
81271a5aa5 | ||
![]() |
80a0bcdcee | ||
![]() |
172174d9e3 |
62
.github/workflows/dotnet.yml
vendored
62
.github/workflows/dotnet.yml
vendored
@@ -3,23 +3,59 @@ name: .NET
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ dev ]
|
branches: [ dev ]
|
||||||
|
paths:
|
||||||
|
- "versions/**"
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ dev ]
|
branches: [ dev ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- name: Get build version
|
||||||
- name: Setup .NET
|
id: date
|
||||||
uses: actions/setup-dotnet@v2
|
run: echo "::set-output name=date::$(date +'%Y%m%d')${{github.run_number}}"
|
||||||
with:
|
- name: Checkout Code
|
||||||
dotnet-version: 6.0.x
|
uses: actions/checkout@v3
|
||||||
- name: Restore dependencies
|
- name: Setup .NET
|
||||||
run: dotnet restore
|
uses: actions/setup-dotnet@v2
|
||||||
- name: Build
|
with:
|
||||||
run: dotnet build --no-restore
|
dotnet-version: 6.0.x
|
||||||
# - name: Test
|
- name: Restore dependencies
|
||||||
# run: dotnet test --no-build --verbosity normal
|
run: dotnet restore
|
||||||
|
- name: Publish
|
||||||
|
working-directory: ./src/ZonyLrcTools.Cli
|
||||||
|
run: |
|
||||||
|
ls -a
|
||||||
|
chmod +x ./publish.sh
|
||||||
|
./publish.sh
|
||||||
|
mv ./TempFiles ../../
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
PUBLISH_VERSION: ${{ steps.date.outputs.date }}
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: release-files
|
||||||
|
path: |
|
||||||
|
./TempFiles
|
||||||
|
./versions/release.md
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.date.outputs.date }}
|
||||||
|
release:
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: release-files
|
||||||
|
path: .
|
||||||
|
- name: Upload Release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
artifacts: "./TempFiles/*.zip"
|
||||||
|
token: ${{ secrets.GITHUBACTIONS }}
|
||||||
|
tag: ZonyLrcToolsX_Alpha.${{ needs.build.outputs.version }}
|
||||||
|
commit: dev
|
||||||
|
bodyFile: ./versions/release.md
|
23
README.md
23
README.md
@@ -57,6 +57,8 @@ macOS 和 Linux 用户请打开终端,切换到软件目录,一样执行命
|
|||||||
|
|
||||||
程序的所有的配置信息,都在 `config.yaml` 进行更改,下面标注了各个配置的说明。
|
程序的所有的配置信息,都在 `config.yaml` 进行更改,下面标注了各个配置的说明。
|
||||||
|
|
||||||
|
其中是否开启的可选项为 `true` 或者 `false`,等同于中文的是和否。
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
globalOption:
|
globalOption:
|
||||||
# 允许扫描的歌曲文件后缀名。
|
# 允许扫描的歌曲文件后缀名。
|
||||||
@@ -95,18 +97,27 @@ globalOption:
|
|||||||
plugin:
|
plugin:
|
||||||
- name: NetEase # 基于网易云音乐的歌词下载器。
|
- name: NetEase # 基于网易云音乐的歌词下载器。
|
||||||
priority: 1 # 优先级,升序排列,改为 -1 时禁用。
|
priority: 1 # 优先级,升序排列,改为 -1 时禁用。
|
||||||
|
depth: 30 # 搜索深度,值越大搜索结果越多,但搜索时间越长。
|
||||||
- name: QQ # 基于 QQ 音乐的歌词下载器。
|
- name: QQ # 基于 QQ 音乐的歌词下载器。
|
||||||
priority: 2
|
priority: 2
|
||||||
|
# depth: 10 # 暂时不支持。
|
||||||
- name: KuGou # 基于酷狗音乐的歌词下载器。
|
- name: KuGou # 基于酷狗音乐的歌词下载器。
|
||||||
priority: 3
|
priority: 3
|
||||||
|
depth: 10
|
||||||
# 歌词下载的一些共有配置参数。
|
# 歌词下载的一些共有配置参数。
|
||||||
config:
|
config:
|
||||||
isOneLine: true # 双语歌词是否合并为一行展示。
|
isOneLine: true # 双语歌词是否合并为一行展示。
|
||||||
lineBreak: "\n" # 换行符的类型,记得使用双引号指定。
|
lineBreak: "\n" # 换行符的类型,记得使用双引号指定。
|
||||||
isEnableTranslation: true # 是否启用翻译歌词。
|
isEnableTranslation: true # 是否启用翻译歌词。
|
||||||
isSkipExistLyricFiles: false # 如果歌词文件已经存在,是否跳过这些文件。
|
isOnlyOutputTranslation: false # 是否只输出翻译歌词。
|
||||||
|
isSkipExistLyricFiles: false # 如果歌词文件已经存在,是否跳过这些文件。
|
||||||
|
fileEncoding: 'utf-8' # 歌词文件的编码格式。
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 支持的编码格式
|
||||||
|
|
||||||
|
详细信息请参考: [MSDN Encoding 列表](https://learn.microsoft.com/en-us/dotnet/api/System.Text.Encoding.GetEncodings?view=net-6.0#examples),使用 `identifier and name` 作为参数值填入 `config.yaml` 文件当中的 `fileEncoding`。
|
||||||
|
|
||||||
### 屏蔽字典
|
### 屏蔽字典
|
||||||
|
|
||||||
屏蔽字典适用于网易云音乐歌词下载,针对某些单词,网易云音乐使用了 * 号进行屏蔽,这个时候可以使用屏蔽字典,设置歌曲名的关键词替换。例如有一首歌曲叫做 *Fucking ABC* ,这个时候网易云实际的名字是 *Fu****ing* ,用户只需要在屏蔽字典加入替换逻辑即可,例如:
|
屏蔽字典适用于网易云音乐歌词下载,针对某些单词,网易云音乐使用了 * 号进行屏蔽,这个时候可以使用屏蔽字典,设置歌曲名的关键词替换。例如有一首歌曲叫做 *Fucking ABC* ,这个时候网易云实际的名字是 *Fu****ing* ,用户只需要在屏蔽字典加入替换逻辑即可,例如:
|
||||||
@@ -123,6 +134,10 @@ globalOption:
|
|||||||
|
|
||||||
<img src="./docs/img/alipay.jpg" width="200"/><img src="./docs/img/wechat.jpg" width="200"/>
|
<img src="./docs/img/alipay.jpg" width="200"/><img src="./docs/img/wechat.jpg" width="200"/>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://star-history.com/#real-zony/ZonyLrcToolsX&Timeline)
|
||||||
|
|
||||||
## 路线图
|
## 路线图
|
||||||
|
|
||||||
- [x] 支持跨平台的 CLI 工具。
|
- [x] 支持跨平台的 CLI 工具。
|
||||||
|
@@ -17,6 +17,7 @@ using ZonyLrcTools.Cli.Infrastructure.IO;
|
|||||||
using ZonyLrcTools.Cli.Infrastructure.Lyric;
|
using ZonyLrcTools.Cli.Infrastructure.Lyric;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Tag;
|
using ZonyLrcTools.Cli.Infrastructure.Tag;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Threading;
|
using ZonyLrcTools.Cli.Infrastructure.Threading;
|
||||||
|
using File = System.IO.File;
|
||||||
|
|
||||||
namespace ZonyLrcTools.Cli.Commands.SubCommand
|
namespace ZonyLrcTools.Cli.Commands.SubCommand
|
||||||
{
|
{
|
||||||
@@ -67,17 +68,19 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand
|
|||||||
|
|
||||||
protected override async Task<int> OnExecuteAsync(CommandLineApplication app)
|
protected override async Task<int> OnExecuteAsync(CommandLineApplication app)
|
||||||
{
|
{
|
||||||
var files = await ScanMusicFilesAsync();
|
|
||||||
var musicInfos = await LoadMusicInfoAsync(files);
|
|
||||||
|
|
||||||
if (DownloadLyric)
|
if (DownloadLyric)
|
||||||
{
|
{
|
||||||
await DownloadLyricFilesAsync(musicInfos);
|
await DownloadLyricFilesAsync(
|
||||||
|
await LoadMusicInfoAsync(
|
||||||
|
RemoveExistLyricFiles(
|
||||||
|
await ScanMusicFilesAsync())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DownloadAlbum)
|
if (DownloadAlbum)
|
||||||
{
|
{
|
||||||
await DownloadAlbumAsync(musicInfos);
|
await DownloadAlbumAsync(
|
||||||
|
await LoadMusicInfoAsync(
|
||||||
|
await ScanMusicFilesAsync()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -95,8 +98,6 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand
|
|||||||
throw new ErrorCodeException(ErrorCodes.NoFilesWereScanned);
|
throw new ErrorCodeException(ErrorCodes.NoFilesWereScanned);
|
||||||
}
|
}
|
||||||
|
|
||||||
files = RemoveExistLyricFiles(files);
|
|
||||||
|
|
||||||
_logger.LogInformation($"已经扫描到了 {files.Count} 个音乐文件。");
|
_logger.LogInformation($"已经扫描到了 {files.Count} 个音乐文件。");
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
@@ -131,7 +132,11 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand
|
|||||||
var warpTaskList = files.Select(file => warpTask.RunAsync(() => Task.Run(async () => await _tagLoader.LoadTagAsync(file))));
|
var warpTaskList = files.Select(file => warpTask.RunAsync(() => Task.Run(async () => await _tagLoader.LoadTagAsync(file))));
|
||||||
var result = (await Task.WhenAll(warpTaskList))
|
var result = (await Task.WhenAll(warpTaskList))
|
||||||
.Where(m => m != null)
|
.Where(m => m != null)
|
||||||
.Where(m => !string.IsNullOrEmpty(m.Name) || !string.IsNullOrEmpty(m.Artist));
|
.Where(m => !string.IsNullOrEmpty(m.Name) || !string.IsNullOrEmpty(m.Artist))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Load music total time info.
|
||||||
|
// result.Foreach(m => { m.TotalTime = (long?)new AudioFileReader(m.FilePath).TotalTime.TotalMilliseconds; });
|
||||||
|
|
||||||
_logger.LogInformation($"已成功加载 {files.Count} 个音乐文件的标签信息。");
|
_logger.LogInformation($"已成功加载 {files.Count} 个音乐文件的标签信息。");
|
||||||
|
|
||||||
@@ -173,7 +178,7 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var lyric = await downloader.DownloadAsync(info.Name, info.Artist);
|
var lyric = await downloader.DownloadAsync(info.Name, info.Artist, info.TotalTime);
|
||||||
var lyricFilePath = Path.Combine(Path.GetDirectoryName(info.FilePath)!,
|
var lyricFilePath = Path.Combine(Path.GetDirectoryName(info.FilePath)!,
|
||||||
$"{Path.GetFileNameWithoutExtension(info.FilePath)}.lrc");
|
$"{Path.GetFileNameWithoutExtension(info.FilePath)}.lrc");
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Lyric;
|
using ZonyLrcTools.Cli.Infrastructure.Lyric;
|
||||||
|
|
||||||
namespace ZonyLrcTools.Cli.Config;
|
namespace ZonyLrcTools.Cli.Config;
|
||||||
@@ -8,6 +9,11 @@ public class LyricOption
|
|||||||
public IEnumerable<LyricProviderOption> Plugin { get; set; }
|
public IEnumerable<LyricProviderOption> Plugin { get; set; }
|
||||||
|
|
||||||
public LyricConfigOption Config { get; set; }
|
public LyricConfigOption Config { get; set; }
|
||||||
|
|
||||||
|
public LyricProviderOption GetLyricProviderOption(string name)
|
||||||
|
{
|
||||||
|
return Plugin.FirstOrDefault(x => x.Name == name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LyricConfigOption
|
public class LyricConfigOption
|
||||||
@@ -36,4 +42,9 @@ public class LyricConfigOption
|
|||||||
/// 歌词文件的编码格式。
|
/// 歌词文件的编码格式。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string FileEncoding { get; set; } = "utf-8";
|
public string FileEncoding { get; set; } = "utf-8";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否只输出翻译歌词。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsOnlyOutputTranslation { get; set; } = false;
|
||||||
}
|
}
|
@@ -11,5 +11,10 @@
|
|||||||
/// 歌词下载时的优先级,当值为 -1 时是禁用。
|
/// 歌词下载时的优先级,当值为 -1 时是禁用。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Priority { get; set; }
|
public int Priority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 搜索深度,值越大搜索结果越多,但搜索时间越长。
|
||||||
|
/// </summary>
|
||||||
|
public int Depth { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,4 @@
|
|||||||
using ZonyLrcTools.Cli.Infrastructure.Lyric;
|
using ZonyLrcTools.Cli.Infrastructure.Tag;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Tag;
|
|
||||||
|
|
||||||
namespace ZonyLrcTools.Cli.Config;
|
namespace ZonyLrcTools.Cli.Config;
|
||||||
|
|
||||||
|
@@ -51,7 +51,7 @@ namespace ZonyLrcTools.Cli.Infrastructure.Album.NetEase
|
|||||||
|
|
||||||
var songDetailJsonStr = await _warpHttpClient.GetAsync(
|
var songDetailJsonStr = await _warpHttpClient.GetAsync(
|
||||||
GetMusicInfoApi,
|
GetMusicInfoApi,
|
||||||
new GetSongDetailsRequest(searchResult.GetFirstMatchSongId(songName)),
|
new GetSongDetailsRequest(searchResult.GetFirstMatchSongId(songName, null)),
|
||||||
_defaultOption);
|
_defaultOption);
|
||||||
|
|
||||||
var url = JObject.Parse(songDetailJsonStr).SelectToken("$.songs[0].album.picUrl")?.Value<string>();
|
var url = JObject.Parse(songDetailJsonStr).SelectToken("$.songs[0].album.picUrl")?.Value<string>();
|
||||||
|
@@ -12,8 +12,9 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="songName">歌曲的名称。</param>
|
/// <param name="songName">歌曲的名称。</param>
|
||||||
/// <param name="artist">歌曲的作者。</param>
|
/// <param name="artist">歌曲的作者。</param>
|
||||||
|
/// <param name="duration">歌曲的时长。</param>
|
||||||
/// <returns>歌曲的歌词数据对象。</returns>
|
/// <returns>歌曲的歌词数据对象。</returns>
|
||||||
ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist);
|
ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist, long? duration = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 下载器的名称。
|
/// 下载器的名称。
|
||||||
|
@@ -12,11 +12,17 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel
|
|||||||
|
|
||||||
[JsonProperty("keyword")] public string Keyword { get; }
|
[JsonProperty("keyword")] public string Keyword { get; }
|
||||||
|
|
||||||
public SongSearchRequest(string musicName, string artistName)
|
[JsonProperty("pagesize")] public int PageSize { get; }
|
||||||
|
|
||||||
|
[JsonProperty("page")] public int Page { get; }
|
||||||
|
|
||||||
|
public SongSearchRequest(string musicName, string artistName, int pageSize = 30)
|
||||||
{
|
{
|
||||||
Filter = 2;
|
Filter = 2;
|
||||||
Platform = "WebFilter";
|
Platform = "WebFilter";
|
||||||
Keyword = HttpUtility.UrlEncode($"{musicName}+{artistName}", Encoding.UTF8);
|
Keyword = HttpUtility.UrlEncode($"{musicName}+{artistName}", Encoding.UTF8);
|
||||||
|
PageSize = pageSize;
|
||||||
|
Page = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using ZonyLrcTools.Cli.Config;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Exceptions;
|
using ZonyLrcTools.Cli.Infrastructure.Exceptions;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel;
|
using ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou.JsonModel;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Network;
|
using ZonyLrcTools.Cli.Infrastructure.Network;
|
||||||
@@ -14,22 +16,25 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.KuGou
|
|||||||
|
|
||||||
private readonly IWarpHttpClient _warpHttpClient;
|
private readonly IWarpHttpClient _warpHttpClient;
|
||||||
private readonly ILyricItemCollectionFactory _lyricItemCollectionFactory;
|
private readonly ILyricItemCollectionFactory _lyricItemCollectionFactory;
|
||||||
|
private readonly ToolOptions _options;
|
||||||
|
|
||||||
private const string KuGouSearchMusicUrl = @"https://songsearch.kugou.com/song_search_v2";
|
private const string KuGouSearchMusicUrl = @"https://songsearch.kugou.com/song_search_v2";
|
||||||
private const string KuGouGetLyricAccessKeyUrl = @"http://lyrics.kugou.com/search";
|
private const string KuGouGetLyricAccessKeyUrl = @"http://lyrics.kugou.com/search";
|
||||||
private const string KuGouGetLyricUrl = @"http://lyrics.kugou.com/download";
|
private const string KuGouGetLyricUrl = @"http://lyrics.kugou.com/download";
|
||||||
|
|
||||||
public KuGourLyricDownloader(IWarpHttpClient warpHttpClient,
|
public KuGourLyricDownloader(IWarpHttpClient warpHttpClient,
|
||||||
ILyricItemCollectionFactory lyricItemCollectionFactory)
|
ILyricItemCollectionFactory lyricItemCollectionFactory,
|
||||||
|
IOptions<ToolOptions> options)
|
||||||
{
|
{
|
||||||
_warpHttpClient = warpHttpClient;
|
_warpHttpClient = warpHttpClient;
|
||||||
_lyricItemCollectionFactory = lyricItemCollectionFactory;
|
_lyricItemCollectionFactory = lyricItemCollectionFactory;
|
||||||
|
_options = options.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask<byte[]> DownloadDataAsync(LyricDownloaderArgs args)
|
protected override async ValueTask<byte[]> DownloadDataAsync(LyricDownloaderArgs args)
|
||||||
{
|
{
|
||||||
var searchResult = await _warpHttpClient.GetAsync<SongSearchResponse>(KuGouSearchMusicUrl,
|
var searchResult = await _warpHttpClient.GetAsync<SongSearchResponse>(KuGouSearchMusicUrl,
|
||||||
new SongSearchRequest(args.SongName, args.Artist));
|
new SongSearchRequest(args.SongName, args.Artist, _options.Provider.Lyric.GetLyricProviderOption(DownloaderName).Depth));
|
||||||
|
|
||||||
ValidateSongSearchResponse(searchResult, args);
|
ValidateSongSearchResponse(searchResult, args);
|
||||||
|
|
||||||
|
@@ -16,10 +16,11 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="songName">歌曲名称。</param>
|
/// <param name="songName">歌曲名称。</param>
|
||||||
/// <param name="artist">歌曲作者/艺术家。</param>
|
/// <param name="artist">歌曲作者/艺术家。</param>
|
||||||
|
/// <param name="duration">歌曲的时长。</param>
|
||||||
/// <returns>下载完成的歌曲数据。</returns>
|
/// <returns>下载完成的歌曲数据。</returns>
|
||||||
public virtual async ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist)
|
public virtual async ValueTask<LyricItemCollection> DownloadAsync(string songName, string artist, long? duration = null)
|
||||||
{
|
{
|
||||||
var args = new LyricDownloaderArgs(songName, artist);
|
var args = new LyricDownloaderArgs(songName, artist, duration ?? 0);
|
||||||
await ValidateAsync(args);
|
await ValidateAsync(args);
|
||||||
var downloadDataBytes = await DownloadDataAsync(args);
|
var downloadDataBytes = await DownloadDataAsync(args);
|
||||||
return await GenerateLyricAsync(downloadDataBytes, args);
|
return await GenerateLyricAsync(downloadDataBytes, args);
|
||||||
|
@@ -6,10 +6,13 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric
|
|||||||
|
|
||||||
public string Artist { get; set; }
|
public string Artist { get; set; }
|
||||||
|
|
||||||
public LyricDownloaderArgs(string songName, string artist)
|
public long Duration { get; set; }
|
||||||
|
|
||||||
|
public LyricDownloaderArgs(string songName, string artist, long duration)
|
||||||
{
|
{
|
||||||
SongName = songName;
|
SongName = songName;
|
||||||
Artist = artist;
|
Artist = artist;
|
||||||
|
Duration = duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -43,6 +43,11 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric
|
|||||||
if (_options.Provider.Lyric.Config.IsEnableTranslation && !string.IsNullOrEmpty(translationLyric))
|
if (_options.Provider.Lyric.Config.IsEnableTranslation && !string.IsNullOrEmpty(translationLyric))
|
||||||
{
|
{
|
||||||
var translatedLyric = InternalBuildLyricObject(new LyricItemCollection(_options.Provider.Lyric.Config), translationLyric);
|
var translatedLyric = InternalBuildLyricObject(new LyricItemCollection(_options.Provider.Lyric.Config), translationLyric);
|
||||||
|
if (_options.Provider.Lyric.Config.IsOnlyOutputTranslation)
|
||||||
|
{
|
||||||
|
return translatedLyric;
|
||||||
|
}
|
||||||
|
|
||||||
return lyric + translatedLyric;
|
return lyric + translatedLyric;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,9 +8,9 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
|
|||||||
{
|
{
|
||||||
public GetLyricRequest(long songId)
|
public GetLyricRequest(long songId)
|
||||||
{
|
{
|
||||||
OS = "osx";
|
OS = "ios";
|
||||||
Id = songId;
|
Id = songId;
|
||||||
Lv = Kv = Tv = -1;
|
Lv = Kv = Tv = Rv = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -30,5 +30,9 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
|
|||||||
[JsonProperty("kv")] public int Kv { get; }
|
[JsonProperty("kv")] public int Kv { get; }
|
||||||
|
|
||||||
[JsonProperty("tv")] public int Tv { get; }
|
[JsonProperty("tv")] public int Tv { get; }
|
||||||
|
|
||||||
|
[JsonProperty("rv")] public int Rv { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("crypto")] public string Protocol { get; set; } = "api";
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -22,6 +22,12 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
|
|||||||
[JsonProperty("tlyric")]
|
[JsonProperty("tlyric")]
|
||||||
public InnerLyric TranslationLyric { get; set; }
|
public InnerLyric TranslationLyric { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 如果存在罗马音歌词,则本项内容为罗马音歌词。
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("romalrc")]
|
||||||
|
public InnerLyric RomaLyric { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 状态码。
|
/// 状态码。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
@@ -42,18 +43,25 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
|
|||||||
[JsonProperty("limit")]
|
[JsonProperty("limit")]
|
||||||
public int Limit { get; set; }
|
public int Limit { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("crypto")] public string Crypto { get; set; } = "weapi";
|
||||||
|
|
||||||
public SongSearchRequest()
|
public SongSearchRequest()
|
||||||
{
|
{
|
||||||
CsrfToken = string.Empty;
|
CsrfToken = string.Empty;
|
||||||
Type = 1;
|
Type = 1;
|
||||||
Offset = 0;
|
Offset = 0;
|
||||||
IsTotal = true;
|
IsTotal = true;
|
||||||
Limit = 5;
|
Limit = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SongSearchRequest(string musicName, string artistName) : this()
|
public SongSearchRequest(string musicName, string artistName, int limit = 10) : this()
|
||||||
{
|
{
|
||||||
|
// Remove all the brackets and the content inside them.
|
||||||
|
var regex = new Regex(@"\([^)]*\)");
|
||||||
|
musicName = regex.Replace(musicName, string.Empty);
|
||||||
|
|
||||||
SearchKey = HttpUtility.UrlEncode($"{musicName}+{artistName}", Encoding.UTF8);
|
SearchKey = HttpUtility.UrlEncode($"{musicName}+{artistName}", Encoding.UTF8);
|
||||||
|
Limit = limit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -10,10 +11,20 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
|
|||||||
|
|
||||||
[JsonProperty("code")] public int StatusCode { get; set; }
|
[JsonProperty("code")] public int StatusCode { get; set; }
|
||||||
|
|
||||||
public int GetFirstMatchSongId(string songName)
|
public int GetFirstMatchSongId(string songName, long? duration)
|
||||||
{
|
{
|
||||||
var item = Items.SongItems.FirstOrDefault(x => x.Name == songName);
|
var perfectMatch = Items.SongItems.FirstOrDefault(x => x.Name == songName);
|
||||||
return item?.Id ?? Items.SongItems[0].Id;
|
if (perfectMatch != null)
|
||||||
|
{
|
||||||
|
return perfectMatch.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration is null or 0)
|
||||||
|
{
|
||||||
|
return Items.SongItems.First().Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Items.SongItems.OrderBy(t => Math.Abs(t.Duration - duration.Value)).First().Id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +60,12 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("album")]
|
[JsonProperty("album")]
|
||||||
public SongAlbumModel Album { get; set; }
|
public SongAlbumModel Album { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 歌曲的实际长度。
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("duration")]
|
||||||
|
public long Duration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SongArtistModel
|
public class SongArtistModel
|
||||||
|
@@ -2,7 +2,9 @@ using System;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using ZonyLrcTools.Cli.Config;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Exceptions;
|
using ZonyLrcTools.Cli.Infrastructure.Exceptions;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel;
|
using ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase.JsonModel;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Network;
|
using ZonyLrcTools.Cli.Infrastructure.Network;
|
||||||
@@ -15,6 +17,7 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase
|
|||||||
|
|
||||||
private readonly IWarpHttpClient _warpHttpClient;
|
private readonly IWarpHttpClient _warpHttpClient;
|
||||||
private readonly ILyricItemCollectionFactory _lyricItemCollectionFactory;
|
private readonly ILyricItemCollectionFactory _lyricItemCollectionFactory;
|
||||||
|
private readonly ToolOptions _options;
|
||||||
|
|
||||||
private const string NetEaseSearchMusicUrl = @"https://music.163.com/api/search/get/web";
|
private const string NetEaseSearchMusicUrl = @"https://music.163.com/api/search/get/web";
|
||||||
private const string NetEaseGetLyricUrl = @"https://music.163.com/api/song/lyric";
|
private const string NetEaseGetLyricUrl = @"https://music.163.com/api/song/lyric";
|
||||||
@@ -23,17 +26,19 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase
|
|||||||
private const string NetEaseRequestContentType = @"application/x-www-form-urlencoded";
|
private const string NetEaseRequestContentType = @"application/x-www-form-urlencoded";
|
||||||
|
|
||||||
public NetEaseLyricDownloader(IWarpHttpClient warpHttpClient,
|
public NetEaseLyricDownloader(IWarpHttpClient warpHttpClient,
|
||||||
ILyricItemCollectionFactory lyricItemCollectionFactory)
|
ILyricItemCollectionFactory lyricItemCollectionFactory,
|
||||||
|
IOptions<ToolOptions> options)
|
||||||
{
|
{
|
||||||
_warpHttpClient = warpHttpClient;
|
_warpHttpClient = warpHttpClient;
|
||||||
_lyricItemCollectionFactory = lyricItemCollectionFactory;
|
_lyricItemCollectionFactory = lyricItemCollectionFactory;
|
||||||
|
_options = options.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async ValueTask<byte[]> DownloadDataAsync(LyricDownloaderArgs args)
|
protected override async ValueTask<byte[]> DownloadDataAsync(LyricDownloaderArgs args)
|
||||||
{
|
{
|
||||||
var searchResult = await _warpHttpClient.PostAsync<SongSearchResponse>(
|
var searchResult = await _warpHttpClient.PostAsync<SongSearchResponse>(
|
||||||
NetEaseSearchMusicUrl,
|
NetEaseSearchMusicUrl,
|
||||||
new SongSearchRequest(args.SongName, args.Artist),
|
new SongSearchRequest(args.SongName, args.Artist, _options.Provider.Lyric.GetLyricProviderOption(DownloaderName).Depth),
|
||||||
true,
|
true,
|
||||||
msg =>
|
msg =>
|
||||||
{
|
{
|
||||||
@@ -48,7 +53,7 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase
|
|||||||
|
|
||||||
var lyricResponse = await _warpHttpClient.GetAsync(
|
var lyricResponse = await _warpHttpClient.GetAsync(
|
||||||
NetEaseGetLyricUrl,
|
NetEaseGetLyricUrl,
|
||||||
new GetLyricRequest(searchResult.GetFirstMatchSongId(args.SongName)),
|
new GetLyricRequest(searchResult.GetFirstMatchSongId(args.SongName, args.Duration)),
|
||||||
msg => msg.Headers.Referrer = new Uri(NetEaseRequestReferer));
|
msg => msg.Headers.Referrer = new Uri(NetEaseRequestReferer));
|
||||||
|
|
||||||
return Encoding.UTF8.GetBytes(lyricResponse);
|
return Encoding.UTF8.GetBytes(lyricResponse);
|
||||||
@@ -70,8 +75,8 @@ namespace ZonyLrcTools.Cli.Infrastructure.Lyric.NetEase
|
|||||||
}
|
}
|
||||||
|
|
||||||
return _lyricItemCollectionFactory.Build(
|
return _lyricItemCollectionFactory.Build(
|
||||||
json.OriginalLyric.Text,
|
json.OriginalLyric?.Text,
|
||||||
json.TranslationLyric.Text);
|
json.TranslationLyric?.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ValidateSongSearchResponse(SongSearchResponse response, LyricDownloaderArgs args)
|
protected virtual void ValidateSongSearchResponse(SongSearchResponse response, LyricDownloaderArgs args)
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace ZonyLrcTools.Cli.Infrastructure
|
namespace ZonyLrcTools.Cli.Infrastructure
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -10,6 +12,11 @@ namespace ZonyLrcTools.Cli.Infrastructure
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string FilePath { get; }
|
public string FilePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 歌曲的实际歌曲长度。
|
||||||
|
/// </summary>
|
||||||
|
public long? TotalTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 歌曲的名称。
|
/// 歌曲的名称。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using ZonyLrcTools.Cli.Infrastructure.DependencyInject;
|
||||||
|
using ZonyLrcTools.Cli.Infrastructure.Network;
|
||||||
|
using ZonyLrcTools.Cli.Infrastructure.Updater.JsonModel;
|
||||||
|
|
||||||
|
namespace ZonyLrcTools.Cli.Infrastructure.Updater;
|
||||||
|
|
||||||
|
public class DefaultUpdater : ISingletonDependency
|
||||||
|
{
|
||||||
|
public const string UpdateUrl = "https://api.zony.me/lrc-tools/update";
|
||||||
|
|
||||||
|
private readonly IWarpHttpClient _warpHttpClient;
|
||||||
|
private readonly ILogger<DefaultUpdater> _logger;
|
||||||
|
|
||||||
|
public DefaultUpdater(IWarpHttpClient warpHttpClient,
|
||||||
|
ILogger<DefaultUpdater> logger)
|
||||||
|
{
|
||||||
|
_warpHttpClient = warpHttpClient;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CheckUpdateAsync()
|
||||||
|
{
|
||||||
|
var response = await _warpHttpClient.GetAsync<NewVersionResponse>(UpdateUrl);
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
if (response.NewVersion <= currentVersion)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var importantItem = response.Items.FirstOrDefault(x => x.ItemType == NewVersionItemType.Important);
|
||||||
|
if (importantItem != null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"发现了新版本,请点击下面的链接进行更新:{importantItem.Url}");
|
||||||
|
_logger.LogWarning($"最新版本号:{response.NewVersion},当前版本号: ${currentVersion}");
|
||||||
|
_logger.LogWarning($"更新内容:{response.NewVersionDescription}");
|
||||||
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
Process.Start("explorer.exe", importantItem.Url);
|
||||||
|
}
|
||||||
|
else if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
Process.Start("open", importantItem.Url);
|
||||||
|
}
|
||||||
|
else if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
Process.Start("xdg-open", importantItem.Url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ZonyLrcTools.Cli.Infrastructure.Updater.JsonModel;
|
||||||
|
|
||||||
|
public class NewVersionItem
|
||||||
|
{
|
||||||
|
public string Url { get; set; }
|
||||||
|
|
||||||
|
public NewVersionItemType ItemType { get; set; }
|
||||||
|
}
|
@@ -0,0 +1,7 @@
|
|||||||
|
namespace ZonyLrcTools.Cli.Infrastructure.Updater.JsonModel;
|
||||||
|
|
||||||
|
public enum NewVersionItemType
|
||||||
|
{
|
||||||
|
Important,
|
||||||
|
NormalBinaryFile
|
||||||
|
}
|
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ZonyLrcTools.Cli.Infrastructure.Updater.JsonModel;
|
||||||
|
|
||||||
|
public class NewVersionResponse
|
||||||
|
{
|
||||||
|
public Version NewVersion { get; set; }
|
||||||
|
|
||||||
|
public string NewVersionDescription { get; set; }
|
||||||
|
|
||||||
|
public List<NewVersionItem> Items { get; set; }
|
||||||
|
|
||||||
|
public DateTime UpdateTime { get; set; }
|
||||||
|
}
|
@@ -3,40 +3,44 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
<AssemblyVersion>0.0.0.1</AssemblyVersion>
|
||||||
|
<FileVersion>0.0.0.1</FileVersion>
|
||||||
|
<PackageVersion>0.0.0.1</PackageVersion>
|
||||||
|
<Version>0.0.0.1</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.1" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.1" />
|
||||||
<PackageReference Include="McMaster.Extensions.Hosting.CommandLine" Version="4.0.1" />
|
<PackageReference Include="McMaster.Extensions.Hosting.CommandLine" Version="4.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||||
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="2.2.0" />
|
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="2.2.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="Refit" Version="6.3.2" />
|
<PackageReference Include="Refit" Version="6.3.2" />
|
||||||
<PackageReference Include="Refit.HttpClientFactory" Version="6.3.2" />
|
<PackageReference Include="Refit.HttpClientFactory" Version="6.3.2" />
|
||||||
<PackageReference Include="Refit.Newtonsoft.Json" Version="6.3.2" />
|
<PackageReference Include="Refit.Newtonsoft.Json" Version="6.3.2" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="4.2.0" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
|
||||||
<PackageReference Include="TagLibSharp" Version="2.2.0" />
|
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="appsettings.json" />
|
<None Remove="appsettings.json" />
|
||||||
<None Remove="Resources\error_msg.json" />
|
<None Remove="Resources\error_msg.json" />
|
||||||
<Content Include="Resources\error_msg.json">
|
<Content Include="Resources\error_msg.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<None Remove="BlockWords.json" />
|
<None Remove="BlockWords.json" />
|
||||||
<Content Include="BlockWords.json">
|
<Content Include="BlockWords.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<None Remove="config.yaml" />
|
<None Remove="config.yaml" />
|
||||||
<Content Include="config.yaml">
|
<Content Include="config.yaml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -9,6 +9,7 @@ globalOption:
|
|||||||
isEnable: false # 是否启用代理。
|
isEnable: false # 是否启用代理。
|
||||||
ip: 127.0.0.1 # 代理服务 IP 地址。
|
ip: 127.0.0.1 # 代理服务 IP 地址。
|
||||||
port: 4780 # 代理服务端口号。
|
port: 4780 # 代理服务端口号。
|
||||||
|
updateUrl: https://api.zony.me/lrc-tools/update # 更新检查地址。
|
||||||
|
|
||||||
# 下载器的相关参数配置。
|
# 下载器的相关参数配置。
|
||||||
provider:
|
provider:
|
||||||
@@ -35,14 +36,18 @@ globalOption:
|
|||||||
plugin:
|
plugin:
|
||||||
- name: NetEase # 基于网易云音乐的歌词下载器。
|
- name: NetEase # 基于网易云音乐的歌词下载器。
|
||||||
priority: 1 # 优先级,升序排列,改为 -1 时禁用。
|
priority: 1 # 优先级,升序排列,改为 -1 时禁用。
|
||||||
|
depth: 30 # 搜索深度,值越大搜索结果越多,但搜索时间越长。
|
||||||
- name: QQ # 基于 QQ 音乐的歌词下载器。
|
- name: QQ # 基于 QQ 音乐的歌词下载器。
|
||||||
priority: 2
|
priority: 2
|
||||||
|
# depth: 10 # 暂时不支持。
|
||||||
- name: KuGou # 基于酷狗音乐的歌词下载器。
|
- name: KuGou # 基于酷狗音乐的歌词下载器。
|
||||||
priority: 3
|
priority: 3
|
||||||
|
depth: 10
|
||||||
# 歌词下载的一些共有配置参数。
|
# 歌词下载的一些共有配置参数。
|
||||||
config:
|
config:
|
||||||
isOneLine: true # 双语歌词是否合并为一行展示。
|
isOneLine: true # 双语歌词是否合并为一行展示。
|
||||||
lineBreak: "\n" # 换行符的类型,记得使用双引号指定。
|
lineBreak: "\n" # 换行符的类型,记得使用双引号指定。
|
||||||
isEnableTranslation: true # 是否启用翻译歌词。
|
isEnableTranslation: true # 是否启用翻译歌词。
|
||||||
isSkipExistLyricFiles: false # 如果歌词文件已经存在,是否跳过这些文件。
|
isOnlyOutputTranslation: false # 是否只输出翻译歌词。
|
||||||
fileEncoding: 'utf-8' # 歌词文件的编码格式。
|
isSkipExistLyricFiles: false # 如果歌词文件已经存在,是否跳过这些文件。
|
||||||
|
fileEncoding: 'utf-8' # 歌词文件的编码格式。
|
@@ -1,5 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
read -r -p "请输入版本号:" Version
|
|
||||||
Platforms=('win-x64' 'linux-x64' 'osx-x64')
|
Platforms=('win-x64' 'linux-x64' 'osx-x64')
|
||||||
|
|
||||||
if ! [ -d './TempFiles' ];
|
if ! [ -d './TempFiles' ];
|
||||||
@@ -11,11 +10,11 @@ rm -rf ./TempFiles/*
|
|||||||
|
|
||||||
for platform in "${Platforms[@]}"
|
for platform in "${Platforms[@]}"
|
||||||
do
|
do
|
||||||
dotnet publish -r "$platform" -c Release -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true
|
dotnet publish -r "$platform" -c Release -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true || exit 1
|
||||||
|
|
||||||
cd ./bin/Release/net5.0/"$platform"/publish/
|
|
||||||
zip -r ./ZonyLrcTools_"$platform"_"$Version".zip ./
|
|
||||||
cd ../../../../../
|
|
||||||
|
|
||||||
mv ./bin/Release/net5.0/"$platform"/publish/ZonyLrcTools_"$platform"_"$Version".zip ./TempFiles
|
cd ./bin/Release/net6.0/"$platform"/publish/ || exit 1
|
||||||
|
zip -r ./ZonyLrcTools_"$platform"_"${PUBLISH_VERSION}".zip ./ || exit 1
|
||||||
|
cd ../../../../../ || exit 1
|
||||||
|
|
||||||
|
mv ./bin/Release/net6.0/"$platform"/publish/ZonyLrcTools_"$platform"_"$PUBLISH_VERSION".zip ./TempFiles
|
||||||
done
|
done
|
@@ -1,8 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using ZonyLrcTools.Cli.Config;
|
||||||
using ZonyLrcTools.Cli.Infrastructure.Lyric;
|
using ZonyLrcTools.Cli.Infrastructure.Lyric;
|
||||||
|
|
||||||
namespace ZonyLrcTools.Tests.Infrastructure.Lyric
|
namespace ZonyLrcTools.Tests.Infrastructure.Lyric
|
||||||
@@ -39,7 +42,7 @@ namespace ZonyLrcTools.Tests.Infrastructure.Lyric
|
|||||||
{
|
{
|
||||||
var lyric = await _lyricDownloader.DownloadAsync("シンデレラ (Giga First Night Remix)", "DECO 27 ギガP");
|
var lyric = await _lyricDownloader.DownloadAsync("シンデレラ (Giga First Night Remix)", "DECO 27 ギガP");
|
||||||
lyric.ShouldNotBeNull();
|
lyric.ShouldNotBeNull();
|
||||||
lyric.IsPruneMusic.ShouldBe(true);
|
lyric.IsPruneMusic.ShouldBe(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -77,5 +80,22 @@ namespace ZonyLrcTools.Tests.Infrastructure.Lyric
|
|||||||
|
|
||||||
lyric.ShouldNotBeNull();
|
lyric.ShouldNotBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DownloaderAsync_Issue101_Test()
|
||||||
|
{
|
||||||
|
var lyric = await _lyricDownloader.DownloadAsync("君への嘘", "VALSHE");
|
||||||
|
lyric.ShouldNotBeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DownloadAsync_Issue114_Test()
|
||||||
|
{
|
||||||
|
var options = ServiceProvider.GetRequiredService<IOptions<ToolOptions>>();
|
||||||
|
options.Value.Provider.Lyric.Config.IsOnlyOutputTranslation = true;
|
||||||
|
|
||||||
|
var lyric = await _lyricDownloader.DownloadAsync("Bones", "Image Dragons");
|
||||||
|
lyric.ToString().ShouldNotContain("Gimme, gimme, gimme some time to think");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,10 +7,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||||
<PackageReference Include="Shouldly" Version="4.0.3" />
|
<PackageReference Include="Shouldly" Version="4.1.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
5
versions/release.md
Normal file
5
versions/release.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
New Features: None
|
||||||
|
Breaking Changes: None
|
||||||
|
Enhancement: None
|
||||||
|
Fixed Bugs:
|
||||||
|
- [[#115](https://github.com/real-zony/ZonyLrcToolsX/issues/115)] NAudio 有问题,暂时屏蔽该功能。
|
Reference in New Issue
Block a user