コード例 #1
0
        private void FormSync_Load(object sender, EventArgs e)
        {
            listViewSyncUp.View          = View.Details;
            listViewSyncUp.FullRowSelect = true;
            listViewSyncUp.Sorting       = SortOrder.Ascending;
            listViewSyncUp.HideSelection = false; // keep selection highlighted (grey) on blur

            listViewSyncUp.Columns.Clear();
            listViewSyncUp.Columns.Add("Name", nameWidth, HorizontalAlignment.Left);
            listViewSyncUp.Columns.Add("Qty", qtyWidth, HorizontalAlignment.Center);
            listViewSyncUp.Columns.Add("Size", sizeWidth, HorizontalAlignment.Right);


            // meh .. seems have to use resizing events
            // listViewSyncUp.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent);

            ResizeColumns();

            ListVideoInfo.Save();

            Sync.Load();
            if (Sync.syncSettings.syncUp == DateTime.MinValue)
            {
                MyFormField.SetLabelText(labelLastSyncUp, "Not yet");
            }
            else
            {
                MyFormField.SetLabelText(labelLastSyncUp, Sync.syncSettings.syncUp);
            }

            SetList();
        }
コード例 #2
0
        private void buttonRemoveSource_Click(object sender, EventArgs e)
        {
            MyFormField.DelayButtonClick(buttonRemoveSource);

            if (currentSource == null)
            {
                return;
            }

            string message = "Are you sure you want to remove this Video Source?" + Environment.NewLine;

            message += "Alias: " + currentSource.alias + Environment.NewLine;
            message += "Type: " + currentSource.type + Environment.NewLine;
            message += "Directory: " + currentSource.directory + Environment.NewLine;
            string lastScanned = currentSource.lastScanned.ToLocalTime().ToString();

            if (currentSource.lastScanned == DateTime.MinValue)
            {
                lastScanned = "Not yet";
            }
            message += "Last Scanned: " + lastScanned + Environment.NewLine;

            if (MessageBox.Show(message, "Confirm Removal",
                                MessageBoxButtons.YesNo, MessageBoxIcon.Question,
                                MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Yes)
            {
                listViewSource.SelectedItems[0].Remove();


                // remove entry from settings
                Config.settings.sources.Remove(currentSource);

                List <VideoInfo> currentVideoInfos = ListVideoInfo.GetList();
                int nbrOrigVideoInfos = currentVideoInfos.Count();
                currentVideoInfos.RemoveAll(s => s.sourceAlias == currentSource.alias);
                int nbrRemovedVideoInfos = nbrOrigVideoInfos - currentVideoInfos.Count();
                ListVideoInfo.SetList(currentVideoInfos);

                // meh, but works
                FormMain        formMain        = (FormMain)this.Owner;
                SubFormListView subFormListView = formMain.GetSubFormListView();
                subFormListView.SetListViewInfos(ListVideoInfo.GetList());

                MyLog.Add("Removed " + currentSource.alias + " and it's " + nbrRemovedVideoInfos + " VideoItems");

                // datatable xml will be updated on main form close
                // settings xml will be updated on main form close

                currentSource = null;
                buttonRemoveSource.Enabled = false;
            }
        }
コード例 #3
0
 public void RunCalcStats(object sender, RunWorkerCompletedEventArgs e)
 {
     MyLog.Add("Setting Stats");
     subFormProgress.Value(0);
     subFormProgress.Text("Setting Stats..");
     if (!CalcVideoInfoStats.Load())
     {
         stopwatchCalcStats = Stopwatch.StartNew(); // stopped when background worker completed
         calcVideoInfoStats.Calc(ListVideoInfo.GetList());
     }
     else
     {
         LoadVideos_Completed(sender, e);
     }
 }
コード例 #4
0
        /// <summary>
        /// ensure some fields are set in listVideoItems
        /// </summary>
        /// <returns></returns>
        public static bool EnsureVideoInfos()
        {
            int index = 0;

            foreach (VideoInfo videoInfo in listVideoInfos)
            {
                // may not be neccessary to re-calc hash .. prob somewhat expensive to do
                string hash = ListVideoInfo.CreateHash(videoInfo);
                listVideoInfos[index].hash = hash;

                // set index; used for quick search
                listVideoInfos[index].index = index;
                index++;
            }
            return(true);
        }
コード例 #5
0
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            loadVideos.AbortBackgroundWorkers();

            // meh
            Application.DoEvents();

            // save settings
            if (!Config.Save(this))
            {
            }

            // save video sources
            if (!ListVideoInfo.Save())
            {
            }
        }
