Esempio n. 1
0
 private static string FormatFromGd3(string pattern, Gd3Tag gd3)
 {
     return(pattern
            .Replace("[title]", gd3.Title.English)
            .Replace("[system]", gd3.System.English)
            .Replace("[game]", gd3.Game.English)
            .Replace("[composer]", gd3.Composer.English));
 }
Esempio n. 2
0
        private static void Render(Settings settings, AudioLoader loader)
        {
            if (settings.OutputFile != null)
            {
                // Emit normalized data to a WAV file for later mixing
                if (settings.MasterAudioFile == null && !settings.NoMasterMix)
                {
                    settings.MasterAudioFile = settings.OutputFile + ".wav";
                    loader.MixToFile(settings.MasterAudioFile, !settings.NoMasterMixReplayGain);
                }
            }

            Console.WriteLine("Generating background image...");

            var backgroundImage = new BackgroundRenderer(settings.Width, settings.Height, ParseColor(settings.BackgroundColor));

            if (settings.BackgroundImageFile != null)
            {
                using (var bm = Image.FromFile(settings.BackgroundImageFile))
                {
                    backgroundImage.Add(new ImageInfo(bm, ContentAlignment.MiddleCenter, true, DockStyle.None, 0.5f));
                }
            }

            if (settings.LogoImageFile != null)
            {
                using (var bm = Image.FromFile(settings.LogoImageFile))
                {
                    backgroundImage.Add(new ImageInfo(bm, ContentAlignment.BottomRight, false, DockStyle.None, 1));
                }
            }

            if (settings.VgmFile != null)
            {
                var gd3     = Gd3Tag.LoadFromVgm(settings.VgmFile);
                var gd3Text = gd3.ToString();
                if (gd3Text.Length > 0)
                {
                    backgroundImage.Add(new TextInfo(gd3Text, settings.Gd3Font, settings.Gd3FontSize, ContentAlignment.BottomLeft, FontStyle.Regular,
                                                     DockStyle.Bottom, ParseColor(settings.Gd3FontColor)));
                }
            }

            var renderer = new WaveformRenderer
            {
                BackgroundImage            = backgroundImage.Image,
                Columns                    = settings.Columns,
                FramesPerSecond            = settings.FramesPerSecond,
                Width                      = settings.Width,
                Height                     = settings.Height,
                SamplingRate               = loader.SampleRate,
                RenderedLineWidthInSamples = settings.ViewWidthMs * loader.SampleRate / 1000,
                RenderingBounds            = backgroundImage.WaveArea
            };

            if (settings.GridLineWidth > 0)
            {
                renderer.Grid = new WaveformRenderer.GridConfig
                {
                    Color      = ParseColor(settings.GridColor),
                    Width      = settings.GridLineWidth,
                    DrawBorder = settings.GridBorder
                };
            }

            if (settings.ZeroLineWidth > 0)
            {
                renderer.ZeroLine = new WaveformRenderer.ZeroLineConfig
                {
                    Color = ParseColor(settings.ZeroLineColor),
                    Width = settings.ZeroLineWidth
                };
            }

            // Add the data to the renderer
            foreach (var channel in loader.Data)
            {
                renderer.AddChannel(new Channel(
                                        channel.Samples,
                                        ParseColor(settings.LineColor),
                                        settings.LineWidth,
                                        GuessChannelName(channel.Filename),
                                        CreateTriggerAlgorithm(settings.TriggerAlgorithm),
                                        settings.TriggerLookahead));
            }

            if (settings.ChannelLabelsFont != null)
            {
                renderer.ChannelLabels = new WaveformRenderer.LabelConfig
                {
                    Color    = ParseColor(settings.ChannelLabelsColor),
                    FontName = settings.ChannelLabelsFont,
                    Size     = settings.ChannelLabelsSize
                };
            }

            var outputs = new List <IGraphicsOutput>();

            if (settings.FfMpegPath != null)
            {
                Console.WriteLine("Adding FFMPEG renderer...");
                outputs.Add(new FfmpegOutput(settings.FfMpegPath, settings.OutputFile, settings.Width, settings.Height, settings.FramesPerSecond, settings.FfMpegExtraOptions, settings.MasterAudioFile));
            }

            if (settings.PreviewFrameskip > 0)
            {
                Console.WriteLine("Adding preview renderer...");
                outputs.Add(new PreviewOutput(settings.PreviewFrameskip));
            }

            try
            {
                Console.WriteLine("Rendering...");
                var sw = Stopwatch.StartNew();
                renderer.Render(outputs);
                sw.Stop();
                int numFrames = (int)(loader.Length.TotalSeconds * settings.FramesPerSecond);
                Console.WriteLine($"Rendering complete in {sw.Elapsed:g}, average {numFrames / sw.Elapsed.TotalSeconds:N} fps");
            }
            catch (Exception ex)
            {
                // Should mean it was cancelled
                Console.WriteLine($"Rendering cancelled: {ex.Message}");
            }
            finally
            {
                foreach (var graphicsOutput in outputs)
                {
                    graphicsOutput.Dispose();
                }
            }
        }
