Exemple #1
0
        private static List<DanbooruTag> RemoveIgnoredTags(DanbooruFilenameFormat format, List<DanbooruTag> groupedTags)
        {
            foreach (DanbooruTag ignoredTag in format.IgnoredTags)
            {
                if (format.IgnoreTagsUseRegex)
                {
                    if (!String.IsNullOrWhiteSpace(format.IgnoredTagsRegex))
                    {
                        Regex re = new Regex(format.IgnoredTagsRegex, RegexOptions.IgnoreCase);

                        if (format.IgnoredTagsOnlyForGeneral)
                        {
                            groupedTags.RemoveAll(x => x.Type == DanbooruTagType.General && re.IsMatch(x.Name));
                        }
                        else
                        {
                            groupedTags.RemoveAll(x => re.IsMatch(x.Name));
                        }
                    }
                }
                else
                {
                    groupedTags.RemoveAll(x => x.Name == ignoredTag.Name);
                }
            }

            return groupedTags;
        }
Exemple #2
0
        /// <summary>
        /// For constructing TAGS_FILENAME.
        /// </summary>
        /// <param name="baseFolder"></param>
        /// <param name="format"></param>
        /// <param name="post"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public static string MakeFilename(DanbooruFilenameFormat format, DanbooruPost post)
        {
            string filename = format.FilenameFormat;
            string provider = post.Provider.Name;
            string query = post.Query;
            string searchTags = post.SearchTags;
            string originalFileName = post.FileUrl.Split('/').Last();

            // sanitizing the format
            filename = Helper.SanitizeFilename(filename, true);

            //remove extension
            originalFileName = originalFileName.Substring(0, originalFileName.LastIndexOf('.'));
            originalFileName = Uri.UnescapeDataString(originalFileName);

            filename = filename.Replace("%provider%", Helper.SanitizeFilename(provider));
            filename = filename.Replace("%id%", post.Id);
            filename = filename.Replace("%rating%", post.Rating);
            filename = filename.Replace("%md5%", post.MD5);
            filename = filename.Replace("%searchParam%", Helper.SanitizeFilename(query));
            filename = filename.Replace("%searchtag%", Helper.SanitizeFilename(searchTags));
            filename = filename.Replace("%originalFilename%", Helper.SanitizeFilename(originalFileName));

            string dtFormat = Properties.Settings.Default.DateTimeFormat;
            if (String.IsNullOrWhiteSpace(dtFormat))
                dtFormat = "yyyy-mm-dd HH:mm:ss";
            filename = filename.Replace("%uploadDateTime%", Helper.SanitizeFilename(post.CreatedAtDateTime.ToString(dtFormat)));

            // copy the tags entity to be grouped.
            var groupedTags = post.TagsEntity;

            // custom sort to prioritize some tags based on file definition
            // Issue #46 and #81
            // regex support
            if (File.Exists(PRIORITY_TAGS))
            {
                var priorityTags = ReadTagsFromTextFile(PRIORITY_TAGS);
                groupedTags.Sort((a, b) =>
                {
                    var containA = priorityTags.Exists(x => Regex.IsMatch(a.Name, x.Name));
                    var containB = priorityTags.Exists(x => Regex.IsMatch(b.Name, x.Name));

                    if (containA && !containB)
                        return -1;
                    if (!containA && containB)
                        return 1;
                    else
                        return a.CompareTo(b);
                });
            }
            else
            {
                groupedTags.Sort();
            }

            // remove ignored tags
            groupedTags = RemoveIgnoredTags(format, groupedTags);

            // artist
            var artist = FilterTags(post,
                                    groupedTags,
                                    DanbooruTagType.Artist,
                                    format.ArtistGroupLimit,
                                    format.ArtistGroupReplacement,
                                    format.MissingTagReplacement,
                                    format.IsReplaceMode,
                                    format.TagReplaceUnderscoreToSpace);
            var artistStr = Helper.SanitizeFilename(artist).Trim();
            filename = filename.Replace("%artist%", artistStr);

            // copyright
            var copyright = FilterTags(post,
                                       groupedTags,
                                       DanbooruTagType.Copyright,
                                       format.CopyrightGroupLimit,
                                       format.CopyrightGroupReplacement,
                                       format.MissingTagReplacement,
                                       format.IsReplaceMode,
                                       format.TagReplaceUnderscoreToSpace);
            var copyStr = Helper.SanitizeFilename(copyright.Trim());
            filename = filename.Replace("%copyright%", copyStr);

            // character
            var character = FilterTags(post,
                                       groupedTags,
                                       DanbooruTagType.Character,
                                       format.CharacterGroupLimit,
                                       format.CharacterGroupReplacement,
                                       format.MissingTagReplacement,
                                       format.IsReplaceMode,
                                       format.TagReplaceUnderscoreToSpace);
            var charaStr = Helper.SanitizeFilename(character.Trim());
            filename = filename.Replace("%character%", charaStr);

            // cirle
            var circle = FilterTags(post,
                                    groupedTags,
                                    DanbooruTagType.Circle,
                                    format.CircleGroupLimit,
                                    format.CircleGroupReplacement,
                                    format.MissingTagReplacement,
                                    format.IsReplaceMode,
                                    format.TagReplaceUnderscoreToSpace);
            var circleStr = Helper.SanitizeFilename(circle.Trim());
            filename = filename.Replace("%circle%", circleStr);

            // faults
            var faults = FilterTags(post,
                                    groupedTags,
                                    DanbooruTagType.Faults,
                                    format.FaultsGroupLimit,
                                    format.FaultsGroupReplacement,
                                    format.MissingTagReplacement,
                                    format.IsReplaceMode,
                                    format.TagReplaceUnderscoreToSpace);
            var faultStr = Helper.SanitizeFilename(faults.Trim());
            filename = filename.Replace("%faults%", faultStr);

            // general
            var general = FilterTags(post,
                                    groupedTags,
                                    DanbooruTagType.General,
                                    0,
                                    "",
                                    "",
                                    format.IsReplaceMode,
                                    format.TagReplaceUnderscoreToSpace);
            var generalStr = Helper.SanitizeFilename(general.Trim());
            filename = filename.Replace("%general%", generalStr);

            // all tags
            var allTempTags = groupedTags.Select(x => x.Name).ToList();
            if (format.TagReplaceUnderscoreToSpace)
            {
                for (int i = 0; i < allTempTags.Count; i++)
                {
                    allTempTags[i] = allTempTags[i].Replace("_", " ").Trim();
                }
            }
            filename = filename.Replace("%tags%", Helper.SanitizeFilename(string.Join(" ", allTempTags)));

            // append base folder from Save Folder text box
            if (format.BaseFolder.EndsWith(@"\")) filename = format.BaseFolder + filename;
            else if (!String.IsNullOrWhiteSpace(format.BaseFolder)) filename = format.BaseFolder + @"\" + filename;

            filename = filename.Substring(0, filename.Length < format.Limit ? filename.Length : format.Limit).Trim();

            return filename;
        }
Exemple #3
0
        /// <summary>
        /// For constructing TAGS_FILENAME.
        /// </summary>
        /// <param name="baseFolder"></param>
        /// <param name="format"></param>
        /// <param name="post"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public static string MakeFilename(DanbooruFilenameFormat format, DanbooruPost post)
        {
            string filename = format.FilenameFormat;
            string provider = post.Provider.Name;
            string query = post.Query;
            string searchTags = post.SearchTags;
            string originalFileName = post.FileUrl.Split('/').Last();

            // sanitizing the format
            filename = Helper.SanitizeFilename(filename, true);

            //remove extension
            originalFileName = originalFileName.Substring(0, originalFileName.LastIndexOf('.'));
            originalFileName = Uri.UnescapeDataString(originalFileName);

            filename = filename.Replace("%provider%", Helper.SanitizeFilename(provider));
            filename = filename.Replace("%id%", post.Id);
            filename = filename.Replace("%rating%", post.Rating);
            filename = filename.Replace("%md5%", post.MD5);
            filename = filename.Replace("%searchParam%", Helper.SanitizeFilename(query));
            filename = filename.Replace("%searchtag%", Helper.SanitizeFilename(searchTags));
            filename = filename.Replace("%originalFilename%", Helper.SanitizeFilename(originalFileName));

            // copy the tags entity to be grouped.
            var groupedTags = post.TagsEntity;
            groupedTags.Sort();

            // remove ignored tags
            groupedTags = RemoveIgnoredTags(format, groupedTags);

            // artist
            var artist = FilterTags(post,
                                    groupedTags,
                                    DanbooruTagType.Artist,
                                    format.ArtistGroupLimit,
                                    format.ArtistGroupReplacement,
                                    format.MissingTagReplacement,
                                    format.IsReplaceMode);
            var artistStr = Helper.SanitizeFilename(artist).Trim();
            if (String.IsNullOrEmpty(artistStr)) artistStr = DanbooruDownloader3.Properties.Settings.Default.tagNoArtistValue;
            filename = filename.Replace("%artist%", artistStr);

            // copyright
            var copyright = FilterTags(post,
                                       groupedTags,
                                       DanbooruTagType.Copyright,
                                       format.CopyrightGroupLimit,
                                       format.CopyrightGroupReplacement,
                                       format.MissingTagReplacement,
                                       format.IsReplaceMode);
            var copyStr = Helper.SanitizeFilename(copyright.Trim());
            if (String.IsNullOrEmpty(copyStr)) copyStr = DanbooruDownloader3.Properties.Settings.Default.tagNoCopyrightValue;
            filename = filename.Replace("%copyright%", copyStr);

            // character
            var character = FilterTags(post,
                                       groupedTags,
                                       DanbooruTagType.Character,
                                       format.CharacterGroupLimit,
                                       format.CharacterGroupReplacement,
                                       format.MissingTagReplacement,
                                    format.IsReplaceMode);
            var charaStr = Helper.SanitizeFilename(character.Trim());
            if (String.IsNullOrEmpty(charaStr)) charaStr = DanbooruDownloader3.Properties.Settings.Default.tagNoCharaValue;
            filename = filename.Replace("%character%", charaStr);

            // cirle
            var circleSelection = post.TagsEntity.Where<DanbooruTag>(x => x.Type == DanbooruTagType.Circle).Select(x => x.Name);
            var circle = FilterTags(post,
                                    groupedTags,
                                    DanbooruTagType.Circle,
                                    format.CircleGroupLimit,
                                    format.CircleGroupReplacement,
                                    format.MissingTagReplacement,
                                    format.IsReplaceMode);
            var circleStr = Helper.SanitizeFilename(circle.Trim());
            if (String.IsNullOrEmpty(circleStr)) circleStr = DanbooruDownloader3.Properties.Settings.Default.tagNoCircleValue;
            filename = filename.Replace("%circle%", circleStr);

            // faults
            var faultsSelection = post.TagsEntity.Where<DanbooruTag>(x => x.Type == DanbooruTagType.Faults).Select(x => x.Name);
            var faults = FilterTags(post,
                                    groupedTags,
                                    DanbooruTagType.Faults,
                                    format.FaultsGroupLimit,
                                    format.FaultsGroupReplacement,
                                    format.MissingTagReplacement,
                                    format.IsReplaceMode);
            var faultStr = Helper.SanitizeFilename(faults.Trim());
            if (String.IsNullOrEmpty(faultStr)) faultStr = DanbooruDownloader3.Properties.Settings.Default.tagNoFaultValue;
            filename = filename.Replace("%faults%", faultStr);

            // all tags
            filename = filename.Replace("%tags%", Helper.SanitizeFilename(string.Join(" ", groupedTags.Select(x => x.Name))));

            // append base folder from Save Folder text box
            if (format.BaseFolder.EndsWith(@"\")) filename = format.BaseFolder + filename;
            else if (!String.IsNullOrWhiteSpace(format.BaseFolder)) filename = format.BaseFolder + @"\" + filename;

            filename = filename.Substring(0, filename.Length < format.Limit ? filename.Length : format.Limit).Trim();

            // check if contains subdirectory
            if (filename.Contains(@"\"))
            {
                string dir = filename.Substring(0, filename.LastIndexOf(@"\"));
                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
            }

            return filename;
        }
        public void DoBatchJob(BindingList<DanbooruBatchJob> batchJob)
        {
            ToggleBatchJobButtonDelegate bjd = new ToggleBatchJobButtonDelegate(ToggleBatchJobButton);
            UpdateUiDelegate del = new UpdateUiDelegate(UpdateUi);
            UpdateUiDelegate2 del2 = new UpdateUiDelegate2(UpdateUi);
            ExtendedWebClient _clientPost = new ExtendedWebClient();
            if (batchJob != null)
            {
                UpdateStatus2("Starting Batch Job");

                for (int i = 0; i < batchJob.Count; i++)
                {
                    batchJob[i].CurrentPage = 0;
                    if (!batchJob[i].isCompleted)
                    {
                        UpdateLog("DoBatchJob", "Processing Batch Job#" + i);

                        DanbooruPostDao prevDao = null;
                        bool flag = true;
                        int currPage = 0;
                        int postCount = 0;
                        do
                        {
                            // stop/pause event handling outside
                            _pauseEvent.WaitOne(Timeout.Infinite);
                            if (_shutdownEvent.WaitOne(0))
                            {
                                batchJob[i].Status = " ==> Stopped.";
                                // toggle button
                                BeginInvoke(bjd, new object[] { true });
                                UpdateLog("DoBatchJob", "Batch Job Stopped.");
                                UpdateStatus2("Batch Job Stopped.");
                                return;
                            }

                            DanbooruPostDao d = null;
                            int imgCount = 0;
                            int skipCount = 0;

                            string url;
                            string query = "";

                            #region Construct the searchParam

                            if (batchJob[i].Provider.BoardType == BoardType.Danbooru
                                || batchJob[i].Provider.BoardType == BoardType.Shimmie2)
                            {
                                currPage = batchJob[i].CurrentPage;
                            }
                            else if (batchJob[i].Provider.BoardType == BoardType.Gelbooru)
                            {
                                if (batchJob[i].Provider.Preferred == PreferredMethod.Html)
                                {
                                    currPage = batchJob[i].CurrentPage * postCount;
                                }
                                else
                                {
                                    currPage = batchJob[i].CurrentPage;
                                }
                            }

                            DanbooruSearchParam searchParam = GetSearchParamsFromJob(batchJob[i], currPage);

                            url = batchJob[i].Provider.GetQueryUrl(searchParam);

                            #endregion Construct the searchParam

                            try
                            {
                                #region Get and load the image list

                                batchJob[i].Status = "Getting list for page: " + searchParam.Page;
                                BeginInvoke(del);
                                UpdateLog("DoBatchJob", "Downloading list: " + url);

                                d = GetBatchImageList(url, query, batchJob[i]);

                                if (d == null)
                                {
                                    // Cannot get list.
                                    UpdateLog("DoBatchJob", "Cannot load list");
                                    batchJob[i].Status = "Cannot load list.";
                                    batchJob[i].isCompleted = false;
                                    batchJob[i].isError = true;
                                    flag = false;
                                }
                                else if (d.Posts == null || d.Posts.Count == 0)
                                {
                                    // No more image
                                    UpdateLog("DoBatchJob", "No more image.");
                                    batchJob[i].Status = "No more image.";
                                    flag = false;
                                    //break;
                                }
                                else
                                {
                                    if (prevDao != null)
                                    {
                                        // identical data returned, probably no more new image.
                                        if (prevDao.RawData != null && prevDao.RawData.Equals(d.RawData))
                                        {
                                            UpdateLog("DoBatchJob", "Identical list, probably last page.");
                                            batchJob[i].Status = "Identical list, probably last page.";
                                            flag = false;
                                            //break;
                                        }
                                    }
                                    prevDao = d;

                                    batchJob[i].Total = d.PostCount;
                                    batchJob[i].CurrentPageTotal = d.Posts.Count;
                                    batchJob[i].CurrentPageOffset = d.Offset;

                                #endregion Get and load the image list

                                    postCount = d.Posts.Count;

                                    foreach (DanbooruPost post in d.Posts)
                                    {
                                        // Update progress bar
                                        object[] myArray = new object[2];
                                        myArray[0] = batchJob[i].ProcessedTotal;
                                        myArray[1] = d.PostCount < batchJob[i].Limit ? d.PostCount : batchJob[i].Limit;
                                        BeginInvoke(del2, myArray);

                                        // thread handling
                                        _pauseEvent.WaitOne(Timeout.Infinite);

                                        if (_shutdownEvent.WaitOne(0))
                                        {
                                            batchJob[i].Status = " ==> Stopped.";
                                            // toggle button
                                            BeginInvoke(bjd, new object[] { true });
                                            UpdateLog("DoBatchJob", "Batch Job Stopped.");
                                            UpdateStatus2("Batch Job Stopped.");
                                            return;
                                        }

                                        // check if have url and post is not deleted
                                        if (string.IsNullOrWhiteSpace(post.FileUrl) && (post.Status != "deleted" || chkProcessDeletedPost.Checked))
                                        {
                                            ResolveFileUrlBatch(_clientPost, post);
                                        }

                                        //Choose the correct urls
                                        var targetUrl = post.FileUrl;
                                        if (_ImageSize == "Thumb" && !String.IsNullOrWhiteSpace(post.PreviewUrl))
                                        {
                                            targetUrl = post.PreviewUrl;
                                        }
                                        else if (_ImageSize == "Jpeg" && !String.IsNullOrWhiteSpace(post.JpegUrl))
                                        {
                                            targetUrl = post.JpegUrl;
                                        }
                                        else if (_ImageSize == "Sample" && !String.IsNullOrWhiteSpace(post.SampleUrl))
                                        {
                                            targetUrl = post.SampleUrl;
                                        }

                                        batchJob[i].Status = "Downloading: " + targetUrl;
                                        BeginInvoke(del);
                                        //if (post.Provider == null) post.Provider = cbxProvider.Text;
                                        //if (post.Query == null) post.Query = txtQuery.Text;
                                        //if (post.SearchTags == null) post.SearchTags = txtTags.Text;

                                        bool download = true;

                                        // check if blacklisted
                                        if (download && post.Hidden)
                                        {
                                            ++skipCount;
                                            ++batchJob[i].Skipped;
                                            download = false;
                                            UpdateLog("DoBatchJob", "Download skipped, contains blacklisted tag: " + post.Tags + " Url: " + targetUrl);
                                        }

                                        string filename = "";
                                        if (download && !string.IsNullOrWhiteSpace(targetUrl))
                                        {
                                            var format = new DanbooruFilenameFormat()
                                            {
                                                FilenameFormat = batchJob[i].SaveFolder,
                                                Limit = Convert.ToInt32(txtFilenameLength.Text),
                                                BaseFolder = txtSaveFolder.Text,
                                                MissingTagReplacement = txtTagReplacement.Text,
                                                ArtistGroupLimit = Convert.ToInt32(txtArtistTagGrouping.Text),
                                                CharacterGroupLimit = Convert.ToInt32(txtCharaTagGrouping.Text),
                                                CopyrightGroupLimit = Convert.ToInt32(txtCopyTagGrouping.Text),
                                                CircleGroupLimit = Convert.ToInt32(txtCircleTagGrouping.Text),
                                                FaultsGroupLimit = Convert.ToInt32(txtFaultsTagGrouping.Text),
                                                IgnoredTags = DanbooruTagsDao.Instance.ParseTagsString(txtIgnoredTags.Text.Replace(Environment.NewLine, " ")),
                                                IgnoredTagsRegex = txtIgnoredTags.Text.Trim().Replace(Environment.NewLine, "|"),
                                                IgnoreTagsUseRegex = chkIgnoreTagsUseRegex.Checked,
                                                IsReplaceMode = chkReplaceMode.Checked,
                                                IgnoredTagsOnlyForGeneral = chkIgnoreForGeneralTag.Checked,
                                                TagReplaceUnderscoreToSpace = chkIsReplaceUnderscoreTag.Checked
                                            };
                                            string extension = Helper.getFileExtensions(targetUrl);
                                            filename = Helper.MakeFilename(format, post) + extension;
                                        }

                                        // check if exist
                                        if (download && !chkOverwrite.Checked)
                                        {
                                            if (File.Exists(filename))
                                            {
                                                ++skipCount;
                                                ++batchJob[i].Skipped;
                                                download = false;
                                                UpdateLog("DoBatchJob", "Download skipped, file exists: " + filename);
                                            }
                                        }
                                        if (download && String.IsNullOrWhiteSpace(targetUrl))
                                        {
                                            ++skipCount;
                                            ++batchJob[i].Skipped;
                                            download = false;
                                            UpdateLog("DoBatchJob", "Download skipped, ID: " + post.Id + " No file_url, probably deleted");
                                        }
                                        Uri uri = null;
                                        if (download && !Uri.TryCreate(targetUrl, UriKind.RelativeOrAbsolute, out uri))
                                        {
                                            ++skipCount;
                                            ++batchJob[i].Skipped;
                                            download = false;
                                            UpdateLog("DoBatchJob", "Download skipped, ID: " + post.Id + " Invalid URL: " + targetUrl);
                                        }

                                        #region download

                                        if (download)
                                        {
                                            imgCount = DoDownloadBatch(targetUrl, batchJob[i], post, filename);
                                        }

                                        #endregion download

                                        // check if more than available post
                                        if (batchJob[i].ProcessedTotal >= d.PostCount && d.PostCount != 0)
                                        {
                                            UpdateLog("DoBatchJob", "No more post.");
                                            flag = false;
                                            break;
                                        }
                                        // check if over given limit
                                        if (batchJob[i].ProcessedTotal >= batchJob[i].Limit)
                                        {
                                            UpdateLog("DoBatchJob", "Limit Reached.");
                                            flag = false;
                                            break;
                                        }

                                        // check batch job delay
                                        int delay = 0;
                                        Int32.TryParse(Properties.Settings.Default.BatchJobDelay, out delay);
                                        if ((Properties.Settings.Default.DelayIncludeSkipped || download) && delay > 0)
                                        {
                                            UpdateLog("DoBatchJob", String.Format("Waiting for {0}ms for the next post.", delay));
                                            Thread.Sleep(delay);
                                        }
                                    }
                                }
                                batchJob[i].Status = " ==> Done.";
                            }
                            catch (Exception ex)
                            {
                                string message = ex.Message;
                                string responseMessage = "";
                                if (ex.InnerException != null)
                                {
                                    message += Environment.NewLine + "Inner: " + ex.InnerException.Message;
                                }
                                message += Environment.NewLine + "Stack Trace: " + Environment.NewLine + ex.StackTrace;
                                message += Environment.NewLine + "Query: " + batchJob[i].TagQuery;

                                batchJob[i].isError = true;
                                batchJob[i].isCompleted = false;

                                if (ex.GetType() == typeof(System.Net.WebException))
                                {
                                    System.Net.WebException wex = (System.Net.WebException)ex;

                                    if (wex.Status == WebExceptionStatus.ProtocolError &&
                                        wex.Response.Headers.AllKeys.Contains("Status") &&
                                        wex.Response.Headers["Status"].ToString() == "500")
                                    {
                                        using (var response = wex.Response.GetResponseStream())
                                        {
                                            if (response != null)
                                            {
                                                var option = new DanbooruPostDaoOption()
                                                {
                                                    Provider = _currProvider,
                                                    Query = query,
                                                    SearchTags = batchJob[i].TagQuery,
                                                    Url = url,
                                                    Referer = "",
                                                    BlacklistedTags = TagBlacklist,
                                                    BlacklistedTagsRegex = TagBlacklistRegex,
                                                    BlacklistedTagsUseRegex = chkBlacklistTagsUseRegex.Checked,
                                                    IgnoredTags = TagIgnore,
                                                    IgnoredTagsRegex = TagIgnoreRegex,
                                                    IgnoredTagsUseRegex = chkIgnoreTagsUseRegex.Checked,
                                                    IsBlacklistOnlyForGeneral = chkBlacklistOnlyGeneral.Checked
                                                };
                                                var resp = new DanbooruPostDao(response, option);
                                                responseMessage = resp.ResponseMessage;
                                                flag = false;
                                            }
                                        }
                                    }
                                }
                                if (ex.Message.Contains("(400)") ||
                                    ex.Message.Contains("(403)") ||
                                    ex.Message.Contains("(500)") ||
                                    ex.Message.Contains("resolved"))
                                {
                                    flag = false;
                                }
                                batchJob[i].Status = " ==> Error: " + (string.IsNullOrWhiteSpace(responseMessage) ? ex.Message : responseMessage) + Environment.NewLine;
                                if (!string.IsNullOrWhiteSpace(responseMessage)) UpdateLog("DoBatchJob", "Server Message: " + responseMessage, ex);
                                else UpdateLog("DoBatchJob", "Error: " + message, ex);

                                if (cbxAbortOnError.Checked)
                                {
                                    MessageBox.Show(message, "Batch Download");
                                    break;
                                }
                            }
                            finally
                            {
                                BeginInvoke(del);
                                {
                                    // Update progress bar
                                    object[] myArray = new object[2];
                                    myArray[0] = batchJob[i].ProcessedTotal;
                                    if (d != null)
                                    {
                                        myArray[1] = d.PostCount < batchJob[i].Limit ? d.PostCount : batchJob[i].Limit;
                                    }
                                    else
                                    {
                                        myArray[1] = -1;
                                    }
                                    BeginInvoke(del2, myArray);
                                }
                            }
                            ++batchJob[i].CurrentPage;
                        } while (flag);

                        UpdateLog("DoBatchJob", "Batch Job #" + i + ": Done");
                        if (batchJob[i].isError)
                        {
                            batchJob[i].isCompleted = false;
                        }
                        else
                        {
                            batchJob[i].isCompleted = true;
                        }
                        BeginInvoke(del);
                    }
                }
            }
            BeginInvoke(bjd, new object[] { true });
            UpdateStatus2("Batch Job Completed!", true);
            {
                // hide progress bar
                object[] myArray = new object[2];
                myArray[0] = -1;
                myArray[1] = -1;
                BeginInvoke(del2, myArray);
            }
        }
        private string MakeCompleteFilename(DanbooruPost post, string url)
        {
            var format = new DanbooruFilenameFormat()
            {
                FilenameFormat = txtFilenameFormat.Text,
                Limit = Convert.ToInt32(txtFilenameLength.Text),
                BaseFolder = txtSaveFolder.Text,
                MissingTagReplacement = txtTagReplacement.Text,
                ArtistGroupLimit = Convert.ToInt32(txtArtistTagGrouping.Text),
                CharacterGroupLimit = Convert.ToInt32(txtCharaTagGrouping.Text),
                CopyrightGroupLimit = Convert.ToInt32(txtCopyTagGrouping.Text),
                CircleGroupLimit = Convert.ToInt32(txtCircleTagGrouping.Text),
                FaultsGroupLimit = Convert.ToInt32(txtFaultsTagGrouping.Text),
                IgnoredTags = DanbooruTagsDao.Instance.ParseTagsString(txtIgnoredTags.Text.Replace(Environment.NewLine, " ")),
                IgnoredTagsRegex = txtIgnoredTags.Text.Trim().Replace(Environment.NewLine, "|"),
                IgnoreTagsUseRegex = chkIgnoreTagsUseRegex.Checked,
                IsReplaceMode = chkReplaceMode.Checked,
                IgnoredTagsOnlyForGeneral = chkIgnoreForGeneralTag.Checked,
                TagReplaceUnderscoreToSpace = chkIsReplaceUnderscoreTag.Checked
            };

            string extension = Helper.getFileExtensions(url);
            string filename = Helper.MakeFilename(format, post) + extension;
            return filename;
        }
        /// <summary>
        /// Async, will be called from event handler client file download.
        /// </summary>
        /// <param name="i"> downloadList index</param>
        public void DownloadRows(DataGridViewRow row)
        {
            if (_isCanceled) return;

            if (CheckDownloadGrid())
            {
                _isDownloading = true;

                // Update the progress bar
                tsProgress2.Visible = true;
                tsProgress2.Maximum = row.DataGridView.Rows.Count;
                tsProgress2.Value = row.Index > tsProgress2.Maximum ? tsProgress2.Maximum : row.Index + 1;
                tsProgressBar.Style = ProgressBarStyle.Continuous;

                if (_isPaused)
                {
                    DialogResult result = MessageBox.Show("Paused." + Environment.NewLine + "Click OK to continue.", "Download", MessageBoxButtons.OKCancel);
                    _isPaused = false;
                    btnPauseDownload.Enabled = true;

                    if (result.Equals(DialogResult.Cancel))
                    {
                        EnableDownloadControls(true);
                        tsStatus.Text = "Canceled.";
                        _isDownloading = false;
                        return;
                    }
                }

                tsStatus.Text = "Downloading Post #" + row.Index;

                DanbooruPost post = _downloadList[row.Index];

                if (!post.Completed)
                {
                    row.Selected = true;

                    if (chkAutoFocus.Checked) dgvDownload.FirstDisplayedScrollingRowIndex = row.Index;

                    string url = (string)row.Cells["colUrl2"].Value;
                    Uri uri = null;

                    if (string.IsNullOrWhiteSpace(url))
                    {
                        ResolveFileUrl(post);
                    }

                    if (url == Constants.LOADING_URL)
                    {
                        // still loading post url
                        row.Cells["colProgress2"].Value = "Still loading post url, try again later.";
                        UpdateLog("[DownloadRow]", "Still loading post url, try again later.: " + row.Index);
                    }
                    else if (url == Constants.NO_POST_PARSER)
                    {
                        // no parser post url
                        row.Cells["colProgress2"].Value = "No post parser for provider: " + post.Provider;
                        UpdateLog("[DownloadRow]", "No post parser for provider: " + post.Provider + " at : " + row.Index);
                    }
                    else if (post.Status == "deleted" && !chkProcessDeletedPost.Checked)
                    {
                        row.Cells["colProgress2"].Value = "Post is deleted.";
                        UpdateLog("[DownloadRow]", "Post is deleted for row: " + row.Index);
                    }
                    else if (!string.IsNullOrWhiteSpace(url) &&
                             Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out uri)) // check if post active and url valid
                    {
                        if (post.Provider == null) post.Provider = _listProvider[cbxProvider.SelectedIndex];
                        if (post.Query == null) post.Query = txtQuery.Text;
                        if (post.SearchTags == null) post.SearchTags = txtTags.Text;

                        var format = new DanbooruFilenameFormat()
                        {
                            FilenameFormat = txtFilenameFormat.Text,
                            Limit = Convert.ToInt32(txtFilenameLength.Text),
                            BaseFolder = txtSaveFolder.Text,
                            MissingTagReplacement = txtTagReplacement.Text,
                            ArtistGroupLimit = Convert.ToInt32(txtArtistTagGrouping.Text),
                            CharacterGroupLimit = Convert.ToInt32(txtCharaTagGrouping.Text),
                            CopyrightGroupLimit = Convert.ToInt32(txtCopyTagGrouping.Text),
                            CircleGroupLimit = Convert.ToInt32(txtCircleTagGrouping.Text),
                            FaultsGroupLimit = Convert.ToInt32(txtFaultsTagGrouping.Text),
                            IgnoredTags = DanbooruTagsDao.Instance.ParseTagsString(txtIgnoredTags.Text.Replace(Environment.NewLine, " ")),
                            IgnoredTagsRegex = txtIgnoredTags.Text.Trim().Replace(Environment.NewLine, "|"),
                            IgnoreTagsUseRegex = chkIgnoreTagsUseRegex.Checked,
                            IsReplaceMode = chkReplaceMode.Checked,
                            IgnoredTagsOnlyForGeneral = chkIgnoreForGeneralTag.Checked
                        };

                        string extension = Helper.getFileExtensions(url);
                        string filename = Helper.MakeFilename(format, post) + extension;

                        if (chkOverwrite.Checked || !File.Exists(filename))
                        {
                            string dir = filename.Substring(0, filename.LastIndexOf(@"\"));
                            if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);

                            row.Cells["colFilename"].Value = filename;
                            var filename2 = filename + ".!tmp";
                            if (File.Exists(filename2))
                            {
                                row.Cells["colProgress2"].Value = "Deleting temporary file: " + filename2;
                                File.Delete(filename2);
                            }

                            // the actual download
                            _clientFile.Referer = post.Referer;
                            Program.Logger.Info("[DownloadRow] Downloading " + url);
                            Program.Logger.Info("[DownloadRow] Saved to    " + filename);
                            row.Cells["colDownloadStart2"].Value = DateTime.Now;
                            _clientFile.DownloadFileAsync(uri, filename2, row);
                            txtLog.AppendText("[clientFileDownload] Saving to " + filename2 + Environment.NewLine);
                            return;
                        }
                        else
                        {
                            // File exist and overwrite is no checked.
                            row.Cells["colProgress2"].Value = "File exists!";
                            UpdateLog("[DownloadRow]", "File exists: " + filename);
                        }
                    }
                    else
                    {
                        // no valid url
                        row.Cells["colProgress2"].Value = "No valid file_url, probably deleted.";
                        UpdateLog("[DownloadRow]", "No valid file_url for row: " + row.Index);
                    }
                }

                // proceed with the next row
                if (row.Index < dgvDownload.Rows.GetLastRow(DataGridViewElementStates.None))
                {
                    DownloadRows(dgvDownload.Rows[row.Index + 1]);
                }
                else
                {
                    // no more row
                    _isPaused = false;
                    _isDownloading = false;
                    ShowMessage("Download List", "Download Complete!");
                    EnableDownloadControls(true);
                    tsProgress2.Visible = false;
                }
            }
        }