Compare commits

..

18 Commits
5.0 ... 5.1

Author SHA1 Message Date
Frank Skare
8626b8283f improved error handling 2019-08-01 11:47:01 +02:00
Frank Skare
d90025e8fe misc 2019-08-01 04:45:11 +02:00
Frank Skare
a572bd8553 new setting remember-volume added 2019-07-31 08:01:03 +02:00
Frank Skare
0f5146e58c startup folder and config folder beeing identical is no longer a supported scenaria 2019-07-29 22:48:08 +02:00
Frank Skare
9c6c0f3506 fix issue with startup folder and config folder beeing identical 2019-07-29 22:05:06 +02:00
Frank Skare
8c36cc8b8c improved error handling 2019-07-29 14:14:23 +02:00
Frank Skare
44435057d7 improved error handling, new setup dialog 2019-07-29 13:59:30 +02:00
Frank Skare
135bdeb638 fixed issue in file associations causing mpv.net not to appear in OS default apps 2019-07-28 23:03:38 +02:00
Frank Skare
93c93b620d update readme 2019-07-28 01:24:17 +02:00
stax76
247aefbf07 update readme.md 2019-07-28 01:08:44 +02:00
Frank Skare
0a8397652f input editor improvements 2019-07-27 23:46:53 +02:00
Frank Skare
ecd5b01161 Merge branch 'master' of https://github.com/stax76/mpv.net 2019-07-27 19:23:44 +02:00
Frank Skare
1e9893977d refactoring 2019-07-27 19:23:42 +02:00
stax76
4fd6b13e0f Update ScriptingExtension.cs 2019-07-27 04:54:00 +02:00
stax76
d21d36c196 Update ScriptingExtension.cs 2019-07-27 04:51:05 +02:00
stax76
fbffbea641 Update RatingExtension.cs 2019-07-27 04:41:18 +02:00
Frank Skare
9899c2cd27 readme update 2019-07-27 03:02:02 +02:00
Frank Skare
10370e9ae2 removed 'Tools > Execute mpv command', mpv-repl is better 2019-07-27 02:28:30 +02:00
32 changed files with 603 additions and 421 deletions

View File

