using N_m3u8DL_RE.Parser.Config; using N_m3u8DL_RE.Common.Entity; using N_m3u8DL_RE.Common.Log; using N_m3u8DL_RE.Common.Resource; using N_m3u8DL_RE.Parser.Constants; using N_m3u8DL_RE.Parser.Extractor; using N_m3u8DL_RE.Common.Util; using N_m3u8DL_RE.Common.Enum; using Spectre.Console; namespace N_m3u8DL_RE.Parser { public class StreamExtractor { public ExtractorType ExtractorType { get => extractor.ExtractorType; } private IExtractor extractor; private ParserConfig parserConfig = new ParserConfig(); private string rawText; private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); public StreamExtractor() { } public StreamExtractor(ParserConfig parserConfig) { this.parserConfig = parserConfig; } public void LoadSourceFromUrl(string url) { Logger.Info(ResString.loadingUrl + url); if (url.StartsWith("file:")) { var uri = new Uri(url); this.rawText = File.ReadAllText(uri.LocalPath); parserConfig.OriginalUrl = parserConfig.Url = url; } else if (url.StartsWith("http")) { parserConfig.OriginalUrl = url; (this.rawText, url) = HTTPUtil.GetWebSourceAndNewUrlAsync(url, parserConfig.Headers).Result; parserConfig.Url = url; } else if (File.Exists(url)) { url = Path.GetFullPath(url); this.rawText = File.ReadAllText(url); parserConfig.OriginalUrl = parserConfig.Url = new Uri(url).AbsoluteUri; } this.rawText = rawText.Trim(); LoadSourceFromText(this.rawText); } public void LoadSourceFromText(string rawText) { rawText = rawText.Trim(); this.rawText = rawText; if (rawText.StartsWith(HLSTags.ext_m3u)) { Logger.InfoMarkUp(ResString.matchHLS); extractor = new HLSExtractor(parserConfig); } else if (rawText.Contains("</MPD>") && rawText.Contains("<MPD")) { Logger.InfoMarkUp(ResString.matchDASH); //extractor = new DASHExtractor(parserConfig); extractor = new DASHExtractor2(parserConfig); } else if (rawText == ResString.ReLiveTs) { Logger.InfoMarkUp(ResString.matchTS); extractor = new LiveTSExtractor(parserConfig); } else { throw new NotSupportedException(ResString.notSupported); } } /// <summary> /// 开始解析流媒体信息 /// </summary> /// <returns></returns> public async Task<List<StreamSpec>> ExtractStreamsAsync() { try { await semaphore.WaitAsync(); Logger.Info(ResString.parsingStream); return await extractor.ExtractStreamsAsync(rawText); } finally { semaphore.Release(); } } /// <summary> /// 根据规格说明填充媒体播放列表信息 /// </summary> /// <param name="streamSpecs"></param> public async Task FetchPlayListAsync(List<StreamSpec> streamSpecs) { try { await semaphore.WaitAsync(); Logger.Info(ResString.parsingStream); await extractor.FetchPlayListAsync(streamSpecs); } finally { semaphore.Release(); } } public async Task RefreshPlayListAsync(List<StreamSpec> streamSpecs) { try { await semaphore.WaitAsync(); int retryCount = 3; //增加重试 reGet: try { await extractor.RefreshPlayListAsync(streamSpecs); } catch (Exception ex) { if (retryCount-- > 0) { Logger.WarnMarkUp($"[grey]Refresh Exception: {ex.Message.EscapeMarkup()} retryCount: {retryCount}[/]"); await Task.Delay(300); goto reGet; } else throw; } } finally { semaphore.Release(); } } } }