Quellcode durchsuchen

brust scan: provide duration and file size

HOME vor 2 Jahren
Ursprung
Commit
b9039f7430
2 geänderte Dateien mit 171 neuen und 37 gelöschten Zeilen
  1. 3 1
      FNZCM/FNZCM.ConHost/Ver2/LibraryModels2.cs
  2. 168 36
      FNZCM/FNZCM.ConHost/Ver2/Program2.cs

+ 3 - 1
FNZCM/FNZCM.ConHost/Ver2/LibraryModels2.cs

@@ -35,13 +35,15 @@ namespace FNZCM.ConHost.Ver2
 
     internal class MediaTag2
     {
-        public MediaTag2(string title, int duration)
+        public MediaTag2(string title, int duration, long length)
         {
             Title = title;
             Duration = duration;
+            Length = length;
         }
 
         public string Title { get; }
         public int Duration { get; }
+        public long Length { get; }
     }
 }

+ 168 - 36
FNZCM/FNZCM.ConHost/Ver2/Program2.cs

@@ -19,13 +19,15 @@ namespace FNZCM.ConHost.Ver2
         //    libs
         //     albums
         //      Tracks(FLAC / AAC_*)
-        //       Meta(title / artist / duration)
+        //       Meta(title(artist) / duration)
+        //       FSI ( size )
 
         // TODO: Generate thumbnail of BKS
 
-        private static readonly ConcurrentDictionary<string, Library2> _library = new();
-        private static readonly ConcurrentDictionary<string, string> _pathMapping = new();
-        private static readonly ConcurrentDictionary<string, MediaTag2> _mediaTags = new();
+        private static readonly ConcurrentDictionary<string, Library2> Libraries = new();
+        private static readonly ConcurrentDictionary<string, string> PathMapping = new();
+        private static readonly ConcurrentDictionary<string, MediaTag2> MediaTags = new();
+
 
         private static bool _isRunning;
         private static bool _isLoading;
@@ -63,17 +65,23 @@ namespace FNZCM.ConHost.Ver2
             try
             {
                 Console.WriteLine("Scanning libraries...");
-
+                MediaTags.Clear();
+                PathMapping.Clear();
+                Libraries.Clear();
                 foreach (var kvpLib in ConfigFile.Instance.Libraries)
                 {
+                    if (_isRunning == false) throw new OperationCanceledException();
+
                     Console.WriteLine($"Library {kvpLib.Key} - {kvpLib.Value}");
 
                     var libPath = kvpLib.Key.ToLower();
-                    var lib = _library[libPath] = new Library2(kvpLib.Key);
+                    var lib = Libraries[libPath] = new Library2(kvpLib.Key);
                     var albDirArray = Directory.GetDirectories(kvpLib.Value);
 
                     foreach (var albDir in albDirArray)
                     {
+                        if (_isRunning == false) throw new OperationCanceledException();
+
                         Console.WriteLine($" Album {albDir}");
 
                         var albName = Path.GetFileName(albDir);
@@ -81,7 +89,7 @@ namespace FNZCM.ConHost.Ver2
                         var alb = lib.Albums[albPath] = new Album2(albName);
 
                         var coverFilePath = Path.Combine(albDir, "cover.jpg");
-                        if (File.Exists(coverFilePath)) _pathMapping[$"/cover/{libPath}/{albPath}/cover.jpg"] = coverFilePath;
+                        if (File.Exists(coverFilePath)) PathMapping[$"/cover/{libPath}/{albPath}/cover.jpg"] = coverFilePath;
 
                         var bkDir = Path.Combine(albDir, "bk");
                         if (Directory.Exists(bkDir))
@@ -93,7 +101,7 @@ namespace FNZCM.ConHost.Ver2
                                 var bkPath = bkName.ToLower();
                                 alb.Bks[bkPath] = bkName;
 
-                                _pathMapping[$"/bk/{libPath}/{albPath}/{bkPath}"] = file;
+                                PathMapping[$"/bk/{libPath}/{albPath}/{bkPath}"] = file;
                             }
                         }
 
@@ -105,7 +113,7 @@ namespace FNZCM.ConHost.Ver2
                             var trackPath = trackName.ToLower();
                             alb.MainTracks[trackPath] = trackName;
 
-                            _pathMapping[$"/media/{libPath}/{albPath}/{trackPath}"] = mainTrackFile;
+                            PathMapping[$"/media/{libPath}/{albPath}/{trackPath}"] = mainTrackFile;
                         }
 
                         var aacTrackDirArray = Directory.GetDirectories(albDir, "AAC_Q*");