コード例 #6
0
        private int CalcStatsForSource(string sourceAlias)
        {
            List <VideoInfo> listVideoInfos = ListVideoInfo.GetList();

            if (listVideoInfos == null)
            {
                return(0);
            }

            listVideoInfos = listVideoInfos.FindAll(x => x.sourceAlias == sourceAlias).ToList();
            if (listVideoInfos == null)
            {
                return(0);
            }

            int nbrVideos = listVideoInfos.Where(x => x.files != null && x.files.video != null).Count();


            return(nbrVideos);
        }
コード例 #7
0
        /// <summary>
        /// load videos from disk into list
        /// </summary>
        public void FilterListView()
        {
            stopwatch = Stopwatch.StartNew(); // stopped when background worker completed

            FilterInfo filterInfo = subFormFilterForm.GetFilterForm();

            subFormListView.listViewColumnSorter.sortColumnIndex = FilterEnums.sortColumn.GetValueByKey(filterInfo.sortColumn);
            subFormListView.listViewColumnSorter.sortOrderIndex  = filterInfo.sortOrderIndex;


            subFormFilterForm.Enabled = false;
            subFormListView.Enabled   = false;
            subFormVideoForm.Enabled  = false;
            subFormGallery.Enabled    = false;


            MyLog.Add("Filter sources -->");
            // since static, no need to pass in .. but has allowed for conatiner to be replaced .. tree, datatabel, etc
            backgroundWorkerFilterSource.Run(ListVideoInfo.GetList(), filterInfo);
        }
コード例 #8
0
        // after form loaded
        private void FormMain_Shown(object sender, EventArgs e)
        {
            MyFormField.HighlightFormFieldsOnFocus(this);

            loadVideos.AddAccessToSubForms(subFormListView, subFormGallery, subFormVideoForm, subFormFilterForm, subFormProgressMain);


            Application.DoEvents(); // meh



            // ensure required app dirs exist
            MyFile.EnsureDirectoryExists(@"cache");
            MyFile.EnsureDirectoryExists(@"cache\gallery");
            MyFile.EnsureDirectoryExists(@"config");
            MyFile.EnsureDirectoryExists(@"data");
            MyFile.EnsureDirectoryExists(@"filters");
            MyFile.EnsureDirectoryExists(@"libs");
            MyFile.EnsureDirectoryExists(@"libs\ffmpeg\bin");
            MyFile.EnsureDirectoryExists(@"logs");
            MyFile.EnsureDirectoryExists(@"stats");
            MyFile.EnsureDirectoryExists(@"sync");



            if (Config.settings.sources.Count == 0)
            {
                MessageBox.Show("No Video Sources found. Add some and Scan..");
                ShowFormSources();
                return;
            }

            if (ListVideoInfo.Load())
            {
                loadVideos.FilterListView();
            }
            else
            {
                loadVideos.LoadFromDisk();
            }
        }
コード例 #9
0
        protected void BackgroundWorkerBuildGalleryImages_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // result of scan .. continue processing ..

            stopwatchBuildGalleryImages.Stop();
            MyLog.AddElapsed(stopwatchBuildGalleryImages.Elapsed);

            List <VideoInfo> videoInfos = (List <VideoInfo>)sender;

            if (videoInfos != null)
            {
                // set list again so get gallery thumbnails
                ListVideoInfo.SetList(videoInfos);

                MyLog.Add("Setting Gallery");
                subFormProgress.Value(0);
                subFormProgress.Text("Setting Gallery..");
                subFormGallery.SetPosters(ListVideoInfo.GetList());
            }

            RunCalcStats(sender, e);
        }
