Exemple #1
0
        /// <summary>
        /// Apply tag to audio file.
        /// </summary>
        private void tagAudio(UtilsName name, string outName, int episodeCount, int curEpisodeCount, int progessCount,
                              int totalTracks,
                              DateTime filenameStartTime, DateTime filenameEndTime, string lyricSubs1, string lyricSubs2)
        {
            int episodeNum = episodeCount + Settings.Instance.EpisodeStartNumber - 1;

            string tagArtist = name.createName(ConstantSettings.AudioId3Artist, episodeNum,
                                               progessCount, filenameStartTime, filenameEndTime, lyricSubs1, lyricSubs2);

            string tagAlbum = name.createName(ConstantSettings.AudioId3Album, episodeNum,
                                              progessCount, filenameStartTime, filenameEndTime, lyricSubs1, lyricSubs2);

            string tagTitle = name.createName(ConstantSettings.AudioId3Title, episodeNum,
                                              progessCount, filenameStartTime, filenameEndTime, lyricSubs1, lyricSubs2);

            string tagGenre = name.createName(ConstantSettings.AudioId3Genre, episodeNum,
                                              progessCount, filenameStartTime, filenameEndTime, lyricSubs1, lyricSubs2);

            string tagLyrics = name.createName(ConstantSettings.AudioId3Lyrics, episodeNum,
                                               progessCount, filenameStartTime, filenameEndTime, lyricSubs1, lyricSubs2);

            UtilsAudio.tagAudio(outName,
                                tagArtist,
                                tagAlbum,
                                tagTitle,
                                tagGenre,
                                tagLyrics,
                                curEpisodeCount,
                                totalTracks);
        }
        /// <summary>
        /// Format a pair of lyrics.
        /// </summary>
        private string formatLyricsPair(InfoCombined comb, UtilsName name, DateTime clipStartTime, int episode, int sequenceNum)
        {
            string pair = "";

            string subs1Text = comb.Subs1.Text;
            string subs2Text = comb.Subs2.Text;

            DateTime lyricStartTime = new DateTime();
            DateTime lyricEndTime   = new DateTime();

            lyricStartTime = lyricStartTime.AddMilliseconds(comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds - clipStartTime.TimeOfDay.TotalMilliseconds);
            lyricEndTime   = lyricEndTime.AddMilliseconds(comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds - clipStartTime.TimeOfDay.TotalMilliseconds);

            string nameStr = name.createName(ConstantSettings.ExtractMediaLyricsSubs1Format, episode,
                                             sequenceNum, lyricStartTime, lyricEndTime, subs1Text, subs2Text);


            pair += String.Format("{0}",
                                  nameStr);

            if (this.textBoxSubs2File.Text.Trim().Length > 0)
            {
                if (ConstantSettings.ExtractMediaLyricsSubs2Format != "")
                {
                    nameStr = name.createName(ConstantSettings.ExtractMediaLyricsSubs2Format, episode,
                                              sequenceNum, lyricStartTime, lyricEndTime, subs1Text, subs2Text);

                    pair += "\r\n";
                    pair += String.Format("{0}",
                                          nameStr);
                }
            }

            return(pair);
        }
Exemple #3
0
        /// <summary>
        /// Extract the image file(s) from the provided Vobsub subtitle text line.
        /// </summary>
        public static List <string> extractVobsubFilesFromText(string text)
        {
            List <string> images = new List <string>();

            UtilsName name = new UtilsName(Settings.Instance.DeckName, 0, 0, new DateTime(),
                                           Settings.Instance.VideoClips.Size.Width, Settings.Instance.VideoClips.Size.Height);
            string prefixStr = name.createName(ConstantSettings.SrsVobsubFilenamePrefix, 0, 0, new DateTime(), new DateTime(), "", "");
            string suffixStr = name.createName(ConstantSettings.SrsVobsubFilenameSuffix, 0, 0, new DateTime(), new DateTime(), "", "");

            try
            {
                // Multiple vobsub image can be shown in a single line, so extract each image
                // and concatenate them before displaying.
                MatchCollection matches = Regex.Matches(text,
                                                        prefixStr + "(?<VobsubImage>[\\w.-]*)" + suffixStr,
                                                        RegexOptions.Compiled);

                foreach (Match match in matches)
                {
                    images.Add(match.Groups["VobsubImage"].ToString().Trim());
                }
            }
            catch
            {
                return(images);
            }

            return(images);
        }
        /// <summary>
        /// Format a pair of dialog for the quick reference text file.
        /// </summary>
        private string formatQuickReferenceDialogPair(InfoCombined comb, UtilsName name, int episode, int sequenceNumber)
        {
            string pair = "";

            string subs1Text = comb.Subs1.Text;
            string subs2Text = comb.Subs2.Text;

            string nameStr = name.createName(ConstantSettings.DuelingQuickRefSubs1Format, episode,
                                             sequenceNumber, comb.Subs1.StartTime, comb.Subs1.StartTime, subs1Text, subs2Text);

            pair += String.Format("{0}",
                                  nameStr);

            if (this.textBoxSubs2File.Text.Trim().Length > 0)
            {
                if (ConstantSettings.DuelingQuickRefSubs2Format != "")
                {
                    nameStr = name.createName(ConstantSettings.DuelingQuickRefSubs2Format, episode,
                                              sequenceNumber, comb.Subs1.StartTime, comb.Subs1.StartTime, subs1Text, subs2Text);

                    pair += "\n";
                    pair += String.Format("{0}",
                                          nameStr);
                }
            }

            return(pair);
        }
