1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279 |
- using FNZCM.Core;
- using FNZCM.Shared.Helpers;
- using FNZCM.Shared.MediaModels;
- using FNZCM.Shared.MetadataModels;
- using Microsoft.VisualBasic.FileIO;
- using Newtonsoft.Json;
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using SearchOption = Microsoft.VisualBasic.FileIO.SearchOption;
- namespace FNZCM.ConHost
- {
- internal static class HostProgram
- {
- //0. start http server
- //1. scan libraries and fill data struct
- // libs
- // disc
- // Tracks(FLAC / AAC_*)
- // Meta(title(artist) / duration)
- // FSI ( size )
- // TODO: Generate thumbnail of BKS
- private static readonly ConcurrentDictionary<string, Library> Libraries = new();
- private static readonly ConcurrentDictionary<string, string> PathMapping = new();
- private static readonly ConcurrentDictionary<string, LoadedModule> Modules = new();
- private static ConcurrentDictionary<string, MediaTag> MediaTags = new();
- private static string _fileSetJson;
- private static string _fileSetJsonChecksum;
- private static string _tagSetJson;
- private static string _tagSetJsonChecksum;
- private static DateTime _cacheTime;
- private static LoadedModule _defaultModule;
- private static bool _isRunning;
- private static bool _isLoading;
- private static int TotalTrackCount => PathMapping.Count(p => p.Key.StartsWith("/media/"));
- private static string LoadingText => $"Loading... {MediaTags.Count} / {TotalTrackCount}";
- private static DateTime _lastRequestAccepted;
- private static int _requestId = 0;
- private static void Main()
- {
- Console.WriteLine("Starting...");
- var tWorker = new Thread(Working);
- _isRunning = true;
- tWorker.Start();
- Task.Run(ReloadConfig);
- Console.WriteLine("Press ENTER to Stop.");
- Console.ReadLine();
- Console.WriteLine("Shutting down...");
- _isRunning = false;
- tWorker.Join();
- Console.WriteLine("Stopped.");
- Console.WriteLine();
- Console.Write("Press ENTER to Exit.");
- Console.ReadLine();
- }
- private static void ReloadConfig()
- {
- if (_isLoading)
- {
- Console.WriteLine("Still loading, SKIP");
- return;
- }
- _isLoading = true;
- try
- {
- ConfigFile.Reload();
- ReloadModulesInternal();
- 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 = Libraries[libPath] = new Library(kvpLib.Key);
- var discDirArray = Directory.GetDirectories(kvpLib.Value);
- foreach (var discDir in discDirArray)
- {
- if (_isRunning == false) throw new OperationCanceledException();
- Console.WriteLine($" Disc {discDir}");
- var discName = Path.GetFileName(discDir);
- var discPath = discName.ToLower();
- try
- {
- var disc = new Disc(discName);
- var bkDir = Path.Combine(discDir, "bk");
- var mainTrackFiles = FileSystem.GetFiles(discDir, SearchOption.SearchTopLevelOnly, ConfigFile.Instance.MediaFilePattern);
- foreach (var mainTrackFile in mainTrackFiles)
- {
- var trackName = Path.GetFileName(mainTrackFile);
- var trackPath = trackName.ToLower();
- disc.MainTracks[trackPath] = trackName;
- PathMapping[$"/media/{libPath}/{discPath}/{trackPath}"] = mainTrackFile;
- }
- if (Directory.Exists(bkDir))
- {
- var bkFiles = FileSystem.GetFiles(bkDir, SearchOption.SearchTopLevelOnly, ConfigFile.Instance.BkFilePattern);
- foreach (var file in bkFiles)
- {
- var bkName = Path.GetFileName(file);
- var bkPath = bkName.ToLower();
- disc.Bks[bkPath] = bkName;
- PathMapping[$"/bk/{libPath}/{discPath}/{bkPath}"] = file;
- }
- }
- var aacTrackDirArray = Directory.GetDirectories(discDir, "AAC_Q*");
- foreach (var aacTrackDir in aacTrackDirArray)
- {
- var aacTrackSetName = Path.GetFileName(aacTrackDir);
- var aacTrackSetPath = aacTrackSetName.ToLower();
- var aacTrackSet = disc.SubTracks[aacTrackSetPath] = new TrackSet(aacTrackSetName);
- foreach (var file in FileSystem.GetFiles(aacTrackDir, SearchOption.SearchTopLevelOnly, "*.m4a", "*.mp4"))
- {
- var aacTrackName = Path.GetFileName(file);
- var aacTrackPath = aacTrackName.ToLower();
- aacTrackSet.Tracks[aacTrackPath] = aacTrackName;
- PathMapping[$"/media/{libPath}/{discPath}/{aacTrackSetPath}/{aacTrackPath}"] = file;
- }
- }
- var coverFilePath = Path.Combine(discDir, "cover.jpg");
- if (File.Exists(coverFilePath)) PathMapping[$"/cover/{libPath}/{discPath}/cover.jpg"] = coverFilePath;
- lib.Discs[discPath] = disc;
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
- }
- }
- Console.WriteLine("Loading meta caches...");
- var cache = MetaCache.Load();
- if (cache != null) MediaTags = cache;
- Console.WriteLine("Looking tags...");
- foreach (var k in PathMapping.Keys.Where(p => p.StartsWith("/media/")))
- {
- GetTag(k);
- }
- Console.WriteLine("Saving meta caches...");
- MetaCache.Save(MediaTags);
- _fileSetJson = JsonConvert.SerializeObject(Libraries);
- _tagSetJson = JsonConvert.SerializeObject(MediaTags);
- _fileSetJsonChecksum = _fileSetJson.ToMd5();
- _tagSetJsonChecksum = _tagSetJson.ToMd5();
- _cacheTime = DateTime.Now;
- Console.WriteLine("Looking tags...Done");
- }
- catch (Exception e)
- {
- Console.WriteLine($"Load error: {e}");
- }
- _isLoading = false;
- }
- private static void ReloadModules()
- {
- ConfigFile.Reload();
- ReloadModulesInternal();
- }
- private static void ReloadModulesInternal()
- {
- Modules.Clear();
- _defaultModule = null;
- if (ConfigFile.Instance.Modules?.Any() == true)
- {
- foreach (var modEnt in ConfigFile.Instance.Modules)
- {
- Console.WriteLine($"Loading module `{modEnt.Value.DisplayText}'...");
- var module = new LoadedModule
- {
- VirtualPath = modEnt.Key,
- DisplayText = modEnt.Value.DisplayText,
- DefaultDocument = modEnt.Value.DefaultDocument,
- EnableFallbackRoute = modEnt.Value.EnableFallbackRoute,
- HtmlBaseReplace = modEnt.Value.HtmlBaseReplace,
- Files = new Dictionary<string, byte[]>()
- };
- if (Directory.Exists(modEnt.Value.Path))
- {
- //load by fs
- var files = Directory.GetFiles(modEnt.Value.Path, "*", System.IO.SearchOption.AllDirectories);
- foreach (var item in files)
- {
- var k = item.Substring(modEnt.Value.Path.Length + 1).Replace("\\", "/").ToLower();
- module.Files[k] = File.ReadAllBytes(item);
- }
- }
- else if (File.Exists(modEnt.Value.Path))
- {
- //load by package
- using var arc = SharpCompress.Archives.ArchiveFactory.Open(modEnt.Value.Path);
- foreach (var ent in arc.Entries.Where(p => p.IsDirectory == false))
- {
- var buf = new byte[ent.Size];
- using var s = ent.OpenEntryStream();
- var r = s.Read(buf, 0, buf.Length);
- module.Files[ent.Key.ToLower()] = buf;
- }
- }
- else
- {
- Console.WriteLine("WARN: resource not found");
- continue;
- }
- if (modEnt.Value.IsDefault && _defaultModule == null) _defaultModule = module;
- Modules[modEnt.Key] = module;
- Console.WriteLine($"Module `{modEnt.Value.DisplayText}' loaded.");
- }
- }
- }
- private static void Working()
- {
- var listener = new HttpListener();
- listener.Prefixes.Add(ConfigFile.Instance.ListenPrefix);
- if (ConfigFile.Instance.AliasPrefix?.Any() == true)
- foreach (var prefix in ConfigFile.Instance.AliasPrefix)
- listener.Prefixes.Add(prefix);
- listener.Start();
- var upTime = DateTime.Now;
- Console.WriteLine($"HTTP Server started, listening on {ConfigFile.Instance.ListenPrefix}");
- listener.BeginGetContext(ContextGet, listener);
- _lastRequestAccepted = DateTime.Now;
- while (_isRunning)
- {
- var timeSpan = DateTime.Now - _lastRequestAccepted;
- var up = DateTime.Now - upTime;
- Console.Title =
- "FNZCM"
- + $" UP {up.Days:00}D {up.Hours:00}H {up.Minutes:00}M {up.Seconds:00}S {up.Milliseconds:000}"
- + $" / "
- + $" LA {timeSpan.Days:00}D {timeSpan.Hours:00}H {timeSpan.Minutes:00}M {timeSpan.Seconds:00}S {timeSpan.Milliseconds:000}"
- ;
- Thread.Sleep(1000);
- }
- listener.Close();
- Thread.Sleep(1000);
- }
- private static void ContextGet(IAsyncResult ar)
- {
- var listener = (HttpListener)ar.AsyncState;
- HttpListenerContext context;
- try
- {
- // ReSharper disable once PossibleNullReferenceException
- context = listener.EndGetContext(ar);
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- return;
- }
- if (_isRunning) listener.BeginGetContext(ContextGet, listener);
- ProcessRequest(context);
- }
- private static void ProcessRequest(HttpListenerContext context)
- {
- _lastRequestAccepted = DateTime.Now;
- var num = Interlocked.Increment(ref _requestId);
- var request = context.Request;
- Console.WriteLine($"Request #{num:00000} from {request.RemoteEndPoint} {request.HttpMethod} {request.RawUrl}");
- try
- {
- var requestAbsPrefix = ConfigFile.Instance.M3uPrefix ?? $"{request.Url.Scheme + Uri.SchemeDelimiter + request.Url.Host + ":" + request.Url.Port}";
- if (request.Headers.AllKeys.Contains("Origin") && false == string.IsNullOrEmpty(request.Headers["Origin"]))
- {
- if (ConfigFile.Instance.AccessControlAllowOrigin?.Any(p => request.Headers["Origin"].StartsWith(p)) == true)
- context.Response.Headers["Access-Control-Allow-Origin"] = "*";
- }
- // GET / show all libraries
- // foo=library bar=disc
- // GET /list/foo/ show all disc and cover with name, provide m3u path
- // GET /list/foo/bar/bk/ list all picture as grid
- // GET /list/foo/bar/tracks/ list all tracks as text list
- // GET /lib_list/foo/playlist.m3u8 auto gen
- // GET /lib_list/foo/aac_q1.00/playlist.m3u8 auto gen
- // GET /list/foo/bar/playlist.m3u8 auto gen
- // GET /list/foo/bar/aac_q1.00/playlist.m3u8 auto gen
- // media streaming HTTP Partial RANGE SUPPORT
- // 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>
- // metadata catalog
- // GET /metadata/progress.json
- // GET /metadata/file-set.json
- // GET /metadata/tag-dict.json
- // loadable module
- // GET /module/<module-key>/<in-module-path>/
- // ReSharper disable once PossibleNullReferenceException
- var requestPath = request.Url.LocalPath.ToLower();
- var pathParts = (IReadOnlyList<string>)requestPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
- if (requestPath == "/admin/" && false == request.QueryString.AllKeys.Contains("action"))
- {
- var sb = new StringBuilder();
- sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
- sb.Append($"<title> Admin - {ConfigFile.Instance.Title} </title>");
- sb.Append("<body bgColor=skyBlue>");
- sb.Append($"<h3>Admin</h3>");
- sb.Append("<div><a href=/>Back to home</a></div>");
- sb.Append($"<form method=GET>");
- sb.Append($"Password: <input type=password name=pass />");
- sb.Append($"<br/>");
- sb.Append($"Operation: ");
- sb.Append($"<input type=submit name=action value=Reload /> ");
- sb.Append($"<input type=submit name=action value=ReloadFully /> ");
- sb.Append($"<input type=submit name=action value=ReloadModules /> ");
- sb.Append($"</form>");
- context.WriteTextUtf8(sb.ToString());
- }
- else if (requestPath == "/admin/" && request.QueryString["action"] == "Reload" && request.QueryString["pass"] == ConfigFile.Instance.AdminPassword)
- {
- Task.Run(ReloadConfig);
- context.Response.Redirect("/");
- }
- else if (requestPath == "/admin/" && request.QueryString["action"] == "ReloadModules" && request.QueryString["pass"] == ConfigFile.Instance.AdminPassword)
- {
- Task.Run(ReloadModules);
- context.Response.Redirect("/");
- }
- else if (requestPath == "/admin/" && request.QueryString["action"] == "ReloadFully" && request.QueryString["pass"] == ConfigFile.Instance.AdminPassword)
- {
- MetaCache.Clear();
- Task.Run(ReloadConfig);
- context.Response.Redirect("/");
- }
- else if (requestPath == "/admin/")
- {
- context.Response.Redirect("/");
- }
- else if (requestPath.StartsWith("/modules/") && pathParts.Count > 1)
- {
- var moduleKey = pathParts[1];
- if (Modules.TryGetValue(moduleKey, out var module))
- {
- var entPath = string.Join("/", pathParts.Skip(2));
- void Output(byte[] bin)
- {
- if (entPath.ToLower().EndsWith(".js")) context.Response.ContentType = "application/javascript";
- else if (entPath.ToLower().EndsWith(".wasm")) context.Response.ContentType = "application/wasm";
- else if (entPath.ToLower().EndsWith(".css")) context.Response.ContentType = "text/css";
- else if (module.HtmlBaseReplace != null && entPath.ToLower().EndsWith(".html"))
- {
- //base replace
- var html = Encoding.UTF8.GetString(bin);
- var r = html.Replace(module.HtmlBaseReplace, $"<base href=\"/modules/{moduleKey}/\" />");
- bin = Encoding.UTF8.GetBytes(r);
- }
- else context.Response.ContentType = "application/octet-stream";
- context.Response.ContentLength64 = bin.Length;
- context.Response.OutputStream.Write(bin, 0, bin.Length);
- }
- if (module.Files.TryGetValue(entPath, out var bin))
- {
- Output(bin);
- }
- else if (module.EnableFallbackRoute && module.Files.TryGetValue(module.DefaultDocument, out var defBin))
- {
- entPath = module.DefaultDocument;
- Output(defBin);
- }
- else context.Response.StatusCode = 404;
- }
- else context.Response.StatusCode = 404;
- }
- else if (requestPath == "/" && _defaultModule != null)
- {
- if (_defaultModule.EnableFallbackRoute) context.Response.Redirect($"/modules/{_defaultModule.VirtualPath}/");
- else context.Response.Redirect($"/modules/{_defaultModule.VirtualPath}/{_defaultModule.DefaultDocument}");
- }
- else if (requestPath == "/" || requestPath == "/classic-index")
- {
- var sb = new StringBuilder();
- sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
- sb.Append($"<title> Libraries - {ConfigFile.Instance.Title} </title>");
- sb.Append("<body bgColor=skyBlue style=font-size:3vh>");
- if (_isLoading) sb.Append($"<h4 style=position:fixed;right:0px;top:0px;margin:0>{LoadingText}</h4>");
- sb.Append($"<h2>{ConfigFile.Instance.Title}</h2>");
- if (Modules?.Any() == true)
- {
- sb.Append($"<h3>Modules</h3>");
- sb.Append($"<h4>(Total number of modules: {Modules.Count})</h4>");
- sb.Append("<ul>");
- foreach (var module in Modules)
- {
- sb.Append("<li>");
- sb.Append($"<a href='/modules/{module.Key.UrlEscape()}/{module.Value.DefaultDocument}'>{module.Value.DisplayText}</a>");
- sb.Append("</li>");
- }
- sb.Append("</ul>");
- }
- sb.Append($"<h3>Libraries</h3>");
- sb.Append($"<h4>(Total number of disc: {Libraries.Sum(p => p.Value.Discs.Count)})</h4>");
- sb.Append("<ul>");
- foreach (var library in Libraries.OrderBy(p => p.Key))
- {
- sb.Append("<li>");
- sb.Append($"<a href='/list/{library.Key.UrlEscape()}/'>{library.Value.Name}</a>");
- sb.Append($"<br/> Number of disc: {library.Value.Discs.Count}");
- sb.Append("</li>");
- }
- sb.Append("</ul>");
- sb.Append($"<hr/>");
- sb.Append($"<div>Your IP: {context?.Request?.RemoteEndPoint?.Address.ToString() ?? "Unknown"}</div>");
- sb.Append($"<div><a href=/admin/>Admin</a></div>");
- sb.Append($"<div>-</div>");
- sb.Append($"<div>Author: Coder (V)</div>");
- sb.Append($"<div>Blog: <a target=_blank href=https://topcl.net/myapps/private-colud-music.html>https://topcl.net/myapps/private-colud-music.html</a></div>");
- sb.Append($"<div>Source Repo: <a target=_blank href=https://topcl.net/gogs/coder/CloudMusic/>https://topcl.net/gogs/coder/CloudMusic/</a></div>");
- context.WriteTextUtf8(sb.ToString());
- }
- else if (pathParts.Count == 2 && pathParts[0] == "list")
- {
- var libName = pathParts[1];
- if (Libraries.TryGetValue(libName, out var lib))
- {
- var sb = new StringBuilder();
- sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
- sb.Append($"<title> Discs of {lib.Name} - {ConfigFile.Instance.Title} </title>");
- sb.Append(
- "<style>" +
- "a:link{ text-decoration: none; }" +
- "div.item{" +
- " vertical-align:top;" +
- " margin-bottom:1vh;" +
- " padding:0.5vh;" +
- " border:solid 1px;" +
- " border-radius:0.5vh;" +
- " font-size:2.2vh;" +
- "}" +
- "div.item::-webkit-scrollbar{" +
- " display: none;" +
- "}" +
- "img.cover{" +
- " float:left;" +
- " width:45vw;" +
- "}" +
- "div.disc_name{" +
- "}" +
- "div.links{" +
- " clear:both;" +
- "}" +
- "a.button{" +
- " margin-left:4vw;" +
- "}" +
- "</style>");
- sb.Append("<script>" +
- "function listPage(a){" +
- "window.open(a.href+'.html','CNZCM_LIST_PAGE',1);" +
- "return false;" +
- "}" +
- "</script>");
- sb.Append($"<body bgColor=skyBlue>");
- if (_isLoading) sb.Append($"<h4 style=position:fixed;right:0px;top:0px;margin:0>{LoadingText}</h4>");
- sb.Append($"<h1>Discs of {lib.Name}</h1>");
- sb.Append("<div><a href=/>Back to home</a></div>");
- if (!_isLoading)
- {
- sb.Append("<div style=margin-top:1vh;margin-bottom:1vh;>");
- //big m3u8
- var trackKeys = lib.Discs.SelectMany(p => p.Value.MainTracks.Keys.Select(q => new { DiscName = p.Key, TrackName = q })).ToArray();
- var totalDur = trackKeys.Sum(p => GetTag($"/media/{libName}/{p.DiscName}/{p.TrackName}", true)?.Duration);
- var totalLen = trackKeys.Sum(p => GetTag($"/media/{libName}/{p.DiscName}/{p.TrackName}", true)?.Length);
- sb.Append($"Number of track: {trackKeys.Length}");
- sb.Append($"<br/>{totalDur.SecondToDur()} {totalLen.BytesToFileSize()} <a onclick=\"return listPage(this)\" href=\"/lib_list/{libName}/playlist.m3u8\">ALL_M3U8_MAIN</a>");
- var subTrackSetNames = lib.Discs.SelectMany(p => p.Value.SubTracks.Keys).Distinct().ToArray();
- foreach (var setName in subTrackSetNames)
- {
- trackKeys = lib.Discs.SelectMany(p =>
- {
- if (p.Value.SubTracks.TryGetValue(setName, out var tSet))
- {
- return tSet.Tracks.Select(q => new { DiscName = p.Key, TrackName = q.Key });
- }
- return new string[0].Select(q => new { DiscName = p.Key, TrackName = q });
- }).ToArray();
- totalDur = trackKeys.Sum(p => GetTag($"/media/{libName}/{p.DiscName}/{setName}/{p.TrackName}", true)?.Duration);
- totalLen = trackKeys.Sum(p => GetTag($"/media/{libName}/{p.DiscName}/{setName}/{p.TrackName}", true)?.Length);
- sb.Append($"<br/>{totalDur.SecondToDur()} {totalLen.BytesToFileSize()} <a onclick=\"return listPage(this)\" href=\"/lib_list/{libName}/{setName}/playlist.m3u8\">ALL_M3U8_{setName.ToUpper()}</a>");
- }
- sb.Append("</div>");
- }
- //Cover list
- foreach (var disc in lib.Discs.OrderByDescending(p => p.Key))
- {
- sb.Append("<div class=item>");
- sb.Append($"<div>");
- sb.Append($"<img class=cover src=\"/cover/{libName}/{disc.Key.UrlEscape()}/cover.jpg\" />");
- sb.Append($"<div class=disc_name>{disc.Value.Name}</div>");
- sb.Append($"</div>");
- sb.Append("<div class=links>");
- sb.Append("<div>");
- sb.Append($"Number of track: {disc.Value.MainTracks.Count} <a href=\"/list/{libName}/{disc.Key.UrlEscape()}/tracks/\">[TRACKERS]</a>");
- if (disc.Value.Bks?.Count > 0) sb.Append($"<a class=button href=\"/list/{libName}/{disc.Key.UrlEscape()}/bk/\">[BK]</a>");
- sb.Append("</div>");
- var totalDur = disc.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{disc.Key}/{p.Key}", true)?.Duration);
- var totalLen = disc.Value.MainTracks.Sum(p => GetTag($"/media/{libName}/{disc.Key}/{p.Key}", true)?.Length);
- sb.Append($"{totalDur.SecondToDur()} {totalLen.BytesToFileSize()} <a onclick=\"return listPage(this)\" href=\"/list/{libName}/{disc.Key.UrlEscape()}/playlist.m3u8\">M3U8_MAIN</a>");
- if (disc.Value.SubTracks.Count > 0)
- {
- foreach (var subTrack in disc.Value.SubTracks)
- {
- totalDur = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{disc.Key}/{subTrack.Key}/{p.Key}", true)?.Duration);
- totalLen = subTrack.Value.Tracks.Sum(p => GetTag($"/media/{libName}/{disc.Key}/{subTrack.Key}/{p.Key}", true)?.Length);
- sb.Append($"<br/>{totalDur.SecondToDur()} {totalLen.BytesToFileSize()} <a onclick=\"return listPage(this)\" href=\"/list/{libName}/{disc.Key.UrlEscape()}/{subTrack.Key.UrlEscape()}/playlist.m3u8\">{subTrack.Value.Name}</a>");
- }
- }
- sb.Append("</div>");
- sb.Append("</div>");
- }
- context.WriteTextUtf8(sb.ToString());
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 4 && pathParts[0] == "list" && pathParts[3] == "tracks")
- {
- var libName = pathParts[1];
- var discPath = pathParts[2];
- if (Libraries.TryGetValue(libName, out var l) && l.Discs.TryGetValue(discPath, out var disc))
- {
- var sb = new StringBuilder();
- sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
- sb.Append($"<body bgColor=skyBlue style=font-size:2vh>");
- if (_isLoading) sb.Append($"<h4 style=position:fixed;right:0px;top:0px;margin:0>{LoadingText}</h4>");
- sb.Append($"<h2>Tracks of</h2><h1>{disc.Name}</h1>");
- sb.Append($"<div><a href='/list/{libName.UrlEscape()}/'>Back to library</a></div>");
- sb.Append($"<img style=float:left;max-width:50vw src=\"/cover/{libName}/{discPath}/cover.jpg\" />");
- var durTotal = 0;
- var sizeTotal = 0L;
- var sbm = new StringBuilder();
- foreach (var kvpTrack in disc.MainTracks.OrderBy(p => p.Key))
- {
- sbm.Append($"<li>");
- sbm.Append($"<a href=\"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{kvpTrack.Key.UrlEscape()}\" >{kvpTrack.Value}</a>");
- var tag = GetTag($"/media/{libName}/{discPath}/{kvpTrack.Key}");
- durTotal += tag.Duration;
- sizeTotal += tag.Length;
- sbm.Append($"<br> {tag.Duration.SecondToDur()} {tag.Length.BytesToFileSize()}");
- sbm.Append($"</li>");
- }
- sb.Append($"<h2>Main ({durTotal.SecondToDur()}) {sizeTotal.BytesToFileSize()}</h2>");
- sb.Append(sbm);
- foreach (var kvpSubSet in disc.SubTracks.OrderBy(p => p.Key))
- {
- durTotal = 0;
- sizeTotal = 0L;
- sbm.Clear();
- foreach (var kvpTrack in kvpSubSet.Value.Tracks.OrderBy(p => p.Key))
- {
- sbm.Append($"<li>");
- sbm.Append($"<a href=\"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{kvpSubSet.Key.UrlEscape()}/{kvpTrack.Key.UrlEscape()}\" >{kvpTrack.Value}</a>");
- var tag = GetTag($"/media/{libName}/{discPath}/{kvpSubSet.Key}/{kvpTrack.Key}");
- durTotal += tag.Duration;
- sizeTotal += tag.Length;
- sbm.Append($"<br/> {tag.Duration.SecondToDur()} {tag.Length.BytesToFileSize()}");
- sbm.Append($"</li>");
- }
- sb.Append($"<h2>{kvpSubSet.Value.Name} ({durTotal.SecondToDur()}) {sizeTotal.BytesToFileSize()}</h2>");
- sb.Append(sbm);
- }
- context.WriteTextUtf8(sb.ToString());
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 4 && pathParts[0] == "list" && pathParts[3] == "bk")
- {
- var libName = pathParts[1];
- var discPath = pathParts[2];
- if (Libraries.TryGetValue(libName, out var lib) && lib.Discs.TryGetValue(discPath, out var disc))
- {
- var sb = new StringBuilder();
- sb.Append("<!DOCTYPE html><html lang=\"zh-cn\"><meta charset=\"UTF-8\">");
- sb.Append($"<body bgColor=skyBlue style=font-size:2vh>");
- if (_isLoading) sb.Append($"<h4 style=position:fixed;right:0px;top:0px;margin:0>{LoadingText}</h4>");
- sb.Append($"<h2>BK of </h2><h1>{disc.Name}</h1>");
- sb.Append($"<div><a href='/list/{libName.UrlEscape()}/'>Back to library</a></div>");
- foreach (var discBk in disc.Bks.OrderBy(p => p.Key))
- {
- sb.Append($"<img src='/bk/{libName.UrlEscape()}/{discPath.UrlEscape()}/{discBk.Key.UrlEscape()}' style=max-width:24vw;max-height:24vw;margin-right:1vw;margin-bottom:1vh; />");
- }
- context.WriteTextUtf8(sb.ToString());
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 3 && pathParts[0] == "lib_list" && pathParts[2] == "playlist.m3u8.html")
- {
- var libName = pathParts[1];
- if (Libraries.TryGetValue(libName, out var lib))
- {
- var sb = new StringBuilder();
- //var prefix = $"{request.Url.GetLeftPart(UriPartial.Scheme | UriPartial.Authority)}";
- foreach (var discKvp in lib.Discs.OrderByDescending(p => p.Key))
- {
- var disc = discKvp.Value;
- var discPath = discKvp.Key;
- var tracks = disc.MainTracks;
- foreach (var track in tracks.OrderBy(p => p.Key))
- {
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{track.Key}");
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{track.Key.UrlEscape()}";
- //<li><span class="simp-source" data-src="http://">Title</span><span class="simp-desc">Artist</span></li>
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"<li>" +
- $"<span class=\"simp-source\" data-src=\"{mediaPath}\">{mediaTag.Title}</span>" +
- $"<span class=\"simp-desc\">{mediaTag.Artist}</span>" +
- $"<span style=\"float:right\">{mediaTag.Duration.SecondToDur()}</span>" +
- $"</li>");
- }
- else
- {
- sb.AppendLine($"<li><span class=\"simp-source\" data-src=\"{mediaPath}\">{track.Value}</span></li>");
- }
- }
- }
- var sbPage = new StringBuilder(Resource.listPage);
- sbPage.Replace("<!-- list place here -->", sb.ToString());
- context.WriteTextUtf8(sbPage.ToString());
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 3 && pathParts[0] == "lib_list" && pathParts[2] == "playlist.m3u8")
- {
- var libName = pathParts[1];
- if (Libraries.TryGetValue(libName, out var lib))
- {
- var sb = new StringBuilder();
- sb.WriteM3U8Header();
- foreach (var discKvp in lib.Discs.OrderByDescending(p => p.Key))
- {
- var disc = discKvp.Value;
- var discPath = discKvp.Key;
- var tracks = disc.MainTracks;
- foreach (var track in tracks.OrderBy(p => p.Key))
- {
- var coverPath = $"/cover/{libName.UrlEscape()}/{discPath.UrlEscape()}/cover.jpg";
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{track.Key}");
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"#EXTINF:{mediaTag.Duration} tvg-logo=\"{requestAbsPrefix + coverPath}\",{mediaTag.Artist} - {mediaTag.Title}");
- }
- else
- {
- sb.AppendLine($"#EXTINF:0 logo=\"{requestAbsPrefix + coverPath}\",{Path.GetFileNameWithoutExtension(track.Key)}");
- }
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{track.Key.UrlEscape()}";
- sb.AppendLine(requestAbsPrefix + mediaPath);
- }
- }
- context.WriteTextUtf8(sb.ToString(), Const.ContentTypeM3U);
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 4 && pathParts[0] == "lib_list" && pathParts[3] == "playlist.m3u8.html")
- {
- var libName = pathParts[1];
- var trackSetName = pathParts[2];
- if (Libraries.TryGetValue(libName, out var lib))
- {
- var sb = new StringBuilder();
- foreach (var discKvp in lib.Discs.OrderByDescending(p => p.Key))
- {
- var disc = discKvp.Value;
- var discPath = discKvp.Key;
- if (disc.SubTracks.TryGetValue(trackSetName, out var tracksSet))
- {
- var tracks = tracksSet.Tracks;
- foreach (var track in tracks.OrderBy(p => p.Key))
- {
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{trackSetName}/{track.Key}");
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{trackSetName.UrlEscape()}/{track.Key.UrlEscape()}";
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"<li>" +
- $"<span class=\"simp-source\" data-src=\"{mediaPath}\">{mediaTag.Title}</span>" +
- $"<span class=\"simp-desc\">{mediaTag.Artist}</span>" +
- $"<span style=\"float:right\">{mediaTag.Duration.SecondToDur()}</span>" +
- $"</li>");
- }
- else
- {
- sb.AppendLine($"<li><span class=\"simp-source\" data-src=\"{mediaPath}\">{track.Value}</span></li>");
- }
- }
- }
- }
- var sbPage = new StringBuilder(Resource.listPage);
- sbPage.Replace("<!-- list place here -->", sb.ToString());
- context.WriteTextUtf8(sbPage.ToString());
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 4 && pathParts[0] == "lib_list" && pathParts[3] == "playlist.m3u8")
- {
- var libName = pathParts[1];
- var trackSetName = pathParts[2];
- if (Libraries.TryGetValue(libName, out var lib))
- {
- var sb = new StringBuilder();
- sb.WriteM3U8Header();
- foreach (var discKvp in lib.Discs.OrderByDescending(p => p.Key))
- {
- var disc = discKvp.Value;
- var discPath = discKvp.Key;
- if (disc.SubTracks.TryGetValue(trackSetName, out var tracksSet))
- {
- var tracks = tracksSet.Tracks;
- foreach (var track in tracks.OrderBy(p => p.Key))
- {
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{trackSetName}/{track.Key}");
- var coverPath = $"/cover/{libName.UrlEscape()}/{discPath.UrlEscape()}/cover.jpg";
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{trackSetName.UrlEscape()}/{track.Key.UrlEscape()}";
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"#EXTINF:{mediaTag.Duration} logo=\"{requestAbsPrefix + coverPath}\",{mediaTag.Artist} - {mediaTag.Title}");
- }
- else
- {
- sb.AppendLine($"#EXTINF:0 logo=\"{requestAbsPrefix + coverPath}\",{Path.GetFileNameWithoutExtension(track.Key)}");
- }
- sb.AppendLine(requestAbsPrefix + mediaPath);
- }
- }
- }
- context.WriteTextUtf8(sb.ToString(), Const.ContentTypeM3U);
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 4 && pathParts[0] == "list" && pathParts[3] == "playlist.m3u8.html")
- {
- var libName = pathParts[1];
- var discPath = pathParts[2];
- if (Libraries.TryGetValue(libName, out var lib) && lib.Discs.TryGetValue(discPath, out var disc))
- {
- var sb = new StringBuilder();
- foreach (var track in disc.MainTracks.OrderBy(p => p.Key))
- {
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{track.Key}");
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{track.Key.UrlEscape()}";
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"<li>" +
- $"<span class=\"simp-source\" data-src=\"{mediaPath}\">{mediaTag.Title}</span>" +
- $"<span class=\"simp-desc\">{mediaTag.Artist}</span>" +
- $"<span style=\"float:right\">{mediaTag.Duration.SecondToDur()}</span>" +
- $"</li>");
- }
- else
- {
- sb.AppendLine($"<li><span class=\"simp-source\" data-src=\"{mediaPath}\">{track.Value}</span></li>");
- }
- }
- var sbPage = new StringBuilder(Resource.listPage);
- sbPage.Replace("<!-- list place here -->", sb.ToString());
- context.WriteTextUtf8(sbPage.ToString());
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 4 && pathParts[0] == "list" && pathParts[3] == "playlist.m3u8")
- {
- var libName = pathParts[1];
- var discPath = pathParts[2];
- if (Libraries.TryGetValue(libName, out var lib) && lib.Discs.TryGetValue(discPath, out var disc))
- {
- var sb = new StringBuilder();
- sb.WriteM3U8Header();
- sb.AppendLine($"#EXTALB: {discPath}");
- var coverPath = $"/cover/{libName.UrlEscape()}/{discPath.UrlEscape()}/cover.jpg";
- foreach (var track in disc.MainTracks.OrderBy(p => p.Key))
- {
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{track.Key}");
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"#EXTINF:{mediaTag.Duration} logo=\"{requestAbsPrefix + coverPath}\",{mediaTag.Artist} - {mediaTag.Title}");
- }
- else
- {
- sb.AppendLine($"#EXTINF:0 logo=\"{requestAbsPrefix + coverPath}\",{Path.GetFileNameWithoutExtension(track.Key)}");
- }
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{track.Key.UrlEscape()}";
- sb.AppendLine(requestAbsPrefix + mediaPath);
- }
- context.WriteTextUtf8(sb.ToString(), Const.ContentTypeM3U);
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 5 && pathParts[0] == "list" && pathParts[4] == "playlist.m3u8.html")
- {
- var libName = pathParts[1];
- var discPath = pathParts[2];
- var subSetPath = pathParts[3];
- if (Libraries.TryGetValue(libName, out var lib) && lib.Discs.TryGetValue(discPath, out var disc))
- {
- if (false == disc.SubTracks.TryGetValue(subSetPath, out var trackSet))
- {
- context.Response.StatusCode = 404;
- }
- else
- {
- var sb = new StringBuilder();
- foreach (var track in trackSet.Tracks.OrderBy(p => p.Key))
- {
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{subSetPath}/{track.Key}");
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{subSetPath.UrlEscape()}/{track.Key.UrlEscape()}";
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"<li>" +
- $"<span class=\"simp-source\" data-src=\"{mediaPath}\">{mediaTag.Title}</span>" +
- $"<span class=\"simp-desc\">{mediaTag.Artist}</span>" +
- $"<span style=\"float:right\">{mediaTag.Duration.SecondToDur()}</span>" +
- $"</li>");
- }
- else
- {
- sb.AppendLine($"<li><span class=\"simp-source\" data-src=\"{mediaPath}\">{track.Value}</span></li>");
- }
- }
- var sbPage = new StringBuilder(Resource.listPage);
- sbPage.Replace("<!-- list place here -->", sb.ToString());
- context.WriteTextUtf8(sbPage.ToString());
- }
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (pathParts.Count == 5 && pathParts[0] == "list" && pathParts[4] == "playlist.m3u8")
- {
- var libName = pathParts[1];
- var discPath = pathParts[2];
- var subSetPath = pathParts[3];
- if (Libraries.TryGetValue(libName, out var lib) && lib.Discs.TryGetValue(discPath, out var disc))
- {
- if (false == disc.SubTracks.TryGetValue(subSetPath, out var trackSet))
- {
- context.Response.StatusCode = 404;
- }
- else
- {
- var sb = new StringBuilder();
- sb.WriteM3U8Header();
- foreach (var track in trackSet.Tracks.OrderBy(p => p.Key))
- {
- var mediaTag = GetTag($"/media/{libName}/{discPath}/{subSetPath}/{track.Key}");
- var coverPath = $"/cover/{libName.UrlEscape()}/{discPath.UrlEscape()}/cover.jpg";
- if (mediaTag != null && false == string.IsNullOrWhiteSpace(mediaTag.Title))
- {
- sb.AppendLine($"#EXTINF:{mediaTag.Duration} logo=\"{requestAbsPrefix + coverPath}\",{mediaTag.Artist} - {mediaTag.Title}");
- }
- else
- {
- sb.AppendLine($"#EXTINF:0 logo=\"{requestAbsPrefix + coverPath}\",{Path.GetFileNameWithoutExtension(track.Key)}");
- }
- var mediaPath = $"/media/{libName.UrlEscape()}/{discPath.UrlEscape()}/{subSetPath.UrlEscape()}/{track.Key.UrlEscape()}";
- sb.AppendLine(requestAbsPrefix + mediaPath);
- }
- context.WriteTextUtf8(sb.ToString(), Const.ContentTypeM3U);
- }
- }
- else
- {
- context.Response.StatusCode = 404;
- //context.Response.Redirect("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- }
- }
- else if (requestPath == "/metadata/progress.json")
- {
- var dic = new Dictionary<string, object>()
- {
- {"IsLoading",_isLoading},
- {nameof(TotalTrackCount),TotalTrackCount},
- {nameof(MediaTags),MediaTags.Count},
- };
- context.WriteTextUtf8(JsonConvert.SerializeObject(new LoadingProgress
- {
- IsLoading = _isLoading,
- TotalTrackCount = TotalTrackCount,
- LoadedTags = MediaTags.Count
- }), Const.ApplicationJson);
- }
- else if (requestPath == "/metadata/file-set.json/checksum") context.WriteTextUtf8(_fileSetJsonChecksum);
- else if (requestPath == "/metadata/file-set.json")
- {
- if (_fileSetJsonChecksum != null && request.Headers["If-None-Match"] == _fileSetJsonChecksum)
- {
- context.Response.StatusCode = 304;
- context.Response.AddHeader("x-custom", "cache applied 304");
- }
- else
- {
- context.Response.AddHeader("Last-Modified", _cacheTime.ToString("R"));
- context.Response.AddHeader("Cache-Control", "public");
- context.Response.AddHeader("ETAG", _fileSetJsonChecksum);
- context.WriteTextUtf8(_fileSetJson ?? "null", Const.ApplicationJson);
- }
- }
- else if (requestPath == "/metadata/tag-dict.json/checksum") context.WriteTextUtf8(_tagSetJsonChecksum);
- else if (requestPath == "/metadata/tag-dict.json")
- {
- if (_tagSetJsonChecksum != null && request.Headers["If-None-Match"] == _tagSetJsonChecksum)
- {
- context.Response.StatusCode = 304;
- context.Response.AddHeader("x-custom", "cache applied 304");
- }
- else
- {
- context.Response.AddHeader("Last-Modified", _cacheTime.ToString("R"));
- context.Response.AddHeader("Cache-Control", "public");
- context.Response.AddHeader("ETAG", _tagSetJsonChecksum);
- context.WriteTextUtf8(_tagSetJson ?? "null", Const.ApplicationJson);
- }
- }
- else if (PathMapping.TryGetValue(requestPath, out var realPath))
- {
- var ext = requestPath.Split('.').LastOrDefault()?.ToLower();
- switch (ext)
- {
- case "flac": context.Response.ContentType = "audio/flac"; break;
- case "m4a": context.Response.ContentType = "audio/mp4"; break;
- case "mp3": context.Response.ContentType = "audio/mpeg"; break;
- case "aac": context.Response.ContentType = "audio/aac"; break;
- case "mp4": context.Response.ContentType = "video/mp4"; break;
- case "mkv": context.Response.ContentType = "video/webm"; break;
- case "jpg":
- case "jpeg": context.Response.ContentType = "image/jpeg"; break;
- case "png": context.Response.ContentType = "image/png"; break;
- case "bmp": context.Response.ContentType = "image/bmp"; break;
- default:
- var firstParts = requestPath.Split('/').FirstOrDefault();
- switch (firstParts)
- {
- case "media": context.Response.ContentType = "audio/" + ext; break;
- case "bk":
- case "cover": context.Response.ContentType = "image/" + ext; break;
- }
- break;
- }
- var range = request.Headers.GetValues("Range");
- FileStream fs = null;
- try
- {
- fs = File.OpenRead(realPath);
- context.Response.Headers.Add("Accept-Ranges", "bytes");
- if (range is { Length: > 0 })
- {
- var rngParts = range[0].Split(new[] { "bytes=", "-" }, StringSplitOptions.RemoveEmptyEntries);
- if (rngParts.Length == 1 && long.TryParse(rngParts[0], out var start))
- {
- fs.Position = start;
- context.Response.StatusCode = 206;
- context.Response.Headers.Add("Content-Range", $"bytes {start}-{fs.Length - 1}/{fs.Length}");
- context.Response.ContentLength64 = fs.Length - start;
- fs.CopyTo(context.Response.OutputStream);
- }
- else if (rngParts.Length == 2 && long.TryParse(rngParts[0], out var start2) && long.TryParse(rngParts[1], out var end))
- {
- fs.Position = start2;
- var realLen = end - start2 + 1;
- context.Response.StatusCode = 206;
- context.Response.Headers.Add("Content-Range", $"bytes {start2}-{end}/{fs.Length}");
- context.Response.ContentLength64 = realLen;
- if (realLen < 4096)
- {
- var buf = new byte[realLen];
- fs.Read(buf, 0, buf.Length);
- context.Response.OutputStream.Write(buf, 0, buf.Length);
- }
- else
- {
- fs.CopyTo(context.Response.OutputStream);
- }
- }
- }
- else
- {
- context.Response.ContentLength64 = fs.Length;
- fs.CopyTo(context.Response.OutputStream);
- }
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- }
- finally
- {
- fs?.Close();
- }
- }
- else
- {
- context.Response.StatusCode = 404;
- }
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- try
- {
- context.Response.StatusCode = 500;
- }
- catch (Exception exception)
- {
- Console.WriteLine(exception);
- }
- }
- finally
- {
- try
- {
- context.Response.Close();
- }
- catch (Exception e)
- {
- Console.WriteLine(e);
- }
- }
- Console.WriteLine($"Request #{num:00000} ends with status code: {context.Response.StatusCode}");
- }
- private static MediaTag GetTag(string internalPath, bool peekMem = false)
- {
- if (peekMem)
- {
- return MediaTags.TryGetValue(internalPath, out var peek) ? peek : null;
- }
- if (MediaTags.TryGetValue(internalPath, out var mediaTag) || !PathMapping.TryGetValue(internalPath, out var mediaFilePath)) return mediaTag;
- try
- {
- var fi = new FileInfo(mediaFilePath);
- using var tagLib = TagLib.File.Create(mediaFilePath, TagLib.ReadStyle.Average);
- mediaTag = MediaTags[internalPath] = new MediaTag(
- tagLib.Tag.Album,
- (int)tagLib.Tag.Disc,
- (int)tagLib.Tag.Track,
- tagLib.Tag.Title,
- string.Join(";", tagLib.Tag.Performers ?? new string[0]),
- tagLib.Properties?.BitsPerSample ?? 0,
- tagLib.Properties?.AudioSampleRate ?? 0,
- (int)(tagLib.Properties?.Duration.TotalSeconds ?? 0),
- fi.Length,
- tagLib.Properties?.AudioBitrate ?? 0
- );
- }
- catch (Exception e)
- {
- Console.WriteLine($"ERROR on get tags: {mediaFilePath}{Environment.NewLine} {e.Message}");
- return null;
- }
- return mediaTag;
- }
- }
- }
|