コード例 #10
0
        private void CalcStatsForSource(ConfigSettings.Source source)
        {
            List <VideoInfo> listVideoInfos = ListVideoInfo.GetList();

            if (listVideoInfos == null)
            {
                return;
            }

            listVideoInfos = listVideoInfos.FindAll(x => x.sourceAlias == source.alias).ToList();
            if (listVideoInfos == null)
            {
                return;
            }

            int nbrVideos = listVideoInfos.Where(x => x.files != null && x.files.video != null).Count();

            // int nbrPosters = listVideoInfos.Where(x => x.files != null && x.files.poster != null).Count();
            // int nbrFanarts = listVideoInfos.Where(x => x.files != null && x.files.fanart != null).Count();
            // int nbrImages = listVideoInfos.Where(x => x.files != null && x.files.images != null).Count();

            // int nbrMBs = listVideoInfos.Where(x => x.files != null && x.files.mb != null).Count();
            // int nbrMVEs = listVideoInfos.Where(x => x.files != null && x.files.mve != null).Count();
            // int nbrXBMCs = listVideoInfos.Where(x => x.files != null && x.files.xbmc != null).Count();

            // int nbrOthers = listVideoInfos.Where(x => x.files != null && x.files.others != null).Count();

            int nbrFiles = listVideoInfos.Where(x => x.files != null).Sum(x => x.files.qty);

            // int nbrNonVideos = nbrImages + nbrMBs + nbrMVEs + nbrXBMCs + nbrOthers;
            int nbrNonVideos = nbrFiles - nbrVideos;


            labelVideoFileQty.Text = nbrVideos.ToString();


            labelOtherFilesQty.Text = nbrNonVideos.ToString();
        }
コード例 #11
0
        public static bool ThumbnailsAlreadySet()
        {
            List <VideoInfo> videoInfos = ListVideoInfo.GetList();
            int nbrThumbnails           = videoInfos.Where(x => x.files.posterThumbnail != null).Count();

            long thumbnailCachesize = MyFile.DirectorySize(@"cache\gallery", "poster*.jpg");

            bool thumbnailsSet;

            // if thumbnails set in list (nbrThumbnails > 0), but cache empty (thumbnailCachesize == 0)
            // assume intent is to rebuild app thumbnails, so thumbnailsSet = false

            // so thumbnails set only if set in list and set in cache
            if (nbrThumbnails > 0 && thumbnailCachesize > 0)
            {
                thumbnailsSet = true;
            }
            else
            {
                thumbnailsSet = false;
            }
            return(thumbnailsSet);
        }
コード例 #12
0
        private void buttonScan_Click(object sender, EventArgs e)
        {
            Button button = (Button)sender;

            if (selectedVideoInfo != null && selectedVideoInfo.videoItem != null)
            {
                button.Enabled = false;
                button.Text    = "Scanning..";

                string directory = selectedVideoInfo.videoDirectory;
                MyLog.Add("Scanning: " + directory);

                ParseVideo parseVideo = new ParseVideo();
                selectedVideoInfo = parseVideo.ReadDirectory(directory);


                subFormFileList.SetList(selectedVideoInfo);
                SetForm(selectedVideoInfo);
                ListVideoInfo.UpdateVideoInfoList(selectedVideoInfo);


                MyFormField.DelayButtonClick(button, "Scan");
            }
        }
コード例 #13
0
 public VideoItem MergeVideoItemWith(VideoInfo videoInfo)
 {
     return(ListVideoInfo.MergeVideoItems(videoItem, videoInfo.videoItem));
 }