Exemple #5
0
        /// <summary>
        /// Experimental video preview on the selected line.
        /// </summary>
        private void buttonPreviewVideo_Click(object sender, EventArgs e)
        {
            string videoConfigPlayer = "";

            if (previewWorkerVars == null || currentInfoComb == null || Settings.Instance.VideoClips.Files.Length == 0)
            {
                return;
            }

            videoConfigPlayer = ConstantSettings.VideoPlayer;

            // Check if the player exists
            if (!File.Exists(videoConfigPlayer))
            {
                UtilsMsg.showErrMsg(
                    $"The video player \"{ConstantSettings.VideoPlayer}\" \nprovided in {ConstantSettings.SettingsFilename} does not exist!");

                return;
            }

            // Kill the player before running it again.
            // For some reason the players that I tested (MPC-HC, ZoomPlayer, VLC) don't
            // read the start time arg correctly unless they are killed first.
            if (videoPlayerProcess != null)
            {
                if (!videoPlayerProcess.HasExited)
                {
                    videoPlayerProcess.Kill();
                }
            }

            DateTime startTime = currentInfoComb.Subs1.StartTime;
            DateTime endTime   = currentInfoComb.Subs1.EndTime;

            // Apply pad (if requested)
            if (Settings.Instance.VideoClips.PadEnabled)
            {
                startTime = UtilsSubs.applyTimePad(startTime, -Settings.Instance.VideoClips.PadStart);
                endTime   = UtilsSubs.applyTimePad(endTime, Settings.Instance.VideoClips.PadEnd);
            }

            UtilsName name = new UtilsName(Settings.Instance.DeckName, Settings.Instance.VideoClips.Files.Length,
                                           0, endTime, Settings.Instance.VideoClips.Size.Width, Settings.Instance.VideoClips.Size.Height);

            string videoConfigArgs = name.createName(ConstantSettings.VideoPlayerArgs,
                                                     comboBoxEpisode.SelectedIndex + Settings.Instance.EpisodeStartNumber - 1, 0, startTime, endTime, "",
                                                     "");

            string videoFileName = Settings.Instance.VideoClips.Files[comboBoxEpisode.SelectedIndex];
            string procArgs      = $"{videoConfigArgs} \"{videoFileName}\"";

            // Play the video
            videoPlayerProcess = new Process();
            videoPlayerProcess.StartInfo.FileName        = videoConfigPlayer;
            videoPlayerProcess.StartInfo.Arguments       = procArgs;
            videoPlayerProcess.StartInfo.UseShellExecute = false;
            videoPlayerProcess.StartInfo.CreateNoWindow  = true;
            videoPlayerProcess.Start();
        }
Exemple #6
0
        /// <summary>
        /// Generate snapshots for all episodes.
        /// </summary>
        public bool genSnapshots(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      progessCount  = 0;
            int      episodeCount  = 0;
            int      totalEpisodes = workerVars.CombinedAll.Count;
            int      totalLines    = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);
            DateTime lastTime      = UtilsSubs.getLastTime(workerVars.CombinedAll);

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, Settings.Instance.VideoClips.Size.Width,
                                           Settings.Instance.VideoClips.Size.Height);

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeCount++;

                // For each line in episode, generate a snapshot
                foreach (InfoCombined t in combArray)
                {
                    progessCount++;

                    string progressText = $"Generating snapshot: {progessCount.ToString()} of {totalLines.ToString()}";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    // Update the progress dialog
                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    InfoCombined comb      = t;
                    DateTime     startTime = comb.Subs1.StartTime;
                    DateTime     endTime   = comb.Subs1.EndTime;
                    DateTime     midTime   = UtilsSubs.getMidpointTime(startTime, endTime);

                    string videoFileName = Settings.Instance.VideoClips.Files[episodeCount - 1];

                    // Create output filename
                    string nameStr = name.createName(ConstantSettings.SnapshotFilenameFormat,
                                                     (int)episodeCount + Settings.Instance.EpisodeStartNumber - 1,
                                                     progessCount, startTime, endTime, comb.Subs1.Text, comb.Subs2.Text);

                    string outFile = $"{workerVars.MediaDir}{Path.DirectorySeparatorChar}{nameStr}"; // {2}

                    // Generate snapshot
                    UtilsSnapshot.takeSnapshotFromVideo(videoFileName, midTime, Settings.Instance.Snapshots.Size,
                                                        Settings.Instance.Snapshots.Crop, outFile);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Exemple #7
0
        /// <summary>
        /// Generate the SRS import file.
        /// </summary>
        public bool genSrs(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int episodeIdx    = -1;
            int totalEpisodes = workerVars.CombinedAll.Count;
            int lineIdx       = -1;
            int totalLines    = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);

            lastTime = UtilsSubs.getLastTime(workerVars.CombinedAll);

            name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                 totalLines, lastTime, Settings.Instance.VideoClips.Size.Width,
                                 Settings.Instance.VideoClips.Size.Height);

            string nameStr = name.createName(ConstantSettings.SrsFilenameFormat, 0,
                                             0, new DateTime(), new DateTime(), "", "");

            // Create filename
            // Example: <outdir>\Toki_wo_Kakeru_Shoujo.tsv
            string     srsFilename = $"{Settings.Instance.OutputDir}{Path.DirectorySeparatorChar}{nameStr}";
            TextWriter srsWriter   = new StreamWriter(srsFilename, false, Encoding.UTF8);

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeIdx++;
                lineIdx = -1;

                // For each line in episode, process
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;
                    lineIdx++;
                    mainComb = comb;

                    // Skip lines that are only needed for context
                    if (mainComb.OnlyNeededForContext)
                    {
                        continue;
                    }

                    string srsLine = "";

                    // Format the current import file line
                    srsLine = formatAll(workerVars.CombinedAll, episodeIdx, lineIdx, FormatType.Normal);

                    // Add leading context lines
                    if (Settings.Instance.ContextLeadingCount > 0)
                    {
                        for (int i = Settings.Instance.ContextLeadingCount; i > 0; i--)
                        {
                            int prevLineIdx = lineIdx - i;

                            if (prevLineIdx >= 0)
                            {
                                if (isLineInContextRange(combArray, lineIdx, prevLineIdx))
                                {
                                    srsLine += formatAll(workerVars.CombinedAll, episodeIdx, prevLineIdx,
                                                         FormatType.Leading);
                                }
                                else
                                {
                                    srsLine += formatContextPlaceholder(FormatType.Leading);
                                }
                            }
                            else
                            {
                                srsLine += formatContextPlaceholder(FormatType.Leading);
                            }
                        }
                    }

                    // Add trailing context lines
                    if (Settings.Instance.ContextTrailingCount > 0)
                    {
                        for (int i = 1; i <= Settings.Instance.ContextTrailingCount; i++)
                        {
                            int nextLineIdx = lineIdx + i;

                            if (nextLineIdx < combArray.Count)
                            {
                                if (isLineInContextRange(combArray, lineIdx, nextLineIdx))
                                {
                                    srsLine += formatAll(workerVars.CombinedAll, episodeIdx, nextLineIdx,
                                                         FormatType.Trailing);
                                }
                                else
                                {
                                    srsLine += formatContextPlaceholder(FormatType.Trailing);
                                }
                            }
                            else
                            {
                                srsLine += formatContextPlaceholder(FormatType.Trailing);
                            }
                        }
                    }

                    // Write line to file
                    srsWriter.WriteLine(srsLine);

                    string progressText =
                        $"Generating SRS (ex. Anki) import file: line {progessCount.ToString()} of {totalLines.ToString()}";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        srsWriter.Close();
                        return(false);
                    }
                }
            }

            srsWriter.Close();

            return(true);
        }
