Пример #1
0
        public static void Merge(this MangaObject mangaObject, IEnumerable <MangaObject> list)
        {
            if (list.Count() > 0)
            {
                // Name
                if (String.IsNullOrWhiteSpace(mangaObject.Name))
                {
                    MangaObject FoD_Obj = list.FirstOrDefault(mO => !String.IsNullOrWhiteSpace(mO.Name));
                    if (FoD_Obj != null)
                    {
                        mangaObject.Name = FoD_Obj.Name;
                    }
                }

                // Released
                if (mangaObject.Released.Equals(DateTime.MinValue))
                {
                    MangaObject FoD_Obj = list.FirstOrDefault(mO => mO.Released > DateTime.MinValue);
                    if (FoD_Obj != null)
                    {
                        mangaObject.Released = FoD_Obj.Released;
                    }
                }

                // Rating
                if (mangaObject.Rating < 0)
                {
                    MangaObject FoD_Obj = list.FirstOrDefault(mO => mO.Rating >= 0);
                    if (FoD_Obj != null)
                    {
                        mangaObject.Rating = FoD_Obj.Rating;
                    }
                }

                // Description
                if (String.IsNullOrWhiteSpace(mangaObject.Description))
                {
                    MangaObject FoD_Obj = list.FirstOrDefault(mO => !String.IsNullOrWhiteSpace(mO.Description));
                    if (FoD_Obj != null)
                    {
                        mangaObject.Description = FoD_Obj.Description;
                    }
                }

                // MangaType & PageFlowDirection
                if (mangaObject.MangaType == Enums.MangaObjectType.Unknown)
                {
                    MangaObject FoD_Obj = list.FirstOrDefault(mO => mO.MangaType != Enums.MangaObjectType.Unknown);
                    if (FoD_Obj != null)
                    {
                        mangaObject.MangaType         = FoD_Obj.MangaType;
                        mangaObject.PageFlowDirection = FoD_Obj.PageFlowDirection;
                    }
                }

                // Locations
                foreach (List <LocationObject> Locations in (from MangaObject obj in list where obj != null select obj.Locations))
                {
                    foreach (LocationObject Location in Locations)
                    {
                        if (!mangaObject.Locations.Any(o => o.ExtensionName == Location.ExtensionName))
                        {
                            mangaObject.Locations.Add(Location);
                        }
                        else
                        {
                            // Update existing location url
                            Int32 idx = mangaObject.Locations.FindIndex(o => o.ExtensionName == Location.ExtensionName);
                            mangaObject.Locations.RemoveAt(idx);
                            mangaObject.Locations.Insert(idx, Location);
                        }
                    }
                }

                // DatabaseLocations
                foreach (List <LocationObject> DatabaseLocations in (from MangaObject obj in list where obj != null select obj.DatabaseLocations))
                {
                    foreach (LocationObject DatabaseLocation in DatabaseLocations)
                    {
                        if (!mangaObject.DatabaseLocations.Any(o => o.ExtensionName == DatabaseLocation.ExtensionName))
                        {
                            mangaObject.DatabaseLocations.Add(DatabaseLocation);
                        }
                    }
                }

                // Artists
                foreach (List <String> Artists in (from MangaObject obj in list where obj != null select obj.Artists))
                {
                    foreach (String Artist in Artists)
                    {
                        if (Artist != null &&
                            !mangaObject.Artists.Any(o => o.ToLower() == Artist.ToLower()))
                        {
                            mangaObject.Artists.Add(Artist);
                        }
                    }
                }

                // Authors
                foreach (List <String> Authors in (from MangaObject obj in list where obj != null select obj.Authors))
                {
                    foreach (String Author in Authors)
                    {
                        if (Author != null &&
                            !mangaObject.Authors.Any(o => o.ToLower() == Author.ToLower()))
                        {
                            mangaObject.Authors.Add(Author);
                        }
                    }
                }

                // Covers
                foreach (List <LocationObject> Covers in (from MangaObject obj in list where obj != null select obj.CoverLocations))
                {
                    foreach (LocationObject Cover in Covers)
                    {
                        if (Cover != null &&
                            !mangaObject.CoverLocations.Any(o => Equals(o.Url, Cover.Url)))
                        {
                            mangaObject.CoverLocations.Add(Cover);
                        }
                    }
                }
                mangaObject.CoverLocations.RemoveAll(c => String.IsNullOrWhiteSpace(c.Url));

                // AlternateNames
                foreach (String Name in (from MangaObject obj in list where obj != null select obj.Name))
                {
                    if (!mangaObject.AlternateNames.Any(o => o.ToLower() == Name.ToLower()) && Name != null)
                    {
                        mangaObject.AlternateNames.Add(Name);
                    }
                }
                foreach (List <String> AlternateNames in (from MangaObject obj in list where obj != null select obj.AlternateNames))
                {
                    foreach (String AlternateName in AlternateNames)
                    {
                        if (AlternateName != null && !mangaObject.AlternateNames.Any(o => o.ToLower() == AlternateName.ToLower()))
                        {
                            mangaObject.AlternateNames.Add(AlternateName);
                        }
                    }
                }

                // Genres
                foreach (List <String> Genres in (from MangaObject obj in list where obj != null select obj.Genres))
                {
                    foreach (String Genre in Genres)
                    {
                        if (Genre != null && !mangaObject.Genres.Any(o => o.ToLower() == Genre.ToLower()))
                        {
                            mangaObject.Genres.Add(Genre);
                        }
                    }
                }

                // Chapters
                foreach (List <ChapterObject> Chapters in (from MangaObject obj in list where obj != null select obj.Chapters))
                {
                    foreach (ChapterObject Chapter in Chapters)
                    {
                        if (Chapter != null)
                        {
                            ChapterObject chapterObject = mangaObject.Chapters.FirstOrDefault(o =>
                            {
                                if (!Int32.Equals(o.Chapter, Chapter.Chapter))
                                {
                                    return(false);
                                }
                                if (!Int32.Equals(o.SubChapter, Chapter.SubChapter))
                                {
                                    return(false);
                                }
                                return(true);
                            });
                            if (ChapterObject.Equals(chapterObject, null))
                            {
                                mangaObject.Chapters.Add(Chapter);
                            }
                            else
                            {
                                chapterObject.Merge(Chapter);
                            }
                        }
                    }
                }

                mangaObject.SortChapters();
            }
        }