コード例 #14
0
        public List <VideoInfosScanSource> ScanSource(List <string> sources, DoWorkEventArgs doWorkEvent)
        {
            if (sources.Count() == 0)
            {
                throw new ArgumentException("sources cannot be empty", "sources");
            }

            ParseVideo parseVideo = new ParseVideo();


            // Abort the operation if the user has canceled.
            // Note that a call to CancelAsync may have set
            // CancellationPending to true just after the
            // last invocation of this method exits, so this
            // code will not have the opportunity to set the
            // DoWorkEventArgs.Cancel flag to true. This means
            // that RunWorkerCompletedEventArgs.Cancelled will
            // not be set to true in your RunWorkerCompleted
            // event handler. This is a race condition.

            if (backgroundWorker.CancellationPending)
            {
                doWorkEvent.Cancel = true;
                return(null);
            }



            // Data structure to hold names of subfolders to be examined for files.
            Stack <DirInfo> dirNodes = new Stack <DirInfo>(1000);

            List <VideoInfosScanSource> videoInfosScanSources = new List <VideoInfosScanSource>();

            percentComplete = 0;
            backgroundWorker.ReportProgress(percentComplete, "Processing sources..");



            // get the root dirs from each source
            int nbrSources       = sources.Count();
            int processingSource = 0;

            foreach (string source in sources)
            {
                percentComplete = (int)Math.Floor((double)processingSource / (double)nbrSources * 100);
                backgroundWorker.ReportProgress(percentComplete, "Scanning source " + source + "..");

                List <VideoInfo> videoInfos = new List <VideoInfo>(10000);

                string sourceAlias = Config.SourceDirectory2Alias(source);

                IEnumerable <string> directories = MyFile.EnumerateDirectories(source, "*", SearchOption.AllDirectories);

                int nbrDirectories      = directories.Count();
                int processingDirectory = 0;
                foreach (string directory in directories)
                {
                    MyLog.Add("Scanning: " + directory);

                    VideoInfo videoInfo = parseVideo.ReadDirectory(directory);

                    if (videoInfo == null || videoInfo.videoItem == null || videoInfo.videoItem.title == null ||
                        videoInfo.files == null || videoInfo.files.video == null)
                    {
                        processingDirectory++;
                        continue;
                    }

                    videoInfo.sourceAlias    = sourceAlias;
                    videoInfo.videoDirectory = directory;

                    // see if any existing item or new
                    videoInfo.index = videoInfos.Count;
                    string hash = ListVideoInfo.CreateHash(videoInfo);
                    videoInfo.hash = hash;
                    VideoInfo foundVideoInfo = ListVideoInfo.FindVideoInfo("hash", hash);

                    bool bNew = false;
                    if (foundVideoInfo == null)
                    {
                        bNew = true;
                    }
                    if (bNew || foundVideoInfo.added == null || foundVideoInfo.added == DateTime.MinValue)
                    {
                        videoInfo.added = DateTime.UtcNow;
                    }
                    if (bNew || foundVideoInfo.updated == null || foundVideoInfo.updated == DateTime.MinValue)
                    {
                        videoInfo.updated = videoInfo.added;
                    }

                    if (!bNew)
                    {
                        // TODO ? needed? found item in list, merge list item with scanned item, scanned item wins
                        videoInfo = ListVideoInfo.MergeVideoInfos(foundVideoInfo, videoInfo);
                    }

                    videoInfos.Add(videoInfo);

                    processingDirectory++;
                    if (processingDirectory % 1 == 0)
                    {
                        percentComplete = (int)Math.Floor((double)processingDirectory / (double)nbrDirectories * 100);
                        string progressMessage = "Scanned " + processingDirectory + " of " + nbrDirectories + " directories\n" + directory.Split(Path.DirectorySeparatorChar).Last() + "..";
                        // progressMessage = directory.Split(Path.DirectorySeparatorChar).Last() + "..";
                        backgroundWorker.ReportProgress(percentComplete, progressMessage);

                        // Thread.Sleep(1000); // dev

                        if (backgroundWorker.CancellationPending)
                        {
                            doWorkEvent.Cancel = true;
                            return(null);
                        }
                    }
                } // foreach directory


                VideoInfosScanSource videoInfosScanSource = new VideoInfosScanSource();
                videoInfosScanSource.videoInfos  = videoInfos;
                videoInfosScanSource.sourceAlias = sourceAlias;

                videoInfosScanSources.Add(videoInfosScanSource);


                processingSource++;
            } // end foreach source

            // add items to main list .. but not here .. in completed event
            // ListVideoInfo.Clear();
            // ListVideoInfo.AddItems(videoInfos);



            percentComplete = 100;
            backgroundWorker.ReportProgress(percentComplete, "Completed scan");

            // meh, so completed msg shows
            Thread.Sleep(500);


            return(videoInfosScanSources);
        }