Exemple #8
0
        /// <summary>
        /// Parse the subtitle file and return a list of lines.
        /// </summary>
        override public List <InfoLine> parse()
        {
            List <InfoLine> lineInfos = new List <InfoLine>(2000);

            SubtitleCreator.SUP.reset();
            SubtitleCreator.SUP sup = SubtitleCreator.SUP.Instance;

            // Load in the .idx/.sub file (takes a while)
            sup.Filename = this.File;

            if (Settings.Instance.VobSubColors.Enabled)
            {
                sup.ReadSUP(this.Stream, Settings.Instance.VobSubColors.Colors, Settings.Instance.VobSubColors.TransparencyEnabled);
            }
            else
            {
                sup.ReadSUP(this.Stream, null, null);
            }

            UtilsName name = new UtilsName(Settings.Instance.DeckName, 0, 0, new DateTime(),
                                           Settings.Instance.VideoClips.Size.Width, Settings.Instance.VideoClips.Size.Height);

            for (int i = 0; i < sup.GetNoOfSubtitles(); i++)
            {
                DateTime startTime = sup.GetStartTime(i);
                DateTime endTime   = sup.GetEndTime(i);

                // Used for the filename and the desision to save the image file.
                // Not used to set the time of the InfoLine because the shift is
                // also applied in WorkerSubs
                DateTime shiftedStartTime = sup.GetStartTime(i);
                DateTime shiftedEndTime   = sup.GetEndTime(i);

                if (Settings.Instance.TimeShiftEnabled)
                {
                    shiftedStartTime = UtilsSubs.shiftTiming(shiftedStartTime, Settings.Instance.Subs[SubsNum - 1].TimeShift);
                    shiftedEndTime   = UtilsSubs.shiftTiming(shiftedEndTime, Settings.Instance.Subs[SubsNum - 1].TimeShift);
                }

                string bitmapFile = string.Format("{0}_{1:000.}_Stream_{2:00.}_Subs{3}_{4:000.}.{5:00.}.{6:00.}-{7:000.}.{8:00.}.{9:00.}.png",
                                                  Settings.Instance.DeckName,
                                                  this.Episode,
                                                  this.Stream,
                                                  this.SubsNum,
                                                  (int)shiftedStartTime.TimeOfDay.TotalMinutes,
                                                  (int)shiftedStartTime.TimeOfDay.Seconds,
                                                  (int)(shiftedStartTime.TimeOfDay.Milliseconds * 0.1),
                                                  (int)shiftedEndTime.TimeOfDay.TotalMinutes,
                                                  (int)shiftedEndTime.TimeOfDay.Seconds,
                                                  (int)(shiftedEndTime.TimeOfDay.Milliseconds * 0.1));

                DateTime spanStart = Settings.Instance.SpanStart;
                DateTime spanEnd   = Settings.Instance.SpanEnd;

                // Create a image file for each line of dialog
                if ((this.WorkerVars.ProcessingType == WorkerVars.SubsProcessingType.Preview) || // Always save the image when previewing
                    (!Settings.Instance.SpanEnabled) || // Always save the image when span is not enabled
                    ((shiftedStartTime >= spanStart) && (shiftedEndTime <= spanEnd))) // When span is enabled, only save the images that are within the span
                {
                    string imageSavePath = Path.Combine(this.WorkerVars.MediaDir, bitmapFile);
                    sup.GetBitmap(i).Save(imageSavePath, System.Drawing.Imaging.ImageFormat.Png);
                }

                string prefixStr = name.createName(ConstantSettings.SrsVobsubFilenamePrefix, 0, 0, new DateTime(), new DateTime(), "", "");
                string suffixStr = name.createName(ConstantSettings.SrsVobsubFilenameSuffix, 0, 0, new DateTime(), new DateTime(), "", "");

                // Set the line of dialog to the bitmap file
                string text = String.Format("{0}{1}{2}",
                                            prefixStr,  // {0}
                                            bitmapFile, // {1}
                                            suffixStr); // {2}

                InfoLine info = new InfoLine(startTime, endTime, text);
                lineInfos.Add(info);
            }

            lineInfos.Sort();

            return(lineInfos);
        }