Пример #2
0
        private static void OnCacheObjectChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            MangaCacheObject control = source as MangaCacheObject;

            if (!Equals(control.MangaObject, null))
            {   // MangaObject exists
                // Use the first ChapterObject or null for the ResumeChapterObject
                ChapterObject ResumeChapterObject = control.MangaObject.Chapters.FirstOrDefault();

                if (!Equals(control.BookmarkObject, null))
                {   // BookmarkObject exists
                    control.IsNewManga = false;
                    // A BookmarkObject exists, lookup the ResumeChapterObject
                    ResumeChapterObject = control.MangaObject.ChapterObjectOfBookmarkObject(control.BookmarkObject);

                    Double ChapterProgressMaxValue = control.MangaObject.Chapters.Count,
                           ChapterProgressValue    = control.MangaObject.IndexOfChapterObject(ResumeChapterObject),
                           ChapterProgressStep     = 1 / ChapterProgressMaxValue,
                           ChapterProgress         = ChapterProgressValue / ChapterProgressMaxValue,
                           ChapterSubProgress      = 1;
                    if (control.BookmarkObject.LastPage > 0)
                    {
                        ChapterSubProgress = (Double)control.BookmarkObject.Page / (Double)control.BookmarkObject.LastPage;
                    }
                    // Calculate and round the readers progress for chapters
                    control.ChapterProgress = (Int32)Math.Round((ChapterProgress + (ChapterSubProgress * ChapterProgressStep)) * 100);

                    ChapterObject LastChapterObject = control.MangaObject.Chapters.LastOrDefault();
                    if (!Equals(LastChapterObject, null))
                    {   // If there is a ChapterObject to resume, check to see if there are more chapters/pages to read.
                        control.HasMoreToRead = false;
                        if (!control.HasMoreToRead)
                        {
                            control.HasMoreToRead = control.BookmarkObject.Volume < LastChapterObject.Volume;
                        }
                        if (!control.HasMoreToRead)
                        {
                            control.HasMoreToRead = control.BookmarkObject.Chapter < LastChapterObject.Chapter;
                        }
                        if (!control.HasMoreToRead)
                        {
                            control.HasMoreToRead = control.BookmarkObject.SubChapter < LastChapterObject.SubChapter;
                        }
                        if (!control.HasMoreToRead)
                        {
                            control.HasMoreToRead = control.BookmarkObject.Page < control.BookmarkObject.LastPage;
                        }
                    }
                }
                else
                {
                    control.IsNewManga      = true;
                    control.ChapterProgress = 0;
                    control.HasMoreToRead   = !Equals(ResumeChapterObject, null);
                }

                // Store boolean for if the ResumeChapterObject is null
                Boolean ResumeChapterIsNull          = Equals(ResumeChapterObject, null);
                String  MangaObjectChaptersDirectory = System.IO.Path.Combine(control.App.CORE.CHAPTER_ARCHIVE_DIRECTORY, control.MangaObject.MangaFileName());
                control.ChapterCacheObjects = new List <ChapterCacheObject>(
                    from ChapterObject in control.MangaObject.Chapters
                    select new ChapterCacheObject(control.MangaObject, ChapterObject)
                {
                    // If ResumeChapterIsNull is true, there is no ResumeChapter
                    IsResumeChapter = ResumeChapterIsNull ? false : Equals(ChapterObject, ResumeChapterObject),

                    // Store if the ChapterObject archive exists locally
                    IsLocal = ChapterObject.IsLocal(
                        MangaObjectChaptersDirectory,
                        control.App.CORE.CHAPTER_ARCHIVE_EXTENSION)
                });
            }
            else
            {
                control.IsNewManga      = false;
                control.HasMoreToRead   = false;
                control.ChapterProgress = 0;
            }
        }
Пример #3
0
 public void Init(ChapterObject chapterObject, Menu.OnChapterAction loadAction)
 {
     chapterName.text = chapterObject.chapterName;
     image.sprite     = chapterObject.image;
     button.onClick.AddListener(() => loadAction.Invoke(chapterObject));
 }
Пример #4
0
 public static Boolean IsLocal(this ChapterObject value, String Folder, String Extension = "zip")
 {
     return((value != null) ? System.IO.File.Exists(System.IO.Path.Combine(Folder, value.ChapterArchiveName(Extension))) : false);
 }
Пример #5
0
 public static PageObject PageObjectOfBookmarkObject(this ChapterObject value, BookmarkObject bookmark_object)
 {
     return(value.Pages.Find(p => p.PageNumber == bookmark_object.Page));
 }