コード例 #15
0
        public bool SaveForm()
        {
            // MyLog.Add("SaveForm");

            bool      ret       = true;
            VideoItem videoItem = selectedVideoInfo.videoItem;

            if (comboBoxIMDBRating.Text == "")
            {
                comboBoxIMDBRating.Text = "0";
            }
            videoItem.imdbRating = Convert.ToDecimal(comboBoxIMDBRating.Text);
            videoItem.lastPlayed = (DateTime)labelLastPlayed.Tag;
            videoItem.movieset   = textBoxMovieSet.Text;
            videoItem.mpaa       = comboBoxMPAA.Text;
            videoItem.notes      = richTextBoxNotes.Text;
            if (comboBoxPlayCount.Text == "")
            {
                comboBoxPlayCount.Text = "0";
            }
            videoItem.playCount = Convert.ToInt32(comboBoxPlayCount.Text);
            videoItem.plot      = richTextBoxPlot.Text;
            if (comboBoxRating.Text == "")
            {
                comboBoxRating.Text = "0";
            }
            videoItem.rating = Convert.ToInt32(comboBoxRating.Text);
            if (textBoxRunTime.Text == "")
            {
                textBoxRunTime.Text = "0";
            }
            videoItem.runtime = Convert.ToInt32(textBoxRunTime.Text);
            videoItem.title   = textBoxTitle.Text;


            videoItem.actors    = new List <VideoItemActor <string, string> > {
            };
            videoItem.directors = new List <VideoItemDirector <string> > {
            };
            for (int index = dataGridViewActors.Rows.Count - 1; index >= 0; index--)
            {
                if (dataGridViewActors.Rows[index].IsNewRow)
                {
                    continue;
                }
                string name = dataGridViewActors.Rows[index].Cells[0].Value.ToString();
                string role = dataGridViewActors.Rows[index].Cells[1].Value.ToString();
                if (!String.IsNullOrWhiteSpace(name) && !String.IsNullOrWhiteSpace(role))
                {
                    if (role.ToLower() == "director")
                    {
                        videoItem.directors.Add(new VideoItemDirector <string>(name));
                    }
                    else
                    {
                        // VideoItemActor<string, string> actor = new VideoItemActor<string, string>(name, role);
                        videoItem.actors.Add(new VideoItemActor <string, string>(name, role));
                    }
                }
            }

            videoItem.tags = new List <VideoItemTag <string> > {
            };
            for (int index = dataGridViewTags.Rows.Count - 1; index >= 0; index--)
            {
                if (dataGridViewTags.Rows[index].IsNewRow)
                {
                    continue;
                }
                string tag = dataGridViewTags.Rows[index].Cells[0].Value.ToString();
                if (!String.IsNullOrWhiteSpace(tag))
                {
                    videoItem.tags.Add(new VideoItemTag <string>(tag));
                }
            }

            videoItem.genres = new List <VideoItemGenre <string> > {
            };
            for (int index = dataGridViewGenres.Rows.Count - 1; index >= 0; index--)
            {
                if (dataGridViewGenres.Rows[index].IsNewRow)
                {
                    continue;
                }
                string genre = dataGridViewGenres.Rows[index].Cells[0].Value.ToString();
                if (!String.IsNullOrWhiteSpace(genre))
                {
                    videoItem.genres.Add(new VideoItemGenre <string>(genre));
                }
            }


            // videoItem.tagline = textBoxTagLine.Text; // not yet

            videoItem.upc    = textBoxUPC.Text;
            videoItem.tmdbId = textBoxTMDB.Text;
            videoItem.imdbId = textBoxIMDB.Text;

            videoItem.source  = comboBoxSource.Text;
            videoItem.version = comboBoxVersion.Text;
            videoItem.watched = checkBoxWatched.Checked ? "YES" : "NO";

            if (comboBoxYear.Text == "")
            {
                comboBoxYear.Text = "0";
            }
            videoItem.year = Convert.ToInt32(comboBoxYear.Text);

            videoItem.encoding.codec = comboBoxCodec.Text;
            if (textBoxBitrate.Text == "")
            {
                textBoxBitrate.Text = "0";
            }
            videoItem.encoding.bitrate = Convert.ToInt32(textBoxBitrate.Text);
            if (textBoxHeight.Text == "")
            {
                textBoxHeight.Text = "0";
            }
            videoItem.encoding.height = Convert.ToInt32(textBoxHeight.Text);
            if (textBoxWidth.Text == "")
            {
                textBoxWidth.Text = "0";
            }
            videoItem.encoding.width = Convert.ToInt32(textBoxWidth.Text);

            // selectedVideoInfo.source = labelSource.Text; // readonly
            // selectedVideoInfo.directory = labelDirectory.Text; // readonly

            selectedVideoInfo.updated = DateTime.UtcNow;
            selectedVideoInfo.edited  = true;

            // reset form in case prior validation changed any fields
            selectedVideoInfo.videoItem = videoItem;
            SetForm(selectedVideoInfo);

            if (!ListVideoInfo.SettingsOkToSaveVideoInfo())
            {
                MessageBox.Show("Nothing to save to.\nNot configured to save Video infomration.\nChange in Tools -> Options.");
                ret = false;
            }
            else
            {
                if (ListVideoInfo.SaveVideoInfo(selectedVideoInfo))
                {
                    buttonSave.Text = "Saved";
                    ret             = true;
                }
                else
                {
                    buttonSave.Text = "Error";
                    ret             = false;
                }
            }
            return(ret);
        }