Exemple #9
0
        /// <summary>
        /// Generate video clips for all episodes.
        /// </summary>
        public bool genVideoClip(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      progessCount  = 0;
            int      episodeCount  = 0;
            int      totalEpisodes = workerVars.CombinedAll.Count;
            int      totalLines    = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);
            DateTime lastTime      = UtilsSubs.getLastTime(workerVars.CombinedAll);

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, Settings.Instance.VideoClips.Size.Width, Settings.Instance.VideoClips.Size.Height);

            DialogProgress.updateProgressInvoke(dialogProgress, 0, "Creating video clips.");

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeCount++;

                // It is possible for all lines in an episode to be set to inactive
                if (combArray.Count == 0)
                {
                    // Skip this episode
                    continue;
                }

                string progressText = String.Format("Converting video file {0} of {1}",
                                                    episodeCount,
                                                    totalEpisodes);

                DialogProgress.updateProgressInvoke(dialogProgress, progressText);

                DateTime entireClipStartTime = combArray[0].Subs1.StartTime;
                DateTime entireClipEndTime   = combArray[combArray.Count - 1].Subs1.EndTime;

                // Apply pad to entire clip timings  (if requested)
                if (Settings.Instance.VideoClips.PadEnabled)
                {
                    entireClipStartTime = UtilsSubs.applyTimePad(entireClipStartTime, -Settings.Instance.VideoClips.PadStart);
                    entireClipEndTime   = UtilsSubs.applyTimePad(entireClipEndTime, Settings.Instance.VideoClips.PadEnd);
                }

                // Enable detail mode in progress dialog
                DialogProgress.enableDetailInvoke(dialogProgress, true);

                // Set the duration of the clip in the progress dialog  (for detail mode)
                DateTime entireClipDuration = UtilsSubs.getDurationTime(entireClipStartTime, entireClipEndTime);
                DialogProgress.setDuration(dialogProgress, entireClipDuration);

                string tempVideoFilename = Path.GetTempPath() + ConstantSettings.TempVideoFilename;
                string videoExtension    = ".avi";

                // Convert entire video (from first line to last line) based on user settings (size, crop, bitrate, etc).
                // It will be cut into smaller video clips later.
                if (Settings.Instance.VideoClips.IPodSupport)
                {
                    videoExtension     = ".mp4";
                    tempVideoFilename += videoExtension;

                    UtilsVideo.convertVideo(Settings.Instance.VideoClips.Files[episodeCount - 1],
                                            Settings.Instance.VideoClips.AudioStream.Num,
                                            entireClipStartTime, entireClipEndTime,
                                            Settings.Instance.VideoClips.Size, Settings.Instance.VideoClips.Crop,
                                            Settings.Instance.VideoClips.BitrateVideo, Settings.Instance.VideoClips.BitrateAudio,
                                            UtilsVideo.VideoCodec.h264, UtilsVideo.AudioCodec.AAC,
                                            UtilsVideo.Profilex264.IPod640, UtilsVideo.Presetx264.SuperFast,
                                            tempVideoFilename, dialogProgress);
                }
                else
                {
                    tempVideoFilename += videoExtension;

                    UtilsVideo.convertVideo(Settings.Instance.VideoClips.Files[episodeCount - 1],
                                            Settings.Instance.VideoClips.AudioStream.Num,
                                            entireClipStartTime, entireClipEndTime,
                                            Settings.Instance.VideoClips.Size, Settings.Instance.VideoClips.Crop,
                                            Settings.Instance.VideoClips.BitrateVideo, Settings.Instance.VideoClips.BitrateAudio,
                                            UtilsVideo.VideoCodec.MPEG4, UtilsVideo.AudioCodec.MP3,
                                            UtilsVideo.Profilex264.None, UtilsVideo.Presetx264.None,
                                            tempVideoFilename, dialogProgress);
                }

                DialogProgress.enableDetailInvoke(dialogProgress, false);

                // Generate a video clip for each line of the episode
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;

                    progressText = string.Format("Generating video clip: {0} of {1}",
                                                 progessCount.ToString(),
                                                 totalLines.ToString());

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    // Update the progress dialog
                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        File.Delete(tempVideoFilename);
                        return(false);
                    }

                    // Adjust timing to sync with the start of the converted video (which starts at the episode's first line of dialog)
                    DateTime startTime = UtilsSubs.shiftTiming(comb.Subs1.StartTime, -((int)entireClipStartTime.TimeOfDay.TotalMilliseconds));
                    DateTime endTime   = UtilsSubs.shiftTiming(comb.Subs1.EndTime, -((int)entireClipStartTime.TimeOfDay.TotalMilliseconds));

                    // Times used in the filename
                    DateTime filenameStartTime = comb.Subs1.StartTime;
                    DateTime filenameEndTime   = comb.Subs1.EndTime;

                    // Apply pad (if requested)
                    if (Settings.Instance.VideoClips.PadEnabled)
                    {
                        startTime         = UtilsSubs.applyTimePad(startTime, -Settings.Instance.VideoClips.PadStart);
                        endTime           = UtilsSubs.applyTimePad(endTime, Settings.Instance.VideoClips.PadEnd);
                        filenameStartTime = UtilsSubs.applyTimePad(comb.Subs1.StartTime, -Settings.Instance.VideoClips.PadStart);
                        filenameEndTime   = UtilsSubs.applyTimePad(comb.Subs1.EndTime, Settings.Instance.VideoClips.PadEnd);
                    }

                    // Create output filename
                    string nameStr = name.createName(ConstantSettings.VideoFilenameFormat, (int)episodeCount + Settings.Instance.EpisodeStartNumber - 1,
                                                     progessCount, filenameStartTime, filenameEndTime, comb.Subs1.Text, comb.Subs2.Text);

                    string outFile = string.Format("{0}{1}{2}{3}",
                                                   workerVars.MediaDir,         // {0}
                                                   Path.DirectorySeparatorChar, // {1}
                                                   nameStr,                     // {2}
                                                   videoExtension);             // {3}

                    // Cut video clip for current line
                    UtilsVideo.cutVideo(tempVideoFilename, startTime, endTime, outFile);
                }

                File.Delete(tempVideoFilename);
            }

            return(true);
        }
