Exemplo n.º 1
0
        private List <ISyncItem> ApplyDownloadStrategy(string stateKey, IPodcastInfo podcastInfo, List <ISyncItem> episodesFound)
        {
            switch (podcastInfo.Feed.DownloadStrategy.Value)
            {
            case PodcastEpisodeDownloadStrategy.All:
                return(episodesFound);

            case PodcastEpisodeDownloadStrategy.HighTide:
                var state       = _stateProvider.GetState(stateKey);
                var newEpisodes =
                    (from episode in episodesFound
                     where episode.Published > state.DownloadHighTide
                     select episode);
                var filteredEpisodes = new List <ISyncItem>(1);
                filteredEpisodes.AddRange(newEpisodes);
                return(filteredEpisodes);

            case PodcastEpisodeDownloadStrategy.Latest:
                episodesFound.Sort((e1, e2) => e2.Published.CompareTo(e1.Published));
                var latestEpisodes = new List <ISyncItem>(1);
                latestEpisodes.AddRange(episodesFound.Take(1));
                return(latestEpisodes);

            default:
                throw new EnumOutOfRangeException();
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Find folders that will be empty and that can be purged
        /// </summary>
        /// <param name="rootFolder">the root folder for all downloads</param>
        /// <param name="podcastInfo">info on the podcast to download</param>
        /// <param name="filesThatWillBeDeleted">files that will be removed and do not count when considering an empty folder</param>
        /// <returns></returns>
        public IList <IDirectoryInfo> FindEmptyFoldersToDelete(string rootFolder, IPodcastInfo podcastInfo, IList <IFileInfo> filesThatWillBeDeleted)
        {
            List <IDirectoryInfo> foldersToDelete = new List <IDirectoryInfo>(10);

            if (!podcastInfo.DeleteEmptyFolder.Value)
            {
                return(foldersToDelete);
            }

            var            feedDownloadsFolder = Path.Combine(rootFolder, podcastInfo.Folder);
            IDirectoryInfo directoryInfo       = _directoryInfoProvider.GetDirectoryInfo(feedDownloadsFolder);

            if (podcastInfo.Feed != null && IsSubFolderBasedNaming(podcastInfo.Feed.NamingStyle.Value))
            {
                CheckIfSubFoldersCanBeDeleted(directoryInfo, filesThatWillBeDeleted, foldersToDelete);
            }
            else
            {
                if (FolderCanBeDeleted(directoryInfo, filesThatWillBeDeleted))
                {
                    foldersToDelete.Add(directoryInfo);
                }
            }
            return(foldersToDelete);
        }
Exemplo n.º 3
0
        private static DateTime GetWhenDownloadWasPublished(IPodcastInfo podcastInfo, IFileInfo file)
        {
            switch (podcastInfo.Feed.NamingStyle.Value)
            {
            case PodcastEpisodeNamingStyle.UrlFileNameAndPublishDateTime:
            case PodcastEpisodeNamingStyle.UrlFileNameFeedTitleAndPublishDateTime:
            case PodcastEpisodeNamingStyle.EpisodeTitleAndPublishDateTime:
            case PodcastEpisodeNamingStyle.UrlFileNameFeedTitleAndPublishDateTimeInfolder:
                try
                {
                    return(ConvertFilenameToPublishedDate(Path.GetFileNameWithoutExtension(file.FullName)));
                }
                catch (Exception)
                {
                    return(file.CreationTime);
                }

            case PodcastEpisodeNamingStyle.EpisodeTitle:
            case PodcastEpisodeNamingStyle.UrlFileName:
                return(file.CreationTime);

            default:
                throw new EnumOutOfRangeException("NamingStyle");
            }
        }
Exemplo n.º 4
0
        private void DownloadFile1()
        {
            ReadOnlyControlFile controlFile = new ReadOnlyControlFile(_inputfilename);
            IPodcastInfo        info        = GetPodcastInfo(controlFile, 0);

            DisplayMessage(string.Format("Reading a feed: {0}", info.Feed.Address));
            IList <ISyncItem> allEpisodes = GetAllEpisodesInFeed(controlFile, info);

            if (allEpisodes.Count < 1)
            {
                DisplayMessage("No episodes in the feed - dont forget the state.xml file is being used", DisplayLevel.Warning);
                return;
            }
            IList <ISyncItem> firstEpisode = new List <ISyncItem>(1);

            firstEpisode.Add(allEpisodes.First());

            DisplayMessage(string.Format("Downloading Eposode: {0}", firstEpisode.First().EpisodeTitle));
            ISyncItemToEpisodeDownloaderTaskConverter converter = _iocContainer.Resolve <ISyncItemToEpisodeDownloaderTaskConverter>();

            IEpisodeDownloader[] downloadTasks = converter.ConvertItemsToTasks(firstEpisode, StatusUpdate, ProgressUpdate);

            // run them in a task pool
            ITaskPool taskPool = _iocContainer.Resolve <ITaskPool>();

            taskPool.RunAllTasks(1, downloadTasks);

            DisplayMessage(string.Format("Download Complete", allEpisodes.Count));
        }
Exemplo n.º 5
0
        private IPodcastInfo GetPodcastInfo(ReadOnlyControlFile controlFile, int index)
        {
            IEnumerable <IPodcastInfo> podcasts = controlFile.GetPodcasts();
            IPodcastInfo info = podcasts.ElementAt(index);

            return(info);
        }
Exemplo n.º 6
0
        /// <summary>
        /// find old downloads that can be deleted
        /// </summary>
        /// <param name="rootFolder">the root folder for all downloads</param>
        /// <param name="podcastInfo">info on the podcast to download</param>
        /// <returns>list of episodes to be deleted for the supplied podcastInfo</returns>
        public IList <IFileInfo> FindEpisodesToPurge(string rootFolder, IPodcastInfo podcastInfo)
        {
            List <IFileInfo> episodesToDelete = new List <IFileInfo>(10);

            if (podcastInfo.Feed == null)
            {
                // it is optional to have a feed
                return(episodesToDelete);
            }

            var feedDownloadsFolder = Path.Combine(rootFolder, podcastInfo.Folder);
            var oldestEpisodeToKeep = DateTime.MinValue;

            if (podcastInfo.Feed.DeleteDownloadsDaysOld.Value < int.MaxValue)
            {
                oldestEpisodeToKeep = _timeProvider.UtcNow.AddDays(-podcastInfo.Feed.DeleteDownloadsDaysOld.Value);
            }

            if (IsSubFolderBasedNaming(podcastInfo.Feed.NamingStyle.Value))
            {
                ScanSubFoldersForOldFiles(feedDownloadsFolder, oldestEpisodeToKeep, episodesToDelete, podcastInfo);
            }
            else
            {
                ScanFolderForOldFiles(feedDownloadsFolder, oldestEpisodeToKeep, episodesToDelete, podcastInfo);
            }

            return(episodesToDelete);
        }
 protected void SetupFoundEpisodes(IPodcastInfo podcastInfo, List <ISyncItem> episodes)
 {
     A.CallTo(() => MockPodcastEpisodeFinder.FindEpisodesToDownload(
                  SOURCE_ROOT,
                  RETRY_TIME,
                  podcastInfo,
                  DIAGS)
              ).Returns(episodes);
 }
Exemplo n.º 8
0
        private void ReadFeed1()
        {
            ReadOnlyControlFile controlFile = new ReadOnlyControlFile(_inputfilename);
            IPodcastInfo        info        = GetPodcastInfo(controlFile, 0);

            DisplayMessage(string.Format("Reading a feed: {0}", info.Feed.Address));

            IList <ISyncItem> allEpisodes = GetAllEpisodesInFeed(controlFile, info);

            DisplayMessage(string.Format("Eposodes in feed: {0}", allEpisodes.Count));
            foreach (ISyncItem item in allEpisodes)
            {
                DisplayMessage(string.Format("Eposode: {0}", item.EpisodeTitle));
            }
        }
Exemplo n.º 9
0
        private string GetDownloadPathname(string rootFolder, IPodcastInfo podcastInfo, IPodcastFeedItem podcastFeedItem)
        {
            var proposedFilename = podcastFeedItem.FileName;

            switch (podcastInfo.Feed.NamingStyle.Value)
            {
            case PodcastEpisodeNamingStyle.UrlFileNameAndPublishDateTime:
                proposedFilename = string.Format(CultureInfo.InvariantCulture, "{0}_{1}",
                                                 podcastFeedItem.Published.ToString("yyyy_MM_dd_HHmm", CultureInfo.InvariantCulture),
                                                 proposedFilename);
                break;

            case PodcastEpisodeNamingStyle.UrlFileNameFeedTitleAndPublishDateTime:
                proposedFilename = string.Format(CultureInfo.InvariantCulture, "{0}_{1}_{2}",
                                                 podcastFeedItem.Published.ToString("yyyy_MM_dd_HHmm", CultureInfo.InvariantCulture),
                                                 podcastInfo.Folder,
                                                 proposedFilename);
                break;

            case PodcastEpisodeNamingStyle.UrlFileNameFeedTitleAndPublishDateTimeInfolder:
                proposedFilename = string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}_{3}_{4}",
                                                 podcastFeedItem.Published.ToString("yyyy_MM", CultureInfo.InvariantCulture),
                                                 _pathUtilities.GetPathSeparator(),
                                                 podcastFeedItem.Published.ToString("yyyy_MM_dd_HHmm", CultureInfo.InvariantCulture),
                                                 podcastInfo.Folder,
                                                 proposedFilename);
                break;

            case PodcastEpisodeNamingStyle.EpisodeTitle:
                proposedFilename = podcastFeedItem.TitleAsFileName;
                break;

            case PodcastEpisodeNamingStyle.EpisodeTitleAndPublishDateTime:
                proposedFilename = string.Format(CultureInfo.InvariantCulture, "{0}_{1}",
                                                 podcastFeedItem.Published.ToString("yyyy_MM_dd_HHmm", CultureInfo.InvariantCulture),
                                                 podcastFeedItem.TitleAsFileName);
                break;

            case PodcastEpisodeNamingStyle.UrlFileName:
                break;

            default:
                throw new EnumOutOfRangeException("NamingStyle");
            }

            return(Path.Combine(Path.Combine(rootFolder, podcastInfo.Folder), proposedFilename));
        }