コード例 #16
0
        /// <summary>
        /// background process getting VideoInfos completed
        /// used for ScanSource and FilterSource
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VideoInfos_RunWorkerCompleted(string action, string message, object sender, RunWorkerCompletedEventArgs e)
        {
            // First, handle the case where an exception was thrown.
            if (e.Error != null)
            {
                MyLog.Add(e.Error.ToString());
                subFormProgress.Text(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                // Next, handle the case where the user canceled the operation.
                // Note that due to a race condition in the DoWork event handler, the Cancelled
                // flag may not have been set, even though CancelAsync was called.
                subFormProgress.Text("Canceled");
            }
            else
            {
                // Finally, handle the case where the operation  succeeded.

                if (action == "scan")
                {
                    List <VideoInfosScanSource> videoInfosScanSources = (List <VideoInfosScanSource>)e.Result;

                    if (videoInfosScanSources == null)
                    {
                        MyLog.Add(message + " Null VideoItems");
                        MyLog.AddElapsed(stopwatch.Elapsed);
                        LoadVideos_Completed(sender, e);
                        return;
                    }

                    MyLog.Add(message);
                    MyLog.AddElapsed(stopwatch.Elapsed);

                    subFormProgress.Text("Applying..");
                    subFormProgress.Value(0);
                    int nbrAppliedSources = 0;
                    int nbrSourcesToApply = videoInfosScanSources.Count();
                    foreach (VideoInfosScanSource videoInfosScanSource in videoInfosScanSources)
                    {
                        MyLog.Add("Applying " + videoInfosScanSource.sourceAlias + " with " + videoInfosScanSource.videoInfos.Count().ToString() + " VideoItems");

                        int progress = (int)Math.Floor((decimal)(nbrSourcesToApply - nbrAppliedSources) / nbrSourcesToApply * 100);
                        subFormProgress.Text("Applying " + videoInfosScanSource.sourceAlias + "..");
                        subFormProgress.Value(progress);

                        // sources scanned less than settings,
                        // so remove scanned sources from existing list
                        // and replace with scanned list
                        List <VideoInfo> currentVideoInfos = ListVideoInfo.GetList();
                        if (currentVideoInfos == null)
                        {
                            ListVideoInfo.SetList(videoInfosScanSource.videoInfos);
                        }
                        else
                        {
                            currentVideoInfos.RemoveAll(s => s.sourceAlias == videoInfosScanSource.sourceAlias);

                            currentVideoInfos.AddRange(videoInfosScanSource.videoInfos);
                            ListVideoInfo.SetList(currentVideoInfos);
                        }
                        // videoInfos = videoInfos.Union(currentVideoInfos).ToList();

                        nbrAppliedSources++;
                    }
                }
                else // filter
                {
                    List <VideoInfo> videoInfos = (List <VideoInfo>)e.Result;

                    if (videoInfos == null)
                    {
                        MyLog.Add(message + " Null VideoItems");
                        MyLog.AddElapsed(stopwatch.Elapsed);
                        LoadVideos_Completed(sender, e);
                        return;
                    }

                    MyLog.Add(message + " " + videoInfos.Count().ToString() + " VideoItems");
                    MyLog.AddElapsed(stopwatch.Elapsed);
                    subFormProgress.Text("Applying..");
                    subFormProgress.Value(0);

                    ListVideoInfo.SetList(videoInfos);
                }

                MyLog.Add("Setting List");
                subFormProgress.Value(0);
                subFormProgress.Text("Setting List..");
                subFormListView.SetListViewInfos(ListVideoInfo.GetList());
                Application.DoEvents(); // meh, not needed but allow ui redraw


                if (Config.settings.gallery.enable)
                {
                    MyLog.Add("Building Gallery");
                    subFormProgress.Text("Building Gallery..");
                    subFormProgress.Value(0);
                    stopwatchBuildGalleryImages = Stopwatch.StartNew(); // stopped when background worker completed
                    // build to either create thumbnails or get existing thumbnails
                    // will call LoadVideos_Completed() via RunCalcStats() when done
                    buildGalleryImages.Build(ListVideoInfo.GetList());
                }
                else
                {
                    RunCalcStats(sender, e);
                }
            }
        }