diff --git a/.editorconfig b/.editorconfig
index fd05618..fa67d48 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -45,7 +45,7 @@ csharp_space_between_method_declaration_parameter_list_parentheses = false
#Formatting - wrapping options
#leave code block on separate lines
-csharp_preserve_single_line_blocks = false
+csharp_preserve_single_line_blocks = true
#Style - Code block preferences
diff --git a/OnlineMusicApi/OnlineMusicApi.csproj b/OnlineMusicApi/OnlineMusicApi.csproj
deleted file mode 100644
index e2f49b7..0000000
--- a/OnlineMusicApi/OnlineMusicApi.csproj
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
- OnlineMusicApi
- OnlineMusicApi
- 在线音乐API
- Copyright © 2019 Binaryify / Wwh
- 3.25.3.0
- net9.0
- true
- ../OnlineMusicApi.snk
- False
- IDE1006;CS0436;CS3021
- true
- ..\bin\$(Configuration)
- OnlineMusicApi
- Binaryify / Wwh
- $(Version)
- https://github.com/wwh1004/OnlineMusicApi
- MIT
- true
- true
- snupkg
- preview
- Exe
-
-
-
-
-
-
diff --git a/OnlineMusicApi/QueryCollection.cs b/OnlineMusicApi/QueryCollection.cs
deleted file mode 100644
index bddfa1e..0000000
--- a/OnlineMusicApi/QueryCollection.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using System.Collections.Generic;
-
-namespace NeteaseCloudMusicApi;
-
-internal sealed class QueryCollection : List>
-{
- public void Add(string key, string value) => Add(new KeyValuePair(key, value));
-}
diff --git a/The Untamed Music Player.sln b/The Untamed Music Player.sln
index 52904be..271b8ef 100644
--- a/The Untamed Music Player.sln
+++ b/The Untamed Music Player.sln
@@ -5,8 +5,6 @@ VisualStudioVersion = 17.10.35027.167
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "The Untamed Music Player", "The Untamed Music Player\The Untamed Music Player.csproj", "{FAF574F3-DB0A-4B33-BF19-45CF6396C9F7}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OnlineMusicApi", "OnlineMusicApi\OnlineMusicApi.csproj", "{BA37573B-D0FC-4FF6-8D06-5F59F348B90B}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -43,22 +41,6 @@ Global
{FAF574F3-DB0A-4B33-BF19-45CF6396C9F7}.Release|x86.ActiveCfg = Release|x86
{FAF574F3-DB0A-4B33-BF19-45CF6396C9F7}.Release|x86.Build.0 = Release|x86
{FAF574F3-DB0A-4B33-BF19-45CF6396C9F7}.Release|x86.Deploy.0 = Release|x86
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|arm64.ActiveCfg = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|arm64.Build.0 = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|x64.Build.0 = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Debug|x86.Build.0 = Debug|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|Any CPU.Build.0 = Release|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|arm64.ActiveCfg = Release|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|arm64.Build.0 = Release|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|x64.ActiveCfg = Release|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|x64.Build.0 = Release|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|x86.ActiveCfg = Release|Any CPU
- {BA37573B-D0FC-4FF6-8D06-5F59F348B90B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/The Untamed Music Player/App.xaml.cs b/The Untamed Music Player/App.xaml.cs
index 1f37907..945f19a 100644
--- a/The Untamed Music Player/App.xaml.cs
+++ b/The Untamed Music Player/App.xaml.cs
@@ -85,6 +85,7 @@ public partial class App : Application
services.AddSingleton();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
services.AddTransient();
// Configuration
diff --git a/The Untamed Music Player/Contracts/Models/IMusicInfoBase.cs b/The Untamed Music Player/Contracts/Models/IMusicInfoBase.cs
new file mode 100644
index 0000000..dec4732
--- /dev/null
+++ b/The Untamed Music Player/Contracts/Models/IMusicInfoBase.cs
@@ -0,0 +1,90 @@
+using Microsoft.UI;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Media.Imaging;
+
+namespace The_Untamed_Music_Player.Contracts.Models;
+public interface IBriefMusicInfoBase
+{
+ string Path { get; set; }
+ string Title { get; set; }
+ string Album { get; set; }
+ string ArtistsStr { get; set; }
+ string DurationStr { get; set; }
+ string YearStr { get; set; }
+
+ ///
+ /// 获取参与创作的艺术家名字符串
+ ///
+ ///
+ ///
+ static string GetArtistsStr(string[] artists) => string.Join(", ", artists);
+
+ ///
+ /// 获取时长字符串
+ ///
+ ///
+ static string GetDurationStr(TimeSpan duration) => duration.Hours > 0 ? $"{duration:hh\\:mm\\:ss}" : $"{duration:mm\\:ss}";
+
+ ///
+ /// 获取发行年份字符串
+ ///
+ ///
+ ///
+ static string GetYearStr(ushort year) => year is 0 ? "" : year.ToString();
+
+ ///
+ /// 获取文本前景色
+ ///
+ ///
+ ///
+ /// 如果是当前播放歌曲, 返回主题色, 如果不是, 根据当前主题返回黑色或白色
+ SolidColorBrush GetTextForeground(IDetailedMusicInfoBase currentMusic, bool isDarkTheme)
+ {
+ var isCurrentMusic = Path == currentMusic.Path;
+ if (isCurrentMusic)
+ {
+ var color = isDarkTheme ? ColorHelper.FromArgb(0xFF, 0x42, 0x9C, 0xE3) : ColorHelper.FromArgb(0xFF, 0x00, 0x5A, 0x9E);
+ return new SolidColorBrush(color);
+ }
+ return new SolidColorBrush(isDarkTheme ? Colors.White : Colors.Black);
+ }
+}
+
+public interface IDetailedMusicInfoBase : IBriefMusicInfoBase
+{
+ bool IsOnline { get; set; }
+ string GenreStr { get; set; }
+ string ItemType { get; set; }
+ string AlbumArtistsStr { get; set; }
+ string ArtistAndAlbumStr { get; set; }
+ BitmapImage? Cover { get; set; }
+ string BitRate { get; set; }
+ string Track { get; set; }
+ string Lyric { get; set; }
+
+ ///
+ /// 获取专辑艺术家字符串
+ ///
+ ///
+ ///
+ static string GetAlbumArtistsStr(string[] albumArtists) => string.Join(", ", albumArtists);
+
+ ///
+ /// 获取艺术家和专辑名字符串
+ ///
+ ///
+ ///
+ ///
+ static string GetArtistAndAlbumStr(string album, string artistsStr)
+ {
+ if (string.IsNullOrEmpty(artistsStr))
+ {
+ return album ?? "";
+ }
+ if (string.IsNullOrEmpty(album))
+ {
+ return artistsStr;
+ }
+ return $"{artistsStr} • {album}";
+ }
+}
diff --git a/The Untamed Music Player/Contracts/Models/IOnlineMusicInfo.cs b/The Untamed Music Player/Contracts/Models/IOnlineMusicInfo.cs
new file mode 100644
index 0000000..a82badf
--- /dev/null
+++ b/The Untamed Music Player/Contracts/Models/IOnlineMusicInfo.cs
@@ -0,0 +1,11 @@
+namespace The_Untamed_Music_Player.Contracts.Models;
+public interface IBriefOnlineMusicInfo : IBriefMusicInfoBase
+{
+ bool IsAvailable { get; set; }
+ long ID { get; set; }
+ long AlbumID { get; set; }
+}
+
+public interface IDetailedOnlineMusicInfo : IBriefOnlineMusicInfo, IDetailedMusicInfoBase
+{
+}
\ No newline at end of file
diff --git a/The Untamed Music Player/Contracts/Models/IOnlineMusicInfoList.cs b/The Untamed Music Player/Contracts/Models/IOnlineMusicInfoList.cs
new file mode 100644
index 0000000..d280627
--- /dev/null
+++ b/The Untamed Music Player/Contracts/Models/IOnlineMusicInfoList.cs
@@ -0,0 +1,13 @@
+using System.Collections.ObjectModel;
+using The_Untamed_Music_Player.Models;
+
+namespace The_Untamed_Music_Player.Contracts.Models;
+public abstract class IBriefOnlineMusicInfoList : ObservableCollection
+{
+ protected string _keyWords = "";
+ public bool HasAllLoaded { get; set; } = false;
+
+ public abstract Task SearchAsync(string keyWords);
+ public abstract Task SearchMore();
+ public abstract Task> GetSearchResultAsync(string keyWords);
+}
\ No newline at end of file
diff --git a/The Untamed Music Player/Models/AlbumInfo.cs b/The Untamed Music Player/Models/AlbumInfo.cs
index 2189857..2c6bcd2 100644
--- a/The Untamed Music Player/Models/AlbumInfo.cs
+++ b/The Untamed Music Player/Models/AlbumInfo.cs
@@ -7,7 +7,7 @@ public class BriefAlbumInfo(AlbumInfo albumInfo)
public string Name { get; set; } = albumInfo.Name;
public string YearStr { get; set; } = albumInfo.Year == 0 ? "AlbumInfo_UnknownYear".GetLocalized() : albumInfo.Year.ToString();
public BitmapImage? Cover { get; set; } = albumInfo.Cover;
- public List SongList { get; set; } = [.. Data.MusicLibrary.GetMusicsByAlbum(albumInfo)];
+ public List SongList { get; set; } = [.. Data.MusicLibrary.GetSongsByAlbum(albumInfo)];
}
public class AlbumInfo
diff --git a/The Untamed Music Player/Models/Data.cs b/The Untamed Music Player/Models/Data.cs
index 0280e78..90030d9 100644
--- a/The Untamed Music Player/Models/Data.cs
+++ b/The Untamed Music Player/Models/Data.cs
@@ -11,14 +11,10 @@ public static class Data
///
public static bool NotFirstUsed { get; set; } = false;
- public static AlbumInfo? SelectedAlbum
- {
- get; set;
- }
- public static ArtistInfo? SelectedArtist
- {
- get; set;
- }
+ public static bool HasMusicLibraryLoaded { get; set; } = false;
+
+ public static AlbumInfo? SelectedAlbum { get; set; }
+ public static ArtistInfo? SelectedArtist { get; set; }
///
/// 软件显示名称
@@ -43,63 +39,25 @@ public static class Data
///
/// 是否显示歌词背景
///
- public static bool IsLyricBackgroundVisible = false;
+ public static bool IsLyricBackgroundVisible { get; set; } = false;
- public static MusicPlayer MusicPlayer { get; set; } = new();
+ public static OnlineMusicLibrary OnlineMusicLibrary { get; set; } = new();
public static MusicLibrary MusicLibrary { get; set; } = new();
- public static bool hasMusicLibraryLoaded { get; set; } = false;
+ public static MusicPlayer MusicPlayer { get; set; } = new();
+ public static MainWindow? MainWindow { get; set; }
+ public static ShellPage? ShellPage { get; set; }
+ public static HomePage HomePage { get; set; } = null!;
+ public static MusicLibraryPage? MusicLibraryPage { get; set; }
+ public static LyricPage? LyricPage { get; set; }
+ public static RootPlayBarView? RootPlayBarView { get; set; }
+ public static DesktopLyricWindow? DesktopLyricWindow { get; set; }
- public static MainWindow? MainWindow
- {
- get; set;
- }
- public static MainViewModel? MainViewModel
- {
- get; set;
- }
- public static ShellPage? ShellPage
- {
- get; set;
- }
- public static MusicLibraryPage? MusicLibraryPage
- {
- get; set;
- }
- public static LyricPage? LyricPage
- {
- get; set;
- }
- public static RootPlayBarView? RootPlayBarView
- {
- get; set;
- }
- public static DesktopLyricWindow? DesktopLyricWindow
- {
- get; set;
- }
- public static SettingsViewModel? SettingsViewModel
- {
- get; set;
- }
- public static ShellViewModel? ShellViewModel
- {
- get; set;
- }
- public static RootPlayBarViewModel? RootPlayBarViewModel
- {
- get; set;
- }
- public static HaveMusicViewModel? HaveMusicViewModel
- {
- get; set;
- }
- public static LocalSongsViewModel? LocalSongsViewModel
- {
- get; set;
- }
- public static LocalAlbumsViewModel? LocalAlbumsViewModel
- {
- get; set;
- }
-}
+ public static MainViewModel? MainViewModel { get; set; }
+ public static SettingsViewModel? SettingsViewModel { get; set; }
+ public static ShellViewModel? ShellViewModel { get; set; }
+ public static RootPlayBarViewModel? RootPlayBarViewModel { get; set; }
+ public static HaveMusicViewModel? HaveMusicViewModel { get; set; }
+ public static LocalSongsViewModel? LocalSongsViewModel { get; set; }
+ public static LocalAlbumsViewModel? LocalAlbumsViewModel { get; set; }
+}
\ No newline at end of file
diff --git a/The Untamed Music Player/Models/MusicInfo.cs b/The Untamed Music Player/Models/MusicInfo.cs
index d4bf0aa..0dcc55e 100644
--- a/The Untamed Music Player/Models/MusicInfo.cs
+++ b/The Untamed Music Player/Models/MusicInfo.cs
@@ -3,11 +3,12 @@ using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
+using The_Untamed_Music_Player.Contracts.Models;
using The_Untamed_Music_Player.Helpers;
using Windows.Storage.Streams;
namespace The_Untamed_Music_Player.Models;
-public class BriefMusicInfo
+public class BriefMusicInfo : IBriefMusicInfoBase
{
///
/// 歌手分隔符
@@ -25,20 +26,15 @@ public class BriefMusicInfo
public string Folder { get; set; } = "";
///
- /// 项目类型
+ /// 歌曲名
///
- public string ItemType { get; set; } = "";
+ public string Title { get; set; } = "";
///
/// 专辑名, 为空时返回"未知专辑"
///
public virtual string Album { get; set; } = "";
- ///
- /// 歌曲名
- ///
- public string Title { get; set; } = "";
-
///
/// 参与创作的艺术家数组
///
@@ -61,7 +57,7 @@ public class BriefMusicInfo
public TimeSpan Duration { get; set; } = TimeSpan.Zero;
///
- /// 时长字符串
+ /// 时长字符串, 为空时返回00:00
///
public virtual string DurationStr { get; set; } = "";
@@ -71,17 +67,14 @@ public class BriefMusicInfo
public ushort Year { get; set; } = 0;
///
- /// 发行年份字符串, 为0时返回空字符串
+ /// 发行年份字符串, 为0时返回""
///
public string YearStr { get; set; } = "";
///
/// 封面(可能为空)
///
- public virtual BitmapImage? Cover
- {
- get; set;
- }
+ public virtual BitmapImage? Cover { get; set; }
///
/// 流派数组
@@ -98,9 +91,7 @@ public class BriefMusicInfo
///
public long ModifiedDate { get; set; } = 0;
- public BriefMusicInfo()
- {
- }
+ public BriefMusicInfo() { }
///
/// 异步工厂方法
@@ -115,7 +106,6 @@ public class BriefMusicInfo
Path = path,
Folder = folder,
ModifiedDate = new DateTimeOffset(new FileInfo(path).LastWriteTime).ToUnixTimeSeconds(),
- ItemType = System.IO.Path.GetExtension(path).ToLower()
};
Task? coverTask = null;
@@ -131,14 +121,14 @@ public class BriefMusicInfo
info.Title = string.IsNullOrEmpty(musicFile.Tag.Title) ? System.IO.Path.GetFileNameWithoutExtension(path) : musicFile.Tag.Title;
string[] combinedArtists = [.. musicFile.Tag.AlbumArtists, .. musicFile.Tag.Performers];
info.Artists = combinedArtists.Length != 0 ? combinedArtists : ["MusicInfo_UnknownArtist".GetLocalized()];
- info.ArtistsStr = info.GetArtistsStr();
+ info.ArtistsStr = IBriefMusicInfoBase.GetArtistsStr(info.Artists);
info.Year = (ushort)musicFile.Tag.Year;
- info.YearStr = info.GetYearStr();
+ info.YearStr = IBriefMusicInfoBase.GetYearStr(info.Year);
var genres = musicFile.Tag.Genres;
info.Genre = genres.Length != 0 ? genres : ["MusicInfo_UnknownGenre".GetLocalized()];
- info.GenreStr = info.GetGenreStr();
+ info.GenreStr = GetGenreStr(info.Genre);
info.Duration = musicFile.Properties.Duration;
- info.DurationStr = info.GetDurationStr();
+ info.DurationStr = IBriefMusicInfoBase.GetDurationStr(info.Duration);
// 等待 LoadCoverAsync 任务完成
if (coverTask != null)
@@ -152,10 +142,10 @@ public class BriefMusicInfo
info.Title = System.IO.Path.GetFileNameWithoutExtension(path);
info.Album = "MusicInfo_UnknownAlbum".GetLocalized();
info.Artists = ["MusicInfo_UnknownArtist".GetLocalized()];
- info.ArtistsStr = info.GetArtistsStr();
+ info.ArtistsStr = IBriefMusicInfoBase.GetArtistsStr(info.Artists);
info.Genre = ["MusicInfo_UnknownGenre".GetLocalized()];
- info.GenreStr = info.GetGenreStr();
- info.DurationStr = info.GetDurationStr();
+ info.GenreStr = GetGenreStr(info.Genre);
+ info.DurationStr = IBriefMusicInfoBase.GetDurationStr(info.Duration);
}
catch (Exception ex)
{
@@ -196,29 +186,11 @@ public class BriefMusicInfo
return tcs.Task;
}
- ///
- /// 获取参与创作的艺术家名字符串, 为空时返回"未知艺术家"
- ///
- ///
- protected virtual string GetArtistsStr() => string.Join(", ", Artists);
-
- ///
- /// 获取时长字符串
- ///
- ///
- protected virtual string GetDurationStr() => Duration.Hours > 0 ? $"{Duration:hh\\:mm\\:ss}" : $"{Duration:mm\\:ss}";
-
///
/// 获取流派字符串
///
///
- protected virtual string GetGenreStr() => string.Join(", ", Genre);
-
- ///
- /// 获取发行年份字符串
- ///
- ///
- protected string GetYearStr() => Year is 0 ? "" : Year.ToString();
+ protected static string GetGenreStr(string[] genre) => string.Join(", ", genre);
///
/// 获取文本前景色
@@ -226,7 +198,7 @@ public class BriefMusicInfo
///
///
/// 如果是当前播放歌曲, 返回主题色, 如果不是, 根据当前主题返回黑色或白色
- public SolidColorBrush GetTextForeground(DetailedMusicInfo currentMusic, bool isDarkTheme)
+ public SolidColorBrush GetTextForeground(IDetailedMusicInfoBase currentMusic, bool isDarkTheme)
{
var isCurrentMusic = Path == currentMusic.Path;
if (isCurrentMusic)
@@ -238,8 +210,10 @@ public class BriefMusicInfo
}
}
-public class DetailedMusicInfo : BriefMusicInfo
+public class DetailedMusicInfo : BriefMusicInfo, IDetailedMusicInfoBase
{
+ public bool IsOnline { get; set; } = false;
+
///
/// 专辑名, 为空时返回""
///
@@ -256,20 +230,15 @@ public class DetailedMusicInfo : BriefMusicInfo
public override string GenreStr { get; set; } = "";
///
- /// 时长字符串
+ /// 时长字符串, 为空时返回""
///
public override string DurationStr { get; set; } = "";
+
///
- /// 专辑艺术家数组
+ /// 项目类型, 为空时返回""
///
- private string[] AlbumArtists
- {
- get;
- set => field = [.. value
- .SelectMany(artist => artist.Split(_delimiters, StringSplitOptions.RemoveEmptyEntries))
- .Distinct()];
- } = [];
+ public string ItemType { get; set; } = "";
///
/// 专辑艺术家字符串, 为空时返回""
@@ -277,17 +246,14 @@ public class DetailedMusicInfo : BriefMusicInfo
public string AlbumArtistsStr { get; set; } = "";
///
- /// 艺术家和专辑名字符串
+ /// 艺术家和专辑名字符串, 为空时返回""
///
public string ArtistAndAlbumStr { get; set; } = "";
///
/// 清晰封面(可能为空)
///
- public override BitmapImage? Cover
- {
- get; set;
- }
+ public override BitmapImage? Cover { get; set; }
///
/// 封面缓冲数据
@@ -295,24 +261,20 @@ public class DetailedMusicInfo : BriefMusicInfo
public byte[] CoverBuffer { get; set; } = [];
///
- /// 比特率
+ /// 比特率, 为空时返回""
///
public string BitRate { get; set; } = "";
///
- /// 曲目
+ /// 曲目, 为空时返回""
///
public string Track { get; set; } = "";
///
- /// 歌词
+ /// 歌词, 为空时返回""
///
public string Lyric { get; set; } = "";
- public DetailedMusicInfo()
- {
- }
-
public DetailedMusicInfo(string path)
{
Path = path;
@@ -337,16 +299,17 @@ public class DetailedMusicInfo : BriefMusicInfo
Title = string.IsNullOrEmpty(musicFile.Tag.Title) ? System.IO.Path.GetFileNameWithoutExtension(path) : musicFile.Tag.Title;
Album = musicFile.Tag.Album ?? "";
Artists = [.. musicFile.Tag.AlbumArtists, .. musicFile.Tag.Performers];
- ArtistsStr = GetArtistsStr();
- AlbumArtists = [.. musicFile.Tag.AlbumArtists];
- AlbumArtistsStr = GetAlbumArtistsStr();
- ArtistAndAlbumStr = GetArtistAndAlbumStr(ArtistsStr);
+ ArtistsStr = IBriefMusicInfoBase.GetArtistsStr(Artists);
+ AlbumArtistsStr = IDetailedMusicInfoBase.GetAlbumArtistsStr([.. musicFile.Tag.AlbumArtists
+ .SelectMany(artist => artist.Split(_delimiters, StringSplitOptions.RemoveEmptyEntries))
+ .Distinct()]);
+ ArtistAndAlbumStr = IDetailedMusicInfoBase.GetArtistAndAlbumStr(Album, ArtistsStr);
Year = (ushort)musicFile.Tag.Year;
- YearStr = GetYearStr();
+ YearStr = IBriefMusicInfoBase.GetYearStr(Year);
Genre = musicFile.Tag.Genres;
- GenreStr = GetGenreStr();
+ GenreStr = GetGenreStr(Genre);
Duration = musicFile.Properties.Duration;
- DurationStr = GetDurationStr();
+ DurationStr = IBriefMusicInfoBase.GetDurationStr(Duration);
Track = musicFile.Tag.Track == 0 ? "" : musicFile.Tag.Track.ToString();
Lyric = musicFile.Tag.Lyrics ?? "";
BitRate = $"{musicFile.Properties.AudioBitrate} kbps";
@@ -360,45 +323,4 @@ public class DetailedMusicInfo : BriefMusicInfo
Debug.WriteLine(ex.StackTrace);
}
}
-
- ///
- /// 获取参与创作的艺术家名字符串, 为空时返回""
- ///
- ///
- protected override string GetArtistsStr() => string.Join(", ", Artists);
-
- ///
- /// 获取时长字符串
- ///
- ///
- protected override string GetDurationStr() => Duration.Hours > 0 ? $"{Duration:hh\\:mm\\:ss}" : $"{Duration:mm\\:ss}";
-
- ///
- /// 获取流派字符串, 为空时返回""
- ///
- ///
- protected override string GetGenreStr() => string.Join(", ", Genre);
-
- ///
- /// 获取专辑艺术家字符串, 为空时返回""
- ///
- ///
- protected string GetAlbumArtistsStr() => string.Join(", ", AlbumArtists);
-
- ///
- /// 获取艺术家和专辑名字符串
- ///
- ///
- protected string GetArtistAndAlbumStr(string artistsStr)
- {
- if (string.IsNullOrEmpty(artistsStr))
- {
- return Album ?? "";
- }
- if (string.IsNullOrEmpty(Album))
- {
- return artistsStr;
- }
- return $"{artistsStr} • {Album}";
- }
}
\ No newline at end of file
diff --git a/The Untamed Music Player/Models/MusicLibrary.cs b/The Untamed Music Player/Models/MusicLibrary.cs
index 54ee325..bc07fc4 100644
--- a/The Untamed Music Player/Models/MusicLibrary.cs
+++ b/The Untamed Music Player/Models/MusicLibrary.cs
@@ -8,7 +8,7 @@ using The_Untamed_Music_Player.ViewModels;
using Windows.Storage;
namespace The_Untamed_Music_Player.Models;
-public partial class MusicLibrary : ObservableObject
+public partial class MusicLibrary : ObservableRecipient
{
///
/// 调度器队列
@@ -105,7 +105,7 @@ public partial class MusicLibrary : ObservableObject
await _librarySemaphore.WaitAsync(); // 等待信号量, 只允许一个线程访问此函数
try
{
- Data.hasMusicLibraryLoaded = true;
+ Data.HasMusicLibraryLoaded = true;
var loadMusicTasks = new List();
if (Folders.Any())
{
@@ -120,8 +120,8 @@ public partial class MusicLibrary : ObservableObject
{
OnPropertyChanged(nameof(HasMusics));
Genres = [.. _musicGenres.Keys
- .Concat([ResourceExtensions.GetLocalized("MusicInfo_AllGenres")])
- .OrderBy(x => x, new GenreComparer())];
+ .Concat([ResourceExtensions.GetLocalized("MusicInfo_AllGenres")])
+ .OrderBy(x => x, new GenreComparer())];
_musicGenres.Clear();
});
await Task.Run(AddFolderWatcher);
@@ -142,7 +142,7 @@ public partial class MusicLibrary : ObservableObject
await _librarySemaphore.WaitAsync();
try
{
- Data.hasMusicLibraryLoaded = true;
+ Data.HasMusicLibraryLoaded = true;
_dispatcherQueue.TryEnqueue(() =>
{
IsProgressRingActive = true;
@@ -165,8 +165,8 @@ public partial class MusicLibrary : ObservableObject
{
OnPropertyChanged(nameof(HasMusics));
Genres = new([.. _musicGenres.Keys
- .Concat([ResourceExtensions.GetLocalized("MusicInfo_AllGenres")])
- .OrderBy(x => x, new GenreComparer())]);
+ .Concat([ResourceExtensions.GetLocalized("MusicInfo_AllGenres")])
+ .OrderBy(x => x, new GenreComparer())]);
OnPropertyChanged("LibraryReloaded");
_musicGenres.Clear();
});
@@ -340,33 +340,30 @@ public partial class MusicLibrary : ObservableObject
}
}
- public IOrderedEnumerable GetMusicsByAlbum(AlbumInfo albumInfo)
- {
- var list = new List();
- var albumName = albumInfo.Name;
+ ///
+ /// 根据专辑信息获取歌曲列表
+ ///
+ ///
+ ///
+ public IOrderedEnumerable GetSongsByAlbum(AlbumInfo albumInfo) => Songs
+ .Where(m => m.Album == albumInfo.Name)
+ .OrderBy(m => m.Title, new TitleComparer());
- foreach (var music in Songs)
- {
- if (music.Album == albumName)
- {
- list.Add(music);
- }
- }
+ ///
+ /// 根据艺术家信息获取专辑列表
+ ///
+ ///
+ ///
+ public List GetAlbumsByArtist(ArtistInfo artistInfo) => [.. artistInfo.Albums
+ .Select(album => new BriefAlbumInfo(Albums[album]))
+ .OrderBy(m => m.Name, new AlbumTitleComparer())];
- return list.OrderBy(m => m.Title, new TitleComparer());
- }
-
- public List GetAlbumsByArtist(ArtistInfo artistInfo)
- {
- var list = new List();
- var albums = artistInfo.Albums;
-
- foreach (var album in albums)
- {
- var albumInfo = Albums[album];
- list.Add(new BriefAlbumInfo(albumInfo));
- }
-
- return [.. list.OrderBy(m => m.Name, new AlbumTitleComparer())];
- }
+ ///
+ /// 根据艺术家信息获取歌曲列表
+ ///
+ ///
+ ///
+ public ObservableCollection GetSongsByArtist(ArtistInfo artistInfo) => [.. artistInfo.Albums
+ .OrderBy(album => album, new AlbumTitleComparer())
+ .SelectMany(album => GetSongsByAlbum(Albums[album]))];
}
diff --git a/The Untamed Music Player/Models/MusicPlayer.cs b/The Untamed Music Player/Models/MusicPlayer.cs
index ed0cace..0e26fcf 100644
--- a/The Untamed Music Player/Models/MusicPlayer.cs
+++ b/The Untamed Music Player/Models/MusicPlayer.cs
@@ -4,6 +4,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
+using The_Untamed_Music_Player.Contracts.Models;
using The_Untamed_Music_Player.Contracts.Services;
using Windows.Media;
using Windows.Media.Core;
@@ -41,7 +42,6 @@ public partial class MusicPlayer : ObservableRecipient
///
private ThreadPoolTimer? _positionUpdateTimer;
-
///
/// 线程锁开启状态, true为开启, false为关闭
///
@@ -100,6 +100,11 @@ public partial class MusicPlayer : ObservableRecipient
///
public MediaPlayer Player { get; set; } = new() { AudioCategory = MediaPlayerAudioCategory.Media };
+ ///
+ /// 歌曲来源模式, 0为本地, 1为网易
+ ///
+ public byte SourceMode { get; set; } = 0;
+
///
/// 随机播放模式, true为开启, false为关闭.
///
@@ -135,8 +140,8 @@ public partial class MusicPlayer : ObservableRecipient
/// 当前播放歌曲
///
[ObservableProperty]
- public partial DetailedMusicInfo CurrentMusic { get; set; } = new();
- partial void OnCurrentMusicChanged(DetailedMusicInfo value)
+ public partial IDetailedMusicInfoBase CurrentMusic { get; set; } = null!;
+ partial void OnCurrentMusicChanged(IDetailedMusicInfoBase value)
{
SetSource(value.Path);
CurrentLyric = LyricSlice.GetLyricSlices(value.Lyric);
@@ -283,7 +288,7 @@ public partial class MusicPlayer : ObservableRecipient
Player.Source = MediaSource.CreateFromStorageFile(mediaFile);
Player.PlaybackSession.PlaybackRate = PlaySpeed;
TotalPlayingTime = Player.PlaybackSession.NaturalDuration;
- _displayUpdater.MusicProperties.Title = CurrentMusic.Title;
+ _displayUpdater.MusicProperties.Title = CurrentMusic!.Title;
_displayUpdater.MusicProperties.Artist = CurrentMusic.ArtistsStr == "未知艺术家" ? "" : CurrentMusic.ArtistsStr;
_positionUpdateTimer = ThreadPoolTimer.CreatePeriodicTimer(UpdateTimerHandler, TimeSpan.FromMilliseconds(250));
}
@@ -293,14 +298,14 @@ public partial class MusicPlayer : ObservableRecipient
}
}
- if (CurrentMusic.Cover != null && CurrentMusic.CoverBuffer.Length != 0)
+ if (CurrentMusic!.Cover != null && CurrentMusic is DetailedMusicInfo info && info.CoverBuffer.Length != 0)
{
try
{
var tempFolder = ApplicationData.Current.TemporaryFolder;
var coverFileName = "Cover.jpg";
var coverFile = await tempFolder.CreateFileAsync(coverFileName, CreationCollisionOption.ReplaceExisting);
- await FileIO.WriteBytesAsync(coverFile, CurrentMusic.CoverBuffer);
+ await FileIO.WriteBytesAsync(coverFile, info.CoverBuffer);
_displayUpdater.Thumbnail = RandomAccessStreamReference.CreateFromFile(coverFile);
}
catch
@@ -320,14 +325,14 @@ public partial class MusicPlayer : ObservableRecipient
///
///
///
- public async void SetPlayList(string name, ObservableCollection list, byte sortmode = 0)
+ public async void SetPlayList(string name, IEnumerable list, byte sortmode = 0)
{
- if (PlayQueue.Count != list.Count || PlayQueueName != name || _sortMode != sortmode)
+ if (PlayQueue.Count != list.Count() || PlayQueueName != name || _sortMode != sortmode)
{
_sortMode = sortmode;
PlayQueueName = name;
PlayQueue = [.. list];
- _playQueueLength = list.Count;
+ _playQueueLength = list.Count();
var hasMusics = PlayQueue.Any();
if (Data.RootPlayBarViewModel != null)
{
@@ -462,7 +467,7 @@ public partial class MusicPlayer : ObservableRecipient
{
if (RepeatMode == 2)
{
- PlaySongByPath(CurrentMusic.Path);
+ PlaySongByPath(CurrentMusic!.Path);
}
else
{
@@ -636,7 +641,7 @@ public partial class MusicPlayer : ObservableRecipient
ShuffledPlayQueue.Clear();
for (var i = 0; i < PlayQueue.Count; i++)
{
- if (PlayQueue[i].Path == CurrentMusic.Path)
+ if (PlayQueue[i].Path == CurrentMusic!.Path)
{
PlayQueueIndex = i;
break;
@@ -665,7 +670,7 @@ public partial class MusicPlayer : ObservableRecipient
ShuffledPlayQueue = new ObservableCollection([.. PlayQueue.OrderBy(x => Guid.NewGuid())]);
for (var i = 0; i < ShuffledPlayQueue.Count; i++)
{
- if (ShuffledPlayQueue[i].Path == CurrentMusic.Path)
+ if (ShuffledPlayQueue[i].Path == CurrentMusic!.Path)
{
PlayQueueIndex = i;
break;
@@ -879,7 +884,7 @@ public partial class MusicPlayer : ObservableRecipient
///
public async void SaveCurrentStateAsync()
{
- await _localSettingsService.SaveSettingAsync("CurrentMusic", CurrentMusic.Path);
+ await _localSettingsService.SaveSettingAsync("CurrentMusic", CurrentMusic!.Path);
/*var playqueuepaths = PlayQueue.Select(music => music.Path).ToList();
await _localSettingsService.SaveSettingAsync("PlayQueuePaths", playqueuepaths);
var shuffledplayqueuepaths = ShuffledPlayQueue.Select(music => music.Path).ToList();
diff --git a/The Untamed Music Player/Models/OnlineMusicLibrary.cs b/The Untamed Music Player/Models/OnlineMusicLibrary.cs
new file mode 100644
index 0000000..0e8e169
--- /dev/null
+++ b/The Untamed Music Player/Models/OnlineMusicLibrary.cs
@@ -0,0 +1,221 @@
+using System.Diagnostics;
+using CommunityToolkit.Mvvm.ComponentModel;
+using Microsoft.UI.Dispatching;
+using Microsoft.UI.Xaml;
+using The_Untamed_Music_Player.Contracts.Models;
+using The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI;
+
+namespace The_Untamed_Music_Player.Models;
+public partial class OnlineMusicLibrary : ObservableRecipient
+{
+ private bool _isSearchingMore = false;
+
+ public byte PageIndex { get; set; }
+ public byte MusicLibraryIndex { get; set; }
+ public string KeyWords { get; set; } = null!;
+ [ObservableProperty]
+ public partial Visibility KeyWordsTextBlockVisibility { get; set; } = Visibility.Collapsed;
+
+ [ObservableProperty]
+ public partial Visibility NetworkErrorVisibility { get; set; } = Visibility.Collapsed;
+
+ [ObservableProperty]
+ public partial double ListViewOpacity { get; set; } = 0;
+
+ ///
+ /// 是否显示加载进度环
+ ///
+ [ObservableProperty]
+ public partial bool IsSearchProgressRingActive { get; set; } = false;
+
+ ///
+ /// 是否显示加载更多进度环
+ ///
+ [ObservableProperty]
+ public partial bool IsSearchMoreProgressRingActive { get; set; } = false;
+
+ [ObservableProperty]
+ public partial IBriefOnlineMusicInfoList OnlineMusicInfoList { get; set; } = null!;
+
+ [ObservableProperty]
+ public partial List SearchResultList { get; set; } = [];
+
+ public async Task Search()
+ {
+ KeyWordsTextBlockVisibility = Visibility.Collapsed;
+ NetworkErrorVisibility = Visibility.Collapsed;
+ ListViewOpacity = 0;
+ if (!await IsInternetAvailableAsync())
+ {
+ NetworkErrorVisibility = Visibility.Visible;
+ return;
+ }
+ IsSearchProgressRingActive = true;
+ try
+ {
+ if (PageIndex == 0)
+ {
+ if (MusicLibraryIndex == 0)
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ await OnlineMusicInfoList.SearchAsync(KeyWords);
+ }
+ else if (MusicLibraryIndex == 1)
+ { }
+ else if (MusicLibraryIndex == 2)
+ { }
+ else if (MusicLibraryIndex == 3)
+ { }
+ else if (MusicLibraryIndex == 4)
+ { }
+ else
+ { }
+ }
+ OnPropertyChanged(nameof(KeyWords));
+ KeyWordsTextBlockVisibility = Visibility.Visible;
+ ListViewOpacity = 1;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.Message);
+ }
+ finally
+ {
+ IsSearchProgressRingActive = false;
+ }
+ }
+
+ public async Task SearchMore()
+ {
+ if (!_isSearchingMore)
+ {
+ _isSearchingMore = true;
+ if (OnlineMusicInfoList.HasAllLoaded || !await IsInternetAvailableAsync())
+ {
+ return;
+ }
+ IsSearchMoreProgressRingActive = true;
+ try
+ {
+ if (PageIndex == 0)
+ {
+ if (MusicLibraryIndex == 0)
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ await OnlineMusicInfoList.SearchMore();
+ }
+ else if (MusicLibraryIndex == 1)
+ { }
+ else if (MusicLibraryIndex == 2)
+ { }
+ else if (MusicLibraryIndex == 3)
+ { }
+ else if (MusicLibraryIndex == 4)
+ { }
+ else
+ { }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.Message);
+ }
+ finally
+ {
+ _isSearchingMore = false;
+ IsSearchMoreProgressRingActive = false;
+ }
+ }
+ }
+
+ public async Task UpdateSearchResult()
+ {
+ if (!string.IsNullOrWhiteSpace(KeyWords))
+ {
+ if (MusicLibraryIndex == 0)
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ SearchResultList = await OnlineMusicInfoList.GetSearchResultAsync(KeyWords);
+ }
+ // 待修改
+ else if (MusicLibraryIndex == 1)
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ SearchResultList = await OnlineMusicInfoList.GetSearchResultAsync(KeyWords);
+ }
+ else if (MusicLibraryIndex == 2)
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ SearchResultList = await OnlineMusicInfoList.GetSearchResultAsync(KeyWords);
+ }
+ else if (MusicLibraryIndex == 3)
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ SearchResultList = await OnlineMusicInfoList.GetSearchResultAsync(KeyWords);
+ }
+ else if (MusicLibraryIndex == 4)
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ SearchResultList = await OnlineMusicInfoList.GetSearchResultAsync(KeyWords);
+ }
+ else
+ {
+ if (OnlineMusicInfoList is not CloudBriefOnlineMusicInfoList)
+ {
+ OnlineMusicInfoList = new CloudBriefOnlineMusicInfoList();
+ }
+ SearchResultList = await OnlineMusicInfoList.GetSearchResultAsync(KeyWords);
+ }
+ }
+ else
+ {
+ ClearSearchResult();
+ }
+ }
+
+ public void ClearSearchResult()
+ {
+ SearchResultList = [];
+ }
+
+ public async void RetryButton_Click(object sender, RoutedEventArgs e)
+ {
+ await Search();
+ }
+
+ private static async Task IsInternetAvailableAsync()
+ {
+ try
+ {
+ using var client = new HttpClient();
+ client.Timeout = TimeSpan.FromSeconds(5);
+ var response = await client.GetAsync("https://www.baidu.com");
+ return response.IsSuccessStatusCode;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+}
diff --git a/The Untamed Music Player/Models/SearchResult.cs b/The Untamed Music Player/Models/SearchResult.cs
new file mode 100644
index 0000000..ce12534
--- /dev/null
+++ b/The Untamed Music Player/Models/SearchResult.cs
@@ -0,0 +1,11 @@
+namespace The_Untamed_Music_Player.Models;
+public class SearchResult
+{
+ public string Icon { get; set; } = null!;
+ public string Label { get; set; } = null!;
+
+ public override string ToString()
+ {
+ return Label;
+ }
+}
\ No newline at end of file
diff --git a/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/CloudOnlineMusicInfo.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/CloudOnlineMusicInfo.cs
new file mode 100644
index 0000000..4123be1
--- /dev/null
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/CloudOnlineMusicInfo.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Microsoft.UI.Xaml.Media.Imaging;
+using Newtonsoft.Json.Linq;
+using The_Untamed_Music_Player.Contracts.Models;
+using Windows.Storage.Streams;
+
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI;
+public class CloudBriefOnlineMusicInfo : IBriefOnlineMusicInfo
+{
+ public bool IsAvailable { get; set; } = false;
+ public string Path { get; set; } = "";
+ public string Title { get; set; } = "";
+ public long ID { get; set; } = 0;
+ public virtual string Album { get; set; } = "";
+ public long AlbumID { get; set; } = 0;
+ public virtual string ArtistsStr { get; set; } = "";
+ public virtual string DurationStr { get; set; } = "";
+ public string YearStr { get; set; } = "";
+
+ public CloudBriefOnlineMusicInfo() { }
+
+ public static async Task CreateAsync(JToken jInfo, NeteaseCloudMusicApi api)
+ {
+ var info = new CloudBriefOnlineMusicInfo();
+ try
+ {
+ info.ID = (long)jInfo["id"]!;
+ var (isOK, songUrlResult) = await api.RequestAsync(CloudMusicApiProviders.SongUrl, new Dictionary { { "id", $"{info.ID}" } });
+ var path = (string)songUrlResult["data"]![0]!["url"]!;
+ if (string.IsNullOrEmpty(path) || !isOK || path == "null")
+ {
+ info.IsAvailable = false;
+ return info;
+ }
+ else
+ {
+ info.Path = path;
+ info.Title = (string)jInfo["name"]!;
+ info.Album = (string)jInfo["album"]!["name"]!;
+ info.AlbumID = (long)jInfo["album"]!["id"]!;
+ string[] artists = [.. jInfo["artists"]!
+ .Select(t => (string)t["name"]!)
+ .Distinct()];
+ info.ArtistsStr = IBriefMusicInfoBase.GetArtistsStr(artists);
+ info.DurationStr = IBriefMusicInfoBase.GetDurationStr(TimeSpan.FromMilliseconds((long)jInfo["duration"]!));
+ info.YearStr = IBriefMusicInfoBase.GetYearStr((ushort)DateTimeOffset.FromUnixTimeMilliseconds((long)jInfo["album"]!["publishTime"]!).Year);
+ info.IsAvailable = true;
+ return info;
+ }
+ }
+ catch
+ {
+ info.IsAvailable = false;
+ return info;
+ }
+ }
+
+ public class CloudDetailedOnlineMusicInfo : CloudBriefOnlineMusicInfo, IDetailedOnlineMusicInfo
+ {
+ public bool IsOnline { get; set; } = true;
+ public string GenreStr { get; set; } = "";
+ public string ItemType { get; set; } = "";
+ public string AlbumArtistsStr { get; set; } = "";
+ public string ArtistAndAlbumStr { get; set; } = "";
+ public BitmapImage? Cover { get; set; }
+ public string CoverUrl { get; set; } = "";
+ public string BitRate { get; set; } = "";
+ public string Track { get; set; } = "";
+ public string Lyric { get; set; } = "";
+
+ public CloudDetailedOnlineMusicInfo() { }
+
+ public CloudDetailedOnlineMusicInfo(IBriefOnlineMusicInfo info)
+ {
+ var api = new NeteaseCloudMusicApi();
+ var songUrlTask = api.RequestAsync(CloudMusicApiProviders.SongUrl, new Dictionary { { "id", $"{info.ID}" } });
+ var albumTask = api.RequestAsync(CloudMusicApiProviders.Album, new Dictionary { { "id", $"{info.AlbumID}" } });
+ var lyricTask = api.RequestAsync(CloudMusicApiProviders.Lyric, new Dictionary { { "id", $"{info.ID}" } });
+ songUrlTask.Wait();
+ albumTask.Wait();
+ lyricTask.Wait();
+ var (isOK1, songUrlResult) = songUrlTask.Result;
+ var (isOK2, albumResult) = albumTask.Result;
+ var (isOK3, lyricResult) = lyricTask.Result;
+ ID = info.ID;
+ Path = info.Path;
+ Title = info.Title;
+ Album = info.Album;
+ AlbumID = info.AlbumID;
+ ArtistsStr = info.ArtistsStr;
+ DurationStr = info.DurationStr;
+ YearStr = info.YearStr;
+ ItemType = (string)songUrlResult["data"]![0]!["type"]!;
+ string[] albumArtists = [.. albumResult["album"]!["artists"]!
+ .Select(t => (string)t["name"]!)
+ .Distinct()];
+ AlbumArtistsStr = IDetailedMusicInfoBase.GetAlbumArtistsStr(albumArtists);
+ ArtistAndAlbumStr = IDetailedMusicInfoBase.GetArtistAndAlbumStr(Album, ArtistsStr);
+ BitRate = $"{((int)songUrlResult["data"]![0]!["br"]!) / 1000} kbps";
+ CoverUrl = (string)albumResult["album"]!["picUrl"]!;
+ if (!string.IsNullOrEmpty(CoverUrl))
+ {
+ using var httpClient = new HttpClient();
+ var imageBytes = httpClient.GetByteArrayAsync(CoverUrl).Result;
+ using var stream = new MemoryStream(imageBytes);
+ var bitmap = new BitmapImage();
+ bitmap.SetSourceAsync(stream.AsRandomAccessStream()).AsTask().Wait();
+ Cover = bitmap;
+ }
+ Lyric = (string)lyricResult["lrc"]!["lyric"]!;
+ IsAvailable = true;
+ }
+
+ public static async Task CreateAsync(IBriefOnlineMusicInfo info)
+ {
+ var detailedInfo = new CloudDetailedOnlineMusicInfo
+ {
+ ID = info.ID,
+ Path = info.Path,
+ Title = info.Title,
+ Album = info.Album,
+ AlbumID = info.AlbumID,
+ ArtistsStr = info.ArtistsStr,
+ DurationStr = info.DurationStr,
+ YearStr = info.YearStr
+ };
+ var api = new NeteaseCloudMusicApi();
+ var songUrlTask = api.RequestAsync(CloudMusicApiProviders.SongUrl, new Dictionary { { "id", $"{info.ID}" } });
+ var albumTask = api.RequestAsync(CloudMusicApiProviders.Album, new Dictionary { { "id", $"{info.AlbumID}" } });
+ var lyricTask = api.RequestAsync(CloudMusicApiProviders.Lyric, new Dictionary { { "id", $"{info.ID}" } });
+ await Task.WhenAll(songUrlTask, albumTask, lyricTask);
+ var (isOK1, songUrlResult) = songUrlTask.Result;
+ var (isOK2, albumResult) = albumTask.Result;
+ var (isOK3, lyricResult) = lyricTask.Result;
+ api.Dispose();
+ detailedInfo.CoverUrl = (string)albumResult["album"]!["picUrl"]!;
+ Task? coverTask = null;
+ if (!string.IsNullOrEmpty(detailedInfo.CoverUrl))
+ {
+ using var httpClient = new HttpClient();
+ var coverBuffer = await httpClient.GetByteArrayAsync(detailedInfo.CoverUrl);
+ coverTask = LoadCoverAsync(coverBuffer, detailedInfo);
+ }
+ detailedInfo.ItemType = (string)songUrlResult["data"]![0]!["type"]!;
+ string[] albumArtists = [.. albumResult["album"]!["artists"]!
+ .Select(t => (string)t["name"]!)
+ .Distinct()];
+ detailedInfo.AlbumArtistsStr = IDetailedMusicInfoBase.GetAlbumArtistsStr(albumArtists);
+ detailedInfo.ArtistAndAlbumStr = IDetailedMusicInfoBase.GetArtistAndAlbumStr(detailedInfo.Album, detailedInfo.ArtistsStr);
+ detailedInfo.BitRate = $"{((int)songUrlResult["data"]![0]!["br"]!) / 1000} kbps";
+ detailedInfo.Lyric = (string)lyricResult["lrc"]!["lyric"]!;
+ detailedInfo.IsAvailable = true;
+ if (coverTask != null)
+ {
+ await coverTask;
+ }
+ return detailedInfo;
+ }
+
+ private static Task LoadCoverAsync(byte[] coverBuffer, CloudDetailedOnlineMusicInfo info)
+ {
+ var tcs = new TaskCompletionSource();
+ App.MainWindow?.DispatcherQueue.TryEnqueue(async () =>
+ {
+ try
+ {
+ using var stream = new InMemoryRandomAccessStream();
+ await stream.WriteAsync(coverBuffer.AsBuffer());
+ stream.Seek(0);
+ var bitmap = new BitmapImage
+ {
+ DecodePixelWidth = 400,
+ DecodePixelHeight = 400
+ };
+ await bitmap.SetSourceAsync(stream);
+ info.Cover = bitmap;
+ tcs.SetResult(true);
+ }
+ catch (Exception ex)
+ {
+ tcs.SetException(ex);
+ }
+ });
+ return tcs.Task;
+ }
+ }
+}
diff --git a/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/CloudOnlineMusicInfoList.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/CloudOnlineMusicInfoList.cs
new file mode 100644
index 0000000..f58efce
--- /dev/null
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/CloudOnlineMusicInfoList.cs
@@ -0,0 +1,160 @@
+using System.Diagnostics;
+using Newtonsoft.Json.Linq;
+using The_Untamed_Music_Player.Contracts.Models;
+using The_Untamed_Music_Player.Models;
+
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI;
+public partial class CloudBriefOnlineMusicInfoList : IBriefOnlineMusicInfoList
+{
+ private readonly NeteaseCloudMusicApi _api = new();
+ private const byte _limit = 30;
+ private ushort _offset = 0;
+ private int _songCount = 0;
+ private int _listCount = 0;
+
+ public CloudBriefOnlineMusicInfoList()
+ {
+ }
+
+ public async override Task SearchAsync(string keyWords)
+ {
+ _offset = 0;
+ _listCount = 0;
+ HasAllLoaded = false;
+ Clear();
+ _keyWords = keyWords;
+ var (isOk, result) = await _api.RequestAsync(CloudMusicApiProviders.Search, new Dictionary
+ {
+ { "keywords", keyWords },
+ { "limit", _limit.ToString() },
+ { "offset", _offset.ToString() }
+ });
+ if (!isOk)
+ {
+ throw new Exception();
+ }
+ try
+ {
+ _songCount = (int)result["result"]!["songCount"]!;
+ if (_songCount == 0)
+ {
+ HasAllLoaded = true;
+ return;
+ }
+ await ProcessSongsAsync(result["result"]!["songs"]!);
+ _offset = 1;
+ }
+ catch
+ {
+ throw new Exception("搜索失败");
+ }
+ }
+
+ public async override Task SearchMore()
+ {
+ var (isOk, result) = await _api.RequestAsync(CloudMusicApiProviders.Search, new Dictionary
+ {
+ { "keywords", _keyWords },
+ { "limit", _limit.ToString() },
+ { "offset", _offset.ToString() }
+ });
+ if (!isOk)
+ {
+ throw new Exception();
+ }
+ try
+ {
+ await ProcessSongsAsync(result["result"]!["songs"]!);
+ _offset++;
+ }
+ catch
+ {
+ throw new Exception("搜索失败");
+ }
+ }
+
+ private async Task ProcessSongsAsync(JToken songs)
+ {
+ var actualCount = songs.Count();
+ var infos = new CloudBriefOnlineMusicInfo[actualCount];
+ var groupTasks = new List();
+
+ // 每组 8 首歌曲
+ for (var i = 0; i < actualCount; i += 8)
+ {
+ var start = i;
+ var end = Math.Min(i + 8, actualCount);
+ // 使用 Task.Run 将每组放在一个线程中执行
+ groupTasks.Add(Task.Run(async () =>
+ {
+ for (var j = start; j < end; j++)
+ {
+ try
+ {
+ var info = await CloudBriefOnlineMusicInfo.CreateAsync(songs[j]!, _api);
+ infos[j] = info;
+ }
+ catch (Exception ex)
+ {
+ _listCount++;
+ Debug.WriteLine(ex.StackTrace);
+ }
+ }
+ }));
+ }
+ await Task.WhenAll(groupTasks);
+ foreach (var info in infos)
+ {
+ Add(info);
+ }
+ }
+
+ protected new void Add(IBriefOnlineMusicInfo info)
+ {
+ _listCount++;
+ if (info.IsAvailable)
+ {
+ base.Add(info);
+ }
+ if (_listCount == _songCount)
+ {
+ HasAllLoaded = true;
+ }
+ }
+
+ public async override Task> GetSearchResultAsync(string keyWords)
+ {
+ var (isOk, result) = await _api.RequestAsync(CloudMusicApiProviders.SearchSuggest, new Dictionary { { "keywords", $"{keyWords}" } });
+ if (!isOk)
+ {
+ Debug.WriteLine("获取网易云音乐搜索建议失败");
+ return [];
+ }
+ var songs = result["result"]!["songs"]?
+ .Select(t => (string)t["name"]!)
+ .Distinct() ?? [];
+ var albums = result["result"]!["albums"]?
+ .Select(t => (string)t["name"]!)
+ .Distinct() ?? [];
+ var artists = result["result"]!["artists"]?
+ .Select(t => (string)t["name"]!)
+ .Distinct() ?? [];
+ var playlists = result["result"]!["playlists"]?
+ .Select(t => (string)t["name"]!)
+ .Distinct() ?? [];
+ var list = new List();
+ AddResults(songs, 5, "\uE8D6", list);
+ AddResults(albums, 3, "\uE93C", list);
+ AddResults(artists, 3, "\uE77B", list);
+ AddResults(playlists, 2, "\uE728", list);
+ return list;
+ }
+
+ private static void AddResults(IEnumerable items, int limit, string icon, List list)
+ {
+ foreach (var item in items.Take(limit))
+ {
+ list.Add(new SearchResult { Icon = icon, Label = item });
+ }
+ }
+}
\ No newline at end of file
diff --git a/OnlineMusicApi/Extensions.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/Extensions.cs
similarity index 94%
rename from OnlineMusicApi/Extensions.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/Extensions.cs
index 46c215e..2b2206d 100644
--- a/OnlineMusicApi/Extensions.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/Extensions.cs
@@ -1,10 +1,9 @@
-using System;
-using System.Collections.Generic;
+#pragma warning disable
+
using System.Security.Cryptography;
using System.Text;
-namespace NeteaseCloudMusicApi;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI;
internal static class Extensions
{
private static readonly MD5 _md5 = MD5.Create();
diff --git a/OnlineMusicApi/NeteaseCloudMusicApi.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/NeteaseCloudMusicApi.cs
similarity index 97%
rename from OnlineMusicApi/NeteaseCloudMusicApi.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/NeteaseCloudMusicApi.cs
index a825e3c..e95292e 100644
--- a/OnlineMusicApi/NeteaseCloudMusicApi.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/NeteaseCloudMusicApi.cs
@@ -1,18 +1,14 @@
-using System;
-using System.Collections.Generic;
-using System.Extensions;
-using System.IO;
-using System.Linq;
+#pragma warning disable
+
using System.Net;
-using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using NeteaseCloudMusicApi.util;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Extensions;
+using The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.util;
-namespace NeteaseCloudMusicApi;
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI;
///
/// 网易云音乐API
///
diff --git a/OnlineMusicApi/NeteaseCloudMusicApiProvider.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/NeteaseCloudMusicApiProvider.cs
similarity index 99%
rename from OnlineMusicApi/NeteaseCloudMusicApiProvider.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/NeteaseCloudMusicApiProvider.cs
index c04ef48..a964e19 100644
--- a/OnlineMusicApi/NeteaseCloudMusicApiProvider.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/NeteaseCloudMusicApiProvider.cs
@@ -1,14 +1,12 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Text.RegularExpressions;
-using NeteaseCloudMusicApi.util;
-using Newtonsoft.Json;
-using static NeteaseCloudMusicApi.NeteaseCloudMusicApiProvider;
+#pragma warning disable
-namespace NeteaseCloudMusicApi;
+using System.Net;
+using System.Text.RegularExpressions;
+using Newtonsoft.Json;
+using The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.util;
+using static The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.NeteaseCloudMusicApiProvider;
+
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI;
///
/// 网易云音乐API相关信息提供者
///
@@ -114,7 +112,7 @@ public sealed class NeteaseCloudMusicApiProvider
SpecialHandle
}
- internal sealed class ParameterInfo(string key, NeteaseCloudMusicApiProvider.ParameterType type, string defaultValue)
+ internal sealed class ParameterInfo(string key, ParameterType type, string defaultValue)
{
public string Key = key;
public ParameterType Type = type;
@@ -311,7 +309,7 @@ public static partial class CloudMusicApiProviders
///
/// 发送/删除评论
///
- public static readonly NeteaseCloudMusicApiProvider Comment = new("/comment", HttpMethod.Post, q => $"https://music.163.com/weapi/resource/comments/{(q["t"] == "1" ? "add" : (q["t"] == "0" ? "delete" : "reply"))}", [], BuildOptions("weapi", [new("os", "pc")]))
+ public static readonly NeteaseCloudMusicApiProvider Comment = new("/comment", HttpMethod.Post, q => $"https://music.163.com/weapi/resource/comments/{(q["t"] == "1" ? "add" : q["t"] == "0" ? "delete" : "reply")}", [], BuildOptions("weapi", [new("os", "pc")]))
{
DataProvider = queries =>
{
diff --git a/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/QueryCollection.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/QueryCollection.cs
new file mode 100644
index 0000000..d5e5368
--- /dev/null
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/QueryCollection.cs
@@ -0,0 +1,5 @@
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI;
+internal sealed partial class QueryCollection : List>
+{
+ public void Add(string key, string value) => Add(new KeyValuePair(key, value));
+}
diff --git a/OnlineMusicApi/System/Extensions/ExceptionExtensions.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/ExceptionExtensions.cs
similarity index 93%
rename from OnlineMusicApi/System/Extensions/ExceptionExtensions.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/ExceptionExtensions.cs
index 7312c36..f596766 100644
--- a/OnlineMusicApi/System/Extensions/ExceptionExtensions.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/ExceptionExtensions.cs
@@ -1,7 +1,8 @@
+#pragma warning disable
+
using System.Text;
-namespace System.Extensions;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Extensions;
internal static class ExceptionExtensions
{
///
diff --git a/OnlineMusicApi/System/Extensions/HttpClientExtensions.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/HttpClientExtensions.cs
similarity index 96%
rename from OnlineMusicApi/System/Extensions/HttpClientExtensions.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/HttpClientExtensions.cs
index 67ea94e..d40aef3 100644
--- a/OnlineMusicApi/System/Extensions/HttpClientExtensions.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/HttpClientExtensions.cs
@@ -1,10 +1,9 @@
-using System.Collections.Generic;
-using System.Net.Http;
+#pragma warning disable
+
using System.Net.Http.Headers;
using System.Text;
-using System.Threading.Tasks;
-namespace System.Extensions;
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Extensions;
internal static class HttpClientExtensions
{
diff --git a/OnlineMusicApi/System/Extensions/HttpExtensions.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/HttpExtensions.cs
similarity index 79%
rename from OnlineMusicApi/System/Extensions/HttpExtensions.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/HttpExtensions.cs
index 1b7ea32..a189e16 100644
--- a/OnlineMusicApi/System/Extensions/HttpExtensions.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Extensions/HttpExtensions.cs
@@ -1,8 +1,4 @@
-using System.Collections.Generic;
-using System.Linq;
-
-namespace System.Extensions;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Extensions;
internal static class HttpExtensions
{
public static string ToQueryString(this IEnumerable> queries)
diff --git a/OnlineMusicApi/System/Numerics/BigInteger.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigInteger.cs
similarity index 94%
rename from OnlineMusicApi/System/Numerics/BigInteger.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigInteger.cs
index 5d69403..12ae123 100644
--- a/OnlineMusicApi/System/Numerics/BigInteger.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigInteger.cs
@@ -1,11 +1,8 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
+#pragma warning disable
using System.Diagnostics;
-namespace System.Numerics;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal readonly struct BigInteger
{
private const uint kuMaskHighBit = unchecked((uint)int.MinValue);
@@ -133,14 +130,14 @@ internal readonly struct BigInteger
{
for (var i = 0; i < byteCount; i++)
{
- _sign = (_sign << 8) | value[i];
+ _sign = _sign << 8 | value[i];
}
}
else
{
for (var i = byteCount - 1; i >= 0; i--)
{
- _sign = (_sign << 8) | value[i];
+ _sign = _sign << 8 | value[i];
}
}
@@ -177,7 +174,7 @@ internal readonly struct BigInteger
for (var byteInDword = 0; byteInDword < 4; byteInDword++)
{
var curByteValue = value[curByte];
- val[curDword] = (val[curDword] << 8) | curByteValue;
+ val[curDword] = val[curDword] << 8 | curByteValue;
curByte++;
}
@@ -192,7 +189,7 @@ internal readonly struct BigInteger
for (var byteInDword = 0; byteInDword < 4; byteInDword++)
{
var curByteValue = value[curByte];
- val[curDword] = (val[curDword] << 8) | curByteValue;
+ val[curDword] = val[curDword] << 8 | curByteValue;
curByte--;
}
@@ -213,7 +210,7 @@ internal readonly struct BigInteger
for (curByte = 0; curByte < unalignedBytes; curByte++)
{
var curByteValue = value[curByte];
- val[curDword] = (val[curDword] << 8) | curByteValue;
+ val[curDword] = val[curDword] << 8 | curByteValue;
}
}
else
@@ -221,7 +218,7 @@ internal readonly struct BigInteger
for (curByte = byteCountMinus1; curByte >= byteCount - unalignedBytes; curByte--)
{
var curByteValue = value[curByte];
- val[curDword] = (val[curDword] << 8) | curByteValue;
+ val[curDword] = val[curDword] << 8 | curByteValue;
}
}
}
@@ -254,7 +251,7 @@ internal readonly struct BigInteger
default:
if (unchecked((int)val[0]) > 0)
{
- _sign = (-1) * ((int)val[0]);
+ _sign = -1 * (int)val[0];
_bits = null;
AssertValid();
return;
@@ -343,7 +340,7 @@ internal readonly struct BigInteger
get
{
AssertValid();
- return (_sign >> (kcbitUint - 1)) - (-_sign >> (kcbitUint - 1));
+ return (_sign >> kcbitUint - 1) - (-_sign >> kcbitUint - 1);
}
}
@@ -432,7 +429,7 @@ internal readonly struct BigInteger
var bits = _bits;
if (bits == null)
{
- highByte = (byte)((sign < 0) ? 0xff : 0x00);
+ highByte = (byte)(sign < 0 ? 0xff : 0x00);
highDword = unchecked((uint)sign);
}
else if (sign == -1)
@@ -565,9 +562,9 @@ internal readonly struct BigInteger
}
// Assert we're big endian, or little endian consistency holds.
- Debug.Assert(isBigEndian || (!needExtraByte && curByte == length - 1) || (needExtraByte && curByte == length - 2));
+ Debug.Assert(isBigEndian || !needExtraByte && curByte == length - 1 || needExtraByte && curByte == length - 2);
// Assert we're little endian, or big endian consistency holds.
- Debug.Assert(!isBigEndian || (!needExtraByte && curByte == 0) || (needExtraByte && curByte == 1));
+ Debug.Assert(!isBigEndian || !needExtraByte && curByte == 0 || needExtraByte && curByte == 1);
if (needExtraByte)
{
diff --git a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.AddSub.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.AddSub.cs
similarity index 94%
rename from OnlineMusicApi/System/Numerics/BigIntegerCalculator.AddSub.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.AddSub.cs
index aa0072a..a9e4ac9 100644
--- a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.AddSub.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.AddSub.cs
@@ -1,11 +1,6 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
using System.Diagnostics;
-namespace System.Numerics;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal static partial class BigIntegerCalculator
{
private static unsafe void Add(uint* left, int leftLength,
diff --git a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.BitsBuffer.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.BitsBuffer.cs
similarity index 90%
rename from OnlineMusicApi/System/Numerics/BigIntegerCalculator.BitsBuffer.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.BitsBuffer.cs
index d008e43..df0834c 100644
--- a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.BitsBuffer.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.BitsBuffer.cs
@@ -1,15 +1,6 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
using System.Diagnostics;
-namespace System.Numerics;
-
-// ATTENTION: always pass BitsBuffer by reference,
-// it's a structure for performance reasons. Furthermore
-// it's a mutable one, so use it only with care!
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal static partial class BigIntegerCalculator
{
internal struct BitsBuffer
diff --git a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.DivRem.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.DivRem.cs
similarity index 97%
rename from OnlineMusicApi/System/Numerics/BigIntegerCalculator.DivRem.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.DivRem.cs
index 67d2a2e..b207cb3 100644
--- a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.DivRem.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.DivRem.cs
@@ -1,11 +1,6 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
using System.Diagnostics;
-namespace System.Numerics;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal static partial class BigIntegerCalculator
{
public static uint Remainder(uint[] left, uint right)
diff --git a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.FastReducer.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.FastReducer.cs
similarity index 95%
rename from OnlineMusicApi/System/Numerics/BigIntegerCalculator.FastReducer.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.FastReducer.cs
index a0f446d..6f8c709 100644
--- a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.FastReducer.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.FastReducer.cs
@@ -1,11 +1,6 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
using System.Diagnostics;
-namespace System.Numerics;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal static partial class BigIntegerCalculator
{
internal readonly struct FastReducer
diff --git a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.PowMod.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.PowMod.cs
similarity index 97%
rename from OnlineMusicApi/System/Numerics/BigIntegerCalculator.PowMod.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.PowMod.cs
index 5e7eb28..b6cf165 100644
--- a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.PowMod.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.PowMod.cs
@@ -1,11 +1,6 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
using System.Diagnostics;
-namespace System.Numerics;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal static partial class BigIntegerCalculator
{
// Executes different exponentiation algorithms, which are
diff --git a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.SquMul.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.SquMul.cs
similarity index 98%
rename from OnlineMusicApi/System/Numerics/BigIntegerCalculator.SquMul.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.SquMul.cs
index 9600ff7..29c405a 100644
--- a/OnlineMusicApi/System/Numerics/BigIntegerCalculator.SquMul.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/BigIntegerCalculator.SquMul.cs
@@ -1,11 +1,6 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
using System.Diagnostics;
-namespace System.Numerics;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal static partial class BigIntegerCalculator
{
private static readonly int SquareThreshold = 32;
diff --git a/OnlineMusicApi/System/Numerics/NumericsHelpers.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/NumericsHelpers.cs
similarity index 76%
rename from OnlineMusicApi/System/Numerics/NumericsHelpers.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/NumericsHelpers.cs
index e25cca2..df0344e 100644
--- a/OnlineMusicApi/System/Numerics/NumericsHelpers.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/System/Numerics/NumericsHelpers.cs
@@ -1,9 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.Numerics;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics;
internal static class NumericsHelpers
{
public static void DangerousMakeTwosComplement(uint[] d)
diff --git a/OnlineMusicApi/util/crypto.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/crypto.cs
similarity index 97%
rename from OnlineMusicApi/util/crypto.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/crypto.cs
index 9de4e25..917050f 100644
--- a/OnlineMusicApi/util/crypto.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/crypto.cs
@@ -1,14 +1,11 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Numerics;
+#pragma warning disable
+
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
+using BigInteger = The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Numerics.BigInteger;
-namespace NeteaseCloudMusicApi.util;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.util;
internal static class crypto
{
private static readonly byte[] iv = Encoding.ASCII.GetBytes("0102030405060708");
diff --git a/OnlineMusicApi/util/options.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/options.cs
similarity index 64%
rename from OnlineMusicApi/util/options.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/options.cs
index ee82c2e..e044b34 100644
--- a/OnlineMusicApi/util/options.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/options.cs
@@ -1,7 +1,8 @@
+#pragma warning disable
+
using System.Net;
-namespace NeteaseCloudMusicApi.util;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.util;
internal sealed class options
{
public string crypto;
diff --git a/OnlineMusicApi/util/request.cs b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/request.cs
similarity index 98%
rename from OnlineMusicApi/util/request.cs
rename to The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/request.cs
index 6495c1c..83d20f6 100644
--- a/OnlineMusicApi/util/request.cs
+++ b/The Untamed Music Player/OnlineAPIs/CloudMusicAPI/util/request.cs
@@ -1,19 +1,14 @@
-using System;
-using System.Collections.Generic;
-using System.Extensions;
-using System.IO;
+#pragma warning disable
+
using System.IO.Compression;
-using System.Linq;
using System.Net;
-using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.System.Extensions;
-namespace NeteaseCloudMusicApi.util;
-
+namespace The_Untamed_Music_Player.OnlineAPIs.CloudMusicAPI.util;
internal static partial class request
{
private static readonly string[] userAgentList = [
diff --git a/The Untamed Music Player/Strings/en-us/Resources.resw b/The Untamed Music Player/Strings/en-us/Resources.resw
index 8a61a16..e3560e9 100644
--- a/The Untamed Music Player/Strings/en-us/Resources.resw
+++ b/The Untamed Music Player/Strings/en-us/Resources.resw
@@ -216,6 +216,9 @@
Songs
+
+ Playlists
+
Albums
@@ -606,4 +609,28 @@
Unknown year
+
+ Music library 1
+
+
+ Music library 6
+
+
+ Music library 5
+
+
+ Music library 4
+
+
+ Music library 3
+
+
+ Music library 2
+
+
+ Network error, please retry later
+
+
+ Retry
+
\ No newline at end of file
diff --git a/The Untamed Music Player/Strings/zh-cn/Resources.resw b/The Untamed Music Player/Strings/zh-cn/Resources.resw
index 4abffec..c9045e8 100644
--- a/The Untamed Music Player/Strings/zh-cn/Resources.resw
+++ b/The Untamed Music Player/Strings/zh-cn/Resources.resw
@@ -216,6 +216,9 @@
歌曲
+
+ 歌单
+
专辑
@@ -606,4 +609,28 @@
未知年份
+
+ 乐库1
+
+
+ 乐库6
+
+
+ 乐库5
+
+
+ 乐库4
+
+
+ 乐库3
+
+
+ 乐库2
+
+
+ 网络异常,请稍后再试
+
+
+ 重试
+
\ No newline at end of file
diff --git a/The Untamed Music Player/The Untamed Music Player.csproj b/The Untamed Music Player/The Untamed Music Player.csproj
index 3a2a086..0b4bcb4 100644
--- a/The Untamed Music Player/The Untamed Music Player.csproj
+++ b/The Untamed Music Player/The Untamed Music Player.csproj
@@ -37,6 +37,12 @@
+
+
+
+
+
+
@@ -45,16 +51,19 @@
+
-
-
+
+
-
-
-
+
+
+
-
+
+
+
@@ -63,6 +72,18 @@
Always
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
MSBuild:Compile
@@ -74,6 +95,8 @@
False
+ False
+ Dynamic
@@ -83,30 +106,36 @@
full
True
+ CS8981
full
True
+ CS8981
full
True
+ CS8981
full
True
+ CS8981
full
True
+ CS8981
full
True
+ CS8981
diff --git a/The Untamed Music Player/ViewModels/AlbumDetailViewModel.cs b/The Untamed Music Player/ViewModels/AlbumDetailViewModel.cs
index f6af740..a1c8209 100644
--- a/The Untamed Music Player/ViewModels/AlbumDetailViewModel.cs
+++ b/The Untamed Music Player/ViewModels/AlbumDetailViewModel.cs
@@ -16,19 +16,19 @@ public partial class AlbumDetailViewModel : ObservableRecipient
public AlbumDetailViewModel()
{
- var tempList = Data.MusicLibrary.GetMusicsByAlbum(Album);
+ var tempList = Data.MusicLibrary.GetSongsByAlbum(Album);
SongList = [.. tempList];
}
public void PlayAllButton_Click(object sender, RoutedEventArgs e)
{
- Data.MusicPlayer.SetPlayList($"Songs:Album:{Album.Name}", SongList);
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Album:{Album.Name}", SongList);
Data.MusicPlayer.PlaySongByPath(SongList[0].Path);
}
public void SongListView_ItemClick(object sender, ItemClickEventArgs e)
{
- Data.MusicPlayer.SetPlayList($"Songs:Album:{Album.Name}", SongList);
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Album:{Album.Name}", SongList);
if (e.ClickedItem is BriefMusicInfo briefMusicInfo)
{
Data.MusicPlayer.PlaySongByPath(briefMusicInfo.Path);
@@ -37,7 +37,7 @@ public partial class AlbumDetailViewModel : ObservableRecipient
public void PlayButton_Click(object sender, RoutedEventArgs e)
{
- Data.MusicPlayer.SetPlayList($"Songs:Album:{Album.Name}", SongList);
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Album:{Album.Name}", SongList);
if (sender is Button button && button.DataContext is BriefMusicInfo briefMusicInfo)
{
Data.MusicPlayer.PlaySongByPath(briefMusicInfo.Path);
diff --git a/The Untamed Music Player/ViewModels/ArtistDetailViewModel.cs b/The Untamed Music Player/ViewModels/ArtistDetailViewModel.cs
index ffc899f..3945144 100644
--- a/The Untamed Music Player/ViewModels/ArtistDetailViewModel.cs
+++ b/The Untamed Music Player/ViewModels/ArtistDetailViewModel.cs
@@ -1,4 +1,6 @@
+using System.Collections.ObjectModel;
using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
using The_Untamed_Music_Player.Contracts.Services;
using The_Untamed_Music_Player.Models;
@@ -21,6 +23,41 @@ public class ArtistDetailViewModel
public void PlayAllButton_Click(object sender, RoutedEventArgs e)
{
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Artist:{Artist.Name}", ConvertAllSongsToFlatList());
+ Data.MusicPlayer.PlaySongByPath(AlbumList[0].SongList[0].Path);
+ }
+
+ public void SongListView_ItemClick(object sender, ItemClickEventArgs e)
+ {
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Artist:{Artist.Name}", ConvertAllSongsToFlatList());
+ if (e.ClickedItem is BriefMusicInfo briefMusicInfo)
+ {
+ Data.MusicPlayer.PlaySongByPath(briefMusicInfo.Path);
+ }
+ }
+
+ public void SongListViewPlayButton_Click(object sender, RoutedEventArgs e)
+ {
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Artist:{Artist.Name}", ConvertAllSongsToFlatList());
+ if (sender is Button button && button.DataContext is BriefMusicInfo briefMusicInfo)
+ {
+ Data.MusicPlayer.PlaySongByPath(briefMusicInfo.Path);
+ }
+ }
+
+ public void AlbumGridViewPlayButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (sender is Button button && button.DataContext is BriefAlbumInfo briefAlbumInfo)
+ {
+ var songList = new ObservableCollection(briefAlbumInfo.SongList);
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Album:{briefAlbumInfo.Name}", songList);
+ Data.MusicPlayer.PlaySongByPath(songList[0].Path);
+ }
+ }
+
+ private ObservableCollection ConvertAllSongsToFlatList()
+ {
+ return [.. AlbumList.SelectMany(album => album.SongList)];
}
public async Task LoadSelectionBarSelectedIndex()
diff --git a/The Untamed Music Player/ViewModels/HomeViewModel.cs b/The Untamed Music Player/ViewModels/HomeViewModel.cs
index 03c657f..6dc48f6 100644
--- a/The Untamed Music Player/ViewModels/HomeViewModel.cs
+++ b/The Untamed Music Player/ViewModels/HomeViewModel.cs
@@ -1,25 +1,132 @@
+using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.WinUI.Controls;
+using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media.Animation;
+using The_Untamed_Music_Player.Contracts.Services;
+using The_Untamed_Music_Player.Models;
+using The_Untamed_Music_Player.Views;
namespace The_Untamed_Music_Player.ViewModels;
public partial class HomeViewModel : ObservableRecipient
{
+ public byte PageIndex
+ {
+ get;
+ set
+ {
+ field = value;
+ Data.OnlineMusicLibrary.PageIndex = value;
+ }
+ }
+
+ [ObservableProperty]
+ public partial byte MusicLibraryIndex { get; set; }
+ partial void OnMusicLibraryIndexChanged(byte value)
+ {
+ Data.OnlineMusicLibrary.MusicLibraryIndex = value;
+ SaveMusicLibraryIndex();
+ }
+
+ private readonly ILocalSettingsService _localSettingsService = App.GetService();
+
public HomeViewModel()
{
+ Initialize();
}
- public void SuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
+ private async void Initialize()
{
-
+ PageIndex = await LoadPageIndex();
+ MusicLibraryIndex = await LoadMusicLibraryIndex();
}
- public void SuggestBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)
+ public async void SuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
-
+ if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
+ {
+ Data.OnlineMusicLibrary.KeyWords = sender.Text;
+ await Data.OnlineMusicLibrary.UpdateSearchResult();
+ }
}
- public void SuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
+ public async void SuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
+ if (args.ChosenSuggestion != null && args.ChosenSuggestion is SearchResult result)
+ {
+ var keyWords = result.Label;
+ Data.OnlineMusicLibrary.ClearSearchResult();
+ var currentSelectedIndex = result.Icon switch
+ {
+ "\uE8D6" => 0,
+ "\uE93C" => 1,
+ "\uE77B" => 2,
+ "\uE728" => 3,
+ _ => 0
+ };
+ Data.OnlineMusicLibrary.KeyWords = keyWords;
+ Navigate(currentSelectedIndex);
+ await Data.OnlineMusicLibrary.Search();
+ }
+ else
+ {
+ Data.OnlineMusicLibrary.KeyWords = args.QueryText;
+ Data.OnlineMusicLibrary.ClearSearchResult();
+ await Data.OnlineMusicLibrary.Search();
+ }
+ }
+ public void SelectorBar_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (sender is SelectorBar selectorBar)
+ {
+ var selectedItem = selectorBar.Items[PageIndex];
+ selectorBar.SelectedItem = selectedItem;
+ }
+ }
+
+ public void SelectorBar_SelectionChanged(SelectorBar sender, SelectorBarSelectionChangedEventArgs args)
+ {
+ var selectedItem = sender.SelectedItem;
+ var currentSelectedIndex = sender.Items.IndexOf(selectedItem);
+
+ Navigate(currentSelectedIndex);
+ }
+
+ public void Navigate(int currentSelectedIndex, bool isFirstLoaded = false)
+ {
+ if (!isFirstLoaded && PageIndex == currentSelectedIndex)
+ {
+ return;
+ }
+ var page = currentSelectedIndex switch
+ {
+ 0 => typeof(OnlineSongsPage),
+ 1 => typeof(OnlineAlbumsPage),
+ 2 => typeof(OnlineArtistsPage),
+ 3 => typeof(OnlinePlayListsPage),
+ _ => typeof(OnlineSongsPage)
+ };
+ var slideNavigationTransitionEffect = currentSelectedIndex - PageIndex > 0 ? SlideNavigationTransitionEffect.FromRight : SlideNavigationTransitionEffect.FromLeft;
+ PageIndex = (byte)currentSelectedIndex;
+ Data.HomePage.GetFrame().Navigate(page, null, new SlideNavigationTransitionInfo() { Effect = slideNavigationTransitionEffect });
+ }
+
+ public async Task LoadPageIndex()
+ {
+ return await _localSettingsService.ReadSettingAsync("HomePageIndex");
+ }
+ public async Task LoadMusicLibraryIndex()
+ {
+ return await _localSettingsService.ReadSettingAsync("HomeMusicLibraryIndex");
+ }
+ public async void SavePageIndex()
+ {
+ await _localSettingsService.SaveSettingAsync("HomePageIndex", PageIndex);
+ }
+ public async void SaveMusicLibraryIndex()
+ {
+ await _localSettingsService.SaveSettingAsync("HomeMusicLibraryIndex", MusicLibraryIndex);
}
}
diff --git a/The Untamed Music Player/ViewModels/LocalAlbumsViewModel.cs b/The Untamed Music Player/ViewModels/LocalAlbumsViewModel.cs
index cea1e5c..34da885 100644
--- a/The Untamed Music Player/ViewModels/LocalAlbumsViewModel.cs
+++ b/The Untamed Music Player/ViewModels/LocalAlbumsViewModel.cs
@@ -123,9 +123,9 @@ public partial class LocalAlbumsViewModel : ObservableRecipient
{
if (sender is Button button && button.DataContext is AlbumInfo albumInfo)
{
- var tempList = Data.MusicLibrary.GetMusicsByAlbum(albumInfo);
+ var tempList = Data.MusicLibrary.GetSongsByAlbum(albumInfo);
var songList = new ObservableCollection(tempList);
- Data.MusicPlayer.SetPlayList($"Songs:Album:{albumInfo.Name}", songList);
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Album:{albumInfo.Name}", songList);
Data.MusicPlayer.PlaySongByPath(songList[0].Path);
}
}
diff --git a/The Untamed Music Player/ViewModels/LocalArtistsViewModel.cs b/The Untamed Music Player/ViewModels/LocalArtistsViewModel.cs
index 7ddc49f..e754619 100644
--- a/The Untamed Music Player/ViewModels/LocalArtistsViewModel.cs
+++ b/The Untamed Music Player/ViewModels/LocalArtistsViewModel.cs
@@ -73,6 +73,16 @@ public partial class LocalArtistsViewModel : ObservableRecipient
}
}
+ public void PlayButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (sender is Button button && button.DataContext is ArtistInfo artistInfo)
+ {
+ var songList = Data.MusicLibrary.GetSongsByArtist(artistInfo);
+ Data.MusicPlayer.SetPlayList($"LocalSongs:Artist:{artistInfo.Name}", songList);
+ Data.MusicPlayer.PlaySongByPath(songList[0].Path);
+ }
+ }
+
public async Task SortArtists()
{
var sortTask = SortMode switch
diff --git a/The Untamed Music Player/ViewModels/LocalSongsViewModel.cs b/The Untamed Music Player/ViewModels/LocalSongsViewModel.cs
index 6078012..6b81c68 100644
--- a/The Untamed Music Player/ViewModels/LocalSongsViewModel.cs
+++ b/The Untamed Music Player/ViewModels/LocalSongsViewModel.cs
@@ -160,7 +160,7 @@ public partial class LocalSongsViewModel : ObservableRecipient
public void SongListView_ItemClick(object sender, ItemClickEventArgs e)
{
- Data.MusicPlayer.SetPlayList("Songs:All", ConvertGroupedToFlatList(), SortMode);
+ Data.MusicPlayer.SetPlayList("LocalSongs:All", ConvertGroupedToFlatList(), SortMode);
if (e.ClickedItem is BriefMusicInfo briefMusicInfo)
{
Data.MusicPlayer.PlaySongByPath(briefMusicInfo.Path);
@@ -169,7 +169,7 @@ public partial class LocalSongsViewModel : ObservableRecipient
public void PlayButton_Click(object sender, RoutedEventArgs e)
{
- Data.MusicPlayer.SetPlayList("Songs:All", ConvertGroupedToFlatList(), SortMode);
+ Data.MusicPlayer.SetPlayList("LocalSongs:All", ConvertGroupedToFlatList(), SortMode);
if (sender is Button button && button.DataContext is BriefMusicInfo briefMusicInfo)
{
Data.MusicPlayer.PlaySongByPath(briefMusicInfo.Path);
@@ -253,27 +253,11 @@ public partial class LocalSongsViewModel : ObservableRecipient
await SortSongs();
}
- public ObservableCollection ConvertGroupedToFlatList()
+ private ObservableCollection ConvertGroupedToFlatList()
{
- if (_isGrouped)
- {
- var flatList = new ObservableCollection();
- foreach (var group in GroupedSongList)
- {
- foreach (var item in group)
- {
- if (item is BriefMusicInfo musicInfo)
- {
- flatList.Add(musicInfo);
- }
- }
- }
- return flatList;
- }
- else
- {
- return NotGroupedSongList;
- }
+ return _isGrouped
+ ? [.. GroupedSongList.SelectMany(group => group.OfType())]
+ : NotGroupedSongList;
}
public object GetSongListViewSource(ICollectionView grouped, ObservableCollection notgrouped)
diff --git a/The Untamed Music Player/ViewModels/MusicLibraryViewModel.cs b/The Untamed Music Player/ViewModels/MusicLibraryViewModel.cs
index 17670f7..016a416 100644
--- a/The Untamed Music Player/ViewModels/MusicLibraryViewModel.cs
+++ b/The Untamed Music Player/ViewModels/MusicLibraryViewModel.cs
@@ -25,7 +25,7 @@ public partial class MusicLibraryViewModel : ObservableRecipient
private async Task InitializeLibraryAsync()
{
Data.MusicLibrary.PropertyChanged += MusicLibrary_PropertyChanged;
- if (!Data.hasMusicLibraryLoaded)
+ if (!Data.HasMusicLibraryLoaded)
{
await Task.Run(Data.MusicLibrary.LoadLibraryAsync);
}
diff --git a/The Untamed Music Player/ViewModels/OnlineSongsViewModel.cs b/The Untamed Music Player/ViewModels/OnlineSongsViewModel.cs
new file mode 100644
index 0000000..ba57798
--- /dev/null
+++ b/The Untamed Music Player/ViewModels/OnlineSongsViewModel.cs
@@ -0,0 +1,9 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using The_Untamed_Music_Player.Contracts.Models;
+using The_Untamed_Music_Player.Models;
+
+namespace The_Untamed_Music_Player.ViewModels;
+
+public partial class OnlineSongsViewModel : ObservableRecipient
+{
+}
diff --git a/The Untamed Music Player/ViewModels/SettingsViewModel.cs b/The Untamed Music Player/ViewModels/SettingsViewModel.cs
index 3b2f85c..6a8dc85 100644
--- a/The Untamed Music Player/ViewModels/SettingsViewModel.cs
+++ b/The Untamed Music Player/ViewModels/SettingsViewModel.cs
@@ -20,10 +20,7 @@ public partial class SettingsViewModel : ObservableRecipient
private readonly IThemeSelectorService _themeSelectorService;
private readonly ILocalSettingsService _localSettingsService;
- public ICommand SwitchThemeCommand
- {
- get;
- }
+ public ICommand SwitchThemeCommand { get; }
///
/// 是否显示文件夹为空信息
@@ -69,19 +66,13 @@ public partial class SettingsViewModel : ObservableRecipient
/// 深浅色主题
///
[ObservableProperty]
- public partial ElementTheme ElementTheme
- {
- get; set;
- }
+ public partial ElementTheme ElementTheme { get; set; }
///
/// 版本信息
///
[ObservableProperty]
- public partial string VersionDescription
- {
- get; set;
- }
+ public partial string VersionDescription { get; set; }
///
/// 选中的字体
diff --git a/The Untamed Music Player/Views/AlbumDetailPage.xaml.cs b/The Untamed Music Player/Views/AlbumDetailPage.xaml.cs
index 861e425..9c785b2 100644
--- a/The Untamed Music Player/Views/AlbumDetailPage.xaml.cs
+++ b/The Untamed Music Player/Views/AlbumDetailPage.xaml.cs
@@ -57,7 +57,7 @@ public sealed partial class AlbumDetailPage : Page
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
- if (e.NavigationMode == NavigationMode.Back)
+ if (e.NavigationMode == NavigationMode.Back && e.SourcePageType != typeof(ArtistDetailPage))
{
ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("BackConnectedAnimation", CoverArt);
}
diff --git a/The Untamed Music Player/Views/ArtistDetailPage.xaml b/The Untamed Music Player/Views/ArtistDetailPage.xaml
index f0759aa..d20e214 100644
--- a/The Untamed Music Player/Views/ArtistDetailPage.xaml
+++ b/The Untamed Music Player/Views/ArtistDetailPage.xaml
@@ -117,6 +117,7 @@
@@ -197,6 +198,7 @@
IsThreeState="False" Visibility="Collapsed"/>
diff --git a/The Untamed Music Player/Views/ArtistDetailPage.xaml.cs b/The Untamed Music Player/Views/ArtistDetailPage.xaml.cs
index 40678d4..a1a5336 100644
--- a/The Untamed Music Player/Views/ArtistDetailPage.xaml.cs
+++ b/The Untamed Music Player/Views/ArtistDetailPage.xaml.cs
@@ -9,6 +9,7 @@ using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Animation;
using Microsoft.UI.Xaml.Navigation;
+using The_Untamed_Music_Player.Models;
using The_Untamed_Music_Player.ViewModels;
using Windows.Storage.Streams;
using EF = CommunityToolkit.WinUI.Animations.Expressions.ExpressionFunctions;
@@ -66,13 +67,24 @@ public sealed partial class ArtistDetailPage : Page
SelectionBarSelectedIndex = await ViewModel.LoadSelectionBarSelectedIndex();
}
+ ///
+ /// 当页面导航到此页时,将调用此方法。
+ ///
+ ///
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
- var animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("ForwardConnectedAnimation");
- animation?.TryStart(CoverArt);
+ if (e.NavigationMode == NavigationMode.New)
+ {
+ var animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("ForwardConnectedAnimation");
+ animation?.TryStart(CoverArt);
+ }
}
+ ///
+ /// 当页面从此页导航时,将调用此方法。
+ ///
+ ///
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
@@ -346,4 +358,51 @@ public sealed partial class ArtistDetailPage : Page
}
SelectionBarSelectedIndex = currentSelectedIndex;
}
+
+ private void SongListViewPlayButton_Click(object sender, RoutedEventArgs e)
+ {
+ ViewModel.SongListViewPlayButton_Click(sender, e);
+ }
+
+ private void SongListView_ItemClick(object sender, ItemClickEventArgs e)
+ {
+ ViewModel.SongListView_ItemClick(sender, e);
+ }
+
+ private void AlbumGridViewPlayButton_Click(object sender, RoutedEventArgs e)
+ {
+ ViewModel.AlbumGridViewPlayButton_Click(sender, e);
+ }
+
+ private void AlbumGridView_ItemClick(object sender, ItemClickEventArgs e)
+ {
+ if (e.ClickedItem is BriefAlbumInfo briefAlbumInfo)
+ {
+ var albumInfo = Data.MusicLibrary.Albums[briefAlbumInfo.Name];
+ if (albumInfo != null)
+ {
+ var grid = (Grid)((ContentControl)AlbumGridView.ContainerFromItem(e.ClickedItem)).ContentTemplateRoot;
+ var border = (Border)grid.Children[1];
+ ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("ForwardConnectedAnimation", border);
+ Data.SelectedAlbum = albumInfo;
+ Data.ShellPage!.GetFrame().Navigate(typeof(AlbumDetailPage), null, new SuppressNavigationTransitionInfo());
+ }
+ }
+ }
+
+ /*private void AlbumGridView_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (Data.SelectedBriefAlbum != null && sender is GridView gridView)
+ {
+ gridView.ScrollIntoView(Data.SelectedBriefAlbum, ScrollIntoViewAlignment.Leading);
+ gridView.UpdateLayout();
+ var animation = ConnectedAnimationService.GetForCurrentView().GetAnimation("BackConnectedAnimation");
+ if (animation != null)
+ {
+ animation.Configuration = new DirectConnectedAnimationConfiguration();
+ await gridView.TryStartConnectedAnimationAsync(animation, Data.SelectedBriefAlbum, "CoverBorder");
+ }
+ gridView.Focus(FocusState.Programmatic);
+ }
+ }*/
}
diff --git a/The Untamed Music Player/Views/HomePage.xaml b/The Untamed Music Player/Views/HomePage.xaml
index 8ef3975..bf3a40f 100644
--- a/The Untamed Music Player/Views/HomePage.xaml
+++ b/The Untamed Music Player/Views/HomePage.xaml
@@ -1,15 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -21,14 +43,34 @@
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -43,25 +85,84 @@
Grid.Column="0"
FontSize="40"
FontWeight="{x:Bind helper:LanguageRelated.GetTitleFontWeight()}"/>
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/The Untamed Music Player/Views/HomePage.xaml.cs b/The Untamed Music Player/Views/HomePage.xaml.cs
index 1596e72..80e403a 100644
--- a/The Untamed Music Player/Views/HomePage.xaml.cs
+++ b/The Untamed Music Player/Views/HomePage.xaml.cs
@@ -1,5 +1,7 @@
+using CommunityToolkit.WinUI.Controls;
+using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
-
+using The_Untamed_Music_Player.Models;
using The_Untamed_Music_Player.ViewModels;
namespace The_Untamed_Music_Player.Views;
@@ -15,10 +17,12 @@ public sealed partial class HomePage : Page
{
ViewModel = App.GetService();
InitializeComponent();
+ Data.HomePage = this;
+ ViewModel.Navigate(ViewModel.PageIndex, true);
}
- private void SelectorBar_SelectionChanged(SelectorBar sender, SelectorBarSelectionChangedEventArgs args)
+ public Frame GetFrame()
{
-
+ return SelectFrame;
}
}
diff --git a/The Untamed Music Player/Views/LocalArtistsPage.xaml b/The Untamed Music Player/Views/LocalArtistsPage.xaml
index f4ed608..6d8c21e 100644
--- a/The Untamed Music Player/Views/LocalArtistsPage.xaml
+++ b/The Untamed Music Player/Views/LocalArtistsPage.xaml
@@ -92,7 +92,7 @@
Width="32" Height="32"
Margin="13,0,0,8" HorizontalAlignment="Left"
VerticalAlignment="Bottom"
- Canvas.ZIndex="2"
+ Canvas.ZIndex="2" Click="PlayButton_Click"
Style="{StaticResource CircularButtonStyle}"
Visibility="Collapsed">
diff --git a/The Untamed Music Player/Views/LocalArtistsPage.xaml.cs b/The Untamed Music Player/Views/LocalArtistsPage.xaml.cs
index 7c2d752..9388db2 100644
--- a/The Untamed Music Player/Views/LocalArtistsPage.xaml.cs
+++ b/The Untamed Music Player/Views/LocalArtistsPage.xaml.cs
@@ -87,4 +87,9 @@ public sealed partial class LocalArtistsPage : Page
gridView.Focus(FocusState.Programmatic);
}
}
+
+ private void PlayButton_Click(object sender, RoutedEventArgs e)
+ {
+ ViewModel.PlayButton_Click(sender, e);
+ }
}
diff --git a/The Untamed Music Player/Views/LocalSongsPage.xaml b/The Untamed Music Player/Views/LocalSongsPage.xaml
index d0ef5ee..3b30b53 100644
--- a/The Untamed Music Player/Views/LocalSongsPage.xaml
+++ b/The Untamed Music Player/Views/LocalSongsPage.xaml
@@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helper="using:The_Untamed_Music_Player.Helpers"
+ xmlns:contract="using:The_Untamed_Music_Player.Contracts.Models"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:The_Untamed_Music_Player.Models"
diff --git a/The Untamed Music Player/Views/OnlineAlbumsPage.xaml b/The Untamed Music Player/Views/OnlineAlbumsPage.xaml
new file mode 100644
index 0000000..f553de0
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlineAlbumsPage.xaml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/The Untamed Music Player/Views/OnlineAlbumsPage.xaml.cs b/The Untamed Music Player/Views/OnlineAlbumsPage.xaml.cs
new file mode 100644
index 0000000..163865e
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlineAlbumsPage.xaml.cs
@@ -0,0 +1,10 @@
+using Microsoft.UI.Xaml.Controls;
+
+namespace The_Untamed_Music_Player.Views;
+public sealed partial class OnlineAlbumsPage : Page
+{
+ public OnlineAlbumsPage()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/The Untamed Music Player/Views/OnlineArtistsPage.xaml b/The Untamed Music Player/Views/OnlineArtistsPage.xaml
new file mode 100644
index 0000000..889ae53
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlineArtistsPage.xaml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/The Untamed Music Player/Views/OnlineArtistsPage.xaml.cs b/The Untamed Music Player/Views/OnlineArtistsPage.xaml.cs
new file mode 100644
index 0000000..fdf19c8
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlineArtistsPage.xaml.cs
@@ -0,0 +1,10 @@
+using Microsoft.UI.Xaml.Controls;
+
+namespace The_Untamed_Music_Player.Views;
+public sealed partial class OnlineArtistsPage : Page
+{
+ public OnlineArtistsPage()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/The Untamed Music Player/Views/OnlinePlayListsPage.xaml b/The Untamed Music Player/Views/OnlinePlayListsPage.xaml
new file mode 100644
index 0000000..09369d2
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlinePlayListsPage.xaml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/The Untamed Music Player/Views/OnlinePlayListsPage.xaml.cs b/The Untamed Music Player/Views/OnlinePlayListsPage.xaml.cs
new file mode 100644
index 0000000..7eb8a04
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlinePlayListsPage.xaml.cs
@@ -0,0 +1,10 @@
+using Microsoft.UI.Xaml.Controls;
+
+namespace The_Untamed_Music_Player.Views;
+public sealed partial class OnlinePlayListsPage : Page
+{
+ public OnlinePlayListsPage()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/The Untamed Music Player/Views/OnlineSongsPage.xaml b/The Untamed Music Player/Views/OnlineSongsPage.xaml
new file mode 100644
index 0000000..c2a00ba
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlineSongsPage.xaml
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/The Untamed Music Player/Views/OnlineSongsPage.xaml.cs b/The Untamed Music Player/Views/OnlineSongsPage.xaml.cs
new file mode 100644
index 0000000..2dcdc58
--- /dev/null
+++ b/The Untamed Music Player/Views/OnlineSongsPage.xaml.cs
@@ -0,0 +1,67 @@
+using CommunityToolkit.WinUI;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+using The_Untamed_Music_Player.Models;
+using The_Untamed_Music_Player.ViewModels;
+
+namespace The_Untamed_Music_Player.Views;
+public sealed partial class OnlineSongsPage : Page
+{
+ private ScrollViewer? _scrollViewer;
+
+ public OnlineSongsViewModel ViewModel
+ {
+ get; set;
+ }
+
+ public OnlineSongsPage()
+ {
+ ViewModel = App.GetService();
+ InitializeComponent();
+ }
+
+ private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e)
+ {
+ var grid = sender as Grid;
+ var checkBox = grid?.FindName("ItemCheckBox") as CheckBox;
+ var playButton = grid?.FindName("PlayButton") as Button;
+ if (checkBox != null)
+ {
+ checkBox.Visibility = Visibility.Visible;
+ }
+ if (playButton != null)
+ {
+ playButton.Visibility = Visibility.Visible;
+ }
+ }
+
+ private void Grid_PointerExited(object sender, PointerRoutedEventArgs e)
+ {
+ var grid = sender as Grid;
+ var checkBox = grid?.FindName("ItemCheckBox") as CheckBox;
+ var playButton = grid?.FindName("PlayButton") as Button;
+ if (checkBox != null)
+ {
+ checkBox.Visibility = Visibility.Collapsed;
+ }
+ if (playButton != null)
+ {
+ playButton.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ private void OnlineSongsPage_Loaded(object sender, RoutedEventArgs e)
+ {
+ _scrollViewer = SongListView.FindDescendant() ?? throw new Exception("Cannot find ScrollViewer in ListView"); // 检索 ListView 内部使用的 ScrollViewer
+
+ _scrollViewer.ViewChanged += async (s, e) =>
+ {
+ if (!Data.OnlineMusicLibrary.OnlineMusicInfoList.HasAllLoaded && _scrollViewer.VerticalOffset + _scrollViewer.ViewportHeight >= _scrollViewer.ExtentHeight - 50)
+ {
+ await Data.OnlineMusicLibrary.SearchMore();
+ await Task.Delay(3000);
+ }
+ };
+ }
+}
diff --git a/The Untamed Music Player/Views/PropertiesDialog.xaml.cs b/The Untamed Music Player/Views/PropertiesDialog.xaml.cs
index 2fc501f..5d767f3 100644
--- a/The Untamed Music Player/Views/PropertiesDialog.xaml.cs
+++ b/The Untamed Music Player/Views/PropertiesDialog.xaml.cs
@@ -1,13 +1,14 @@
using System.Diagnostics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
+using The_Untamed_Music_Player.Contracts.Models;
using The_Untamed_Music_Player.Models;
namespace The_Untamed_Music_Player.Views;
public sealed partial class PropertiesDialog : ContentDialog
{
- public DetailedMusicInfo Music { get; set; } = Data.MusicPlayer.CurrentMusic;
+ public IDetailedMusicInfoBase Music { get; set; } = Data.MusicPlayer.CurrentMusic!;
public PropertiesDialog()
{
diff --git a/The Untamed Music Player/Views/RootPlayBarView.xaml.cs b/The Untamed Music Player/Views/RootPlayBarView.xaml.cs
index 6969c61..ccdf58c 100644
--- a/The Untamed Music Player/Views/RootPlayBarView.xaml.cs
+++ b/The Untamed Music Player/Views/RootPlayBarView.xaml.cs
@@ -1,5 +1,6 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
+using The_Untamed_Music_Player.Contracts.Models;
using The_Untamed_Music_Player.Helpers;
using The_Untamed_Music_Player.Models;
using The_Untamed_Music_Player.ViewModels;
@@ -90,7 +91,7 @@ public sealed partial class RootPlayBarView : Page
};
}
- public Visibility GetArtistAndAlbumStrVisibility(DetailedMusicInfo detailedmusicinfo)
+ public Visibility GetArtistAndAlbumStrVisibility(IDetailedMusicInfoBase detailedmusicinfo)
{
return detailedmusicinfo.ArtistAndAlbumStr == "" ? Visibility.Collapsed : Visibility.Visible;
}