Exemple #10
0
        /// <summary>
        /// Generate Audio clips for all episodes.
        /// </summary>
        public bool genAudioClip(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      progessCount    = 0;
            int      episodeCount    = 0;
            int      totalEpisodes   = workerVars.CombinedAll.Count;
            int      curEpisodeCount = 0;
            int      totalLines      = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);
            DateTime lastTime        = UtilsSubs.getLastTime(workerVars.CombinedAll);

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, Settings.Instance.VideoClips.Size.Width,
                                           Settings.Instance.VideoClips.Size.Height);

            DialogProgress.updateProgressInvoke(dialogProgress, 0, "Creating audio clips.");

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeCount++;

                // It is possible for all lines in an episode to be set to inactive
                if (combArray.Count == 0)
                {
                    // Skip this episode
                    continue;
                }

                // Is the audio input an mp3 file?
                bool inputFileIsMp3 = Settings.Instance.AudioClips.Files.Length > 0 &&
                                      Path.GetExtension(Settings.Instance.AudioClips.Files[episodeCount - 1])
                                      .ToLower() == ".mp3";

                DateTime entireClipStartTime = combArray[0].Subs1.StartTime;
                DateTime entireClipEndTime   = combArray[combArray.Count - 1].Subs1.EndTime;
                string   tempMp3Filename     = Path.GetTempPath() + ConstantSettings.TempAudioFilename;

                // Apply pad to entire clip timings  (if requested)
                if (Settings.Instance.AudioClips.PadEnabled)
                {
                    entireClipStartTime =
                        UtilsSubs.applyTimePad(entireClipStartTime, -Settings.Instance.AudioClips.PadStart);
                    entireClipEndTime = UtilsSubs.applyTimePad(entireClipEndTime, Settings.Instance.AudioClips.PadEnd);
                }

                // Do we need to extract the audio from the video file?
                if (Settings.Instance.AudioClips.UseAudioFromVideo)
                {
                    string progressText = $"Extracting audio from video file {episodeCount} of {totalEpisodes}"; // {1}

                    bool success = convertToMp3(
                        Settings.Instance.VideoClips.Files[episodeCount - 1],
                        Settings.Instance.VideoClips.AudioStream.Num,
                        progressText,
                        dialogProgress,
                        entireClipStartTime,
                        entireClipEndTime,
                        tempMp3Filename);

                    if (!success)
                    {
                        UtilsMsg.showErrMsg("Failed to extract the audio from the video.\n" +
                                            "Make sure that the video does not have any DRM restrictions.");
                        return(false);
                    }
                }
                // If the reencode option is set or the input audio is not an mp3, reencode to mp3
                else if (ConstantSettings.ReencodeBeforeSplittingAudio || !inputFileIsMp3)
                {
                    string progressText = $"Reencoding audio file {episodeCount} of {totalEpisodes}";

                    bool success = convertToMp3(
                        Settings.Instance.AudioClips.Files[episodeCount - 1],
                        "0",
                        progressText,
                        dialogProgress,
                        entireClipStartTime,
                        entireClipEndTime,
                        tempMp3Filename);

                    if (!success)
                    {
                        UtilsMsg.showErrMsg("Failed to reencode the audio file.\n" +
                                            "Make sure that the audio file does not have any DRM restrictions.");
                        return(false);
                    }
                }

                curEpisodeCount = 0; // Reset

                // For each line in episode, generate an audio clip
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;
                    curEpisodeCount++;

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    string progressText =
                        $"Generating audio clip: {progessCount.ToString()} of {totalLines.ToString()}";

                    // Update the progress dialog
                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        File.Delete(tempMp3Filename);
                        return(false);
                    }

                    DateTime startTime         = comb.Subs1.StartTime;
                    DateTime endTime           = comb.Subs1.EndTime;
                    DateTime filenameStartTime = comb.Subs1.StartTime;
                    DateTime filenameEndTime   = comb.Subs1.EndTime;
                    string   fileToCut         = "";

                    if (Settings.Instance.AudioClips.UseAudioFromVideo ||
                        ConstantSettings.ReencodeBeforeSplittingAudio || !inputFileIsMp3)
                    {
                        startTime = UtilsSubs.shiftTiming(startTime,
                                                          -(int)entireClipStartTime.TimeOfDay.TotalMilliseconds);
                        endTime = UtilsSubs.shiftTiming(endTime,
                                                        -(int)entireClipStartTime.TimeOfDay.TotalMilliseconds);
                        fileToCut = tempMp3Filename;
                    }
                    else
                    {
                        fileToCut = Settings.Instance.AudioClips.Files[episodeCount - 1];
                    }

                    // Apply pad (if requested)
                    if (Settings.Instance.AudioClips.PadEnabled)
                    {
                        startTime         = UtilsSubs.applyTimePad(startTime, -Settings.Instance.AudioClips.PadStart);
                        endTime           = UtilsSubs.applyTimePad(endTime, Settings.Instance.AudioClips.PadEnd);
                        filenameStartTime = UtilsSubs.applyTimePad(comb.Subs1.StartTime,
                                                                   -Settings.Instance.AudioClips.PadStart);
                        filenameEndTime =
                            UtilsSubs.applyTimePad(comb.Subs1.EndTime, Settings.Instance.AudioClips.PadEnd);
                    }

                    string lyricSubs2 = "";

                    // Set the Subs2 lyric if it exists
                    if (Settings.Instance.Subs[1].Files.Length != 0)
                    {
                        lyricSubs2 = comb.Subs2.Text.Trim();
                    }

                    // Create output filename
                    string nameStr = name.createName(ConstantSettings.AudioFilenameFormat,
                                                     (int)episodeCount + Settings.Instance.EpisodeStartNumber - 1,
                                                     progessCount, filenameStartTime, filenameEndTime, comb.Subs1.Text, lyricSubs2);

                    string outName = $"{workerVars.MediaDir}{Path.DirectorySeparatorChar}{nameStr}"; // {2}

                    // Create audio clip
                    UtilsAudio.cutAudio(fileToCut, startTime, endTime, outName);

                    // Tag the audio clip
                    tagAudio(name, outName, episodeCount, curEpisodeCount, progessCount, combArray.Count,
                             filenameStartTime, filenameEndTime, comb.Subs1.Text, lyricSubs2);
                }

                File.Delete(tempMp3Filename);
            }

            // Normalize all mp3 files in the media directory
            if (Settings.Instance.AudioClips.Normalize)
            {
                DialogProgress.updateProgressInvoke(dialogProgress, -1, "Normalizing audio...");

                UtilsAudio.normalizeAudio(workerVars.MediaDir);
            }

            return(true);
        }
        /// <summary>
        /// Performs the work of the audio extraction thread.
        /// </summary>
        private void splitAudio(object sender, DoWorkEventArgs e)
        {
            WorkerVars workerVars = e.Argument as WorkerVars;
            List <List <InfoCombined> > combinedAll = new List <List <InfoCombined> >();
            WorkerSubs subsWorker = new WorkerSubs();

            if (groupBoxCheckLyrics.Checked)
            {
                // Parse and combine the subtitles
                try
                {
                    combinedAll = subsWorker.combineAllSubs(workerVars, dialogProgress);

                    if (combinedAll != null)
                    {
                        workerVars.CombinedAll = combinedAll;
                    }
                    else
                    {
                        e.Cancel = true;
                        return;
                    }
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong before processing could start.\n" + e1);
                    e.Cancel = true;
                    return;
                }
            }

            DateTime mediaStartime = new DateTime();
            DateTime mediaEndtime  = new DateTime();
            DateTime mediaDuration = new DateTime();

            int episode = 0;

            DialogProgress.updateProgressInvoke(dialogProgress, 0, "Starting...");


            foreach (string file in mediaFiles)
            {
                episode++;

                try
                {
                    mediaEndtime = UtilsVideo.getVideoLength(file);
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong while determining duration of the media:\n" + e1);
                    return;
                }

                if (useSpan)
                {
                    mediaStartime = spanStart;

                    // If the span end time if not greater than the actual duration of the media
                    if (spanEnd < mediaEndtime)
                    {
                        mediaEndtime = spanEnd;
                    }
                }

                UtilsName name = new UtilsName(
                    deckName,
                    mediaFiles.Length, // Total number of episodes
                    1,                 // Total number of lines (Note: not filled out here)
                    mediaEndtime,      // Last time
                    0, 0               // Width and height (Note: not filled out anywhere)
                    );

                mediaDuration = UtilsSubs.getDurationTime(mediaStartime, mediaEndtime);

                string progressText = String.Format("Processing audio from media file {0} of {1}",
                                                    episode,
                                                    mediaFiles.Length);

                int progress = Convert.ToInt32((episode - 1) * (100.0 / mediaFiles.Length));

                DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                // Enable detail mode in progress dialog
                DialogProgress.enableDetailInvoke(dialogProgress, true);

                // Set the duration of the clip in the progress dialog  (for detail mode)
                DialogProgress.setDuration(dialogProgress, mediaDuration);


                string tempMp3Filename = Path.GetTempPath() + ConstantSettings.TempAudioFilename;

                UtilsAudio.ripAudioFromVideo(mediaFiles[episode - 1],
                                             audioStream.Num,
                                             mediaStartime, mediaEndtime,
                                             bitrate, tempMp3Filename, dialogProgress);

                DialogProgress.enableDetailInvoke(dialogProgress, false);

                if (dialogProgress.Cancel)
                {
                    e.Cancel = true;
                    File.Delete(tempMp3Filename);
                    return;
                }

                int numClips = 1;

                if (!isSingleFile)
                {
                    numClips = (int)Math.Ceiling((mediaDuration.TimeOfDay.TotalMilliseconds / (clipLength.TimeOfDay.TotalSeconds * 1000.0)));
                }

                for (int clipIdx = 0; clipIdx < numClips; clipIdx++)
                {
                    progressText = String.Format("Splitting segment {0} of {1} from media file {2} of {3}",
                                                 clipIdx + 1,
                                                 numClips,
                                                 episode,
                                                 mediaFiles.Length);

                    progress = Convert.ToInt32((episode - 1) * (100.0 / mediaFiles.Length));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);


                    if (dialogProgress.Cancel)
                    {
                        e.Cancel = true;
                        File.Delete(tempMp3Filename);
                        return;
                    }

                    // The start and end times used for processing
                    DateTime startTime = new DateTime();
                    DateTime endTime   = new DateTime();

                    if (isSingleFile)
                    {
                        endTime = mediaDuration;
                    }
                    else
                    {
                        startTime = startTime.AddSeconds((double)(clipLength.TimeOfDay.TotalSeconds * clipIdx));
                        endTime   = endTime.AddSeconds((double)(clipLength.TimeOfDay.TotalSeconds * (clipIdx + 1)));

                        if (endTime.TimeOfDay.TotalMilliseconds >= mediaDuration.TimeOfDay.TotalMilliseconds)
                        {
                            endTime = mediaDuration;
                        }
                    }

                    // The start and end times that will be displayed
                    DateTime startTimeName = startTime.AddMilliseconds(mediaStartime.TimeOfDay.TotalMilliseconds);
                    DateTime endTimeName   = endTime.AddMilliseconds(mediaStartime.TimeOfDay.TotalMilliseconds);

                    // Fill in the total number of lines with the total number of clips
                    name.TotalNumLines = numClips;

                    string nameStr = name.createName(ConstantSettings.ExtractMediaAudioFilenameFormat, episode + episodeStartNumber - 1,
                                                     clipIdx + 1, startTimeName, endTimeName, "", "");


                    string outName = String.Format("{0}{1}{2}",
                                                   outputDir,                   // {0}
                                                   Path.DirectorySeparatorChar, // {1}
                                                   nameStr);                    // {2}

                    UtilsAudio.cutAudio(tempMp3Filename, startTime, endTime, outName);

                    nameStr = name.createName(ConstantSettings.AudioId3Artist, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagArtist = String.Format("{0}",
                                                     nameStr); // {0}

                    nameStr = name.createName(ConstantSettings.AudioId3Album, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagAlbum = String.Format("{0}",
                                                    nameStr); // {0}

                    nameStr = name.createName(ConstantSettings.AudioId3Title, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagTitle = String.Format("{0}",
                                                    nameStr); // {0}

                    nameStr = name.createName(ConstantSettings.AudioId3Genre, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagGenre = String.Format("{0}",
                                                    nameStr); // {0}

                    string tagLyrics = "";

                    if (groupBoxCheckLyrics.Checked)
                    {
                        int totalLyricsLines = 0;
                        int curLyricsNum     = 1;

                        // Precount the number of lyrics lines
                        foreach (InfoCombined comb in combinedAll[episode - 1])
                        {
                            if (comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds >= startTimeName.TimeOfDay.TotalMilliseconds &&
                                comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds <= endTimeName.TimeOfDay.TotalMilliseconds)
                            {
                                totalLyricsLines++;
                            }
                        }

                        // Fill in the total number of lyrics lines
                        name.TotalNumLines = curLyricsNum;

                        // Foreach comb in the current episode, if the comb lies within the
                        // current clip, add it to the lryics tag
                        foreach (InfoCombined comb in combinedAll[episode - 1])
                        {
                            if (comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds >= startTimeName.TimeOfDay.TotalMilliseconds &&
                                comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds <= endTimeName.TimeOfDay.TotalMilliseconds)
                            {
                                tagLyrics += formatLyricsPair(comb, name, startTimeName, episode + episodeStartNumber - 1, curLyricsNum) + "\r\n";
                                curLyricsNum++;
                            }
                        }
                    }

                    UtilsAudio.tagAudio(outName,
                                        tagArtist,
                                        tagAlbum,
                                        tagTitle,
                                        tagGenre,
                                        tagLyrics,
                                        clipIdx + 1,
                                        numClips);
                }
            }

            return;
        }
        /// <summary>
        /// Create the quick reference text file.
        /// </summary>
        private bool createQuickReference(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      totalLines    = 0;
            int      progessCount  = 0;
            int      episodeIdx    = -1;
            int      totalEpisodes = workerVars.CombinedAll.Count;
            int      lineIdx       = -1;
            DateTime lastTime      = new DateTime();

            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                totalLines += combArray.Count;

                // Get the last time
                foreach (InfoCombined info in combArray)
                {
                    if (info.Subs1.EndTime.TimeOfDay.TotalMilliseconds > lastTime.TimeOfDay.TotalMilliseconds)
                    {
                        lastTime = new DateTime();
                        lastTime = lastTime.AddMilliseconds(info.Subs1.EndTime.TimeOfDay.TotalMilliseconds);
                    }
                }
            }

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, 0, 0);

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeIdx++;
                lineIdx = -1;

                string nameStr = name.createName(ConstantSettings.DuelingQuickRefFilenameFormat, Settings.Instance.EpisodeStartNumber + episodeIdx,
                                                 0, new DateTime(), new DateTime(), "", "");

                // Create filename
                string subtitleFilename = String.Format("{0}{1}{2}",
                                                        Settings.Instance.OutputDir,
                                                        Path.DirectorySeparatorChar,
                                                        nameStr);
                TextWriter subtitleWriter = new StreamWriter(subtitleFilename, false, Encoding.UTF8);

                /*
                 * [0:00:31.14]  This is the first line from Subs1
                 * [0:00:31.14]  This is corresponding line from Subs2
                 *
                 * [0:00:34.35]  This is the second line from Subs1
                 * [0:00:34.35]  This is corresponding line from Subs2
                 */

                // For each line in episode
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;
                    lineIdx++;

                    string dialogLine = formatQuickReferenceDialogPair(comb, name, Settings.Instance.EpisodeStartNumber + episodeIdx, progessCount);

                    // Write line to file
                    subtitleWriter.WriteLine(dialogLine);


                    string progressText = string.Format("Generating quick reference file: line {0} of {1}",
                                                        progessCount.ToString(),
                                                        totalLines.ToString());

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    if (dialogProgress.Cancel)
                    {
                        subtitleWriter.Close();
                        return(false);
                    }
                }

                subtitleWriter.Close();
            }

            return(true);
        }
        /// <summary>
        /// Create the Dueling Subtitles .ass file.
        /// </summary>
        private bool createDuelingSubtitles(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      totalLines    = 0;
            int      progessCount  = 0;
            int      totalEpisodes = workerVars.CombinedAll.Count;
            int      episodeIdx    = -1;
            int      lineIdx       = -1;
            DateTime lastTime      = new DateTime();

            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                totalLines += combArray.Count;

                // Get the last time
                foreach (InfoCombined info in combArray)
                {
                    if (info.Subs1.EndTime.TimeOfDay.TotalMilliseconds > lastTime.TimeOfDay.TotalMilliseconds)
                    {
                        lastTime = new DateTime();
                        lastTime = lastTime.AddMilliseconds(info.Subs1.EndTime.TimeOfDay.TotalMilliseconds);
                    }
                }
            }

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, 0, 0);

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeIdx++;
                lineIdx = -1;

                string nameStr = name.createName(ConstantSettings.DuelingSubtitleFilenameFormat, Settings.Instance.EpisodeStartNumber + episodeIdx,
                                                 0, new DateTime(), new DateTime(), "", "");

                // Create filename
                string subtitleFilename = String.Format("{0}{1}{2}",
                                                        Settings.Instance.OutputDir,
                                                        Path.DirectorySeparatorChar,
                                                        nameStr);
                TextWriter subtitleWriter = new StreamWriter(subtitleFilename, false, Encoding.UTF8);

                /*
                 * Example .ass file:
                 * ; Generated with subs2srs - http://sourceforge.net/projects/subs2srs/
                 *
                 * [Script Info]
                 * Title:Some_Title_001
                 * ScriptType:v4.00+
                 * Collisions:Normal
                 * Timer:100.0000
                 *
                 * [V4+ Styles]
                 * Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
                 * Style: Subs1,Meiryo,18,&H00F9EDFF,&H0000FFFF,&H3C2B0E17,&HA0000000,0,0,0,0,84,100,0,0,1,2,1,2,10,10,15,1
                 * Style: Subs2,Meiryo,18,&H00F9EDFF,&H0000FFFF,&H3C2B0E17,&HA0000000,0,0,0,0,84,100,0,0,1,2,1,2,10,10,15,1
                 *
                 * [Events]
                 * Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text
                 *
                 * Dialogue: 0,0:00:31.14,0:00:36.16,Subs1,NTP,0000,0000,0000,,This is the first line from Subs1
                 * Dialogue: 0,0:00:31.14,0:00:36.16,Subs2,NTP,0000,0000,0000,,This is corresponding line from Subs2
                 *
                 * etc.
                 */

                // [Script Info]
                string scriptInfoText = formatScriptInfoText(Settings.Instance.EpisodeStartNumber + episodeIdx);
                subtitleWriter.WriteLine(scriptInfoText);

                // [V4+ Styles]
                string stylesText = formatSytlesText();
                subtitleWriter.WriteLine(stylesText);

                // [Events] (header)
                string eventsHeaderText = formatEventHeaderText();
                subtitleWriter.WriteLine(eventsHeaderText);

                // For each line in episode, [Events] Dialog: ...
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;
                    lineIdx++;

                    string dialogLine = "";

                    dialogLine = formatDialogPair(workerVars.CombinedAll, episodeIdx, lineIdx);

                    // Write line to file
                    subtitleWriter.WriteLine(dialogLine);

                    string progressText = string.Format("Generating Subtitle file: line {0} of {1}",
                                                        progessCount.ToString(),
                                                        totalLines.ToString());

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    if (dialogProgress.Cancel)
                    {
                        subtitleWriter.Close();
                        return(false);
                    }
                }

                subtitleWriter.Close();
            }

            return(true);
        }