Esempio n. 3
0
        private static async Task <string> UploadToYouTube(Settings settings)
        {
            ClientSecrets secrets;

            if (settings.YouTubeUploadClientSecret != null)
            {
                using (var stream = new FileStream(settings.YouTubeUploadClientSecret, FileMode.Open, FileAccess.Read))
                {
                    secrets = GoogleClientSecrets.Load(stream).Secrets;
                }
            }
            else
            {
                // We use our embedded client secret
                using (var stream = Properties.Resources.ResourceManager.GetStream(nameof(Properties.Resources.ClientSecret)))
                {
                    secrets = GoogleClientSecrets.Load(stream).Secrets;
                }
            }

            var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                secrets,
                // This OAuth 2.0 access scope allows an application to upload files to the
                // authenticated user's YouTube channel, but doesn't allow other types of access.
                new[] { YouTubeService.Scope.YoutubeUpload, YouTubeService.Scope.YoutubeForceSsl },
                "SidWizPlus",
                CancellationToken.None
                );

            var youtubeService = new YouTubeService(new BaseClientService.Initializer
            {
                HttpClientInitializer = credential,
                ApplicationName       = Assembly.GetExecutingAssembly().GetName().Name,
                GZipEnabled           = true
            });

            var video = new Video
            {
                Snippet = new VideoSnippet
                {
                    Title      = settings.YouTubeTitle,
                    CategoryId = "10" // Music
                },
                Status = new VideoStatus {
                    PrivacyStatus = "public"
                }
                // or "private" or "public"
            };

            var tags = new List <string>();

            if (settings.YouTubeTags != null)
            {
                tags.AddRange(settings.YouTubeTags.Split(','));
            }

            Gd3Tag gd3 = null;

            if (settings.VgmFile != null)
            {
                gd3 = Gd3Tag.LoadFromVgm(settings.VgmFile);
            }

            if (gd3 != null)
            {
                video.Snippet.Description = $"Oscilloscope View of {gd3.Title}";
                if (gd3.Game.English.Length > 0)
                {
                    video.Snippet.Description += $" from the game {gd3.Game.English}";
                }
                if (gd3.System.English.Length > 0)
                {
                    video.Snippet.Description += $" for the {gd3.System.English}";
                }
                if (gd3.Composer.English.Length > 0)
                {
                    video.Snippet.Description += $", composed by {gd3.Composer}";
                }
                video.Snippet.Description += ".";
                if (gd3.Ripper.Length > 0)
                {
                    video.Snippet.Description += $"\nRipped by {gd3.Ripper}";
                }
                if (gd3.Notes.Length > 0)
                {
                    video.Snippet.Description += "\n\nNotes:\n" + gd3.Notes;
                }
            }

            if (settings.YouTubeDescriptionsExtra != null)
            {
                video.Snippet.Description += "\n" + settings.YouTubeDescriptionsExtra;
            }

            video.Snippet.Description += "\n\nVideo created using SidWizPlus - https://github.com/maxim-zhao/SidWizPlus";

            if (settings.YouTubeTagsFromGd3 && gd3 != null)
            {
                tags.Add(gd3.Game.English);
                tags.Add(gd3.System.English);
                tags.AddRange(gd3.Composer.English.Split(';'));
            }

            video.Snippet.Tags = tags.Where(t => !string.IsNullOrEmpty(t)).Select(t => t.Trim()).ToList();

            if (settings.YouTubeCategory != null)
            {
                var request = youtubeService.VideoCategories.List("snippet");
                request.RegionCode = "US";
                var response = request.Execute();
                video.Snippet.CategoryId = response.Items
                                           .Where(c => c.Snippet.Title.ToLowerInvariant().Contains(settings.YouTubeCategory.ToLowerInvariant()))
                                           .Select(c => c.Id)
                                           .FirstOrDefault();
                if (video.Snippet.CategoryId == null)
                {
                    Console.Error.WriteLine($"Warning: couldn't find category matching \"{settings.YouTubeCategory}\", defaulting to \"Music\"");
                }
            }

            if (gd3 != null)
            {
                video.Snippet.Title = FormatFromGd3(video.Snippet.Title, gd3);
            }

            if (video.Snippet.Title.Length > 100)
            {
                video.Snippet.Title = video.Snippet.Title.Substring(0, 97) + "...";
            }

            // We now escape some strings as the API doesn't do it internally...
            video.Snippet.Title       = RemoveAngledBrackets(video.Snippet.Title);
            video.Snippet.Description = RemoveAngledBrackets(video.Snippet.Description);
            video.Snippet.Tags        = video.Snippet.Tags.Select(RemoveAngledBrackets).ToList();

            using (var fileStream = new FileStream(settings.OutputFile, FileMode.Open))
            {
                var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
                videosInsertRequest.ChunkSize = ResumableUpload.MinimumChunkSize;
                long totalSize   = fileStream.Length;
                bool shouldRetry = true;
                var  sw          = Stopwatch.StartNew();
                videosInsertRequest.ProgressChanged += progress =>
                {
                    switch (progress.Status)
                    {
                    case UploadStatus.Uploading:
                    {
                        var elapsedSeconds   = sw.Elapsed.TotalSeconds;
                        var fractionComplete = (double)progress.BytesSent / totalSize;
                        var eta         = TimeSpan.FromSeconds(elapsedSeconds / fractionComplete - elapsedSeconds);
                        var sent        = (double)progress.BytesSent / 1024 / 1024;
                        var kbPerSecond = progress.BytesSent / sw.Elapsed.TotalSeconds / 1024;
                        Console.Write($"\r{sent:f}MB sent ({fractionComplete:P}, average {kbPerSecond:f}KB/s, ETA {eta:g})");
                        break;
                    }

                    case UploadStatus.Failed:
                        Console.Error.WriteLine($"Upload failed: {progress.Exception}");
                        // Google API says we can retry if we get a non-API error, or one of these four 5xx error codes
                        shouldRetry = !(progress.Exception is GoogleApiException errorCode) ||
                                      new[] {
                            HttpStatusCode.InternalServerError, HttpStatusCode.BadGateway,
                            HttpStatusCode.ServiceUnavailable, HttpStatusCode.GatewayTimeout
                        }.Contains(errorCode.HttpStatusCode);
                        if (shouldRetry)
                        {
                            Console.WriteLine("Retrying...");
                        }
                        break;

                    case UploadStatus.Completed:
                        Console.WriteLine($"Progress: {progress.Status}");
                        shouldRetry = false;
                        break;

                    default:
                        Console.WriteLine($"Progress: {progress.Status}");
                        break;
                    }
                };
                videosInsertRequest.ResponseReceived += video1 =>
                {
                    video.Id = video1.Id;
                    Console.WriteLine($"\nUpload completed: video ID is {video1.Id}");
                };

                try
                {
                    videosInsertRequest.Upload();
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"Upload failed: {ex}");
                }

                while (shouldRetry)
                {
                    try
                    {
                        videosInsertRequest.Resume();
                    }
                    catch (Exception ex)
                    {
                        Console.Error.WriteLine($"Upload failed: {ex}");
                    }
                }
            }

            if (settings.YouTubePlaylist != null && !string.IsNullOrEmpty(video.Id))
            {
                if (gd3 != null)
                {
                    settings.YouTubePlaylist = RemoveAngledBrackets(FormatFromGd3(settings.YouTubePlaylist, gd3));
                }

                // We need to decide if it's an existing playlist

                // We iterate over all channels...
                var playlistsRequest = youtubeService.Playlists.List("snippet");
                playlistsRequest.Mine = true;
                var playlistsResponse = playlistsRequest.Execute();
                var playlist          = playlistsResponse.Items.FirstOrDefault(p => p.Snippet.Title == settings.YouTubePlaylist);
                if (playlist == null)
                {
                    // Create it
                    playlist = new Playlist
                    {
                        Snippet = new PlaylistSnippet
                        {
                            Title = settings.YouTubePlaylist
                        },
                        Status = new PlaylistStatus
                        {
                            PrivacyStatus = "public"
                        }
                    };
                    if (settings.YouTubePlaylistDescriptionFile != null)
                    {
                        playlist.Snippet.Description = RemoveAngledBrackets(File.ReadAllText(settings.YouTubePlaylistDescriptionFile));
                    }

                    if (settings.YouTubeDescriptionsExtra != null)
                    {
                        playlist.Snippet.Description += "\n\n" + settings.YouTubeDescriptionsExtra;
                    }

                    playlist = youtubeService.Playlists.Insert(playlist, "snippet, status").Execute();
                    Console.WriteLine($"Created playlist \"{settings.YouTubePlaylist}\" with ID {playlist.Id}");
                }

                // Add to it
                var newPlaylistItem = new PlaylistItem
                {
                    Snippet = new PlaylistItemSnippet
                    {
                        PlaylistId = playlist.Id,
                        ResourceId = new ResourceId {
                            Kind = "youtube#video", VideoId = video.Id
                        }
                    }
                };
                newPlaylistItem = await youtubeService.PlaylistItems.Insert(newPlaylistItem, "snippet").ExecuteAsync();

                Console.WriteLine($"Added video {video.Id} ({video.Snippet.Title}) to playlist {playlist.Id} ({playlist.Snippet.Title}) as item {newPlaylistItem.Id}");
            }

            return(video.Id);
        }