@@ -1,3 +1,38 @@
### 5.1
- 'Tools > Execute mpv command' was replaced with [mpv-repl](https://github.com/rossy/mpv-repl)
- many [wiki pages](https://github.com/stax76/mpv.net/wiki) were improved
- the logo/icon had a very small cosmetic change
- the help in the context menu was improved,
for quick access consider the command palette (F1 key)
- config options specific to mpv.net are now available from the command line
- the input editor no longer has known limitations, 'alt gr' and ctrl+alt are working now
- the help in the input editor was simplified and the filter logic was improved
- fixed issue in file associations causing mpv.net not to appear in OS default apps
- 'Tools > Manage File Associations' was replaced by 'Tools > OS Setup',
it has now a feature to add and remove mpv.net to and from the Path
environment variable and the OS default apps settings can be opened (Win 10 only)
- startup folder and config folder beeing identical was causing a critical issue
as mpv.net was loading extensions twice and scripts four times, now identical
folders are no longer permitted
- error messages are shown when unknown scripts and extensions are found in the startup folder
because user scripts and extensions are supposed to be located in the config folder instead
- changing from maximized to fullscreen did not work
- the search field in the config editor was not always remembered
- new setting remember-volume added, saves volume and mute on exit
and restores it on start.
- it's now enforced that mpv properties on the command line and in
the mpv.conf config file are lowercase, if not a error is shown
- gpu-api vulkan was not working if media files were opened via
command line (that included Explorer)
- new setting minimum-aspect-ratio added, minimum aspect ratio for the window,
this was previously hard coded to 1.3
- new setting auto-load-folder added, for single files automatically load
the entire directory into the playlist, previously this was forced,
now it can be disabled
- new setting themed-menu added, follow theme color in context menu,
default: no. UI related settings have now a separate UI tab in the config editor
### 5.0 ### 5.0
- [changed icon design](https://github.com/stax76/mpv.net/blob/master/img/mpvnet.png) - [changed icon design](https://github.com/stax76/mpv.net/blob/master/img/mpvnet.png)
@@ -12,13 +47,13 @@
change is that there exist too many different terms, addons, addins, change is that there exist too many different terms, addons, addins,
extensions, modules, packages etc.. mpv.net follows Google Chrome as the worlds extensions, modules, packages etc.. mpv.net follows Google Chrome as the worlds
most popular extendable app, Chrome uses the term Extension. most popular extendable app, Chrome uses the term Extension.
- a thread synchronisation bug was fixed, the shutdown thread was aborted - a thread synchronization bug was fixed, the shutdown thread was aborted
if it was running more then 3 seconds, this caused the rating extension if it was running more than 3 seconds, this caused the rating extension
to fail if it was waiting for a drive to wakeup to fail if it was waiting for a drive to wake up
- a new JavaScript was included to show the playlist with a smaller font size, - a new JavaScript was included to show the playlist with a smaller font size,
the script is located at startup/scripts the script is located at startup/scripts
- terminal support added using mpvnet.com ! - terminal support added using mpvnet.com !
- script engine performence and error handling was improved - script engine performance and error handling was improved
- the [scripting wiki page](https://github.com/stax76/mpv.net/wiki/Scripting) was improved - the [scripting wiki page](https://github.com/stax76/mpv.net/wiki/Scripting) was improved
- the C# scripting host extension was converted from VB to C# because it's not - the C# scripting host extension was converted from VB to C# because it's not
only used for hosting but I also use it now to code and debug script code only used for hosting but I also use it now to code and debug script code

View File

@@ -1,5 +1,7 @@
![](https://raw.githubusercontent.com/stax76/mpv.net/master/img/mpvnet.png) ![](https://raw.githubusercontent.com/stax76/mpv.net/master/img/mpvnet.png)
![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/stax76/mpv.net) ![GitHub closed issues](https://img.shields.io/github/issues-closed/stax76/mpv.net) ![GitHub All Releases](https://img.shields.io/github/downloads/stax76/mpv.net/total) ![GitHub tag (latest by date)](https://img.shields.io/github/tag-date/stax76/mpv.net) ![GitHub stars](https://img.shields.io/github/stars/stax76/mpv.net) [![PayPal donate button](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.me/stax76)
# 🎞 mpv.net # 🎞 mpv.net
mpv.net is a modern media player for Windows that works just like [mpv](https://mpv.io). mpv.net is a modern media player for Windows that works just like [mpv](https://mpv.io).
@@ -60,6 +62,7 @@ Table of contents
- Language agnostic JSON IPC to control the player with a external programs - Language agnostic JSON IPC to control the player with a external programs
- On Screen Controler (OSC, play control buttons) - On Screen Controler (OSC, play control buttons)
- [Command Line Interface](https://mpv.io/manual/master/#options) - [Command Line Interface](https://mpv.io/manual/master/#options)
- If started from a PowerShell terminal mpv.net will attach to the terminal and print status and debug output
- DXVA2 video decoding acceleration - DXVA2 video decoding acceleration
- OpenGL based video output capable of features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more - OpenGL based video output capable of features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more
- Search feature powered by [Everything](https://www.voidtools.com) to find and play media ([Screenshot](#media-search-screenshot)) - Search feature powered by [Everything](https://www.voidtools.com) to find and play media ([Screenshot](#media-search-screenshot))
@@ -218,39 +221,30 @@ Third party components:
[Support thread in VideoHelp forum](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows) [Support thread in VideoHelp forum](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows)
[Issue tracker to report bugs and request features](https://github.com/stax76/mpv.net/issues) [Issue tracker](https://github.com/stax76/mpv.net/issues), feel free to use for anything mpv.net related
[frank.skare.de@gmail.com](mailto:frank.skare.de@gmail.com?Subject=mpv.net%20support) [frank.skare.de@gmail.com](mailto:frank.skare.de@gmail.com?Subject=mpv.net%20support)
Please click on the star at the top of the page and like mpv.net at [alternativeto.net](https://alternativeto.net/software/mpv-net/). Please click on the star at the top of the page and like mpv.net at [alternativeto.net](https://alternativeto.net/software/mpv-net/).
If you like you can express your appreciation for my player by sending little beer money with paypal. If you want to support the development of mpv.net or express your appreciation you can do so with a donation:
<https://www.paypal.me/stax76> <https://www.paypal.me/stax76>
### Links ### Links
mpv manual: <https://mpv.io/manual/master/> - mpv.net wiki: <https://github.com/stax76/mpv.net/wiki>
- mpv.net default key bindings: <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
mpv wiki: <https://github.com/mpv-player/mpv/wiki> - mpv.net download: <https://github.com/stax76/mpv.net/releases>
- mpv.net bugs and requests: <https://github.com/stax76/mpv.net/issues>
mpv.net wiki: <https://github.com/stax76/mpv.net/wiki> - mpv website: <https://mpv.io/>
- mpv manual: <https://mpv.io/manual/master/>
mpv apps: <https://github.com/mpv-player/mpv/wiki/Applications-using-mpv> - mpv wiki: <https://github.com/mpv-player/mpv/wiki>
- mpv apps: <https://github.com/mpv-player/mpv/wiki/Applications-using-mpv>
mpv user scripts: <https://github.com/mpv-player/mpv/wiki/User-Scripts> - mpv user scripts: <https://github.com/mpv-player/mpv/wiki/User-Scripts>
- mpv default key bindings: <https://github.com/mpv-player/mpv/blob/master/etc/input.conf>
mpv default key bindings: <https://github.com/mpv-player/mpv/blob/master/etc/input.conf> - mpv download: <https://mpv.io/installation/>
- mpv bugs and requests: <https://mpv.io/bug-reports/>
mpv.net default key bindings: <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
mpv download: <https://mpv.io/installation/>
mpv.net download: <https://github.com/stax76/mpv.net/releases>
mpv bugs and requests: <https://mpv.io/bug-reports/>
mpv.net bugs and requests: <https://github.com/stax76/mpv.net/issues>
### Changelog ### Changelog
@@ -258,4 +252,4 @@ mpv.net bugs and requests: <https://github.com/stax76/mpv.net/issues>
### Download ### Download
<https://github.com/stax76/mpv.net/releases> <https://github.com/stax76/mpv.net/releases>

View File

@@ -1,4 +1,8 @@
using System; // This extension writes a rating to the filename of rated videos when mpv.net shuts down.
// The input.conf defaults contain key bindings for this extension to set ratings.
using System;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@@ -58,4 +62,4 @@ namespace RatingExtension // the assembly name must end with 'Extension'
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."); 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.");
} }
} }
} }

View File

@@ -1,14 +1,14 @@
//'This extension implements the C# scripting feature of mpv.net which // This extension implements the C# scripting feature of mpv.net which
// is based on CS-Script (https://www.cs-script.net). // is based on CS-Script (https://www.cs-script.net).
// Furthermore the extension is used to code and debug scripts // I also use this extension to code scripts in order to have full
// because writing script code without debugger is not an option :-) // code completion and debugger support, once the script code is
// finished I move it from the extension to a standalone script.
using System; using System;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Windows.Forms;
using mpvnet; using mpvnet;
using CSScriptLibrary; using CSScriptLibrary;
@@ -18,7 +18,7 @@ namespace ScriptingExtension // the file name of extensions must end with 'Exten
[Export(typeof(IExtension))] [Export(typeof(IExtension))]
public class ScriptingExtension : IExtension public class ScriptingExtension : IExtension
{ {
Script Script; //Script Script;
public ScriptingExtension() public ScriptingExtension()
{ {
@@ -28,8 +28,9 @@ namespace ScriptingExtension // the file name of extensions must end with 'Exten
if (Directory.Exists(mp.ConfigFolder + "scripts")) if (Directory.Exists(mp.ConfigFolder + "scripts"))
scriptFiles.AddRange(Directory.GetFiles(mp.ConfigFolder + "scripts", "*.cs")); scriptFiles.AddRange(Directory.GetFiles(mp.ConfigFolder + "scripts", "*.cs"));
if (Directory.Exists(Application.StartupPath + "\\scripts")) if (Directory.Exists(PathHelp.StartupPath + "scripts"))
scriptFiles.AddRange(Directory.GetFiles(Application.StartupPath + "\\scripts", "*.cs")); foreach (string path in Directory.GetFiles(PathHelp.StartupPath + "scripts", "*.cs"))
scriptFiles.AddRange(Directory.GetFiles(PathHelp.StartupPath + "scripts", "*.cs"));
if (scriptFiles.Count == 0) return; if (scriptFiles.Count == 0) return;
CSScriptLibrary.CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom; CSScriptLibrary.CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;

BIN
img/Avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

124
mpv.net/Misc/App.cs Normal file
View File

@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
namespace mpvnet
{
public class App
{
public static string[] VideoTypes { get; } = "264 265 asf avc avi avs flv h264 h265 hevc m2ts m2v m4v mkv mov mp4 mpeg mpg mpv mts ts vob vpy webm webm wmv y4m".Split(' ');
public static string[] AudioTypes { get; } = "mp3 mp2 ac3 ogg opus flac wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 mka aac mpa".Split(' ');
public static string[] ImageTypes { get; } = {"jpg", "bmp", "gif", "png"};
public static string[] SubtitleTypes { get; } = { "srt", "ass", "idx", "sup", "ttxt", "ssa", "smi" };
public static string[] UrlWhitelist { get; set; } = { "tube", "vimeo", "ard", "zdf" };
public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName;
public static string ConfPath { get; } = mp.ConfigFolder + "\\mpvnet.conf";
public static string DarkMode { get; set; } = "always";
public static string ProcessInstance { get; set; } = "single";
public static string DarkColor { get; set; }
public static string LightColor { get; set; }
public static bool RememberHeight { get; set; } = true;
public static bool RememberPosition { get; set; }
public static bool DebugMode { get; set; }
public static bool IsStartedFromTerminal { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
public static bool RememberVolume { get; set; }
public static bool AutoLoadFolder { get; set; } = true;
public static bool ThemedMenu { get; set; }
public static int StartThreshold { get; set; } = 1500;
public static float MinimumAspectRatio { get; set; } = 1.3f;
public static bool IsDarkMode {
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
}
public static void Init()
{
string dummy = mp.ConfigFolder;
var dummy2 = mp.Conf;
foreach (var i in Conf)
ProcessProperty(i.Key, i.Value);
if (App.DebugMode)
{
try
{
string filePath = mp.ConfigFolder + "\\mpvnet-debug.log";
if (File.Exists(filePath)) File.Delete(filePath);
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
Trace.AutoFlush = true;
//if (App.DebugMode) Trace.WriteLine("");
}
catch (Exception e)
{
Msg.ShowException(e);
}
}
mp.Shutdown += Shutdown;
mp.Initialized += Initialized;
}
private static void Initialized()
{
if (RememberVolume)
{
mp.set_property_int("volume", RegHelp.GetInt(App.RegPath, "Volume"));
mp.set_property_string("mute", RegHelp.GetString(App.RegPath, "Mute"));
}
}
private static void Shutdown()
{
if (RememberVolume)
{
RegHelp.SetObject(App.RegPath, "Volume", mp.get_property_int("volume"));
RegHelp.SetObject(App.RegPath, "Mute", mp.get_property_string("mute"));
}
}
static Dictionary<string, string> _Conf;
public static Dictionary<string, string> Conf {
get {
if (_Conf == null)
{
_Conf = new Dictionary<string, string>();
if (File.Exists(ConfPath))
foreach (string i in File.ReadAllLines(ConfPath))
if (i.Contains("=") && !i.StartsWith("#"))
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
return _Conf;
}
}
public static bool ProcessProperty(string name, string value)
{
switch (name)
{
case "remember-position": RememberPosition = value == "yes"; return true;
case "start-size": RememberHeight = value == "previous"; return true;
case "process-instance": ProcessInstance = value; return true;
case "dark-mode": DarkMode = value; return true;
case "debug-mode": DebugMode = value == "yes"; return true;
case "dark-color": DarkColor = value.Trim('\'', '"'); return true;
case "light-color": LightColor = value.Trim('\'', '"'); return true;
case "url-whitelist": UrlWhitelist = value.Split(' ', ',', ';'); return true;
case "remember-volume": RememberVolume = value == "yes"; return true;
case "start-threshold": StartThreshold = value.Int(); return true;
case "minimum-aspect-ratio": MinimumAspectRatio = value.Float(); return true;
case "auto-load-folder": AutoLoadFolder = value == "yes"; return true;
case "themed-menu": ThemedMenu = value == "yes"; return true;
}
return false;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace mpvnet
{ {
switch (id) switch (id)
{ {
case "manage-file-associations": ManageFileAssociations(); break; case "manage-file-associations": ManageFileAssociations(); break; // deprecated 2019
case "cycle-audio": CycleAudio(); break; case "cycle-audio": CycleAudio(); break;
case "load-audio": LoadAudio(); break; case "load-audio": LoadAudio(); break;
case "load-sub": LoadSubtitle(); break; case "load-sub": LoadSubtitle(); break;
@@ -28,6 +28,7 @@ namespace mpvnet
case "show-about": ShowDialog(typeof(AboutWindow)); break; case "show-about": ShowDialog(typeof(AboutWindow)); break;
case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break; case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break;
case "show-input-editor": ShowDialog(typeof(InputWindow)); break; case "show-input-editor": ShowDialog(typeof(InputWindow)); break;
case "show-setup-dialog": ShowDialog(typeof(SetupWindow)); break;
case "open-conf-folder": Process.Start(mp.ConfigFolder); break; case "open-conf-folder": Process.Start(mp.ConfigFolder); break;
case "open-files": OpenFiles(args); break; case "open-files": OpenFiles(args); break;
case "shell-execute": Process.Start(args[0]); break; case "shell-execute": Process.Start(args[0]); break;
@@ -92,7 +93,7 @@ namespace mpvnet
{ {
fileSize = new FileInfo(path).Length; fileSize = new FileInfo(path).Length;
if (App.AudioTypes.Contains(Path.GetExtension(path).ToLower().TrimStart('.'))) if (App.AudioTypes.Contains(path.ShortExt()))
{ {
using (MediaInfo mediaInfo = new MediaInfo(path)) using (MediaInfo mediaInfo = new MediaInfo(path))
{ {
@@ -110,13 +111,13 @@ namespace mpvnet
if (date != "") text += "Year: " + date + "\n"; if (date != "") text += "Year: " + date + "\n";
if (duration != "") text += "Length: " + duration + "\n"; if (duration != "") text += "Length: " + duration + "\n";
text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n"; text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n";
text += "Type: " + Path.GetExtension(path).ToUpper().TrimStart('.'); text += "Type: " + path.ShortExt().ToUpper();
mp.commandv("show-text", text, "5000"); mp.commandv("show-text", text, "5000");
return; return;
} }
} }
else if (App.ImageTypes.Contains(Path.GetExtension(path).ToLower().TrimStart('.'))) else if (App.ImageTypes.Contains(path.ShortExt()))
{ {
using (MediaInfo mediaInfo = new MediaInfo(path)) using (MediaInfo mediaInfo = new MediaInfo(path))
{ {
@@ -124,7 +125,7 @@ namespace mpvnet
"Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" + "Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" +
"Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" + "Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" +
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" + "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
"Type: " + Path.GetExtension(path).ToUpper().TrimStart('.'); "Type: " + path.ShortExt().ToUpper();
mp.commandv("show-text", text, "5000"); mp.commandv("show-text", text, "5000");
return; return;
@@ -137,7 +138,7 @@ namespace mpvnet
string videoFormat = mp.get_property_string("video-format").ToUpper(); string videoFormat = mp.get_property_string("video-format").ToUpper();
string audioCodec = mp.get_property_string("audio-codec-name").ToUpper(); string audioCodec = mp.get_property_string("audio-codec-name").ToUpper();
text = PathHelp.GetFileName(path) + "\n" + text = path.FileName() + "\n" +
FormatTime(position.TotalMinutes) + ":" + FormatTime(position.TotalMinutes) + ":" +
FormatTime(position.Seconds) + " / " + FormatTime(position.Seconds) + " / " +
FormatTime(duration2.TotalMinutes) + ":" + FormatTime(duration2.TotalMinutes) + ":" +
@@ -158,7 +159,7 @@ namespace mpvnet
} }
} }
public static void ExecuteMpvCommand() public static void ExecuteMpvCommand() // deprecated 2019
{ {
InvokeOnMainThread(new Action(() => { InvokeOnMainThread(new Action(() => {
string command = VB.Interaction.InputBox("Enter a mpv command to be executed.", "Execute Command", RegHelp.GetString(App.RegPath, "RecentExecutedCommand")); string command = VB.Interaction.InputBox("Enter a mpv command to be executed.", "Execute Command", RegHelp.GetString(App.RegPath, "RecentExecutedCommand"));
@@ -230,31 +231,6 @@ namespace mpvnet
} }
} }
public static void ManageFileAssociations() public static void ManageFileAssociations() => ShowDialog(typeof(SetupWindow)); // deprecated 2019
{
using (var td = new TaskDialog<string>())
{
td.MainInstruction = "Choose an option.";
td.MainIcon = MsgIcon.Shield;
td.AddCommandLink("Register video file extensions", "video");
td.AddCommandLink("Register audio file extensions", "audio");
td.AddCommandLink("Register image file extensions", "image");
td.AddCommandLink("Unregister file extensions", "unreg");
string result = td.Show();
if (!string.IsNullOrEmpty(result))
{
using (var proc = new Process())
{
proc.StartInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
proc.StartInfo.Arguments = "--reg-file-assoc " + result;
proc.StartInfo.Verb = "runas";
try { proc.Start(); } catch { }
}
}
}
}
} }
} }

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; using System.ComponentModel.Composition.Hosting;
using System.IO; using System.IO;
using System.Windows.Forms; using System.Linq;
namespace mpvnet namespace mpvnet
{ {
@@ -19,14 +19,22 @@ namespace mpvnet
try try
{ {
AggregateCatalog catalog = new AggregateCatalog(); AggregateCatalog catalog = new AggregateCatalog();
string dir = PathHelp.StartupPath + "Extensions";
string dir = Application.StartupPath + "\\Extensions";
if (Directory.Exists(dir)) if (Directory.Exists(dir))
foreach (string i in Directory.GetDirectories(dir)) {
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Extension.dll")); string[] knownExtensions = { "RatingExtension", "ScriptingExtension" };
dir = mp.ConfigFolder + "\\Extensions"; foreach (string path in Directory.GetDirectories(dir))
{
if (knownExtensions.Contains(Path.GetFileName(path)))
catalog.Catalogs.Add(new DirectoryCatalog(path, "*Extension.dll"));
else
Msg.ShowError("Failed to load extension", path + "\n\nOnly extensions that ship with mpv.net are allowed in <startup>\\extensions\n\nUser extensions have to use <config folder>\\extensions\n\nNever copy or install a new mpv.net version over a old mpv.net version.");
}
}
dir = mp.ConfigFolder + "Extensions";
if (Directory.Exists(dir)) if (Directory.Exists(dir))
foreach (string i in Directory.GetDirectories(dir)) foreach (string i in Directory.GetDirectories(dir))

View File

@@ -0,0 +1,32 @@
using System.Globalization;
using System.IO;
public static class Extensions
{
public static string FileName(this string path)
{
if (string.IsNullOrEmpty(path)) return "";
int index = path.LastIndexOf('\\');
if (index > -1) return path.Substring(index + 1);
index = path.LastIndexOf('/');
if (index > -1) return path.Substring(index + 1);
return path;
}
public static string ShortExt(this string path)
{
return Path.GetExtension(path).ToLower().TrimStart('.');
}
public static int Int(this string value)
{
int.TryParse(value, out int result);
return result;
}
public static float Float(this string value)
{
float.TryParse(value.Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out float result);
return result;
}
}

View File

@@ -3,7 +3,6 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -16,121 +15,6 @@ using Microsoft.Win32;
namespace mpvnet namespace mpvnet
{ {
public class App
{
public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName;
public static string ConfPath { get; } = mp.ConfigFolder + "\\mpvnet.conf";
public static string DarkMode { get; set; } = "always";
public static string ProcessInstance { get; set; } = "single";
public static string DarkColor { get; set; }
public static string LightColor { get; set; }
public static string[] VideoTypes { get; } = "264 265 asf avc avi avs flv h264 h265 hevc m2ts m2v m4v mkv mov mp4 mpeg mpg mpv mts ts vob vpy webm webm wmv y4m".Split(' ');
public static string[] AudioTypes { get; } = "mp3 mp2 ac3 ogg opus flac wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 mka aac mpa".Split(' ');
public static string[] ImageTypes { get; } = "jpg bmp gif png".Split(' ');
public static string[] SubtitleTypes { get; } = "srt ass idx sup ttxt ssa smi".Split(' ');
public static string[] UrlWhitelist { get; set; } = { "tube", "vimeo", "ard", "zdf" };
public static bool RememberHeight { get; set; } = true;
public static bool RememberPosition { get; set; }
public static bool DebugMode { get; set; }
public static bool IsStartedFromTerminal { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
public static int StartThreshold { get; set; } = 1500;
public static bool IsDarkMode {
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
}
public static void Init()
{
string dummy = mp.ConfigFolder;
var dummy2 = mp.Conf;
foreach (var i in Conf)
ProcessProperty(i.Key, i.Value);
if (App.DebugMode)
{
try
{
string filePath = mp.ConfigFolder + "\\mpvnet-debug.log";
if (File.Exists(filePath)) File.Delete(filePath);
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
Trace.AutoFlush = true;
//if (App.DebugMode) Trace.WriteLine("");
}
catch (Exception e)
{
Msg.ShowException(e);
}
}
}
static Dictionary<string, string> _Conf;
public static Dictionary<string, string> Conf {
get {
if (_Conf == null)
{
_Conf = new Dictionary<string, string>();
if (File.Exists(ConfPath))
foreach (string i in File.ReadAllLines(ConfPath))
if (i.Contains("=") && !i.StartsWith("#"))
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
return _Conf;
}
}
public static void ProcessProperty(string name, string value)
{
switch (name)
{
case "remember-position": RememberPosition = value == "yes"; break;
case "start-size": RememberHeight = value == "previous"; break;
case "process-instance": ProcessInstance = value; break;
case "dark-mode": DarkMode = value; break;
case "debug-mode": DebugMode = value == "yes"; break;
case "dark-color": DarkColor = value.Trim('\'', '"'); break;
case "light-color": LightColor = value.Trim('\'', '"'); break;
case "url-whitelist":
UrlWhitelist = value.Split(' ', ',', ';');
break;
case "start-threshold":
int.TryParse(value, out int result);
StartThreshold = result;
break;
}
}
public static void ProcessCommandLineEarly()
{
var args = Environment.GetCommandLineArgs().Skip(1);
foreach (string i in args)
{
if (i.StartsWith("--"))
{
if (i.Contains("="))
{
string left = i.Substring(2, i.IndexOf("=") - 2);
string right = i.Substring(left.Length + 3);
mp.ProcessProperty(left, right);
ProcessProperty(left, right);
}
else
{
string name = i.Substring(2);
mp.ProcessProperty(name, "yes");
ProcessProperty(name, "yes");
}
}
}
}
}
public class Sys public class Sys
{ {
public static bool IsDarkTheme { public static bool IsDarkTheme {
@@ -178,25 +62,23 @@ namespace mpvnet
{ {
Types = types; Types = types;
RegHelp.SetObject(@"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename, null, ExePath); RegHelp.SetObject($"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\{ExeFilename}", null, ExePath);
RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}", "FriendlyAppName", "mpv.net media player"); RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}", "FriendlyAppName", "mpv.net media player");
RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\""); RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\"");
RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationDescription", "mpv.net media player"); RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationDescription", "mpv.net media player");
RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationName", "mpv.net"); RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationName", "mpv.net");
RegHelp.SetObject($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}", null, ""); RegHelp.SetObject($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}", null, "");
RegHelp.SetObject($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}", null, ""); RegHelp.SetObject($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}", null, "");
RegHelp.SetObject(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net", @"SOFTWARE\Clients\Media\mpv.net\Capabilities");
foreach (string ext in Types) foreach (string ext in Types)
{ {
RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}\\SupportedTypes", "." + ext, ""); RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}\\SupportedTypes", "." + ext, "");
RegHelp.SetObject($"HKCR\\" + "." + ext, null, ExeFilenameNoExt + "." + ext); RegHelp.SetObject($"HKCR\\" + "." + ext, null, ExeFilenameNoExt + "." + ext);
RegHelp.SetObject($"HKCR\\" + "." + ext + "\\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, ""); RegHelp.SetObject($"HKCR\\" + "." + ext + "\\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, "");
if (App.VideoTypes.Contains(ext)) if (App.VideoTypes.Contains(ext)) RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "video");
RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "video"); if (App.AudioTypes.Contains(ext)) RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "audio");
if (App.AudioTypes.Contains(ext)) if (App.ImageTypes.Contains(ext)) RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "image");
RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "audio");
if (App.ImageTypes.Contains(ext))
RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "image");
RegHelp.SetObject($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open", null, "Play with " + Application.ProductName); RegHelp.SetObject($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open", null, "Play with " + Application.ProductName);
RegHelp.SetObject($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\""); RegHelp.SetObject($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\"");
RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext); RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext);
@@ -205,17 +87,16 @@ namespace mpvnet
public static void Unregister() public static void Unregister()
{ {
RegHelp.RemoveKey(@"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename); RegHelp.RemoveKey($"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\{ExeFilename}");
RegHelp.RemoveKey($"HKCR\\Applications\\{ExeFilename}"); RegHelp.RemoveKey($"HKCR\\Applications\\{ExeFilename}");
RegHelp.RemoveKey(@"HKLM\SOFTWARE\Clients\Media\mpv.net"); RegHelp.RemoveKey($"HKLM\\SOFTWARE\\Clients\\Media\\mpv.net");
RegHelp.RemoveKey($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}"); RegHelp.RemoveKey($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}");
RegHelp.RemoveKey($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}"); RegHelp.RemoveKey($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}");
RegHelp.RemoveValue(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net");
foreach (string id in Registry.ClassesRoot.GetSubKeyNames()) foreach (string id in Registry.ClassesRoot.GetSubKeyNames())
{ {
if (id.StartsWith(ExeFilenameNoExt + ".")) if (id.StartsWith(ExeFilenameNoExt + ".")) Registry.ClassesRoot.DeleteSubKeyTree(id);
Registry.ClassesRoot.DeleteSubKeyTree(id);
RegHelp.RemoveValue($"HKCR\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id); RegHelp.RemoveValue($"HKCR\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id);
RegHelp.RemoveValue($"HKLM\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id); RegHelp.RemoveValue($"HKLM\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id);
} }
@@ -412,14 +293,6 @@ namespace mpvnet
public class PathHelp public class PathHelp
{ {
public static string GetFileName(string path) public static string StartupPath { get; } = Application.StartupPath + "\\";
{
if (string.IsNullOrEmpty(path)) return "";
int index = path.LastIndexOf('\\');
if (index > -1) return path.Substring(index + 1);
index = path.LastIndexOf('/');
if (index > -1) return path.Substring(index + 1);
return path;
}
} }
} }

View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("5.0.0.0")] [assembly: AssemblyVersion("5.1.0.0")]
[assembly: AssemblyFileVersion("5.0.0.0")] [assembly: AssemblyFileVersion("5.1.0.0")]

View File

@@ -150,19 +150,27 @@
F1 script-message mpv.net show-command-palette #menu: Tools > Show All Commands F1 script-message mpv.net show-command-palette #menu: Tools > Show All Commands
h script-message mpv.net show-history #menu: Tools > Show History h script-message mpv.net show-history #menu: Tools > Show History
Ctrl+r script-message-to repl type "" #menu: Tools > Show REPL
l ab-loop #menu: Tools > Set/clear A-B loop points l ab-loop #menu: Tools > Set/clear A-B loop points
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Toggle Hardware Decoding Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Toggle Hardware Decoding
_ script-message mpv.net execute-mpv-command #menu: Tools > Execute mpv command... _ script-message mpv.net show-setup-dialog #menu: Tools > OS Setup...
_ script-message mpv.net manage-file-associations #menu: Tools > Manage File Associations...
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Show mpv manual _ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/Manual.md #menu: Help > mpv.net Manual
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: Help > Show mpv default keys _ script-message mpv.net shell-execute https://github.com/stax76/mpv.net #menu: Help > mpv.net GitHub
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt #menu: Help > Show mpv.net default keys _ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/wiki #menu: Help > mpv.net Wiki
_ script-message mpv.net shell-execute https://mpv-net.github.io/mpv.net-web-site/ #menu: Help > Show mpv.net web site _ script-message mpv.net shell-execute https://github.com/stax76/mpv.net#support #menu: Help > mpv.net Support
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/Manual.md #menu: Help > Show mpv.net manual _ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/releases #menu: Help > mpv.net Download
_ ignore #menu: Help > - _ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt #menu: Help > mpv.net Default Key Bindings
_ script-message mpv.net show-about #menu: Help > About mpv.net _ ignore #menu: Help > -
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > mpv Manual
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/wiki #menu: Help > mpv Wiki
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/wiki/User-Scripts #menu: Help > mpv User Scripts
_ script-message mpv.net shell-execute https://mpv.io/bug-reports/ #menu: Help > mpv Bugs and Requests
_ script-message mpv.net shell-execute https://mpv.io/installation/ #menu: Help > mpv Download
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: Help > mpv Default Key Bindings
_ ignore #menu: Help > -
_ script-message mpv.net show-about #menu: Help > About mpv.net
_ ignore #menu: - _ ignore #menu: -
Esc quit #menu: Exit Esc quit #menu: Exit

View File

@@ -1,9 +1,4 @@
input-ar-delay = 500
# manual: https://mpv.io/manual/master/
# defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt
input-ar-delay = 500
input-ar-rate = 20 input-ar-rate = 20
volume = 50 volume = 50
hwdec = yes hwdec = yes

View File

@@ -244,17 +244,17 @@ help = "Specify the OSD font size. See sub-font-size for details. Default: 55"
[[settings]] [[settings]]
name = "autofit" name = "autofit"
filter = "Screen" filter = "Screen"
help = "<int> Initial window height in percent. Default: 50%" help = "<int> Initial window height in percent. Default: 50"
[[settings]] [[settings]]
name = "autofit-smaller" name = "autofit-smaller"
filter = "Screen" filter = "Screen"
help = "<int> Minimum window height in percent. Default: 40%" help = "<int> Minimum window height in percent. Default: 40"
[[settings]] [[settings]]
name = "autofit-larger" name = "autofit-larger"
filter = "Screen" filter = "Screen"
help = "<int> Maximum window height in percent. Default: 75%" help = "<int> Maximum window height in percent. Default: 75"
[[settings]] [[settings]]
name = "screenshot-directory" name = "screenshot-directory"

View File

@@ -1,29 +1,9 @@
[[settings]] [[settings]]
name = "dark-mode"
default = "always"
filter = "General"
help = "Enables a dark theme. (mpv.net specific setting)"
options = [{ name = "always" },
{ name = "system" , help = "Available on Windows 10 or higher" },
{ name = "never" }]
[[settings]]
name = "dark-color"
type = "color"
filter = "General"
help = "Theme color used in dark-mode. Leave empty to use OS theme. (mpv.net specific setting)"
[[settings]]
name = "light-color"
type = "color"
filter = "General"
help = "Theme color used when dark-mode is disabled. Leave empty to use OS theme. (mpv.net specific setting)"
[[settings]]
name = "url-whitelist" name = "url-whitelist"
filter = "General" filter = "General"
type = "string" type = "string"
help = "Whitelist setting to monitor the clipboard for URLs to play. (mpv.net specific setting)\n\nDefault: tube vimeo ard zdf" help = "Whitelist setting to monitor the clipboard for URLs to play. (mpv.net specific setting)\n\nDefault: tube vimeo ard zdf\n\nHow to start mpv.net directly from Google Chrome is described in the manual:"
url = "https://github.com/stax76/mpv.net/blob/master/Manual.md#chrome-extension"
[[settings]] [[settings]]
name = "process-instance" name = "process-instance"
@@ -55,10 +35,60 @@ name = "start-threshold"
filter = "Screen" filter = "Screen"
help = "Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. (mpv.net specific setting) Default: 1500" help = "Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. (mpv.net specific setting) Default: 1500"
[[settings]]
name = "minimum-aspect-ratio"
filter = "Screen"
help = "<float> Minimum aspect ratio for the window. Default: 1.3"
[[settings]] [[settings]]
name = "remember-position" name = "remember-position"
default = "no" default = "no"
filter = "Screen" filter = "Screen"
help = "Setting to save the window position on exit. (mpv.net specific setting)" help = "Save the window position on exit. (mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "remember-volume"
default = "no"
filter = "Audio"
help = "Save volume and mute on exit and restore it on start. (mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "auto-load-folder"
default = "yes"
filter = "Playback"
help = "For single files automatically load the entire directory into the playlist. (mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "dark-mode"
default = "always"
filter = "UI"
help = "Enables a dark theme. (mpv.net specific setting)"
options = [{ name = "always" },
{ name = "system" , help = "Available on Windows 10 or higher" },
{ name = "never" }]
[[settings]]
name = "dark-color"
type = "color"
filter = "UI"
help = "Theme color used in dark-mode. Leave empty to use OS theme. (mpv.net specific setting)"
[[settings]]
name = "light-color"
type = "color"
filter = "UI"
help = "Theme color used when dark-mode is disabled. Leave empty to use OS theme. (mpv.net specific setting)"
[[settings]]
name = "themed-menu"
default = "no"
filter = "UI"
help = "Follow theme color in context menu. (mpv.net specific setting)"
options = [{ name = "yes" }, options = [{ name = "yes" },
{ name = "no" }] { name = "no" }]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -5,7 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:WPF="clr-namespace:WPF" xmlns:WPF="clr-namespace:WPF"
mc:Ignorable="d" mc:Ignorable="d"
Height="500" Width="700" Loaded="ConfWindow1_Loaded" ShowInTaskbar="False" Height="530" Width="700" Loaded="ConfWindow1_Loaded" ShowInTaskbar="False"
WindowStartupLocation="CenterScreen" Title="Config Editor"> WindowStartupLocation="CenterScreen" Title="Config Editor">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -21,7 +21,7 @@
<StackPanel x:Name="MainStackPanel"></StackPanel> <StackPanel x:Name="MainStackPanel"></StackPanel>
</ScrollViewer> </ScrollViewer>
<StackPanel Margin="20,0,0,0" Grid.Row="1"> <StackPanel Margin="20,0,0,0" Grid.Row="1">
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static WPF:WPF.ThemeBrush}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"> <ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="FilterListBox_SelectionChanged" Foreground="{x:Static WPF:WPF.ThemeBrush}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding}" FontSize="16" /> <TextBlock Text="{Binding}" FontSize="16" />

View File

@@ -29,7 +29,7 @@ namespace mpvnet
LoadSettings(NetSettingsDefinitions, NetConf); LoadSettings(NetSettingsDefinitions, NetConf);
InitialContent = GetContent(mp.ConfPath, Conf, SettingsDefinitions) + InitialContent = GetContent(mp.ConfPath, Conf, SettingsDefinitions) +
GetContent(App.ConfPath, NetConf, NetSettingsDefinitions); GetContent(App.ConfPath, NetConf, NetSettingsDefinitions);
SearchControl.Text = RegHelp.GetString(App.RegPath, "config editor search"); SearchControl.Text = RegHelp.GetString(App.RegPath, "ConfigEditorSearch");
if (App.IsDarkMode) if (App.IsDarkMode)
{ {
@@ -124,14 +124,13 @@ namespace mpvnet
protected override void OnClosed(EventArgs e) protected override void OnClosed(EventArgs e)
{ {
base.OnClosed(e); base.OnClosed(e);
RegHelp.SetObject(App.RegPath, "ConfigEditorSearch", SearchControl.Text);
string content = GetContent(mp.ConfPath, Conf, SettingsDefinitions); string content = GetContent(mp.ConfPath, Conf, SettingsDefinitions);
string netContent = GetContent(App.ConfPath, NetConf, NetSettingsDefinitions); string netContent = GetContent(App.ConfPath, NetConf, NetSettingsDefinitions);
if (InitialContent == content + netContent) return; if (InitialContent == content + netContent) return;
string header = "\r\n# manual: https://mpv.io/manual/master/\r\n\r\n# defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt\r\n\r\n"; File.WriteAllText(mp.ConfPath, content);
File.WriteAllText(mp.ConfPath, header + content);
File.WriteAllText(App.ConfPath, netContent); File.WriteAllText(App.ConfPath, netContent);
Msg.Show("Changes will be available on next mpv.net startup."); Msg.Show("Changes will be available on next mpv.net startup.");
RegHelp.SetObject(App.RegPath, "config editor search", SearchControl.Text);
} }
string GetContent(string filePath, Dictionary<string, string> confSettings, List<SettingBase> settings) string GetContent(string filePath, Dictionary<string, string> confSettings, List<SettingBase> settings)
@@ -198,7 +197,7 @@ namespace mpvnet
i.Update(); i.Update();
} }
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) private void FilterListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (e.AddedItems.Count > 0) if (e.AddedItems.Count > 0)
SearchControl.Text = e.AddedItems[0].ToString() + ":"; SearchControl.Text = e.AddedItems[0].ToString() + ":";

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@@ -137,10 +136,11 @@ namespace mpvnet
Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH); Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH);
Everything_SetSort(EVERYTHING_SORT_SIZE_DESCENDING); Everything_SetSort(EVERYTHING_SORT_SIZE_DESCENDING);
Everything_Query(true); Everything_Query(true);
for (i = 0; i < Everything_GetNumResults(); i++) for (i = 0; i < Everything_GetNumResults(); i++)
{ {
Everything_GetResultFullPathName(i, buf, bufsize); Everything_GetResultFullPathName(i, buf, bufsize);
string ext = Path.GetExtension(buf.ToString()).TrimStart('.').ToLower(); string ext = buf.ToString().ShortExt();
if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext) || if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext) ||
App.ImageTypes.Contains(ext)) App.ImageTypes.Contains(ext))
@@ -149,6 +149,7 @@ namespace mpvnet
if (items.Count > 100) break; if (items.Count > 100) break;
} }
Application.Current.Dispatcher.Invoke(() => { Application.Current.Dispatcher.Invoke(() => {
ListView.ItemsSource = items; ListView.ItemsSource = items;
SelectFirst(); SelectFirst();

View File

@@ -48,16 +48,21 @@ namespace mpvnet
CollectionView.Refresh(); CollectionView.Refresh();
if (SearchControl.SearchTextBox.Text == "?") if (SearchControl.SearchTextBox.Text == "?")
Msg.Show("Filtering works by searching in the Input, Menu and Command but it's possible to reduce the filter scope to either of Input, Menu or Command by prefixing as follows:\n\ni <input search>\ni: <input search>\n\nm <menu search>\nm: <menu search>\n\nc <command search>\nc: <command search>\n\nIf only one character is entered the search will be performed only in the input.", "Filtering"); {
SearchControl.SearchTextBox.Text = "";
Msg.Show("Filtering", "Reduce the filter scope with:\n\ni input\n\nm menu\n\nc command\n\nIf only one character is entered input search is performed.");
}
} }
bool Filter(CommandItem item) bool Filter(CommandItem item)
{ {
if (item.Command == "") return false; if (item.Command == "") return false;
string searchText = SearchControl.SearchTextBox.Text.ToLower(); string searchText = SearchControl.SearchTextBox.Text.ToLower();
if (searchText == "") return true; if (searchText == "" || searchText == "?") return true;
if (searchText.StartsWith("i ") || searchText.StartsWith("i:") || searchText.Length == 1) if (searchText.Length == 1)
return item.Input.ToLower().Replace("ctrl+", "").Replace("shift+", "").Replace("alt+", "") == searchText.ToLower();
else if (searchText.StartsWith("i ") || searchText.StartsWith("i:") || searchText.Length == 1)
{ {
if (searchText.Length > 1) if (searchText.Length > 1)
searchText = searchText.Substring(2).Trim(); searchText = searchText.Substring(2).Trim();

View File

@@ -5,7 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
Title="Learn Input" Height="200" Width="400" WindowStartupLocation="CenterOwner" Title="Learn Input" Height="200" Width="400" WindowStartupLocation="CenterOwner"
ResizeMode="NoResize" Loaded="Window_Loaded" Background="Black" MouseWheel="Window_MouseWheel" MouseUp="Window_MouseUp" MouseDoubleClick="Window_MouseDoubleClick"> ResizeMode="NoResize" Loaded="Window_Loaded" Background="Black" MouseWheel="Window_MouseWheel" MouseUp="Window_MouseUp" MouseDoubleClick="Window_MouseDoubleClick" TextInput="Window_TextInput">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />

View File

@@ -10,7 +10,8 @@ namespace mpvnet
public partial class LearnWindow : Window public partial class LearnWindow : Window
{ {
public CommandItem InputItem { get; set; } public CommandItem InputItem { get; set; }
public string NewKey { get; set; } = ""; string NewKey = "";
string KeyChar = "";
public LearnWindow() => InitializeComponent(); public LearnWindow() => InitializeComponent();
@@ -60,9 +61,9 @@ namespace mpvnet
case WF.Keys.NumPad9: case WF.Keys.NumPad9:
text = "KP" + e.KeyCode.ToString()[6].ToString(); break; text = "KP" + e.KeyCode.ToString()[6].ToString(); break;
case WF.Keys.Space: case WF.Keys.Space:
text = "SPACE"; break; text = "Space"; break;
case WF.Keys.Enter: case WF.Keys.Enter:
text = "ENTER"; break; text = "Enter"; break;
case WF.Keys.Tab: case WF.Keys.Tab:
text = "TAB"; break; text = "TAB"; break;
case WF.Keys.Back: case WF.Keys.Back:
@@ -72,7 +73,7 @@ namespace mpvnet
case WF.Keys.Insert: case WF.Keys.Insert:
text = "INS"; break; text = "INS"; break;
case WF.Keys.Home: case WF.Keys.Home:
text = "HOME"; break; text = "Home"; break;
case WF.Keys.End: case WF.Keys.End:
text = "END"; break; text = "END"; break;
case WF.Keys.PageUp: case WF.Keys.PageUp:
@@ -82,56 +83,56 @@ namespace mpvnet
case WF.Keys.Escape: case WF.Keys.Escape:
text = "ESC"; break; text = "ESC"; break;
case WF.Keys.PrintScreen: case WF.Keys.PrintScreen:
text = "PRINT"; break; text = "Print"; break;
case WF.Keys.Play: case WF.Keys.Play:
text = "PLAY"; break; text = "Play"; break;
case WF.Keys.Pause: case WF.Keys.Pause:
text = "PAUSE"; break; text = "Pause"; break;
case WF.Keys.MediaPlayPause: case WF.Keys.MediaPlayPause:
text = "PLAYPAUSE"; break; text = "PlayPause"; break;
case WF.Keys.MediaStop: case WF.Keys.MediaStop:
text = "STOP"; break; text = "Stop"; break;
case WF.Keys.MediaNextTrack: case WF.Keys.MediaNextTrack:
text = "NEXT"; break; text = "Next"; break;
case WF.Keys.MediaPreviousTrack: case WF.Keys.MediaPreviousTrack:
text = "PREV"; break; text = "Prev"; break;
case WF.Keys.VolumeUp: case WF.Keys.VolumeUp:
text = "VOLUME_UP"; break; text = "Volume_Up"; break;
case WF.Keys.VolumeDown: case WF.Keys.VolumeDown:
text = "VOLUME_DOWN"; break; text = "Volume_Down"; break;
case WF.Keys.VolumeMute: case WF.Keys.VolumeMute:
text = "MUTE"; break; text = "Mute"; break;
case WF.Keys.BrowserHome: case WF.Keys.BrowserHome:
text = "HOMEPAGE"; break; text = "Homepage"; break;
case WF.Keys.LaunchMail: case WF.Keys.LaunchMail:
text = "MAIL"; break; text = "Mail"; break;
case WF.Keys.BrowserFavorites: case WF.Keys.BrowserFavorites:
text = "FAVORITES"; break; text = "Favorites"; break;
case WF.Keys.BrowserSearch: case WF.Keys.BrowserSearch:
text = "SEARCH"; break; text = "Search"; break;
case WF.Keys.Sleep: case WF.Keys.Sleep:
text = "SLEEP"; break; text = "Sleep"; break;
case WF.Keys.Cancel: case WF.Keys.Cancel:
text = "CANCEL"; break; text = "Cancel"; break;
} }
bool shiftWasHandled = false; bool wasModified = false;
bool isAlt = GetKeyState(18) < (short)0; bool isAlt = GetKeyState(18) < (short)0;
bool isShift = GetKeyState(16) < (short)0; bool isShift = GetKeyState(16) < (short)0;
bool isCtrl = GetKeyState(17) < (short)0; bool isCtrl = GetKeyState(17) < (short)0;
if (text.Length == 1 && isShift && text[0] != GetModifiedKey(text[0])) if (text.Length == 1 && KeyChar != text)
{ {
text = GetModifiedKey(text[0]).ToString(); text = KeyChar;
shiftWasHandled = true; wasModified = true;
} }
if (text == "#") text = "Sharp"; if (text == "#") text = "SHARP";
if (isAlt) text = "Alt+" + text; if (isAlt && !wasModified) text = "ALT+" + text;
if (isShift && !shiftWasHandled) text = "Shift+" + text; if (isShift && !wasModified) text = "SHIFT+" + text;
if (isCtrl) text = "Ctrl+" + text; if (isCtrl && !wasModified) text = "CTRL+" + text;
if (!string.IsNullOrEmpty(text)) if (!string.IsNullOrEmpty(text))
SetKey(text); SetKey(text);
@@ -163,24 +164,6 @@ namespace mpvnet
} }
} }
public static char GetModifiedKey(char c)
{
short vkKeyScanResult = VkKeyScan(c);
if (vkKeyScanResult == -1)
return c;
uint code = (uint)vkKeyScanResult & 0xff;
byte[] b = new byte[256];
b[0x10] = 0x80;
uint r;
if (1 != ToAscii(code, code, b, out r, 0))
return c;
return (char)r;
}
void ProcessKeyEventArgs(ref WF.Message m) void ProcessKeyEventArgs(ref WF.Message m)
{ {
int WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319; int WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319;
@@ -382,5 +365,10 @@ namespace mpvnet
BlockMBTN_LEFT = true; BlockMBTN_LEFT = true;
} }
} }
private void Window_TextInput(object sender, TextCompositionEventArgs e)
{
KeyChar = e.Text;
}
} }
} }

View File

@@ -0,0 +1,19 @@
<Window x:Class="mpvnet.SetupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="mpv.net OS Setup" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterOwner">
<Grid>
<StackPanel>
<Button Name="RegisterVideo" Margin="5" Click="RegisterVideo_Click">Register video file extensions (requires elevated privileges)</Button>
<Button Name="RegisterAudio" Margin="5" Click="RegisterAudio_Click">Register audio file extensions (requires elevated privileges)</Button>
<Button Name="RegisterImage" Margin="5" Click="RegisterImage_Click">Register image file extensions (requires elevated privileges)</Button>
<Button Name="AddToPathEnvVar" Margin="5" Click="AddToPathEnvVar_Click">Add mpv.net to Path environment variable</Button>
<Button Name="ManageDefaultApps" Margin="5" Click="ManageDefaultApps_Click">Manage Default Apps (Win 10 or higher)</Button>
<Button Name="UnregisterFileAssociations" Margin="5,20,5,5" Click="UnregisterFileAssociations_Click">Unregister file extensions (requires elevated privileges)</Button>
<Button Name="RemoveFromPathEnvVar" Margin="5" Click="RemoveFromPathEnvVar_Click">Remove mpv.net from Path environment variable</Button>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,57 @@
using System;
using System.Diagnostics;
using System.Windows;
using WF = System.Windows.Forms;
namespace mpvnet
{
public partial class SetupWindow : Window
{
public SetupWindow() => InitializeComponent();
void RegisterFileAssociations(string value)
{
using (var proc = new Process())
{
proc.StartInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
proc.StartInfo.Arguments = "--reg-file-assoc " + value;
proc.StartInfo.Verb = "runas";
try { proc.Start(); } catch { }
}
}
private void RegisterVideo_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("video");
private void RegisterAudio_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("audio");
private void RegisterImage_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("image");
private void UnregisterFileAssociations_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("unreg");
private void ManageDefaultApps_Click(object sender, RoutedEventArgs e) => Process.Start("ms-settings:defaultapps");
private void AddToPathEnvVar_Click(object sender, RoutedEventArgs e)
{
string var = WF.Application.StartupPath + ";";
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
if (path.Contains(var))
Msg.ShowWarning("Path was already containing mpv.net.");
else
{
Environment.SetEnvironmentVariable("Path", var + path, EnvironmentVariableTarget.User);
Msg.Show("mpv.net was successfully added to Path.", (var + path).Replace(";","\n"));
}
}
private void RemoveFromPathEnvVar_Click(object sender, RoutedEventArgs e)
{
string var = WF.Application.StartupPath + ";";
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
if (path.Contains(var))
{
Environment.SetEnvironmentVariable("Path", path.Replace(var, ""), EnvironmentVariableTarget.User);
Msg.Show("mpv.net was successfully removed from Path.");
}
else
Msg.ShowWarning("Path was not containing mpv.net.");
}
}
}

View File

@@ -2,7 +2,6 @@
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
@@ -50,8 +49,6 @@ namespace mpvnet
ContextMenu.Opened += ContextMenu_Opened; ContextMenu.Opened += ContextMenu_Opened;
ContextMenu.Opening += ContextMenu_Opening; ContextMenu.Opening += ContextMenu_Opening;
App.ProcessCommandLineEarly();
if (mp.Screen == -1) mp.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen); if (mp.Screen == -1) mp.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
int targetIndex = mp.Screen; int targetIndex = mp.Screen;
Screen[] screens = Screen.AllScreens; Screen[] screens = Screen.AllScreens;
@@ -75,8 +72,7 @@ namespace mpvnet
mp.VideoSizeChanged += VideoSizeChanged; mp.VideoSizeChanged += VideoSizeChanged;
mp.FileLoaded += FileLoaded; mp.FileLoaded += FileLoaded;
mp.Idle += Idle; mp.Idle += Idle;
mp.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
if (Height < FontHeight * 4) SetFormPosAndSize();
mp.observe_property_bool("fullscreen", PropChangeFullscreen); mp.observe_property_bool("fullscreen", PropChangeFullscreen);
mp.observe_property_bool("ontop", PropChangeOnTop); mp.observe_property_bool("ontop", PropChangeOnTop);
mp.observe_property_bool("border", PropChangeBorder); mp.observe_property_bool("border", PropChangeBorder);
@@ -84,6 +80,9 @@ namespace mpvnet
mp.observe_property_string("aid", PropChangeAid); mp.observe_property_string("aid", PropChangeAid);
mp.observe_property_string("vid", PropChangeVid); mp.observe_property_string("vid", PropChangeVid);
mp.observe_property_int("edition", PropChangeEdition); mp.observe_property_int("edition", PropChangeEdition);
if (mp.GPUAPI != "vulkan") mp.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
if (Height < FontHeight * 4) SetFormPosAndSize();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -239,7 +238,7 @@ namespace mpvnet
int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * mp.Autofit); int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * mp.Autofit);
if (mp.VideoSize.Height == 0 || mp.VideoSize.Width == 0 || if (mp.VideoSize.Height == 0 || mp.VideoSize.Width == 0 ||
mp.VideoSize.Width / (float)mp.VideoSize.Height < 1.3) mp.VideoSize.Width / (float)mp.VideoSize.Height < App.MinimumAspectRatio)
mp.VideoSize = new Size((int)(autoFitHeight * (16 / 9.0)), autoFitHeight); mp.VideoSize = new Size((int)(autoFitHeight * (16 / 9.0)), autoFitHeight);
@@ -310,8 +309,11 @@ namespace mpvnet
if (enabled) if (enabled)
{ {
if (WindowState != FormWindowState.Maximized) if (WindowState != FormWindowState.Maximized || FormBorderStyle != FormBorderStyle.None)
{ {
if (WindowState == FormWindowState.Maximized)
WindowState = FormWindowState.Minimized;
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized; WindowState = FormWindowState.Maximized;
} }
@@ -325,7 +327,7 @@ namespace mpvnet
if (mp.Border) if (mp.Border)
FormBorderStyle = FormBorderStyle.Sizable; FormBorderStyle = FormBorderStyle.Sizable;
else else
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
SetFormPosAndSize(); SetFormPosAndSize();
} }
@@ -367,7 +369,7 @@ namespace mpvnet
string path = mp.get_property_string("path"); string path = mp.get_property_string("path");
BeginInvoke(new Action(() => { BeginInvoke(new Action(() => {
if (File.Exists(path) || path.Contains("://")) if (File.Exists(path) || path.Contains("://"))
Text = PathHelp.GetFileName(path) + " - mpv.net " + Application.ProductVersion; Text = path.FileName() + " - mpv.net " + Application.ProductVersion;
else else
Text = "mpv.net " + Application.ProductVersion; Text = "mpv.net " + Application.ProductVersion;
})); }));
@@ -467,22 +469,6 @@ namespace mpvnet
base.WndProc(ref m); base.WndProc(ref m);
} }
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(DataFormats.Text))
e.Effect = DragDropEffects.Copy;
}
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop))
mp.Load(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control));
if (e.Data.GetDataPresent(DataFormats.Text))
mp.Load(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control));
}
void Timer_Tick(object sender, EventArgs e) void Timer_Tick(object sender, EventArgs e)
{ {
if (CursorHelp.IsPosDifferent(LastCursorPosChanged)) if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
@@ -524,9 +510,10 @@ namespace mpvnet
protected override void OnShown(EventArgs e) protected override void OnShown(EventArgs e)
{ {
base.OnShown(e); base.OnShown(e);
if (mp.GPUAPI == "vulkan") mp.ProcessCommandLine();
var wpfColor = WPF.WPF.ThemeColor; var wpfColor = WPF.WPF.ThemeColor;
Color color = Color.FromArgb(wpfColor.A, wpfColor.R, wpfColor.G, wpfColor.B); Color color = Color.FromArgb(wpfColor.A, wpfColor.R, wpfColor.G, wpfColor.B);
ToolStripRendererEx.InitColors(color, App.IsDarkMode); ToolStripRendererEx.InitColors(color, App.IsDarkMode, App.ThemedMenu);
BuildMenu(); BuildMenu();
ContextMenuStrip = ContextMenu; ContextMenuStrip = ContextMenu;
WPF.WPF.Init(); WPF.WPF.Init();
@@ -588,6 +575,22 @@ namespace mpvnet
mp.commandv("quit"); mp.commandv("quit");
} }
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(DataFormats.Text))
e.Effect = DragDropEffects.Copy;
}
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop))
mp.Load(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control));
if (e.Data.GetDataPresent(DataFormats.Text))
mp.Load(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control));
}
protected override void OnLostFocus(EventArgs e) protected override void OnLostFocus(EventArgs e)
{ {
base.OnLostFocus(e); base.OnLostFocus(e);

View File

@@ -131,8 +131,6 @@ public class MenuItem : ToolStripMenuItem
public class ToolStripRendererEx : ToolStripSystemRenderer public class ToolStripRendererEx : ToolStripSystemRenderer
{ {
public static bool IsDarkMode { get; set; }
public static Color ColorForeground { get; set; } = Color.Black; public static Color ColorForeground { get; set; } = Color.Black;
public static Color ColorTheme { get; set; } public static Color ColorTheme { get; set; }
public static Color ColorChecked { get; set; } public static Color ColorChecked { get; set; }
@@ -141,34 +139,33 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
public static Color ColorSelection { get; set; } public static Color ColorSelection { get; set; }
public static Color ColorBackground { get; set; } public static Color ColorBackground { get; set; }
public static Color ColorToolStrip1 { get; set; }
public static Color ColorToolStrip2 { get; set; }
public static Color ColorToolStrip3 { get; set; }
public static Color ColorToolStrip4 { get; set; }
int TextOffset; int TextOffset;
public static void InitColors(Color c, bool darkMode) public static void InitColors(Color themeColor, bool darkMode, bool themed)
{ {
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(160);
ColorSelection = HSLColor.Convert(c).ToColorSetLuminosity(180);
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(210);
ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240);
if (darkMode) if (darkMode)
{ {
ColorBorder = Color.White; ColorBorder = Color.White;
ColorBackground = Color.FromArgb(50, 50, 50); ColorBackground = Color.FromArgb(50, 50, 50);
ColorSelection = Color.FromArgb(80, 80, 80); ColorSelection = Color.FromArgb(80, 80, 80);
ColorForeground = Color.White;
if (themed)
ColorForeground = themeColor;
else
ColorForeground = Color.White;
ColorChecked = Color.FromArgb(90, 90, 90); ColorChecked = Color.FromArgb(90, 90, 90);
} }
else
{
if (!themed) themeColor = Color.FromArgb(238, 238, 238);
ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1))); ColorBorder = HSLColor.Convert(themeColor).ToColorSetLuminosity(100);
ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f))); ColorChecked = HSLColor.Convert(themeColor).ToColorSetLuminosity(160);
ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f))); ColorSelection = HSLColor.Convert(themeColor).ToColorSetLuminosity(180);
ColorToolStrip4 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.4f))); ColorBackground = HSLColor.Convert(themeColor).ToColorSetLuminosity(210);
ColorTop = HSLColor.Convert(themeColor).ToColorSetLuminosity(240);
}
} }
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
@@ -200,17 +197,6 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
base.OnRenderItemText(e); base.OnRenderItemText(e);
} }
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
if (!(e.ToolStrip is ToolStripDropDownMenu) && !(e.ToolStrip.LayoutStyle == ToolStripLayoutStyle.VerticalStackWithOverflow))
{
Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height);
using (SolidBrush b = new SolidBrush(ColorToolStrip2))
e.Graphics.FillRectangle(b, r);
}
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{ {
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size); Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);

