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);
        }