Prechádzať zdrojové kódy

cleanup code; add m3u support (no debugged)

Coder 8 mesiacov pred
rodič
commit
7a260fde65

+ 19 - 2
Bmp.Core/Common/Utility/MarshalExtension.cs

@@ -7,6 +7,23 @@ using System.Threading.Tasks;
 
 namespace Bmp.Core.Common.Utility
 {
+    public static class IoExtension
+    {
+        public static IEnumerable<string> ReadLines(this Stream stream, Encoding? encoding = null)
+        {
+            using var reader = encoding == null
+                ? new StreamReader(stream, leaveOpen: true)
+                : new StreamReader(stream, encoding, true);
+
+            while (true)
+            {
+                var line = reader.ReadLine();
+                if (line == null) yield break;
+                yield return line;
+            }
+        }
+    }
+
     public static class MarshalExtension
     {
         public static byte[] ReadBytes(this Stream stream, int count)
@@ -26,7 +43,7 @@ namespace Bmp.Core.Common.Utility
         public static T ReadStruct<T>(this Stream stream)
         {
             var buffer = stream.ReadBytes(Marshal.SizeOf(typeof(T)));
- 
+
             var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
             var result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T))!;
             handle.Free();
@@ -37,7 +54,7 @@ namespace Bmp.Core.Common.Utility
         public static void ReadStruct<T>(this Stream stream, ref T result)
         {
             var buffer = stream.ReadBytes(Marshal.SizeOf(typeof(T)));
-          
+
             var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
             result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T))!;
             handle.Free();

+ 70 - 46
Bmp.Core/Playback/Inputs/InputSourceProvider.cs

@@ -1,5 +1,6 @@
 using System.Text;
 using Bmp.Core.Common.Net;
+using Bmp.Core.Common.Utility;
 using Bmp.Core.FFMpeg.CsCorePorts;
 using Bmp.Core.FFMpeg.CsCorePorts.FFMpegWrap;
 using Bmp.Core.Playback.Inputs;
