private void btnPreview_Click(object sender, EventArgs e) { var filePaths = txbFilePath.Text.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); if (filePaths.Length == 0) { MessageBox.Show("未选择字幕文件"); return; } SubtitleFiles.Clear(); stOperator = SubtitleHelper.GetOperatorByFileName(filePaths[0]); foreach (var filePath in filePaths) { var content = FileOperationHelper.ReadFile(filePath); var srts = stOperator.Parse(content); SubtitleFiles.Add(filePath, srts); } richTextBox1.Clear(); foreach (var subtitleFile in SubtitleFiles) { richTextBox1.AppendText("----" + subtitleFile.Key + "----\r\n"); richTextBox1.AppendText(stOperator.Subtitle2String(subtitleFile.Value)); } }
private static async Task <bool> SendSegmentAsync(string fileName, IOwinContext context, StreamItem streamItem) { if (!string.IsNullOrEmpty(fileName) && streamItem.StreamContext is TranscodeContext tc) { using (await streamItem.RequestBusyLockAsync(SendDataCancellation.Token)) { var segment = await MediaConverter.GetSegmentFileAsync((VideoTranscoding)streamItem.TranscoderObject.TranscodingParameter, tc, fileName); if (segment != null) { if (segment.Value.ContainerEnum is VideoContainer) { VideoTranscoding video = (VideoTranscoding)streamItem.TranscoderObject.TranscodingParameter; List <string> profiles = ProfileMime.ResolveVideoProfile((VideoContainer)segment.Value.ContainerEnum, video.TargetVideoCodec, video.TargetAudioCodec, EncodingProfile.Unknown, 0, 0, 0, 0, 0, 0, Timestamp.None); string mime = "video/unknown"; ProfileMime.FindCompatibleMime(streamItem.Profile, profiles, ref mime); context.Response.ContentType = mime; } else if (segment.Value.ContainerEnum is SubtitleCodec) { context.Response.ContentType = SubtitleHelper.GetSubtitleMime((SubtitleCodec)segment.Value.ContainerEnum); } bool onlyHeaders = context.Request.Method == "HEAD" || context.Response.StatusCode == (int)HttpStatusCode.NotModified; Logger.Debug("RetrieveStream: Sending file header only: {0}", onlyHeaders.ToString()); await SendWholeFileAsync(context, segment.Value.FileData, onlyHeaders); // Close the Stream so that FFMpeg can replace the playlist file segment.Value.FileData.Dispose(); return(true); } } } return(false); }
private void btnPickupNewWords_Click(object sender, EventArgs e) { if (folderBrowserDialog1.ShowDialog() != DialogResult.OK) { return; } SentenceParse sentenceParse = new SentenceParse(); DirectoryInfo directoryInfo = new DirectoryInfo(folderBrowserDialog1.SelectedPath); List <string> sentences = new List <string>(); foreach (FileInfo fileInfo in directoryInfo.GetFiles()) { string filePath = fileInfo.FullName; var txt = FileOperationHelper.ReadFile(filePath); var stOperator = SubtitleHelper.GetOperatorByFileName(filePath); var srts = stOperator.Parse(txt); srts = stOperator.RemoveChinese(srts); sentences.AddRange(srts.Bodies.Values.Select(l => l.EnglishText)); } Splash.Show(); Splash.Status = "解析字幕中..."; IDictionary <string, VPreviewWord> previewWords = new Dictionary <string, VPreviewWord>(); foreach (var sentence in sentences) { var newWords = sentenceParse.Pickup(sentence); foreach (KeyValuePair <string, string> keyValuePair in newWords) { string original = keyValuePair.Key; string word = keyValuePair.Value; if (previewWords.ContainsKey(original)) { previewWords[original].Rank++; } else { var mean = sentenceParse.RemarkWord(sentence, word, original); if (mean != null) { var wd = new VPreviewWord() { Word = mean.Word, Rank = 1, Sentence = sentence, Mean = mean.DefaultMean == null ? mean.Means[0].ToString() : mean.DefaultMean.ToString() }; previewWords.Add(original, wd); } } } } DisplayPreviewWords(previewWords.Values); Splash.Close(); }
public Media(string fileName, string path) { Path = path; FileName = fileName; ShowName = SeriesHelper.GetTitle(fileName); EpisodeNumber = SeriesHelper.GetEpisodeNumber(fileName); SeasonNumber = SeriesHelper.GetSeasonNumber(fileName); Releaser = SubtitleHelper.GetReleaser(fileName); Quality = SubtitleHelper.GetQuality(fileName); }
private void btnParse_Click(object sender, EventArgs e) { var txt = FileOperationHelper.ReadFile(txbSubtitleFilePath.Text); stOperator = SubtitleHelper.GetOperatorByFileName(txbSubtitleFilePath.Text); var srts = stOperator.Parse(txt); srts = stOperator.RemoveChinese(srts); ShowSubtitleText(srts.Bodies); subtitle = srts; }
private void ReadAndShowSubtitle() { var txt = FileOperationHelper.ReadFile(txbSubtitleFilePath.Text); stOperator = SubtitleHelper.GetOperatorByFileName(txbSubtitleFilePath.Text); var srts = stOperator.Parse(txt); srts = stOperator.RemoveChinese(srts); srts = stOperator.RemoveFormat(srts); ShowSubtitleText(srts.Bodies.Values); subtitle = srts; }
public bool RefreshMediaInfo() { try { logger.Trace("Getting media info for: {0}", FullServerPath ?? VideoLocal_Place_ID.ToString()); MediaContainer m = null; if (VideoLocal == null) { logger.Error($"VideoLocal for {FullServerPath ?? VideoLocal_Place_ID.ToString()} failed to be retrived for MediaInfo"); return(false); } if (FullServerPath != null) { if (GetFile() == null) { logger.Error($"File {FullServerPath ?? VideoLocal_Place_ID.ToString()} failed to be retrived for MediaInfo"); return(false); } string name = FullServerPath.Replace("/", $"{Path.DirectorySeparatorChar}"); m = Utilities.MediaInfoLib.MediaInfo.GetMediaInfo(name); //Mediainfo should have libcurl.dll for http var duration = m?.GeneralStream?.Duration ?? 0; if (duration == 0) { m = null; } } if (m != null) { SVR_VideoLocal info = VideoLocal; List <TextStream> subs = SubtitleHelper.GetSubtitleStreams(this); if (subs.Count > 0) { m.media.track.AddRange(subs); } info.Media = m; return(true); } logger.Error($"File {FullServerPath ?? VideoLocal_Place_ID.ToString()} failed to read MediaInfo"); } catch (Exception e) { logger.Error($"Unable to read the media information of file {FullServerPath ?? VideoLocal_Place_ID.ToString()} ERROR: {e}"); } return(false); }
public static string GetSubtitleBaseURL(Guid mediaItemId, EndPointSettings client, out string subMime, out string subExtension) { SubtitleCodec codec = SubtitleCodec.Unknown; subMime = null; subExtension = null; if (UseSoftCodedSubtitle(client, out codec, out subMime) == true) { subExtension = SubtitleHelper.GetSubtitleExtension(codec); string subType = codec.ToString(); return(string.Format(GetBaseResourceURL() + GetResourceUrl(mediaItemId.ToString(), client.ClientId) + "&aspect=SUBTITLE&type={0}&file=subtitle.{1}", subType, subExtension)); } return(null); }
public static bool UseSoftCodedSubtitle(EndPointSettings client, out SubtitleCodec targetCodec, out string targetMime) { targetCodec = SubtitleCodec.Unknown; targetMime = "text/plain"; if (client.Profile.MediaTranscoding.SubtitleSettings.SubtitleMode == SubtitleSupport.SoftCoded) { targetCodec = client.Profile.MediaTranscoding.SubtitleSettings.SubtitlesSupported[0].Format; if (string.IsNullOrEmpty(client.Profile.MediaTranscoding.SubtitleSettings.SubtitlesSupported[0].Mime) == false) { targetMime = client.Profile.MediaTranscoding.SubtitleSettings.SubtitlesSupported[0].Mime; } else { targetMime = SubtitleHelper.GetSubtitleMime(targetCodec); } return(true); } return(false); }
// returns false if we should retry private bool MoveFileIfRequired(bool deleteEmpty = true) { // TODO move A LOT of this into renamer helper methods. A renamer can do them optionally if (!ServerSettings.Instance.Import.MoveOnImport) { logger.Trace($"Skipping move of \"{this.FullServerPath}\" as move on import is disabled"); return(true); } // TODO Make this take an argument to disable removing empty dirs. It's slow, and should only be done if needed try { logger.Trace($"Attempting to MOVE file: \"{FullServerPath ?? VideoLocal_Place_ID.ToString()}\""); if (FullServerPath == null) { logger.Error($"Could not find or access the file to move: {VideoLocal_Place_ID}"); return(true); } // check if this file is in the drop folder // otherwise we don't need to move it if (ImportFolder.IsDropSource == 0) { logger.Trace($"Not moving file as it is NOT in the drop folder: \"{FullServerPath}\""); return(true); } if (!File.Exists(FullServerPath)) { logger.Error($"Could not find or access the file to move: \"{FullServerPath}\""); // this can happen due to file locks, so retry return(false); } var sourceFile = new FileInfo(FullServerPath); // find the default destination (var destImpl, string newFolderPath) = RenameFileHelper.GetDestination(this, null); if (!(destImpl is SVR_ImportFolder destFolder)) { // In this case, an error string was returned, but we'll suppress it and give an error elsewhere if (newFolderPath != null) { return(true); } logger.Error($"Could not find a valid destination: \"{FullServerPath}\""); return(true); } // keep the original drop folder for later (take a copy, not a reference) SVR_ImportFolder dropFolder = ImportFolder; if (string.IsNullOrEmpty(newFolderPath)) { return(true); } // We've already resolved FullServerPath, so it doesn't need to be checked string newFilePath = Path.Combine(newFolderPath, Path.GetFileName(FullServerPath)); string newFullServerPath = Path.Combine(destFolder.ImportFolderLocation, newFilePath); var destFullTree = Path.Combine(destFolder.ImportFolderLocation, newFolderPath); if (!Directory.Exists(destFullTree)) { try { Directory.CreateDirectory(destFullTree); } catch (Exception e) { logger.Error(e); return(true); } } // Last ditch effort to ensure we aren't moving a file unto itself if (newFullServerPath.Equals(FullServerPath, StringComparison.InvariantCultureIgnoreCase)) { logger.Error($"Resolved to move \"{newFullServerPath}\" unto itself. NOT MOVING"); return(true); } var originalFileName = FullServerPath; var textStreams = SubtitleHelper.GetSubtitleStreams(this); if (File.Exists(newFullServerPath)) { // A file with the same name exists at the destination. // Handle Duplicate Files, A duplicate file record won't exist yet, // so we'll check the old fashioned way logger.Trace("A file already exists at the new location, checking it for duplicate"); var destVideoLocalPlace = RepoFactory.VideoLocalPlace.GetByFilePathAndImportFolderID(newFilePath, destFolder.ImportFolderID); var destVideoLocal = destVideoLocalPlace?.VideoLocal; if (destVideoLocal == null) { logger.Error("The existing file at the new location does not have a VideoLocal. Not moving"); return(true); } if (destVideoLocal.Hash == VideoLocal.Hash) { logger.Info($"Not moving file as it already exists at the new location, deleting source file instead: \"{FullServerPath}\" --- \"{newFullServerPath}\""); // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving try { sourceFile.Delete(); } catch (Exception e) { logger.Warn($"Unable to DELETE file: \"{FullServerPath}\" error {e}"); RemoveRecord(false); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource != 1) { return(true); } RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); return(true); } } // Not a dupe, don't delete it logger.Trace("A file already exists at the new location, checking it for version and group"); var destinationExistingAniDBFile = destVideoLocal.GetAniDBFile(); if (destinationExistingAniDBFile == null) { logger.Error("The existing file at the new location does not have AniDB info. Not moving."); return(true); } var aniDBFile = VideoLocal.GetAniDBFile(); if (aniDBFile == null) { logger.Error("The file does not have AniDB info. Not moving."); return(true); } if (destinationExistingAniDBFile.Anime_GroupName == aniDBFile.Anime_GroupName && destinationExistingAniDBFile.FileVersion < aniDBFile.FileVersion) { // This is a V2 replacing a V1 with the same name. // Normally we'd let the Multiple Files Utility handle it, but let's just delete the V1 logger.Info("The existing file is a V1 from the same group. Replacing it."); // Delete the destination (bool success, string _) = destVideoLocalPlace.RemoveAndDeleteFile(); if (!success) { return(false); } // Move ShokoServer.PauseWatchingFiles(); logger.Info($"Moving file from \"{FullServerPath}\" to \"{newFullServerPath}\""); try { sourceFile.MoveTo(newFullServerPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{FullServerPath}\" to \"{newFullServerPath}\" error {e}"); ShokoServer.UnpauseWatchingFiles(); return(false); } // Handle Duplicate Files var dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID).ToList(); foreach (var dup in dups) { // Move source if (dup.FilePathFile1.Equals(FilePath) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = newFilePath; dup.ImportFolderIDFile1 = destFolder.ImportFolderID; } else if (dup.FilePathFile2.Equals(FilePath) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = newFilePath; dup.ImportFolderIDFile2 = destFolder.ImportFolderID; } // validate the dup file // There are cases where a dup file was not cleaned up before, so we'll do it here, too if (!dup.GetFullServerPath1() .Equals(dup.GetFullServerPath2(), StringComparison.InvariantCultureIgnoreCase)) { RepoFactory.DuplicateFile.Save(dup); } else { RepoFactory.DuplicateFile.Delete(dup); } } ImportFolderID = destFolder.ImportFolderID; FilePath = newFilePath; RepoFactory.VideoLocalPlace.Save(this); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1 && deleteEmpty) { RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); } } } else { ShokoServer.PauseWatchingFiles(); logger.Info($"Moving file from \"{FullServerPath}\" to \"{newFullServerPath}\""); try { sourceFile.MoveTo(newFullServerPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{FullServerPath}\" to \"{newFullServerPath}\" error {e}"); ShokoServer.UnpauseWatchingFiles(); return(false); } // Handle Duplicate Files var dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID).ToList(); foreach (var dup in dups) { // Move source if (dup.FilePathFile1.Equals(FilePath) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = newFilePath; dup.ImportFolderIDFile1 = destFolder.ImportFolderID; } else if (dup.FilePathFile2.Equals(FilePath) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = newFilePath; dup.ImportFolderIDFile2 = destFolder.ImportFolderID; } // validate the dup file // There are cases where a dup file was not cleaned up before, so we'll do it here, too if (!dup.GetFullServerPath1() .Equals(dup.GetFullServerPath2(), StringComparison.InvariantCultureIgnoreCase)) { RepoFactory.DuplicateFile.Save(dup); } else { RepoFactory.DuplicateFile.Delete(dup); } } ImportFolderID = destFolder.ImportFolderID; FilePath = newFilePath; RepoFactory.VideoLocalPlace.Save(this); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1 && deleteEmpty) { RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); } } try { // move any subtitle files foreach (TextStream subtitleFile in textStreams) { if (string.IsNullOrEmpty(subtitleFile.Filename)) { continue; } var newParent = Path.GetDirectoryName(newFullServerPath); var srcParent = Path.GetDirectoryName(originalFileName); if (string.IsNullOrEmpty(newParent) || string.IsNullOrEmpty(srcParent)) { continue; } var subPath = Path.Combine(srcParent, subtitleFile.Filename); if (!File.Exists(subPath)) { continue; } var subFile = new FileInfo(subPath); string newSubPath = Path.Combine(newParent, subFile.Name); if (File.Exists(newSubPath)) { try { File.Delete(newSubPath); } catch (Exception e) { logger.Warn($"Unable to DELETE file: \"{subtitleFile}\" error {e}"); } } try { subFile.MoveTo(newSubPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{subtitleFile}\" to \"{newSubPath}\" error {e}"); } } } catch (Exception ex) { logger.Error(ex, ex.ToString()); } } catch (Exception ex) { logger.Error(ex, $"Could not MOVE file: \"{FullServerPath ?? VideoLocal_Place_ID.ToString()}\" -- {ex}"); } ShokoServer.UnpauseWatchingFiles(); return(true); }
// TODO Merge these, with proper logic depending on the scenario (import, force, etc) public (string, string) MoveWithResultString(string scriptName, bool force = false) { // TODO Make this take an argument to disable removing empty dirs. It's slow, and should only be done if needed if (FullServerPath == null) { logger.Error($"Could not find or access the file to move: {VideoLocal_Place_ID}"); return(string.Empty, "ERROR: Unable to access file"); } if (!File.Exists(FullServerPath)) { logger.Error($"Could not find or access the file to move: \"{FullServerPath}\""); // this can happen due to file locks, so retry return(string.Empty, "ERROR: Could not access the file"); } FileInfo sourceFile = new FileInfo(FullServerPath); // There is a possibility of weird logic based on source of the file. Some handling should be made for it....later (var destImpl, string newFolderPath) = RenameFileHelper.GetDestination(this, scriptName); if (!(destImpl is SVR_ImportFolder destFolder)) { // In this case, an error string was returned, but we'll suppress it and give an error elsewhere if (newFolderPath != null) { logger.Error($"Unable to find destination for: \"{FullServerPath}\""); logger.Error($"The error message was: {newFolderPath}"); return(string.Empty, "ERROR: " + newFolderPath); } logger.Error($"Unable to find destination for: \"{FullServerPath}\""); return(string.Empty, "ERROR: There was an error but no error code returned..."); } // keep the original drop folder for later (take a copy, not a reference) SVR_ImportFolder dropFolder = ImportFolder; if (string.IsNullOrEmpty(newFolderPath)) { logger.Error($"Unable to find destination for: \"{FullServerPath}\""); return(string.Empty, "ERROR: The returned path was null or empty"); } // We've already resolved FullServerPath, so it doesn't need to be checked string newFilePath = Path.Combine(newFolderPath, Path.GetFileName(FullServerPath)); string newFullServerPath = Path.Combine(destFolder.ImportFolderLocation, newFilePath); var destFullTree = Path.Combine(destFolder.ImportFolderLocation, newFolderPath); if (!Directory.Exists(destFullTree)) { try { Directory.CreateDirectory(destFullTree); } catch (Exception e) { logger.Error(e); return(string.Empty, $"ERROR: Unable to create directory tree: \"{destFullTree}\""); } } // Last ditch effort to ensure we aren't moving a file unto itself if (newFullServerPath.Equals(FullServerPath, StringComparison.InvariantCultureIgnoreCase)) { logger.Info($"Moving file SKIPPED! The file is already at its desired location: \"{FullServerPath}\""); return(newFolderPath, string.Empty); } if (File.Exists(newFullServerPath)) { logger.Error($"A file already exists at the desired location: \"{FullServerPath}\""); return(string.Empty, "ERROR: A file already exists at the destination"); } ShokoServer.PauseWatchingFiles(); logger.Info($"Moving file from \"{FullServerPath}\" to \"{newFullServerPath}\""); try { sourceFile.MoveTo(newFullServerPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{FullServerPath}\" to \"{newFullServerPath}\" error {e}"); ShokoServer.UnpauseWatchingFiles(); return(newFullServerPath, "ERROR: " + e); } // Save for later. Scan for subtitles while the vlplace is still set for the source location string originalFileName = FullServerPath; var textStreams = SubtitleHelper.GetSubtitleStreams(this); // Handle Duplicate Files var dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID).ToList(); foreach (var dup in dups) { // Move source if (dup.FilePathFile1.Equals(FilePath) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = newFilePath; dup.ImportFolderIDFile1 = destFolder.ImportFolderID; } else if (dup.FilePathFile2.Equals(FilePath) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = newFilePath; dup.ImportFolderIDFile2 = destFolder.ImportFolderID; } // validate the dup file // There are cases where a dup file was not cleaned up before, so we'll do it here, too if (!dup.GetFullServerPath1() .Equals(dup.GetFullServerPath2(), StringComparison.InvariantCultureIgnoreCase)) { RepoFactory.DuplicateFile.Save(dup); } else { RepoFactory.DuplicateFile.Delete(dup); } } ImportFolderID = destFolder.ImportFolderID; FilePath = newFilePath; RepoFactory.VideoLocalPlace.Save(this); try { // move any subtitle files foreach (TextStream subtitleFile in textStreams) { if (string.IsNullOrEmpty(subtitleFile.Filename)) { continue; } var newParent = Path.GetDirectoryName(newFullServerPath); var srcParent = Path.GetDirectoryName(originalFileName); if (string.IsNullOrEmpty(newParent) || string.IsNullOrEmpty(srcParent)) { continue; } var subPath = Path.Combine(srcParent, subtitleFile.Filename); if (!File.Exists(subPath)) { continue; } var subFile = new FileInfo(subPath); string newSubPath = Path.Combine(newParent, subFile.Name); if (File.Exists(newSubPath)) { try { File.Delete(newSubPath); } catch (Exception e) { logger.Warn($"Unable to DELETE file: \"{subtitleFile}\" error {e}"); } } try { subFile.MoveTo(newSubPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{subtitleFile}\" to \"{newSubPath}\" error {e}"); } } } catch (Exception ex) { logger.Error(ex, ex.ToString()); } // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1) { RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); } ShokoServer.UnpauseWatchingFiles(); return(newFolderPath, string.Empty); }
// returns false if we should try again after the timer // TODO Generify this and Move and make a return model instead of tuple public (bool, string, string) RenameFile(bool preview = false, string scriptName = null) { if (scriptName != null && scriptName.Equals(Shoko.Models.Constants.Renamer.TempFileName)) { return(true, string.Empty, "Error: Do not attempt to use a temp file to rename."); } if (ImportFolder == null) { logger.Error($"Error: The renamer can't get the import folder for ImportFolderID: {ImportFolderID}, File: \"{FilePath}\""); return(true, string.Empty, "Error: Could not find the file"); } string renamed = RenameFileHelper.GetFilename(this, scriptName); if (string.IsNullOrEmpty(renamed)) { logger.Error($"Error: The renamer returned a null or empty name for: \"{FilePath}\""); return(true, string.Empty, "Error: The file renamer returned a null or empty value"); } if (renamed.StartsWith("*Error: ")) { logger.Error($"Error: The renamer returned an error on file: \"{FilePath}\"\n {renamed}"); return(true, string.Empty, renamed.Substring(1)); } // actually rename the file string fullFileName = FullServerPath; // check if the file exists if (string.IsNullOrEmpty(fullFileName)) { logger.Error($"Error could not find the original file for renaming, or it is in use: \"{fullFileName}\""); return(false, renamed, "Error: Could not access the file"); } if (!File.Exists(fullFileName)) { logger.Error($"Error could not find the original file for renaming, or it is in use: \"{fullFileName}\""); return(false, renamed, "Error: Could not access the file"); } // actually rename the file string path = Path.GetDirectoryName(fullFileName); string newFullName = Path.Combine(path, renamed); var textStreams = SubtitleHelper.GetSubtitleStreams(this); try { if (fullFileName.Equals(newFullName, StringComparison.InvariantCultureIgnoreCase)) { logger.Info($"Renaming file SKIPPED! no change From \"{fullFileName}\" to \"{newFullName}\""); return(true, renamed, string.Empty); } if (File.Exists(newFullName)) { logger.Info($"Renaming file SKIPPED! Destination Exists \"{newFullName}\""); return(true, renamed, "Error: The filename already exists"); } if (preview) { return(false, renamed, string.Empty); } ShokoServer.PauseWatchingFiles(); logger.Info($"Renaming file From \"{fullFileName}\" to \"{newFullName}\""); try { var file = new FileInfo(fullFileName); file.MoveTo(newFullName); } catch (Exception e) { logger.Info($"Renaming file FAILED! From \"{fullFileName}\" to \"{newFullName}\" - {e}"); ShokoServer.UnpauseWatchingFiles(); return(false, renamed, "Error: Failed to rename file"); } // Rename external subs! var oldBasename = Path.GetFileNameWithoutExtension(fullFileName); var newBasename = Path.GetFileNameWithoutExtension(renamed); foreach (TextStream sub in textStreams) { if (string.IsNullOrEmpty(sub.Filename)) { continue; } var oldSubPath = Path.Combine(path, sub.Filename); if (!File.Exists(oldSubPath)) { logger.Error($"Unable to rename external subtitle \"{sub.Filename}\". Cannot access the file"); continue; } var newSub = sub.Filename.Replace(oldBasename, newBasename); try { var file = new FileInfo(oldSubPath); file.MoveTo(newSub); } catch (Exception e) { logger.Error($"Unable to rename external subtitle \"{sub.Filename}\" to \"{newSub}\". {e}"); } } logger.Info($"Renaming file SUCCESS! From \"{fullFileName}\" to \"{newFullName}\""); Tuple <SVR_ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(newFullName); if (tup == null) { logger.Error($"Unable to LOCATE file \"{newFullName}\" inside the import folders"); ShokoServer.UnpauseWatchingFiles(); return(false, renamed, "Error: Unable to resolve new path"); } // Before we change all references, remap Duplicate Files List <DuplicateFile> dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID); if (dups != null && dups.Count > 0) { foreach (var dup in dups) { bool dupchanged = false; if (dup.FilePathFile1.Equals(FilePath, StringComparison.InvariantCultureIgnoreCase) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = tup.Item2; dupchanged = true; } else if (dup.FilePathFile2.Equals(FilePath, StringComparison.InvariantCultureIgnoreCase) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = tup.Item2; dupchanged = true; } if (dupchanged) { RepoFactory.DuplicateFile.Save(dup); } } } // Rename hash xrefs var filenameHash = RepoFactory.FileNameHash.GetByHash(VideoLocal.Hash); if (!filenameHash.Any(a => a.FileName.Equals(renamed))) { FileNameHash fnhash = new FileNameHash { DateTimeUpdated = DateTime.Now, FileName = renamed, FileSize = VideoLocal.FileSize, Hash = VideoLocal.Hash }; RepoFactory.FileNameHash.Save(fnhash); } FilePath = tup.Item2; RepoFactory.VideoLocalPlace.Save(this); // just in case VideoLocal.FileName = renamed; RepoFactory.VideoLocal.Save(VideoLocal, false); } catch (Exception ex) { logger.Info($"Renaming file FAILED! From \"{fullFileName}\" to \"{newFullName}\" - {ex.Message}"); logger.Error(ex, ex.ToString()); return(true, string.Empty, $"Error: {ex.Message}"); } ShokoServer.UnpauseWatchingFiles(); return(true, renamed, string.Empty); }
private static void PopulateVideoEpisodeFromVideoLocal(Video l, VideoLocal v, JMMType type, int userid) { l.Type = "episode"; l.Summary = "Episode Overview Not Available"; //TODO Intenationalization l.Title = Path.GetFileNameWithoutExtension(v.FilePath); l.Key = ContructVideoLocalIdUrl(userid, v.VideoLocalID, type); l.AddedAt = v.DateTimeCreated.ToUnixTime(); l.UpdatedAt = v.DateTimeUpdated.ToUnixTime(); l.OriginallyAvailableAt = v.DateTimeCreated.ToPlexDate(); l.Year = v.DateTimeCreated.Year.ToString(); VideoInfo info = v.VideoInfo; Media m = null; if (info != null) { if (!string.IsNullOrEmpty(info.FullInfo)) { try { m = XmlDeserializeFromString <Media>(info.FullInfo); } catch (Exception) { info.FullInfo = null; } } if (string.IsNullOrEmpty(info.FullInfo)) { VideoInfoRepository repo = new VideoInfoRepository(); MediaInfoResult mInfo = FileHashHelper.GetMediaInfo(v.FullServerPath, true); info.AudioBitrate = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate; info.AudioCodec = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec; info.Duration = mInfo.Duration; info.VideoBitrate = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate; info.VideoBitDepth = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth; info.VideoCodec = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec; info.VideoFrameRate = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate; info.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution; info.FullInfo = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo; repo.Save(info); m = XmlDeserializeFromString <Media>(info.FullInfo); } } l.Medias = new List <Media>(); if (m != null) { m.Id = null; List <JMMContracts.PlexContracts.Stream> subs = SubtitleHelper.GetSubtitleStreams(v.FullServerPath); if (subs.Count > 0) { foreach (JMMContracts.PlexContracts.Stream s in subs) { s.Key = ConstructFileStream(userid, s.File); } m.Parts[0].Streams.AddRange(subs); } foreach (Part p in m.Parts) { p.Id = null; string ff = Path.GetExtension(v.FullServerPath); p.Key = ConstructVideoLocalStream(userid, v.VideoLocalID, ff); p.Accessible = "1"; p.Exists = "1"; bool vid = false; bool aud = false; bool txt = false; foreach (JMMContracts.PlexContracts.Stream ss in p.Streams.ToArray()) { if ((ss.StreamType == "1") && (!vid)) { vid = true; } if ((ss.StreamType == "2") && (!aud)) { aud = true; ss.Selected = "1"; } if ((ss.StreamType == "3") && (!txt)) { txt = true; ss.Selected = "1"; } } } l.Medias.Add(m); l.Duration = m.Duration; } }
private static void PopulateVideoEpisodeFromVideoLocal(Video l, VideoLocal v, JMMType type) { l.Type = "episode"; l.Summary = "Episode Overview Not Available"; l.Title = Path.GetFileNameWithoutExtension(v.FilePath); l.Key = l.PrimaryExtraKey = ServerUrl(int.Parse(ServerSettings.JMMServerPort), MainWindow.PathAddressKodi + "/GetMetadata/0/" + (int)type + "/" + v.VideoLocalID); l.AddedAt = v.DateTimeCreated.Year.ToString("0000") + "-" + v.DateTimeCreated.Month.ToString("00") + "-" + v.DateTimeCreated.Day.ToString("00") + " " + v.DateTimeCreated.Hour.ToString("00") + ":" + v.DateTimeCreated.Minute.ToString("00") + ":" + v.DateTimeCreated.Millisecond.ToString("00"); l.UpdatedAt = v.DateTimeUpdated.Year.ToString("0000") + "-" + v.DateTimeUpdated.Month.ToString("00") + "-" + v.DateTimeUpdated.Day.ToString("00") + " " + v.DateTimeUpdated.Hour.ToString("00") + ":" + v.DateTimeUpdated.Minute.ToString("00") + ":" + v.DateTimeUpdated.Millisecond.ToString("00"); l.OriginallyAvailableAt = v.DateTimeCreated.Year.ToString("0000") + "-" + v.DateTimeCreated.Month.ToString("00") + "-" + v.DateTimeCreated.Day.ToString("00"); l.Year = v.DateTimeCreated.Year.ToString(); VideoInfo info = v.VideoInfo; Media m = null; if (info != null) { if (!string.IsNullOrEmpty(info.FullInfo)) { try { m = XmlDeserializeFromString <Media>(info.FullInfo); } catch (Exception) { info.FullInfo = null; } } if (string.IsNullOrEmpty(info.FullInfo)) { VideoInfoRepository repo = new VideoInfoRepository(); MediaInfoResult mInfo = FileHashHelper.GetMediaInfo(v.FullServerPath, true, true); info.AudioBitrate = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate; info.AudioCodec = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec; info.Duration = mInfo.Duration; info.VideoBitrate = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate; info.VideoBitDepth = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth; info.VideoCodec = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec; info.VideoFrameRate = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate; info.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution; info.FullInfo = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo; repo.Save(info); m = XmlDeserializeFromString <Media>(info.FullInfo); } } l.Medias = new List <Media>(); if (m != null) { m.Id = null; List <JMMContracts.KodiContracts.Stream> subs = SubtitleHelper.GetSubtitleStreamsKodi(v.FullServerPath); if (subs.Count > 0) { foreach (JMMContracts.KodiContracts.Stream s in subs) { s.Key = ServerUrl(int.Parse(ServerSettings.JMMServerFilePort), "file/0/" + Base64EncodeUrl(s.File), KodiObject.IsExternalRequest); } m.Parts[0].Streams.AddRange(subs); } foreach (Part p in m.Parts) { p.Id = null; p.File = v.FullServerPath; string ff = Path.GetExtension(v.FullServerPath); p.Key = ServerUrl(int.Parse(ServerSettings.JMMServerFilePort), "videolocal/0/" + v.VideoLocalID + "/file" + ff, KodiObject.IsExternalRequest); p.Accessible = "1"; p.Exists = "1"; bool vid = false; bool aud = false; bool txt = false; foreach (JMMContracts.KodiContracts.Stream ss in p.Streams.ToArray()) { if ((ss.StreamType == "1") && (!vid)) { vid = true; } if ((ss.StreamType == "2") && (!aud)) { aud = true; ss.Selected = "1"; } if ((ss.StreamType == "3") && (!txt)) { txt = true; ss.Selected = "1"; } } } l.Medias.Add(m); l.Duration = m.Duration; } }
public static Media GenerateMediaFromVideoLocal(VideoLocal v) { VideoInfo info = v.VideoInfo; Media m = null; if (info != null) { if (!string.IsNullOrEmpty(info.FullInfo)) { try { m = XmlDeserializeFromString <Media>(info.FullInfo); } catch (Exception) { info.FullInfo = null; } } if (string.IsNullOrEmpty(info.FullInfo)) { try { VideoInfoRepository repo = new VideoInfoRepository(); MediaInfoResult mInfo = FileHashHelper.GetMediaInfo(v.FullServerPath, true); info.AudioBitrate = string.IsNullOrEmpty(mInfo.AudioBitrate) ? "" : mInfo.AudioBitrate; info.AudioCodec = string.IsNullOrEmpty(mInfo.AudioCodec) ? "" : mInfo.AudioCodec; info.Duration = mInfo.Duration; info.VideoBitrate = string.IsNullOrEmpty(mInfo.VideoBitrate) ? "" : mInfo.VideoBitrate; info.VideoBitDepth = string.IsNullOrEmpty(mInfo.VideoBitDepth) ? "" : mInfo.VideoBitDepth; info.VideoCodec = string.IsNullOrEmpty(mInfo.VideoCodec) ? "" : mInfo.VideoCodec; info.VideoFrameRate = string.IsNullOrEmpty(mInfo.VideoFrameRate) ? "" : mInfo.VideoFrameRate; info.VideoResolution = string.IsNullOrEmpty(mInfo.VideoResolution) ? "" : mInfo.VideoResolution; info.FullInfo = string.IsNullOrEmpty(mInfo.FullInfo) ? "" : mInfo.FullInfo; repo.Save(info); m = XmlDeserializeFromString <Media>(info.FullInfo); } catch (Exception) { //FILE DO NOT EXIST } } } if (m != null) { m.Id = v.VideoLocalID.ToString(); List <Stream> subs = SubtitleHelper.GetSubtitleStreams(v.FullServerPath); if (subs.Count > 0) { m.Parts[0].Streams.AddRange(subs); } foreach (Part p in m.Parts) { p.Id = null; p.Accessible = "1"; p.Exists = "1"; bool vid = false; bool aud = false; bool txt = false; foreach (Stream ss in p.Streams.ToArray()) { if ((ss.StreamType == "1") && !vid) { vid = true; } if ((ss.StreamType == "2") && !aud) { aud = true; ss.Selected = "1"; } if ((ss.StreamType == "3") && !txt) { txt = true; ss.Selected = "1"; } } } } return(m); }
public bool RefreshMediaInfo() { try { logger.Trace($"Getting media info for: {FullServerPath}"); string name = (ImportFolder.CloudID == null) ? FullServerPath.Replace("/", "\\") : PlexAndKodi.Helper.ReplaceSchemeHost(PlexAndKodi.Helper.ConstructVideoLocalStream(0, VideoLocalID.ToString(), "file", false)); Media m = MediaConvert.Convert(name, GetFile()); //Mediainfo should have libcurl.dll for http if (string.IsNullOrEmpty(m.Duration)) { m = null; } if (m != null) { VideoLocal info = VideoLocal; info.VideoResolution = (!string.IsNullOrEmpty(m.Width) && !string.IsNullOrEmpty(m.Height)) ? m.Width + "x" + m.Height : string.Empty; info.VideoCodec = (!string.IsNullOrEmpty(m.VideoCodec)) ? m.VideoCodec : string.Empty; info.AudioCodec = (!string.IsNullOrEmpty(m.AudioCodec)) ? m.AudioCodec : string.Empty; info.Duration = (!string.IsNullOrEmpty(m.Duration)) ? (long)double.Parse(m.Duration, NumberStyles.Any, CultureInfo.InvariantCulture) : 0; info.VideoBitrate = info.VideoBitDepth = info.VideoFrameRate = info.AudioBitrate = string.Empty; List <JMMContracts.PlexAndKodi.Stream> vparts = m.Parts[0].Streams.Where(a => a.StreamType == "1").ToList(); if (vparts.Count > 0) { if (!string.IsNullOrEmpty(vparts[0].Bitrate)) { info.VideoBitrate = vparts[0].Bitrate; } if (!string.IsNullOrEmpty(vparts[0].BitDepth)) { info.VideoBitDepth = vparts[0].BitDepth; } if (!string.IsNullOrEmpty(vparts[0].FrameRate)) { info.VideoFrameRate = vparts[0].FrameRate; } } List <JMMContracts.PlexAndKodi.Stream> aparts = m.Parts[0].Streams.Where(a => a.StreamType == "2").ToList(); if (aparts.Count > 0) { if (!string.IsNullOrEmpty(aparts[0].Bitrate)) { info.AudioBitrate = aparts[0].Bitrate; } } m.Id = VideoLocalID.ToString(); List <JMMContracts.PlexAndKodi.Stream> subs = SubtitleHelper.GetSubtitleStreams(this); if (subs.Count > 0) { m.Parts[0].Streams.AddRange(subs); } foreach (Part p in m.Parts) { p.Id = null; p.Accessible = "1"; p.Exists = "1"; bool vid = false; bool aud = false; bool txt = false; foreach (JMMContracts.PlexAndKodi.Stream ss in p.Streams.ToArray()) { if ((ss.StreamType == "1") && !vid) { vid = true; } if ((ss.StreamType == "2") && !aud) { aud = true; ss.Selected = "1"; } if ((ss.StreamType == "3") && !txt) { txt = true; ss.Selected = "1"; } } } info.Media = m; return(true); } logger.Error($"File {FullServerPath} do not exists, we're unable to read the media information from it"); } catch (Exception e) { logger.Error($"Unable to read the media information of file {FullServerPath} ERROR: {e}"); } return(false); }
public bool RefreshMediaInfo() { try { logger.Trace($"Getting media info for: {FullServerPath}"); Media m = null; List <Providers.Azure.Media> webmedias = AzureWebAPI.Get_Media(VideoLocal.ED2KHash); if (webmedias != null && webmedias.Count > 0) { m = webmedias[0].GetMedia(); } if (m == null) { string name = (ImportFolder.CloudID == null) ? FullServerPath.Replace("/", "\\") : PlexAndKodi.Helper.ReplaceSchemeHost(PlexAndKodi.Helper.ConstructVideoLocalStream(0, VideoLocalID.ToString(), "file", false)); m = MediaConvert.Convert(name, GetFile()); //Mediainfo should have libcurl.dll for http if (string.IsNullOrEmpty(m.Duration)) { m = null; } if (m != null) { AzureWebAPI.Send_Media(VideoLocal.ED2KHash, m); } } if (m != null) { VideoLocal info = VideoLocal; FillVideoInfoFromMedia(info, m); m.Id = VideoLocalID.ToString(); List <JMMContracts.PlexAndKodi.Stream> subs = SubtitleHelper.GetSubtitleStreams(this); if (subs.Count > 0) { m.Parts[0].Streams.AddRange(subs); } foreach (Part p in m.Parts) { p.Id = null; p.Accessible = "1"; p.Exists = "1"; bool vid = false; bool aud = false; bool txt = false; foreach (JMMContracts.PlexAndKodi.Stream ss in p.Streams.ToArray()) { if ((ss.StreamType == "1") && !vid) { vid = true; } if ((ss.StreamType == "2") && !aud) { aud = true; ss.Selected = "1"; } if ((ss.StreamType == "3") && !txt) { txt = true; ss.Selected = "1"; } } } info.Media = m; return(true); } logger.Error($"File {FullServerPath} does not exist, unable to read media information from it"); } catch (Exception e) { logger.Error($"Unable to read the media information of file {FullServerPath} ERROR: {e}"); } return(false); }
protected override async Task <TranscodeContext> TranscodeVideoAsync(string clientId, VideoTranscoding video, double timeStart, double timeDuration, bool waitForBuffer) { FFMpegTranscodeContext context = new FFMpegTranscodeContext(_cacheEnabled, _cachePath); context.TargetDuration = video.SourceMediaDuration; if (timeStart == 0 && video.TargetIsLive == false && _cacheEnabled) { timeDuration = 0; context.Partial = false; } else if (video.TargetVideoContainer == VideoContainer.Hls) { context.Partial = true; } else { video.TargetIsLive = true; context.Partial = true; } if (video.TargetVideoContainer == VideoContainer.Unknown) { video.TargetVideoContainer = video.SourceVideoContainer; } bool embeddedSupported = false; SubtitleCodec embeddedSubCodec = SubtitleCodec.Unknown; if (video.TargetSubtitleSupport == SubtitleSupport.Embedded) { if (video.TargetVideoContainer == VideoContainer.Matroska) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.Ass; video.TargetSubtitleCodec = SubtitleCodec.Ass; } else if (video.TargetVideoContainer == VideoContainer.Mp4) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.MovTxt; video.TargetSubtitleCodec = SubtitleCodec.MovTxt; } else if (video.TargetVideoContainer == VideoContainer.Hls) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.WebVtt; video.TargetSubtitleCodec = SubtitleCodec.WebVtt; } else if (video.TargetVideoContainer == VideoContainer.Avi) { embeddedSupported = true; embeddedSubCodec = SubtitleCodec.Srt; video.TargetSubtitleCodec = SubtitleCodec.Srt; } //else if (video.TargetVideoContainer == VideoContainer.Mpeg2Ts) //{ // embeddedSupported = true; // embeddedSubCodec = SubtitleCodec.DvbSub; // video.TargetSubtitleCodec = SubtitleCodec.VobSub; //} else { _logger.Debug("FFMpegMediaConverter: Container {0} does not support embedded subtitles", video.TargetVideoContainer); } } video.TargetSubtitleMime = SubtitleHelper.GetSubtitleMime(video.TargetSubtitleCodec); video.PreferredSourceSubtitles = await GetSubtitlesAsync(clientId, video, timeStart).ConfigureAwait(false); string transcodingFile = GetTranscodingVideoFileName(video, timeStart, embeddedSupported); transcodingFile = Path.Combine(_cachePath, transcodingFile); if (File.Exists(transcodingFile)) { //Use non-partial transcode if possible TranscodeContext existingContext = await GetExistingTranscodeContextAsync(clientId, video.TranscodeId).ConfigureAwait(false); if (existingContext != null) { existingContext.TargetFile = transcodingFile; if (existingContext.Stream == null) { existingContext.AssignStream(await GetFileStreamAsync(transcodingFile).ConfigureAwait(false)); } if (existingContext.CurrentDuration.TotalSeconds == 0) { double bitrate = 0; if (video.TargetVideoBitrate.HasValue && video.TargetAudioBitrate.HasValue) { bitrate = video.TargetVideoBitrate.Value + video.TargetAudioBitrate.Value; } else if (video.SourceVideoStream.Bitrate.HasValue && video.SourceAudioStreams.Any(a => a.Bitrate > 0)) { bitrate = video.SourceVideoStream.Bitrate.Value + video.SourceAudioStreams.Max(a => a.Bitrate ?? 0); } bitrate *= 1024; //Bitrate in bits/s if (bitrate > 0) { long startByte = Convert.ToInt64((bitrate * timeStart) / 8.0); if (existingContext.Stream.Length > startByte) { return(existingContext); } } } else { if (existingContext.CurrentDuration.TotalSeconds > timeStart) { return(existingContext); } } } else { //Presume that it is a cached file TouchFile(transcodingFile); context.Partial = false; context.TargetFile = transcodingFile; context.AssignStream(await GetFileStreamAsync(transcodingFile).ConfigureAwait(false)); return(context); } } if (video.TargetVideoContainer == VideoContainer.Hls) { long requestedSegmentSequence = requestedSegmentSequence = Convert.ToInt64(timeStart / HLSSegmentTimeInSeconds); if (requestedSegmentSequence > 0) { requestedSegmentSequence--; //1 segment file margin } string pathName = FFMpegPlaylistManifest.GetPlaylistFolderFromTranscodeFile(_cachePath, transcodingFile); string playlist = Path.Combine(pathName, PlaylistManifest.PLAYLIST_MANIFEST_FILE_NAME); string segmentFile = Path.Combine(pathName, requestedSegmentSequence.ToString("00000") + ".ts"); if (File.Exists(playlist) == true && File.Exists(segmentFile) == true) { //Use exisitng context if possible TranscodeContext existingContext = await GetExistingTranscodeContextAsync(clientId, video.TranscodeId).ConfigureAwait(false); if (existingContext != null) { if (existingContext.LastSegment > requestedSegmentSequence) { existingContext.TargetFile = playlist; existingContext.SegmentDir = pathName; if (existingContext.Stream == null) { existingContext.AssignStream(await GetFileStreamAsync(playlist).ConfigureAwait(false)); } existingContext.HlsBaseUrl = video.HlsBaseUrl; return(existingContext); } } else { //Presume that it is a cached file TouchDirectory(pathName); context.Partial = false; context.TargetFile = playlist; context.SegmentDir = pathName; context.HlsBaseUrl = video.HlsBaseUrl; context.AssignStream(await GetFileStreamAsync(playlist).ConfigureAwait(false)); return(context); } } } FFMpegTranscodeData data = new FFMpegTranscodeData(_cachePath) { TranscodeId = video.TranscodeId, ClientId = clientId }; if (string.IsNullOrEmpty(video.TranscoderBinPath) == false) { data.TranscoderBinPath = video.TranscoderBinPath; } if (string.IsNullOrEmpty(video.TranscoderArguments) == false) { data.ConcatedFileInput = video.ConcatSourceMediaPaths; data.TranscoderArguments = video.TranscoderArguments; data.InputMediaFilePaths = video.SourceMediaPaths; if (video.PreferredSourceSubtitles != null) { foreach (var mediaSourceIndex in video.PreferredSourceSubtitles.Keys) { foreach (var sub in video.PreferredSourceSubtitles[mediaSourceIndex]) { if (string.IsNullOrEmpty(sub.SourcePath) == false) { data.AddSubtitle(mediaSourceIndex, sub.SourcePath); context.TargetSubtitles.Add(sub.SourcePath); } } } } data.OutputFilePath = transcodingFile; context.TargetFile = transcodingFile; } else { data.Encoder = _ffMpegEncoderHandler.StartEncoding(video.TranscodeId, video.TargetVideoCodec); _ffMpegCommandline.InitTranscodingParameters(video.ConcatSourceMediaPaths, video.SourceMediaPaths, ref data); bool useX26XLib = video.TargetVideoCodec == VideoCodec.H264 || video.TargetVideoCodec == VideoCodec.H265; _ffMpegCommandline.AddTranscodingThreadsParameters(!useX26XLib, ref data); int subCopyStream = -1; if (video.PreferredSourceSubtitles.Any()) { if (video.FirstPreferredSourceSubtitle.IsEmbedded) { subCopyStream = video.FirstPreferredSourceSubtitle.StreamIndex; _ffMpegCommandline.AddSubtitleCopyParameters(video.FirstPreferredSourceSubtitle, data); } else if (embeddedSupported) { foreach (int mediaSourceIndex in video.PreferredSourceSubtitles.Keys) { _ffMpegCommandline.AddSubtitleEmbeddingParameters(mediaSourceIndex, video.PreferredSourceSubtitles[mediaSourceIndex], embeddedSubCodec, timeStart, data); } } else if (video.TargetSubtitleSupport != SubtitleSupport.SoftCoded) { video.TargetSubtitleSupport = SubtitleSupport.HardCoded; //Fallback to hardcoded subtitles _logger.Debug("FFMpegMediaConverter: Soft subs not supported. Fallback to hardcoded subtitles"); } } else { embeddedSupported = false; data.OutputArguments.Add("-sn"); } _ffMpegCommandline.AddTimeParameters(video, timeStart, timeDuration, data); _ffMpegCommandline.AddStreamMapParameters(video, data); FFMpegEncoderConfig encoderConfig = _ffMpegEncoderHandler.GetEncoderConfig(data.Encoder); _ffMpegCommandline.AddVideoParameters(video, data.TranscodeId, encoderConfig, data); _ffMpegCommandline.AddVideoAudioParameters(video, data); var result = await _ffMpegCommandline.AddTargetVideoFormatAndOutputFileParametersAsync(video, transcodingFile, timeStart, data).ConfigureAwait(false); context.TargetFile = result.TranscodingFile; context.CurrentSegment = result.StartSegment; if (video.PreferredSourceSubtitles.Any()) { foreach (var sub in video.PreferredSourceSubtitles.SelectMany(s => s.Value)) { if (string.IsNullOrEmpty(sub.SourcePath) == false) { context.TargetSubtitles.Add(sub.SourcePath); } } } } _logger.Info("FFMpegMediaConverter: Invoking transcoder to transcode video file '{0}' for transcode '{1}' with arguments '{2}'", video.SourceMediaPaths.First().Value, video.TranscodeId, String.Join(", ", data.OutputArguments.ToArray())); context.Start(); context.AssignStream(await ExecuteTranscodingProcessAsync(data, context, waitForBuffer).ConfigureAwait(false)); return(context); }