public DownloadListenerContext(ComicDownloadRequest request, ComicChapter chapter, ComicPage page, CancellationToken token) { Request = request; Chapter = chapter; Page = page; Token = token; }
protected override async Task <ComicPage[]> GetPagesAsync(ComicChapter chapter) { ComicPage[] res = null; if (UseStore) { res = await GetAsAsync <ComicPage[]>(chapter.TargetUrl); } if (res is null) { var remoteFetch = AppEngine.GetService <RemoteEngine>(); if (remoteFetch != null && EnableRemote) { res = await RemoteFetchPagesAsync(remoteFetch, chapter.TargetUrl); if (res is null) { res = await base.GetPagesAsync(chapter); } } else { res = await base.GetPagesAsync(chapter); } } return(res); }
public DownloadExceptionListenerContext(ComicDownloadRequest request, ComicChapter chapter, ComicPage page, CancellationToken token, Exception exception) : base(request, chapter, page, token) { Exception = exception; }
protected override async Task <ComicPage[]> GetPagesAsync(ComicChapter chapter) { if (Entity is null) { return(null); } var entity = await rootFetcher.FetchChapterAsync(Entity.ComicUrl, chapter.TargetUrl); return(entity?.Pages); }
public async Task <IActionResult> Content(Guid chapterId) { if (await _chapterManager.GetById(chapterId) is var chapter && chapter == null) { return(NotFound()); } if (await _titlesManager.GetById(chapter.TitleId) is var title && title == null) { return(NotFound()); } if (!title.Visible || !chapter.Visible) { return(NotFound()); } object result = chapter switch { ComicChapter comicChapter => new { chapter.Id, chapter.Volume, chapter.Number, chapter.Name, chapter.ReleaseDate, chapter.TitleId, Pages = (await _pagesManager.GetAll(comicChapter)).Select(page => (ComicPage)page).OrderBy(page => page.Number).Select(page => new { page.Id, page.Number, pageUrl = $"/content/{comicChapter.TitleId}/{comicChapter.Id}/{page.Id}{(page.Animated ? ".gif" : ".png")}" }).ToArray() }, NovelChapter novelChapter => new { chapter.Id, chapter.Volume, chapter.Number, chapter.Name, chapter.ReleaseDate, chapter.TitleId, novelChapter.Content, Pages = (await _pagesManager.GetAll(novelChapter)).Select(page => new { page.Id, pageUrl = $"/content/{novelChapter.TitleId}/{novelChapter.Id}/{page.Id}{(page.Animated ? ".gif" : ".png")}" }).ToArray() }, _ => throw new ArgumentException($"{chapter.GetType().Name} is not a supported type.") }; return(Json(result)); }
public ComicDownloadContext(ComicEntity entity, ComicChapter chapter, ComicPage page, Stream sourceStream, CancellationToken token) { Token = token; Entity = entity; Chapter = chapter; Page = page; SourceStream = sourceStream; }
public void GivenValueInit_PropertyValueMustEqualGiven() { var chapter = new ComicChapter(); var page = new ComicPage(); var req = new DownloadItemRequest(chapter, page); Assert.AreEqual(chapter, req.Chapter); Assert.AreEqual(page, req.Page); req = new DownloadItemRequest(page); Assert.IsNull(req.Chapter); Assert.AreEqual(page, req.Page); }
public async Task <ComicEntity> GetChaptersAsync(string targetUrl) { var str = string.Empty; using (var sr = new StreamReader(await GetStreamAsync(targetUrl))) { str = sr.ReadToEnd(); } var html = new HtmlDocument(); html.LoadHtml(str); var block = html.DocumentNode.SelectNodes("//ul[@id='detail-list-select-1']/li/a"); var hideBlock = html.DocumentNode.SelectNodes("//ul[@id='detail-list-select-1']/ul[@class='chapteritem']/li/a"); var titleBlock = html.DocumentNode.SelectSingleNode("//div[@class='banner_detail_form']/div[@class='info']/p[@class='title']")?.ChildNodes[0].InnerText; if (titleBlock == null) { titleBlock = targetUrl.Split(targetUrlSplit, StringSplitOptions.RemoveEmptyEntries) .Last(); } var descBlock = html.DocumentNode.SelectSingleNode("//div[@class='banner_detail_form']/div[@class='info']/p[@class='content']"); var imgBlock = html.DocumentNode.SelectSingleNode("//div[@class='banner_detail_form']/div[@class='cover']/img"); var caps = new List <ComicChapter>(); IEnumerable <HtmlNode> blocks = block; if (hideBlock != null) { blocks = blocks.Concat(hideBlock); } foreach (var item in blocks) { var url = item.Attributes["href"]; var text = item.ChildNodes[0].InnerText; var cap = new ComicChapter { TargetUrl = GetBaseAddress() + url?.Value, Title = text?.Trim() }; caps.Add(cap); } caps.Reverse(); return(new ComicEntity { Chapters = caps.ToArray(), Descript = descBlock?.InnerText, ComicUrl = targetUrl, ImageUrl = imgBlock?.Attributes["src"]?.Value, Name = titleBlock?.Trim() }); }
public async Task <ComicEntity> GetChaptersAsync(string targetUrl) { var mc = new Uri(targetUrl).Segments.Last(); var part = mc.Remove(0, 2); using (var mem = GetStream()) { var arg = $"{{\"comic_id\":{part}}}"; WrtieStream(mem, arg); var stream = await GetStreamAsync(detailUri, "POST", mem); string str = null; using (var sr = new StreamReader(stream)) { str = sr.ReadToEnd(); } using (var jobj = JsonVisitor.FromString(str)) { var data = jobj["data"]; var entity = new ComicEntity { Name = data["title"].ToString(), Descript = data["evaluate"].ToString(), ComicUrl = targetUrl, ImageUrl = data["vertical_cover"].ToString() }; var ep = data["ep_list"].ToEnumerable(); var len = ep.Count(); var chapts = new List <ComicChapter>(ep.Count()); foreach (var item in ep) { var title = item["title"].ToString(); if (string.IsNullOrWhiteSpace(title)) { title = entity.Name + "-" + (len - chapts.Count); } var id = item["id"].ToString(); var url = "https://manga.bilibili.com/" + mc + "/mc" + id; var chp = new ComicChapter { TargetUrl = url, Title = title }; chapts.Add(chp); } chapts.Reverse(); entity.Chapters = chapts.ToArray(); return(entity); } } }
public void GivenValue_PropertyValueMustEqualGiven() { var saver = new NullComicSaver(); var req = new DownloadItemRequest[0]; var prov = new NullSourceProvider(); var eq = new ComicDownloadRequest(saver, null, null, req, prov); var chp = new ComicChapter(); var page = new ComicPage(); var ctx = new DownloadListenerContext(eq, chp, page, default); Assert.AreEqual(eq, ctx.Request); Assert.AreEqual(chp, ctx.Chapter); Assert.AreEqual(page, ctx.Page); Assert.AreEqual(CancellationToken.None, ctx.Token); }
public async Task <IActionResult> ChapterJson(Guid chapterId) { if (await _chapterManager.GetById(chapterId) is var chapter && chapter == null) { return(Json(new { success = false, messages = new[] { ValidationMessages.ChapterNotFound } })); } var title = await _titlesManager.GetById(chapter.TitleId); if (!_signInManager.IsSignedIn(User) && (!title !.Visible || !chapter.Visible)) { return(Json(new { success = false, messages = new[] { ValidationMessages.ContentNotAvailable } })); } object result = chapter switch { ComicChapter comicChapter => new { success = true, Pages = (await _pagesManager.GetAll(comicChapter)).Select(page => (ComicPage)page).OrderBy(page => page.Number).Select(page => new { number = page.Number, address = $"/content/{comicChapter.TitleId}/{comicChapter.Id}/{page.Id}{(page.Animated ? ".gif" : ".png")}" }).ToArray() }, NovelChapter novelChapter => new { success = true, content = novelChapter.Content.AddImgLazyLoading("/assets/placeholder_page.png") }, _ => new { success = false } }; return(Json(result)); }
public async Task <ComicEntity> GetChaptersAsync(string targetUrl) { var str = string.Empty; using (var sr = new StreamReader(await CreateRequest(targetUrl))) { str = await sr.ReadToEndAsync(); } var html = new HtmlDocument(); html.LoadHtml(str); var title = html.DocumentNode.SelectSingleNode("//div[@class='TopicList']/div/div[@class='right fl']/h3")?.InnerText; if (title == null) { title = targetUrl.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); } var desc = html.DocumentNode.SelectSingleNode("//div[@class='comicIntro']/div[@class='details']/div/p"); var nodes = html.DocumentNode.SelectNodes("//div[@class='TopicItem cls']"); var img = html.DocumentNode.SelectSingleNode("//div[@class='TopicItem cls']/div[@class='left fl']/img[@class='imgCover']"); var caps = new List <ComicChapter>(); foreach (var item in nodes) { var a = item.SelectSingleNode("div[@class='cover fl']/a"); var href = a.Attributes["href"]; var imgs = a.SelectNodes("img")[1]; var dt = imgs.Attributes["alt"]; var chap = new ComicChapter { TargetUrl = "https://www.kuaikanmanhua.com/" + href.Value, Title = dt.Value }; caps.Add(chap); } caps.Reverse(); return(new ComicEntity { Chapters = caps.ToArray(), Name = title, Descript = desc?.InnerText, ComicUrl = targetUrl, ImageUrl = img?.Attributes["src"]?.Value }); }
protected virtual async Task StorePageAsync(ComicEntity entity, ComicChapter chapter, ComicPage page) { KeepingAction?.Invoke(entity, chapter, page, null, KeepingActionTypes.BeginStorePage); OnBeginStorePage(chapter, page); try { var mode = WriteMode; if (mode == ComicStoreWriteModes.NotExists) { var ok = await storeService.ExistsAsync(page.TargetUrl); if (ok) { KeepingAction?.Invoke(entity, chapter, page, null, KeepingActionTypes.EndStorePage); OnEndStorePage(chapter, page, false); return; } } var path = page.TargetUrl; if (HasImageFolderName) { path = string.Concat(ImageFolderName, "/", page.TargetUrl); } var stream = await fetchService.GetStreamAsync(page.TargetUrl); if (stream is null) { stream = await Provider.GetImageStreamAsync(page.TargetUrl); if (fetchService != storeService) { await fetchService.SaveAsync(path, stream); } } stream.Seek(0, SeekOrigin.Begin); await storeService.SaveAsync(path, stream); } catch (Exception ex) { KeepingAction?.Invoke(entity, chapter, page, ex, KeepingActionTypes.StorePageException); OnStorePageException(chapter, page, ex); } KeepingAction?.Invoke(entity, chapter, page, null, KeepingActionTypes.EndStorePage); OnEndStorePage(chapter, page, true); }
public async Task <ComicEntity> GetChaptersAsync(string targetUrl) { var str = string.Empty; using (var sr = new StreamReader(await GetStreamAsync(targetUrl))) { str = sr.ReadToEnd(); } var html = new HtmlDocument(); html.LoadHtml(str); var img = html.DocumentNode.SelectSingleNode("//div[@class='banner_detail_form']/div[@class='cover']/img"); var title = html.DocumentNode.SelectSingleNode("//div[@class='banner_detail_form']/div[@class='info']/p[@class='title']"); var desc = html.DocumentNode.SelectSingleNode("//p[@id='a_closes']"); var chpsBox = html.DocumentNode.SelectNodes("//div[@id='chapterlistload']/ul/li/a"); var chps = new List <ComicChapter>(); foreach (var item in chpsBox) { var name = item.InnerText.Trim(); var addr = item.Attributes["href"].Value; var chp = new ComicChapter { Title = name, TargetUrl = "http://www.bikabika.com" + addr }; chps.Add(chp); } var entity = new ComicEntity { ComicUrl = targetUrl, Descript = desc?.InnerText, ImageUrl = img?.Attributes["src"].Value, Name = title?.InnerText, Chapters = chps.ToArray() }; return(entity); }
public async Task <ComicEntity> GetChaptersAsync(string targetUrl) { var str = string.Empty; using (var sr = new StreamReader(await GetStreamAsync(targetUrl))) { str = sr.ReadToEnd(); } var html = new HtmlDocument(); html.LoadHtml(str); var imgBox = html.DocumentNode.SelectSingleNode("//div[@class='works-intro clearfix']/div[@class='works-cover ui-left']/a/img"); var targetList = html.DocumentNode.SelectNodes("//div[@id='chapter']/div[@class='works-chapter-list-wr ui-left']/ol/li/p/span/a"); var baseQuery = "//div[@class='works-intro-text']/"; var nameBox = html.DocumentNode.SelectSingleNode(baseQuery + "div[@class='works-intro-head clearfix']/h2[@class='works-intro-title ui-left']"); var descBox = html.DocumentNode.SelectSingleNode("//p[@class='works-intro-short ui-text-gray9']"); var imgLink = imgBox?.Attributes["src"]?.Value; var chapters = new List <ComicChapter>(); foreach (var item in targetList) { var name = item.InnerText?.Trim(); var link = "https://ac.qq.com" + item.Attributes["href"].Value; var ch = new ComicChapter { TargetUrl = link, Title = name }; chapters.Add(ch); } return(new ComicEntity { Name = nameBox?.InnerText, Descript = descBox?.InnerText?.Trim(), ComicUrl = targetUrl, ImageUrl = imgLink, Chapters = chapters.ToArray() }); }
public async Task <ComicEntity> GetChaptersAsync(string targetUrl) { using (var stream = await GetStreamAsync(targetUrl)) { var str = string.Empty; using (var sr = new StreamReader(stream)) { str = sr.ReadToEnd(); } var html = new HtmlDocument(); html.LoadHtml(str); var img = html.DocumentNode.SelectSingleNode("//div[@class='inner']/div[@class='ctdbLeft ']/a/img"); var desc = html.DocumentNode.SelectSingleNode("//p[@id='worksDesc']"); var list = html.DocumentNode.SelectNodes("//div[@class='comic-content-list']/ul/li/a"); var chps = new List <ComicChapter>(); foreach (var item in list) { var url = item.Attributes["href"].Value; var name = item.Attributes["title"].Value; var chp = new ComicChapter { TargetUrl = "https://www.qimiaomh.com" + url, Title = name }; chps.Add(chp); } var entity = new ComicEntity { Name = img.Attributes["alt"].Value, Chapters = chps.ToArray(), ComicUrl = targetUrl, Descript = desc?.InnerText, ImageUrl = img.Attributes["src"].Value }; return(entity); } }
public DownloadSaveListenerContext(ComicDownloadRequest request, ComicChapter chapter, ComicPage page, CancellationToken token, Stream targetStream) : base(request, chapter, page, token) { baseStream = targetStream; }
private async Task DownloadPageAsync(ComicDownloadRequest request, ComicChapter chapter, ComicPage page, CancellationToken token) { var listener = request.Listener; DownloadListenerContext listenerContext = null; if (listener != null) { listenerContext = new DownloadListenerContext(request, chapter, page, token); await listener.ReadyFetchAsync(listenerContext); } if (listener != null && token.IsCancellationRequested) { await listener.CanceledAsync(listenerContext); return; } var ctx = new ComicDownloadContext(request.Entity, chapter, page, null, token); if (!request.Saver.NeedToSave(ctx)) { if (listener != null) { await listener.NotNeedToSaveAsync(listenerContext); } return; } try { if (listener != null) { await listener.BeginFetchPageAsync(listenerContext); } using (var stream = await request.Provider.GetImageStreamAsync(page.TargetUrl)) using (var destStream = streamManager.GetStream()) { DownloadSaveListenerContext saveCtx = null; if (listener != null) { saveCtx = new DownloadSaveListenerContext(request, chapter, page, token, destStream); await listener.ReadySaveAsync(saveCtx); } await stream.CopyToAsync(destStream); destStream.Seek(0, SeekOrigin.Begin); ctx = new ComicDownloadContext(request.Entity, chapter, page, destStream, token); await request.Saver.SaveAsync(ctx); if (listener != null) { await listener.EndFetchPageAsync(saveCtx); } } } catch (Exception ex) { if (listener != null) { var errCtx = new DownloadExceptionListenerContext(request, chapter, page, token, ex); await listener.FetchPageExceptionAsync(errCtx); } } if (listener != null) { await listener.ComplatedSaveAsync(listenerContext); } }
public ChapterWithPage(ComicChapter chapter, ComicPage[] pages) { Chapter = chapter; Pages = pages; }
public DownloadItemRequest(ComicChapter chapter, ComicPage page) { Chapter = chapter; Page = page; }
protected virtual void OnBeginStorePage(ComicChapter chapter, ComicPage page) { }
protected virtual async Task <ChapterWithPage> StoreChapterAsync(ComicEntity entity, ComicChapter chapter) { var pages = await Provider.GetPagesAsync(chapter.TargetUrl); if (pages != null) { foreach (var item in pages) { if (tokenSource.IsCancellationRequested) { break; } await StorePageAsync(entity, chapter, item); } } return(new ChapterWithPage(chapter, pages)); }
protected virtual void OnStoreChapterException(ComicEntity entity, ComicChapter chapter, Exception ex) { }
public void LoadChapter() { comicChapter = ComicChapter.LoadFromFile(inpPathfield.text); }
protected virtual void OnEndStorePage(ComicChapter chapter, ComicPage page, bool write) { }
public async Task <ComicEntity> GetChaptersAsync(string targetUrl) { targetUrl = GetTrueUrl(targetUrl); string str = null; using (var sr = new StreamReader(await CreateRequest(targetUrl))) { str = sr.ReadToEnd(); } var doc = new HtmlDocument(); doc.LoadHtml(str); var title = doc.DocumentNode.SelectSingleNode("//div[@class='comic_deCon']/h1/a")?.InnerText; if (title == null) { title = doc.DocumentNode.SelectSingleNode("//span[@class='anim_title_text']/a/h1")?.InnerText; } if (title == null) { title = targetUrl.Split('/').Last(); } var desc = doc.DocumentNode.SelectSingleNode("//div[@clas='wrap_intro_l_comic']/div[@class='comic_deCon']/p[@class='comic_deCon_d']"); var node = doc.DocumentNode.SelectNodes("//div[@class='cartoon_online_border']/ul/li/a"); if (node == null) { node = doc.DocumentNode.SelectNodes("//ul[@class='list_con_li autoHeight']/li/a"); } var img = doc.DocumentNode.SelectSingleNode("//div[@class='wrap_intro_l_comic']/div[@class='comic_i']/div[@class='comic_i_img']/a/img"); var chartps = new List <ComicChapter>(); for (int i = node.Count - 1; i >= 0; i--) { var item = node[i]; var name = item.InnerText; var url = item.Attributes["href"]?.Value; if (url != null && !url.StartsWith("http://") && !url.StartsWith("https://")) { url = "https://manhua.dmzj.com" + url; } var chap = new ComicChapter { TargetUrl = url, Title = HttpUtility.UrlDecode(name) }; chartps.Add(chap); } chartps.Reverse(); var entity = new ComicEntity { Chapters = chartps.ToArray(), Descript = desc?.InnerText, ComicUrl = targetUrl, ImageUrl = img?.Attributes["src"]?.Value, Name = title?.Trim() }; return(entity); }
protected virtual void OnEndStoreChapter(ComicEntity entity, ComicChapter chapter) { }
protected virtual void OnStorePageException(ComicChapter chapter, ComicPage page, Exception ex) { }