diff --git a/NLyric/Audio/Album.cs b/NLyric/Audio/Album.cs
index 9f2bc1c..5fe03aa 100644
--- a/NLyric/Audio/Album.cs
+++ b/NLyric/Audio/Album.cs
@@ -16,9 +16,9 @@ public class Album : ITrackOrAlbum {
public int? Year => _year;
public Album(string name, string[] artists, int? trackCount, int? year) {
- if (name == null)
+ if (name is null)
throw new ArgumentNullException(nameof(name));
- if (artists == null)
+ if (artists is null)
throw new ArgumentNullException(nameof(artists));
_name = name;
@@ -33,7 +33,7 @@ public Album(string name, string[] artists, int? trackCount, int? year) {
///
/// 当 为空时,是否从 获取艺术家
public Album(ATL.Track track, bool getArtistsFromTrack) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
if (!HasAlbumInfo(track))
throw new ArgumentException(nameof(track) + " 中不存在专辑信息");
@@ -52,7 +52,7 @@ public Album(ATL.Track track, bool getArtistsFromTrack) {
}
public static bool HasAlbumInfo(ATL.Track track) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
return !string.IsNullOrWhiteSpace(track.Album);
diff --git a/NLyric/Audio/Track.cs b/NLyric/Audio/Track.cs
index cb43bc4..a05dde1 100644
--- a/NLyric/Audio/Track.cs
+++ b/NLyric/Audio/Track.cs
@@ -10,9 +10,9 @@ public class Track : ITrackOrAlbum {
public string[] Artists => _artists;
public Track(string name, string[] artists) {
- if (name == null)
+ if (name is null)
throw new ArgumentNullException(nameof(name));
- if (artists == null)
+ if (artists is null)
throw new ArgumentNullException(nameof(artists));
_name = name;
@@ -20,7 +20,7 @@ public Track(string name, string[] artists) {
}
public Track(ATL.Track track) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
_name = track.Title.GetSafeString();
diff --git a/NLyric/Caches/AlbumCache.cs b/NLyric/Caches/AlbumCache.cs
index 56de5c1..38055f4 100644
--- a/NLyric/Caches/AlbumCache.cs
+++ b/NLyric/Caches/AlbumCache.cs
@@ -17,7 +17,7 @@ public AlbumCache(Album album, int id) : this(album.Name, id) {
}
public AlbumCache(string name, int id) {
- if (name == null)
+ if (name is null)
throw new ArgumentNullException(nameof(name));
Name = name;
diff --git a/NLyric/Caches/Extensions.cs b/NLyric/Caches/Extensions.cs
index 44ea764..db78a3a 100644
--- a/NLyric/Caches/Extensions.cs
+++ b/NLyric/Caches/Extensions.cs
@@ -6,25 +6,25 @@
namespace NLyric.Caches {
public static class Extensions {
public static AlbumCache Match(this IEnumerable caches, Album album) {
- if (album == null)
+ if (album is null)
throw new ArgumentNullException(nameof(album));
return caches.FirstOrDefault(t => IsMatched(t, album));
}
public static TrackCache Match(this IEnumerable caches, Track track, Album album) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
- if (album == null)
+ if (album is null)
throw new ArgumentNullException(nameof(album));
return caches.FirstOrDefault(t => IsMatched(t, track, album));
}
public static TrackCache Match(this IEnumerable caches, Track track, string fileName) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
- if (fileName == null)
+ if (fileName is null)
throw new ArgumentNullException(nameof(fileName));
return caches.FirstOrDefault(t => IsMatched(t, track, fileName));
@@ -35,25 +35,25 @@ public static LyricCache Match(this IEnumerable caches, int id) {
}
public static bool IsMatched(this AlbumCache cache, Album album) {
- if (album == null)
+ if (album is null)
throw new ArgumentNullException(nameof(album));
return cache.Name == album.Name;
}
public static bool IsMatched(this TrackCache cache, Track track, Album album) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
- if (album == null)
+ if (album is null)
throw new ArgumentNullException(nameof(album));
return cache.Name == track.Name && cache.AlbumName == album.Name && cache.Artists.SequenceEqual(track.Artists);
}
public static bool IsMatched(this TrackCache cache, Track track, string fileName) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
- if (fileName == null)
+ if (fileName is null)
throw new ArgumentNullException(nameof(fileName));
return cache.Name == track.Name && cache.FileName == fileName && cache.Artists.SequenceEqual(track.Artists);
diff --git a/NLyric/Caches/LyricCache.cs b/NLyric/Caches/LyricCache.cs
index 8e427a8..0b5e81b 100644
--- a/NLyric/Caches/LyricCache.cs
+++ b/NLyric/Caches/LyricCache.cs
@@ -25,7 +25,7 @@ public LyricCache(NcmLyric lyric, string checkSum) : this(lyric.Id, lyric.IsAbso
}
public LyricCache(int id, bool isAbsoluteMusic, int rawVersion, int translatedVersion, string checkSum) {
- if (checkSum == null)
+ if (checkSum is null)
throw new ArgumentNullException(nameof(checkSum));
Id = id;
diff --git a/NLyric/Caches/TrackCache.cs b/NLyric/Caches/TrackCache.cs
index 3c433c0..ffbd561 100644
--- a/NLyric/Caches/TrackCache.cs
+++ b/NLyric/Caches/TrackCache.cs
@@ -26,11 +26,11 @@ public TrackCache(Track track, string fileName, int id) : this(track.Name, track
}
public TrackCache(string name, string[] artists, string albumName, string fileName, int id) {
- if (name == null)
+ if (name is null)
throw new ArgumentNullException(nameof(name));
- if (artists == null)
+ if (artists is null)
throw new ArgumentNullException(nameof(artists));
- if (albumName == null && fileName == null)
+ if (albumName is null && fileName is null)
throw new ArgumentException($"{nameof(albumName)} 和 {nameof(fileName)} 不能同时为 null");
Name = name;
diff --git a/NLyric/ChineseConverter.cs b/NLyric/ChineseConverter.cs
new file mode 100644
index 0000000..43736f5
--- /dev/null
+++ b/NLyric/ChineseConverter.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+namespace NLyric {
+ internal static class ChineseConverter {
+ private static readonly Dictionary _traditionalToSimplifiedMap;
+
+ static ChineseConverter() {
+ Assembly assembly;
+
+ assembly = Assembly.GetExecutingAssembly();
+ using (Stream stream = assembly.GetManifestResourceStream("NLyric.TraditionalToSimplified.map"))
+ using (BinaryReader reader = new BinaryReader(stream)) {
+ int count;
+
+ count = (int)stream.Length / 4;
+ _traditionalToSimplifiedMap = new Dictionary(count);
+ for (int i = 0; i < count; i++)
+ _traditionalToSimplifiedMap.Add((char)reader.ReadUInt16(), (char)reader.ReadUInt16());
+ }
+ }
+
+ public static string TraditionalToSimplified(string s) {
+ if (s is null)
+ return null;
+
+ StringBuilder sb;
+
+ sb = new StringBuilder(s);
+ for (int i = 0; i < sb.Length; i++)
+ if (_traditionalToSimplifiedMap.TryGetValue(sb[i], out char c))
+ sb[i] = c;
+ return sb.ToString();
+ }
+ }
+}
diff --git a/NLyric/Crc32.cs b/NLyric/Crc32.cs
index 9e44344..c829157 100644
--- a/NLyric/Crc32.cs
+++ b/NLyric/Crc32.cs
@@ -24,7 +24,7 @@ static Crc32() {
}
public static uint Compute(byte[] data) {
- if (data == null)
+ if (data is null)
throw new ArgumentNullException(nameof(data));
uint crc32;
diff --git a/NLyric/DictionaryComparer.cs b/NLyric/DictionaryComparer.cs
index 154aeb2..f603259 100644
--- a/NLyric/DictionaryComparer.cs
+++ b/NLyric/DictionaryComparer.cs
@@ -6,7 +6,7 @@ internal sealed class DictionaryComparer : IComparer where T
private readonly Dictionary _dictionary;
public DictionaryComparer(Dictionary dictionary) {
- if (dictionary == null)
+ if (dictionary is null)
throw new ArgumentNullException(nameof(dictionary));
_dictionary = dictionary;
diff --git a/NLyric/Logger.cs b/NLyric/Logger.cs
index b80f5f4..6dd877a 100644
--- a/NLyric/Logger.cs
+++ b/NLyric/Logger.cs
@@ -12,13 +12,11 @@ private Logger() {
}
public void LogNewLine() {
- lock (_syncRoot)
- Console.WriteLine();
+ LogInfo(string.Empty, ConsoleColor.Gray);
}
public void LogInfo(string value) {
- lock (_syncRoot)
- Console.WriteLine(value);
+ LogInfo(value, ConsoleColor.Gray);
}
public void LogWarning(string value) {
@@ -41,14 +39,14 @@ public void LogInfo(string value, ConsoleColor color) {
}
public void LogException(Exception value) {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
LogError(ExceptionToString(value));
}
private static string ExceptionToString(Exception exception) {
- if (exception == null)
+ if (exception is null)
throw new ArgumentNullException(nameof(exception));
StringBuilder sb;
@@ -65,7 +63,7 @@ private static void DumpException(Exception exception, StringBuilder sb) {
sb.AppendLine("StackTrace: " + Environment.NewLine + exception.StackTrace);
sb.AppendLine("TargetSite: " + Environment.NewLine + exception.TargetSite.ToString());
sb.AppendLine("----------------------------------------");
- if (exception.InnerException != null)
+ if (!(exception.InnerException is null))
DumpException(exception.InnerException, sb);
}
}
diff --git a/NLyric/Lyrics/Lrc.cs b/NLyric/Lyrics/Lrc.cs
index fa1acc7..70d16bb 100644
--- a/NLyric/Lyrics/Lrc.cs
+++ b/NLyric/Lyrics/Lrc.cs
@@ -16,12 +16,12 @@ public sealed class Lrc {
private string _album;
private string _by;
private TimeSpan? _offset;
- private readonly Dictionary _lyrics = new Dictionary();
+ private Dictionary _lyrics = new Dictionary();
public string Title {
get => _title;
set {
- if (value == null) {
+ if (value is null) {
_title = value;
return;
}
@@ -33,7 +33,7 @@ public string Title {
public string Artist {
get => _artist;
set {
- if (value == null) {
+ if (value is null) {
_artist = value;
return;
}
@@ -45,7 +45,7 @@ public string Artist {
public string Album {
get => _album;
set {
- if (value == null) {
+ if (value is null) {
_album = value;
return;
}
@@ -57,7 +57,7 @@ public string Album {
public string By {
get => _by;
set {
- if (value == null) {
+ if (value is null) {
_by = value;
return;
}
@@ -68,10 +68,18 @@ public string By {
public TimeSpan? Offset {
get => _offset;
- set => _offset = (value == null || value.Value.Ticks == 0) ? null : value;
+ set => _offset = (value is null || value.Value.Ticks == 0) ? null : value;
}
- public Dictionary Lyrics => _lyrics;
+ public Dictionary Lyrics {
+ get => _lyrics;
+ set {
+ if (value is null)
+ throw new ArgumentNullException(nameof(value));
+
+ _lyrics = value;
+ }
+ }
public static Lrc Parse(string text) {
if (string.IsNullOrEmpty(text))
@@ -83,7 +91,7 @@ public static Lrc Parse(string text) {
using (StringReader reader = new StringReader(text)) {
string line;
- while ((line = reader.ReadLine()) != null)
+ while (!((line = reader.ReadLine()) is null))
if (!TryParseLine(line.Trim(), lrc))
throw new FormatException();
}
@@ -100,7 +108,7 @@ public static Lrc UnsafeParse(string text) {
using (StringReader reader = new StringReader(text)) {
string line;
- while ((line = reader.ReadLine()) != null)
+ while (!((line = reader.ReadLine()) is null))
TryParseLine(line.Trim(), lrc);
}
return lrc;
@@ -164,15 +172,15 @@ public override string ToString() {
StringBuilder sb;
sb = new StringBuilder();
- if (_title != null)
+ if (!(_title is null))
AppendLine(sb, TI, _title);
- if (_artist != null)
+ if (!(_artist is null))
AppendLine(sb, AR, _artist);
- if (_album != null)
+ if (!(_album is null))
AppendLine(sb, AL, _album);
- if (_by != null)
+ if (!(_by is null))
AppendLine(sb, BY, _by);
- if (_offset != null)
+ if (!(_offset is null))
AppendLine(sb, OFFSET, ((long)_offset.Value.TotalMilliseconds).ToString());
foreach (KeyValuePair lyric in _lyrics)
sb.AppendLine($"[{TimeSpanToLyricString(lyric.Key)}]{lyric.Value}");
diff --git a/NLyric/NLyric.csproj b/NLyric/NLyric.csproj
index a2e090c..77bd82b 100644
--- a/NLyric/NLyric.csproj
+++ b/NLyric/NLyric.csproj
@@ -1,16 +1,22 @@
-
+
NLyric
NLyric
NLyric
Copyright © 2019 Wwh
- 2.0.2.0
- 2.0.2.0
+ 2.1.0.0
+ 2.1.0.0
Exe
netcoreapp2.1;net472
NLyric
7.3
+
+
+
+
+
+
diff --git a/NLyric/CliWorker.cs b/NLyric/NLyricImpl.cs
similarity index 86%
rename from NLyric/CliWorker.cs
rename to NLyric/NLyricImpl.cs
index b1cc286..8e02080 100644
--- a/NLyric/CliWorker.cs
+++ b/NLyric/NLyricImpl.cs
@@ -12,7 +12,7 @@
using NLyric.Settings;
namespace NLyric {
- internal static partial class CliWorker {
+ internal static class NLyricImpl {
private static readonly SearchSettings _searchSettings = AllSettings.Default.Search;
private static readonly FuzzySettings _fuzzySettings = AllSettings.Default.Fuzzy;
private static readonly MatchSettings _matchSettings = AllSettings.Default.Match;
@@ -23,12 +23,14 @@ internal static partial class CliWorker {
// AlbumId -> Tracks
private static readonly Dictionary _cachedNcmLyrics = new Dictionary();
// TrackId -> Lyric
+ private static string _allCachesPath;
private static AllCaches _allCaches;
public static async Task ExecuteAsync(Arguments arguments) {
Logger.Instance.LogInfo("程序会自动过滤相似度为0的结果与歌词未被收集的结果!!!", ConsoleColor.Green);
Logger.Instance.LogNewLine();
- LoadLocalCaches(arguments.Directory);
+ _allCachesPath = Path.Combine(arguments.Directory, ".nlyric");
+ LoadLocalCaches();
foreach (string audioPath in Directory.EnumerateFiles(arguments.Directory, "*", SearchOption.AllDirectories)) {
string lrcPath;
int? trackId;
@@ -39,14 +41,14 @@ public static async Task ExecuteAsync(Arguments arguments) {
Logger.Instance.LogInfo($"开始搜索文件\"{Path.GetFileName(audioPath)}\"的歌词。");
trackId = await TryGetMusicId(audioPath);
// 同时尝试通过163Key和专辑获取歌曲信息
- if (trackId == null)
+ if (trackId is null)
Logger.Instance.LogWarning($"无法找到文件\"{Path.GetFileName(audioPath)}\"的网易云音乐ID!");
else
await WriteLrcAsync(trackId.Value, lrcPath);
Logger.Instance.LogNewLine();
Logger.Instance.LogNewLine();
}
- SaveLocalCaches(arguments.Directory);
+ SaveLocalCaches();
}
private static bool CanSkip(string audioPath, string lrcPath) {
@@ -80,7 +82,7 @@ private static bool IsAudioFile(string extension) {
try {
// 歌曲无163Key,通过自己的算法匹配
ncmTrack = await MapToAsync(track, album, audioPath);
- if (ncmTrack != null) {
+ if (!(ncmTrack is null)) {
trackId = ncmTrack.Id;
Logger.Instance.LogInfo($"已获取文件\"{Path.GetFileName(audioPath)}\"的网易云音乐ID: {trackId}。");
}
@@ -110,16 +112,18 @@ private static async Task WriteLrcAsync(int trackId, string lrcPath) {
}
if (hasLrcFile) {
// 如果歌词存在,判断是否需要覆盖或更新
- if (lyricCache != null && lyricCache.CheckSum == lyricCheckSum) {
+ if (!(lyricCache is null) && lyricCache.CheckSum == lyricCheckSum) {
// 歌词由NLyric创建
if (ncmLyric.RawVersion <= lyricCache.RawVersion && ncmLyric.TranslatedVersion <= lyricCache.TranslatedVersion) {
// 是最新版本
- Logger.Instance.LogInfo("本地歌词已是最新版本,正在跳过。", ConsoleColor.Green);
+ Logger.Instance.LogInfo("本地歌词已是最新版本,正在跳过。", ConsoleColor.Yellow);
return;
}
else {
// 不是最新版本
- if (!_lyricSettings.AutoUpdate) {
+ if (_lyricSettings.AutoUpdate)
+ Logger.Instance.LogInfo("本地歌词不是最新版本,正在更新。", ConsoleColor.Green);
+ else {
Logger.Instance.LogInfo("本地歌词不是最新版本但是自动更新被禁止,正在跳过。", ConsoleColor.Yellow);
return;
}
@@ -128,13 +132,13 @@ private static async Task WriteLrcAsync(int trackId, string lrcPath) {
else {
// 歌词非NLyric创建
if (!_lyricSettings.Overwriting) {
- Logger.Instance.LogInfo("本地歌词已存在并且非NLyric创建,正在跳过。", ConsoleColor.Cyan);
+ Logger.Instance.LogInfo("本地歌词已存在并且非NLyric创建,正在跳过。", ConsoleColor.Yellow);
return;
}
}
}
lrc = ToLrc(ncmLyric);
- if (lrc != null) {
+ if (!(lrc is null)) {
string lyric;
lyric = lrc.ToString();
@@ -153,9 +157,9 @@ private static async Task WriteLrcAsync(int trackId, string lrcPath) {
///
///
private static async Task MapToAsync(Track track, Album album, string audioPath) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
- if (audioPath == null)
+ if (audioPath is null)
throw new ArgumentNullException(nameof(audioPath));
string fileName;
@@ -164,9 +168,9 @@ private static async Task MapToAsync(Track track, Album album, string
NcmTrack ncmTrack;
fileName = Path.GetFileName(audioPath);
- trackCache = album == null ? _allCaches.TrackCaches.Match(track, fileName) : _allCaches.TrackCaches.Match(track, album);
+ trackCache = album is null ? _allCaches.TrackCaches.Match(track, fileName) : _allCaches.TrackCaches.Match(track, album);
// 有专辑信息就用专辑信息,没有专辑信息就用文件名
- if (trackCache != null)
+ if (!(trackCache is null))
return new NcmTrack(track, trackCache.Id);
// 先尝试从缓存获取歌曲
if (The163KeyHelper.TryGetMusicId(audioPath, out trackId)) {
@@ -177,21 +181,21 @@ private static async Task MapToAsync(Track track, Album album, string
NcmAlbum ncmAlbum;
ncmAlbum = null;
- if (album != null) {
+ if (!(album is null)) {
// 存在专辑信息,尝试获取网易云音乐上对应的专辑
AlbumCache albumCache;
albumCache = _allCaches.AlbumCaches.Match(album);
- if (albumCache != null)
+ if (!(albumCache is null))
ncmAlbum = new NcmAlbum(album, albumCache.Id);
// 先尝试从缓存获取专辑
- if (ncmAlbum == null) {
+ if (ncmAlbum is null) {
ncmAlbum = await MapToAsync(album);
- if (ncmAlbum != null)
+ if (!(ncmAlbum is null))
UpdateCache(album, ncmAlbum.Id);
}
}
- if (ncmAlbum == null) {
+ if (ncmAlbum is null) {
// 没有对应的专辑信息,使用无专辑匹配
ncmTrack = await MapToAsync(track);
}
@@ -202,16 +206,16 @@ private static async Task MapToAsync(Track track, Album album, string
ncmTracks = (await GetTracksAsync(ncmAlbum)).Where(t => ComputeSimilarity(t.Name, track.Name, false) != 0).ToArray();
// 获取网易云音乐上专辑收录的歌曲
ncmTrack = MatchByUser(ncmTracks, track);
- if (ncmTrack == null)
+ if (ncmTrack is null)
// 网易云音乐上的专辑可能没收录这个歌曲,不清楚为什么,但是确实存在这个情况,比如专辑id:3094396
ncmTrack = await MapToAsync(track);
}
}
- if (ncmTrack == null)
+ if (ncmTrack is null)
Logger.Instance.LogWarning("歌曲匹配失败!");
else {
Logger.Instance.LogInfo("歌曲匹配成功!");
- if (album == null)
+ if (album is null)
UpdateCache(track, fileName, ncmTrack.Id);
else
UpdateCache(track, album, ncmTrack.Id);
@@ -241,7 +245,7 @@ private static async Task GetTracksAsync(NcmAlbum ncmAlbum) {
///
///
private static async Task MapToAsync(Track track) {
- if (track == null)
+ if (track is null)
throw new ArgumentNullException(nameof(track));
NcmTrack ncmTrack;
@@ -249,7 +253,7 @@ private static async Task MapToAsync(Track track) {
Logger.Instance.LogInfo($"开始搜索歌曲\"{track}\"。");
Logger.Instance.LogWarning("正在尝试带艺术家搜索,结果可能将过少!");
ncmTrack = await MapToAsync(track, true);
- if (ncmTrack == null && _fuzzySettings.TryIgnoringArtists) {
+ if (ncmTrack is null && _fuzzySettings.TryIgnoringArtists) {
Logger.Instance.LogWarning("正在尝试忽略艺术家搜索,结果可能将不精确!");
ncmTrack = await MapToAsync(track, false);
}
@@ -262,7 +266,7 @@ private static async Task MapToAsync(Track track) {
///
///
private static async Task MapToAsync(Album album) {
- if (album == null)
+ if (album is null)
throw new ArgumentNullException(nameof(album));
string replacedAlbumName;
@@ -274,11 +278,11 @@ private static async Task MapToAsync(Album album) {
Logger.Instance.LogInfo($"开始搜索专辑\"{album}\"。");
Logger.Instance.LogWarning("正在尝试带艺术家搜索,结果可能将过少!");
ncmAlbum = await MapToAsync(album, true);
- if (ncmAlbum == null && _fuzzySettings.TryIgnoringArtists) {
+ if (ncmAlbum is null && _fuzzySettings.TryIgnoringArtists) {
Logger.Instance.LogWarning("正在尝试忽略艺术家搜索,结果可能将不精确!");
ncmAlbum = await MapToAsync(album, false);
}
- if (ncmAlbum == null) {
+ if (ncmAlbum is null) {
Logger.Instance.LogWarning("专辑匹配失败!");
_cachedNcmAlbums[replacedAlbumName] = null;
return null;
@@ -321,13 +325,10 @@ private static async Task MapToAsync(Album album, bool withArtists) {
#endregion
#region local cache
- private static void LoadLocalCaches(string directoryPath) {
- string cachePath;
-
- cachePath = Path.Combine(directoryPath, ".nlyric");
- if (File.Exists(cachePath)) {
- _allCaches = JsonConvert.DeserializeObject(File.ReadAllText(cachePath));
- Logger.Instance.LogInfo($"搜索缓存\"{cachePath}\"已被加载。");
+ private static void LoadLocalCaches() {
+ if (File.Exists(_allCachesPath)) {
+ _allCaches = JsonConvert.DeserializeObject(File.ReadAllText(_allCachesPath));
+ Logger.Instance.LogInfo($"搜索缓存\"{_allCachesPath}\"加载成功。");
}
else
_allCaches = new AllCaches() {
@@ -337,15 +338,16 @@ private static void LoadLocalCaches(string directoryPath) {
};
}
- private static void SaveLocalCaches(string directoryPath) {
- string cachePath;
-
- cachePath = Path.Combine(directoryPath, ".nlyric");
+ private static void SaveLocalCaches() {
_allCaches.AlbumCaches.Sort((x, y) => x.Name.CompareTo(y.Name));
_allCaches.TrackCaches.Sort((x, y) => x.Name.CompareTo(y.Name));
_allCaches.LyricCaches.Sort((x, y) => x.Id.CompareTo(y.Id));
+ SaveLocalCachesCore(_allCachesPath);
+ Logger.Instance.LogInfo($"搜索缓存\"{_allCachesPath}\"已被保存。");
+ }
+
+ private static void SaveLocalCachesCore(string cachePath) {
File.WriteAllText(cachePath, FormatJson(JsonConvert.SerializeObject(_allCaches)));
- Logger.Instance.LogInfo($"搜索缓存\"{cachePath}\"已被保存。");
}
private static string FormatJson(string json) {
@@ -362,24 +364,30 @@ private static void UpdateCache(Album album, int id) {
AlbumCache cache;
cache = _allCaches.AlbumCaches.Match(album);
- if (cache == null)
- _allCaches.AlbumCaches.Add(new AlbumCache(album, id));
+ if (!(cache is null))
+ return;
+ _allCaches.AlbumCaches.Add(new AlbumCache(album, id));
+ OnCacheUpdated();
}
private static void UpdateCache(Track track, Album album, int id) {
TrackCache cache;
cache = _allCaches.TrackCaches.Match(track, album);
- if (cache == null)
- _allCaches.TrackCaches.Add(new TrackCache(track, album, id));
+ if (!(cache is null))
+ return;
+ _allCaches.TrackCaches.Add(new TrackCache(track, album, id));
+ OnCacheUpdated();
}
private static void UpdateCache(Track track, string fileName, int id) {
TrackCache cache;
cache = _allCaches.TrackCaches.Match(track, fileName);
- if (cache == null)
- _allCaches.TrackCaches.Add(new TrackCache(track, fileName, id));
+ if (!(cache is null))
+ return;
+ _allCaches.TrackCaches.Add(new TrackCache(track, fileName, id));
+ OnCacheUpdated();
}
private static void UpdateCache(NcmLyric lyric, string checkSum) {
@@ -389,6 +397,11 @@ private static void UpdateCache(NcmLyric lyric, string checkSum) {
if (index != -1)
_allCaches.LyricCaches.RemoveAt(index);
_allCaches.LyricCaches.Add(new LyricCache(lyric, checkSum));
+ OnCacheUpdated();
+ }
+
+ private static void OnCacheUpdated() {
+ SaveLocalCachesCore(_allCachesPath);
}
#endregion
@@ -399,7 +412,7 @@ private static TSource MatchByUser(TSource[] sources, TTarget
if (sources.Length == 0)
return null;
result = MatchByUser(sources, target, false);
- if (result == null && _fuzzySettings.TryIgnoringExtraInfo)
+ if (result is null && _fuzzySettings.TryIgnoringExtraInfo)
result = MatchByUser(sources, target, true);
return result;
}
@@ -415,8 +428,8 @@ private static TSource MatchByUser(TSource[] sources, TTarget
foreach (TSource source in sources)
nameSimilarities[source] = ComputeSimilarity(source.Name, target.Name, fuzzy);
result = Match(sources, target, nameSimilarities, out isExact);
- if (result != null && (isExact || Confirm("不完全相似,是否使用自动匹配结果?")))
- // 自动匹配成功,如果是完全匹配,不需要用户再次确认,反正由用户再次确认
+ if (isExact)
+ // 自动匹配成功,如果是完全匹配,不需要用户再次确认
return result;
return fuzzy ? Select(sources.Where(t => nameSimilarities[t] > _matchSettings.MinimumSimilarityUser).OrderByDescending(t => t, new DictionaryComparer(nameSimilarities)).ToArray(), target, nameSimilarities) : null;
// fuzzy为true时是第二次搜索了,再让用户再次手动从搜索结果中选择,自动匹配失败的原因可能是 Settings.Match.MinimumSimilarity 设置太大了
@@ -482,7 +495,7 @@ private static TSource Select(TSource[] sources, TTarget targe
}
Logger.Instance.LogWarning("输入有误,请重新输入!");
} while (true);
- if (result != null)
+ if (!(result is null))
Logger.Instance.LogInfo("已选择:" + result.ToString());
return result;
@@ -493,23 +506,6 @@ string TrackOrAlbumToString(ITrackOrAlbum trackOrAlbum) {
}
}
- private static bool Confirm(string text) {
- Logger.Instance.LogInfo(text);
- Logger.Instance.LogInfo("请手动输入Yes或No。");
- do {
- string userInput;
-
- userInput = Console.ReadLine().Trim().ToUpperInvariant();
- switch (userInput) {
- case "YES":
- return true;
- case "NO":
- return false;
- }
- Logger.Instance.LogWarning("输入有误,请重新输入!");
- } while (true);
- }
-
private static double ComputeSimilarity(string x, string y, bool fuzzy) {
x = x.ReplaceEx();
y = y.ReplaceEx();
@@ -543,20 +539,24 @@ private static Lrc ToLrc(NcmLyric lyric) {
Logger.Instance.LogWarning("当前歌曲是纯音乐无歌词!");
return null;
}
+ if (!(lyric.Raw is null))
+ NormalizeLyric(lyric.Raw, false);
+ if (!(lyric.Translated is null))
+ NormalizeLyric(lyric.Translated, _lyricSettings.SimplifyTranslated);
foreach (string mode in _lyricSettings.Modes) {
switch (mode.ToUpperInvariant()) {
case "MERGED":
- if (lyric.Raw == null || lyric.Translated == null)
+ if (lyric.Raw is null || lyric.Translated is null)
continue;
Logger.Instance.LogInfo("已获取混合歌词。");
return MergeLyric(lyric.Raw, lyric.Translated);
case "RAW":
- if (lyric.Raw == null)
+ if (lyric.Raw is null)
continue;
Logger.Instance.LogInfo("已获取原始歌词。");
return lyric.Raw;
case "TRANSLATED":
- if (lyric.Translated == null)
+ if (lyric.Translated is null)
continue;
Logger.Instance.LogInfo("已获取翻译歌词。");
return lyric.Translated;
@@ -568,12 +568,22 @@ private static Lrc ToLrc(NcmLyric lyric) {
return null;
}
- private static Lrc MergeLyric(Lrc rawLrc, Lrc translatedLrc) {
- if (rawLrc == null)
- throw new ArgumentNullException(nameof(rawLrc));
- if (translatedLrc == null)
- throw new ArgumentNullException(nameof(translatedLrc));
+ private static void NormalizeLyric(Lrc lrc, bool simplify) {
+ Dictionary newLyrics;
+ newLyrics = new Dictionary(lrc.Lyrics.Count);
+ foreach (KeyValuePair lyric in lrc.Lyrics) {
+ string value;
+
+ value = lyric.Value.Trim('/', ' ');
+ if (simplify)
+ value = ChineseConverter.TraditionalToSimplified(value);
+ newLyrics.Add(lyric.Key, value);
+ }
+ lrc.Lyrics = newLyrics;
+ }
+
+ private static Lrc MergeLyric(Lrc rawLrc, Lrc translatedLrc) {
Lrc mergedLrc;
mergedLrc = new Lrc {
diff --git a/NLyric/Ncm/NcmApi.cs b/NLyric/Ncm/NcmApi.cs
index 1cfff0b..a38c092 100644
--- a/NLyric/Ncm/NcmApi.cs
+++ b/NLyric/Ncm/NcmApi.cs
@@ -24,17 +24,19 @@ public enum SearchType {
}
public static async Task SearchAsync(IEnumerable keywords, SearchType type, int limit) {
- FormUrlEncodedCollection parameters;
+ QueryCollection queries;
- parameters = new FormUrlEncodedCollection {
+ queries = new QueryCollection {
{ "s", string.Join(" ", keywords) },
{ "type", ((int)type).ToString() },
{ "limit", limit.ToString() }
};
using (HttpClient client = new HttpClient())
- using (HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, SEARCH_URL, parameters, null)) {
+ using (HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, SEARCH_URL, queries, null)) {
JObject json;
+ if (!response.IsSuccessStatusCode)
+ throw new HttpRequestException();
json = JObject.Parse(await response.Content.ReadAsStringAsync());
if ((int)json["code"] != 200)
throw new HttpRequestException();
@@ -43,15 +45,17 @@ public static async Task SearchAsync(IEnumerable keywords, Searc
}
public static async Task GetAlbumAsync(int id) {
- FormUrlEncodedCollection parameters;
+ QueryCollection queries;
- parameters = new FormUrlEncodedCollection {
+ queries = new QueryCollection {
{ "id", id.ToString() }
};
using (HttpClient client = new HttpClient())
- using (HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, ALBUM_URL, parameters, null)) {
+ using (HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, ALBUM_URL, queries, null)) {
JObject json;
+ if (!response.IsSuccessStatusCode)
+ throw new HttpRequestException();
json = JObject.Parse(await response.Content.ReadAsStringAsync());
if ((int)json["code"] != 200)
throw new HttpRequestException();
@@ -60,17 +64,19 @@ public static async Task GetAlbumAsync(int id) {
}
public static async Task GetLyricAsync(int id) {
- FormUrlEncodedCollection parameters;
+ QueryCollection queries;
- parameters = new FormUrlEncodedCollection {
+ queries = new QueryCollection {
{ "id", id.ToString() },
{ "lv", "-1" },
{ "tv", "-1" }
};
using (HttpClient client = new HttpClient())
- using (HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, LYRIC_URL, parameters, null)) {
+ using (HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, LYRIC_URL, queries, null)) {
JObject json;
+ if (!response.IsSuccessStatusCode)
+ throw new HttpRequestException();
json = JObject.Parse(await response.Content.ReadAsStringAsync());
if ((int)json["code"] != 200)
throw new HttpRequestException();
diff --git a/NLyric/Program.cs b/NLyric/Program.cs
index 03907d3..fb53eb8 100644
--- a/NLyric/Program.cs
+++ b/NLyric/Program.cs
@@ -8,7 +8,7 @@
namespace NLyric {
public static class Program {
private static void Main(string[] args) {
- if (args == null || args.Length == 0) {
+ if (args is null || args.Length == 0) {
CommandLine.ShowUsage();
return;
}
@@ -25,7 +25,7 @@ private static void Main(string[] args) {
return;
}
AllSettings.Default = JsonConvert.DeserializeObject(File.ReadAllText("Settings.json"));
- CliWorker.ExecuteAsync(arguments).GetAwaiter().GetResult();
+ NLyricImpl.ExecuteAsync(arguments).GetAwaiter().GetResult();
Logger.Instance.LogInfo("完成", ConsoleColor.Green);
#if DEBUG
Console.ReadKey(true);
diff --git a/NLyric/FormUrlEncodedCollection.cs b/NLyric/QueryCollection.cs
similarity index 65%
rename from NLyric/FormUrlEncodedCollection.cs
rename to NLyric/QueryCollection.cs
index e0e78cc..749aee2 100644
--- a/NLyric/FormUrlEncodedCollection.cs
+++ b/NLyric/QueryCollection.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
namespace NLyric {
- internal sealed class FormUrlEncodedCollection : List> {
+ internal sealed class QueryCollection : List> {
public void Add(string key, string value) {
Add(new KeyValuePair(key, value));
}
diff --git a/NLyric/Settings.json b/NLyric/Settings.json
index 1b465ee..4ab2274 100644
--- a/NLyric/Settings.json
+++ b/NLyric/Settings.json
@@ -68,6 +68,7 @@
"Raw",
"Translated"
], // 歌词模式,依次尝试每一个模式直到成功,Merged表示混合未翻译和翻译后歌词,Raw表示未翻译的歌词,Translated表示翻译后的歌词
+ "SimplifyTranslated": true, // 部分翻译后的歌词是繁体的,这个选项可以简体化翻译后的歌词
"AutoUpdate": true, // 是否自动更新由NLyric创建的歌词
"Overwriting": false // 是否覆盖非NLyric创建的歌词
}
diff --git a/NLyric/Settings/AllSettings.cs b/NLyric/Settings/AllSettings.cs
index 61879fe..c061aa3 100644
--- a/NLyric/Settings/AllSettings.cs
+++ b/NLyric/Settings/AllSettings.cs
@@ -6,15 +6,17 @@ internal sealed class AllSettings {
public static AllSettings Default {
get {
- if (_default == null)
+ if (_default is null)
throw new InvalidOperationException();
+
return _default;
}
set {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
- if (_default != null)
+ if (!(_default is null))
throw new InvalidOperationException();
+
_default = value;
}
}
diff --git a/NLyric/Settings/LyricSettings.cs b/NLyric/Settings/LyricSettings.cs
index a763a1e..64ff713 100644
--- a/NLyric/Settings/LyricSettings.cs
+++ b/NLyric/Settings/LyricSettings.cs
@@ -2,6 +2,8 @@ namespace NLyric.Settings {
internal sealed class LyricSettings {
public string[] Modes { get; set; }
+ public bool SimplifyTranslated { get; set; }
+
public bool AutoUpdate { get; set; }
public bool Overwriting { get; set; }
diff --git a/NLyric/StringHelper.cs b/NLyric/StringHelper.cs
index 59df501..4bb0301 100644
--- a/NLyric/StringHelper.cs
+++ b/NLyric/StringHelper.cs
@@ -16,7 +16,7 @@ internal static class StringHelper {
///
///
public static string GetSafeString(this string value) {
- return value == null ? string.Empty : value.Trim();
+ return value is null ? string.Empty : value.Trim();
}
///
@@ -25,7 +25,7 @@ public static string GetSafeString(this string value) {
///
///
public static string ReplaceEx(this string value) {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
return value.ToHalfWidth().WholeWordReplace().CharReplace();
@@ -37,7 +37,7 @@ public static string ReplaceEx(this string value) {
///
///
public static string WholeWordReplace(this string value) {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
if (value.Length == 0)
@@ -54,7 +54,7 @@ public static string WholeWordReplace(this string value) {
///
///
public static string CharReplace(this string value) {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
StringBuilder buffer;
@@ -75,7 +75,7 @@ public static string CharReplace(this string value) {
///
///
public static string Fuzzy(this string value) {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
int fuzzyStartIndex;
@@ -97,7 +97,7 @@ public static string Fuzzy(this string value) {
///
///
public static string[] SplitEx(this string value) {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
return value.Split(_searchSettings.Separators, StringSplitOptions.RemoveEmptyEntries);
@@ -109,7 +109,7 @@ public static string[] SplitEx(this string value) {
///
///
public static string ToHalfWidth(this string value) {
- if (value == null)
+ if (value is null)
throw new ArgumentNullException(nameof(value));
char[] chars;
diff --git a/NLyric/System/Cli/ArgumentAttribute.cs b/NLyric/System/Cli/ArgumentAttribute.cs
index 3c1dc46..4cf61c4 100644
--- a/NLyric/System/Cli/ArgumentAttribute.cs
+++ b/NLyric/System/Cli/ArgumentAttribute.cs
@@ -10,23 +10,38 @@ internal sealed class ArgumentAttribute : Attribute {
private string _type;
private string _description;
+ ///
+ /// 参数名
+ ///
public string Name => _name;
+ ///
+ /// 是否为必选参数
+ ///
public bool IsRequired {
get => _isRequired;
set => _isRequired = value;
}
+ ///
+ /// 默认值,当 为 时, 必须为 。
+ ///
public object DefaultValue {
get => _defaultValue;
set => _defaultValue = value;
}
+ ///
+ /// 参数类型,用于 显示类型来简单描述参数。若应用到返回类型为 的属性上, 必须为 。
+ ///
public string Type {
get => _type;
set => _type = value;
}
+ ///
+ /// 参数介绍,用于 具体描述参数。
+ ///
public string Description {
get => _description;
set => _description = value;
diff --git a/NLyric/System/Cli/CommandLine.cs b/NLyric/System/Cli/CommandLine.cs
index f483a59..1fa70d1 100644
--- a/NLyric/System/Cli/CommandLine.cs
+++ b/NLyric/System/Cli/CommandLine.cs
@@ -6,7 +6,7 @@
namespace System.Cli {
internal static class CommandLine {
public static T Parse(string[] args) where T : new() {
- if (args == null)
+ if (args is null)
throw new ArgumentNullException(nameof(args));
T result;
@@ -17,7 +17,7 @@ internal static class CommandLine {
}
public static bool TryParse(string[] args, out T result) where T : new() {
- if (args == null) {
+ if (args is null) {
result = default;
return false;
}
@@ -102,7 +102,7 @@ public static bool ShowUsage() {
if (!VerifyProperty(propertyInfo, out attribute))
return false;
- if (attribute == null)
+ if (attribute is null)
continue;
argumentInfos.Add(new ArgumentInfo(attribute, propertyInfo));
}
@@ -135,7 +135,7 @@ private static bool TryGetArgumentInfos(Type type, out Dictionary SendAsync(this HttpClient client, HttpMe
return client.SendAsync(method, url, null, null);
}
- public static Task SendAsync(this HttpClient client, HttpMethod method, string url, IEnumerable> parameters, IEnumerable> headers) {
- return client.SendAsync(method, url, parameters, headers, (byte[])null, "application/x-www-form-urlencoded");
+ public static Task SendAsync(this HttpClient client, HttpMethod method, string url, IEnumerable> queries, IEnumerable> headers) {
+ return client.SendAsync(method, url, queries, headers, (byte[])null, "application/x-www-form-urlencoded");
}
- public static Task SendAsync(this HttpClient client, HttpMethod method, string url, IEnumerable> parameters, IEnumerable> headers, string content, string contentType) {
- return client.SendAsync(method, url, parameters, headers, content == null ? null : Encoding.UTF8.GetBytes(content), contentType);
+ public static Task SendAsync(this HttpClient client, HttpMethod method, string url, IEnumerable> queries, IEnumerable> headers, string content, string contentType) {
+ return client.SendAsync(method, url, queries, headers, content is null ? null : Encoding.UTF8.GetBytes(content), contentType);
}
- public static Task SendAsync(this HttpClient client, HttpMethod method, string url, IEnumerable> parameters, IEnumerable> headers, byte[] content, string contentType) {
- if (client == null)
+ public static Task SendAsync(this HttpClient client, HttpMethod method, string url, IEnumerable> queries, IEnumerable> headers, byte[] content, string contentType) {
+ if (client is null)
throw new ArgumentNullException(nameof(client));
- if (method == null)
+ if (method is null)
throw new ArgumentNullException(nameof(method));
if (string.IsNullOrEmpty(url))
throw new ArgumentNullException(nameof(url));
if (string.IsNullOrEmpty(contentType))
throw new ArgumentNullException(nameof(contentType));
- if (method != HttpMethod.Get && parameters != null && content != null)
- throw new NotSupportedException();
UriBuilder uriBuilder;
HttpRequestMessage request;
uriBuilder = new UriBuilder(url);
- if (parameters != null && method == HttpMethod.Get) {
+ if (!(queries is null)) {
string query;
- query = FormToString(parameters);
+ query = queries.ToQueryString();
if (!string.IsNullOrEmpty(query))
if (string.IsNullOrEmpty(uriBuilder.Query))
uriBuilder.Query = query;
@@ -46,29 +43,16 @@ public static Task SendAsync(this HttpClient client, HttpMe
uriBuilder.Query += "&" + query;
}
request = new HttpRequestMessage(method, uriBuilder.Uri);
- if (content != null)
+ if (!(content is null))
request.Content = new ByteArrayContent(content);
- else if (parameters != null && method != HttpMethod.Get)
- request.Content = new FormUrlEncodedContent(parameters);
- if (request.Content != null)
+ else if (!(queries is null) && method != HttpMethod.Get)
+ request.Content = new FormUrlEncodedContent(queries);
+ if (!(request.Content is null))
request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
- if (headers != null)
- UpdateHeaders(request.Headers, headers);
+ if (!(headers is null))
+ foreach (KeyValuePair header in headers)
+ request.Headers.TryAddWithoutValidation(header.Key, header.Value);
return client.SendAsync(request);
}
-
- private static string FormToString(IEnumerable> values) {
- return string.Join("&", values.Select(t => t.Key + "=" + Uri.EscapeDataString(t.Value)));
- }
-
- private static void UpdateHeaders(HttpRequestHeaders requestHeaders, IEnumerable> headers) {
- if (requestHeaders == null)
- throw new ArgumentNullException(nameof(requestHeaders));
- if (headers == null)
- throw new ArgumentNullException(nameof(headers));
-
- foreach (KeyValuePair item in headers)
- requestHeaders.TryAddWithoutValidation(item.Key, item.Value);
- }
}
}
diff --git a/NLyric/System/Extensions/HttpExtensions.cs b/NLyric/System/Extensions/HttpExtensions.cs
new file mode 100644
index 0000000..02640da
--- /dev/null
+++ b/NLyric/System/Extensions/HttpExtensions.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace System.Extensions {
+ internal static class HttpExtensions {
+ public static string ToQueryString(this IEnumerable> queries) {
+ if (queries is null)
+ throw new ArgumentNullException(nameof(queries));
+
+ return string.Join("&", queries.Select(t => Uri.EscapeDataString(t.Key) + "=" + Uri.EscapeDataString(t.Value)));
+ }
+ }
+}
diff --git a/NLyric/The163KeyHelper.cs b/NLyric/The163KeyHelper.cs
index 699046d..6fd4f93 100644
--- a/NLyric/The163KeyHelper.cs
+++ b/NLyric/The163KeyHelper.cs
@@ -38,7 +38,7 @@ public static bool TryGetMusicId(string filePath, out int trackId) {
byt163Key = null;
break;
}
- if (byt163Key == null) {
+ if (byt163Key is null) {
trackId = 0;
return false;
}
diff --git a/NLyric/TraditionalToSimplified.map b/NLyric/TraditionalToSimplified.map
new file mode 100644
index 0000000..54c8efe
Binary files /dev/null and b/NLyric/TraditionalToSimplified.map differ