diff --git a/Changelog.md b/Changelog.md index fdd56ac..c8d4906 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,8 +1,26 @@ -5.4.4.7 Beta (not yet released) +5.4.5.2 Beta (not yet released) ============ -- + + + +5.4.5.1 Beta +============ + +- extensions no longer need to end with *Extension.dll but rather + the file name and the directory name must be identical +- text encoding exception fix +- the PowerShell script host is more feature complete, easier to use + and more efficient, there were however many PowerShell and C# breaking + changes requrired to make the core more robust and efficient +- Python 2 script host removed, Python 3 support is planned for summer + + +5.4.5.0 +======= + +stable release, no changes since the last beta 5.4.4.6 Beta diff --git a/Manual.md b/Manual.md index 72619c1..e7d0258 100644 --- a/Manual.md +++ b/Manual.md @@ -341,7 +341,7 @@ The PowerShell scripting host is like extensions not initialized before media fi mpv.net does not define scripting interfaces but instead exposed its complete internals, there are no compatibility guaranties. -[Example Scripts](scripts/examples) +[Example Scripts](scripts) #### C# @@ -358,16 +358,16 @@ Script code can be written within a C# [extension](#extensions), that way full c The C# scripting host is like [extensions](#extensions) not initialized before media files are loaded. -[Example Scripts](scripts/examples) +[Example Scripts](scripts) Extensions ---------- -Extensions are located in the config folder and the filename must end with 'Extension.dll': +Extensions are located in a subfolder _extensions_ in the config folder and the filename must have the same name as the directory: ```Text -\Extensions\ExampleExtension\ExampleExtension.dll +\extensions\ExampleExtension\ExampleExtension.dll ``` mpv.net does not define extension interfaces but instead exposed its complete internals, there are no compatibility guaranties. diff --git a/Release.ps1 b/Release.ps1 index b48dc97..d37ce64 100644 --- a/Release.ps1 +++ b/Release.ps1 @@ -7,7 +7,6 @@ $include = @( '*.iss', '*.js', '*.lua', - '*.md', '*.ps1', '*.resx', '*.sln', diff --git a/extensions/RatingExtension/RatingExtension.cs b/extensions/RatingExtension/RatingExtension.cs index 439bee1..b675219 100644 --- a/extensions/RatingExtension/RatingExtension.cs +++ b/extensions/RatingExtension/RatingExtension.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.IO; using mpvnet; +using static mpvnet.Core; namespace RatingExtension // the assembly name must end with 'Extension' { @@ -19,8 +20,8 @@ namespace RatingExtension // the assembly name must end with 'Extension' public RatingExtension() // plugin initialization { - mp.ClientMessage += ClientMessage; //handles keys defined in input.conf - mp.Shutdown += Shutdown; // handles MPV_EVENT_SHUTDOWN + core.ClientMessage += ClientMessage; //handles keys defined in input.conf + core.Shutdown += Shutdown; // handles MPV_EVENT_SHUTDOWN } // handles MPV_EVENT_SHUTDOWN @@ -53,10 +54,10 @@ namespace RatingExtension // the assembly name must end with 'Extension' if (int.TryParse(args[1], out int rating)) { - string path = mp.get_property_string("path"); + string path = core.get_property_string("path"); if (!File.Exists(path)) return; Dic[path] = rating; - mp.commandv("show-text", $"Rating: {rating}"); + core.commandv("show-text", $"Rating: {rating}"); } else if (args[1] == "about") Msg.Show("Rating Extension", "This extension writes a rating to the filename of rated videos when mpv.net shuts down.\n\nThe input.conf defaults contain key bindings for this extension to set ratings."); diff --git a/extensions/ScriptingExtension/ScriptingExtension.cs b/extensions/ScriptingExtension/ScriptingExtension.cs index 97916fd..8f01666 100644 --- a/extensions/ScriptingExtension/ScriptingExtension.cs +++ b/extensions/ScriptingExtension/ScriptingExtension.cs @@ -13,6 +13,7 @@ using System.IO; using mpvnet; using CSScriptLibrary; +using static mpvnet.Core; // the file name of extensions must end with 'Extension' namespace ScriptingExtension @@ -27,8 +28,8 @@ namespace ScriptingExtension //Script = new Script(); List files = new List(); - if (Directory.Exists(mp.ConfigFolder + "scripts-cs")) - files.AddRange(Directory.GetFiles(mp.ConfigFolder + "scripts-cs", "*.cs")); + if (Directory.Exists(core.ConfigFolder + "scripts-cs")) + files.AddRange(Directory.GetFiles(core.ConfigFolder + "scripts-cs", "*.cs")); if (Directory.Exists(Folder.Startup + "scripts")) foreach (string path in Directory.GetFiles(Folder.Startup + "scripts", "*.cs")) diff --git a/extensions/ScriptingExtension/script.cs b/extensions/ScriptingExtension/script.cs index 24477da..dfba005 100644 --- a/extensions/ScriptingExtension/script.cs +++ b/extensions/ScriptingExtension/script.cs @@ -2,12 +2,13 @@ using System.IO; using mpvnet; +using static mpvnet.Core; class Script { public Script() { - mp.Shutdown += Shutdown; + core.Shutdown += Shutdown; } void Shutdown() diff --git a/mpv.net/IronPython/IKVM.Reflection.dll b/mpv.net/IronPython/IKVM.Reflection.dll deleted file mode 100644 index c2b777c..0000000 Binary files a/mpv.net/IronPython/IKVM.Reflection.dll and /dev/null differ diff --git a/mpv.net/IronPython/IronPython.Modules.dll b/mpv.net/IronPython/IronPython.Modules.dll deleted file mode 100644 index 1b1b7c9..0000000 Binary files a/mpv.net/IronPython/IronPython.Modules.dll and /dev/null differ diff --git a/mpv.net/IronPython/IronPython.dll b/mpv.net/IronPython/IronPython.dll deleted file mode 100644 index 6fc06a0..0000000 Binary files a/mpv.net/IronPython/IronPython.dll and /dev/null differ diff --git a/mpv.net/IronPython/IronPythonAddon.dll b/mpv.net/IronPython/IronPythonAddon.dll deleted file mode 100644 index 5ff18ca..0000000 Binary files a/mpv.net/IronPython/IronPythonAddon.dll and /dev/null differ diff --git a/mpv.net/IronPython/Microsoft.Dynamic.dll b/mpv.net/IronPython/Microsoft.Dynamic.dll deleted file mode 100644 index 9f89f5c..0000000 Binary files a/mpv.net/IronPython/Microsoft.Dynamic.dll and /dev/null differ diff --git a/mpv.net/IronPython/Microsoft.Scripting.dll b/mpv.net/IronPython/Microsoft.Scripting.dll deleted file mode 100644 index 86ade62..0000000 Binary files a/mpv.net/IronPython/Microsoft.Scripting.dll and /dev/null differ diff --git a/mpv.net/Misc/App.cs b/mpv.net/Misc/App.cs index f5ac4dc..8e3acec 100644 --- a/mpv.net/Misc/App.cs +++ b/mpv.net/Misc/App.cs @@ -8,6 +8,7 @@ using System.Windows.Forms; using UI; using static libmpv; +using static mpvnet.Core; using System.Threading.Tasks; @@ -21,7 +22,7 @@ namespace mpvnet public static string[] SubtitleTypes { get; } = { "srt", "ass", "idx", "sup", "ttxt", "ssa", "smi" }; public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName; - public static string ConfPath { get => mp.ConfigFolder + "mpvnet.conf"; } + public static string ConfPath { get => core.ConfigFolder + "mpvnet.conf"; } public static string ProcessInstance { get; set; } = "single"; public static string DarkMode { get; set; } = "always"; public static string DarkTheme { get; set; } = "dark"; @@ -49,8 +50,8 @@ namespace mpvnet public static void Init() { - string dummy = mp.ConfigFolder; - var dummy2 = mp.Conf; + string dummy = core.ConfigFolder; + var dummy2 = core.Conf; foreach (var i in Conf) ProcessProperty(i.Key, i.Value, true); @@ -59,7 +60,7 @@ namespace mpvnet { try { - string filePath = mp.ConfigFolder + "mpvnet-debug.log"; + string filePath = core.ConfigFolder + "mpvnet-debug.log"; if (File.Exists(filePath)) File.Delete(filePath); @@ -78,17 +79,17 @@ namespace mpvnet string themeContent = null; - if (File.Exists(mp.ConfigFolder + "theme.conf")) - themeContent = File.ReadAllText(mp.ConfigFolder + "theme.conf"); + if (File.Exists(core.ConfigFolder + "theme.conf")) + themeContent = File.ReadAllText(core.ConfigFolder + "theme.conf"); Theme.Init( themeContent, Properties.Resources.theme, IsDarkMode ? DarkTheme : LightTheme); - mp.Shutdown += Shutdown; - mp.Initialized += Initialized; - mp.LogMessage += ShowFatalError; + core.Shutdown += Shutdown; + core.Initialized += Initialized; + core.LogMessage += ShowFatalError; } static void ShowFatalError(mpv_log_level level, string msg) @@ -103,6 +104,7 @@ namespace mpvnet try { action.Invoke(); + Debug.WriteLine(Environment.TickCount); } catch (Exception e) { @@ -116,25 +118,36 @@ namespace mpvnet if (obj is Exception e) { if (App.IsStartedFromTerminal) - ConsoleHelp.WriteError(e.ToString(), "mpv.net"); + ConsoleHelp.WriteError(e.ToString()); else Msg.ShowException(e); } else { if (App.IsStartedFromTerminal) - ConsoleHelp.WriteError(obj.ToString(), "mpv.net"); + ConsoleHelp.WriteError(obj.ToString()); else Msg.ShowError(obj.ToString()); } } + public static void ShowError(string title, string msg) + { + if (App.IsStartedFromTerminal) + { + ConsoleHelp.WriteError(title); + ConsoleHelp.WriteError(msg); + } + else + Msg.ShowError(title, msg); + } + static void Initialized() { if (RememberVolume) { - mp.set_property_int("volume", RegistryHelp.GetInt(App.RegPath, "Volume", 70)); - mp.set_property_string("mute", RegistryHelp.GetString(App.RegPath, "Mute", "no")); + core.set_property_int("volume", RegistryHelp.GetInt(App.RegPath, "Volume", 70)); + core.set_property_string("mute", RegistryHelp.GetString(App.RegPath, "Mute", "no")); } } @@ -142,8 +155,8 @@ namespace mpvnet { if (RememberVolume) { - RegistryHelp.SetValue(App.RegPath, "Volume", mp.get_property_int("volume")); - RegistryHelp.SetValue(App.RegPath, "Mute", mp.get_property_string("mute")); + RegistryHelp.SetValue(App.RegPath, "Volume", core.get_property_int("volume")); + RegistryHelp.SetValue(App.RegPath, "Mute", core.get_property_string("mute")); } } @@ -184,7 +197,7 @@ namespace mpvnet case "light-theme": LightTheme = value.Trim('\'', '"'); return true; default: if (writeError) - ConsoleHelp.WriteError($"unknown mpvnet.conf property: {name}", "mpv.net"); + ConsoleHelp.WriteError($"unknown mpvnet.conf property: {name}"); return false; } } diff --git a/mpv.net/Misc/Command.cs b/mpv.net/Misc/Commands.cs similarity index 78% rename from mpv.net/Misc/Command.cs rename to mpv.net/Misc/Commands.cs index b14768f..a3fc30d 100644 --- a/mpv.net/Misc/Command.cs +++ b/mpv.net/Misc/Commands.cs @@ -8,13 +8,13 @@ using System.Windows.Forms; using System.Windows.Interop; using VB = Microsoft.VisualBasic; -using ScriptHost; using static NewLine; +using static mpvnet.Core; namespace mpvnet { - public class Command + public class Commands { public static void Execute(string id, string[] args) { @@ -36,7 +36,7 @@ namespace mpvnet case "show-about": ShowDialog(typeof(AboutWindow)); break; case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break; case "show-input-editor": ShowDialog(typeof(InputWindow)); break; - case "open-conf-folder": Process.Start(mp.ConfigFolder); break; + case "open-conf-folder": Process.Start(core.ConfigFolder); break; case "shell-execute": Process.Start(args[0]); break; case "show-info": ShowInfo(); break; case "playlist-first": PlaylistFirst(); break; @@ -49,7 +49,7 @@ namespace mpvnet } } - public static void InvokeOnMainThread(Action action) => MainForm.Instance.Invoke(action); + public static void InvokeOnMainThread(Action action) => MainForm.Instance.BeginInvoke(action); public static void ShowDialog(Type winType) { @@ -74,7 +74,7 @@ namespace mpvnet InvokeOnMainThread(new Action(() => { using (var d = new OpenFileDialog() { Multiselect = true }) if (d.ShowDialog() == DialogResult.OK) - mp.LoadFiles(d.FileNames, loadFolder, append); + core.LoadFiles(d.FileNames, loadFolder, append); })); } @@ -90,13 +90,13 @@ namespace mpvnet { if (Directory.Exists(d.SelectedPath + "\\BDMV")) { - mp.set_property_string("bluray-device", d.SelectedPath); - mp.LoadFiles(new[] { @"bd://" }, false, false); + core.set_property_string("bluray-device", d.SelectedPath); + core.LoadFiles(new[] { @"bd://" }, false, false); } else { - mp.set_property_string("dvd-device", d.SelectedPath); - mp.LoadFiles(new[] { @"dvd://" }, false, false); + core.set_property_string("dvd-device", d.SelectedPath); + core.LoadFiles(new[] { @"dvd://" }, false, false); } } } @@ -105,31 +105,31 @@ namespace mpvnet public static void PlaylistFirst() { - int pos = mp.get_property_int("playlist-pos"); + int pos = core.get_property_int("playlist-pos"); if (pos != 0) - mp.set_property_int("playlist-pos", 0); + core.set_property_int("playlist-pos", 0); } public static void PlaylistLast() { - int pos = mp.get_property_int("playlist-pos"); - int count = mp.get_property_int("playlist-count"); + int pos = core.get_property_int("playlist-pos"); + int count = core.get_property_int("playlist-count"); if (pos < count - 1) - mp.set_property_int("playlist-pos", count - 1); + core.set_property_int("playlist-pos", count - 1); } public static void ShowHistory() { - if (File.Exists(mp.ConfigFolder + "history.txt")) - Process.Start(mp.ConfigFolder + "history.txt"); + if (File.Exists(core.ConfigFolder + "history.txt")) + Process.Start(core.ConfigFolder + "history.txt"); else { if (Msg.ShowQuestion("Create history.txt file in config folder?", "mpv.net will write the date, time and filename of opened files to it.") == MsgResult.OK) - File.WriteAllText(mp.ConfigFolder + "history.txt", ""); + File.WriteAllText(core.ConfigFolder + "history.txt", ""); } } @@ -139,13 +139,13 @@ namespace mpvnet { string performer, title, album, genre, date, duration, text = ""; long fileSize = 0; - string path = mp.get_property_string("path"); + string path = core.get_property_string("path"); if (path.Contains("://")) - path = mp.get_property_string("media-title"); + path = core.get_property_string("media-title"); - int width = mp.get_property_int("video-params/w"); - int height = mp.get_property_int("video-params/h"); + int width = core.get_property_int("video-params/w"); + int height = core.get_property_int("video-params/h"); if (File.Exists(path)) { @@ -171,7 +171,7 @@ namespace mpvnet text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n"; text += "Type: " + path.ShortExt().ToUpper(); - mp.commandv("show-text", text, "5000"); + core.commandv("show-text", text, "5000"); return; } } @@ -185,16 +185,16 @@ namespace mpvnet "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" + "Type: " + path.ShortExt().ToUpper(); - mp.commandv("show-text", text, "5000"); + core.commandv("show-text", text, "5000"); return; } } } - TimeSpan position = TimeSpan.FromSeconds(mp.get_property_number("time-pos")); - TimeSpan duration2 = TimeSpan.FromSeconds(mp.get_property_number("duration")); - string videoFormat = mp.get_property_string("video-format").ToUpper(); - string audioCodec = mp.get_property_string("audio-codec-name").ToUpper(); + TimeSpan position = TimeSpan.FromSeconds(core.get_property_number("time-pos")); + TimeSpan duration2 = TimeSpan.FromSeconds(core.get_property_number("duration")); + string videoFormat = core.get_property_string("video-format").ToUpper(); + string audioCodec = core.get_property_string("audio-codec-name").ToUpper(); text = path.FileName() + "\n" + FormatTime(position.TotalMinutes) + ":" + @@ -208,12 +208,12 @@ namespace mpvnet text += $"{videoFormat}\n{audioCodec}"; - mp.commandv("show-text", text, "5000"); + core.commandv("show-text", text, "5000"); string FormatTime(double value) => ((int)value).ToString("00"); } catch (Exception e) { - Msg.ShowException(e); + App.ShowException(e); } } @@ -221,9 +221,12 @@ namespace mpvnet { InvokeOnMainThread(new Action(() => { string command = VB.Interaction.InputBox("Enter a mpv command to be executed.", "Execute Command", RegistryHelp.GetString(App.RegPath, "RecentExecutedCommand")); - if (string.IsNullOrEmpty(command)) return; + + if (string.IsNullOrEmpty(command)) + return; + RegistryHelp.SetValue(App.RegPath, "RecentExecutedCommand", command); - mp.command(command, false); + core.command(command, false); })); } @@ -231,12 +234,14 @@ namespace mpvnet { InvokeOnMainThread(new Action(() => { string clipboard = System.Windows.Forms.Clipboard.GetText(); + if (string.IsNullOrEmpty(clipboard) || (!clipboard.Contains("://") && !File.Exists(clipboard)) || clipboard.Contains("\n")) { - Msg.ShowError("The clipboard does not contain a valid URL or file, URLs have to contain :// and are not allowed to contain a newline character."); + App.ShowError("No URL found", "The clipboard does not contain a valid URL or file."); return; } - mp.LoadFiles(new [] { clipboard }, false, Control.ModifierKeys.HasFlag(Keys.Control)); + + core.LoadFiles(new [] { clipboard }, false, Control.ModifierKeys.HasFlag(Keys.Control)); })); } @@ -245,7 +250,7 @@ namespace mpvnet InvokeOnMainThread(new Action(() => { using (var d = new OpenFileDialog()) { - string path = mp.get_property_string("path"); + string path = core.get_property_string("path"); if (File.Exists(path)) d.InitialDirectory = Path.GetDirectoryName(path); @@ -254,7 +259,7 @@ namespace mpvnet if (d.ShowDialog() == DialogResult.OK) foreach (string filename in d.FileNames) - mp.commandv("sub-add", filename); + core.commandv("sub-add", filename); } })); } @@ -264,40 +269,40 @@ namespace mpvnet InvokeOnMainThread(new Action(() => { using (var d = new OpenFileDialog()) { - string path = mp.get_property_string("path"); + string path = core.get_property_string("path"); if (File.Exists(path)) d.InitialDirectory = Path.GetDirectoryName(path); d.Multiselect = true; if (d.ShowDialog() == DialogResult.OK) foreach (string i in d.FileNames) - mp.commandv("audio-add", i); + core.commandv("audio-add", i); } })); } public static void CycleAudio() { - string path = mp.get_property_string("path"); + string path = core.get_property_string("path"); if (!File.Exists(path)) return; using (MediaInfo mi = new MediaInfo(path)) { - MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray(); + MediaTrack[] audTracks = core.MediaTracks.Where(track => track.Type == "a").ToArray(); if (audTracks.Length < 2) return; - int aid = mp.get_property_int("aid"); + int aid = core.get_property_int("aid"); aid += 1; if (aid > audTracks.Length) aid = 1; - mp.commandv("set", "aid", aid.ToString()); - mp.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000"); + core.commandv("set", "aid", aid.ToString()); + core.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000"); } } @@ -317,7 +322,7 @@ namespace mpvnet '' }"; - string json = mp.get_property_string("profile-list"); + string json = core.get_property_string("profile-list"); string file = Path.GetTempPath() + @"\mpv profile-list.txt"; File.WriteAllText(file, BR + PowerShell.InvokeAndReturnString(code, "json", json)); Process.Start(file); @@ -344,7 +349,7 @@ namespace mpvnet } }"; - string json = mp.get_property_string("command-list"); + string json = core.get_property_string("command-list"); string file = Path.GetTempPath() + @"\mpv command-list.txt"; File.WriteAllText(file, PowerShell.InvokeAndReturnString(code, "json", json) + BR); Process.Start(file); @@ -353,7 +358,7 @@ namespace mpvnet static void ShowProperties() { string file = Path.GetTempPath() + @"\mpv property-list.txt"; - var props = mp.get_property_string("property-list").Split(',').OrderBy(prop => prop); + var props = core.get_property_string("property-list").Split(',').OrderBy(prop => prop); File.WriteAllText(file, BR + string.Join(BR, props) + BR); Process.Start(file); } diff --git a/mpv.net/Misc/Extension.cs b/mpv.net/Misc/Extension.cs index b28ae32..520f625 100644 --- a/mpv.net/Misc/Extension.cs +++ b/mpv.net/Misc/Extension.cs @@ -1,10 +1,13 @@ -using System; + +using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.IO; using System.Linq; +using static mpvnet.Core; + namespace mpvnet { public class Extension @@ -25,20 +28,23 @@ namespace mpvnet { string[] knownExtensions = { "RatingExtension", "ScriptingExtension" }; - foreach (string path in Directory.GetDirectories(dir)) + foreach (string extDir in Directory.GetDirectories(dir)) { - if (knownExtensions.Contains(Path.GetFileName(path))) - catalog.Catalogs.Add(new DirectoryCatalog(path, "*Extension.dll")); + if (knownExtensions.Contains(Path.GetFileName(extDir))) + catalog.Catalogs.Add(new DirectoryCatalog(extDir, Path.GetFileName(extDir) + ".dll")); else - Msg.ShowError("Failed to load extension", path + "\n\nOnly extensions that ship with mpv.net are allowed in \\extensions\n\nUser extensions have to use \\extensions\n\nNever copy or install a new mpv.net version over a old mpv.net version."); + ConsoleHelp.WriteError("Failed to load extension:\n\n" + extDir + + "\n\nOnly extensions that ship with mpv.net are allowed in \\extensions" + + "\n\nUser extensions have to use \\extensions" + + "\n\nNever copy or install a new mpv.net version over a old mpv.net version."); } } - dir = mp.ConfigFolder + "extensions"; + dir = core.ConfigFolder + "extensions"; if (Directory.Exists(dir)) - foreach (string i in Directory.GetDirectories(dir)) - catalog.Catalogs.Add(new DirectoryCatalog(i, "*Extension.dll")); + foreach (string extDir in Directory.GetDirectories(dir)) + catalog.Catalogs.Add(new DirectoryCatalog(extDir, Path.GetFileName(extDir) + ".dll")); if (catalog.Catalogs.Count > 0) { @@ -48,7 +54,7 @@ namespace mpvnet } catch (Exception ex) { - Msg.ShowException(ex); + App.ShowException(ex); } } } @@ -56,4 +62,4 @@ namespace mpvnet public interface IExtension { } -} \ No newline at end of file +} diff --git a/mpv.net/Misc/Help.cs b/mpv.net/Misc/Help.cs index f89fd80..ae35288 100644 --- a/mpv.net/Misc/Help.cs +++ b/mpv.net/Misc/Help.cs @@ -6,7 +6,10 @@ public static class ConsoleHelp { public static int Padding { get; set; } - public static void WriteError(object obj, string module = null) => Write(obj, module, ConsoleColor.Red, false); + public static void WriteError(object obj, string module = "mpv.net") + { + Write(obj, module, ConsoleColor.Red, false); + } public static void Write(object obj, string module = "mpv.net") { diff --git a/mpv.net/Misc/Misc.cs b/mpv.net/Misc/Misc.cs index 31e3c20..3f7a8f0 100644 --- a/mpv.net/Misc/Misc.cs +++ b/mpv.net/Misc/Misc.cs @@ -14,6 +14,8 @@ using System.Windows.Forms; using Microsoft.Win32; +using static mpvnet.Core; + namespace mpvnet { public class Sys @@ -186,7 +188,7 @@ namespace mpvnet public static ObservableCollection Items { get { if (_Items is null) - _Items = GetItems(File.ReadAllText(mp.InputConfPath)); + _Items = GetItems(File.ReadAllText(core.InputConfPath)); return _Items; } diff --git a/mpv.net/Misc/PowerShell.cs b/mpv.net/Misc/PowerShell.cs new file mode 100644 index 0000000..904d766 --- /dev/null +++ b/mpv.net/Misc/PowerShell.cs @@ -0,0 +1,244 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Runspaces; +using System.Threading; +using System.Threading.Tasks; + +using static mpvnet.Core; +using static NewLine; + +namespace mpvnet +{ + public class PowerShell + { + public Runspace Runspace { get; set; } + public Pipeline Pipeline { get; set; } + public string Module { get; set; } + public bool Print { get; set; } + public List Scripts { get; } = new List(); + public List> Variables = new List>(); + public string[] Parameters { get; } + public event Action Event; + public event Action PropertyChanged; + public List> EventHandlers = new List>(); + public List> PropChangedHandlers = new List>(); + + public static List Instances { get; } = new List(); + + public object Invoke() => Invoke(null, null); + + public object Invoke(string variable, object obj) + { + try + { + Runspace = RunspaceFactory.CreateRunspace(); + Runspace.ApartmentState = ApartmentState.STA; + Runspace.Open(); + Pipeline = Runspace.CreatePipeline(); + + foreach (string script in Scripts) + Pipeline.Commands.AddScript(script); + + if (Parameters != null) + foreach (string param in Parameters) + foreach (Command command in Pipeline.Commands) + command.Parameters.Add(null, param); + + Runspace.SessionStateProxy.SetVariable("mp", this); + + foreach (var i in Variables) + Runspace.SessionStateProxy.SetVariable(i.Key, i.Value); + + if (!string.IsNullOrEmpty(variable)) + Runspace.SessionStateProxy.SetVariable(variable, obj); + + if (Print) + { + Pipeline.Output.DataReady += Output_DataReady; + Pipeline.Error.DataReady += Error_DataReady; + } + + return Pipeline.Invoke(); + } + catch (RuntimeException e) + { + string message = e.Message + BR + BR + e.ErrorRecord.ScriptStackTrace.Replace( + " , ", "") + BR + BR + Module + BR; + + throw new PowerShellException(message); + } + catch (Exception e) + { + throw e; + } + } + + public static string InvokeAndReturnString(string code, string varName, object varValue) + { + PowerShell ps = new PowerShell() { Print = false }; + ps.Scripts.Add(code); + string ret = string.Join(Environment.NewLine, (ps.Invoke(varName, varValue) + as IEnumerable).Select(item => item.ToString())).ToString(); + ps.Runspace.Dispose(); + return ret; + } + + public void Output_DataReady(object sender, EventArgs e) + { + var output = sender as PipelineReader; + + while (output.Count > 0) + ConsoleHelp.Write(output.Read(), Module); + } + + public void Error_DataReady(object sender, EventArgs e) + { + var output = sender as PipelineReader; + + while (output.Count > 0) + ConsoleHelp.WriteError(output.Read(), Module); + } + + public void RedirectStreams(PSEventJob job) + { + if (Print) + { + job.Output.DataAdded += Output_DataAdded; + job.Error.DataAdded += Error_DataAdded; + } + } + + public void commandv(params string[] args) => core.commandv(args); + + public void command(string command) => core.command(command); + + public bool get_property_bool(string name) => core.get_property_bool(name); + + public void set_property_bool(string name, bool value) => core.set_property_bool(name, value); + + public int get_property_int(string name) => core.get_property_int(name); + + public void set_property_int(string name, int value) => core.set_property_int(name, value); + + public double get_property_number(string name) => core.get_property_number(name); + + public void set_property_number(string name, double value) => core.set_property_number(name, value); + + public string get_property_string(string name) => core.get_property_string(name); + + public void set_property_string(string name, string value) => core.set_property_string(name, value); + + public void observe_property(string name, string type, ScriptBlock sb) + { + PropChangedHandlers.Add(new KeyValuePair(name, sb)); + + switch (type) + { + case "bool": case "boolean": + core.observe_property_bool(name, (value) => Task.Run(() => PropertyChanged.Invoke(name, value))); + break; + case "string": + core.observe_property_string(name, (value) => Task.Run(() => PropertyChanged.Invoke(name, value))); + break; + case "int": case "integer": + core.observe_property_int(name, (value) => Task.Run(() => PropertyChanged.Invoke(name, value))); + break; + case "float": case "double": + core.observe_property_double(name, (value) => Task.Run(() => PropertyChanged.Invoke(name, value))); + break; + case "nil": case "none": case "native": + core.observe_property(name, () => Task.Run(() => PropertyChanged.Invoke(name, null))); + break; + default: + App.ShowError("Invalid Type", "Valid types are: bool or boolean, string, int or integer, float or double, nil or none or native"); + break; + } + } + + public void register_event(string name, ScriptBlock sb) + { + EventHandlers.Add(new KeyValuePair(name, sb)); + + switch (name) + { + case "log-message": + core.LogMessageAsync += (level, msg) => Event.Invoke("log-message", new object[] { level, msg }); + break; + + case "end-file": + core.EndFileAsync += (reason) => Event.Invoke("end-file", new object[] { reason }); + break; + + case "client-message": + core.ClientMessageAsync += (args) => Event.Invoke("client-message", args); + break; + + case "shutdown": + core.Shutdown += () => Event.Invoke("shutdown", null); + break; + + case "get-property-reply": + core.GetPropertyReplyAsync += () => Event.Invoke("get-property-reply", null); + break; + + case "set-property-reply": + core.SetPropertyReplyAsync += () => Event.Invoke("set-property-reply", null); + break; + + case "command-reply": + core.CommandReplyAsync += () => Event.Invoke("command-reply", null); + break; + + case "start-file": + core.StartFileAsync += () => Event.Invoke("start-file", null); + break; + + case "file-loaded": + core.FileLoadedAsync += () => Event.Invoke("file-loaded", null); + break; + + case "idle": + core.IdleAsync += () => Event.Invoke("idle", null); + break; + + case "video-reconfig": + core.VideoReconfigAsync += () => Event.Invoke("video-reconfig", null); + break; + + case "audio-reconfig": + core.AudioReconfigAsync += () => Event.Invoke("audio-reconfig", null); + break; + + case "seek": + core.SeekAsync += () => Event.Invoke("seek", null); + break; + + case "playback-restart": + core.PlaybackRestartAsync += () => Event.Invoke("playback-restart", null); + break; + } + } + + void Output_DataAdded(object sender, DataAddedEventArgs e) + { + var output = sender as PSDataCollection; + ConsoleHelp.Write(output[e.Index], Module); + } + + void Error_DataAdded(object sender, DataAddedEventArgs e) + { + var error = sender as PSDataCollection; + ConsoleHelp.WriteError(error[e.Index], Module); + } + } + + public class PowerShellException : Exception + { + public PowerShellException(string message) : base(message) + { + } + } +} diff --git a/mpv.net/Misc/Program.cs b/mpv.net/Misc/Program.cs index 2157e7e..d60ec64 100644 --- a/mpv.net/Misc/Program.cs +++ b/mpv.net/Misc/Program.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.Threading; using System.Diagnostics; +using static mpvnet.Core; + namespace mpvnet { static class Program @@ -21,7 +23,7 @@ namespace mpvnet if (App.IsStartedFromTerminal) WinAPI.AttachConsole(-1 /*ATTACH_PARENT_PROCESS*/); - if (mp.ConfigFolder == "") + if (core.ConfigFolder == "") return; string[] args = Environment.GetCommandLineArgs().Skip(1).ToArray(); @@ -95,4 +97,4 @@ namespace mpvnet } } } -} \ No newline at end of file +} diff --git a/mpv.net/Misc/Theme.cs b/mpv.net/Misc/Theme.cs index 45de449..e413e5b 100644 --- a/mpv.net/Misc/Theme.cs +++ b/mpv.net/Misc/Theme.cs @@ -45,7 +45,7 @@ namespace UI if (!theme.Dictionary.ContainsKey(key)) { isKeyMissing = true; - ConsoleHelp.WriteError($"Theme '{activeTheme}' misses '{key}'", "mpv.net"); + ConsoleHelp.WriteError($"Theme '{activeTheme}' misses '{key}'"); break; } } diff --git a/mpv.net/Misc/UpdateCheck.cs b/mpv.net/Misc/UpdateCheck.cs index 203bbf6..ea89bee 100644 --- a/mpv.net/Misc/UpdateCheck.cs +++ b/mpv.net/Misc/UpdateCheck.cs @@ -6,6 +6,8 @@ using System.Reflection; using System.Text.RegularExpressions; using System.Windows.Forms; +using static mpvnet.Core; + namespace mpvnet { class UpdateCheck @@ -61,7 +63,7 @@ namespace mpvnet proc.Start(); } - mp.command("quit"); + core.command("quit"); } RegistryHelp.SetValue(RegistryHelp.ApplicationKey, "UpdateCheckVersion", onlineVersion.ToString()); @@ -74,4 +76,4 @@ namespace mpvnet } } } -} \ No newline at end of file +} diff --git a/mpv.net/Properties/AssemblyInfo.cs b/mpv.net/Properties/AssemblyInfo.cs index ea09f0b..951b8ee 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.5.0")] -[assembly: AssemblyFileVersion("5.4.5.0")] +[assembly: AssemblyVersion("5.4.5.1")] +[assembly: AssemblyFileVersion("5.4.5.1")] diff --git a/mpv.net/Scripting/IronPython.cs b/mpv.net/Scripting/IronPython.cs deleted file mode 100644 index 6abb6d0..0000000 --- a/mpv.net/Scripting/IronPython.cs +++ /dev/null @@ -1,61 +0,0 @@ - -using System; -using System.IO; -using System.Reflection; - -using Microsoft.Scripting; -using Microsoft.Scripting.Hosting; - -using IronPython.Hosting; -using IronPython.Runtime; -using IronPython.Runtime.Operations; - -namespace mpvnet -{ - public class PythonScript - { - ScriptEngine engine; - ScriptScope scope; - - public PythonScript(string scriptPath) - { - try - { - engine = Python.CreateEngine(); - scope = engine.CreateScope(); - scope.ImportModule("clr"); - engine.Execute("import clr", scope); - engine.Execute("clr.AddReference(\"mpvnet\")", scope); - engine.Execute("import mpvnet", scope); - engine.Execute("from mpvnet import *", scope); - engine.Execute(File.ReadAllText(scriptPath), scope); - } - catch (Exception ex) - { - if (ex is SyntaxErrorException e) - Msg.ShowError(e.GetType().Name,$"{e.Line}, {e.Column}: " + e.Message + "\n\n" + Path.GetFileName(scriptPath)); - else - Msg.ShowError(ex.GetType().Name, ex.Message + "\n\n" + Path.GetFileName(scriptPath)); - } - } - } - - public class PythonEventObject - { - public PythonFunction PythonFunction { get; set; } - public EventInfo EventInfo { get; set; } - public Delegate Delegate { get; set; } - - public void Invoke() => PythonCalls.Call(PythonFunction); - - public void InvokeEndFileEventMode(EndFileEventMode arg) - { - PythonCalls.Call(PythonFunction, new[] { arg }); - } - - public void InvokeStrings(string[] arg) - { - PythonCalls.Call(PythonFunction, new[] { arg }); - } - } -} \ No newline at end of file diff --git a/mpv.net/Scripting/PowerShell.cs b/mpv.net/Scripting/PowerShell.cs deleted file mode 100644 index 0f363da..0000000 --- a/mpv.net/Scripting/PowerShell.cs +++ /dev/null @@ -1,123 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Runspaces; -using System.Threading; - -namespace ScriptHost -{ - public class PowerShell - { - public Runspace Runspace { get; set; } - public Pipeline Pipeline { get; set; } - public string Module { get; set; } - public bool Print { get; set; } - public List Scripts { get; } = new List(); - public string[] Parameters { get; } - - public static List Instances { get; } = new List(); - - string NL = Environment.NewLine; - - public object Invoke() => Invoke(null, null); - - public object Invoke(string variable, object obj) - { - try - { - Runspace = RunspaceFactory.CreateRunspace(); - Runspace.ApartmentState = ApartmentState.STA; - Runspace.Open(); - Pipeline = Runspace.CreatePipeline(); - - foreach (string script in Scripts) - Pipeline.Commands.AddScript(script); - - if (Parameters != null) - foreach (string param in Parameters) - foreach (Command command in Pipeline.Commands) - command.Parameters.Add(null, param); - - Runspace.SessionStateProxy.SetVariable("ScriptHost", this); - - if (!string.IsNullOrEmpty(variable)) - Runspace.SessionStateProxy.SetVariable(variable, obj); - - if (Print) - { - Pipeline.Output.DataReady += Output_DataReady; - Pipeline.Error.DataReady += Error_DataReady; - } - - return Pipeline.Invoke(); - } - catch (RuntimeException e) - { - string message = e.Message + NL + NL + e.ErrorRecord.ScriptStackTrace.Replace( - " , ", "") + NL + NL + Module + NL; - - throw new PowerShellException(message); - } - catch (Exception e) - { - throw e; - } - } - - public static string InvokeAndReturnString(string code, string varName, object varValue) - { - PowerShell ps = new PowerShell() { Print = false }; - ps.Scripts.Add(code); - string ret = string.Join(Environment.NewLine, (ps.Invoke(varName, varValue) - as IEnumerable).Select(item => item.ToString())).ToString(); - ps.Runspace.Dispose(); - return ret; - } - - public void Output_DataReady(object sender, EventArgs e) - { - var output = sender as PipelineReader; - - while (output.Count > 0) - ConsoleHelp.Write(output.Read(), Module); - } - - public void Error_DataReady(object sender, EventArgs e) - { - var output = sender as PipelineReader; - - while (output.Count > 0) - ConsoleHelp.WriteError(output.Read(), Module); - } - - public void RedirectEventJobStreams(PSEventJob job) - { - if (Print) - { - job.Output.DataAdded += Output_DataAdded; - job.Error.DataAdded += Error_DataAdded; - } - } - - void Output_DataAdded(object sender, DataAddedEventArgs e) - { - var output = sender as PSDataCollection; - ConsoleHelp.Write(output[e.Index], Module); - } - - void Error_DataAdded(object sender, DataAddedEventArgs e) - { - var error = sender as PSDataCollection; - ConsoleHelp.WriteError(error[e.Index], Module); - } - } - - public class PowerShellException : Exception - { - public PowerShellException(string message) : base(message) - { - } - } -} diff --git a/mpv.net/WPF/AboutWindow.xaml.cs b/mpv.net/WPF/AboutWindow.xaml.cs index 61920a3..cbf5b76 100644 --- a/mpv.net/WPF/AboutWindow.xaml.cs +++ b/mpv.net/WPF/AboutWindow.xaml.cs @@ -1,7 +1,10 @@ -using System.IO; + +using System.IO; using System.Windows; using System.Windows.Input; +using static mpvnet.Core; + namespace mpvnet { public partial class AboutWindow : Window @@ -10,7 +13,7 @@ namespace mpvnet { InitializeComponent(); Version.Text = $"mpv.net Version {System.Windows.Forms.Application.ProductVersion} ({File.GetLastWriteTime(System.Windows.Forms.Application.ExecutablePath).ToShortDateString()})"; - mpvVersion.Text = $"{mp.get_property_string("mpv-version")} ({File.GetLastWriteTime(Folder.Startup + "mpv-1.dll").ToShortDateString()})"; + mpvVersion.Text = $"{core.get_property_string("mpv-version")} ({File.GetLastWriteTime(Folder.Startup + "mpv-1.dll").ToShortDateString()})"; } protected override void OnPreviewKeyDown(KeyEventArgs e) => Close(); diff --git a/mpv.net/WPF/CommandPaletteWindow.xaml.cs b/mpv.net/WPF/CommandPaletteWindow.xaml.cs index 8e4fb7e..680d402 100644 --- a/mpv.net/WPF/CommandPaletteWindow.xaml.cs +++ b/mpv.net/WPF/CommandPaletteWindow.xaml.cs @@ -6,6 +6,8 @@ using System.Windows.Data; using System.Windows.Input; using System.Windows.Interop; +using static mpvnet.Core; + namespace mpvnet { public partial class CommandPaletteWindow : Window @@ -106,7 +108,7 @@ namespace mpvnet { CommandItem item = ListView.SelectedItem as CommandItem; Close(); - mp.command(item.Command); + core.command(item.Command); } } diff --git a/mpv.net/WPF/ConfWindow.xaml.cs b/mpv.net/WPF/ConfWindow.xaml.cs index df2a5fd..bcd1c6f 100644 --- a/mpv.net/WPF/ConfWindow.xaml.cs +++ b/mpv.net/WPF/ConfWindow.xaml.cs @@ -11,6 +11,7 @@ using System.Windows.Controls; using System.Windows.Input; using DynamicGUI; +using static mpvnet.Core; namespace mpvnet { @@ -26,7 +27,7 @@ namespace mpvnet InitializeComponent(); DataContext = this; SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged; - LoadConf(mp.ConfPath); + LoadConf(core.ConfPath); LoadConf(App.ConfPath); LoadSettings(); InitialContent = GetCompareString(); @@ -74,7 +75,7 @@ namespace mpvnet if (InitialContent == GetCompareString()) return; - File.WriteAllText(mp.ConfPath, GetContent("mpv")); + File.WriteAllText(core.ConfPath, GetContent("mpv")); File.WriteAllText(App.ConfPath, GetContent("mpvnet")); Msg.Show("Changes will be available on next mpv.net startup."); } @@ -293,7 +294,7 @@ namespace mpvnet void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e) { - Process.Start(Path.GetDirectoryName(mp.ConfPath)); + Process.Start(Path.GetDirectoryName(core.ConfPath)); } void PreviewTextBlock_MouseUp(object sender, MouseButtonEventArgs e) @@ -319,4 +320,4 @@ namespace mpvnet Close(); } } -} \ No newline at end of file +} diff --git a/mpv.net/WPF/EverythingWindow.xaml.cs b/mpv.net/WPF/EverythingWindow.xaml.cs index 48d586c..9b61eb3 100644 --- a/mpv.net/WPF/EverythingWindow.xaml.cs +++ b/mpv.net/WPF/EverythingWindow.xaml.cs @@ -10,6 +10,8 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; +using static mpvnet.Core; + namespace mpvnet { public partial class EverythingWindow : Window @@ -103,7 +105,7 @@ namespace mpvnet void Execute() { if (ListView.SelectedItem != null) - mp.LoadFiles(new[] { ListView.SelectedItem as string }, true, Keyboard.Modifiers == ModifierKeys.Control); + core.LoadFiles(new[] { ListView.SelectedItem as string }, true, Keyboard.Modifiers == ModifierKeys.Control); Keyboard.Focus(FilterTextBox); } diff --git a/mpv.net/WPF/InputWindow.xaml.cs b/mpv.net/WPF/InputWindow.xaml.cs index 7b90de8..2406459 100644 --- a/mpv.net/WPF/InputWindow.xaml.cs +++ b/mpv.net/WPF/InputWindow.xaml.cs @@ -8,6 +8,8 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; +using static mpvnet.Core; + namespace mpvnet { public partial class InputWindow : Window @@ -123,7 +125,7 @@ namespace mpvnet void Window_Closed(object sender, EventArgs e) { if (InitialInputConfContent == GetInputConfContent()) return; - File.WriteAllText(mp.InputConfPath, GetInputConfContent()); + File.WriteAllText(core.InputConfPath, GetInputConfContent()); Msg.Show("Changes will be available on next mpv.net startup."); } diff --git a/mpv.net/WPF/LearnWindow.xaml.cs b/mpv.net/WPF/LearnWindow.xaml.cs index c044bae..9038bae 100644 --- a/mpv.net/WPF/LearnWindow.xaml.cs +++ b/mpv.net/WPF/LearnWindow.xaml.cs @@ -6,6 +6,7 @@ using System.Windows.Input; using System.Windows.Interop; using WinForms = System.Windows.Forms; +using static mpvnet.Core; namespace mpvnet { @@ -183,7 +184,7 @@ namespace mpvnet OnKeyUp(new WinForms.KeyEventArgs((WinForms.Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys)); else if (m.Msg == WM_APPCOMMAND) { - if (!mp.get_property_bool("input-media-keys")) + if (!core.get_property_bool("input-media-keys")) return; var value = (AppCommand)(m.LParam.ToInt64() >> 16 & ~0xf000); diff --git a/mpv.net/WinForms/MainForm.cs b/mpv.net/WinForms/MainForm.cs index 44514cc..9afe93b 100644 --- a/mpv.net/WinForms/MainForm.cs +++ b/mpv.net/WinForms/MainForm.cs @@ -12,7 +12,7 @@ using System.Diagnostics; using System.Threading.Tasks; using UI; -using ScriptHost; +using static mpvnet.Core; namespace mpvnet { @@ -47,30 +47,30 @@ namespace mpvnet Instance = this; Hwnd = Handle; ConsoleHelp.Padding = 60; - mp.Init(); + core.Init(); - mp.Shutdown += Shutdown; - mp.VideoSizeChanged += VideoSizeChanged; - mp.FileLoaded += FileLoaded; - mp.Idle += Idle; - mp.Seek += () => UpdateProgressBar(); + core.Shutdown += Shutdown; + core.VideoSizeChanged += VideoSizeChanged; + core.FileLoaded += FileLoaded; + core.Idle += Idle; + core.Seek += () => UpdateProgressBar(); - mp.observe_property("window-maximized", PropChangeWindowMaximized); - mp.observe_property("window-minimized", PropChangeWindowMinimized); - mp.observe_property_bool("pause", PropChangePause); - mp.observe_property_bool("fullscreen", PropChangeFullscreen); - mp.observe_property_bool("ontop", PropChangeOnTop); - mp.observe_property_bool("border", PropChangeBorder); + core.observe_property("window-maximized", PropChangeWindowMaximized); + core.observe_property("window-minimized", PropChangeWindowMinimized); + core.observe_property_bool("pause", PropChangePause); + core.observe_property_bool("fullscreen", PropChangeFullscreen); + core.observe_property_bool("ontop", PropChangeOnTop); + core.observe_property_bool("border", PropChangeBorder); - mp.observe_property_string("sid", PropChangeSid); - mp.observe_property_string("aid", PropChangeAid); - mp.observe_property_string("vid", PropChangeVid); + core.observe_property_string("sid", PropChangeSid); + core.observe_property_string("aid", PropChangeAid); + core.observe_property_string("vid", PropChangeVid); - mp.observe_property_int("edition", PropChangeEdition); - mp.observe_property_double("window-scale", PropChangeWindowScale); + core.observe_property_int("edition", PropChangeEdition); + core.observe_property_double("window-scale", PropChangeWindowScale); - if (mp.GPUAPI != "vulkan") - mp.ProcessCommandLine(false); + if (core.GPUAPI != "vulkan") + core.ProcessCommandLine(false); AppDomain.CurrentDomain.UnhandledException += (sender, e) => App.ShowException(e.ExceptionObject); Application.ThreadException += (sender, e) => App.ShowException(e.Exception); @@ -82,10 +82,10 @@ namespace mpvnet ContextMenu.Opened += ContextMenu_Opened; ContextMenu.Opening += ContextMenu_Opening; - if (mp.Screen == -1) - mp.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen); + if (core.Screen == -1) + core.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen); - int targetIndex = mp.Screen; + int targetIndex = core.Screen; Screen[] screens = Screen.AllScreens; if (targetIndex < 0) @@ -99,7 +99,7 @@ namespace mpvnet Left = target.X + (target.Width - Width) / 2; Top = target.Y + (target.Height - Height) / 2; - if (!mp.Border) + if (!core.Border) FormBorderStyle = FormBorderStyle.None; int posX = RegistryHelp.GetInt(App.RegPath, "PosX"); @@ -111,13 +111,13 @@ namespace mpvnet Top = posY - Height / 2; } - if (mp.WindowMaximized) + if (core.WindowMaximized) { SetFormPosAndSize(1, true); WindowState = FormWindowState.Maximized; } - if (mp.WindowMinimized) + if (core.WindowMinimized) { SetFormPosAndSize(1, true); WindowState = FormWindowState.Minimized; @@ -163,7 +163,7 @@ namespace mpvnet void ContextMenu_Opening(object sender, CancelEventArgs e) { - lock (mp.MediaTracks) + lock (core.MediaTracks) { MenuItem trackMenuItem = FindMenuItem("Track"); @@ -171,16 +171,16 @@ namespace mpvnet { trackMenuItem.DropDownItems.Clear(); - MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray(); - MediaTrack[] subTracks = mp.MediaTracks.Where(track => track.Type == "s").ToArray(); - MediaTrack[] vidTracks = mp.MediaTracks.Where(track => track.Type == "v").ToArray(); - MediaTrack[] ediTracks = mp.MediaTracks.Where(track => track.Type == "e").ToArray(); + MediaTrack[] audTracks = core.MediaTracks.Where(track => track.Type == "a").ToArray(); + MediaTrack[] subTracks = core.MediaTracks.Where(track => track.Type == "s").ToArray(); + MediaTrack[] vidTracks = core.MediaTracks.Where(track => track.Type == "v").ToArray(); + MediaTrack[] ediTracks = core.MediaTracks.Where(track => track.Type == "e").ToArray(); foreach (MediaTrack track in vidTracks) { MenuItem mi = new MenuItem(track.Text); - mi.Action = () => mp.commandv("set", "vid", track.ID.ToString()); - mi.Checked = mp.Vid == track.ID.ToString(); + mi.Action = () => core.commandv("set", "vid", track.ID.ToString()); + mi.Checked = core.Vid == track.ID.ToString(); trackMenuItem.DropDownItems.Add(mi); } @@ -190,8 +190,8 @@ namespace mpvnet foreach (MediaTrack track in audTracks) { MenuItem mi = new MenuItem(track.Text); - mi.Action = () => mp.commandv("set", "aid", track.ID.ToString()); - mi.Checked = mp.Aid == track.ID.ToString(); + mi.Action = () => core.commandv("set", "aid", track.ID.ToString()); + mi.Checked = core.Aid == track.ID.ToString(); trackMenuItem.DropDownItems.Add(mi); } @@ -201,16 +201,16 @@ namespace mpvnet foreach (MediaTrack track in subTracks) { MenuItem mi = new MenuItem(track.Text); - mi.Action = () => mp.commandv("set", "sid", track.ID.ToString()); - mi.Checked = mp.Sid == track.ID.ToString(); + mi.Action = () => core.commandv("set", "sid", track.ID.ToString()); + mi.Checked = core.Sid == track.ID.ToString(); trackMenuItem.DropDownItems.Add(mi); } if (subTracks.Length > 0) { MenuItem mi = new MenuItem("S: No subtitles"); - mi.Action = () => mp.commandv("set", "sid", "no"); - mi.Checked = mp.Sid == "no"; + mi.Action = () => core.commandv("set", "sid", "no"); + mi.Checked = core.Sid == "no"; trackMenuItem.DropDownItems.Add(mi); } @@ -220,14 +220,14 @@ namespace mpvnet foreach (MediaTrack track in ediTracks) { MenuItem mi = new MenuItem(track.Text); - mi.Action = () => mp.commandv("set", "edition", track.ID.ToString()); - mi.Checked = mp.Edition == track.ID; + mi.Action = () => core.commandv("set", "edition", track.ID.ToString()); + mi.Checked = core.Edition == track.ID; trackMenuItem.DropDownItems.Add(mi); } } } - lock (mp.Chapters) + lock (core.Chapters) { MenuItem chaptersMenuItem = FindMenuItem("Chapters"); @@ -235,11 +235,11 @@ namespace mpvnet { chaptersMenuItem.DropDownItems.Clear(); - foreach (var i in mp.Chapters) + foreach (var i in core.Chapters) { MenuItem mi = new MenuItem(i.Key); mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " "; - mi.Action = () => mp.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute"); + mi.Action = () => core.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute"); chaptersMenuItem.DropDownItems.Add(mi); } } @@ -252,7 +252,7 @@ namespace mpvnet recent.DropDownItems.Clear(); foreach (string path in RecentFiles) - MenuItem.Add(recent.DropDownItems, path, () => mp.LoadFiles(new[] { path }, true, Control.ModifierKeys.HasFlag(Keys.Control))); + MenuItem.Add(recent.DropDownItems, path, () => core.LoadFiles(new[] { path }, true, Control.ModifierKeys.HasFlag(Keys.Control))); recent.DropDownItems.Add(new ToolStripSeparator()); MenuItem mi = new MenuItem("Clear List"); @@ -287,7 +287,7 @@ namespace mpvnet if (WindowState != FormWindowState.Normal) return; - if (mp.Fullscreen) + if (core.Fullscreen) { CycleFullscreen(true); return; @@ -295,17 +295,17 @@ namespace mpvnet } Screen screen = Screen.FromControl(this); - int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * mp.Autofit); + int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * core.Autofit); - if (mp.VideoSize.Height == 0 || mp.VideoSize.Width == 0 || - mp.VideoSize.Width / (float)mp.VideoSize.Height < App.MinimumAspectRatio) + if (core.VideoSize.Height == 0 || core.VideoSize.Width == 0 || + core.VideoSize.Width / (float)core.VideoSize.Height < App.MinimumAspectRatio) - mp.VideoSize = new Size((int)(autoFitHeight * (16 / 9.0)), autoFitHeight); + core.VideoSize = new Size((int)(autoFitHeight * (16 / 9.0)), autoFitHeight); - Size videoSize = mp.VideoSize; + Size videoSize = core.VideoSize; int height = videoSize.Height; - if (mp.WasInitialSizeSet || scale != 1) + if (core.WasInitialSizeSet || scale != 1) height = ClientSize.Height; else { @@ -317,7 +317,7 @@ namespace mpvnet if (App.StartSize != "video") height = autoFitHeight; - mp.WasInitialSizeSet = true; + core.WasInitialSizeSet = true; } height = Convert.ToInt32(height * scale); @@ -325,15 +325,15 @@ namespace mpvnet int maxHeight = screen.WorkingArea.Height - (Height - ClientSize.Height); int maxWidth = screen.WorkingArea.Width - (Width - ClientSize.Width); - if (height < maxHeight * mp.AutofitSmaller) + if (height < maxHeight * core.AutofitSmaller) { - height = Convert.ToInt32(maxHeight * mp.AutofitSmaller); + height = Convert.ToInt32(maxHeight * core.AutofitSmaller); width = Convert.ToInt32(height * videoSize.Width / (double)videoSize.Height); } - if (height > maxHeight * mp.AutofitLarger) + if (height > maxHeight * core.AutofitLarger) { - height = Convert.ToInt32(maxHeight * mp.AutofitLarger); + height = Convert.ToInt32(maxHeight * core.AutofitLarger); width = Convert.ToInt32(height * videoSize.Width / (double)videoSize.Height); } @@ -374,7 +374,7 @@ namespace mpvnet public void CycleFullscreen(bool enabled) { LastCycleFullscreen = Environment.TickCount; - mp.Fullscreen = enabled; + core.Fullscreen = enabled; if (enabled) { @@ -401,7 +401,7 @@ namespace mpvnet else WindowState = FormWindowState.Normal; - if (mp.Border) + if (core.Border) FormBorderStyle = FormBorderStyle.Sizable; else FormBorderStyle = FormBorderStyle.None; @@ -414,7 +414,7 @@ namespace mpvnet public void BuildMenu() { - string content = File.ReadAllText(mp.InputConfPath); + string content = File.ReadAllText(core.InputConfPath); var items = CommandItem.GetItems(content); if (!content.Contains("#menu:")) @@ -438,7 +438,7 @@ namespace mpvnet MenuItem menuItem = ContextMenu.Add(path, () => { try { - mp.command(item.Command); + core.command(item.Command); } catch (Exception ex) { Msg.ShowException(ex); } @@ -451,19 +451,24 @@ namespace mpvnet void FileLoaded() { - string path = mp.get_property_string("path"); + string path = core.get_property_string("path"); BeginInvoke(new Action(() => { if (path.Contains("://")) - Text = mp.get_property_string("media-title") + " - mpv.net " + Application.ProductVersion; + Text = core.get_property_string("media-title") + " - mpv.net " + Application.ProductVersion; else if (path.Contains(":\\") || path.StartsWith("\\\\")) Text = path.FileName() + " - mpv.net " + Application.ProductVersion; else Text = "mpv.net " + Application.ProductVersion; - int interval = (int)(mp.Duration.TotalMilliseconds / 100); - if (interval < 100) interval = 100; - if (interval > 1000) interval = 1000; + int interval = (int)(core.Duration.TotalMilliseconds / 100); + + if (interval < 100) + interval = 100; + + if (interval > 1000) + interval = 1000; + ProgressTimer.Interval = interval; UpdateProgressBar(); })); @@ -510,19 +515,17 @@ namespace mpvnet case 0x20A: // WM_MOUSEWHEEL case 0x100: // WM_KEYDOWN case 0x101: // WM_KEYUP - case 0x102: // WM_CHAR case 0x104: // WM_SYSKEYDOWN case 0x105: // WM_SYSKEYUP - case 0x106: // WM_SYSCHAR case 0x319: // WM_APPCOMMAND - if (mp.WindowHandle != IntPtr.Zero) - m.Result = WinAPI.SendMessage(mp.WindowHandle, m.Msg, m.WParam, m.LParam); + if (core.WindowHandle != IntPtr.Zero) + m.Result = WinAPI.SendMessage(core.WindowHandle, m.Msg, m.WParam, m.LParam); break; case 0x0200: // WM_MOUSEMOVE if (Environment.TickCount - LastCycleFullscreen > 500) { Point pos = PointToClient(Cursor.Position); - mp.command($"mouse {pos.X} {pos.Y}"); + core.command($"mouse {pos.X} {pos.Y}"); } if (CursorHelp.IsPosDifferent(LastCursorPosition)) @@ -530,12 +533,12 @@ namespace mpvnet break; case 0x2a3: // WM_MOUSELEAVE //osc won't auto hide after mouse left window in borderless mode - mp.command($"mouse {ClientSize.Width / 2} {ClientSize.Height / 3}"); + core.command($"mouse {ClientSize.Width / 2} {ClientSize.Height / 3}"); break; case 0x203: // WM_LBUTTONDBLCLK { Point pos = PointToClient(Cursor.Position); - mp.command($"mouse {pos.X} {pos.Y} 0 double"); + core.command($"mouse {pos.X} {pos.Y} 0 double"); } break; case 0x02E0: // WM_DPICHANGED @@ -553,7 +556,7 @@ namespace mpvnet var r = rc; NativeHelp.SubtractWindowBorders(Handle, ref r); int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top; - Size s = mp.VideoSize; + Size s = core.VideoSize; if (s == Size.Empty) s = new Size(16, 9); @@ -582,11 +585,11 @@ namespace mpvnet switch (mode) { case "single": - mp.LoadFiles(files, true, Control.ModifierKeys.HasFlag(Keys.Control)); + core.LoadFiles(files, true, Control.ModifierKeys.HasFlag(Keys.Control)); break; case "queue": foreach (string file in files) - mp.commandv("loadfile", file, "append"); + core.commandv("loadfile", file, "append"); break; } @@ -595,7 +598,7 @@ namespace mpvnet return; } - if (m.Msg == TaskbarButtonCreatedMessage && mp.TaskbarProgress) + if (m.Msg == TaskbarButtonCreatedMessage && core.TaskbarProgress) { Taskbar = new Taskbar(Handle); ProgressTimer.Start(); @@ -622,26 +625,26 @@ namespace mpvnet void UpdateProgressBar() { - if (mp.TaskbarProgress && Taskbar != null) - Taskbar.SetValue(mp.get_property_number("time-pos"), mp.Duration.TotalSeconds); + if (core.TaskbarProgress && Taskbar != null) + Taskbar.SetValue(core.get_property_number("time-pos"), core.Duration.TotalSeconds); } void PropChangeOnTop(bool value) => BeginInvoke(new Action(() => TopMost = value)); - void PropChangeAid(string value) => mp.Aid = value; + void PropChangeAid(string value) => core.Aid = value; - void PropChangeSid(string value) => mp.Sid = value; + void PropChangeSid(string value) => core.Sid = value; - void PropChangeVid(string value) => mp.Vid = value; + void PropChangeVid(string value) => core.Vid = value; - void PropChangeEdition(int value) => mp.Edition = value; + void PropChangeEdition(int value) => core.Edition = value; void PropChangeWindowScale(double value) { if (value != 1) { BeginInvoke(new Action(() => SetFormPosAndSize(value))); - mp.command("no-osd set window-scale 1"); + core.command("no-osd set window-scale 1"); } } @@ -652,11 +655,11 @@ namespace mpvnet BeginInvoke(new Action(() => { - mp.WindowMaximized = mp.get_property_bool("window-maximized"); + core.WindowMaximized = core.get_property_bool("window-maximized"); - if (mp.WindowMaximized && WindowState != FormWindowState.Maximized) + if (core.WindowMaximized && WindowState != FormWindowState.Maximized) WindowState = FormWindowState.Maximized; - else if (!mp.WindowMaximized && WindowState == FormWindowState.Maximized) + else if (!core.WindowMaximized && WindowState == FormWindowState.Maximized) WindowState = FormWindowState.Normal; })); } @@ -668,25 +671,25 @@ namespace mpvnet BeginInvoke(new Action(() => { - mp.WindowMinimized = mp.get_property_bool("window-minimized"); + core.WindowMinimized = core.get_property_bool("window-minimized"); - if (mp.WindowMinimized && WindowState != FormWindowState.Minimized) + if (core.WindowMinimized && WindowState != FormWindowState.Minimized) WindowState = FormWindowState.Minimized; - else if (!mp.WindowMinimized && WindowState == FormWindowState.Minimized) + else if (!core.WindowMinimized && WindowState == FormWindowState.Minimized) WindowState = FormWindowState.Normal; })); } void PropChangeBorder(bool enabled) { - mp.Border = enabled; + core.Border = enabled; BeginInvoke(new Action(() => { if (!IsFullscreen) { - if (mp.Border && FormBorderStyle == FormBorderStyle.None) + if (core.Border && FormBorderStyle == FormBorderStyle.None) FormBorderStyle = FormBorderStyle.Sizable; - if (!mp.Border && FormBorderStyle == FormBorderStyle.Sizable) + if (!core.Border && FormBorderStyle == FormBorderStyle.Sizable) FormBorderStyle = FormBorderStyle.None; } })); @@ -694,7 +697,7 @@ namespace mpvnet void PropChangePause(bool enabled) { - if (Taskbar != null && mp.TaskbarProgress) + if (Taskbar != null && core.TaskbarProgress) { if (enabled) Taskbar.SetState(TaskbarStates.Paused); @@ -707,8 +710,8 @@ namespace mpvnet { base.OnLoad(e); - if (mp.GPUAPI != "vulkan") - mp.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold); + if (core.GPUAPI != "vulkan") + core.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold); LastCycleFullscreen = Environment.TickCount; SetFormPosAndSize(); @@ -718,8 +721,8 @@ namespace mpvnet { base.OnShown(e); - if (mp.GPUAPI == "vulkan") - mp.ProcessCommandLine(false); + if (core.GPUAPI == "vulkan") + core.ProcessCommandLine(false); ToolStripRendererEx.ForegroundColor = Theme.Current.GetWinFormsColor("menu-foreground"); ToolStripRendererEx.BackgroundColor = Theme.Current.GetWinFormsColor("menu-background"); @@ -733,7 +736,7 @@ namespace mpvnet System.Windows.Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown; Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y); UpdateCheck.DailyCheck(); - mp.LoadScripts(); + core.LoadScripts(); Task.Run(() => App.Extension = new Extension()); ShownTickCount = Environment.TickCount; } @@ -749,8 +752,8 @@ namespace mpvnet { base.OnResize(e); - if (mp.IsLogoVisible) - mp.ShowLogo(); + if (core.IsLogoVisible) + core.ShowLogo(); if (FormBorderStyle != FormBorderStyle.None) { @@ -764,16 +767,16 @@ namespace mpvnet { if (WindowState == FormWindowState.Minimized) { - mp.set_property_string("window-minimized", "yes"); + core.set_property_string("window-minimized", "yes"); } else if (WindowState == FormWindowState.Normal) { - mp.set_property_string("window-maximized", "no"); - mp.set_property_string("window-minimized", "no"); + core.set_property_string("window-maximized", "no"); + core.set_property_string("window-minimized", "no"); } else if (WindowState == FormWindowState.Maximized) { - mp.set_property_string("window-maximized", "yes"); + core.set_property_string("window-maximized", "yes"); } } } @@ -784,10 +787,10 @@ namespace mpvnet SaveWindowProperties(); RegistryHelp.SetValue(App.RegPath, "Recent", RecentFiles.ToArray()); - if (mp.IsQuitNeeded) - mp.commandv("quit"); + if (core.IsQuitNeeded) + core.commandv("quit"); - if (!mp.ShutdownAutoResetEvent.WaitOne(10000)) + if (!core.ShutdownAutoResetEvent.WaitOne(10000)) Msg.ShowError("Shutdown thread failed to complete within 10 seconds."); try { // PowerShell 5.1 might not be available @@ -809,7 +812,7 @@ namespace mpvnet } if (Width - e.Location.X < 10 && e.Location.Y < 10) - mp.commandv("quit"); + core.commandv("quit"); } protected override void OnDragEnter(DragEventArgs e) @@ -825,10 +828,10 @@ namespace mpvnet base.OnDragDrop(e); if (e.Data.GetDataPresent(DataFormats.FileDrop)) - mp.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control)); + core.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control)); if (e.Data.GetDataPresent(DataFormats.Text)) - mp.LoadFiles(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control)); + core.LoadFiles(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control)); } protected override void OnLostFocus(EventArgs e) @@ -839,8 +842,10 @@ namespace mpvnet protected override void OnKeyDown(KeyEventArgs e) { - e.SuppressKeyPress = true; // prevent beep using alt key + if (Control.ModifierKeys == Keys.Alt) + e.SuppressKeyPress = true; // prevent beep using alt key + base.OnKeyDown(e); } } -} \ No newline at end of file +} diff --git a/mpv.net/mpv.net.csproj b/mpv.net/mpv.net.csproj index 5d117a7..2cc129a 100644 --- a/mpv.net/mpv.net.csproj +++ b/mpv.net/mpv.net.csproj @@ -76,29 +76,6 @@ Auto - - False - IronPython\IKVM.Reflection.dll - - - False - IronPython\IronPython.dll - - - False - IronPython\IronPython.Modules.dll - - - IronPython\IronPythonAddon.dll - - - False - IronPython\Microsoft.Dynamic.dll - - - False - IronPython\Microsoft.Scripting.dll - @@ -156,7 +133,7 @@ - + SearchTextBoxUserControl.xaml @@ -179,7 +156,6 @@ True Resources.resx - Form @@ -188,8 +164,8 @@ MainForm.cs - - + + diff --git a/mpv.net/mpv/mp.cs b/mpv.net/mpv/Core.cs similarity index 57% rename from mpv.net/mpv/mp.cs rename to mpv.net/mpv/Core.cs index c62b44f..f75defc 100644 --- a/mpv.net/mpv/mp.cs +++ b/mpv.net/mpv/Core.cs @@ -7,97 +7,110 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Linq; -using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; -using ScriptHost; - -using WinForms = System.Windows.Forms; - using static libmpv; using static WinAPI; using static NewLine; namespace mpvnet { - public delegate void MpvBoolPropChangeHandler(string propName, bool value); - - public class mp + public class Core { - public static event Action VideoSizeChanged; - // Lua/JS event libmpv event + public static Core core { get; } = new Core(); - // MPV_EVENT_NONE - public static event Action LogMessage; // log-message MPV_EVENT_LOG_MESSAGE - public static event Action Shutdown; // shutdown MPV_EVENT_SHUTDOWN - public static event Action GetPropertyReply; // get-property-reply MPV_EVENT_GET_PROPERTY_REPLY - public static event Action SetPropertyReply; // set-property-reply MPV_EVENT_SET_PROPERTY_REPLY - public static event Action CommandReply; // command-reply MPV_EVENT_COMMAND_REPLY - public static event Action StartFile; // start-file MPV_EVENT_START_FILE - public static event Action EndFile; // end-file MPV_EVENT_END_FILE - public static event Action FileLoaded; // file-loaded MPV_EVENT_FILE_LOADED - public static event Action TracksChanged; // MPV_EVENT_TRACKS_CHANGED - public static event Action TrackSwitched; // MPV_EVENT_TRACK_SWITCHED - public static event Action Idle; // idle MPV_EVENT_IDLE - public static event Action Pause; // MPV_EVENT_PAUSE - public static event Action Unpause; // MPV_EVENT_UNPAUSE - public static event Action ScriptInputDispatch; // MPV_EVENT_SCRIPT_INPUT_DISPATCH - public static event Action ClientMessage; // client-message MPV_EVENT_CLIENT_MESSAGE - public static event Action VideoReconfig; // video-reconfig MPV_EVENT_VIDEO_RECONFIG - public static event Action AudioReconfig; // audio-reconfig MPV_EVENT_AUDIO_RECONFIG - public static event Action MetadataUpdate; // MPV_EVENT_METADATA_UPDATE - public static event Action Seek; // seek MPV_EVENT_SEEK - public static event Action PlaybackRestart; // playback-restart MPV_EVENT_PLAYBACK_RESTART - // MPV_EVENT_PROPERTY_CHANGE - public static event Action ChapterChange; // MPV_EVENT_CHAPTER_CHANGE - public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW - public static event Action Hook; // MPV_EVENT_HOOK + public event Action LogMessageAsync; // log-message MPV_EVENT_LOG_MESSAGE + public event Action EndFileAsync; // end-file MPV_EVENT_END_FILE + public event Action ClientMessageAsync; // client-message MPV_EVENT_CLIENT_MESSAGE + public event Action GetPropertyReplyAsync; // get-property-reply MPV_EVENT_GET_PROPERTY_REPLY + public event Action SetPropertyReplyAsync; // set-property-reply MPV_EVENT_SET_PROPERTY_REPLY + public event Action CommandReplyAsync; // command-reply MPV_EVENT_COMMAND_REPLY + public event Action StartFileAsync; // start-file MPV_EVENT_START_FILE + public event Action FileLoadedAsync; // file-loaded MPV_EVENT_FILE_LOADED + public event Action TracksChangedAsync; // MPV_EVENT_TRACKS_CHANGED + public event Action TrackSwitchedAsync; // MPV_EVENT_TRACK_SWITCHED + public event Action IdleAsync; // idle MPV_EVENT_IDLE + public event Action PauseAsync; // MPV_EVENT_PAUSE + public event Action UnpauseAsync; // MPV_EVENT_UNPAUSE + public event Action ScriptInputDispatchAsync; // MPV_EVENT_SCRIPT_INPUT_DISPATCH + public event Action VideoReconfigAsync; // video-reconfig MPV_EVENT_VIDEO_RECONFIG + public event Action AudioReconfigAsync; // audio-reconfig MPV_EVENT_AUDIO_RECONFIG + public event Action MetadataUpdateAsync; // MPV_EVENT_METADATA_UPDATE + public event Action SeekAsync; // seek MPV_EVENT_SEEK + public event Action PlaybackRestartAsync; // playback-restart MPV_EVENT_PLAYBACK_RESTART + public event Action ChapterChangeAsync; // MPV_EVENT_CHAPTER_CHANGE - public static event Action Initialized; + public event ActionLogMessage; // log-message MPV_EVENT_LOG_MESSAGE + public event Action EndFile; // end-file MPV_EVENT_END_FILE + public event Action ClientMessage; // client-message MPV_EVENT_CLIENT_MESSAGE + public event Action Shutdown; // shutdown MPV_EVENT_SHUTDOWN + public event Action GetPropertyReply; // get-property-reply MPV_EVENT_GET_PROPERTY_REPLY + public event Action SetPropertyReply; // set-property-reply MPV_EVENT_SET_PROPERTY_REPLY + public event Action CommandReply; // command-reply MPV_EVENT_COMMAND_REPLY + public event Action StartFile; // start-file MPV_EVENT_START_FILE + public event Action FileLoaded; // file-loaded MPV_EVENT_FILE_LOADED + public event Action TracksChanged; // MPV_EVENT_TRACKS_CHANGED + public event Action TrackSwitched; // MPV_EVENT_TRACK_SWITCHED + public event Action Idle; // idle MPV_EVENT_IDLE + public event Action Pause; // MPV_EVENT_PAUSE + public event Action Unpause; // MPV_EVENT_UNPAUSE + public event Action ScriptInputDispatch; // MPV_EVENT_SCRIPT_INPUT_DISPATCH + public event Action VideoReconfig; // video-reconfig MPV_EVENT_VIDEO_RECONFIG + public event Action AudioReconfig; // audio-reconfig MPV_EVENT_AUDIO_RECONFIG + public event Action MetadataUpdate; // MPV_EVENT_METADATA_UPDATE + public event Action Seek; // seek MPV_EVENT_SEEK + public event Action PlaybackRestart; // playback-restart MPV_EVENT_PLAYBACK_RESTART + public event Action ChapterChange; // MPV_EVENT_CHAPTER_CHANGE - public static List> PropChangeActions { get; set; } = new List>(); - public static List>> BoolPropChangeActions { get; set; } = new List>>(); - public static List>> IntPropChangeActions { get; set; } = new List>>(); - public static List>> DoublePropChangeActions { get; set; } = new List>>(); - public static List>> StringPropChangeActions { get; set; } = new List>>(); + public event Action Initialized; + public event Action InitializedAsync; + + public event Action VideoSizeChanged; + public event Action VideoSizeChangedAsync; + + public Dictionary> PropChangeActions { get; set; } = new Dictionary>(); + public Dictionary>> IntPropChangeActions { get; set; } = new Dictionary>>(); + public Dictionary>> BoolPropChangeActions { get; set; } = new Dictionary>>(); + public Dictionary>> DoublePropChangeActions { get; set; } = new Dictionary>>(); + public Dictionary>> StringPropChangeActions { get; set; } = new Dictionary>>(); - public static List MediaTracks { get; set; } = new List(); - public static List> Chapters { get; set; } = new List>(); - public static IntPtr Handle { get; set; } - public static IntPtr WindowHandle { get; set; } - public static List PythonScripts { get; set; } = new List(); - public static Size VideoSize { get; set; } - public static TimeSpan Duration; - public static AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false); - public static AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false); + public List MediaTracks { get; set; } = new List(); + public List> Chapters { get; set; } = 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); - public static string InputConfPath { get => ConfigFolder + "input.conf"; } - public static string ConfPath { get => ConfigFolder + "mpv.conf"; } - public static string Sid { get; set; } = ""; - public static string Aid { get; set; } = ""; - public static string Vid { get; set; } = ""; - public static string GPUAPI { get; set; } = "auto"; + public string InputConfPath { get => ConfigFolder + "input.conf"; } + public string ConfPath { get => ConfigFolder + "mpv.conf"; } + public string Sid { get; set; } = ""; + public string Aid { get; set; } = ""; + public string Vid { get; set; } = ""; + public string GPUAPI { get; set; } = "auto"; - public static bool WasInitialSizeSet; - public static bool Border { get; set; } = true; - public static bool Fullscreen { get; set; } - public static bool IsLogoVisible { set; get; } - public static bool IsQuitNeeded { set; get; } = true; - public static bool TaskbarProgress { get; set; } = true; - public static bool WindowMaximized { get; set; } - public static bool WindowMinimized { get; set; } + public bool WasInitialSizeSet; + public bool Border { get; set; } = true; + public bool Fullscreen { get; set; } + public bool IsLogoVisible { set; get; } + public bool IsQuitNeeded { set; get; } = true; + public bool TaskbarProgress { get; set; } = true; + public bool WindowMaximized { get; set; } + public bool WindowMinimized { get; set; } - public static int Screen { get; set; } = -1; - public static int Edition { get; set; } + public int Screen { get; set; } = -1; + public int Edition { get; set; } + public int PropertyChangedID; - public static float Autofit { get; set; } = 0.6f; - public static float AutofitSmaller { get; set; } = 0.3f; - public static float AutofitLarger { get; set; } = 0.8f; + public float Autofit { get; set; } = 0.6f; + public float AutofitSmaller { get; set; } = 0.3f; + public float AutofitLarger { get; set; } = 0.8f; - public static void Init() + public void Init() { Handle = mpv_create(); @@ -105,6 +118,7 @@ namespace mpvnet throw new Exception("error mpv_create"); mpv_request_log_messages(Handle, "info"); + Task.Run(() => EventLoop()); if (App.IsStartedFromTerminal) @@ -128,10 +142,12 @@ namespace mpvnet throw new Exception("mpv_initialize error\n\n" + GetError(err)); Initialized?.Invoke(); + InvokeAsync(InitializedAsync); + LoadMpvScripts(); } - public static void ProcessProperty(string name, string value) + public void ProcessProperty(string name, string value) { if (name.Any(char.IsUpper)) Msg.ShowError("Uppercase char detected: " + name, @@ -165,9 +181,9 @@ namespace mpvnet AutofitLarger = 1; } - static string _ConfigFolder; + string _ConfigFolder; - public static string ConfigFolder { + public string ConfigFolder { get { if (_ConfigFolder == null) { @@ -199,12 +215,12 @@ namespace mpvnet if (_ConfigFolder == "custom") { - using (var d = new WinForms.FolderBrowserDialog()) + using (var dialog = new FolderBrowserDialog()) { - d.Description = "Choose a folder."; + dialog.Description = "Choose a folder."; - if (d.ShowDialog() == WinForms.DialogResult.OK) - _ConfigFolder = d.SelectedPath + @"\"; + if (dialog.ShowDialog() == DialogResult.OK) + _ConfigFolder = dialog.SelectedPath + @"\"; else _ConfigFolder = appdataFolder; } @@ -244,9 +260,9 @@ namespace mpvnet } } - static Dictionary _Conf; + Dictionary _Conf; - public static Dictionary Conf { + public Dictionary Conf { get { if (_Conf == null) { @@ -265,7 +281,7 @@ namespace mpvnet } } - public static void LoadMpvScripts() + public void LoadMpvScripts() { if (Directory.Exists(Folder.Startup + "Scripts")) foreach (string path in Directory.GetFiles(Folder.Startup + "Scripts")) @@ -273,9 +289,9 @@ namespace mpvnet commandv("load-script", $"{path}"); } - public static string[] KnownScripts { get; } = { "show-playlist.js"}; + public string[] KnownScripts { get; } = { "show-playlist.js"}; - public static void LoadScripts() + public void LoadScripts() { if (Directory.Exists(Folder.Startup + "Scripts")) { @@ -283,32 +299,68 @@ namespace mpvnet { if (KnownScripts.Contains(Path.GetFileName(file))) { - if (file.EndsWith(".py")) - App.RunAction(() => PythonScripts.Add(new PythonScript(file))); - else if (file.EndsWith(".ps1")) + if (file.EndsWith(".ps1")) App.RunAction(() => InvokePowerShellScript(file)); } else - ConsoleHelp.WriteError("Failed to load script:" + BR + file + BR + - "Only scripts that ship with mpv.net are allowed in \\scripts." + BR + - "Never copy or install a new mpv.net version on top of a old mpv.net version."); + ConsoleHelp.WriteError("Failed to load script:\n" + file + + "\nOnly scripts that ship with mpv.net are allowed in \\scripts." + + "\nNever copy or install a new mpv.net version on top of a old mpv.net version."); } } - - if (Directory.Exists(ConfigFolder + "scripts-py")) - foreach (string scriptPath in Directory.GetFiles(ConfigFolder + "scripts-py", "*.py")) - App.RunAction(() => PythonScripts.Add(new PythonScript(scriptPath))); if (Directory.Exists(ConfigFolder + "scripts-ps")) foreach (string file in Directory.GetFiles(ConfigFolder + "scripts-ps", "*.ps1")) App.RunAction(() => InvokePowerShellScript(file)); } - public static void InvokePowerShellScript(string file) + public void InvokePowerShellScript(string file) { PowerShell ps = new PowerShell(); - ps.Scripts.Add("Using namespace mpvnet" + BR + - "[Reflection.Assembly]::LoadWithPartialName('mpvnet')" + BR); + ps.Variables.Add(new KeyValuePair("core", core)); + ps.Variables.Add(new KeyValuePair("window", MainForm.Instance)); + ps.Scripts.Add("Using namespace mpvnet; [Reflection.Assembly]::LoadWithPartialName('mpvnet')" + BR); + + string eventCode = @" + $eventJob = Register-ObjectEvent -InputObject $mp -EventName Event -Action { + foreach ($pair in $mp.EventHandlers) + { + if ($pair.Key -eq $args[0]) + { + if ($args.Length -gt 1) + { + $args2 = $args[1] + } + + Invoke-Command -ScriptBlock $pair.Value -ArgumentList $args2 + } + } + } + + $mp.RedirectStreams($eventJob) + "; + + string propertyChangedCode = @" + $propertyChangedJob = Register-ObjectEvent -InputObject $mp -EventName PropertyChanged -Action { + foreach ($pair in $mp.PropChangedHandlers) + { + if ($pair.Key -eq $args[0]) + { + if ($args.Length -gt 1) + { + $args2 = $args[1] + } + + Invoke-Command -ScriptBlock $pair.Value -ArgumentList $args2 + } + } + } + + $mp.RedirectStreams($propertyChangedJob) + "; + + ps.Scripts.Add(eventCode); + ps.Scripts.Add(propertyChangedCode); ps.Scripts.Add(File.ReadAllText(file)); ps.Module = Path.GetFileName(file); ps.Print = true; @@ -319,7 +371,7 @@ namespace mpvnet ps.Invoke(); } - public static void EventLoop() + public void EventLoop() { while (true) { @@ -344,25 +396,42 @@ namespace mpvnet case mpv_event_id.MPV_EVENT_LOG_MESSAGE: { var data = (mpv_event_log_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_log_message)); - LogMessage?.Invoke(data.log_level, $"[{data.prefix}] {data.text}"); + mpv_log_level level = data.log_level; + string msg = $"[{ConvertFromUtf8(data.prefix)}] {ConvertFromUtf8(data.text)}"; + InvokeAsync(LogMessageAsync, level, msg); + LogMessage?.Invoke(level, msg); } break; - case mpv_event_id.MPV_EVENT_GET_PROPERTY_REPLY: - GetPropertyReply?.Invoke(); + case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE: + { + var data = (mpv_event_client_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_client_message)); + string[] args = ConvertFromUtf8Strings(data.args, data.num_args); + + if (args.Length > 1 && args[0] == "mpv.net") + App.RunAction(() => Commands.Execute(args[1], args.Skip(2).ToArray())); + + InvokeAsync(ClientMessageAsync, args); + ClientMessage?.Invoke(args); + } break; - case mpv_event_id.MPV_EVENT_SET_PROPERTY_REPLY: - SetPropertyReply?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_COMMAND_REPLY: - CommandReply?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_START_FILE: - StartFile?.Invoke(); + case mpv_event_id.MPV_EVENT_VIDEO_RECONFIG: + { + Size size = new Size(get_property_int("dwidth"), get_property_int("dheight")); + + if (size.Width != 0 && size.Height != 0 && VideoSize != size) + { + VideoSize = size; + InvokeEvent(VideoSizeChanged, VideoSizeChangedAsync); + } + + InvokeEvent(VideoReconfig, VideoReconfigAsync); + } break; case mpv_event_id.MPV_EVENT_END_FILE: { var data = (mpv_event_end_file)Marshal.PtrToStructure(evt.data, typeof(mpv_event_end_file)); - EndFileEventMode reason = (EndFileEventMode)data.reason; + var reason = (mpv_end_file_reason)data.reason; + InvokeAsync(EndFileAsync, reason); EndFile?.Invoke(reason); } break; @@ -372,8 +441,8 @@ namespace mpvnet Duration = TimeSpan.FromSeconds(get_property_number("duration")); if (App.StartSize == "video") - mp.WasInitialSizeSet = false; - + core.WasInitialSizeSet = false; + Size size = new Size(get_property_int("width"), get_property_int("height")); if (size.Width == 0 || size.Height == 0) @@ -382,71 +451,25 @@ namespace mpvnet if (VideoSize != size) { VideoSize = size; - VideoSizeChanged?.Invoke(); + InvokeEvent(VideoSizeChanged, VideoSizeChangedAsync); } VideoSizeAutoResetEvent.Set(); + Task.Run(new Action(() => ReadMetaData())); - string path = mp.get_property_string("path"); - if (path.Contains("://")) - path = mp.get_property_string("media-title"); + Task.Run(new Action(() => { + string path = core.get_property_string("path"); - WriteHistory(path); - FileLoaded?.Invoke(); + if (path.Contains("://")) + path = core.get_property_string("media-title"); + + WriteHistory(path); + })); + + InvokeEvent(FileLoaded, FileLoadedAsync); } break; - case mpv_event_id.MPV_EVENT_TRACKS_CHANGED: - TracksChanged?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_TRACK_SWITCHED: - TrackSwitched?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_IDLE: - Idle?.Invoke(); - ShowLogo(); - break; - case mpv_event_id.MPV_EVENT_PAUSE: - Pause?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_UNPAUSE: - Unpause?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_SCRIPT_INPUT_DISPATCH: - ScriptInputDispatch?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE: - { - var data = (mpv_event_client_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_client_message)); - string[] args = ConvertFromUtf8Strings(data.args, data.num_args); - - if (args.Length > 1 && args[0] == "mpv.net") - Command.Execute(args[1], args.Skip(2).ToArray()); - else if (args.Length > 0) - ClientMessage?.Invoke(args); - } - break; - case mpv_event_id.MPV_EVENT_VIDEO_RECONFIG: - { - VideoReconfig?.Invoke(); - Size size = new Size(get_property_int("dwidth"), get_property_int("dheight")); - - if (size.Width != 0 && size.Height != 0 && VideoSize != size) - { - VideoSize = size; - VideoSizeChanged?.Invoke(); - } - } - break; - case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG: - AudioReconfig?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_METADATA_UPDATE: - MetadataUpdate?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_SEEK: - Seek?.Invoke(); - break; case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE: { var data = (mpv_event_property)Marshal.PtrToStructure(evt.data, typeof(mpv_event_property)); @@ -455,106 +478,183 @@ namespace mpvnet if (data.format == mpv_format.MPV_FORMAT_FLAG) { lock (BoolPropChangeActions) - foreach (var i in BoolPropChangeActions) - if (i.Key== data.name) - i.Value.Invoke(Marshal.PtrToStructure(data.data) == 1); + foreach (var pair in BoolPropChangeActions) + if (pair.Key == data.name) + { + bool value = Marshal.PtrToStructure(data.data) == 1; + + foreach (var action in pair.Value) + action.Invoke(value); + } } else if (data.format == mpv_format.MPV_FORMAT_STRING) { lock (StringPropChangeActions) - foreach (var i in StringPropChangeActions) - if (i.Key == data.name) - i.Value.Invoke(ConvertFromUtf8(Marshal.PtrToStructure(data.data))); + foreach (var pair in StringPropChangeActions) + if (pair.Key == data.name) + { + string value = ConvertFromUtf8(Marshal.PtrToStructure(data.data)); + + foreach (var action in pair.Value) + action.Invoke(value); + } } - else if(data.format == mpv_format.MPV_FORMAT_INT64) + else if (data.format == mpv_format.MPV_FORMAT_INT64) { lock (IntPropChangeActions) - foreach (var i in IntPropChangeActions) - if (i.Key == data.name) - i.Value.Invoke(Marshal.PtrToStructure(data.data)); + foreach (var pair in IntPropChangeActions) + if (pair.Key == data.name) + { + int value = Marshal.PtrToStructure(data.data); + + foreach (var action in pair.Value) + action.Invoke(value); + } } else if (data.format == mpv_format.MPV_FORMAT_NONE) { lock (PropChangeActions) - foreach (var i in PropChangeActions) - if (i.Key == data.name) - i.Value.Invoke(); + foreach (var pair in PropChangeActions) + if (pair.Key == data.name) + foreach (var action in pair.Value) + action.Invoke(); } else if (data.format == mpv_format.MPV_FORMAT_DOUBLE) { lock (DoublePropChangeActions) - foreach (var i in DoublePropChangeActions) - if (i.Key == data.name) - i.Value.Invoke(Marshal.PtrToStructure(data.data)); + foreach (var pair in DoublePropChangeActions) + if (pair.Key == data.name) + { + double value = Marshal.PtrToStructure(data.data); + + foreach (var action in pair.Value) + action.Invoke(value); + } } } break; + case mpv_event_id.MPV_EVENT_GET_PROPERTY_REPLY: + InvokeEvent(GetPropertyReply, GetPropertyReplyAsync); + break; + case mpv_event_id.MPV_EVENT_SET_PROPERTY_REPLY: + InvokeEvent(SetPropertyReply, SetPropertyReplyAsync); + break; + case mpv_event_id.MPV_EVENT_COMMAND_REPLY: + InvokeEvent(CommandReply, CommandReplyAsync); + break; + case mpv_event_id.MPV_EVENT_START_FILE: + InvokeEvent(StartFile, StartFileAsync); + break; + case mpv_event_id.MPV_EVENT_TRACKS_CHANGED: + InvokeEvent(TracksChanged, TracksChangedAsync); + break; + case mpv_event_id.MPV_EVENT_TRACK_SWITCHED: + InvokeEvent(TrackSwitched, TrackSwitchedAsync); + break; + case mpv_event_id.MPV_EVENT_IDLE: + ShowLogo(); + InvokeEvent(Idle, IdleAsync); + break; + case mpv_event_id.MPV_EVENT_PAUSE: + InvokeEvent(Pause, PauseAsync); + break; + case mpv_event_id.MPV_EVENT_UNPAUSE: + InvokeEvent(Unpause, UnpauseAsync); + break; + case mpv_event_id.MPV_EVENT_SCRIPT_INPUT_DISPATCH: + InvokeEvent(ScriptInputDispatch, ScriptInputDispatchAsync); + break; + case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG: + InvokeEvent(AudioReconfig, AudioReconfigAsync); + break; + case mpv_event_id.MPV_EVENT_METADATA_UPDATE: + InvokeEvent(MetadataUpdate, MetadataUpdateAsync); + break; + case mpv_event_id.MPV_EVENT_SEEK: + InvokeEvent(Seek, SeekAsync); + break; case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART: - PlaybackRestart?.Invoke(); + InvokeEvent(PlaybackRestart, PlaybackRestartAsync); break; case mpv_event_id.MPV_EVENT_CHAPTER_CHANGE: - ChapterChange?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_QUEUE_OVERFLOW: - QueueOverflow?.Invoke(); - break; - case mpv_event_id.MPV_EVENT_HOOK: - Hook?.Invoke(); + InvokeEvent(ChapterChange, ChapterChangeAsync); break; } } catch (Exception ex) { - Msg.ShowException(ex); + App.ShowException(ex); } } } - static void HideLogo() + void InvokeEvent(Action action, Action asyncAction) + { + InvokeAsync(asyncAction); + action?.Invoke(); + } + + void InvokeAsync(Action action) + { + if (action != null) + { + foreach (Action a in action.GetInvocationList()) + { + var a2 = a; + App.RunAction(a2); + } + } + } + + void InvokeAsync(Action action, T t) + { + if (action != null) + { + foreach (Action a in action.GetInvocationList()) + { + var a2 = a; + Task.Run(() => { + try + { + a2.Invoke(t); + } + catch (Exception e) + { + App.ShowException(e); + } + }); + } + } + } + + void InvokeAsync(Action action, T1 t1, T2 t2) + { + if (action != null) + { + foreach (Action a in action.GetInvocationList()) + { + var a2 = a; + Task.Run(() => { + try + { + a2.Invoke(t1, t2); + } + catch (Exception e) + { + App.ShowException(e); + } + }); + } + } + } + + void HideLogo() { command("overlay-remove 0"); IsLogoVisible = false; } - - static List PythonEventObjects = new List(); - - public static void register_event(string name, IronPython.Runtime.PythonFunction pyFunc) - { - foreach (var eventInfo in typeof(mp).GetEvents()) - { - if (eventInfo.Name.ToLower() == name.Replace("-", "")) - { - PythonEventObject eventObject = new PythonEventObject(); - PythonEventObjects.Add(eventObject); - eventObject.PythonFunction = pyFunc; - MethodInfo mi; - - if (eventInfo.EventHandlerType == typeof(Action)) - mi = eventObject.GetType().GetMethod(nameof(PythonEventObject.Invoke)); - else if (eventInfo.EventHandlerType == typeof(Action)) - mi = eventObject.GetType().GetMethod(nameof(PythonEventObject.InvokeEndFileEventMode)); - else if (eventInfo.EventHandlerType == typeof(Action)) - mi = eventObject.GetType().GetMethod(nameof(PythonEventObject.InvokeStrings)); - else - throw new Exception(); - - eventObject.EventInfo = eventInfo; - Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, eventObject, mi); - eventObject.Delegate = handler; - eventInfo.AddEventHandler(eventObject, handler); - break; - } - } - } - - public static void unregister_event(IronPython.Runtime.PythonFunction pyFunc) - { - foreach (var eventObjects in PythonEventObjects) - if (eventObjects.PythonFunction == pyFunc) - eventObjects.EventInfo.RemoveEventHandler(eventObjects, eventObjects.Delegate); - } - - public static void commandv(params string[] args) + + public void commandv(params string[] args) { IntPtr mainPtr = AllocateUtf8ArrayWithSentinel(args, out IntPtr[] byteArrayPointers); mpv_error err = mpv_command(Handle, mainPtr); @@ -568,7 +668,7 @@ namespace mpvnet HandleError(err, true, "error executing command:", string.Join("\n", args)); } - public static void command(string command, bool throwException = false) + public void command(string command, bool throwException = false) { mpv_error err = mpv_command_string(Handle, command); @@ -576,16 +676,18 @@ namespace mpvnet HandleError(err, throwException, "error executing command:", command); } - public static void set_property_int(string name, int value, bool throwException = false) + public bool get_property_bool(string name, bool throwException = false) { - Int64 val = value; - mpv_error err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_INT64, ref val); + mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), + mpv_format.MPV_FORMAT_FLAG, out IntPtr lpBuffer); if (err < 0) - HandleError(err, throwException, $"error setting property: {name} = {value}"); + HandleError(err, throwException, $"error getting property: {name}"); + + return lpBuffer.ToInt32() != 0; } - public static void set_property_bool(string name, bool value, bool throwException = false) + public void set_property_bool(string name, bool value, bool throwException = false) { Int64 val = (value) ? 1 : 0; mpv_error err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_FLAG, ref val); @@ -594,16 +696,47 @@ namespace mpvnet HandleError(err, throwException, $"error setting property: {name} = {value}"); } - public static void set_property_string(string name, string value, bool throwException = false) + public int get_property_int(string name, bool throwException = false) { - byte[] bytes = GetUtf8Bytes(value); - mpv_error err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, ref bytes); + mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), + mpv_format.MPV_FORMAT_INT64, out IntPtr lpBuffer); if (err < 0) - HandleError(err, throwException, $"error setting property: {name} = " + value); + HandleError(err, throwException, $"error getting property: {name}"); + + return lpBuffer.ToInt32(); } - public static string get_property_string(string name, bool throwException = false) + public void set_property_int(string name, int value, bool throwException = false) + { + Int64 val = value; + mpv_error err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_INT64, ref val); + + if (err < 0) + HandleError(err, throwException, $"error setting property: {name} = {value}"); + } + + public double get_property_number(string name, bool throwException = false) + { + mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), + mpv_format.MPV_FORMAT_DOUBLE, out double value); + + if (err < 0) + HandleError(err, throwException, $"error getting property: {name}"); + + return value; + } + + public void set_property_number(string name, double value, bool throwException = false) + { + double val = value; + mpv_error err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_DOUBLE, ref val); + + if (err < 0) + HandleError(err, throwException, $"error setting property: {name} = {value}"); + } + + public string get_property_string(string name, bool throwException = false) { mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, out IntPtr lpBuffer); @@ -619,112 +752,123 @@ namespace mpvnet return ""; } - public static int get_property_int(string name, bool throwException = false) + public void set_property_string(string name, string value, bool throwException = false) { - mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), - mpv_format.MPV_FORMAT_INT64, out IntPtr lpBuffer); + byte[] bytes = GetUtf8Bytes(value); + mpv_error err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, ref bytes); if (err < 0) - HandleError(err, throwException, $"error getting property: {name}"); - - return lpBuffer.ToInt32(); + HandleError(err, throwException, $"error setting property: {name} = " + value); } - public static bool get_property_bool(string name, bool throwException = false) + public void observe_property_int(string name, Action action) { - mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), - mpv_format.MPV_FORMAT_FLAG, out IntPtr lpBuffer); + lock (IntPropChangeActions) + { + if (!IntPropChangeActions.ContainsKey(name)) + { + mpv_error err = mpv_observe_property(Handle, 0, name, mpv_format.MPV_FORMAT_INT64); - if (err < 0) - HandleError(err, throwException, $"error getting property: {name}"); + if (err < 0) + HandleError(err, true, $"error observing property: {name}"); + else + IntPropChangeActions[name] = new List>(); + } - return lpBuffer.ToInt32() != 0; + if (IntPropChangeActions.ContainsKey(name)) + IntPropChangeActions[name].Add(action); + } } - public static double get_property_number(string name, bool throwException = false) + public void observe_property_double(string name, Action action) { - mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), - mpv_format.MPV_FORMAT_DOUBLE, out double value); + lock (DoublePropChangeActions) + { + if (!DoublePropChangeActions.ContainsKey(name)) + { + mpv_error err = mpv_observe_property(Handle, 0, name, mpv_format.MPV_FORMAT_DOUBLE); - if (err < 0) - HandleError(err, throwException, $"error getting property: {name}"); + if (err < 0) + HandleError(err, true, $"error observing property: {name}"); + else + DoublePropChangeActions[name] = new List>(); + } - return value; + if (DoublePropChangeActions.ContainsKey(name)) + DoublePropChangeActions[name].Add(action); + } } - public static void observe_property_int(string name, Action action) + public void observe_property_bool(string name, Action action) { - mpv_error err = mpv_observe_property(Handle, (ulong)action.GetHashCode(), - name, mpv_format.MPV_FORMAT_INT64); + lock (BoolPropChangeActions) + { + if (!BoolPropChangeActions.ContainsKey(name)) + { + mpv_error err = mpv_observe_property(Handle, 0, name, mpv_format.MPV_FORMAT_FLAG); - if (err < 0) - HandleError(err, true, $"error observing property: {name}"); - else - lock (IntPropChangeActions) - IntPropChangeActions.Add(new KeyValuePair>(name, action)); + if (err < 0) + HandleError(err, true, $"error observing property: {name}"); + else + BoolPropChangeActions[name] = new List>(); + } + + if (BoolPropChangeActions.ContainsKey(name)) + BoolPropChangeActions[name].Add(action); + } } - public static void observe_property_double(string name, Action action) + public void observe_property_string(string name, Action action) { - mpv_error err = mpv_observe_property(Handle, (ulong)action.GetHashCode(), - name, mpv_format.MPV_FORMAT_DOUBLE); + lock (StringPropChangeActions) + { + if (!StringPropChangeActions.ContainsKey(name)) + { + mpv_error err = mpv_observe_property(Handle, 0, name, mpv_format.MPV_FORMAT_STRING); - if (err < 0) - HandleError(err, true, $"error observing property: {name}"); - else - lock (DoublePropChangeActions) - DoublePropChangeActions.Add(new KeyValuePair>(name, action)); + if (err < 0) + HandleError(err, true, $"error observing property: {name}"); + else + StringPropChangeActions[name] = new List>(); + } + + if (StringPropChangeActions.ContainsKey(name)) + StringPropChangeActions[name].Add(action); + } } - public static void observe_property_bool(string name, Action action) + public void observe_property(string name, Action action) { - mpv_error err = mpv_observe_property(Handle, (ulong)action.GetHashCode(), - name, mpv_format.MPV_FORMAT_FLAG); + lock (PropChangeActions) + { + if (!PropChangeActions.ContainsKey(name)) + { + mpv_error err = mpv_observe_property(Handle, 0, name, mpv_format.MPV_FORMAT_NONE); - if (err < 0) - HandleError(err, true, $"error observing property: {name}"); - else - lock (BoolPropChangeActions) - BoolPropChangeActions.Add(new KeyValuePair>(name, action)); + if (err < 0) + HandleError(err, true, $"error observing property: {name}"); + else + PropChangeActions[name] = new List(); + } + + if (PropChangeActions.ContainsKey(name)) + PropChangeActions[name].Add(action); + } } - public static void observe_property_string(string name, Action action) - { - mpv_error err = mpv_observe_property(Handle, (ulong)action.GetHashCode(), - name, mpv_format.MPV_FORMAT_STRING); - - if (err < 0) - HandleError(err, true, $"error observing property: {name}"); - else - lock (StringPropChangeActions) - StringPropChangeActions.Add(new KeyValuePair>(name, action)); - } - - public static void observe_property(string name, Action action) - { - mpv_error err = mpv_observe_property(Handle, (ulong)action.GetHashCode(), - name, mpv_format.MPV_FORMAT_NONE); - - if (err < 0) - HandleError(err, true, $"error observing property: {name}"); - else - lock (PropChangeActions) - PropChangeActions.Add(new KeyValuePair(name, action)); - } - - public static void HandleError(mpv_error err, bool throwException, params string[] messages) + public void HandleError(mpv_error err, bool throwException, params string[] messages) { if (throwException) { foreach (string msg in messages) - ConsoleHelp.WriteError(msg, "mpv.net"); + ConsoleHelp.WriteError(msg); - ConsoleHelp.WriteError(GetError(err), "mpv.net"); + ConsoleHelp.WriteError(GetError(err)); throw new Exception(string.Join(BR2, messages) + BR2 + GetError(err)); } } - public static void ProcessCommandLine(bool preInit) + public void ProcessCommandLine(bool preInit) { var args = Environment.GetCommandLineArgs().Skip(1); @@ -761,14 +905,14 @@ namespace mpvnet if (preInit && preInitProperties.Contains(left)) { - mp.ProcessProperty(left, right); + core.ProcessProperty(left, right); if (!App.ProcessProperty(left, right)) set_property_string(left, right, true); } else if (!preInit && !preInitProperties.Contains(left)) { - mp.ProcessProperty(left, right); + core.ProcessProperty(left, right); if (!App.ProcessProperty(left, right)) set_property_string(left, right, true); @@ -805,9 +949,9 @@ namespace mpvnet } } - public static DateTime LastLoad; + public DateTime LastLoad; - public static void LoadFiles(string[] files, bool loadFolder, bool append) + public void LoadFiles(string[] files, bool loadFolder, bool append) { if (files is null || files.Length == 0) return; @@ -839,7 +983,7 @@ namespace mpvnet Task.Run(() => LoadFolder()); } - public static void LoadFolder() + public void LoadFolder() { if (!App.AutoLoadFolder || Control.ModifierKeys.HasFlag(Keys.Shift)) return; @@ -868,10 +1012,10 @@ namespace mpvnet commandv("playlist-move", "0", (index + 1).ToString()); } - static string LastHistoryPath; - static DateTime LastHistoryStartDateTime; + string LastHistoryPath; + DateTime LastHistoryStartDateTime; - static void WriteHistory(string path) + void WriteHistory(string path) { if (!File.Exists(ConfigFolder + "history.txt")) return; @@ -886,32 +1030,36 @@ namespace mpvnet LastHistoryStartDateTime = DateTime.Now; } - public static void ShowLogo() + public void ShowLogo() { - if (MainForm.Instance is null) return; + if (MainForm.Instance is null) + return; + Rectangle cr = MainForm.Instance.ClientRectangle; int len = cr.Height / 5; - if (len == 0) return; - using (Bitmap b = new Bitmap(len, len)) + if (len == 0) + return; + + using (Bitmap bmp = new Bitmap(len, len)) { - using (Graphics g = Graphics.FromImage(b)) + using (Graphics gx = Graphics.FromImage(bmp)) { - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - g.Clear(Color.Black); + gx.InterpolationMode = InterpolationMode.HighQualityBicubic; + gx.Clear(Color.Black); Rectangle rect = new Rectangle(0, 0, len, len); - g.DrawImage(Properties.Resources.mpvnet, rect); - BitmapData bd = b.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb); + gx.DrawImage(Properties.Resources.mpvnet, rect); + BitmapData bd = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb); int x = Convert.ToInt32((cr.Width - len) / 2.0); int y = Convert.ToInt32(((cr.Height - len) / 2.0) * 0.9); commandv("overlay-add", "0", $"{x}", $"{y}", "&" + bd.Scan0.ToInt64().ToString(), "0", "bgra", bd.Width.ToString(), bd.Height.ToString(), bd.Stride.ToString()); - b.UnlockBits(bd); + bmp.UnlockBits(bd); IsLogoVisible = true; } } } - static void ReadMetaData() + void ReadMetaData() { lock (MediaTracks) { @@ -1012,14 +1160,4 @@ namespace mpvnet } } } - - public enum EndFileEventMode - { - Eof, - Stop, - Quit, - Error, - Redirect, - Unknown - } -} \ No newline at end of file +} diff --git a/mpv.net/mpv/libmpv.cs b/mpv.net/mpv/libmpv.cs index c53e413..53b41c7 100644 --- a/mpv.net/mpv/libmpv.cs +++ b/mpv.net/mpv/libmpv.cs @@ -44,6 +44,9 @@ public class libmpv [DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)] public static extern mpv_error mpv_set_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref Int64 data); + [DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern mpv_error mpv_set_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref double data); + [DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)] public static extern mpv_error mpv_observe_property(IntPtr mpvHandle, UInt64 reply_userdata, [MarshalAs(UnmanagedType.LPUTF8Str)] string name, mpv_format format); @@ -149,9 +152,9 @@ public class libmpv [StructLayout(LayoutKind.Sequential)] public struct mpv_event_log_message { - public string prefix; - public string level; - public string text; + public IntPtr prefix; + public IntPtr level; + public IntPtr text; public mpv_log_level log_level; } diff --git a/scripts/examples/dynamic-context-menu-items.cs b/scripts/c-sharp/dynamic-context-menu-items.cs similarity index 74% rename from scripts/examples/dynamic-context-menu-items.cs rename to scripts/c-sharp/dynamic-context-menu-items.cs index cd732a6..99eb420 100644 --- a/scripts/examples/dynamic-context-menu-items.cs +++ b/scripts/c-sharp/dynamic-context-menu-items.cs @@ -8,9 +8,11 @@ using System.Linq; class Script { MainForm MainForm; + Core core; public Script() { + core = Core.core; MainForm = mpvnet.MainForm.Instance; MainForm.ContextMenu.Opening += ContextMenu_Opening; } @@ -24,13 +26,13 @@ class Script return; menuItem.DropDownItems.Clear(); - var editionTracks = mp.MediaTracks.Where(track => track.Type == "e"); + var editionTracks = core.MediaTracks.Where(track => track.Type == "e"); foreach (MediaTrack track in editionTracks) { MenuItem mi = new MenuItem(track.Text); - mi.Action = () => { mp.commandv("set", "edition", track.ID.ToString()); }; - mi.Checked = mp.Edition == track.ID; + mi.Action = () => { core.commandv("set", "edition", track.ID.ToString()); }; + mi.Checked = core.Edition == track.ID; menuItem.DropDownItems.Add(mi); } } diff --git a/scripts/examples/key-binding.cs b/scripts/c-sharp/key-binding.cs similarity index 69% rename from scripts/examples/key-binding.cs rename to scripts/c-sharp/key-binding.cs index f9e476e..e9e718a 100644 --- a/scripts/examples/key-binding.cs +++ b/scripts/c-sharp/key-binding.cs @@ -11,9 +11,10 @@ class Script { string content = "ctrl+w script-message my-message-1 my-argument-1"; string sectionName = Assembly.GetExecutingAssembly().GetName().Name; - mp.commandv("define-section", sectionName, content, "force"); - mp.commandv("enable-section", sectionName); - mp.ClientMessage += ClientMessage; + Core core = Core.core; + core.commandv("define-section", sectionName, content, "force"); + core.commandv("enable-section", sectionName); + core.ClientMessage += ClientMessage; } void ClientMessage(string[] args) diff --git a/scripts/examples/observe-property-and-draw-text.cs b/scripts/c-sharp/observe-property-and-draw-text.cs similarity index 55% rename from scripts/examples/observe-property-and-draw-text.cs rename to scripts/c-sharp/observe-property-and-draw-text.cs index e7caec3..87383f8 100644 --- a/scripts/examples/observe-property-and-draw-text.cs +++ b/scripts/c-sharp/observe-property-and-draw-text.cs @@ -6,13 +6,16 @@ using mpvnet; class Script { + Core core; + public Script() { - mp.observe_property_bool("fullscreen", FullscreenChange); + core = Core.core; + core.observe_property_bool("fullscreen", FullscreenChange); } void FullscreenChange(bool value) { - mp.commandv("show-text", "fullscreen: " + value); + core.commandv("show-text", "fullscreen: " + value); } } diff --git a/scripts/examples/pause-when-minimize.cs b/scripts/c-sharp/pause-when-minimize.cs similarity index 75% rename from scripts/examples/pause-when-minimize.cs rename to scripts/c-sharp/pause-when-minimize.cs index b217944..175b5ab 100644 --- a/scripts/examples/pause-when-minimize.cs +++ b/scripts/c-sharp/pause-when-minimize.cs @@ -9,12 +9,14 @@ using mpvnet; class Script { MainForm Form; + Core core; bool WasPlaying; bool WasPaused; public Script() { + core = Core.core; Form = MainForm.Instance; Form.Resize += Form_Resize; } @@ -23,11 +25,11 @@ class Script { if (Form.WindowState == FormWindowState.Minimized) { - WasPlaying = !mp.get_property_bool("pause"); + WasPlaying = !core.get_property_bool("pause"); if (WasPlaying) { - mp.set_property_bool("pause", true, true); + core.set_property_bool("pause", true, true); WasPaused = true; } } @@ -35,7 +37,7 @@ class Script { if (WasPaused) { - mp.set_property_bool("pause", false, true); + core.set_property_bool("pause", false, true); WasPaused = false; } } diff --git a/scripts/examples/message-box.ps1 b/scripts/examples/message-box.ps1 deleted file mode 100644 index 66286f7..0000000 --- a/scripts/examples/message-box.ps1 +++ /dev/null @@ -1,4 +0,0 @@ - -// This script shows a message box using the Msg class of mpv.net. - -[Msg]::Show("Hello World") diff --git a/scripts/examples/open-file-dialog.ps1 b/scripts/examples/open-file-dialog.ps1 deleted file mode 100644 index a22e11a..0000000 --- a/scripts/examples/open-file-dialog.ps1 +++ /dev/null @@ -1,25 +0,0 @@ - -# Shows the Open File dialog to open a file without loading its folder into the playlist. - -# In input.conf add: script-message load-without-folder - -$job = Register-ObjectEvent -InputObject ([mpvnet.mp]) -EventName ClientMessage -Action { - - # exit if message does not equal 'load-without-folder' - if ($args.Length -ne 1 -or $args[0] -ne 'load-without-folder') - { - exit - } - - $dialog = New-Object Windows.Forms.OpenFileDialog - - if ($dialog.ShowDialog() -ne "OK") { - $dialog.Dispose() - exit - } - - [mp]::Load($dialog.FileNames, $false, $false); - $dialog.Dispose() -} - -$ScriptHost.RedirectEventJobStreams($job) diff --git a/scripts/examples/seek.ps1 b/scripts/examples/seek.ps1 deleted file mode 100644 index 290813b..0000000 --- a/scripts/examples/seek.ps1 +++ /dev/null @@ -1,8 +0,0 @@ - -# Display position in window title bar when seeking - -$job = Register-ObjectEvent -InputObject ([mpvnet.mp]) -EventName Seek -Action { - [MainForm]::Instance.Text = [mp]::get_property_number("time-pos") -} - -$ScriptHost.RedirectEventJobStreams($job) diff --git a/scripts/examples/seek-show-position.js b/scripts/javascript/seek-show-position.js similarity index 100% rename from scripts/examples/seek-show-position.js rename to scripts/javascript/seek-show-position.js diff --git a/scripts/examples/show-playlist.js b/scripts/javascript/show-playlist.js similarity index 99% rename from scripts/examples/show-playlist.js rename to scripts/javascript/show-playlist.js index 46b3d21..c40078d 100644 --- a/scripts/examples/show-playlist.js +++ b/scripts/javascript/show-playlist.js @@ -3,7 +3,6 @@ function showPlaylist() { - // set font size mp.set_property_number("osd-font-size", 40); diff --git a/scripts/examples/pause-when-minimize.lua b/scripts/lua/pause-when-minimize.lua similarity index 80% rename from scripts/examples/pause-when-minimize.lua rename to scripts/lua/pause-when-minimize.lua index f36fc61..629d3fe 100644 --- a/scripts/examples/pause-when-minimize.lua +++ b/scripts/lua/pause-when-minimize.lua @@ -8,18 +8,16 @@ local did_minimize = false mp.observe_property("window-minimized", "bool", function(name, value) - local pause = mp.get_property_bool("pause") - + local pause = mp.get_property_native("pause") if value == true then if pause == false then - mp.set_property_bool("pause", true) + mp.set_property_native("pause", true) did_minimize = true end elseif value == false then if did_minimize and (pause == true) then - mp.set_property_bool("pause", false) + mp.set_property_native("pause", false) end - did_minimize = false end end) diff --git a/scripts/powershell/open-file-dialog.ps1 b/scripts/powershell/open-file-dialog.ps1 new file mode 100644 index 0000000..e1f804f --- /dev/null +++ b/scripts/powershell/open-file-dialog.ps1 @@ -0,0 +1,20 @@ + +# Shows the Open File dialog to open a file without loading its folder into the playlist. + +# In input.conf add: script-message load-without-folder + +$code = { + if ($args[0] -eq 'load-without-folder') + { + $dialog = New-Object Windows.Forms.OpenFileDialog + + if ($dialog.ShowDialog() -eq 'OK') + { + $core.LoadFiles($dialog.FileNames, $false, $false); + } + + $dialog.Dispose() + } +} + +$mp.register_event("client-message", $code) diff --git a/scripts/powershell/pause-when-minimize.ps1 b/scripts/powershell/pause-when-minimize.ps1 new file mode 100644 index 0000000..5fc3e2a --- /dev/null +++ b/scripts/powershell/pause-when-minimize.ps1 @@ -0,0 +1,27 @@ + +Set-Variable wasPaused $false -Option AllScope + +$code = { + $isMinimized = $args[0] + $isPaused = $mp.get_property_bool('pause') + + if ($isMinimized) + { + if (-not $isPaused) + { + $mp.set_property_bool('pause', $true) + $wasPaused = $true + } + } + else + { + if ($wasPaused -and $isPaused) + { + $mp.set_property_bool('pause', $false) + } + + $wasPaused = $false + } +} + +$mp.observe_property('window-minimized', 'bool', $code)