Пример #6
0
        public MangaObject ParseMangaObject(string Content)
        {
            HtmlDocument MangaObjectDocument = new HtmlDocument();

            MangaObjectDocument.LoadHtml(Content);

            HtmlNode MangaNode = MangaObjectDocument.DocumentNode.SelectSingleNode(".//section[contains(@class, 'manga')]");
            String   Name      = HtmlEntity.DeEntitize(MangaNode.SelectSingleNode(".//div/div[1]/h1/a").InnerText);

            Name = Name.Substring(0, Name.LastIndexOf(' '));
            HtmlNode      AlternateNamesNode = MangaNode.SelectSingleNode(".//div/table/tr/td[2]/table/tr[4]/td");
            List <String> AlternateNames     = (from AltName in HtmlEntity.DeEntitize(AlternateNamesNode.InnerText).Split(';')
                                                select AltName.Trim()).ToList();
            List <String> Authors = (from Node in MangaNode.SelectNodes(".//div/table/tr/td[2]/table/tr[5]/td/a")
                                     select HtmlEntity.DeEntitize(Node.InnerText)).ToList();
            List <String> Artists = (from Node in MangaNode.SelectNodes(".//div/table/tr/td[2]/table/tr[6]/td/a")
                                     select HtmlEntity.DeEntitize(Node.InnerText)).ToList();
            List <String> Genres = (from Node in MangaNode.SelectNodes(".//div/table/tr/td[2]/table/tr[7]/td/a")
                                    select HtmlEntity.DeEntitize(Node.InnerText)).ToList();

            // Detect type
            MangaObjectType MangaType = MangaObjectType.Unknown;
            String          mType     = MangaNode.SelectSingleNode(".//div/table/tr/td[2]/table/tr[8]/td").InnerText.ToLower();

            if (mType.Contains("japanese manga"))
            {
                MangaType = MangaObjectType.Manga;
            }
            else if (mType.Contains("korean manhwa"))
            {
                MangaType = MangaObjectType.Manhwa;
            }

            // Get description
            String Description = HtmlEntity.DeEntitize(MangaNode.SelectSingleNode(".//div/p").InnerText);

            // Chapters
            List <ChapterObject> Chapters = new List <ChapterObject>();

            foreach (HtmlNode ChapterVersionNode in MangaNode.SelectNodes(".//*[@id='list']/div[starts-with(@id, 'stream_')]"))
            {
                foreach (HtmlNode VolumeNode in ChapterVersionNode.SelectNodes(".//div[contains(@class, 'volume')]"))
                {
                    UInt32   Volume         = 0;
                    HtmlNode VolumeNameNode = VolumeNode.SelectSingleNode(".//h4");
                    if (!Equals(VolumeNameNode, null))
                    {
                        String[] idParts = VolumeNameNode.GetAttributeValue("id", "v-1-").Split('-');
                        UInt32.TryParse(idParts[2], out Volume);
                    }

                    foreach (HtmlNode ChapterNode in ChapterVersionNode.SelectNodes(".//div/ul/li"))
                    {
                        HtmlNode InfoNode = ChapterNode.SelectSingleNode(".//a");
                        String   ChapterName = HtmlEntity.DeEntitize(InfoNode.InnerText),
                                 Url = InfoNode.GetAttributeValue("href", null);
                        UInt32 Chapter = 0, SubChapter = 0;

                        Match match = Regex.Match(ChapterName, @"(vol\.(?<Volume>\d+)\s)?ch\.(?<Chapter>\d+)(\.(?<SubChapter>\d+))?");
                        if (match.Success)
                        {
                            if (match.Groups["Volume"].Success)
                            {
                                UInt32.TryParse(match.Groups["Volume"].Value, out Volume);
                            }
                            if (match.Groups["Chapter"].Success)
                            {
                                UInt32.TryParse(match.Groups["Chapter"].Value, out Chapter);
                            }
                            if (match.Groups["SubChapter"].Success)
                            {
                                UInt32.TryParse(match.Groups["SubChapter"].Value, out SubChapter);
                            }
                        }

                        if (Equals(Url, null))
                        {
                            continue;
                        }
                        Url = String.Format("{0}{1}", ExtensionDescriptionAttribute.RootUrl, Url);

                        ChapterObject NewChapterObject = new ChapterObject()
                        {
                            Name       = ChapterName,
                            Volume     = Volume,
                            Chapter    = Chapter,
                            SubChapter = SubChapter,
                            Locations  =
                            {
                                new LocationObject()
                                {
                                    Enabled           = true,
                                    ExtensionName     = ExtensionDescriptionAttribute.Name,
                                    ExtensionLanguage = ExtensionDescriptionAttribute.Language,
                                    Url = Url
                                }
                            }
                        };
                        ChapterObject ExistingChapterObject = Chapters.FirstOrDefault(o =>
                        {
                            if (!Int32.Equals(o.Chapter, NewChapterObject.Chapter))
                            {
                                return(false);
                            }
                            if (!Int32.Equals(o.SubChapter, NewChapterObject.SubChapter))
                            {
                                return(false);
                            }
                            return(true);
                        });
                        if (Equals(ExistingChapterObject, null))
                        {
                            Chapters.Add(NewChapterObject);
                        }
                        else
                        {
                            ExistingChapterObject.Merge(NewChapterObject);
                        }
                    }
                }
            }
            Chapters = Chapters.OrderBy(c => c.Chapter).ThenBy(c => c.SubChapter).ThenBy(c => c.Volume).ToList();

            return(new MangaObject()
            {
                Name = Name,
                AlternateNames = AlternateNames,
                Description = Description,
                Authors = Authors,
                Artists = Artists,
                Genres = Genres,
                MangaType = MangaType,
                Chapters = Chapters
            });
        }
