/// <summary> /// Gets the chapter name from a manga. /// This is used because chapter names are inconsistent in MangaEdens api. /// Some chapters use chapter numbers, some use titles, some use chapter numbers in the title field. /// This formats everything to be consistent. /// </summary> /// <param name="m">The manga</param> /// <param name="i">The index of the chapter</param> /// <returns>The formated name</returns> public string GetChapterName(Manga m, int i) { if (m.chapters[i][0] != null) { if (m.chapters[i][2] != null) { if ((string)m.chapters[i][2] == ((float)m.chapters[i][0]).ToString()) { return($"Ch.{(string)m.chapters[i][2]}"); } else { return($"Ch.{(float)m.chapters[i][0]}: {(string)m.chapters[i][2]} "); } } else { return($"Ch.{(float)m.chapters[i][0]}"); } } else if (m.chapters[i][2] != null) { return($"{(string)m.chapters[i][2]}"); } else { return($"?Ch.{i + 1}?"); } }
/// <summary> /// Fetches the cover of a manga synchronously. /// </summary> /// <param name="m">The manga</param> /// <returns>The downloaded image</returns> public BitmapImage FetchCover(Manga m) { if (m.image == null) { return(null); } if (m.isLocal) { if (m.chapters.Length > 0) { foreach (var item in Directory.GetFiles((string)m.chapters[0][3])) { string p = item.ToLower(); if (p.EndsWith(".png") || p.EndsWith(".jpg") || p.EndsWith(".jpeg")) { var img = new BitmapImage(new Uri(item)); img.Freeze(); return(img); } } return(null); } else { return(null); } } else { BitmapImage img; string cachePath = $@"{AppDomain.CurrentDomain.BaseDirectory}{COVERS_CACHE_DIR}{(string)m.id}.png"; lock (fileIOLock) { if (File.Exists(cachePath)) { img = new BitmapImage(new Uri(cachePath)); } else { img = DownloadImage(API_IMG + (string)m.image); if (img == null) { return(null); } SaveImage(img, cachePath); } } img.Freeze(); return(img); } }
/// <summary> /// Load a chapter from a local path /// </summary> /// <param name="path">The path</param> /// <returns>The loaded images</returns> public BitmapImage[] LoadChapter(Manga m, int index) { List <BitmapImage> imgs = new List <BitmapImage>(); string[] files = Directory.GetFiles((string)m.chapters[index][3]); Array.Sort(files); foreach (var item in files) { string p = item.ToLower(); if (p.EndsWith(".png") || p.EndsWith(".jpg") || p.EndsWith(".jpeg")) { BitmapImage img = new BitmapImage(new Uri(p)); img.Freeze(); imgs.Add(img); } } return(imgs.ToArray()); }
public void AsyncFetchChapter(Manga m, int chIndex) { if (fetchingChapter)//Can only fetch one cahpter at a time { return; } fetchingChapter = true; //If prefetching, abort it cause were jumping to a new chapter if (mangaPrefetchThread != null) { mangaPrefetchThread.Abort(); } mangaPrefetchThread = null; prefetchedData = null; ImagePane.Children.Clear(); BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += (s, e) => {//Fetch if (m.isLocal) { e.Result = api.LoadChapter(m, chIndex); } else { e.Result = api.FetchChapter(e.Argument as string, worker); } }; worker.WorkerReportsProgress = true; worker.ProgressChanged += (s, e) => { ProgressTip = $"Fetching {e.ProgressPercentage}"; }; worker.RunWorkerCompleted += (s, e) => { LoadChapterFromData(e.Result as BitmapImage[], m, chIndex); loadPrefetchOnComplete = false; ProgressTip = "Idle"; fetchingChapter = false; AsyncFetchRecents();//Update recents panel }; worker.RunWorkerAsync(m.chapters[chIndex][3] as string); }
/// <summary> /// Fetches more detailed manga info synchronously. /// </summary> /// <param name="id">id</param> /// <returns>The manga</returns> public Manga FetchManga(string id) { using (WebClient client = new WebClient()) { try { Manga m = JsonConvert.DeserializeObject <Manga>(client.DownloadString(API_BASE + $@"/manga/{id}/")); m.title = System.Net.WebUtility.HtmlDecode(m.title); m.alias = System.Net.WebUtility.HtmlDecode(m.alias); m.description = System.Net.WebUtility.HtmlDecode(m.description); Array.Reverse(m.chapters); for (int i = 0; i < m.chapters.Length; i++) { if (m.chapters[i][0] != null) { m.chapters[i][0] = float.Parse(m.chapters[i][0].ToString()); } } m.id = id; return(m); } catch (WebException) { return(null); } } }
/// <summary> /// Loads a chapter from the date provided /// </summary> /// <param name="data">The images</param> /// <param name="m">The manga it came from</param> /// <param name="chIndex">The chapter it came from</param> public void LoadChapterFromData(BitmapImage[] data, Manga m, int chIndex) { prefetchedData = null; loadPrefetchOnComplete = false; if (!m.isLocal) { if (bookmarks.ContainsKey(m.id)) //Update bookmark buttons { if (curManga != m && ChGrid.Children.Count > bookmarks[m.id].lastChapter) { (ChGrid.Children[bookmarks[m.id].lastChapter] as Button).Background = null; } bookmarks[m.id].lastChapter = chIndex; bookmarks[m.id].lastRead = DateTime.UtcNow; } else { bookmarks.Add(m.id, new MangaBookmark() { id = m.id, lastChapter = chIndex, lastRead = DateTime.UtcNow }); } } Binding binding = new Binding(); binding.Path = new PropertyPath("ViewportWidth"); binding.Source = DisplayScroll; ImagePane.Children.Clear(); for (int i = 0; i < data.Length; i++) { Image img = new Image(); img.MouseDown += ZoomStart; img.MouseRightButtonUp += ZoomEnd; img.MouseEnter += ZoomEnter; img.MouseMove += ZoomMove; img.Source = data[i]; BindingOperations.SetBinding(img, Image.MaxWidthProperty, binding); ImagePane.Children.Add(img); } //Update bookmark buttons if (ChGrid.Children.Count > chIndex) { if (curManga == null) { (ChGrid.Children[chIndex] as Button).Background = Brushes.DarkGoldenrod; } else if (curManga == m) { (ChGrid.Children[curChIndex] as Button).Background = null; (ChGrid.Children[chIndex] as Button).Background = Brushes.DarkGoldenrod; } } curManga = m; curChIndex = chIndex; //Update top bar BarChName.Text = m.title + ", " + api.GetChapterName(m, chIndex); hasPrev = chIndex > 0; hasNext = chIndex < m.chapters.Length - 1; if (LeftToRight) //Makes sure the left and right butts are properly switched when using different read directions { LeftButt.Visibility = hasPrev ? Visibility.Visible : Visibility.Hidden; RightButt.Visibility = hasNext ? Visibility.Visible : Visibility.Hidden; DisplayScroll.ScrollToLeftEnd(); LeftButt.ToolTip = "Prev"; RightButt.ToolTip = "Next (Fetching...)"; } else { LeftButt.Visibility = hasNext ? Visibility.Visible : Visibility.Hidden; RightButt.Visibility = hasPrev ? Visibility.Visible : Visibility.Hidden; DisplayScroll.ScrollToRightEnd(); RightButt.ToolTip = "Prev"; LeftButt.ToolTip = "Next (Fetching...)"; } if (hasNext)//Prefetch next chapter if applicable { AsyncPrefetchChapter(m, chIndex + 1); } GC.Collect(); }
/// <summary> /// Loads a manga from a path and its subfolders /// Chapters are laid out based on discovery order the bfs search and their names /// Chapters discovered first will always come first /// If the discoervy depth is the same, then they are sorted by name /// </summary> /// <param name="path">The local path on disk</param> /// <returns></returns> public Manga LoadManga(string path) { Manga m = new Manga(); m.title = Path.GetFileName(path); m.author = "Meow!"; m.categories = new string[] { "Local" }; m.description = "Local files: \n" + path + "\n"; m.released = DateTime.Now.Year; m.isLocal = true; var q = new Queue <string>(); List <object[]> chapters = new List <object[]>(); q.Enqueue(path); double time = DateTime.UtcNow.ToUnixTime(); //Move through file system to find folders with atleast one image file and sort them according to the rule while (q.Count > 0) { string n = q.Dequeue(); //Checks for image file foreach (var item in Directory.GetFiles(n)) { string p = item.ToLower(); if (p.EndsWith(".png") || p.EndsWith(".jpg") || p.EndsWith(".jpeg")) { chapters.Add(new object[] { null, time, Path.GetFileName(n), n }); break; } } string[] paths = Directory.GetDirectories(n); Array.Sort(paths, (a, b) => { int ida, idb; int ai = Math.Max(0, a.LastIndexOf(Path.DirectorySeparatorChar)); int bi = Math.Max(0, b.LastIndexOf(Path.DirectorySeparatorChar)); while ((ida = ParseID(a, ref ai)) != -1 && (idb = ParseID(b, ref bi)) != -1) { if (ida > idb) { return(1); } else if (ida < idb) { return(-1); } } ai = Math.Min(a.Length, b.Length); for (int i = 0; i < ai; i++) { if (a[i] > b[i]) { return(1); } else if (a[i] < b[i]) { return(-1); } } if (a.Length > b.Length) { return(1); } if (a.Length < b.Length) { return(-1); } return(0); }); foreach (var item in paths) { q.Enqueue(item); } } m.chapters = chapters.ToArray(); return(m); }