InputSourceProviderLite.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System.Text;
  2. using Bmp.Core.Common.Net;
  3. using Bmp.Core.Common.Utility;
  4. namespace Bmp.Core.Lite.Playback.Inputs;
  5. public class InputSourceProviderLite
  6. {
  7. protected InputSourceProviderLite()
  8. {
  9. }
  10. public static string[] ExpandPaths(string inputPath)
  11. {
  12. // TODO: InputSourceProvider::ExpandPath M3U(8) ISO ZIP RAR 7Z / InURL
  13. // TODO: InputSourceProvider::ExpandPath EventBus for warn and err
  14. // [http[s]://foo.bar/]foo.zip?#path/to/inner/01.flac
  15. // [http[s]://foo.bar/]foo.iso?#DSD.ISO#1
  16. var (exists, size) = FileCheckSize(inputPath);
  17. if (exists)
  18. {
  19. var ex = Path.GetExtension(inputPath).ToLower();
  20. using var stream = ReadContentAsSeekableStream(inputPath);
  21. // TODO: ExpandPaths Pack Files : ISO zip rar 7z more
  22. // ------------ m3u/8 ------------
  23. if (size.HasValue && size > 1024 * 1024)
  24. {
  25. // > 1MB may not playlist, skip
  26. }
  27. else
  28. {
  29. const string sign_ExtM3u = "#EXTM3U";
  30. if (Encoding.ASCII.GetString(stream.ReadBytes(sign_ExtM3u.Length)) == sign_ExtM3u)
  31. {
  32. stream.Position = 0;
  33. var lines = stream.ReadLines(ex == ".m3u8" ? Encoding.UTF8 : null);
  34. return lines.Where(p => p.StartsWith("#") == false).ToArray();
  35. }
  36. }
  37. }
  38. return new[] { inputPath };
  39. }
  40. // ----- utils -----
  41. protected static readonly IReadOnlyList<string> CoverFilePaths = new List<string>
  42. {
  43. "./Cover.jpg",
  44. "./Folder.jpg",
  45. "BK/Cover.jpg",
  46. "PIC/Cover.jpg",
  47. "PICS/Cover.jpg",
  48. "SCAN/Cover.jpg",
  49. "SCANS/Cover.jpg",
  50. "./Cover.webp",
  51. "./Folder.webp",
  52. "BK/Cover.webp",
  53. "PIC/Cover.webp",
  54. "PICS/Cover.webp",
  55. "SCAN/Cover.webp",
  56. "SCANS/Cover.webp",
  57. "./Cover.png",
  58. "./Folder.png",
  59. "BK/Cover.png",
  60. "PIC/Cover.png",
  61. "PICS/Cover.png",
  62. "SCAN/Cover.png",
  63. "SCANS/Cover.png"
  64. };
  65. protected static string ProcessUrlOrPathForFFMPEG(string urlOrPath)
  66. {
  67. var processedUrlOrPath = urlOrPath;
  68. if (Uri.TryCreate(urlOrPath, UriKind.Absolute, out var url))
  69. {
  70. if (url.IsFile) processedUrlOrPath = url.LocalPath;
  71. else if (url.IsAbsoluteUri) processedUrlOrPath = url.AbsoluteUri;
  72. }
  73. return processedUrlOrPath;
  74. }
  75. public static (bool exists, long? size) FileCheckSize(string urlOrPath)
  76. {
  77. var exists = false;
  78. long? size = null;
  79. if (!Uri.TryCreate(urlOrPath, UriKind.RelativeOrAbsolute, out var uri) || uri.IsAbsoluteUri == false || uri.IsFile)
  80. {
  81. if (!File.Exists(urlOrPath)) return (exists, size);
  82. exists = true;
  83. var fileInfo = new FileInfo(urlOrPath);
  84. size = fileInfo.Length;
  85. }
  86. else if (uri.IsAbsoluteUri && uri.Scheme.ToLower() == "data")
  87. {
  88. var base64 = urlOrPath.Split(",").LastOrDefault();
  89. if (base64 != null)
  90. {
  91. try
  92. {
  93. var bytes = Convert.FromBase64String(base64);
  94. exists = true;
  95. return (exists, bytes.Length);
  96. }
  97. catch (Exception e)
  98. {
  99. //TODO: 消息机制 错误 解析 DataURI 失败 无法获取大小
  100. Console.WriteLine(e);
  101. }
  102. }
  103. }
  104. else
  105. {
  106. using var client = new HttpClient();
  107. // use GET instead of HEAD for compatible
  108. using var request = new HttpRequestMessage(HttpMethod.Get, urlOrPath);
  109. using var response = client.Send(request, HttpCompletionOption.ResponseHeadersRead);
  110. exists = response.IsSuccessStatusCode;
  111. if (exists && response.Content.Headers.ContentLength.HasValue) size = response.Content.Headers.ContentLength.Value;
  112. }
  113. return (exists, size);
  114. }
  115. public static ReadOnlyMemory<byte> ReadContent(string urlOrPath)
  116. {
  117. if (!Uri.TryCreate(urlOrPath, UriKind.RelativeOrAbsolute, out var uri) || uri.IsAbsoluteUri == false || uri.IsFile)
  118. {
  119. if (File.Exists(urlOrPath))
  120. {
  121. return File.ReadAllBytes(urlOrPath);
  122. }
  123. }
  124. else
  125. {
  126. using var client = new HttpClient();
  127. var req = new HttpRequestMessage(HttpMethod.Get, urlOrPath);
  128. var response = client.Send(req);
  129. if (response.IsSuccessStatusCode)
  130. {
  131. ReadOnlyMemory<byte> result = null;
  132. Task.Run(async () => { result = await response.Content.ReadAsByteArrayAsync(); }).Wait();
  133. return result;
  134. }
  135. }
  136. return null;
  137. }
  138. public static Stream ReadContentAsSeekableStream(string urlOrPath)
  139. {
  140. if (!Uri.TryCreate(urlOrPath, UriKind.RelativeOrAbsolute, out var uri) || uri.IsAbsoluteUri == false || uri.IsFile)
  141. {
  142. return File.OpenRead(urlOrPath);
  143. }
  144. if (uri.IsAbsoluteUri && uri.Scheme.ToLower() == "data")
  145. {
  146. var base64 = urlOrPath.Split(",").LastOrDefault();
  147. if (base64 != null)
  148. {
  149. try
  150. {
  151. var bytes = Convert.FromBase64String(base64);
  152. return new MemoryStream(bytes);
  153. }
  154. catch (Exception e)
  155. {
  156. //TODO: 消息机制 错误 解析 DataURI 失败
  157. Console.WriteLine(e);
  158. throw;
  159. }
  160. }
  161. }
  162. return new SeekableHttpStream(urlOrPath);
  163. }
  164. }