@@ -121,11 +129,16 @@ namespace FNZCM.ConHost.Ver2
                                 var aacTrackPath = aacTrackName.ToLower();
                                 aacTrackSet.Tracks[aacTrackPath] = aacTrackName;
 
-                                _pathMapping[$"/media/{libPath}/{albPath}/{aacTrackSetPath}/{aacTrackPath}"] = file;
+                                PathMapping[$"/media/{libPath}/{albPath}/{aacTrackSetPath}/{aacTrackPath}"] = file;
                             }
                         }
                     }
                 }
+
+                Console.WriteLine("Looking tags...");
+                Parallel.ForEach(PathMapping.Keys.Where(p => p.StartsWith("/media/")), k => GetTag(k));
+                Console.WriteLine("Looking tags...Done");
+
             }
             catch (Exception e)
             {
@@ -235,7 +248,7 @@ namespace FNZCM.ConHost.Ver2
                     sb.Append("<h1>Libraries</h1>");
 
                     sb.Append("<ul>");
-                    foreach (var library in _library.OrderBy(p => p.Key))
+                    foreach (var library in Libraries.OrderBy(p => p.Key))
                     {
                         sb.Append("<li>");
                         sb.Append($"<a href='/list/{library.Key.FuckVlcAndEscape()}/'>{library.Value.Name}</a>");
@@ -251,7 +264,7 @@ namespace FNZCM.ConHost.Ver2
                 else if (pathParts.Count == 2 && pathParts[0] == "list")
                 {
                     var libName = pathParts[1];
-                    if (_library.TryGetValue(libName, out var l))
+                    if (Libraries.TryGetValue(libName, out var l))
                     {
                         var sb = new StringBuilder();
                         sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
@@ -300,8 +313,22 @@ namespace FNZCM.ConHost.Ver2
                             sb.Append("<div class=buttons>");
                             sb.Append($"<a class=button href=\"/list/{libName}/{a.Key}/tracks/\">[TRACKERS]</a>");
                             if (a.Value.Bks?.Count > 0) sb.Append($"<a class=button href=\"/list/{libName}/{a.Key}/bk/\">[BK]</a>");
-                            sb.Append($"<a class=button href=\"/list/{libName}/{a.Key.FuckVlcAndEscape()}/playlist.m3u8\">[M3U8]</a>");
-                            //TODO: AAC M3U8
+
+                            var totalDur = a.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{p.Key}").Duration);
+                            var totalLen = a.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{p.Key}").Length);
+                            sb.Append($"<a class=button href=\"/list/{libName}/{a.Key.FuckVlcAndEscape()}/playlist.m3u8\">[M3U8({totalDur.FormatDuration()}){totalLen.FormatFileSize()}]</a>");
+
+                            if (a.Value.SubTracks.Count > 0)
+                            {
+                                sb.Append("<br/>");
+                                foreach (var subTrack in a.Value.SubTracks)
+                                {
+                                    totalDur = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{subTrack.Key}/{p.Key}").Duration);
+                                    totalLen = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{subTrack.Key}/{p.Key}").Length);
+                                    sb.Append($"<a class=button href=\"/list/{libName}/{a.Key.FuckVlcAndEscape()}/{subTrack.Key.FuckVlcAndEscape()}/playlist.m3u8\">[M3U8-{subTrack.Value.Name}({totalDur.FormatDuration()}){totalLen.FormatFileSize()}]</a>");
+                                }
+                            }
+
                             sb.Append("</div>");
                             sb.Append($"<span>{a.Value.Name}<span>");
                             sb.Append("</div>");
@@ -322,8 +349,7 @@ namespace FNZCM.ConHost.Ver2
                     var libName = pathParts[1];
                     var albPath = pathParts[2];
 
-
-                    if (_library.TryGetValue(libName, out var l) && l.Albums.TryGetValue(albPath, out var alb))
+                    if (Libraries.TryGetValue(libName, out var l) && l.Albums.TryGetValue(albPath, out var alb))
                     {
                         var sb = new StringBuilder();
                         sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
@@ -332,23 +358,51 @@ namespace FNZCM.ConHost.Ver2
                         if (_isLoading) sb.Append("<h2 style=position:fixed;right:0px;top:0px;margin:0>Still Loading...</h2>");
 
                         sb.Append($"<h2>Tracks of</h2><h1>{alb.Name}</h1>");
-                        sb.Append($"<div><a href=/list/{libName}/>Back to library</a></div>");
+                        sb.Append($"<div><a href='/list/{libName.FuckVlcAndEscape()}/'>Back to library</a></div>");
 
-                        if (alb.SubTracks.Count > 0) sb.Append($"<div>Main</div>");
 
+                        var durTotal = 0;
+                        var sizeTotal = 0L;
+
+                        var sbm = new StringBuilder();
                         foreach (var kvpTrack in alb.MainTracks.OrderBy(p => p.Key))
                         {
-                            sb.Append($"<li><a href=\"/media/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/{kvpTrack.Key.FuckVlcAndEscape()}\" >{kvpTrack.Value}</a></li>");
+                            sbm.Append($"<li>");
+                            sbm.Append($"<a href=\"/media/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/{kvpTrack.Key.FuckVlcAndEscape()}\" >{kvpTrack.Value}</a>");
+
+                            var tag = GetTag($"/media/{libName}/{albPath}/{kvpTrack.Key}");
+                            durTotal += tag.Duration;
+                            sizeTotal += tag.Length;
+                            sbm.Append($" ({tag.Duration.FormatDuration()}) {tag.Length.FormatFileSize()}");
+
+                            sbm.Append($"</li>");
                         }
 
-                        foreach (var kvpAacSet in alb.SubTracks.OrderBy(p => p.Key))
+                        sb.Append($"<h2>Main ({durTotal.FormatDuration()}) {sizeTotal.FormatFileSize()}</h2>");
+                        sb.Append(sbm);
+
+                        foreach (var kvpSubSet in alb.SubTracks.OrderBy(p => p.Key))
                         {
-                            sb.Append($"<div>{kvpAacSet.Value.Name}</div>");
+                            durTotal = 0;
+                            sizeTotal = 0L;
 
-                            foreach (var kvpTrack in kvpAacSet.Value.Tracks.OrderBy(p => p.Key))
+                            sbm.Clear();
+                            foreach (var kvpTrack in kvpSubSet.Value.Tracks.OrderBy(p => p.Key))
                             {
-                                sb.Append($"<li><a href=\"/media/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/{kvpAacSet.Key.FuckVlcAndEscape()}/{kvpTrack.Key.FuckVlcAndEscape()}\" >{kvpTrack.Value}</a></li>");
+                                sbm.Append($"<li>");
+                                sbm.Append($"<a href=\"/media/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/{kvpSubSet.Key.FuckVlcAndEscape()}/{kvpTrack.Key.FuckVlcAndEscape()}\" >{kvpTrack.Value}</a>");
+
+                                var tag = GetTag($"/media/{libName}/{albPath}/{kvpSubSet.Key}/{kvpTrack.Key}");
+                                durTotal += tag.Duration;
+                                sizeTotal += tag.Length;
+                                sbm.Append($" ({tag.Duration.FormatDuration()}) {tag.Length.FormatFileSize()}");
+
+                                sbm.Append($"</li>");
                             }
+
+                            sb.Append($"<h2>{kvpSubSet.Value.Name} ({durTotal.FormatDuration()}) {sizeTotal.FormatFileSize()}</h2>");
+                            sb.Append(sbm);
+
                         }
 
                         context.Response.ContentType = "text/html";
@@ -366,7 +420,7 @@ namespace FNZCM.ConHost.Ver2
                     var libName = pathParts[1];
                     var albPath = pathParts[2];
 
-                    if (_library.TryGetValue(libName, out var lib) && lib.Albums.TryGetValue(albPath, out var alb))
+                    if (Libraries.TryGetValue(libName, out var lib) && lib.Albums.TryGetValue(albPath, out var alb))
                     {
                         var sb = new StringBuilder();
                         sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
@@ -375,7 +429,7 @@ namespace FNZCM.ConHost.Ver2
                         if (_isLoading) sb.Append("<h2 style=position:fixed;right:0px;top:0px;margin:0>Still Loading...</h2>");
 
                         sb.Append($"<h2>BK of </h2><h1>{alb.Name}</h1>");
-                        sb.Append($"<div><a href=/list/{libName}/>Back to library</a></div>");
+                        sb.Append($"<div><a href='/list/{libName.FuckVlcAndEscape()}/'>Back to library</a></div>");
 
                         foreach (var albBk in alb.Bks.OrderBy(p => p.Key))
                         {
@@ -395,12 +449,10 @@ namespace FNZCM.ConHost.Ver2
                 }
                 else if (pathParts.Count == 4 && pathParts[0] == "list" && pathParts[3] == "playlist.m3u8")
                 {
-                    //TODO: AAC M3U8
-
                     var libName = pathParts[1];
                     var albPath = pathParts[2];
 
-                    if (_library.TryGetValue(libName, out var lib) && lib.Albums.TryGetValue(albPath, out var alb))
+                    if (Libraries.TryGetValue(libName, out var lib) && lib.Albums.TryGetValue(albPath, out var alb))
                     {
                         // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
                         var prefix = $"{request.Url.GetLeftPart(UriPartial.Scheme | UriPartial.Authority)}";
@@ -410,13 +462,7 @@ namespace FNZCM.ConHost.Ver2
                         sb.AppendLine("#EXTM3U");
                         foreach (var track in alb.MainTracks.OrderBy(p => p.Key))
                         {
-                            var mediaInternalPath = $"/media/{libName}/{albPath}/{track.Key}";
-                            if (false == _mediaTags.TryGetValue(mediaInternalPath, out var mediaTag) && _pathMapping.TryGetValue(mediaInternalPath, out var mediaFilePath))
-                            {
-                                using var tagLib = TagLib.File.Create(mediaFilePath);
-                                mediaTag = _mediaTags[mediaInternalPath] = new MediaTag2($"{string.Join(";", tagLib.Tag.Performers)} - {tagLib.Tag.Title}", (int)tagLib.Properties.Duration.TotalSeconds);
-                            }
-
+                            var mediaTag = GetTag($"/media/{libName}/{albPath}/{track.Key}");
                             if (mediaTag != null)
                             {
                                 var coverPath = $"/cover/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/cover.jpg";
@@ -437,7 +483,51 @@ namespace FNZCM.ConHost.Ver2
                         //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
                     }
                 }
-                else if (_pathMapping.TryGetValue(requestPath, out var realPath))
+                else if (pathParts.Count == 5 && pathParts[0] == "list" && pathParts[4] == "playlist.m3u8")
+                {
+                    var libName = pathParts[1];
+                    var albPath = pathParts[2];
+                    var subSetPath = pathParts[3];
+
+                    if (Libraries.TryGetValue(libName, out var lib) && lib.Albums.TryGetValue(albPath, out var alb))
+                    {
+                        // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
+                        var prefix = $"{request.Url.GetLeftPart(UriPartial.Scheme | UriPartial.Authority)}";
+
+                        if (false == alb.SubTracks.TryGetValue(subSetPath, out var trackSet))
+                        {
+                            context.Response.StatusCode = 404;
+                        }
+                        else
+                        {
+                            var sb = new StringBuilder();
+
+                            sb.AppendLine("#EXTM3U");
+                            foreach (var track in trackSet.Tracks.OrderBy(p => p.Key))
+                            {
+                                var mediaTag = GetTag($"/media/{libName}/{albPath}/{subSetPath}/{track.Key}");
+                                if (mediaTag != null)
+                                {
+                                    var coverPath = $"/cover/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/cover.jpg";
+                                    sb.AppendLine($"#EXTINF:{mediaTag.Duration} tvg-logo=\"{prefix + coverPath}\",{mediaTag.Title}");
+                                }
+
+                                var mediaPath = $"/media/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/{subSetPath.FuckVlcAndEscape()}/{track.Key.FuckVlcAndEscape()}";
+                                sb.AppendLine(prefix + mediaPath);
+                            }
+
+                            context.Response.ContentType = "audio/mpegurl";
+                            context.Response.ContentEncoding = Encoding.UTF8;
+                            context.Response.WriteText(sb.ToString());
+                        }
+                    }
+                    else
+                    {
+                        context.Response.StatusCode = 404;
+                        //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
+                    }
+                }
+                else if (PathMapping.TryGetValue(requestPath, out var realPath))
                 {
                     var range = request.Headers.GetValues("Range");
 
@@ -507,6 +597,32 @@ namespace FNZCM.ConHost.Ver2
             }
         }
 
+        private static string FormatDuration(this int second)
+        {
+            var sbd = new StringBuilder();
+            var ts = TimeSpan.FromSeconds(second);
+            if (ts.TotalHours > 1) sbd.Append($"{ts.TotalHours:00}:");
+            sbd.Append($"{ts.Minutes:00}:{ts.Seconds:00}");
+            return sbd.ToString();
+        }
+
+        private static string FormatFileSize(this long length)
+        {
+            string[] sizes = { "B", "KB", "MB", "GB", "TB" };
+            double len = length;
+            int order = 0;
+            while (len >= 1024 && order < sizes.Length - 1)
+            {
+                order++;
+                len = len / 1024;
+            }
+
+            // Adjust the format string to your preferences. For example "{0:0.#}{1}" would
+            // show a single decimal place, and no space.
+            string result = String.Format("{0:0.##} {1}", len, sizes[order]);
+            return result;
+        }
+
         private static void WriteText(this HttpListenerResponse response, string content)
         {
             var bytes = Encoding.UTF8.GetBytes(content);
@@ -522,5 +638,21 @@ namespace FNZCM.ConHost.Ver2
                 .Replace("'", "%27")
                 ;
         }
+
+        private static MediaTag2 GetTag(string internalPath)
+        {
+            if (false == MediaTags.TryGetValue(internalPath, out var mediaTag) && PathMapping.TryGetValue(internalPath, out var mediaFilePath))
+            {
+                var fi = new FileInfo(mediaFilePath);
+                using var tagLib = TagLib.File.Create(mediaFilePath);
+                mediaTag = MediaTags[internalPath] = new MediaTag2(
+                    $"{string.Join(";", tagLib.Tag.Performers)} - {tagLib.Tag.Title}",
+                    (int)tagLib.Properties.Duration.TotalSeconds,
+                    fi.Length
+                );
+            }
+
+            return mediaTag;
+        }
     }
 }