Exemplo n.º 10
0
        public virtual void CancelEdit()
        {
            _podcast = _backupPodcastInfo;

            _backupPodcastInfo = null;
        }
Exemplo n.º 11
0
 public virtual void AcceptEdit()
 {
     _backupPodcastInfo = null;
 }
Exemplo n.º 12
0
 public virtual void StartEditing()
 {
     _backupPodcastInfo = _podcast.Clone() as PodcastInfo;
 }
Exemplo n.º 13
0
 public PodcastViewModel(IPodcastInfo podcast)
 {
     _podcast = podcast;
 }
Exemplo n.º 14
0
 private void OnStatusVerbose(string message, IPodcastInfo podcastInfo)
 {
     OnStatusUpdate(new StatusUpdateEventArgs(StatusUpdateLevel.Verbose, message, false, podcastInfo));
 }
Exemplo n.º 15
0
        private void ScanFolderForOldFiles(string folderToScan, DateTime oldestEpisodeToKeep, List <IFileInfo> episodesToDelete, IPodcastInfo podcastInfo)
        {
            IDirectoryInfo directoryInfo = _directoryInfoProvider.GetDirectoryInfo(folderToScan);

            IFileInfo[] files;
            try
            {
                files = directoryInfo.GetFiles(podcastInfo.Pattern.Value);
            }
            catch (DirectoryNotFoundException)
            {
                // if the folder is not there then there is nothing to do
                return;
            }

            foreach (IFileInfo file in files)
            {
                var extension = Path.GetExtension(file.FullName);
                if (extension != null && extension.ToUpperInvariant() == ".XML")
                {
                    // do not delete the state file
                    continue;
                }
                if (GetWhenDownloadWasPublished(podcastInfo, file) < oldestEpisodeToKeep)
                {
                    episodesToDelete.Add(file);
                }
            }
        }
Exemplo n.º 16
0
        private void ScanSubFoldersForOldFiles(string folderToScan, DateTime oldestEpisodeToKeep, List <IFileInfo> episodesToDelete, IPodcastInfo podcastInfo)
        {
            IDirectoryInfo directoryInfo = _directoryInfoProvider.GetDirectoryInfo(folderToScan);

            IDirectoryInfo[] subFolders;
            try
            {
                subFolders = directoryInfo.GetDirectories("*.*");
            }
            catch (DirectoryNotFoundException)
            {
                // if the folder is not there then there is nothing to do
                return;
            }

            foreach (IDirectoryInfo subFolder in subFolders)
            {
                ScanFolderForOldFiles(subFolder.FullName, oldestEpisodeToKeep, episodesToDelete, podcastInfo);
            }
        }
Exemplo n.º 17
0
 private void OnStatusError(string message, IPodcastInfo podcastInfo)
 {
     OnStatusUpdate(new StatusUpdateEventArgs(StatusUpdateLevel.Error, message, false, podcastInfo));
 }
Exemplo n.º 18
0
        private IList <ISyncItem> GetAllEpisodesInFeed(ReadOnlyControlFile controlFile, IPodcastInfo info)
        {
            List <ISyncItem>  allEpisodes          = new List <ISyncItem>(20);
            IEpisodeFinder    podcastEpisodeFinder = _iocContainer.Resolve <IEpisodeFinder>();
            IList <ISyncItem> episodesInThisFeed   = podcastEpisodeFinder.FindEpisodesToDownload(
                controlFile.GetSourceRoot(),
                controlFile.GetRetryWaitInSeconds(),
                info,
                controlFile.GetDiagnosticRetainTemporaryFiles()
                );

            allEpisodes.AddRange(episodesInThisFeed);
            return(allEpisodes);
        }
        /// <summary>
        /// replace any token elements in a command line and return a full command ready to be executed
        /// </summary>
        /// <param name="tokenisedCommand">tokenised command</param>
        /// <param name="rootFolder">the root folder for all downloads</param>
        /// <param name="destinationPathname">the full pathname for the download</param>
        /// <param name="podcast">the podcast, used as a source of tokens</param>
        /// <returns>a full command line, NULL if there is no command to execute</returns>
        public IExternalCommand ReplaceTokensInCommand(ITokenisedCommand tokenisedCommand, string rootFolder, string destinationPathname, IPodcastInfo podcast)
        {
            if (tokenisedCommand == null)
            {
                return(null);
            }

            var command = new ExternalCommand();

            command.Command          = ReplaceTokensInString(tokenisedCommand.Command.Value, rootFolder, destinationPathname, podcast);
            command.Arguments        = ReplaceTokensInString(tokenisedCommand.Arguments.Value, rootFolder, destinationPathname, podcast);
            command.WorkingDirectory = ReplaceTokensInString(tokenisedCommand.WorkingDirectory.Value, rootFolder, destinationPathname, podcast);

            return(command);
        }
Exemplo n.º 20
0
        public IList <ISyncItem> FindEpisodesToDownload(string rootFolder, int retryWaitTimeInSeconds, IPodcastInfo podcastInfo, bool retainFeedStream)
        {
            List <ISyncItem> episodesToDownload = new List <ISyncItem>(10);

            if (podcastInfo.Feed == null)
            {
                // it is optional to have a feed
                return(episodesToDownload);
            }

            var    stateKey     = Path.Combine(rootFolder, podcastInfo.Folder);
            string feedSaveFile = null;

            if (retainFeedStream)
            {
                CreateFolderIfNeeded(stateKey);
                feedSaveFile = Path.Combine(Path.Combine(rootFolder, podcastInfo.Folder), "last_download_feed.xml");
            }

            using (var webClient = _webClientFactory.CreateWebClient())
            {
                var downloader = new Downloader(webClient, _feedFactory);

                try
                {
                    var feed = downloader.DownloadFeed(podcastInfo.Feed.Format.Value, podcastInfo.Feed.Address, feedSaveFile);
                    feed.StatusUpdate += StatusUpdate;
                    var episodes = feed.Episodes;

                    var oldestEpisodeToAccept = DateTime.MinValue;
                    if (podcastInfo.Feed.MaximumDaysOld.Value < int.MaxValue)
                    {
                        oldestEpisodeToAccept = _timeProvider.UtcNow.AddDays(-podcastInfo.Feed.MaximumDaysOld.Value);
                    }

                    foreach (IPodcastFeedItem podcastFeedItem in episodes)
                    {
                        if (podcastFeedItem.Published > oldestEpisodeToAccept)
                        {
                            var destinationPath = GetDownloadPathname(rootFolder, podcastInfo, podcastFeedItem);
                            if (!_fileUtilities.FileExists(destinationPath))
                            {
                                var downloadItem = new SyncItem()
                                {
                                    Id       = Guid.NewGuid(),
                                    StateKey = stateKey,
                                    RetryWaitTimeInSeconds = retryWaitTimeInSeconds,
                                    Published           = podcastFeedItem.Published,
                                    EpisodeUrl          = podcastFeedItem.Address,
                                    DestinationPath     = destinationPath,
                                    EpisodeTitle        = string.Format(CultureInfo.InvariantCulture, "{0} {1}", podcastInfo.Folder, podcastFeedItem.EpisodeTitle),
                                    PostDownloadCommand = _commandGenerator.ReplaceTokensInCommand(podcastInfo.PostDownloadCommand, rootFolder, destinationPath, podcastInfo),
                                };
                                episodesToDownload.Add(downloadItem);
                            }
                            else
                            {
                                OnStatusVerbose(string.Format(CultureInfo.InvariantCulture, "Episode already downloaded: {0}", podcastFeedItem.EpisodeTitle), podcastInfo);
                            }
                        }
                        else
                        {
                            OnStatusVerbose(string.Format(CultureInfo.InvariantCulture, "Episode too old: {0}", podcastFeedItem.EpisodeTitle), podcastInfo);
                        }
                    }
                }
                catch (Exception e)
                {
                    OnStatusError(string.Format(CultureInfo.InvariantCulture, "Error processing feed {0}: {1}", podcastInfo.Feed.Address, e.Message), podcastInfo);
                }
            }

            var filteredEpisodes = ApplyDownloadStrategy(stateKey, podcastInfo, episodesToDownload);

            foreach (var filteredEpisode in filteredEpisodes)
            {
                OnStatusMessageUpdate(string.Format(CultureInfo.InvariantCulture, "Queued: {0}", filteredEpisode.EpisodeTitle), podcastInfo);
            }
            return(filteredEpisodes);
        }
Exemplo n.º 21
0
 protected override void When()
 {
     CreatedPodcast = PodcastFactory.CreatePodcast(_controlFile);
 }
        private string ReplaceTokensInString(string input, string rootFolder, string destinationPathname, IPodcastInfo podcast)
        {
            if (input == null)
            {
                return(null);
            }

            string returnValue = input.Replace("{downloadfullpath}", destinationPathname);

            returnValue = returnValue.Replace("{downloadroot}", rootFolder);
            returnValue = returnValue.Replace("{downloadfolder}", podcast.Folder);
            returnValue = returnValue.Replace("{exefolder}", GetExeFolder());

            return(returnValue);
        }