Esempio n. 4
0
        private static void Render(Settings settings, IReadOnlyCollection <Channel> channels)
        {
            Console.WriteLine("Generating background image...");

            var backgroundImage = new BackgroundRenderer(settings.Width, settings.Height, ParseColor(settings.BackgroundColor));

            if (settings.BackgroundImageFile != null)
            {
                using (var bm = Image.FromFile(settings.BackgroundImageFile))
                {
                    backgroundImage.Add(new ImageInfo(bm, ContentAlignment.MiddleCenter, true, DockStyle.None, 0.5f));
                }
            }

            if (!string.IsNullOrEmpty(settings.LogoImageFile))
            {
                using (var bm = Image.FromFile(settings.LogoImageFile))
                {
                    backgroundImage.Add(new ImageInfo(bm, ContentAlignment.BottomRight, false, DockStyle.None, 1));
                }
            }

            if (settings.VgmFile != null)
            {
                var gd3     = Gd3Tag.LoadFromVgm(settings.VgmFile);
                var gd3Text = gd3.ToString();
                if (gd3Text.Length > 0)
                {
                    backgroundImage.Add(new TextInfo(gd3Text, settings.Gd3Font, settings.Gd3FontSize, ContentAlignment.BottomLeft, FontStyle.Regular,
                                                     DockStyle.Bottom, ParseColor(settings.Gd3FontColor)));
                }
            }

            if (settings.MaximumAspectRatio > 0.0)
            {
                Console.WriteLine($"Determining column count for maximum aspect ratio {settings.MaximumAspectRatio}:");
                for (var columns = 1; columns < 100; ++columns)
                {
                    var width  = backgroundImage.WaveArea.Width / columns;
                    var rows   = channels.Count / columns + (channels.Count % columns == 0 ? 0 : 1);
                    var height = backgroundImage.WaveArea.Height / rows;
                    var ratio  = (double)width / height;
                    Console.WriteLine($"- {columns} columns => {width} x {height} pixels => ratio {ratio}");
                    if (ratio < settings.MaximumAspectRatio)
                    {
                        settings.Columns = columns;
                        break;
                    }
                }
            }

            var renderer = new WaveformRenderer
            {
                BackgroundImage = backgroundImage.Image,
                Columns         = settings.Columns,
                FramesPerSecond = settings.FramesPerSecond,
                Width           = settings.Width,
                Height          = settings.Height,
                SamplingRate    = channels.First().SampleRate,
                RenderingBounds = backgroundImage.WaveArea
            };

            if (settings.GridLineWidth > 0)
            {
                foreach (var channel in channels)
                {
                    channel.BorderColor = ParseColor(settings.GridColor);
                    channel.BorderWidth = settings.GridLineWidth;
                    channel.BorderEdges = settings.GridBorder;
                }
            }

            // Add the data to the renderer
            foreach (var channel in channels)
            {
                renderer.AddChannel(channel);
            }

            var outputs = new List <IGraphicsOutput>();

            if (settings.FfMpegPath != null)
            {
                Console.WriteLine("Adding FFMPEG renderer...");
                outputs.Add(new FfmpegOutput(settings.FfMpegPath, settings.OutputFile, settings.Width, settings.Height, settings.FramesPerSecond, settings.FfMpegExtraOptions, settings.MasterAudioFile));
            }

            if (settings.PreviewFrameskip > 0)
            {
                Console.WriteLine("Adding preview renderer...");
                outputs.Add(new PreviewOutput(settings.PreviewFrameskip, true));
            }

            try
            {
                Console.WriteLine("Rendering...");
                var sw = Stopwatch.StartNew();
                renderer.Render(outputs);
                sw.Stop();
                int numFrames = (int)(channels.Max(x => x.Length).TotalSeconds *settings.FramesPerSecond);
                Console.WriteLine($"Rendering complete in {sw.Elapsed:g}, average {numFrames / sw.Elapsed.TotalSeconds:N} fps");
            }
            catch (Exception ex)
            {
                // Should mean it was cancelled
                Console.WriteLine($"Rendering cancelled: {ex.Message}");
            }
            finally
            {
                foreach (var graphicsOutput in outputs)
                {
                    graphicsOutput.Dispose();
                }
            }
        }