Пример #7
0
        public async Task DownloadAsync(MangaObject MangaObject, ChapterObject ChapterObject, IProgress <Int32> ProgressReporter = null)
        {
            String CK = CacheKey(MangaObject, ChapterObject);

            if (ActiveDownloadsCache.Contains(CK))
            {
                return;
            }
            ActiveDownloadsCache.Set(CK, true, DateTimeOffset.MaxValue);

            try
            {
                await Task.Delay(TimeSpan.FromSeconds(1));

                // Load the ChapterObject via Async and LimitedTaskFactory
                IProgress <Int32> ChapterObjectProgressReporter = new Progress <Int32>(ProgressValue =>
                {
                    if (!Equals(ProgressReporter, null))
                    {
                        ProgressReporter.Report((Int32)Math.Round((Double)ProgressValue * 0.25));
                    }
                });
                ChapterObject = await ContentTaskFactory.StartNew(() => LoadChapterObjectAsync(
                                                                      MangaObject,
                                                                      ChapterObject,
                                                                      cts.Token,
                                                                      ChapterObjectProgressReporter)).Unwrap();

                if (!ChapterObject.Pages.Count.Equals(0))
                { // Check for pages
                  // Save the ChapterObject via Async to Save Path with Retry and Timeout of 30min
                    await StoreChapterObject(MangaObject, ChapterObject);

                    // Load the PageObjects from the ChapterObject
                    List <Task <PageObject> > PageObjectDownloadTasks = new List <Task <PageObject> >();

                    foreach (PageObject PageObject in ChapterObject.Pages)
                    {
                        PageObjectDownloadTasks.Add(ContentTaskFactory.StartNew(() => LoadPageObjectAsync(
                                                                                    MangaObject,
                                                                                    ChapterObject,
                                                                                    PageObject,
                                                                                    cts.Token,
                                                                                    null)).Unwrap());
                    }

                    foreach (Task <PageObject> PageObjectDownloadTask in PageObjectDownloadTasks)
                    {
                        PageObject PageObject = await PageObjectDownloadTask;
                        Int32      index      = ChapterObject.Pages.FindIndex(_PageObject => Equals(_PageObject.PageNumber, PageObject.PageNumber));
                        ChapterObject.Pages[index] = PageObject;
                    }
                    await StoreChapterObject(MangaObject, ChapterObject);

                    // Download Images
                    IEnumerable <Task> DownloadImageTasksQuery =
                        from PageObject in ChapterObject.Pages
                        select DownloadImageAsync(
                            PageObject.ImgUrl,
                            PageObject.Url,
                            CORE.SiteExtensions.First(_SiteExtension => PageObject.Url.Contains(_SiteExtension.ExtensionDescriptionAttribute.URLFormat)).Cookies,
                            SavePath(MangaObject, ChapterObject),
                            Path.GetFileName(new Uri(PageObject.ImgUrl).LocalPath));

                    List <Task> DownloadImageTasks = DownloadImageTasksQuery.ToList();
                    Int32       OriginalDownloadImageTasksCount = DownloadImageTasks.Count;

                    while (DownloadImageTasks.Count > 0)
                    {
                        Task completedTask = await Task.WhenAny(DownloadImageTasks);

                        DownloadImageTasks.Remove(completedTask);

                        Int32 DownloadImageTasksProgress = (Int32)Math.Round(((Double)(OriginalDownloadImageTasksCount - DownloadImageTasks.Count) / (Double)OriginalDownloadImageTasksCount) * 75);
                        if (!Equals(ProgressReporter, null))
                        {
                            ProgressReporter.Report(25 + DownloadImageTasksProgress);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (!Equals(CORE.Logger, null))
                {
                    CORE.Logger.Warn(String.Format("[ContentDownloadManager] An exception was thrown while processing {0}.", MangaObject.Name), ex);
                }
                throw ex;
            }
            finally
            {
                if (!Equals(ProgressReporter, null))
                {
                    ProgressReporter.Report(100);
                }
                ActiveDownloadsCache.Remove(CK);
            }
        }
Пример #8
0
 public static void Merge(this ChapterObject chapterObject, params ChapterObject[] list)
 {
     chapterObject.Merge(list.AsEnumerable());
 }
Пример #9
0
 public static Int32 IndexOfPageObject(this ChapterObject value, PageObject page_object)
 {
     return(value.Pages.FindIndex(p => p.PageNumber == page_object.PageNumber));
 }
Пример #10
0
 public ChapterObjectEntry(ChapterObject chapterObject)
 {
     _chapterObject = chapterObject;
 }
Пример #11
0
        public MangaObject ParseMangaObject(string content)
        {
            HtmlDocument MangaObjectDocument = new HtmlDocument();

            MangaObjectDocument.LoadHtml(content);

            HtmlNode InformationNode = MangaObjectDocument.DocumentNode.SelectSingleNode("//div[contains(@class,'ipsBox')]/div");
            String   Cover           = InformationNode.SelectSingleNode(".//div[1]/img").Attributes["src"].Value;

            HtmlNode MangaProperties = InformationNode.SelectSingleNode(".//table[contains(@class,'ipb_table')]"),
                     ChapterListing  = MangaObjectDocument.DocumentNode.SelectSingleNode("//table[contains(@class,'chapters_list')]");

            String MangaName                  = HtmlEntity.DeEntitize(MangaObjectDocument.DocumentNode.SelectSingleNode("//h1[contains(@class,'ipsType_pagetitle')]").InnerText.Trim()),
                   MangaTypeProp              = HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[5]/td[2]").InnerText),
                   Desciption                 = HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[7]/td[2]").InnerText.Replace("<br>", "\n"));
            MangaObjectType MangaType         = MangaObjectType.Unknown;
            FlowDirection   PageFlowDirection = FlowDirection.RightToLeft;

            switch (MangaTypeProp.ToLower())
            {
            default:
                MangaType         = MangaObjectType.Unknown;
                PageFlowDirection = FlowDirection.RightToLeft;
                break;

            case "manga (japanese)":
                MangaType         = MangaObjectType.Manga;
                PageFlowDirection = FlowDirection.RightToLeft;
                break;

            case "manhwa (korean)":
                MangaType         = MangaObjectType.Manhwa;
                PageFlowDirection = FlowDirection.LeftToRight;
                break;

            case "manhua (chinese)":
                MangaType         = MangaObjectType.Manhua;
                PageFlowDirection = FlowDirection.LeftToRight;
                break;
            }

            HtmlNodeCollection AlternateNameNodes = MangaProperties.SelectSingleNode(".//tr[1]/td[2]").SelectNodes(".//span"),
                               GenreNodes         = MangaProperties.SelectSingleNode(".//tr[4]/td[2]").SelectNodes(".//a/span");

            String[] AlternateNames = { },
            Authors = { HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[2]/td[2]/a").InnerText) },
            Artists = { HtmlEntity.DeEntitize(MangaProperties.SelectSingleNode(".//tr[3]/td[2]/a").InnerText) },
            Genres  = { };
            if (AlternateNameNodes != null && AlternateNameNodes.Count > 0)
            {
                AlternateNames = (from HtmlNode AltNameNode in AlternateNameNodes select HtmlEntity.DeEntitize(AltNameNode.InnerText.Trim())).ToArray();
            }
            if (GenreNodes != null && GenreNodes.Count > 0)
            {
                Genres = (from HtmlNode GenreNode in GenreNodes select HtmlEntity.DeEntitize(GenreNode.InnerText.Trim())).ToArray();
            }

            List <ChapterObject> Chapters     = new List <ChapterObject>();
            HtmlNodeCollection   ChapterNodes = ChapterListing.SelectNodes(String.Format(".//tr[contains(@class,'lang_{0} chapter_row')]", ExtensionDescriptionAttribute.Language));

            if (ChapterNodes != null && ChapterNodes.Count > 0)
            {
                foreach (HtmlNode ChapterNode in ChapterNodes)
                {
                    HtmlNode VolChapNameNode = ChapterNode.SelectSingleNode("td[1]/a");
                    Match    VolChapMatch = Regex.Match(VolChapNameNode.InnerText, @"(Vol\.(?<Volume>\d+)\s)?(Ch\.(?<Chapter>\d+))(\.(?<SubChapter>\d+))?");
                    String   ChapterName = VolChapNameNode.InnerText.Substring(VolChapMatch.Length + 2).Trim(),
                             ReleaseData = ReleaseData = ChapterNode.SelectSingleNode("td[5]").InnerText;
                    ChapterObject PrevChapter = Chapters.LastOrDefault();
                    UInt32        Volume = 0, Chapter = 0, SubChapter = 0;
                    if (VolChapMatch.Groups["Volume"].Success)
                    {
                        UInt32.TryParse(VolChapMatch.Groups["Volume"].Value, out Volume);
                    }
                    if (VolChapMatch.Groups["Chapter"].Success)
                    {
                        UInt32.TryParse(VolChapMatch.Groups["Chapter"].Value, out Chapter);
                    }
                    if (VolChapMatch.Groups["SubChapter"].Success)
                    {
                        UInt32.TryParse(VolChapMatch.Groups["SubChapter"].Value, out SubChapter);
                    }

                    DateTime Released = DateTime.Now;
                    if (ReleaseData.Contains("-"))
                    {
                        ReleaseData = ReleaseData.Split(new String[] { " - " }, StringSplitOptions.RemoveEmptyEntries)[0];
                        DateTime.TryParseExact(ReleaseData, "dd MMMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out Released);
                    }
                    else if (ReleaseData.EndsWith("ago"))
                    {
                        String[] ReleaseDataParts = ReleaseData.Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        Double   Offset           = 1;
                        if (!Double.TryParse(ReleaseDataParts[0], out Offset))
                        {
                            Offset = 1;
                        }
                        Offset *= -1;
                        switch (ReleaseDataParts[1].ToLower())
                        {
                        default:
                        case "seconds":
                            Released = Released.AddSeconds(Offset);
                            break;

                        case "minutes":
                            Released = Released.AddMinutes(Offset);
                            break;

                        case "hours":
                            Released = Released.AddHours(Offset);
                            break;

                        case "days":
                            Released = Released.AddDays(Offset);
                            break;

                        case "weeks":
                            Released = Released.AddDays(7 * Offset);
                            break;
                        }
                    }

                    String ChapterUrl  = VolChapNameNode.Attributes["href"].Value;
                    String ChapterHash = ChapterUrl.Split('#').Last().Split('_').First();
                    ChapterUrl = String.Format("https://bato.to/areader?id={0}&p=1&supress_webtoon=t", ChapterHash);
                    ChapterObject chapterObject = new ChapterObject()
                    {
                        Name       = HtmlEntity.DeEntitize(ChapterName),
                        Volume     = Volume,
                        Chapter    = Chapter,
                        SubChapter = SubChapter,
                        Released   = Released,
                        Locations  =
                        {
                            new LocationObject()
                            {
                                ExtensionName     = ExtensionDescriptionAttribute.Name,
                                ExtensionLanguage = ExtensionDescriptionAttribute.Language,
                                Url = ChapterUrl
                            }
                        }
                    };
                    if (!Chapters.Any(o => o.Chapter == chapterObject.Chapter && ((Int32)o.SubChapter - chapterObject.SubChapter).InRange(-4, 4)))
                    {
                        Chapters.Add(chapterObject);
                    }
                    else
                    {
                        Chapters.Find(o => o.Chapter == chapterObject.Chapter && ((Int32)o.SubChapter - chapterObject.SubChapter).InRange(-4, 4)).Merge(chapterObject);
                    }
                }
            }
            Chapters.Reverse();

            Double Rating = -1;

            try
            {
                HtmlNode RatingNode = MangaObjectDocument.DocumentNode.SelectSingleNode("//div[contains(@class,'rating')]");
                String   RatingText = new String(RatingNode.InnerText.Trim().Substring(1, 4).Where(IsValidRatingChar).ToArray());
                Double.TryParse(RatingText, out Rating);
            }
            catch { }

            return(new MangaObject()
            {
                Name = MangaName,
                MangaType = MangaType,
                PageFlowDirection = PageFlowDirection,
                Description = HtmlEntity.DeEntitize(Desciption),
                AlternateNames = AlternateNames.ToList(),
                CoverLocations = { new LocationObject()
                                   {
                                       Url = Cover,
                                       ExtensionName = ExtensionDescriptionAttribute.Name,
                                       ExtensionLanguage = ExtensionDescriptionAttribute.Language
                                   } },
                Authors = Authors.ToList(),
                Artists = Artists.ToList(),
                Genres = Genres.ToList(),
                Released = (Chapters.FirstOrDefault() ?? new ChapterObject()).Released,
                Chapters = Chapters,
                Rating = Rating
            });
        }
Пример #12
0
        public MangaObject ParseMangaObject(String content)
        {
            Int32 MangaInformationContentStart = content.IndexOf("<!-- Intro Series -->"),
                  MangaInformationContentEnd   = content.IndexOf("<!-- **END: Intro Series -->", MangaInformationContentStart);
            String MangaInformationContent     = content.Substring(MangaInformationContentStart, MangaInformationContentEnd - MangaInformationContentStart);

            Int32 MangaChaptersContentStart = content.IndexOf("<!-- Main Content -->"),
                  MangaChaptersContentEnd   = content.IndexOf("<!-- **END: Main Content -->", MangaChaptersContentStart);
            String MangaChaptersContent     = content.Substring(MangaChaptersContentStart, MangaChaptersContentEnd - MangaChaptersContentStart);

            HtmlDocument MangaObjectDocument = new HtmlDocument();

            MangaObjectDocument.LoadHtml(MangaInformationContent);

            HtmlNode MangaObjectNode = MangaObjectDocument.DocumentNode.SelectSingleNode(".//div/div");

            String MangaName             = String.Empty,
                   Description           = String.Empty;
            List <String> AlternateNames = new List <String>(),
                          AuthorsArtists = new List <String>(),
                          Genres         = new List <String>();

            foreach (HtmlNode DetailNode in MangaObjectNode.SelectNodes(".//div[2]/div[contains(@class,'row')]"))
            {
                HtmlNode DetailTypeNode             = DetailNode.SelectSingleNode(".//div[1]/b[1] | .//div[1]/strong[1]"),
                              DetailTextNode        = (DetailTypeNode != null) ? DetailTypeNode.NextSibling : null,
                              DetailDescriptionNode = (DetailTextNode != null) ? DetailTextNode.NextSibling : null,
                              MangaNameNode         = DetailNode.SelectSingleNode(".//div[1]/h1");
                HtmlNodeCollection DetailLinkNodes  = DetailNode.SelectNodes(".//div[1]/a");
                String             DetailType       = (DetailTypeNode != null) ? DetailTypeNode.InnerText.Trim().TrimEnd(':') : "MangaName",
                                   DetailValue = String.Empty;
                String[] DetailValues          = { };
                if (DetailLinkNodes != null)
                {
                    DetailValues = (from HtmlNode LinkNode in DetailLinkNodes select HtmlEntity.DeEntitize(LinkNode.InnerText.Trim())).ToArray();
                }
                else if (MangaNameNode != null)
                {
                    DetailValue = HtmlEntity.DeEntitize(MangaNameNode.InnerText.Trim());
                }
                else if (DetailDescriptionNode != null)
                {
                    DetailValue = HtmlEntity.DeEntitize(DetailDescriptionNode.InnerText.Trim());
                }
                else if (DetailTextNode != null)
                {
                    DetailValue = HtmlEntity.DeEntitize(DetailTextNode.InnerText.Trim());
                }

                switch (DetailType)
                {
                default: break;

                case "MangaName": MangaName = DetailValue; break;

                case "Alternate Names": AlternateNames = (from String AltName in DetailValue.Split(',') select HtmlEntity.DeEntitize(AltName.Trim())).ToList(); break;

                case "Author": AuthorsArtists = DetailValues.ToList(); break;

                case "Genre": Genres = DetailValues.ToList(); break;

                case "Description": Description = DetailValue; break;
                }
            }


            String Cover = ExtensionDescriptionAttribute.RootUrl + MangaObjectNode.SelectSingleNode(".//div[1]/img/@src").Attributes["src"].Value;

            List <ChapterObject> Chapters = new List <ChapterObject>();

            MangaObjectDocument.LoadHtml(MangaChaptersContent);
            HtmlNodeCollection RawChapterList = MangaObjectDocument.DocumentNode.SelectNodes(".//div[contains(@class,'row')]");

            foreach (HtmlNode RawChapterNode in RawChapterList.Skip(1))
            {
                HtmlNode ChapterNumberNode = RawChapterNode.SelectSingleNode(".//div[1]/a"),
                              ReleaseDate  = RawChapterNode.SelectSingleNode(".//div[2]/time");
                String   ChapterNumber     = Regex.Match(ChapterNumberNode.InnerText, @"\d+(\.\d+)?").Value;
                String[] ChapterSub        = ChapterNumber.Trim().Split('.');


                DateTime Released    = DateTime.Now;
                String   ReleasedTxt = ReleaseDate.InnerText.ToLower();
                if (ReleasedTxt.StartsWith("today"))
                {
                    Released = DateTime.Today;
                }
                else if (ReleasedTxt.StartsWith("yesterday"))
                {
                    Released = DateTime.Today.AddDays(-1);
                }
                else if (ReleasedTxt.EndsWith("ago"))
                {
                    Int32 tDelta = 0;
                    Int32.TryParse(ReleasedTxt.Split(' ')[0], out tDelta);
                    if (ReleasedTxt.Contains("hours"))
                    {
                        Released = Released.AddHours(0 - tDelta);
                    }
                    if (ReleasedTxt.Contains("minutes"))
                    {
                        Released = Released.AddMinutes(0 - tDelta);
                    }
                    if (ReleasedTxt.Contains("seconds"))
                    {
                        Released = Released.AddSeconds(0 - tDelta);
                    }
                }
                else
                {
                    Released = DateTime.Parse(ReleasedTxt);
                }

                ChapterObject Chapter = new ChapterObject()
                {
                    Name      = HtmlEntity.DeEntitize(RawChapterNode.SelectSingleNode(".//div[1]/gray").InnerText),
                    Chapter   = UInt32.Parse(ChapterSub[0]),
                    Locations =
                    {
                        new LocationObject()
                        {
                            ExtensionName     = ExtensionDescriptionAttribute.Name,
                            ExtensionLanguage = ExtensionDescriptionAttribute.Language,
                            Url = ExtensionDescriptionAttribute.RootUrl + ChapterNumberNode.Attributes["href"].Value
                        },
                    },
                    Released = Released
                };
                if (ChapterSub.Length == 2)
                {
                    Chapter.SubChapter = UInt32.Parse(ChapterSub[1]);
                }
                Chapters.Add(Chapter);
            }
            Chapters.Reverse();
            MangaObject MangaObj = new MangaObject()
            {
                Name           = HtmlEntity.DeEntitize(MangaName),
                Description    = HtmlEntity.DeEntitize(Description),
                AlternateNames = AlternateNames.ToList(),
                CoverLocations = { new LocationObject()
                                   {
                                       Url               = Cover,
                                       ExtensionName     = ExtensionDescriptionAttribute.Name,
                                       ExtensionLanguage = ExtensionDescriptionAttribute.Language
                                   } },
                Authors  = AuthorsArtists.ToList(),
                Artists  = AuthorsArtists.ToList(),
                Genres   = Genres.ToList(),
                Released = Chapters.First().Released,
                Chapters = Chapters
            };

            MangaObj.AlternateNames.RemoveAll(an => an.ToLower().Equals("none"));
            MangaObj.Genres.RemoveAll(g => g.ToLower().Equals("none"));
            return(MangaObj);
        }
Пример #13
0
        private async Task <ChapterObject> LoadChapterObjectAsync(MangaObject MangaObject, ChapterObject ChapterObject, CancellationToken ct, IProgress <Int32> progress)
        {
            try
            {
                await TaskConcurrencySemaphore.WaitAsync(ct);

                ct.ThrowIfCancellationRequested();

                // Store valid ISiteExtension
                IEnumerable <ISiteExtension> ValidSiteExtensions = ValidExtensions(CORE.SiteExtensions, CORE.UserConfiguration.EnabledExtensions).Cast <ISiteExtension>();

                // Re-Order the Chapter's LocationObjects to the EnabledExtensions order.
                IEnumerable <LocationObject> OrderedChapterObjectLocations = from EnExt in CORE.UserConfiguration.EnabledExtensions
                                                                             where ChapterObject.Locations.Exists(LocObj => EnExt.EqualsLocationObject(LocObj))
                                                                             select ChapterObject.Locations.FirstOrDefault(LocObj => EnExt.EqualsLocationObject(LocObj));

                foreach (LocationObject LocationObject in OrderedChapterObjectLocations)
                {
                    ct.ThrowIfCancellationRequested();
                    ISiteExtension SiteExtension = ValidSiteExtensions.FirstOrDefault(_ => LocationObjectExtension(_, LocationObject));
                    if (Equals(SiteExtension, null))
                    {
                        continue;                               // Continue with the foreach loop
                    }
                    ct.ThrowIfCancellationRequested();
                    using (WebDownloader WebDownloader = new WebDownloader(SiteExtension.Cookies))
                    {
                        WebDownloader.Encoding = System.Text.Encoding.UTF8;
                        WebDownloader.Referer  = SiteExtension.ExtensionDescriptionAttribute.RefererHeader;
                        DownloadProgressChangedEventHandler ProgressEventHandler = (s, e) =>
                        {
                            if (!Equals(progress, null))
                            {
                                progress.Report((Int32)Math.Round((Double)e.ProgressPercentage * 0.9));
                            }
                            ct.ThrowIfCancellationRequested();
                        };
                        WebDownloader.DownloadProgressChanged += ProgressEventHandler;

                        String ChapterWebContent = await WebDownloader.DownloadStringTaskAsync(LocationObject.Url).Retry(DOWNLOAD_TIMEOUT);

                        ChapterObject DownloadedChapterObject = SiteExtension.ParseChapterObject(ChapterWebContent);

                        WebDownloader.DownloadProgressChanged -= ProgressEventHandler;
                        ct.ThrowIfCancellationRequested();
                        if (!Equals(DownloadedChapterObject, null))
                        {
                            ChapterObject.Merge(DownloadedChapterObject);
                            ChapterObject.Pages = DownloadedChapterObject.Pages;
                            break;  // Break free of the foreach loop
                        }
                    }
                }
                if (!Equals(progress, null))
                {
                    progress.Report(100);
                }
                ct.ThrowIfCancellationRequested();
                return(ChapterObject);
            }
            finally { TaskConcurrencySemaphore.Release(); }
        }
Пример #14
0
 public void Download(MangaObject MangaObject, ChapterObject ChapterObject, PageObject PageObject, IProgress <Int32> ProgressReporter = null)
 {
     Task.Run(() => DownloadAsync(MangaObject, ChapterObject, PageObject, ProgressReporter));
 }
Пример #15
0
 public static Int32 IndexOfChapterObject(this MangaObject value, ChapterObject chapter_object)
 {
     return(value.Chapters.FindIndex(c => c.Volume == chapter_object.Volume && c.Chapter == chapter_object.Chapter && c.SubChapter == chapter_object.SubChapter));
 }
Пример #16
0
        public static void Merge(this ChapterObject chapterObject, IEnumerable <ChapterObject> list)
        {
            if (list.Count() > 0)
            {
                // Name
                Regex nameRgx = new Regex(@"^vol(ume)?[\d\s]+.+?ch(apter)?[\d\s]+");
                if (String.IsNullOrWhiteSpace(chapterObject.Name) || nameRgx.IsMatch(chapterObject.Name.ToLower()))
                {
                    ChapterObject FoD_Obj = list.FirstOrDefault(cO => !String.IsNullOrWhiteSpace(cO.Name) && !nameRgx.IsMatch(cO.Name.ToLower()));
                    if (FoD_Obj != null)
                    {
                        chapterObject.Name = FoD_Obj.Name;
                    }
                }

                // Volume
                foreach (UInt32 Volume in (from ChapterObject obj in list where obj != null select obj.Volume))
                {
                    if (chapterObject.Volume <= 0 && Volume >= 0)
                    {
                        chapterObject.Volume = Volume;
                    }
                }

                // Chapter
                foreach (UInt32 Chapter in (from ChapterObject obj in list where obj != null select obj.Chapter))
                {
                    if (chapterObject.Chapter <= 0 && Chapter >= 0)
                    {
                        chapterObject.Chapter = Chapter;
                    }
                }

                // SubChapter
                foreach (UInt32 SubChapter in (from ChapterObject obj in list where obj != null select obj.SubChapter))
                {
                    if (chapterObject.SubChapter < 0 && SubChapter >= 0)
                    {
                        chapterObject.SubChapter = SubChapter;
                    }
                }

                // Locations
                foreach (List <LocationObject> Locations in (from ChapterObject obj in list where obj != null select obj.Locations))
                {
                    foreach (LocationObject Location in Locations)
                    {
                        if (!chapterObject.Locations.Any(o => o.ExtensionName == Location.ExtensionName))
                        {
                            chapterObject.Locations.Add(Location);
                        }
                        else
                        {
                            // Update existing location url
                            Int32 idx = chapterObject.Locations.FindIndex(o => o.ExtensionName == Location.ExtensionName);
                            chapterObject.Locations.RemoveAt(idx);
                            chapterObject.Locations.Insert(idx, Location);
                        }
                    }
                }

                // Pages
                if (Int32.Equals(chapterObject.Pages.Count, 0))
                {
                    chapterObject.Pages.AddRange(list.First().Pages);
                }
            }
        }
Пример #17
0
        public MangaObject ParseMangaObject(string content)
        {
            if (content.ToLower().Contains("has been licensed, it is not available in MangaHere.".ToLower()))
            {
                return(null);
            }
            HtmlDocument MangaObjectDocument = new HtmlDocument();

            MangaObjectDocument.LoadHtml(content);

            HtmlNode TitleNode                       = MangaObjectDocument.DocumentNode.SelectSingleNode("//h1[contains(@class,'title')]"),
                     MangaDetailsNode                = MangaObjectDocument.DocumentNode.SelectSingleNode("//div[contains(@class,'manga_detail')]"),
                     MangaPropertiesNode             = MangaDetailsNode.SelectSingleNode(".//div[1]"),
                     MangaDesciptionNode             = MangaObjectDocument.GetElementbyId("show"),
                     AuthorsNode                     = MangaPropertiesNode.SelectSingleNode(".//ul/li[5]"),
                     ArtistsNode                     = MangaPropertiesNode.SelectSingleNode(".//ul/li[6]"),
                     GenresNode                      = MangaPropertiesNode.SelectSingleNode(".//ul/li[4]");
            HtmlNodeCollection AuthorsNodeCollection = AuthorsNode.SelectNodes(".//a"),
                               ArtistsNodeCollection = ArtistsNode.SelectNodes(".//a");
            String Desciption = MangaDesciptionNode != null ? MangaDesciptionNode.FirstChild.InnerText : String.Empty,
                   MangaName  = HtmlEntity.DeEntitize(System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(TitleNode.LastChild.InnerText.ToLower()));

            String[] AlternateNames = MangaPropertiesNode.SelectSingleNode(".//ul/li[3]").LastChild.InnerText.Split(new String[] { "; " }, StringSplitOptions.RemoveEmptyEntries),
            Authors = { }, Artists = { },
            Genres  = MangaPropertiesNode.SelectSingleNode(".//ul/li[4]").LastChild.InnerText.Split(new String[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
            if (AuthorsNodeCollection != null)
            {
                Authors = (from HtmlNode AuthorNode in AuthorsNodeCollection select HtmlEntity.DeEntitize(AuthorNode.InnerText)).ToArray();
            }
            if (ArtistsNodeCollection != null)
            {
                Artists = (from HtmlNode ArtistNode in ArtistsNodeCollection select HtmlEntity.DeEntitize(ArtistNode.InnerText)).ToArray();
            }

            List <ChapterObject> Chapters       = new List <ChapterObject>();
            HtmlNodeCollection   RawChapterList = MangaDetailsNode.SelectNodes(".//div[contains(@class,'detail_list')]/ul[1]/li");

            foreach (HtmlNode ChapterNode in RawChapterList)
            {
                String   volNode       = ChapterNode.SelectSingleNode(".//span[1]/span").InnerText;
                String[] volChapSub    = { (volNode != null && volNode.Length > 0) ? volNode.Substring(4).Trim() : "0" };
                String   ChapterTitle  = ChapterNode.SelectSingleNode(".//span[1]/a").InnerText.Trim();
                String   ChapterNumber = ChapterTitle.Substring(ChapterTitle.LastIndexOf(' ') + 1).Trim();
                volChapSub = volChapSub.Concat(ChapterNumber.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries)).ToArray();

                ChapterObject Chapter = new ChapterObject()
                {
                    Name      = ChapterTitle,
                    Volume    = UInt32.Parse(volChapSub[0]),
                    Chapter   = UInt32.Parse(volChapSub[1]),
                    Locations =
                    {
                        new LocationObject()
                        {
                            ExtensionName     = ExtensionDescriptionAttribute.Name,
                            ExtensionLanguage = ExtensionDescriptionAttribute.Language,
                            Url = ChapterNode.SelectSingleNode(".//span[1]/a").Attributes["href"].Value
                        }
                    },
                    Released = ChapterNode.SelectSingleNode(".//span[2]").InnerText.ToLower().Equals("today") ? DateTime.Today : (ChapterNode.SelectSingleNode(".//span[2]").InnerText.ToLower().Equals("yesterday") ? DateTime.Today.AddDays(-1) : DateTime.Parse(ChapterNode.SelectSingleNode(".//span[2]").InnerText))
                };
                if (volChapSub.Length == 3)
                {
                    Chapter.SubChapter = UInt32.Parse(volChapSub[2]);
                }
                Chapters.Add(Chapter);
            }
            Chapters.Reverse();
            String Cover = MangaPropertiesNode.SelectSingleNode(".//img[1]/@src").Attributes["src"].Value;

            Cover = Cover.Substring(0, Cover.LastIndexOf('?'));

            MangaObject MangaObj = new MangaObject()
            {
                Name           = HtmlEntity.DeEntitize(MangaName),
                Description    = HtmlEntity.DeEntitize(Desciption),
                AlternateNames = (from AltName in AlternateNames select HtmlEntity.DeEntitize(AltName)).ToList(),
                CoverLocations = { new LocationObject()
                                   {
                                       Url               = Cover,
                                       ExtensionName     = ExtensionDescriptionAttribute.Name,
                                       ExtensionLanguage = ExtensionDescriptionAttribute.Language
                                   } },
                Authors  = Authors.ToList(),
                Artists  = Artists.ToList(),
                Genres   = Genres.ToList(),
                Released = Chapters.First().Released,
                Chapters = Chapters
            };

            MangaObj.AlternateNames.RemoveAll(an => an.ToLower().Equals("none"));
            MangaObj.Genres.RemoveAll(g => g.ToLower().Equals("none"));
            return(MangaObj);
        }
Пример #18
0
 //Yes the archive is a zip file, read the docs
 public static String ChapterArchiveName(this ChapterObject value, String Extension = "zip")
 {
     return(String.Format("{0}.{1}.{2}.{3}", value.Volume, value.Chapter, value.SubChapter, Extension));
 }
Пример #19
0
 public ReadChapterRequestObject(MangaObject MangaObject, ChapterObject ChapterObject)
 {
     this.MangaObject   = MangaObject;
     this.ChapterObject = ChapterObject;
 }
Пример #20
0
 public String CacheKey(MangaObject MangaObject, ChapterObject ChapterObject, PageObject PageObject)
 {
     return(String.Format("{0}/{1}/{2}", MangaObject.MangaArchiveName(CORE.MANGA_ARCHIVE_EXTENSION), ChapterObject.ChapterArchiveName(CORE.CHAPTER_ARCHIVE_EXTENSION), PageObject.PageNumber));
 }