Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Imports System.Net
- Imports System.Threading
- Imports System.IO
- ''' <summary>
- ''' A comic downloader.
- ''' </summary>
- Public Class FrmNHDownloader
- #Region "Variables and Structures"
- ''' <summary>
- ''' Number of threads. Used for limiting concurrent downloads.
- ''' </summary>
- <ThreadStatic> Shared Threads As Integer = 0
- ''' <summary>
- ''' Number of threads. Used for limiting concurrent downloads.
- ''' </summary>
- <ThreadStatic> Shared MaxThreads As Integer = 10
- ''' <summary>
- ''' The scale of the image previews in the flow layout.
- ''' </summary>
- <ThreadStatic> Shared ImageScale As Integer = 3
- ''' <summary>
- ''' The number of pages downloaded.
- ''' </summary>
- <ThreadStatic> Shared PagedDownloaded As Integer = 0
- ''' <summary>
- ''' Name of the sub-folder to place downloded items in.
- ''' </summary>
- <ThreadStatic> Shared FolderName As String
- ''' <summary>
- ''' Check if the user wants to open the folder when the comic finishes.
- ''' </summary>
- <ThreadStatic> Shared OpenOnExit As Boolean = True
- ''' <summary>
- ''' Data structure for handling comic parsing.
- ''' </summary>
- Private Class ComicData
- Public ComicURL As String
- Public Name As String
- Public NumPages As Integer
- End Class
- #End Region
- #Region "Controls and UI Functionality"
- ''' <summary>
- ''' Redraws the images when the form is resized. Updates the flow panel size.
- ''' </summary>
- ''' <param name="sender"></param>
- ''' <param name="e"></param>
- Private Sub FrmNHDownloader_ResizeEnd(sender As Object, e As EventArgs) Handles MyBase.ResizeEnd
- ResizeImages()
- End Sub
- ''' <summary>
- ''' Resizes the flow panel that contains the image previews of downloaded pages.
- ''' </summary>
- ''' <param name="sender"></param>
- ''' <param name="e"></param>
- Private Sub FrmNHDownloader_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
- FlowImages.Height = Height - 185
- FlowImages.MaximumSize = New Size(Width, 9999)
- End Sub
- ''' <summary>
- ''' Updates the size of the image previews.
- ''' </summary>
- ''' <param name="sender"></param>
- ''' <param name="e"></param>
- Private Sub TBImageSize_Scroll(sender As Object, e As EventArgs) Handles TBImageSize.ValueChanged
- ImageScale = TBImageSize.Value
- ResizeImages()
- End Sub
- ''' <summary>
- ''' Remove focus after usage. Lets users scroll throgh the images instead.
- ''' </summary>
- Private Sub TBImageSize_OnFocus(sender As Object, e As EventArgs) Handles TBImageSize.GotFocus
- FlowImages.Focus()
- End Sub
- ''' <summary>
- ''' Updates the folder name to download files to. An empty name will default to what is found online.
- ''' </summary>
- ''' <param name="sender"></param>
- ''' <param name="e"></param>
- Private Sub TxtFolder_TextChanged(sender As Object, e As EventArgs) Handles TxtFolder.TextChanged
- FolderName = TxtFolder.Text
- End Sub
- ''' <summary>
- ''' Updates the value that determines if the folder is opened when the comic finishes downloading.
- ''' </summary>
- ''' <param name="sender"></param>
- ''' <param name="e"></param>
- Private Sub ChkOpenOnCreate_CheckedChanged(sender As Object, e As EventArgs) Handles ChkOpenOnCreate.CheckedChanged
- OpenOnExit = ChkOpenOnCreate.Checked
- End Sub
- ''' <summary>
- ''' Updates the number of allowed threads.
- ''' </summary>
- ''' <param name="sender"></param>
- ''' <param name="e"></param>
- Private Sub NUDThreads_ValueChanged(sender As Object, e As EventArgs) Handles NUDThreads.ValueChanged
- MaxThreads = NUDThreads.Value
- End Sub
- ''' <summary>
- ''' Adds an image preview of the downloaded file to the flow display.
- ''' </summary>
- ''' <param name="FilePath">Path to file</param>
- Private Sub UpdateDownloadedFiles(ByVal FilePath As String)
- ' Check if Flow needs to be invoked
- If FlowImages.InvokeRequired Then
- FlowImages.Invoke(New UpdateDownloadedFilesDel(AddressOf UpdateDownloadedFiles), {FilePath})
- ElseIf File.Exists(FilePath) Then
- ' Read image from file path
- ' Create PictureBox
- ' Append PictureBox to Flow layout
- Dim Image As Image = Image.FromFile(FilePath)
- Dim PictureBox As PictureBox = New PictureBox()
- PictureBox.Image = Image
- PictureBox.SizeMode = PictureBoxSizeMode.StretchImage
- PictureBox.Width = CInt(Math.Round((FlowImages.Width) / (ImageScale + 0.1) - 10.0))
- PictureBox.Height = CInt(Math.Round(PictureBox.Width * 1.4))
- FlowImages.Controls.Add(PictureBox)
- End If
- End Sub
- Private Delegate Sub UpdateDownloadedFilesDel(ByVal FilePath As String)
- ''' <summary>
- ''' Checks how many pages there are to download and launches downloader threads.
- ''' </summary>
- ''' <param name="sender"></param>
- ''' <param name="e"></param>
- Private Sub BtnDownload_Click(sender As Object, e As EventArgs) Handles BtnDownload.Click
- PagedDownloaded = 0
- ' Check if URL is valid
- Dim URL As String = TxtComicURL.Text
- If Not URL.StartsWith("http") Then
- MessageBox.Show("Enter a valid URL")
- Return
- End If
- ' Read HTML from comic page
- Dim HTML As String = GrabHTML(URL)
- If String.IsNullOrEmpty(HTML) Then
- MessageBox.Show("Failed to grab comic HTML")
- Return
- End If
- ' Parse the comic
- Dim Data As ComicData = ParseComic(URL, HTML)
- If Data Is Nothing Then
- MessageBox.Show("Failed to parse comic data")
- Return
- End If
- ' Ensure download directory exists
- Dim DLDirectory As String = If(String.IsNullOrEmpty(FolderName), Data.Name, FolderName)
- Directory.CreateDirectory(DLDirectory)
- Process.Start(DLDirectory)
- ' Download the comic
- Dim Page As Integer = 1
- While Page <= Data.NumPages
- ' Not all comics use JPG's but we'll handle that in the download method
- Dim URLPage As String = ""
- If URL.Contains("nhentai") Then
- URLPage = Data.ComicURL & Page & ".jpg"
- ElseIf URL.Contains("myhentaicomics") Then
- URLPage = Data.ComicURL & Page.ToString("000") & ".jpg"
- End If
- LaunchDownloadThread(URLPage, Data, Page)
- Page += 1
- End While
- End Sub
- #End Region
- #Region "Utils"
- ''' <summary>
- ''' Grabs the HTML from the website at the given URL.
- ''' </summary>
- ''' <param name="URL">URL to visit.</param>
- ''' <returns>HTML of URL</returns>
- Private Function GrabHTML(URL As String) As String
- Using wc As New WebClient
- Return wc.DownloadString(URL)
- End Using
- Return Nothing
- End Function
- ''' <summary>
- ''' Parses comic data from the given HTML.
- ''' </summary>
- ''' <param name="HTML">Raw HTML to parse</param>
- ''' <returns>Comic Data</returns>
- Private Function ParseComic(URL As String, HTML As String) As ComicData
- Try
- Dim Data As New ComicData()
- ' Comic name is denoted by the title tag
- Dim ComicName As String = HTML.Substring(HTML.IndexOf("<title>") + 7)
- ComicName = ComicName.Substring(0, ComicName.IndexOf("</title>"))
- ComicName = ComicName.Trim()
- 'Substringing garbage away
- If URL.Contains("nhentai") Then
- If ComicName.Contains("nhentai") Then
- ComicName = ComicName.Substring(0, ComicName.IndexOf("nhentai"))
- End If
- If ComicName.Contains("»") Then
- ComicName = ComicName.Substring(0, ComicName.IndexOf("»"))
- End If
- End If
- ' Purge bad characters
- ComicName = ComicName.Replace("*", " ")
- ComicName = ComicName.Replace(":", "-")
- ComicName = ComicName.Replace("|", "-")
- ComicName = ComicName.Replace("?", "")
- ComicName = ComicName.Replace("/", "")
- ComicName = ComicName.Replace("\", "")
- ComicName = ComicName.Replace("<", "(")
- ComicName = ComicName.Replace(">", ")")
- ' Update comic name
- Data.Name = ComicName
- ' "pages" is only shows up inside a div
- ' Just parse around that to get the number of pages
- If URL.Contains("nhentai") Then
- Dim PagesIndex As Integer = HTML.IndexOf("pages</div>")
- Dim PagesData As String = HTML.Substring(PagesIndex - 10)
- PagesData = PagesData.Substring(0, PagesData.IndexOf(" "))
- PagesData = PagesData.Substring(PagesData.IndexOf("<div>") + 5)
- Data.NumPages = Integer.Parse(PagesData)
- ElseIf URL.Contains("myhentaicomics") Then
- ' Photos 1 - 15 of 37
- Dim PagesIndex As Integer = HTML.IndexOf("Photos 1")
- Dim PagesData As String = HTML.Substring(PagesIndex)
- PagesData = PagesData.Substring(PagesData.IndexOf("of") + 3)
- PagesData = PagesData.Substring(0, PagesData.IndexOf("</li>") - 1)
- Data.NumPages = Integer.Parse(PagesData)
- End If
- ' Read the cover image URL since its consistent, then change it a little bit
- ' so that it matches the comic page syntax.
- If URL.Contains("nhentai") Then
- Dim ComURL As String = HTML.Substring(HTML.IndexOf("content=""https://t.nhentai.net/galleries/"))
- ComURL = ComURL.Substring(0, ComURL.IndexOf("/>")).Substring(ComURL.IndexOf("http")).Replace("t.n", "i.n")
- ComURL = ComURL.Substring(0, ComURL.IndexOf("cover."))
- Data.ComicURL = ComURL
- ElseIf URL.Contains("myhentaicomics") Then
- Dim ComURL As String = HTML.Substring(HTML.IndexOf("/var/thumbs/"))
- ComURL = ComURL.Substring(0, ComURL.IndexOf("?m="))
- ComURL = ComURL.Replace("thumbs", "resizes")
- ComURL = "http://myhentaicomics.com" & ComURL.Substring(0, ComURL.LastIndexOf("/") + 1)
- Data.ComicURL = ComURL
- End If
- Return Data
- Catch : End Try
- Return Nothing
- End Function
- Private Sub ResizeImages()
- For Each control As Control In Me.FlowImages.Controls
- Dim pictureBox As PictureBox = CType(control, PictureBox)
- pictureBox.Width = CInt(Math.Round((FlowImages.Width) / (ImageScale + 0.1) - 10.0))
- pictureBox.Height = CInt(Math.Round((pictureBox.Width) * 1.4))
- Next
- End Sub
- #End Region
- #Region "Downloading"
- ''' <summary>
- ''' Starts a thread that downloads a file at the given URL.
- ''' </summary>
- ''' <param name="URL">URL to download from</param>
- ''' <param name="DATA">Additional comic data</param>
- Private Sub LaunchDownloadThread(ByVal URL As String, ByVal Data As ComicData, ByVal PageIndex As Integer)
- Dim Evaluator As Thread = New Thread(Sub() Me.Download(URL, Data, PageIndex))
- Evaluator.Start()
- End Sub
- ''' <summary>
- ''' Downloads a comic page from the given URL.
- ''' </summary>
- ''' <param name="URL">URL to download from</param>
- ''' <param name="Data">Extra comic data</param>
- ''' <param name="PageIndex">The page being downloaded</param>
- Private Sub Download(ByVal URL As String, ByVal Data As ComicData, ByVal PageIndex As Integer)
- ' Prevent too many concurrent threads.
- ' Too many download threads slows every one down.
- While Threads > MaxThreads
- Thread.Sleep(100)
- End While
- Threads += 1
- ' Try to download the file
- Try
- Dim DLDirectory As String = If(String.IsNullOrEmpty(FolderName), Data.Name, FolderName)
- Dim LocalName As String = DLDirectory & "/" & URL.Substring(URL.LastIndexOf("/") + 1)
- Using wc As New WebClient
- tryDownload(wc, URL, LocalName)
- End Using
- PagedDownloaded += 1
- Catch
- End Try
- Threads -= 1
- End Sub
- ''' <summary>
- ''' Download the file at the given url to the given local-name.
- ''' </summary>
- ''' <param name="wc"></param>
- ''' <param name="URL"></param>
- ''' <param name="LocalName"></param>
- Private Sub TryDownload(ByRef wc As WebClient, ByVal URL As String, ByVal LocalName As String)
- Try
- wc.DownloadFile(URL, LocalName)
- UpdateDownloadedFiles(LocalName)
- Catch e As WebException
- Try
- wc.DownloadFile(URL.Replace(".jpg", ".png"), LocalName.Replace(".jpg", ".png"))
- UpdateDownloadedFiles(LocalName.Replace(".jpg", ".png"))
- Catch ex As WebException : End Try
- End Try
- End Sub
- #End Region
- End Class
Advertisement
Add Comment
Please, Sign In to add comment