@@ -9,31 +10,6 @@ namespace Bmp.Core.Playback.Inputs
 {
     public static class InputSourceProvider
     {
-        private static readonly IReadOnlyList<string> CoverFilePaths = new List<string>
-        {
-            "./Cover.jpg",
-            "./Folder.jpg",
-            "BK/Cover.jpg",
-            "PIC/Cover.jpg",
-            "PICS/Cover.jpg",
-            "SCAN/Cover.jpg",
-            "SCANS/Cover.jpg",
-            "./Cover.webp",
-            "./Folder.webp",
-            "BK/Cover.webp",
-            "PIC/Cover.webp",
-            "PICS/Cover.webp",
-            "SCAN/Cover.webp",
-            "SCANS/Cover.webp",
-            "./Cover.png",
-            "./Folder.png",
-            "BK/Cover.png",
-            "PIC/Cover.png",
-            "PICS/Cover.png",
-            "SCAN/Cover.png",
-            "SCANS/Cover.png"
-        };
-
         public static AttachedPic[] GetPics(string urlOrPath)
         {
             AttachedPic[]? mappedEmbeddedPics = null;
@@ -75,7 +51,7 @@ namespace Bmp.Core.Playback.Inputs
             return mappedEmbeddedPics ?? Array.Empty<AttachedPic>();
         }
 
-        public static MetaData GetMeta(string urlOrPath)
+        public static MetaData ReadMeta(string urlOrPath)
         {
             if (Uri.TryCreate(urlOrPath, UriKind.Absolute, out var url))
             {
@@ -108,6 +84,8 @@ namespace Bmp.Core.Playback.Inputs
 
         public static WaveStream CreateWaveStream(string urlOrPath, bool decodeDsdToPcm = false)
         {
+            //TODO: InputSourceProvider::CreateWaveStream detect inner path
+
             //BACKLOG: more decoder
 
             if (decodeDsdToPcm == false)
@@ -129,6 +107,62 @@ namespace Bmp.Core.Playback.Inputs
             return new FFMPEGAudioReader(urlOrPath);
         }
 
+        public static string[] ExpandPaths(string inputPath)
+        {
+            // TODO: InputSourceProvider::ExpandPath M3U(8) ISO ZIP RAR 7Z / InURL 
+            // TODO: InputSourceProvider::ExpandPath EventBus for warn and err
+            // [http://]foo.bar/foo.zip?path/to/inner/01.flac
+
+            var (exists, size) = FileCheckSize(inputPath);
+            if (exists)
+            {
+                var ex = Path.GetExtension(inputPath).ToLower();
+                using var stream = ReadContentAsSeekableStream(inputPath);
+                // ------------ m3u/8 ------------
+                if (size.HasValue && size < 1024 * 1025 * 1) // < 1MB
+                {
+                    const string sign_ExtM3u = "#EXTM3U";
+                    if (Encoding.ASCII.GetString(stream.ReadBytes(sign_ExtM3u.Length)) == sign_ExtM3u)
+                    {
+                        stream.Position = 0;
+                        var lines = stream.ReadLines(ex == ".m3u8" ? Encoding.UTF8 : null);
+                        return lines.Where(p => p.StartsWith("#")).ToArray();
+                    }
+                    //TODO: Debug here
+                }
+
+            }
+
+            return new[] { inputPath };
+        }
+
+        // ----- utils  ----- 
+
+        private static readonly IReadOnlyList<string> CoverFilePaths = new List<string>
+        {
+            "./Cover.jpg",
+            "./Folder.jpg",
+            "BK/Cover.jpg",
+            "PIC/Cover.jpg",
+            "PICS/Cover.jpg",
+            "SCAN/Cover.jpg",
+            "SCANS/Cover.jpg",
+            "./Cover.webp",
+            "./Folder.webp",
+            "BK/Cover.webp",
+            "PIC/Cover.webp",
+            "PICS/Cover.webp",
+            "SCAN/Cover.webp",
+            "SCANS/Cover.webp",
+            "./Cover.png",
+            "./Folder.png",
+            "BK/Cover.png",
+            "PIC/Cover.png",
+            "PICS/Cover.png",
+            "SCAN/Cover.png",
+            "SCANS/Cover.png"
+        };
+
         public static (bool exists, long? size) FileCheckSize(string urlOrPath)
         {
             var exists = false;
@@ -136,30 +170,20 @@ namespace Bmp.Core.Playback.Inputs
 
             if (!Uri.TryCreate(urlOrPath, UriKind.RelativeOrAbsolute, out var uri) || uri.IsAbsoluteUri == false || uri.IsFile)
             {
-                if (File.Exists(urlOrPath))
-                {
-                    exists = true;
-                    var fileInfo = new FileInfo(urlOrPath);
-                    size = fileInfo.Length;
-                }
+                if (!File.Exists(urlOrPath)) return (exists, size);
+                exists = true;
+                var fileInfo = new FileInfo(urlOrPath);
+                size = fileInfo.Length;
             }
             else
             {
-                using (var client = new HttpClient())
+                using var client = new HttpClient();
+                var request = new HttpRequestMessage(HttpMethod.Head, urlOrPath);
+                var response = client.Send(request);
+                exists = response.IsSuccessStatusCode;
+                if (exists && response.Content.Headers.ContentLength.HasValue)
                 {
-                    HttpResponseMessage response = null;
-
-                    Task.Run(async () =>
-                    {
-                        var request = new HttpRequestMessage(HttpMethod.Head, urlOrPath);
-                        response = await client.SendAsync(request);
-                    }).Wait();
-
-                    exists = response.IsSuccessStatusCode;
-                    if (exists && response.Content.Headers.ContentLength.HasValue)
-                    {
-                        size = response.Content.Headers.ContentLength.Value;
-                    }
+                    size = response.Content.Headers.ContentLength.Value;
                 }
             }
 

+ 20 - 39
Bmp.WinForms/MainForm.cs

@@ -11,8 +11,6 @@ using Bmp.Core.Playback.Outputs;
 using Bmp.WinForms.SaveLoad;
 using Bmp.WinForms.SaveLoad.Models;
 using EnumsNET;
-using Microsoft.AspNetCore.Identity.UI.Services;
-using Microsoft.AspNetCore.Routing.Constraints;
 using Microsoft.Extensions.Logging.Abstractions;
 using NAudio.Wave;
 using AsioOut = Bmp.Core.Playback.Outputs.NAudioASIO.AsioOut;
@@ -398,38 +396,18 @@ namespace Bmp.WinForms
         private async Task TrackPrevAsync()
         {
             //TODO: 上一曲(按播放模式)
-            if (_currentListViewItem != null)
-            {
-                if (_currentListViewItem.ListView != null)
-                {
-                    var nextIndex = _currentListViewItem.Index - 1;
-                    if (nextIndex > 0)
-                    {
-                        await LoadItemAsync(MainListView.Items[nextIndex]);
-                    }
-                }
-            }
+            if (_currentListViewItem is not { ListView: { } }) return;
+            var nextIndex = _currentListViewItem.Index - 1;
+            if (nextIndex > 0) await LoadItemAsync(MainListView.Items[nextIndex]);
         }
 
         private async Task TrackNextAsync()
         {
             //TODO: 下一曲(按播放模式)
-            if (_currentListViewItem != null)
-            {
-                if (_currentListViewItem.ListView != null)
-                {
-                    var nextIndex = _currentListViewItem.Index + 1;
-                    if (MainListView.Items.Count > nextIndex)
-                    {
-                        await LoadItemAsync(MainListView.Items[nextIndex]);
-                    }
-                    else
-                    {
-                        //列表最后一项时
-                        _playbackState = UIPlaybackState.Stopped;
-                    }
-                }
-            }
+            if (_currentListViewItem?.ListView == null) return;
+            var nextIndex = _currentListViewItem.Index + 1;
+            if (MainListView.Items.Count > nextIndex) await LoadItemAsync(MainListView.Items[nextIndex]);
+            else _playbackState = UIPlaybackState.Stopped; //列表最后一项时
         }
 
         // -----------------  playback event -----------------
@@ -478,22 +456,25 @@ namespace Bmp.WinForms
             _sl.Save();
         }
 
-        private async void ProcessPendingAddQueue()
+        private async void StartProcessPendingAddQueue()
         {
             var reader = _pendingAddToList.Reader;
             while (_isRunning)
             {
-                var path = await reader.ReadAsync();
-                var item = new ListViewItem();
-                item.Name = path;
-                item.Text = path;
+                var inputPath1 = await reader.ReadAsync();
 
-                for (var i = 0; i < MainListView.Columns.Count - 1; i++)
+                foreach (var path in InputSourceProvider.ExpandPaths(inputPath1))
                 {
-                    item.SubItems.Add("");
-                }
+                    var item = new ListViewItem();
+                    item.Name = path;
+
+                    item.Text = Path.GetFileName(path);
+                    if (string.IsNullOrWhiteSpace(item.Text)) item.Text = path;
 
-                MainListView.Items.Add(item);
+                    for (var i = 0; i < MainListView.Columns.Count - 1; i++) item.SubItems.Add("");
+
+                    MainListView.Items.Add(item);
+                }
             }
         }
 
@@ -730,7 +711,7 @@ namespace Bmp.WinForms
 
             _isRunning = true;
 
-            ProcessPendingAddQueue();
+            StartProcessPendingAddQueue();
         }
 
         private void MainForm_FormClosed(object sender, FormClosedEventArgs e)