View File

@@ -114,11 +114,16 @@
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Misc\App.cs" />
<Compile Include="Misc\Extension.cs" /> <Compile Include="Misc\Extension.cs" />
<Page Include="Controls\SearchTextBoxUserControl.xaml"> <Page Include="Controls\SearchTextBoxUserControl.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
<Page Include="WPF\SetupWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="WPF\AboutWindow.xaml"> <Page Include="WPF\AboutWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
@@ -146,6 +151,7 @@
<DependentUpon>StringSettingControl.xaml</DependentUpon> <DependentUpon>StringSettingControl.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="DynamicGUI\Tommy.cs" /> <Compile Include="DynamicGUI\Tommy.cs" />
<Compile Include="Misc\ExtensionMethods.cs" />
<Compile Include="Native\MediaInfo.cs" /> <Compile Include="Native\MediaInfo.cs" />
<Compile Include="WinForms\Menu.cs"> <Compile Include="WinForms\Menu.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
@@ -172,6 +178,9 @@
<Compile Include="Misc\Program.cs" /> <Compile Include="Misc\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Native\TaskDialog.cs" /> <Compile Include="Native\TaskDialog.cs" />
<Compile Include="WPF\SetupWindow.xaml.cs">
<DependentUpon>SetupWindow.xaml</DependentUpon>
</Compile>
<Compile Include="WPF\EverythingWindow.xaml.cs"> <Compile Include="WPF\EverythingWindow.xaml.cs">
<DependentUpon>EverythingWindow.xaml</DependentUpon> <DependentUpon>EverythingWindow.xaml</DependentUpon>
</Compile> </Compile>

