|
@@ -1,4 +1,5 @@
|
|
-using System;
|
|
|
|
|
|
+using Microsoft.VisualBasic.FileIO;
|
|
|
|
+using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO;
|
|
@@ -7,7 +8,6 @@ using System.Net;
|
|
using System.Text;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
-using Microsoft.VisualBasic.FileIO;
|
|
|
|
using SearchOption = Microsoft.VisualBasic.FileIO.SearchOption;
|
|
using SearchOption = Microsoft.VisualBasic.FileIO.SearchOption;
|
|
|
|
|
|
namespace FNZCM.ConHost.Ver2
|
|
namespace FNZCM.ConHost.Ver2
|
|
@@ -28,12 +28,10 @@ namespace FNZCM.ConHost.Ver2
|
|
private static readonly ConcurrentDictionary<string, string> PathMapping = new();
|
|
private static readonly ConcurrentDictionary<string, string> PathMapping = new();
|
|
private static readonly ConcurrentDictionary<string, MediaTag2> MediaTags = new();
|
|
private static readonly ConcurrentDictionary<string, MediaTag2> MediaTags = new();
|
|
|
|
|
|
-
|
|
|
|
private static bool _isRunning;
|
|
private static bool _isRunning;
|
|
private static bool _isLoading;
|
|
private static bool _isLoading;
|
|
private static DateTime _lastRequestAccepted;
|
|
private static DateTime _lastRequestAccepted;
|
|
|
|
|
|
-
|
|
|
|
private static void Main()
|
|
private static void Main()
|
|
{
|
|
{
|
|
Console.WriteLine("Starting...");
|
|
Console.WriteLine("Starting...");
|
|
@@ -138,7 +136,6 @@ namespace FNZCM.ConHost.Ver2
|
|
Console.WriteLine("Looking tags...");
|
|
Console.WriteLine("Looking tags...");
|
|
Parallel.ForEach(PathMapping.Keys.Where(p => p.StartsWith("/media/")), k => GetTag(k));
|
|
Parallel.ForEach(PathMapping.Keys.Where(p => p.StartsWith("/media/")), k => GetTag(k));
|
|
Console.WriteLine("Looking tags...Done");
|
|
Console.WriteLine("Looking tags...Done");
|
|
-
|
|
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
catch (Exception e)
|
|
{
|
|
{
|
|
@@ -218,11 +215,10 @@ namespace FNZCM.ConHost.Ver2
|
|
// GET /list/foo/bar/aac_q1.00/playlist.m3u8 auto gen
|
|
// GET /list/foo/bar/aac_q1.00/playlist.m3u8 auto gen
|
|
|
|
|
|
// media streaming HTTP Partial RANGE SUPPORT
|
|
// media streaming HTTP Partial RANGE SUPPORT
|
|
- // GET /cover/foo/bar/cover.jpg
|
|
|
|
- // GET /media/foo/bar/01.%20foobar.flac
|
|
|
|
- // GET /bk/foo/bar/foobar.jpg
|
|
|
|
-
|
|
|
|
- // GET /media/foo/aac_q1.00/01.%20foobar.m4a
|
|
|
|
|
|
+ // GET /cover/foo/bar/cover.jpg image/<ext>
|
|
|
|
+ // GET /media/foo/bar/01.%20foobar.flac audio/<ext>
|
|
|
|
+ // GET /media/foo/bar/aac_q1.00/01.%20foobar.m4a audio/<ext>
|
|
|
|
+ // GET /bk/foo/bar/foobar.jpg image/<ext>
|
|
|
|
|
|
try
|
|
try
|
|
{
|
|
{
|
|
@@ -274,22 +270,27 @@ namespace FNZCM.ConHost.Ver2
|
|
"a:link{ text-decoration: none; }" +
|
|
"a:link{ text-decoration: none; }" +
|
|
"div.item{" +
|
|
"div.item{" +
|
|
" vertical-align:top;" +
|
|
" vertical-align:top;" +
|
|
- " height:20vh;" +
|
|
|
|
|
|
+ //" height:20vh;" +
|
|
|
|
+ //" overflow:scroll;" +
|
|
" margin-bottom:1vh;" +
|
|
" margin-bottom:1vh;" +
|
|
" padding:0.5vh;" +
|
|
" padding:0.5vh;" +
|
|
" border:solid 1px;" +
|
|
" border:solid 1px;" +
|
|
" border-radius:0.5vh;" +
|
|
" border-radius:0.5vh;" +
|
|
- " font-size:1.5vh;" +
|
|
|
|
- " overflow:scroll;" +
|
|
|
|
|
|
+ " font-size:2.2vh;" +
|
|
"}" +
|
|
"}" +
|
|
"div.item::-webkit-scrollbar{" +
|
|
"div.item::-webkit-scrollbar{" +
|
|
" display: none;" +
|
|
" display: none;" +
|
|
"}" +
|
|
"}" +
|
|
"img.cover{" +
|
|
"img.cover{" +
|
|
" float:left;" +
|
|
" float:left;" +
|
|
- " background-size:cover;" +
|
|
|
|
- " max-width:25vw;" +
|
|
|
|
- " max-height:20vh" +
|
|
|
|
|
|
+ " max-width:50vw;" +
|
|
|
|
+ " max-height:30vh" +
|
|
|
|
+ "}" +
|
|
|
|
+ "div.disc_name{" +
|
|
|
|
+ //" float:right;" +
|
|
|
|
+ "}" +
|
|
|
|
+ "div.links{" +
|
|
|
|
+ " clear:both;" +
|
|
"}" +
|
|
"}" +
|
|
"a.button{" +
|
|
"a.button{" +
|
|
" margin-left:4vw;" +
|
|
" margin-left:4vw;" +
|
|
@@ -307,29 +308,33 @@ namespace FNZCM.ConHost.Ver2
|
|
foreach (var a in l.Albums.OrderBy(p => p.Key))
|
|
foreach (var a in l.Albums.OrderBy(p => p.Key))
|
|
{
|
|
{
|
|
sb.Append("<div class=item>");
|
|
sb.Append("<div class=item>");
|
|
|
|
+
|
|
|
|
+ sb.Append($"<div>");
|
|
sb.Append($"<img class=cover src=\"/cover/{libName}/{a.Key}/cover.jpg\" />");
|
|
sb.Append($"<img class=cover src=\"/cover/{libName}/{a.Key}/cover.jpg\" />");
|
|
|
|
+ sb.Append($"<div class=disc_name>{a.Value.Name}</div>");
|
|
|
|
+ sb.Append($"</div>");
|
|
|
|
+
|
|
|
|
+ sb.Append("<div class=links>");
|
|
|
|
|
|
- sb.Append("<div style=text-align:right>");
|
|
|
|
|
|
+ sb.Append("<div>");
|
|
sb.Append($"<a class=button href=\"/list/{libName}/{a.Key}/tracks/\">[TRACKERS]</a>");
|
|
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>");
|
|
if (a.Value.Bks?.Count > 0) sb.Append($"<a class=button href=\"/list/{libName}/{a.Key}/bk/\">[BK]</a>");
|
|
sb.Append("</div>");
|
|
sb.Append("</div>");
|
|
|
|
|
|
- sb.Append("<div style=text-align:right>");
|
|
|
|
var totalDur = a.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{p.Key}", true)?.Duration ?? 0);
|
|
var totalDur = a.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{p.Key}", true)?.Duration ?? 0);
|
|
var totalLen = a.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{p.Key}", true)?.Length ?? 0);
|
|
var totalLen = a.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{p.Key}", true)?.Length ?? 0);
|
|
- sb.Append($"<a class=button href=\"/list/{libName}/{a.Key.FuckVlcAndEscape()}/playlist.m3u8\">[M3U8({totalDur.FormatDuration()}){totalLen.FormatFileSize()}]</a>");
|
|
|
|
|
|
+ sb.Append($"{totalDur.FormatDuration()} {totalLen.FormatFileSize()} <a href=\"/list/{libName}/{a.Key.FuckVlcAndEscape()}/playlist.m3u8\">M3U8_MAIN</a>");
|
|
if (a.Value.SubTracks.Count > 0)
|
|
if (a.Value.SubTracks.Count > 0)
|
|
{
|
|
{
|
|
foreach (var subTrack in a.Value.SubTracks)
|
|
foreach (var subTrack in a.Value.SubTracks)
|
|
{
|
|
{
|
|
totalDur = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{subTrack.Key}/{p.Key}", true)?.Duration ?? 0);
|
|
totalDur = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{subTrack.Key}/{p.Key}", true)?.Duration ?? 0);
|
|
totalLen = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{subTrack.Key}/{p.Key}", true)?.Length ?? 0);
|
|
totalLen = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{a.Key}/{subTrack.Key}/{p.Key}", true)?.Length ?? 0);
|
|
- sb.Append($"<br/><a class=button href=\"/list/{libName}/{a.Key.FuckVlcAndEscape()}/{subTrack.Key.FuckVlcAndEscape()}/playlist.m3u8\">[{subTrack.Value.Name}({totalDur.FormatDuration()}){totalLen.FormatFileSize()}]</a>");
|
|
|
|
|
|
+ sb.Append($"<br/>{totalDur.FormatDuration()} {totalLen.FormatFileSize()} <a href=\"/list/{libName}/{a.Key.FuckVlcAndEscape()}/{subTrack.Key.FuckVlcAndEscape()}/playlist.m3u8\">{subTrack.Value.Name}</a>");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sb.Append("</div>");
|
|
sb.Append("</div>");
|
|
|
|
|
|
- sb.Append($"<div>{a.Value.Name}</div>");
|
|
|
|
sb.Append("</div>");
|
|
sb.Append("</div>");
|
|
}
|
|
}
|
|
|
|
|
|
@@ -359,7 +364,6 @@ namespace FNZCM.ConHost.Ver2
|
|
sb.Append($"<h2>Tracks of</h2><h1>{alb.Name}</h1>");
|
|
sb.Append($"<h2>Tracks of</h2><h1>{alb.Name}</h1>");
|
|
sb.Append($"<div><a href='/list/{libName.FuckVlcAndEscape()}/'>Back to library</a></div>");
|
|
sb.Append($"<div><a href='/list/{libName.FuckVlcAndEscape()}/'>Back to library</a></div>");
|
|
|
|
|
|
-
|
|
|
|
var durTotal = 0;
|
|
var durTotal = 0;
|
|
var sizeTotal = 0L;
|
|
var sizeTotal = 0L;
|
|
|
|
|
|
@@ -401,7 +405,6 @@ namespace FNZCM.ConHost.Ver2
|
|
|
|
|
|
sb.Append($"<h2>{kvpSubSet.Value.Name} ({durTotal.FormatDuration()}) {sizeTotal.FormatFileSize()}</h2>");
|
|
sb.Append($"<h2>{kvpSubSet.Value.Name} ({durTotal.FormatDuration()}) {sizeTotal.FormatFileSize()}</h2>");
|
|
sb.Append(sbm);
|
|
sb.Append(sbm);
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
context.Response.ContentType = "text/html";
|
|
context.Response.ContentType = "text/html";
|
|
@@ -432,7 +435,7 @@ namespace FNZCM.ConHost.Ver2
|
|
|
|
|
|
foreach (var albBk in alb.Bks.OrderBy(p => p.Key))
|
|
foreach (var albBk in alb.Bks.OrderBy(p => p.Key))
|
|
{
|
|
{
|
|
- //TODO: auto gen thumbnail 512x512 jpg 80
|
|
|
|
|
|
+ //TODO: auto gen thumbnail 512x512 jpg 80
|
|
sb.Append($"<img src='/bk/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/{albBk.Key.FuckVlcAndEscape()}' style=max-width:24vw;max-height:24vw;margin-right:1vw;margin-bottom:1vh; />");
|
|
sb.Append($"<img src='/bk/{libName.FuckVlcAndEscape()}/{albPath.FuckVlcAndEscape()}/{albBk.Key.FuckVlcAndEscape()}' style=max-width:24vw;max-height:24vw;margin-right:1vw;margin-bottom:1vh; />");
|
|
}
|
|
}
|
|
|
|
|
|
@@ -528,6 +531,18 @@ namespace FNZCM.ConHost.Ver2
|
|
}
|
|
}
|
|
else if (PathMapping.TryGetValue(requestPath, out var realPath))
|
|
else if (PathMapping.TryGetValue(requestPath, out var realPath))
|
|
{
|
|
{
|
|
|
|
+ switch (pathParts.FirstOrDefault())
|
|
|
|
+ {
|
|
|
|
+ default: context.Response.ContentType = "video/mp4"; break;
|
|
|
|
+ case "media":
|
|
|
|
+ context.Response.ContentType = $"audio/{requestPath?.Split('.').LastOrDefault() ?? "flac"}";
|
|
|
|
+ break;
|
|
|
|
+ case "cover":
|
|
|
|
+ case "bk":
|
|
|
|
+ context.Response.ContentType = $"image/{requestPath?.Split('.').LastOrDefault() ?? "jpg"}";
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
var range = request.Headers.GetValues("Range");
|
|
var range = request.Headers.GetValues("Range");
|
|
|
|
|
|
FileStream fs = null;
|
|
FileStream fs = null;
|
|
@@ -545,13 +560,11 @@ namespace FNZCM.ConHost.Ver2
|
|
context.Response.Headers.Add("Accept-Ranges", "bytes");
|
|
context.Response.Headers.Add("Accept-Ranges", "bytes");
|
|
context.Response.Headers.Add("Content-Range", $"bytes {start}-{fs.Length - 1}/{fs.Length}");
|
|
context.Response.Headers.Add("Content-Range", $"bytes {start}-{fs.Length - 1}/{fs.Length}");
|
|
context.Response.ContentLength64 = fs.Length - start;
|
|
context.Response.ContentLength64 = fs.Length - start;
|
|
- context.Response.ContentType = "video/mp4";
|
|
|
|
fs.CopyTo(context.Response.OutputStream);
|
|
fs.CopyTo(context.Response.OutputStream);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- context.Response.ContentType = "video/mp4";
|
|
|
|
context.Response.ContentLength64 = fs.Length;
|
|
context.Response.ContentLength64 = fs.Length;
|
|
fs.CopyTo(context.Response.OutputStream);
|
|
fs.CopyTo(context.Response.OutputStream);
|
|
}
|
|
}
|
|
@@ -618,7 +631,7 @@ namespace FNZCM.ConHost.Ver2
|
|
|
|
|
|
// Adjust the format string to your preferences. For example "{0:0.#}{1}" would
|
|
// Adjust the format string to your preferences. For example "{0:0.#}{1}" would
|
|
// show a single decimal place, and no space.
|
|
// show a single decimal place, and no space.
|
|
- string result = String.Format("{0:0.##} {1}", len, sizes[order]);
|
|
|
|
|
|
+ string result = $"{len:000.00} {sizes[order]}";
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -664,8 +677,6 @@ namespace FNZCM.ConHost.Ver2
|
|
|
|
|
|
return mediaTag;
|
|
return mediaTag;
|
|
}
|
|
}
|
|
-
|
|
|
|
-
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|