diff --git a/Changelog.md b/Changelog.md index faaccf9..818c476 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,8 +1,17 @@ -5.4.8.2 Beta (not yet released) +5.4.8.3 Beta (not yet released) ============ -- CLI --shuffle issue fix +5.4.8.2 Beta +============ + +- CLI --shuffle issue fix. +- ISO image files can be opened like any other files, files smaller + than 10 GB are handled as DVD and larger as BluRay. +- Menu support for BluRay title, audio and subtitle selection. +- Property input-key-list can be shown with: View > Show Keys +- youtube-dl 2020.06.16.1 +- libmpv 2020-06-21 shinchiro 5.4.8.1 Beta diff --git a/mpv.net/Misc/App.cs b/mpv.net/Misc/App.cs index fc51754..3255560 100644 --- a/mpv.net/Misc/App.cs +++ b/mpv.net/Misc/App.cs @@ -179,9 +179,9 @@ namespace mpvnet case "start-size": StartSize = value; return true; case "process-instance": ProcessInstance = value; return true; case "dark-mode": DarkMode = value; return true; - case "start-threshold": StartThreshold = value.Int(); return true; - case "recent-count": RecentCount = value.Int(); return true; - case "minimum-aspect-ratio": MinimumAspectRatio = value.Float(); return true; + case "start-threshold": StartThreshold = value.ToInt(); return true; + case "recent-count": RecentCount = value.ToInt(); return true; + case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true; case "dark-theme": DarkTheme = value.Trim('\'', '"'); return true; case "light-theme": LightTheme = value.Trim('\'', '"'); return true; default: diff --git a/mpv.net/Misc/Commands.cs b/mpv.net/Misc/Commands.cs index a3fc30d..3749880 100644 --- a/mpv.net/Misc/Commands.cs +++ b/mpv.net/Misc/Commands.cs @@ -44,6 +44,7 @@ namespace mpvnet case "show-profiles": ShowProfiles(); break; case "show-properties": ShowProperties(); break; case "show-commands": ShowCommands(); break; + case "show-keys": ShowKeys(); break; case "add-files-to-playlist": OpenFiles("append"); break; // deprecated 2019 default: Msg.ShowError($"No command '{id}' found."); break; } @@ -151,7 +152,7 @@ namespace mpvnet { fileSize = new FileInfo(path).Length; - if (App.AudioTypes.Contains(path.ShortExt())) + if (App.AudioTypes.Contains(path.Ext())) { using (MediaInfo mediaInfo = new MediaInfo(path)) { @@ -169,13 +170,13 @@ namespace mpvnet if (date != "") text += "Year: " + date + "\n"; if (duration != "") text += "Length: " + duration + "\n"; text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n"; - text += "Type: " + path.ShortExt().ToUpper(); + text += "Type: " + path.Ext().ToUpper(); core.commandv("show-text", text, "5000"); return; } } - else if (App.ImageTypes.Contains(path.ShortExt())) + else if (App.ImageTypes.Contains(path.Ext())) { using (MediaInfo mediaInfo = new MediaInfo(path)) { @@ -183,7 +184,7 @@ namespace mpvnet "Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" + "Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" + "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" + - "Type: " + path.ShortExt().ToUpper(); + "Type: " + path.Ext().ToUpper(); core.commandv("show-text", text, "5000"); return; @@ -328,6 +329,14 @@ namespace mpvnet Process.Start(file); } + static void ShowKeys() + { + string txt = core.get_property_string("input-key-list"); + string file = Path.GetTempPath() + @"\mpv input-key-list.txt"; + File.WriteAllText(file, txt.Replace(",", BR) + BR); + Process.Start(file); + } + static void ShowCommands() { string code = @" diff --git a/mpv.net/Misc/ExtensionMethods.cs b/mpv.net/Misc/ExtensionMethods.cs index 71deda3..d29ae03 100644 --- a/mpv.net/Misc/ExtensionMethods.cs +++ b/mpv.net/Misc/ExtensionMethods.cs @@ -1,32 +1,70 @@ -using System.Globalization; + +using System.Globalization; using System.IO; public static class Extensions { - public static string FileName(this string path) + public static bool ContainsEx(this string instance, string value) { - if (string.IsNullOrEmpty(path)) return ""; - int index = path.LastIndexOf('\\'); - if (index > -1) return path.Substring(index + 1); - index = path.LastIndexOf('/'); - if (index > -1) return path.Substring(index + 1); - return path; + if (instance != null && value != null) + return instance.Contains(value); + + return false; } - public static string ShortExt(this string path) + public static bool StartsWithEx(this string instance, string value) { - return Path.GetExtension(path).ToLower().TrimStart('.'); + if (instance != null && value != null) + return instance.StartsWith(value); + + return false; } - public static int Int(this string value) + public static string ToUpperEx(this string instance) { - int.TryParse(value, out int result); + if (instance != null) + return instance.ToUpper(); + + return ""; + } + + public static string FileName(this string instance) + { + if (string.IsNullOrEmpty(instance)) + return ""; + + int index = instance.LastIndexOf('\\'); + + if (index > -1) + return instance.Substring(index + 1); + + index = instance.LastIndexOf('/'); + + if (index > -1) + return instance.Substring(index + 1); + + return instance; + } + + public static string Ext(this string instance) + { + if (instance == null) + return ""; + + return Path.GetExtension(instance).ToLower().TrimStart('.'); + } + + public static int ToInt(this string instance) + { + int.TryParse(instance, out int result); return result; } - public static float Float(this string value) + public static float ToFloat(this string instance) { - float.TryParse(value.Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out float result); + float.TryParse(instance.Replace(",", "."), NumberStyles.Float, + CultureInfo.InvariantCulture, out float result); + return result; } -} \ No newline at end of file +} diff --git a/mpv.net/Properties/AssemblyInfo.cs b/mpv.net/Properties/AssemblyInfo.cs index d37e1bb..2c75c23 100644 --- a/mpv.net/Properties/AssemblyInfo.cs +++ b/mpv.net/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("5.4.8.1")] -[assembly: AssemblyFileVersion("5.4.8.1")] +[assembly: AssemblyVersion("5.4.8.2")] +[assembly: AssemblyFileVersion("5.4.8.2")] diff --git a/mpv.net/Resources/input.conf.txt b/mpv.net/Resources/input.conf.txt index f84e5d8..90d9d4a 100644 --- a/mpv.net/Resources/input.conf.txt +++ b/mpv.net/Resources/input.conf.txt @@ -66,6 +66,7 @@ Ctrl+Right seek 300 #menu: Navigate > Jump 5 min forward Ctrl+Left seek -300 #menu: Navigate > Jump 5 min backward _ ignore #menu: Navigate > - + _ ignore #menu: Navigate > Titles _ ignore #menu: Navigate > Chapters Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size @@ -149,11 +150,12 @@ T script-binding stats/display-stats-toggle #menu: View > Toggle Statistics Del script-binding osc/visibility #menu: View > Toggle OSC Visibility F8 script-binding show-playlist #menu: View > Show Playlist - F9 show-text ${track-list} 5000 #menu: View > Show Audio/Video/Subtitle List + F9 show-text ${track-list} 5000 #menu: View > Show Tracks p show-progress #menu: View > Show Progress Ctrl+p script-message mpv.net show-profiles #menu: View > Show Profiles Shift+p script-message mpv.net show-properties #menu: View > Show Properties Shift+c script-message mpv.net show-commands #menu: View > Show Commands + _ script-message mpv.net show-keys #menu: View > Show Keys ` script-binding console/enable #menu: View > Show Console c script-message mpv.net show-conf-editor #menu: Settings > Show Config Editor diff --git a/mpv.net/WPF/EverythingWindow.xaml.cs b/mpv.net/WPF/EverythingWindow.xaml.cs index df17805..9516a2a 100644 --- a/mpv.net/WPF/EverythingWindow.xaml.cs +++ b/mpv.net/WPF/EverythingWindow.xaml.cs @@ -137,7 +137,7 @@ namespace mpvnet for (i = 0; i < Everything_GetNumResults(); i++) { Everything_GetResultFullPathName(i, buf, bufsize); - string ext = buf.ToString().ShortExt(); + string ext = buf.ToString().Ext(); if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext) || App.ImageTypes.Contains(ext)) diff --git a/mpv.net/WinForms/MainForm.cs b/mpv.net/WinForms/MainForm.cs index 7b40e14..b69e7bb 100644 --- a/mpv.net/WinForms/MainForm.cs +++ b/mpv.net/WinForms/MainForm.cs @@ -235,11 +235,11 @@ namespace mpvnet { chaptersMenuItem.DropDownItems.Clear(); - foreach (var i in core.Chapters) + foreach (var pair in core.Chapters) { - MenuItem mi = new MenuItem(i.Key); - mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " "; - mi.Action = () => core.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute"); + MenuItem mi = new MenuItem(pair.Key); + mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(pair.Value).ToString().Substring(0, 8) + " "; + mi.Action = () => core.commandv("seek", pair.Value.ToString(CultureInfo.InvariantCulture), "absolute"); chaptersMenuItem.DropDownItems.Add(mi); } } @@ -259,6 +259,26 @@ namespace mpvnet mi.Action = () => RecentFiles.Clear(); recent.DropDownItems.Add(mi); } + + MenuItem titles = FindMenuItem("Titles"); + + if (titles != null) + { + titles.DropDownItems.Clear(); + + lock (core.BluRayTitles) + { + for (int i = 0; i < core.BluRayTitles.Count; i++) + { + if (core.BluRayTitles[i] != "00:00:00") + { + int tmp = i; + MenuItem.Add(titles.DropDownItems, $"{core.BluRayTitles[i]} ({i})", + () => core.SetBluRayTitle(tmp)); + } + } + } + } } MenuItem FindMenuItem(string text, ToolStripItemCollection items) diff --git a/mpv.net/mpv/Core.cs b/mpv.net/mpv/Core.cs index b97d005..46c3c1b 100644 --- a/mpv.net/mpv/Core.cs +++ b/mpv.net/mpv/Core.cs @@ -15,6 +15,7 @@ using System.Windows.Forms; using static libmpv; using static WinAPI; using static NewLine; +using System.Globalization; namespace mpvnet { @@ -79,10 +80,13 @@ namespace mpvnet public List MediaTracks { get; set; } = new List(); public List> Chapters { get; set; } = new List>(); + public List BluRayTitles { get; } = new List(); public IntPtr Handle { get; set; } public IntPtr WindowHandle { get; set; } + public Size VideoSize { get; set; } public TimeSpan Duration; + public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false); public AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false); @@ -398,6 +402,14 @@ namespace mpvnet { var data = (mpv_event_log_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_log_message)); + if (data.log_level == mpv_log_level.MPV_LOG_LEVEL_INFO) + { + string prefix = ConvertFromUtf8(data.prefix); + + if (prefix == "bd") + ProcessBluRayLogMessage(ConvertFromUtf8(data.text)); + } + if (LogMessage != null || LogMessageAsync != null) { string msg = $"[{ConvertFromUtf8(data.prefix)}] {ConvertFromUtf8(data.text)}"; @@ -592,6 +604,26 @@ namespace mpvnet } } + void ProcessBluRayLogMessage(string msg) + { + lock (BluRayTitles) + { + if (msg.Contains(" 0 duration: ")) + BluRayTitles.Clear(); + + if (msg.Contains(" duration: ")) + { + int start = msg.IndexOf(" duration: ") + 11; + BluRayTitles.Add(msg.Substring(start, 8)); + } + } + } + + public void SetBluRayTitle(int id) + { + core.LoadFiles(new[] { @"bd://" + id }, false, false); + } + void InvokeEvent(Action action, Action asyncAction) { InvokeAsync(asyncAction); @@ -979,9 +1011,11 @@ namespace mpvnet for (int i = 0; i < files.Length; i++) { string file = files[i]; - LoadLibrary(file.ShortExt()); + LoadLibrary(file.Ext()); - if (App.SubtitleTypes.Contains(file.ShortExt())) + if (file.Ext() == "iso") + LoadISO(file); + else if(App.SubtitleTypes.Contains(file.Ext())) commandv("sub-add", file); else if (i == 0 && !append) @@ -997,6 +1031,24 @@ namespace mpvnet Task.Run(() => LoadFolder()); } + public void LoadISO(string path) + { + core.command("stop"); + Thread.Sleep(500); + long gb = new FileInfo(path).Length / 1024 / 1024 / 1024; + + if (gb < 10) + { + core.set_property_string("dvd-device", path); + core.LoadFiles(new[] { @"dvd://" }, false, false); + } + else + { + core.set_property_string("bluray-device", path); + core.LoadFiles(new[] { @"bd://" }, false, false); + } + } + public void LoadFolder() { if (!App.AutoLoadFolder || Control.ModifierKeys.HasFlag(Keys.Shift)) @@ -1011,9 +1063,9 @@ namespace mpvnet List files = Directory.GetFiles(Path.GetDirectoryName(path)).ToList(); files = files.Where(file => - App.VideoTypes.Contains(file.ShortExt()) || - App.AudioTypes.Contains(file.ShortExt()) || - App.ImageTypes.Contains(file.ShortExt())).ToList(); + App.VideoTypes.Contains(file.Ext()) || + App.AudioTypes.Contains(file.Ext()) || + App.ImageTypes.Contains(file.Ext())).ToList(); files.Sort(new StringLogicalComparer()); int index = files.IndexOf(path); @@ -1084,14 +1136,58 @@ namespace mpvnet } } + string GetLanguage(string id) + { + foreach (var ci in CultureInfo.GetCultures(CultureTypes.NeutralCultures)) + if (ci.ThreeLetterISOLanguageName == id) + return ci.EnglishName; + + return id; + } + void ReadMetaData() { + string path = get_property_string("path"); + + if (!path.StartsWithEx("bd://")) + lock (BluRayTitles) + BluRayTitles.Clear(); + lock (MediaTracks) { MediaTracks.Clear(); - string path = get_property_string("path"); - if (File.Exists(path)) + if (path.StartsWithEx("bd://")) + { + int count = core.get_property_int("track-list/count"); + + for (int i = 0; i < count; i++) + { + string type = core.get_property_string($"track-list/{i}/type"); + + if (type == "audio") + { + MediaTrack track = new MediaTrack(); + Add(track, GetLanguage(core.get_property_string($"track-list/{i}/lang"))); + Add(track, core.get_property_string($"track-list/{i}/codec").ToUpperEx()); + Add(track, core.get_property_int($"track-list/{i}/audio-channels") + " channels"); + track.Text = "A: " + track.Text.Trim(' ', ','); + track.Type = "a"; + track.ID = core.get_property_int($"track-list/{i}/id"); + MediaTracks.Add(track); + } + else if (type == "sub") + { + MediaTrack track = new MediaTrack(); + Add(track, GetLanguage(core.get_property_string($"track-list/{i}/lang"))); + track.Text = "S: " + track.Text.Trim(' ', ','); + track.Type = "s"; + track.ID = core.get_property_int($"track-list/{i}/id"); + MediaTracks.Add(track); + } + } + } + else if (File.Exists(path)) { using (MediaInfo mi = new MediaInfo(path)) { @@ -1161,12 +1257,6 @@ namespace mpvnet track.ID = i; MediaTracks.Add(track); } - - void Add(MediaTrack track, string val) - { - if (!string.IsNullOrEmpty(val) && !(track.Text != null && track.Text.Contains(val))) - track.Text += " " + val + ","; - } } } } @@ -1183,6 +1273,12 @@ namespace mpvnet Chapters.Add(new KeyValuePair(text, time)); } } + + void Add(MediaTrack track, object value) + { + if (value != null && !(track.Text != null && track.Text.Contains(value.ToString()))) + track.Text += " " + value + ","; + } } } }