View File

@@ -54,30 +54,34 @@ namespace mpvnet
public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW
public static event Action Hook; // MPV_EVENT_HOOK public static event Action Hook; // MPV_EVENT_HOOK
public static IntPtr Handle { get; set; } public static event Action Initialized;
public static IntPtr WindowHandle { get; set; }
public static Extension Extension { get; set; }
public static bool IsLogoVisible { set; get; }
public static bool IsQuitNeeded { set; get; } = true;
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<bool>>>(); public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<bool>>>();
public static List<KeyValuePair<string, Action<int>>> IntPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<int>>>(); public static List<KeyValuePair<string, Action<int>>> IntPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<int>>>();
public static List<KeyValuePair<string, Action<string>>> StringPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<string>>>(); public static List<KeyValuePair<string, Action<string>>> StringPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<string>>>();
public static Size VideoSize { get; set; }
public static List<PythonScript> PythonScripts { get; set; } = new List<PythonScript>();
public static AutoResetEvent ShutdownAutoResetEvent { get; set; } = new AutoResetEvent(false);
public static AutoResetEvent VideoSizeAutoResetEvent { get; set; } = new AutoResetEvent(false);
public static List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>(); public static List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public static List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>(); public static List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>();
public static IntPtr Handle { get; set; }
public static IntPtr WindowHandle { get; set; }
public static Extension Extension { get; set; }
public static List<PythonScript> PythonScripts { get; set; } = new List<PythonScript>();
public static Size VideoSize { get; set; }
public static AutoResetEvent ShutdownAutoResetEvent { get; set; } = new AutoResetEvent(false);
public static AutoResetEvent VideoSizeAutoResetEvent { get; set; } = new AutoResetEvent(false);
public static string InputConfPath { get; } = ConfigFolder + "\\input.conf"; public static string InputConfPath { get; } = ConfigFolder + "\\input.conf";
public static string ConfPath { get; } = ConfigFolder + "\\mpv.conf"; public static string ConfPath { get; } = ConfigFolder + "\\mpv.conf";
public static string Sid { get; set; } = ""; public static string Sid { get; set; } = "";
public static string Aid { get; set; } = ""; public static string Aid { get; set; } = "";
public static string Vid { get; set; } = ""; public static string Vid { get; set; } = "";
public static string GPUAPI { get; set; } = "auto";
public static bool IsLogoVisible { set; get; }
public static bool IsQuitNeeded { set; get; } = true;
public static bool Fullscreen { get; set; } public static bool Fullscreen { get; set; }
public static bool Border { get; set; } = true; public static bool Border { get; set; } = true;
public static int Screen { get; set; } = -1; public static int Screen { get; set; } = -1;
public static int Edition { get; set; } public static int Edition { get; set; }
@@ -89,6 +93,7 @@ namespace mpvnet
{ {
LoadLibrary("mpv-1.dll"); LoadLibrary("mpv-1.dll");
Handle = mpv_create(); Handle = mpv_create();
Task.Run(() => { EventLoop(); });
if (App.IsStartedFromTerminal) if (App.IsStartedFromTerminal)
{ {
@@ -96,20 +101,24 @@ namespace mpvnet
set_property_string("msg-level", "osd/libass=fatal"); set_property_string("msg-level", "osd/libass=fatal");
} }
set_property_string("config-dir", ConfigFolder);
set_property_string("osc", "yes");
set_property_string("config", "yes");
set_property_string("wid", MainForm.Hwnd.ToString()); set_property_string("wid", MainForm.Hwnd.ToString());
set_property_string("osc", "yes");
set_property_string("force-window", "yes"); set_property_string("force-window", "yes");
set_property_string("input-media-keys", "yes"); set_property_string("input-media-keys", "yes");
set_property_string("config-dir", ConfigFolder);
set_property_string("config", "yes");
mpv_initialize(Handle); mpv_initialize(Handle);
Initialized?.Invoke();
ShowLogo(); ShowLogo();
ProcessCommandLine(); LoadMpvScripts();
Task.Run(() => { EventLoop(); }); if (GPUAPI != "vulkan") ProcessCommandLine();
} }
public static void ProcessProperty(string name, string value) public static void ProcessProperty(string name, string value)
{ {
if (name.Any(char.IsUpper)) Msg.ShowError("Uppercase char detected: " + name, "mpv properties using the command line and the mpv.conf config file are required to be lowercase.");
switch (name) switch (name)
{ {
case "autofit": case "autofit":
@@ -128,6 +137,7 @@ namespace mpvnet
case "fullscreen": Fullscreen = value == "yes"; break; case "fullscreen": Fullscreen = value == "yes"; break;
case "border": Border = value == "yes"; break; case "border": Border = value == "yes"; break;
case "screen": Screen = Convert.ToInt32(value); break; case "screen": Screen = Convert.ToInt32(value); break;
case "gpu-api": GPUAPI = value; break;
} }
} }
@@ -137,17 +147,16 @@ namespace mpvnet
get { get {
if (_ConfigFolder == null) if (_ConfigFolder == null)
{ {
_ConfigFolder = Application.StartupPath + "\\portable_config\\"; string portableFolder = PathHelp.StartupPath + "portable_config\\";
_ConfigFolder = portableFolder;
if (!Directory.Exists(_ConfigFolder)) if (!Directory.Exists(_ConfigFolder))
_ConfigFolder = RegHelp.GetString(App.RegPath, "ConfigFolder"); _ConfigFolder = RegHelp.GetString(App.RegPath, "ConfigFolder");
if (!Directory.Exists(_ConfigFolder)) if (!Directory.Exists(_ConfigFolder))
{ {
string portableFolder = Application.StartupPath + "\\portable_config\\";
string appdataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv.net\\"; string appdataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv.net\\";
string appdataFolderMpv = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\"; string appdataFolderMpv = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
string startupFolder = Application.StartupPath + "\\";
using (TaskDialog<string> td = new TaskDialog<string>()) using (TaskDialog<string> td = new TaskDialog<string>())
{ {
@@ -155,7 +164,6 @@ namespace mpvnet
td.AddCommandLink(@"AppData\Roaming\mpv.net", appdataFolder, appdataFolder); td.AddCommandLink(@"AppData\Roaming\mpv.net", appdataFolder, appdataFolder);
td.AddCommandLink(@"AppData\Roaming\mpv", appdataFolderMpv, appdataFolderMpv); td.AddCommandLink(@"AppData\Roaming\mpv", appdataFolderMpv, appdataFolderMpv);
td.AddCommandLink("<startup>\\portable_config", portableFolder, portableFolder); td.AddCommandLink("<startup>\\portable_config", portableFolder, portableFolder);
td.AddCommandLink("<startup>", startupFolder, startupFolder);
td.AddCommandLink("Choose custom folder", "custom"); td.AddCommandLink("Choose custom folder", "custom");
td.AllowCancel = false; td.AllowCancel = false;
_ConfigFolder = td.Show(); _ConfigFolder = td.Show();
@@ -166,6 +174,7 @@ namespace mpvnet
using (var d = new WinForms.FolderBrowserDialog()) using (var d = new WinForms.FolderBrowserDialog())
{ {
d.Description = "Choose a folder."; d.Description = "Choose a folder.";
if (d.ShowDialog() == WinForms.DialogResult.OK) if (d.ShowDialog() == WinForms.DialogResult.OK)
_ConfigFolder = d.SelectedPath + "\\"; _ConfigFolder = d.SelectedPath + "\\";
else else
@@ -174,6 +183,12 @@ namespace mpvnet
} }
} }
if (PathHelp.StartupPath == _ConfigFolder)
{
Msg.ShowError("Startup folder and config folder cannot be identical, using portable_config instead.");
_ConfigFolder = portableFolder;
}
if (!Directory.Exists(_ConfigFolder)) if (!Directory.Exists(_ConfigFolder))
Directory.CreateDirectory(_ConfigFolder); Directory.CreateDirectory(_ConfigFolder);
@@ -203,41 +218,53 @@ namespace mpvnet
if (File.Exists(ConfPath)) if (File.Exists(ConfPath))
foreach (var i in File.ReadAllLines(ConfPath)) foreach (var i in File.ReadAllLines(ConfPath))
if (i.Contains("=") && ! i.StartsWith("#")) if (i.Contains("=") && !i.TrimStart().StartsWith("#"))
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim(); _Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
foreach (var i in Conf) foreach (var i in _Conf)
ProcessProperty(i.Key, i.Value); ProcessProperty(i.Key, i.Value);
} }
return _Conf; return _Conf;
} }
} }
public static void LoadMpvScripts()
{
if (Directory.Exists(PathHelp.StartupPath + "Scripts"))
{
string[] startupScripts = Directory.GetFiles(PathHelp.StartupPath + "Scripts");
foreach (string path in startupScripts)
if ((path.EndsWith(".lua") || path.EndsWith(".js")) && KnownScripts.Contains(Path.GetFileName(path)))
commandv("load-script", $"{path}");
}
}
public static string[] KnownScripts { get; } = { "osc-visibility.js", "show-playlist.js", "seek-show-position.py", "repl.lua" };
public static void LoadScripts() public static void LoadScripts()
{ {
if (Directory.Exists(PathHelp.StartupPath + "Scripts"))
if (Directory.Exists(Application.StartupPath + "\\Scripts"))
{ {
string[] startupScripts = Directory.GetFiles(Application.StartupPath + "\\Scripts"); foreach (string path in Directory.GetFiles(PathHelp.StartupPath + "Scripts"))
{
foreach (string scriptPath in startupScripts) if (KnownScripts.Contains(Path.GetFileName(path)))
if (scriptPath.EndsWith(".lua") || scriptPath.EndsWith(".js")) {
commandv("load-script", $"{scriptPath}"); if (path.EndsWith(".py"))
PythonScripts.Add(new PythonScript(File.ReadAllText(path)));
foreach (string scriptPath in startupScripts) else if (path.EndsWith(".ps1"))
if (Path.GetExtension(scriptPath) == ".py") PowerShellScript.Init(path);
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath))); }
else
foreach (string scriptPath in startupScripts) Msg.ShowError("Failed to load script", path + "\n\nOnly scripts that ship with mpv.net are allowed in <startup>\\scripts\n\nUser scripts have to use <config folder>\\scripts\n\nNever copy or install a new mpv.net version over a old mpv.net version.");
if (Path.GetExtension(scriptPath) == ".ps1") }
PowerShellScript.Init(scriptPath);
} }
if (Directory.Exists(ConfigFolder + "Scripts")) if (Directory.Exists(ConfigFolder + "Scripts"))
foreach (string scriptPath in Directory.GetFiles(ConfigFolder + "Scripts")) foreach (string scriptPath in Directory.GetFiles(ConfigFolder + "Scripts"))
if (Path.GetExtension(scriptPath) == ".py") if (scriptPath.EndsWith(".py"))
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath))); PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
else if (Path.GetExtension(scriptPath) == ".ps1") else if (scriptPath.EndsWith(".ps1"))
PowerShellScript.Init(scriptPath); PowerShellScript.Init(scriptPath);
} }
@@ -538,7 +565,7 @@ namespace mpvnet
StringPropChangeActions.Add(new KeyValuePair<string, Action<string>>(name, action)); StringPropChangeActions.Add(new KeyValuePair<string, Action<string>>(name, action));
} }
protected static void ProcessCommandLine() public static void ProcessCommandLine()
{ {
var args = Environment.GetCommandLineArgs().Skip(1); var args = Environment.GetCommandLineArgs().Skip(1);
List<string> files = new List<string>(); List<string> files = new List<string>();
@@ -562,10 +589,17 @@ namespace mpvnet
{ {
string left = i.Substring(2, i.IndexOf("=") - 2); string left = i.Substring(2, i.IndexOf("=") - 2);
string right = i.Substring(left.Length + 3); string right = i.Substring(left.Length + 3);
set_property_string(left, right, true); mp.ProcessProperty(left, right);
if (!App.ProcessProperty(left, right))
set_property_string(left, right, true);
} }
else else
set_property_string(i.Substring(2), "yes", true); {
string name = i.Substring(2);
mp.ProcessProperty(name, "yes");
if (!App.ProcessProperty(name, "yes"))
set_property_string(name, "yes", true);
}
} }
catch (Exception e) catch (Exception e)
{ {
@@ -596,7 +630,7 @@ namespace mpvnet
LastLoad = DateTime.Now; LastLoad = DateTime.Now;
for (int i = 0; i < files.Length; i++) for (int i = 0; i < files.Length; i++)
if (App.SubtitleTypes.Contains(Path.GetExtension(files[i]).TrimStart('.').ToLower())) if (App.SubtitleTypes.Contains(files[i].ShortExt()))
commandv("sub-add", files[i]); commandv("sub-add", files[i]);
else else
if (i == 0 && !append) if (i == 0 && !append)
@@ -612,14 +646,15 @@ namespace mpvnet
public static void LoadFolder() public static void LoadFolder()
{ {
if (!App.AutoLoadFolder) return;
Thread.Sleep(200); // user reported race condition Thread.Sleep(200); // user reported race condition
string path = get_property_string("path"); string path = get_property_string("path");
if (!File.Exists(path) || get_property_int("playlist-count") != 1) return; if (!File.Exists(path) || get_property_int("playlist-count") != 1) return;
List<string> files = Directory.GetFiles(Path.GetDirectoryName(path)).ToList(); List<string> files = Directory.GetFiles(Path.GetDirectoryName(path)).ToList();
files = files.Where((file) => files = files.Where((file) =>
App.VideoTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower()) || App.VideoTypes.Contains(file.ShortExt()) ||
App.AudioTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower()) || App.AudioTypes.Contains(file.ShortExt()) ||
App.ImageTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower())).ToList(); App.ImageTypes.Contains(file.ShortExt())).ToList();
files.Sort(new StringLogicalComparer()); files.Sort(new StringLogicalComparer());
int index = files.IndexOf(path); int index = files.IndexOf(path);
files.Remove(path); files.Remove(path);
@@ -628,7 +663,7 @@ namespace mpvnet
if (index > 0) commandv("playlist-move", "0", (index + 1).ToString()); if (index > 0) commandv("playlist-move", "0", (index + 1).ToString());
} }
static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers) public static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
{ {
int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel) int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel)
byteArrayPointers = new IntPtr[numberOfStrings]; byteArrayPointers = new IntPtr[numberOfStrings];
@@ -646,7 +681,7 @@ namespace mpvnet
return rootPointer; return rootPointer;
} }
static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr unmanagedStringArray, int StringCount) public static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr unmanagedStringArray, int StringCount)
{ {
IntPtr[] intPtrArray = new IntPtr[StringCount]; IntPtr[] intPtrArray = new IntPtr[StringCount];
string[] stringArray = new string[StringCount]; string[] stringArray = new string[StringCount];
@@ -658,7 +693,7 @@ namespace mpvnet
return stringArray; return stringArray;
} }
static string StringFromNativeUtf8(IntPtr nativeUtf8) public static string StringFromNativeUtf8(IntPtr nativeUtf8)
{ {
int len = 0; int len = 0;
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len; while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
@@ -667,7 +702,7 @@ namespace mpvnet
return Encoding.UTF8.GetString(buffer); return Encoding.UTF8.GetString(buffer);
} }
static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0"); public static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
static string LastHistoryPath; static string LastHistoryPath;
static DateTime LastHistoryStartDateTime; static DateTime LastHistoryStartDateTime;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB