Example #1
0
        /// <summary>
        /// Downloads videos from a YouTube playlist and creates metadata for use in media players.
        /// </summary>
        /// <param name="playlistId">The ID of the YouTube playlist.</param>
        /// <param name="downloadFolder">The folder to download videos to.</param>
        public static void Main(string playlistId, string downloadFolder)
        {
            if (playlistId == null)
            {
                throw new ArgumentNullException(nameof(playlistId));
            }
            if (downloadFolder == null)
            {
                throw new ArgumentNullException(nameof(downloadFolder));
            }

            Directory.CreateDirectory(downloadFolder);

            var httpClient    = new HttpClient();
            var seenItems     = new SeenItems(downloadFolder);
            var localMetadata = new LocalMetadata(httpClient);

            EnsureFfmpegDependency(new Ffmpeg(httpClient));

            var playlist = GetPlaylist(playlistId);

            EnsureMetadata(playlist, downloadFolder, localMetadata);

            var allVideos = playlist.Videos;
            var newVideos = FilterAndSortVideos(allVideos, seenItems.GetIds());

            ProcessVideos(newVideos, seenItems, downloadFolder, localMetadata);
        }
Example #2
0
 public LocalMetadataTest()
 {
     FakeHttpMessageHandler = new FakeHttpMessageHandler();
     LocalMetadata          = new LocalMetadata(new HttpClient(FakeHttpMessageHandler));
     Folder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
     Directory.CreateDirectory(Folder);
 }
        public void DownloadPlaylist(string id, bool doNotReorder, string downloadFolder, int season = 1)
        {
            if (id == null)
            {
                throw new ArgumentNullException(nameof(id));
            }
            if (downloadFolder == null)
            {
                throw new ArgumentNullException(nameof(downloadFolder));
            }

            Directory.CreateDirectory(downloadFolder);

            var seenItems     = new SeenItems(downloadFolder);
            var localMetadata = new LocalMetadata(HttpClient);

            var playlist = GetPlaylist(id);

            EnsureMetadata(playlist, downloadFolder, localMetadata);

            var allVideos    = playlist.Videos;
            var sortedVideos = doNotReorder ? allVideos : allVideos.OrderBy(item => item.UploadDate).ToList();
            var newVideos    = sortedVideos.Where(video => !seenItems.GetIds().Contains(video.Id.Value));

            ProcessVideos(newVideos, seenItems, downloadFolder, season, localMetadata);
        }
Example #4
0
        public void Save_Episode_Required()
        {
            var metadata = new Episode("제목");

            LocalMetadata.Save(metadata, Folder, metadata.Title);
            GetMetadataFileContents(metadata.Title).ShouldBe(
                @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes""?>
<episodedetails>
	<title>제목</title>
	<plot />
	<aired />
</episodedetails>"
                );
        }
        public void Save_Movie_Required()
        {
            var metadata = new Movie("제목");

            LocalMetadata.Save(metadata, Folder, metadata.Title);
            GetMetadataFileContents(metadata.Title).ShouldBe(
                @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes""?>
<movie>
	<title>제목</title>
	<plot />
	<releasedate />
</movie>"
                );
        }
Example #6
0
        public void Save_TVShow_Required()
        {
            var metadata = new TVShow("제목");

            LocalMetadata.Save(metadata, Folder);
            GetMetadataFileContents("tvshow").ShouldBe(
                @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes""?>
<tvshow>
	<title>제목</title>
	<plot />
	<premiered />
</tvshow>"
                );
        }
Example #7
0
        public void Save_TVShow_PosterUrl()
        {
            var fakePosterUrl      = "https://fake.tv.show/poster.png";
            var fakePosterContents = "fake tv show poster";

            FakeHttpMessageHandler.Mock(fakePosterUrl, fakePosterContents);

            string posterMetadataPath = Path.Combine(Folder, "folder.png");
            var    metadata           = new TVShow(title: "title", posterPathOrUrl: fakePosterUrl);

            LocalMetadata.Save(metadata, Folder);

            File.Exists(posterMetadataPath).ShouldBeTrue();
            File.ReadAllText(posterMetadataPath).ShouldBe(fakePosterContents);
        }
Example #8
0
        public void Save_TVShow_PosterPath()
        {
            var fakePosterPath     = Path.GetTempFileName();
            var fakePosterContents = "fake tv show poster";

            File.WriteAllText(fakePosterPath, fakePosterContents);

            string posterMetadataPath = Path.Combine(Folder, $"folder{Path.GetExtension(fakePosterPath)}");
            var    metadata           = new TVShow(title: "title", posterPathOrUrl: fakePosterPath);

            LocalMetadata.Save(metadata, Folder);

            File.Exists(posterMetadataPath).ShouldBeTrue();
            File.ReadAllText(posterMetadataPath).ShouldBe(fakePosterContents);
        }
Example #9
0
        public void Save_TVShow_Optional()
        {
            var metadata = new TVShow(title: "제목", plot: "a\nb", premiered: new DateTime(2019, 02, 03), posterPathOrUrl: "");

            LocalMetadata.Save(metadata, Folder);
            GetMetadataFileContents("tvshow").ShouldBe(
                @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes""?>
<tvshow>
	<title>제목</title>
	<plot>a
b</plot>
	<premiered>2019-02-03</premiered>
</tvshow>"
                );
        }
Example #10
0
        public void Save_Episode_Optional()
        {
            var metadata = new Episode(title: "제목", plot: "a\nb", aired: new DateTime(2019, 02, 03));

            LocalMetadata.Save(metadata, Folder, metadata.Title);
            GetMetadataFileContents(metadata.Title).ShouldBe(
                @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes""?>
<episodedetails>
	<title>제목</title>
	<plot>a
b</plot>
	<aired>2019-02-03</aired>
</episodedetails>"
                );
        }
        public void Save_Movie_PosterUrl()
        {
            var fakePosterUrl      = "https://fake.com/poster.png";
            var fakePosterContents = "fake poster";

            FakeHttpMessageHandler.Mock(fakePosterUrl, fakePosterContents);

            var    metadata           = new Movie(title: "title", posterPathOrUrl: fakePosterUrl);
            string posterMetadataPath = Path.Combine(Folder, $"{metadata.Title}.png");

            LocalMetadata.Save(metadata, Folder, metadata.Title);

            File.Exists(posterMetadataPath).ShouldBeTrue();
            File.ReadAllText(posterMetadataPath).ShouldBe(fakePosterContents);
        }
        public void Save_Movie_Optional()
        {
            var metadata = new Movie(title: "제목", plot: "a\nb", releaseDate: new DateTime(2019, 02, 03), posterPathOrUrl: "");

            LocalMetadata.Save(metadata, Folder, metadata.Title);
            GetMetadataFileContents(metadata.Title).ShouldBe(
                @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""yes""?>
<movie>
	<title>제목</title>
	<plot>a
b</plot>
	<releasedate>2019-02-03</releasedate>
</movie>"
                );
        }
Example #13
0
 private static void EnsureMetadata(Playlist playlist, string downloadFolder, LocalMetadata localMetadata)
 {
     if (!File.Exists(Path.Combine(downloadFolder, "tvshow.nfo")))
     {
         Console.WriteLine("Creating metadata");
         Console.Write("\tInput poster path or URL: ");
         var posterPathOrUrl = Console.ReadLine();
         localMetadata.Save(
             new TVShow(
                 title: playlist.Title,
                 plot: playlist.Description,
                 premiered: playlist.Videos.OrderBy(video => video.UploadDate).First().UploadDate,
                 posterPathOrUrl: posterPathOrUrl),
             downloadFolder);
     }
 }
        public void DownloadVideo(string id, string downloadFolder)
        {
            if (id == null)
            {
                throw new ArgumentNullException(nameof(id));
            }
            if (downloadFolder == null)
            {
                throw new ArgumentNullException(nameof(downloadFolder));
            }

            Directory.CreateDirectory(downloadFolder);

            var localMetadata = new LocalMetadata(HttpClient);

            var video             = GetVideo(id);
            var videoFileNameBase = video.Title.Aggregate("", (agg, cur) => Path.GetInvalidFileNameChars().Contains(cur) ? agg : agg + cur);

            SaveMetadata(video, downloadFolder, videoFileNameBase, localMetadata);
            SaveVideo(video, downloadFolder, videoFileNameBase);
        }
        private void SaveMetadata(YTVideo video, string downloadFolder, string videoFileNameBase, LocalMetadata localMetadata)
        {
            Console.WriteLine("Creating metadata");
            Console.Write("\tInput poster path or URL: ");
            var posterPathOrUrl = Console.ReadLine();

            localMetadata.Save(
                new Movie(
                    title: video.Title,
                    plot: video.Description,
                    releaseDate: video.UploadDate,
                    posterPathOrUrl: posterPathOrUrl),
                downloadFolder,
                videoFileNameBase);
        }
        private void ProcessVideos(IEnumerable <YTVideo> videos, SeenItems seenItems, string downloadFolder, int season, LocalMetadata localMetadata)
        {
            var client       = new YoutubeClient();
            var seasonFolder = Path.Combine(downloadFolder, $"Season {season}");

            Directory.CreateDirectory(seasonFolder);
            var episodeNumber = GetLastEpisodeNumber(seasonFolder);

            videos.ToList().ForEach(video =>
            {
                episodeNumber++;

                Console.WriteLine($"  0.00% Downloading {video.Id} {episodeNumber} {video.Title}");
                Console.SetCursorPosition(0, Console.CursorTop - 1);

                var videoFileNameBase = $"S{season.ToString().PadLeft(2, '0')}E{episodeNumber.ToString("N0").PadLeft(2, '0')} " + video.Title.Aggregate("", (agg, cur) => Path.GetInvalidFileNameChars().Contains(cur) ? agg : agg + cur);

                var progress = new ConcurrentProgress <double>(d =>
                {
                    Console.SetCursorPosition(0, Console.CursorTop);
                    Console.Write((d * 100).ToString("N2").PadLeft(6));
                });

                Downloaders.DownloadVideo(client, video, seasonFolder, videoFileNameBase, progress);
                Downloaders.DownloadAllCaptions(client, video, seasonFolder, videoFileNameBase, progress);
                CreateMetadata(video, seasonFolder, videoFileNameBase, localMetadata);

                seenItems.SaveId(video.Id);

                Console.WriteLine();
            });
        }
Example #17
0
        private static void ProcessVideos(IEnumerable <Video> videos, SeenItems seenItems, string downloadFolder, LocalMetadata localMetadata)
        {
            var client       = new YoutubeClient();
            var seasonFolder = Path.Combine(downloadFolder, "Season 1");

            Directory.CreateDirectory(seasonFolder);
            var episodeNumber = GetLastEpisodeNumber(seasonFolder);

            videos.ToList().ForEach(video =>
            {
                Console.WriteLine($"  0.00% Downloading {video.Title}");
                Console.SetCursorPosition(0, Console.CursorTop - 1);

                episodeNumber++;

                var videoFileNameBase = $"S01E{episodeNumber.ToString("N0").PadLeft(2, '0')} " + video.Title.Replace('|', '-');

                var progress = new ConcurrentProgress <double>(d =>
                {
                    Console.SetCursorPosition(0, Console.CursorTop);
                    Console.Write((d * 100).ToString("N2").PadLeft(6));
                });

                DownloadVideo(client, video, seasonFolder, videoFileNameBase, progress);
                DownloadAllCaptions(client, video, seasonFolder, videoFileNameBase, progress);
                CreateMetadata(video, seasonFolder, videoFileNameBase, localMetadata);

                seenItems.SaveId(video.Id);

                Console.WriteLine();
            });
        }
Example #18
0
 private static void CreateMetadata(Video video, string downloadFolder, string videoFileNameBase, LocalMetadata localMetadata)
 {
     Console.WriteLine();
     Console.Write("        \tmetadata");
     localMetadata.Save(new Episode(title: video.Title, plot: video.Description, aired: video.UploadDate), downloadFolder, videoFileNameBase);
 }