Compare commits
12 Commits
v7.0.0.1
...
v7.0.0.3-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ea3fbc917 | ||
|
|
b23542d681 | ||
|
|
e0616dee76 | ||
|
|
cd54e67b87 | ||
|
|
9d4779fd96 | ||
|
|
d4d147e5fc | ||
|
|
35b17bc620 | ||
|
|
3eb4af5e75 | ||
|
|
49f22a1f81 | ||
|
|
7cd5686488 | ||
|
|
0d63feec57 | ||
|
|
0ee8318ca4 |
@@ -1,4 +1,30 @@
|
||||
|
||||
# v7.0.0.3 Beta (2023-12-15)
|
||||
|
||||
- New conf editor option `Video/libplacebo/preset`.
|
||||
- New conf editor option `Video/libplacebo/Scaling/upscaler`.
|
||||
- New menu item `Settings/Setup/Add mpv.net to Path environment variable' added.
|
||||
- New menu item `Settings/Edit mpv.conf` added for opening mpv.conf with a text editor. Default binding `c`.
|
||||
- New menu item `Settings/Edit input.conf` added for opening input.conf with a text editor. Default binding `k`.
|
||||
- mpv.net can no longer be downloaded from the Microsoft store due
|
||||
to a general very poor experience with the package creation and submission.
|
||||
I've submitted mpv.net to the winget package repository, it's not yet processed.
|
||||
- Improved conf file reader/writer.
|
||||
- Conf editor support added for the mpv options:
|
||||
`reset-on-next-file`, `input-ipc-server`, `background`, `title`
|
||||
- Conf editor crash fixed.
|
||||
- When mpv.net is started for the first time from a new startup location, it asks if mpv.net should be added to the Path environment variable.
|
||||
|
||||
# v7.0.0.2 Beta (2023-12-13)
|
||||
|
||||
- Besides a portable download there is now again a setup installer.
|
||||
- Fix dynamic menu items missing in context menu.
|
||||
- Fix certain binding setups shown poorly or incorrectly in the main menu.
|
||||
- Fix conf editor not remembering the search text.
|
||||
- Fix quit-watch-later not working.
|
||||
- New option `menu-syntax`. Default: `#menu:`
|
||||
- New zhongfly libmpv build.
|
||||
|
||||
# v7.0.0.1 Beta (2023-12-11)
|
||||
|
||||
- [.NET 6 is a new requirement](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
|
||||
|
||||
@@ -42,13 +42,11 @@ differences are documented in this manual under [Differences compared to mpv](#d
|
||||
Download
|
||||
--------
|
||||
|
||||
1. [Stable via Microsoft Store](https://www.microsoft.com/store/productId/9N64SQZTB3LM)
|
||||
1. [Stable and beta portable and setup via GitHub download](../../../releases)
|
||||
|
||||
2. [Stable and beta portable via GitHub download](../../../releases)
|
||||
2. Stable via command line from winget: `winget install mpv.net`
|
||||
|
||||
3. Stable via command line from Microsoft Store: `winget install mpv.net`
|
||||
|
||||
4. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions)
|
||||
3. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions)
|
||||
|
||||
[Changelog](changelog.md)
|
||||
|
||||
@@ -204,6 +202,9 @@ mpv.net specific commands
|
||||
|
||||
mpv.net commands are used when mpv commands don't exist or lack a feature.
|
||||
|
||||
### add-to-path
|
||||
Adds mpv.net to the Path environment variable.
|
||||
|
||||
### load-audio
|
||||
Shows a file browser dialog to open external audio files.
|
||||
|
||||
@@ -390,6 +391,10 @@ For single files automatically load the entire directory into the playlist.
|
||||
|
||||
### General
|
||||
|
||||
#### --menu-syntax=\<value\>
|
||||
|
||||
Used menu syntax for defining the context menu in input.conf.\nmpv.net by default uses `#menu:`, uosc uses `#!` by default.
|
||||
|
||||
#### --process-instance=\<value\>
|
||||
|
||||
Defines if more then one mpv.net process is allowed.
|
||||
|
||||
@@ -23,3 +23,12 @@ dotnet_diagnostic.IDE0044.severity = silent
|
||||
|
||||
# Member does not access instance data and can be marked as static
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
# IDE0057: Use range operator
|
||||
csharp_style_prefer_range_operator = false
|
||||
|
||||
# CA1401: P/Invokes should not be visible
|
||||
dotnet_diagnostic.CA1401.severity = none
|
||||
|
||||
# IDE0017: Simplify object initialization
|
||||
dotnet_style_object_initializer = false
|
||||
|
||||
@@ -90,6 +90,9 @@ public class ConfParser
|
||||
{
|
||||
string line = it.Trim();
|
||||
|
||||
if (line.StartsWith('#'))
|
||||
continue;
|
||||
|
||||
if (line == "")
|
||||
{
|
||||
currentGroup = new ConfSection();
|
||||
|
||||
@@ -11,6 +11,9 @@ using MpvNet.Windows.WinForms;
|
||||
using MpvNet.Windows.WPF.Views;
|
||||
using MpvNet.Windows.WPF;
|
||||
using MpvNet.Windows.WPF.MsgBox;
|
||||
using MpvNet.Help;
|
||||
using System.Text.Json;
|
||||
using MpvNet.Windows.Help;
|
||||
|
||||
namespace MpvNet;
|
||||
|
||||
@@ -45,6 +48,9 @@ public class GuiCommand
|
||||
["show-menu"] = args => ShowMenu?.Invoke(),
|
||||
["show-bindings"] = args => ShowBindings(),
|
||||
["show-playlist"] = args => ShowPlaylist(),
|
||||
["add-to-path"] = args => AddToPath(),
|
||||
["edit-conf-file"] = EditCongFile,
|
||||
["show-commands"] = args => ShowCommands(),
|
||||
|
||||
|
||||
// deprecated
|
||||
@@ -98,6 +104,53 @@ public class GuiCommand
|
||||
Player.LoadDiskFolder(dialog.SelectedPath);
|
||||
}
|
||||
|
||||
public void EditCongFile(IList<string> args)
|
||||
{
|
||||
string file = Player.ConfigFolder + args[0];
|
||||
|
||||
if (File.Exists(file))
|
||||
ProcessHelp.ShellExecute(WinApiHelp.GetAppPathForExtension("txt"), "\"" + file + "\"");
|
||||
}
|
||||
|
||||
public static void ShowTextWithEditor(string name, string text)
|
||||
{
|
||||
string file = Path.Combine(Path.GetTempPath(), name + ".txt");
|
||||
App.TempFiles.Add(file);
|
||||
File.WriteAllText(file, BR + text.Trim() + BR);
|
||||
ProcessHelp.ShellExecute(WinApiHelp.GetAppPathForExtension("txt"), "\"" + file + "\"");
|
||||
}
|
||||
|
||||
public static void ShowCommands()
|
||||
{
|
||||
string json = Core.GetPropertyString("command-list");
|
||||
var enumerator = JsonDocument.Parse(json).RootElement.EnumerateArray();
|
||||
var commands = enumerator.OrderBy(it => it.GetProperty("name").GetString());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (var cmd in commands)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(cmd.GetProperty("name").GetString());
|
||||
|
||||
foreach (var args in cmd.GetProperty("args").EnumerateArray())
|
||||
{
|
||||
string value = args.GetProperty("name").GetString() + " <" +
|
||||
args.GetProperty("type").GetString()!.ToLower() + ">";
|
||||
|
||||
if (args.GetProperty("optional").GetBoolean())
|
||||
value = "[" + value + "]";
|
||||
|
||||
sb.AppendLine(" " + value);
|
||||
}
|
||||
}
|
||||
|
||||
string header = BR +
|
||||
"https://mpv.io/manual/master/#list-of-input-commands" + BR2 +
|
||||
"https://github.com/stax76/mpv-scripts#command_palette" + BR;
|
||||
|
||||
ShowTextWithEditor("Input Commands", header + sb.ToString());
|
||||
}
|
||||
|
||||
public void OpenFromClipboard(IList<string> args)
|
||||
{
|
||||
if (System.Windows.Forms.Clipboard.ContainsFileDropList())
|
||||
@@ -248,7 +301,7 @@ public class GuiCommand
|
||||
text = text.TrimEx();
|
||||
|
||||
if (editor)
|
||||
Command.ShowTextWithEditor("media-info", text);
|
||||
ShowTextWithEditor("media-info", text);
|
||||
else if (osd)
|
||||
Command.ShowText(text.Replace("\r", ""), 5000, 16);
|
||||
else
|
||||
@@ -261,7 +314,24 @@ public class GuiCommand
|
||||
|
||||
public static string FormatTime(double value) => ((int)value).ToString("00");
|
||||
|
||||
public void ShowBindings() => Command.ShowTextWithEditor("Bindings", Player.UsedInputConfContent);
|
||||
public void ShowBindings() => ShowTextWithEditor("Bindings", Player.UsedInputConfContent);
|
||||
|
||||
public void AddToPath()
|
||||
{
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User)!;
|
||||
|
||||
if (path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower()))
|
||||
{
|
||||
Msg.ShowWarning("mpv.net is already in Path.");
|
||||
return;
|
||||
}
|
||||
|
||||
Environment.SetEnvironmentVariable("Path",
|
||||
Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path,
|
||||
EnvironmentVariableTarget.User);
|
||||
|
||||
Msg.ShowInfo("mpv.net successfully was added to Path.");
|
||||
}
|
||||
|
||||
public void ShowPlaylist()
|
||||
{
|
||||
|
||||
126
src/MpvNet.Windows/Help/WinApiHelp.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
using static MpvNet.Windows.Native.WinApi;
|
||||
|
||||
namespace MpvNet.Windows.Help;
|
||||
|
||||
public class WinApiHelp
|
||||
{
|
||||
public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607
|
||||
|
||||
public static int GetResizeBorder(int v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case 1 /* WMSZ_LEFT */ : return 3;
|
||||
case 3 /* WMSZ_TOP */ : return 2;
|
||||
case 2 /* WMSZ_RIGHT */ : return 3;
|
||||
case 6 /* WMSZ_BOTTOM */ : return 2;
|
||||
case 4 /* WMSZ_TOPLEFT */ : return 1;
|
||||
case 5 /* WMSZ_TOPRIGHT */ : return 1;
|
||||
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
|
||||
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SubtractWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
Rect r = new Rect(0, 0, 0, 0);
|
||||
AddWindowBorders(hwnd, ref r, dpi);
|
||||
rc.Left -= r.Left;
|
||||
rc.Top -= r.Top;
|
||||
rc.Right -= r.Right;
|
||||
rc.Bottom -= r.Bottom;
|
||||
}
|
||||
|
||||
public static void AddWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
uint windowStyle = (uint)GetWindowLong(hwnd, -16); // GWL_STYLE
|
||||
uint windowStyleEx = (uint)GetWindowLong(hwnd, -20); // GWL_EXSTYLE
|
||||
|
||||
if (Environment.OSVersion.Version >= WindowsTen1607)
|
||||
AdjustWindowRectExForDpi(ref rc, windowStyle, false, windowStyleEx, (uint)dpi);
|
||||
else
|
||||
AdjustWindowRect(ref rc, windowStyle, false);
|
||||
}
|
||||
|
||||
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
|
||||
{
|
||||
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out Rect dwmRect) &&
|
||||
GetWindowRect(handle, out Rect rect))
|
||||
{
|
||||
int left = workingArea.Left;
|
||||
int top = workingArea.Top;
|
||||
int right = workingArea.Right;
|
||||
int bottom = workingArea.Bottom;
|
||||
|
||||
left += rect.Left - dwmRect.Left;
|
||||
top -= rect.Top - dwmRect.Top;
|
||||
right -= dwmRect.Right - rect.Right;
|
||||
bottom -= dwmRect.Bottom - rect.Bottom;
|
||||
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
return workingArea;
|
||||
}
|
||||
|
||||
public static bool GetDwmWindowRect(IntPtr handle, out Rect rect)
|
||||
{
|
||||
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
|
||||
|
||||
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||
out rect, (uint)Marshal.SizeOf<Rect>());
|
||||
}
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLongPtr(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
}
|
||||
|
||||
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
|
||||
else
|
||||
return SetWindowLong32(hWnd, nIndex, dwNewLong);
|
||||
}
|
||||
|
||||
public static string GetAppPathForExtension(params string[] extensions)
|
||||
{
|
||||
foreach (string it in extensions)
|
||||
{
|
||||
string extension = it;
|
||||
|
||||
if (!extension.StartsWith("."))
|
||||
extension = "." + extension;
|
||||
|
||||
uint c = 0U;
|
||||
|
||||
if (AssocQueryString(0x40, 2, extension, null, null, ref c) == 1)
|
||||
{
|
||||
if (c > 0L)
|
||||
{
|
||||
var sb = new StringBuilder((int)c);
|
||||
|
||||
if (0 == AssocQueryString(0x40, 2, extension, default, sb, ref c))
|
||||
{
|
||||
string ret = sb.ToString();
|
||||
|
||||
if (File.Exists(ret))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,36 @@
|
||||
|
||||
using MpvNet.ExtensionMethod;
|
||||
using System.Windows;
|
||||
|
||||
using MpvNet.Windows.WPF;
|
||||
|
||||
namespace MpvNet.Windows.Help;
|
||||
|
||||
public class WinMpvHelp
|
||||
{
|
||||
public static void CopyMpvNetCom()
|
||||
public static void AddToPath()
|
||||
{
|
||||
string dir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).AddSep() +
|
||||
"Microsoft\\WindowsApps\\";
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User)!;
|
||||
|
||||
if (File.Exists(dir + "mpvnet.exe") && !File.Exists(dir + "mpvnet.com"))
|
||||
File.Copy(Folder.Startup + "mpvnet.com", dir + "mpvnet.com");
|
||||
if (path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower()))
|
||||
return;
|
||||
|
||||
string dir = RegistryHelp.GetString("PathEnvVarCheck");
|
||||
|
||||
if (dir == Folder.Startup)
|
||||
return;
|
||||
|
||||
var result = Msg.ShowQuestion("Would you like to add mpv.net to the Path environment variable?",
|
||||
MessageBoxButton.YesNo);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("Path",
|
||||
Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path,
|
||||
EnvironmentVariableTarget.User);
|
||||
|
||||
Msg.ShowInfo("mpv.net was added successfully to Path.");
|
||||
}
|
||||
|
||||
RegistryHelp.SetString("PathEnvVarCheck", Folder.Startup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,19 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>mpv-icon.ico</ApplicationIcon>
|
||||
<Product>mpv.net</Product>
|
||||
<AssemblyVersion>7.0.0.1</AssemblyVersion>
|
||||
<FileVersion>7.0.0.1</FileVersion>
|
||||
<FileVersion>7.0.0.3</FileVersion>
|
||||
<AssemblyVersion>7.0.0.3</AssemblyVersion>
|
||||
<InformationalVersion>7.0.0.3</InformationalVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Misc\**" />
|
||||
<EmbeddedResource Remove="Misc\**" />
|
||||
<None Remove="Misc\**" />
|
||||
<Page Remove="Misc\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="mpv-icon.ico" />
|
||||
</ItemGroup>
|
||||
@@ -38,8 +46,4 @@
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Misc\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace MpvNet.Windows.Native;
|
||||
|
||||
public static class WinApi
|
||||
{
|
||||
public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AttachConsole(int dwProcessId);
|
||||
|
||||
@@ -60,18 +59,10 @@ public static class WinApi
|
||||
IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
|
||||
static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLongPtr(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
}
|
||||
public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
|
||||
public static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, uint dwNewLong);
|
||||
@@ -79,50 +70,17 @@ public static class WinApi
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, uint dwNewLong);
|
||||
|
||||
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
|
||||
else
|
||||
return SetWindowLong32(hWnd, nIndex, dwNewLong);
|
||||
}
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[DllImport("shlwapi", CharSet = CharSet.Auto)]
|
||||
public static extern uint AssocQueryString(
|
||||
uint flags, uint str, string? pszAssoc, string? pszExtra, [Out] StringBuilder? pszOut, ref uint pcchOut);
|
||||
|
||||
[DllImport("dwmapi.dll")]
|
||||
public static extern int DwmGetWindowAttribute(
|
||||
IntPtr hwnd, uint dwAttribute, out Rect pvAttribute, uint cbAttribute);
|
||||
|
||||
public static bool GetDwmWindowRect(IntPtr handle, out Rect rect)
|
||||
{
|
||||
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
|
||||
|
||||
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||
out rect, (uint)Marshal.SizeOf<Rect>());
|
||||
}
|
||||
|
||||
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
|
||||
{
|
||||
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out Rect dwmRect) &&
|
||||
GetWindowRect(handle, out Rect rect))
|
||||
{
|
||||
int left = workingArea.Left;
|
||||
int top = workingArea.Top;
|
||||
int right = workingArea.Right;
|
||||
int bottom = workingArea.Bottom;
|
||||
|
||||
left += rect.Left - dwmRect.Left;
|
||||
top -= rect.Top - dwmRect.Top;
|
||||
right -= dwmRect.Right - rect.Right;
|
||||
bottom -= dwmRect.Bottom - rect.Bottom;
|
||||
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
return workingArea;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Rect
|
||||
{
|
||||
@@ -171,41 +129,4 @@ public static class WinApi
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpData;
|
||||
}
|
||||
|
||||
public static int GetResizeBorder(int v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case 1 /* WMSZ_LEFT */ : return 3;
|
||||
case 3 /* WMSZ_TOP */ : return 2;
|
||||
case 2 /* WMSZ_RIGHT */ : return 3;
|
||||
case 6 /* WMSZ_BOTTOM */ : return 2;
|
||||
case 4 /* WMSZ_TOPLEFT */ : return 1;
|
||||
case 5 /* WMSZ_TOPRIGHT */ : return 1;
|
||||
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
|
||||
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SubtractWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
Rect r = new Rect(0, 0, 0, 0);
|
||||
AddWindowBorders(hwnd, ref r, dpi);
|
||||
rc.Left -= r.Left;
|
||||
rc.Top -= r.Top;
|
||||
rc.Right -= r.Right;
|
||||
rc.Bottom -= r.Bottom;
|
||||
}
|
||||
|
||||
public static void AddWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
|
||||
{
|
||||
uint windowStyle = (uint)GetWindowLong(hwnd, -16); // GWL_STYLE
|
||||
uint windowStyleEx = (uint)GetWindowLong(hwnd, -20); // GWL_EXSTYLE
|
||||
|
||||
if (Environment.OSVersion.Version >= WindowsTen1607)
|
||||
AdjustWindowRectExForDpi(ref rc, windowStyle, false, windowStyleEx, (uint)dpi);
|
||||
else
|
||||
AdjustWindowRect(ref rc, windowStyle, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,137 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity
|
||||
Name="5664FrankSkare.mpv.net"
|
||||
Publisher="CN=6A1A1E69-736C-4C77-B310-7B6D38E32617"
|
||||
Version="6.0.3.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>mpv.net</DisplayName>
|
||||
<PublisherDisplayName>Frank Skare</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="mpv.net"
|
||||
Description="mpv.net is a modern media player based on the popular mpv player."
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Images\Square150x150Logo.png"
|
||||
Square44x44Logo="Images\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
<uap3:Extension Category="windows.appExecutionAlias">
|
||||
<uap3:AppExecutionAlias>
|
||||
<desktop:ExecutionAlias Alias="MpvNet.exe" />
|
||||
</uap3:AppExecutionAlias>
|
||||
</uap3:Extension>
|
||||
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="videotypes">
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.264</uap:FileType>
|
||||
<uap:FileType>.265</uap:FileType>
|
||||
<uap:FileType>.asf</uap:FileType>
|
||||
<uap:FileType>.avc</uap:FileType>
|
||||
<uap:FileType>.avi</uap:FileType>
|
||||
<uap:FileType>.avs</uap:FileType>
|
||||
<uap:FileType>.dav</uap:FileType>
|
||||
<uap:FileType>.flv</uap:FileType>
|
||||
<uap:FileType>.h264</uap:FileType>
|
||||
<uap:FileType>.h265</uap:FileType>
|
||||
<uap:FileType>.hevc</uap:FileType>
|
||||
<uap:FileType>.m2t</uap:FileType>
|
||||
<uap:FileType>.m2ts</uap:FileType>
|
||||
<uap:FileType>.m2v</uap:FileType>
|
||||
<uap:FileType>.m4v</uap:FileType>
|
||||
<uap:FileType>.mkv</uap:FileType>
|
||||
<uap:FileType>.mov</uap:FileType>
|
||||
<uap:FileType>.mp4</uap:FileType>
|
||||
<uap:FileType>.mpeg</uap:FileType>
|
||||
<uap:FileType>.mpg</uap:FileType>
|
||||
<uap:FileType>.mpv</uap:FileType>
|
||||
<uap:FileType>.mts</uap:FileType>
|
||||
<uap:FileType>.ts</uap:FileType>
|
||||
<uap:FileType>.vob</uap:FileType>
|
||||
<uap:FileType>.vpy</uap:FileType>
|
||||
<uap:FileType>.webm</uap:FileType>
|
||||
<uap:FileType>.wmv</uap:FileType>
|
||||
<uap:FileType>.y4m</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
</uap:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.fileTypeAssociation">
|
||||
<uap:FileTypeAssociation Name="audiotypes">
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:FileType>.aac</uap:FileType>
|
||||
<uap:FileType>.ac3</uap:FileType>
|
||||
<uap:FileType>.dts</uap:FileType>
|
||||
<uap:FileType>.dtshd</uap:FileType>
|
||||
<uap:FileType>.dtshr</uap:FileType>
|
||||
<uap:FileType>.dtsma</uap:FileType>
|
||||
<uap:FileType>.eac3</uap:FileType>
|
||||
<uap:FileType>.flac</uap:FileType>
|
||||
<uap:FileType>.m4a</uap:FileType>
|
||||
<uap:FileType>.mka</uap:FileType>
|
||||
<uap:FileType>.mp2</uap:FileType>
|
||||
<uap:FileType>.mp3</uap:FileType>
|
||||
<uap:FileType>.mpa</uap:FileType>
|
||||
<uap:FileType>.mpc</uap:FileType>
|
||||
<uap:FileType>.ogg</uap:FileType>
|
||||
<uap:FileType>.opus</uap:FileType>
|
||||
<uap:FileType>.thd</uap:FileType>
|
||||
<uap:FileType>.w64</uap:FileType>
|
||||
<uap:FileType>.wav</uap:FileType>
|
||||
</uap:SupportedFileTypes>
|
||||
</uap:FileTypeAssociation>
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="ytdl" />
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="rtsp" />
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="srt" />
|
||||
</uap:Extension>
|
||||
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="srtp" />
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
@@ -1,78 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '15.0'">
|
||||
<VisualStudioVersion>15.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>81daee3a-76ff-4494-9384-d28a651d70bb</ProjectGuid>
|
||||
<TargetPlatformVersion>10.0.22000.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
|
||||
<EntryPointProjectUniqueName>..\mpv.net.csproj</EntryPointProjectUniqueName>
|
||||
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
||||
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
||||
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
||||
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
|
||||
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
|
||||
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\bin\MediaInfo.dll">
|
||||
<Link>mpv.net\MediaInfo.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\bin\Microsoft.Management.Infrastructure.dll">
|
||||
<Link>mpv.net\Microsoft.Management.Infrastructure.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\bin\libmpv-2.dll">
|
||||
<Link>mpv.net\libmpv-2.dll</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\bin\mpvnet.com">
|
||||
<Link>mpv.net\mpvnet.com</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Images\SplashScreen.scale-200.png" />
|
||||
<Content Include="Images\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Images\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Images\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Images\StoreLogo.png" />
|
||||
<Content Include="Images\Wide310x150Logo.scale-200.png" />
|
||||
<None Include="Package.StoreAssociation.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.19041.8" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\mpv.net.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -39,6 +39,11 @@ directory = General
|
||||
width = 500
|
||||
help = Image file extensions used to create file associations and used by the auto-load-folder feature. (mpv.net option)
|
||||
|
||||
name = menu-syntax
|
||||
file = mpvnet
|
||||
directory = General
|
||||
help = Used menu syntax for defining the context menu in input.conf.\nmpv.net by default uses '#menu:', uosc uses '#!' by default.
|
||||
|
||||
name = debug-mode
|
||||
file = mpvnet
|
||||
default = no
|
||||
@@ -113,10 +118,18 @@ option = display-adrop
|
||||
option = display-desync
|
||||
option = desync
|
||||
|
||||
name = d3d11va-zero-copy
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
help = By default, when using hardware decoding with --gpu-api=d3d11, the video image will be copied (GPU-to-GPU) from the decoder surface to a shader resource. Set this option to avoid that copy by sampling directly from the decoder image. This may increase performance and reduce power usage, but can cause the image to be sampled incorrectly on the bottom and right edges due to padding, and may invoke driver bugs, since Direct3D 11 technically does not allow sampling from a decoder surface (though most drivers support it.)
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = scale
|
||||
file = mpv
|
||||
default = bilinear
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = The GPU renderer filter function to use when upscaling video. There are some more filters, but most are not as useful. For a complete list, pass help as value, e.g.: mpv --scale=help
|
||||
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
|
||||
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
|
||||
@@ -129,7 +142,7 @@ option = oversample A version of nearest neighbour that (naively) oversam
|
||||
name = cscale
|
||||
file = mpv
|
||||
default = bilinear
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = As scale, but for interpolating chroma information. If the image is not subsampled, this option is ignored entirely.
|
||||
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
|
||||
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
|
||||
@@ -142,7 +155,7 @@ option = oversample A version of nearest neighbour that (naively) oversam
|
||||
name = dscale
|
||||
file = mpv
|
||||
default =
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = Like scale, but apply these filters on downscaling instead. \nIf no option is selected, it will keep the same with the upscaler.
|
||||
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
|
||||
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
|
||||
@@ -155,7 +168,7 @@ option = oversample A version of nearest neighbour that (naively) oversam
|
||||
name = dither-depth
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = Set dither target depth to N. Note that the depth of the connected video display device cannot be detected. Often, LCD panels will do dithering on their own, which conflicts with this option and leads to ugly output.
|
||||
option = no Disable any dithering done by mpv.
|
||||
option = auto Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed.
|
||||
@@ -165,7 +178,7 @@ option = 10 Dither to 10 bit output.
|
||||
name = correct-downscaling
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = When using convolution based filters, extend the filter size when downscaling. Increases quality, but reduces performance while downscaling.\n\nThis will perform slightly sub-optimally for anamorphic video (but still better than without it) since it will extend the size to match only the milder of the scale factors between the axes.
|
||||
option = yes
|
||||
option = no
|
||||
@@ -173,7 +186,7 @@ option = no
|
||||
name = sigmoid-upscaling
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = When upscaling, use a sigmoidal color transform to avoid emphasizing ringing artifacts. This also implies linear-scaling.
|
||||
option = yes
|
||||
option = no
|
||||
@@ -181,23 +194,15 @@ option = no
|
||||
name = deband
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = Enable the debanding algorithm. This greatly reduces the amount of visible banding, blocking and other quantization artifacts, at the expense of very slightly blurring some of the finest details. In practice, it's virtually always an improvement - the only reason to disable it would be for performance.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = d3d11va-zero-copy
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video
|
||||
help = By default, when using hardware decoding with --gpu-api=d3d11, the video image will be copied (GPU-to-GPU) from the decoder surface to a shader resource. Set this option to avoid that copy by sampling directly from the decoder image. This may increase performance and reduce power usage, but can cause the image to be sampled incorrectly on the bottom and right edges due to padding, and may invoke driver bugs, since Direct3D 11 technically does not allow sampling from a decoder surface (though most drivers support it.)
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = hdr-compute-peak
|
||||
file = mpv
|
||||
default = auto
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = Compute the HDR peak and frame average brightness per-frame instead of relying on tagged metadata. These values are averaged over local regions as well as over several frames to prevent the value from jittering around too much. This option basically gives you dynamic, per-scene tone mapping. Requires compute shaders, which is a fairly recent OpenGL feature, and will probably also perform horribly on some drivers, so enable at your own risk. The special value auto (default) will enable HDR peak computation automatically if compute shaders and SSBOs are supported.
|
||||
option = auto
|
||||
option = yes
|
||||
@@ -206,11 +211,111 @@ option = no
|
||||
name = allow-delayed-peak-detect
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video
|
||||
directory = Video/Render Options
|
||||
help = When using --hdr-compute-peak, allow delaying the detected peak by a frame when beneficial for performance. In particular, this is required to avoid an unnecessary FBO indirection when no advanced rendering is required otherwise. Has no effect if there already is an indirect pass, such as when advanced scaling is enabled. (Only affects --vo=gpu-next, note that --vo=gpu always delays the peak.)
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = background
|
||||
file = mpv
|
||||
directory = Video/Render Options
|
||||
help = Color used to draw parts of the mpv window not covered by video. See the --sub-color option for how colors are defined.
|
||||
|
||||
name = libplacebo-opts
|
||||
file = mpv
|
||||
directory = Video/Render Options
|
||||
help = Passes extra raw option to the libplacebo rendering backend (used by --vo=gpu-next). May override the effects of any other options set using the normal options system.
|
||||
|
||||
name = preset
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo
|
||||
default = default
|
||||
help = Override all libplacebo options by the values from the given preset.
|
||||
url = https://libplacebo.org/options/#presetdefaultfasthigh_quality
|
||||
option = default Default settings, tuned to provide a balance of performance and quality.
|
||||
option = fast Disable all advanced rendering, equivalent to passing no to every option.
|
||||
option = high_quality Reset all everything to high quality presets (where available).
|
||||
|
||||
name = upscaler
|
||||
file = libplacebo
|
||||
directory = Video/libplacebo/Scaling
|
||||
default = default
|
||||
help = Sets the filter used for upscaling. Defaults to lanczos.
|
||||
url = https://libplacebo.org/options/#upscalerfilter
|
||||
option = default Default.
|
||||
option = none No filter, only use basic GPU texture sampling.
|
||||
option = nearest Nearest-neighbour (box) sampling (very fast).
|
||||
option = bilinear Bilinear sampling (very fast).
|
||||
option = oversample Aspect-ratio preserving nearest neighbour sampling (very fast).
|
||||
option = bicubic Bicubic interpolation (fast).
|
||||
option = gaussian Gaussian smoothing (fast).
|
||||
option = catmull_rom Catmull-Rom cubic spline.
|
||||
option = lanczos Lanczos reconstruction.
|
||||
option = ewa_lanczos EWA Lanczos ("Jinc") reconstruction (slow).
|
||||
option = ewa_lanczossharp Sharpened version of ewa_lanczos (slow).
|
||||
option = ewa_lanczos4sharpest Very sharp version of ewa_lanczos, with anti-ringing (very slow).
|
||||
|
||||
name = screenshot-directory
|
||||
file = mpv
|
||||
width = 500
|
||||
type = folder
|
||||
directory = Video/Screenshot
|
||||
help = Store screenshots in this directory. This path is joined with the filename generated by screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot.
|
||||
|
||||
name = screenshot-format
|
||||
file = mpv
|
||||
default = jpg
|
||||
directory = Video/Screenshot
|
||||
help = Set the image file type used for saving screenshots.
|
||||
option = jpg
|
||||
option = png
|
||||
|
||||
name = screenshot-tag-colorspace
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video/Screenshot
|
||||
help = Tag screenshots with the appropriate colorspace. Note that not all formats are supported.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-high-bit-depth
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = If possible, write screenshots with a bit depth similar to the source video. This is interesting in particular for PNG, as this sometimes triggers writing 16 bit PNGs with huge file sizes. This will also include an unused alpha channel in the resulting files if 16 bit is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-jpeg-source-chroma
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = Write JPEG files with the same chroma subsampling as the video. If disabled, the libjpeg default is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-template
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
type = string
|
||||
help = Specify the filename template used to save screenshots. The template specifies the filename without file extension, and can contain format specifiers, which will be substituted when taking a screenshot. By default, the template is mpv-shot%n, which results in filenames like mpv-shot0012.png for example.\n\nFind the full documentation here:
|
||||
url = https://mpv.io/manual/master/#options-screenshot-template
|
||||
|
||||
name = screenshot-jpeg-quality
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-100> Set the JPEG quality level. Higher means better quality. The default is 90.
|
||||
|
||||
name = screenshot-png-compression
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-9> Set the PNG compression level. Higher means better compression. This will affect the file size of the written screenshot file and the time it takes to write a screenshot. Too high compression might occupy enough CPU time to interrupt playback. The default is 7.
|
||||
|
||||
name = screenshot-png-filter
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-5> Set the filter applied prior to PNG compression. 0 is none, 1 is 'sub', 2 is 'up', 3 is 'average', 4 is 'Paeth', and 5 is 'mixed'. This affects the level of compression that can be achieved. For most images, 'mixed' achieves the best compression ratio, hence it is the default.
|
||||
|
||||
name = volume
|
||||
file = mpv
|
||||
directory = Audio
|
||||
@@ -425,6 +530,12 @@ file = mpvnet
|
||||
directory = 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. Default: 1500 (mpv.net option)
|
||||
|
||||
name = title
|
||||
file = mpv
|
||||
directory = Window
|
||||
width = 400
|
||||
help = Set the window title. This is used for the video window, and if possible, also sets the audio stream title. Properties are expanded. Warning! There is a danger of this causing significant CPU usage, depending on the properties used.
|
||||
|
||||
name = taskbar-progress
|
||||
file = mpv
|
||||
default = yes
|
||||
@@ -508,6 +619,12 @@ help = For single files automatically load the entire directory into the playlis
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = reset-on-next-file
|
||||
file = mpv
|
||||
directory = Program Behavior
|
||||
help = Normally, mpv will try to keep all settings when playing the next file on the playlist, even if they were changed by the user during playback. This can be changed with this option. It accepts a list of options, and mpv will reset the value of these options on playback start to the initial value.
|
||||
width = 400
|
||||
|
||||
name = input-ar-delay
|
||||
file = mpv
|
||||
directory = Input
|
||||
@@ -518,6 +635,12 @@ file = mpv
|
||||
directory = Input
|
||||
help = Number of key presses to generate per second on autorepeat.
|
||||
|
||||
name = input-ipc-server
|
||||
file = mpv
|
||||
directory = Input
|
||||
help = Enable the IPC support and create the listening socket at the given path.
|
||||
url = https://mpv.io/manual/master/#options-input-ipc-server
|
||||
|
||||
name = language
|
||||
file = mpvnet
|
||||
default = system
|
||||
@@ -550,67 +673,6 @@ directory = UI
|
||||
url = https://github.com/mpvnet-player/mpv.net/blob/main/docs/manual.md#color-theme
|
||||
help = Color theme used in light mode.\nmpv.net must be restarted after a change.\nmpv.net specific option. Default: light
|
||||
|
||||
name = screenshot-directory
|
||||
file = mpv
|
||||
width = 500
|
||||
type = folder
|
||||
directory = Video/Screenshot
|
||||
help = Store screenshots in this directory. This path is joined with the filename generated by screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot.
|
||||
|
||||
name = screenshot-format
|
||||
file = mpv
|
||||
default = jpg
|
||||
directory = Video/Screenshot
|
||||
help = Set the image file type used for saving screenshots.
|
||||
option = jpg
|
||||
option = png
|
||||
|
||||
name = screenshot-tag-colorspace
|
||||
file = mpv
|
||||
default = no
|
||||
directory = Video/Screenshot
|
||||
help = Tag screenshots with the appropriate colorspace. Note that not all formats are supported.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-high-bit-depth
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = If possible, write screenshots with a bit depth similar to the source video. This is interesting in particular for PNG, as this sometimes triggers writing 16 bit PNGs with huge file sizes. This will also include an unused alpha channel in the resulting files if 16 bit is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-jpeg-source-chroma
|
||||
file = mpv
|
||||
default = yes
|
||||
directory = Video/Screenshot
|
||||
help = Write JPEG files with the same chroma subsampling as the video. If disabled, the libjpeg default is used.
|
||||
option = yes
|
||||
option = no
|
||||
|
||||
name = screenshot-template
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
type = string
|
||||
help = Specify the filename template used to save screenshots. The template specifies the filename without file extension, and can contain format specifiers, which will be substituted when taking a screenshot. By default, the template is mpv-shot%n, which results in filenames like mpv-shot0012.png for example.\n\nFind the full documentation here:
|
||||
url = https://mpv.io/manual/master/#options-screenshot-template
|
||||
|
||||
name = screenshot-jpeg-quality
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-100> Set the JPEG quality level. Higher means better quality. The default is 90.
|
||||
|
||||
name = screenshot-png-compression
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-9> Set the PNG compression level. Higher means better compression. This will affect the file size of the written screenshot file and the time it takes to write a screenshot. Too high compression might occupy enough CPU time to interrupt playback. The default is 7.
|
||||
|
||||
name = screenshot-png-filter
|
||||
file = mpv
|
||||
directory = Video/Screenshot
|
||||
help = <0-5> Set the filter applied prior to PNG compression. 0 is none, 1 is 'sub', 2 is 'up', 3 is 'average', 4 is 'Paeth', and 5 is 'mixed'. This affects the level of compression that can be achieved. For most images, 'mixed' achieves the best compression ratio, hence it is the default.
|
||||
|
||||
name = cache
|
||||
file = mpv
|
||||
default = auto
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
@@ -34,13 +35,14 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
DataContext = this;
|
||||
LoadConf(Player.ConfPath);
|
||||
LoadConf(App.ConfPath);
|
||||
LoadLibplaceboConf();
|
||||
LoadSettings();
|
||||
InitialContent = GetCompareString();
|
||||
|
||||
if (string.IsNullOrEmpty(App.Settings.ConfigEditorSearch))
|
||||
SearchControl.Text = "General:";
|
||||
SearchText = "General:";
|
||||
else
|
||||
SearchControl.Text = App.Settings.ConfigEditorSearch;
|
||||
SearchText = App.Settings.ConfigEditorSearch;
|
||||
|
||||
foreach (var node in Nodes)
|
||||
SelectNodeFromSearchText(node);
|
||||
@@ -82,6 +84,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
|
||||
public static TreeNode? AddNode(IList<TreeNode> nodes, string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return null;
|
||||
|
||||
string[] parts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
for (int x = 0; x < parts.Length; x++)
|
||||
@@ -127,14 +132,14 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
if (!FilterStrings.Contains(setting.Directory!))
|
||||
FilterStrings.Add(setting.Directory!);
|
||||
|
||||
foreach (ConfItem confItem in ConfItems)
|
||||
foreach (ConfItem item in ConfItems)
|
||||
{
|
||||
if (setting.Name == confItem.Name && confItem.Section == "" && !confItem.IsSectionItem)
|
||||
if (setting.Name == item.Name && item.Section == "" && !item.IsSectionItem)
|
||||
{
|
||||
setting.Value = confItem.Value.Trim('\'', '"');
|
||||
setting.Value = item.Value;
|
||||
setting.StartValue = setting.Value;
|
||||
setting.ConfItem = confItem;
|
||||
confItem.SettingBase = setting;
|
||||
setting.ConfItem = item;
|
||||
item.SettingBase = setting;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,11 +160,20 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
App.Settings.ConfigEditorSearch = SearchControl.Text;
|
||||
App.Settings.ConfigEditorSearch = SearchText;
|
||||
|
||||
if (InitialContent == GetCompareString())
|
||||
return;
|
||||
|
||||
foreach (Setting setting in Settings)
|
||||
{
|
||||
if (setting.Name == "libplacebo-opts")
|
||||
{
|
||||
setting.Value = GetKeyValueContent("libplacebo");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText(Player.ConfPath, GetContent("mpv"));
|
||||
File.WriteAllText(App.ConfPath, GetContent("mpvnet"));
|
||||
|
||||
@@ -201,10 +215,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
string GetCompareString()
|
||||
{
|
||||
return string.Join("", Settings.Select(item => item.Name + item.Value).ToArray());
|
||||
}
|
||||
string GetCompareString() => string.Join("", Settings.Select(item => item.Name + item.Value).ToArray());
|
||||
|
||||
void LoadConf(string file)
|
||||
{
|
||||
@@ -221,42 +232,47 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
string line = currentLine.Trim();
|
||||
|
||||
if (line == "")
|
||||
{
|
||||
comment += "\r\n";
|
||||
}
|
||||
else if (line.StartsWith("#"))
|
||||
{
|
||||
comment += line.Trim() + "\r\n";
|
||||
}
|
||||
else if (line.StartsWith("[") && line.Contains("]"))
|
||||
else if (line.StartsWith("[") && line.Contains(']'))
|
||||
{
|
||||
if (!isSectionItem && comment != "" && comment != "\r\n")
|
||||
ConfItems.Add(new ConfItem() {
|
||||
Comment = comment, File = Path.GetFileNameWithoutExtension(file)});
|
||||
Comment = comment, File = System.IO.Path.GetFileNameWithoutExtension(file)});
|
||||
|
||||
section = line.Substring(0, line.IndexOf("]") + 1);
|
||||
comment = "";
|
||||
isSectionItem = true;
|
||||
}
|
||||
else if (line.Contains("="))
|
||||
else if (line.Contains('=') || Regex.Match(line, "^[\\w-]+$").Success)
|
||||
{
|
||||
ConfItem item = new ConfItem();
|
||||
item.File = Path.GetFileNameWithoutExtension(file);
|
||||
if (!line.Contains('='))
|
||||
line += "=yes";
|
||||
|
||||
ConfItem item = new();
|
||||
item.File = System.IO.Path.GetFileNameWithoutExtension(file);
|
||||
item.IsSectionItem = isSectionItem;
|
||||
item.Comment = comment;
|
||||
comment = "";
|
||||
item.Section = section;
|
||||
section = "";
|
||||
|
||||
if (line.Contains("#") && !line.Contains("'") && !line.Contains("\""))
|
||||
if (line.Contains('#') && !line.Contains("'") && !line.Contains("\""))
|
||||
{
|
||||
item.LineComment = line.Substring(line.IndexOf("#")).Trim();
|
||||
line = line.Substring(0, line.IndexOf("#")).Trim();
|
||||
}
|
||||
|
||||
int pos = line.IndexOf("=");
|
||||
string left = line.Substring(0, pos).Trim().ToLower();
|
||||
string left = line.Substring(0, pos).Trim().ToLower().TrimStart('-');
|
||||
string right = line.Substring(pos + 1).Trim();
|
||||
|
||||
if (right.StartsWith('\'') && right.EndsWith('\''))
|
||||
right = right.Trim('\'');
|
||||
|
||||
if (right.StartsWith('"') && right.EndsWith('"'))
|
||||
right = right.Trim('"');
|
||||
|
||||
if (left == "fs")
|
||||
left = "fullscreen";
|
||||
@@ -271,6 +287,67 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
}
|
||||
}
|
||||
|
||||
string GetKeyValueContent(string filename)
|
||||
{
|
||||
List<string> pairs = new();
|
||||
|
||||
foreach (Setting setting in Settings)
|
||||
{
|
||||
if (filename != setting.File)
|
||||
continue;
|
||||
|
||||
if ((setting.Value ?? "") != setting.Default)
|
||||
pairs.Add(setting.Name + "=" + EscapeValue(setting.Value!));
|
||||
}
|
||||
|
||||
return string.Join(',', pairs);
|
||||
}
|
||||
|
||||
void LoadLibplaceboConf()
|
||||
{
|
||||
foreach (ConfItem item in ConfItems.ToArray())
|
||||
if (item.Name == "libplacebo-opts")
|
||||
LoadKeyValueList(item.Value, "libplacebo");
|
||||
}
|
||||
|
||||
void LoadKeyValueList(string options, string file)
|
||||
{
|
||||
string[] optionStrings = options.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (string pair in optionStrings)
|
||||
{
|
||||
if (!pair.Contains('='))
|
||||
continue;
|
||||
|
||||
int pos = pair.IndexOf("=");
|
||||
string left = pair.Substring(0, pos).Trim().ToLower();
|
||||
string right = pair.Substring(pos + 1).Trim();
|
||||
|
||||
ConfItem item = new();
|
||||
item.Name = left;
|
||||
item.Value = right;
|
||||
item.File = file;
|
||||
ConfItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
string EscapeValue(string value)
|
||||
{
|
||||
if (value.Contains('\''))
|
||||
return '"' + value + '"';
|
||||
|
||||
if (value.Contains('"'))
|
||||
return '\'' + value + '\'';
|
||||
|
||||
if (value.Contains('"') || value.Contains('#') || value.StartsWith("%") ||
|
||||
value.StartsWith(" ") || value.EndsWith(" "))
|
||||
{
|
||||
return '\'' + value + '\'';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
string GetContent(string filename)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -288,7 +365,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
{
|
||||
if (item.Name != "")
|
||||
{
|
||||
sb.Append(item.Name + " = " + item.Value);
|
||||
sb.Append(item.Name + " = " + EscapeValue(item.Value));
|
||||
|
||||
if (item.LineComment != "")
|
||||
sb.Append(" " + item.LineComment);
|
||||
@@ -299,17 +376,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
}
|
||||
else if ((item.SettingBase.Value ?? "") != item.SettingBase.Default)
|
||||
{
|
||||
string? value;
|
||||
|
||||
if (item.SettingBase.Type == "string" ||
|
||||
item.SettingBase.Type == "folder" ||
|
||||
item.SettingBase.Type == "color")
|
||||
|
||||
value = "'" + item.SettingBase.Value + "'";
|
||||
else
|
||||
value = item.SettingBase.Value;
|
||||
|
||||
sb.Append(item.Name + " = " + value);
|
||||
sb.Append(item.Name + " = " + EscapeValue(item.SettingBase.Value!));
|
||||
|
||||
if (item.LineComment != "")
|
||||
sb.Append(" " + item.LineComment);
|
||||
@@ -319,28 +386,13 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
}
|
||||
}
|
||||
|
||||
if (!sb.ToString().Contains("# Editor"))
|
||||
sb.AppendLine("# Editor");
|
||||
|
||||
foreach (Setting setting in Settings)
|
||||
{
|
||||
if (filename != setting.File || namesWritten.Contains(setting.Name!))
|
||||
continue;
|
||||
|
||||
if ((setting.Value ?? "") != setting.Default)
|
||||
{
|
||||
string? value;
|
||||
|
||||
if (setting.Type == "string" ||
|
||||
setting.Type == "folder" ||
|
||||
setting.Type == "color")
|
||||
|
||||
value = "'" + setting.Value + "'";
|
||||
else
|
||||
value = setting.Value;
|
||||
|
||||
sb.AppendLine(setting.Name + " = " + value);
|
||||
}
|
||||
sb.AppendLine(setting.Name + " = " + EscapeValue(setting.Value!));
|
||||
}
|
||||
|
||||
foreach (ConfItem item in ConfItems)
|
||||
@@ -359,7 +411,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
if (item.Comment != "")
|
||||
sb.Append(item.Comment);
|
||||
|
||||
sb.Append(item.Name + " = " + item.Value);
|
||||
sb.Append(item.Name + " = " + EscapeValue(item.Value));
|
||||
|
||||
if (item.LineComment != "")
|
||||
sb.Append(" " + item.LineComment);
|
||||
@@ -443,7 +495,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
|
||||
void SelectNodeFromSearchText(NodeViewModel node)
|
||||
{
|
||||
if (node.Path + ":" == SearchControl.Text)
|
||||
if (node.Path + ":" == SearchText)
|
||||
{
|
||||
node.IsSelected = true;
|
||||
return;
|
||||
@@ -470,7 +522,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
|
||||
ExpandNode(it);
|
||||
}
|
||||
|
||||
[RelayCommand] void ShowMpvNetSpecificSettings() => SearchControl.Text = "mpv.net";
|
||||
[RelayCommand] void ShowMpvNetSpecificSettings() => SearchText = "mpv.net";
|
||||
|
||||
[RelayCommand] void PreviewMpvConfFile() => Msg.ShowInfo(GetContent("mpv"));
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Windows.Navigation;
|
||||
|
||||
using MpvNet.Help;
|
||||
|
||||
// TODO: change namespace to MpvNet.Windows.WPF.Controls
|
||||
namespace MpvNet.Windows.WPF;
|
||||
|
||||
public class HyperlinkEx : Hyperlink
|
||||
@@ -20,6 +19,6 @@ public class HyperlinkEx : Hyperlink
|
||||
NavigateUri = new Uri(url);
|
||||
RequestNavigate += HyperLinkEx_RequestNavigate;
|
||||
Inlines.Clear();
|
||||
Inlines.Add(url);
|
||||
Inlines.Add("Manual");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public partial class SearchControl : UserControl
|
||||
{
|
||||
HintTextBlock.Text = string.IsNullOrEmpty(Text) ? HintText : "";
|
||||
|
||||
if (string.IsNullOrEmpty(Text) || HideClearButton)
|
||||
if (string.IsNullOrEmpty(Text) || HideClearButton || Text.Length > 21)
|
||||
SearchClearButton.Visibility = Visibility.Hidden;
|
||||
else
|
||||
SearchClearButton.Visibility = Visibility.Visible;
|
||||
|
||||
@@ -109,7 +109,7 @@ public partial class InputWindow : Window
|
||||
else
|
||||
{
|
||||
newContent = InputHelp.ConvertToString(InputHelp.GetReducedBindings(Bindings));
|
||||
newContent = newContent.Replace("#menu: ", "# ");
|
||||
newContent = newContent.Replace(App.MenuSyntax + " ", "# ");
|
||||
File.WriteAllText(App.InputConf.Path, App.InputConf.Content = newContent);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,39 +122,67 @@
|
||||
<Border x:Name="stackButtons" Grid.Row="3" Padding="10"
|
||||
Background="{Binding Path=ButtonBackground}" >
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" >
|
||||
<Button x:Name="btnOK" Content=" OK " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnOK"
|
||||
Content=" OK "
|
||||
MinWidth="75"
|
||||
Margin="5,0,5,0"
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
Height="25"
|
||||
MinHeight="25"
|
||||
Visibility="{Binding Path=ShowOk}"
|
||||
IsDefault="{Binding Path=IsDefaultOK}"
|
||||
Click="BtnOK_Click" />
|
||||
<Button x:Name="btnYes" Content=" Yes " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnYes"
|
||||
Content=" Yes "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowYes}"
|
||||
IsDefault="{Binding Path=IsDefaultYes}"
|
||||
Click="BtnYes_Click"/>
|
||||
<Button x:Name="btnNo" Content=" No " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnNo"
|
||||
Content=" No "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowNo}"
|
||||
IsDefault="{Binding Path=IsDefaultNo}"
|
||||
Click="BtnNo_Click"/>
|
||||
<Button x:Name="btnAbort" Content=" Abort " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnAbort"
|
||||
Content=" Abort "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowAbort}"
|
||||
IsDefault="{Binding Path=IsDefaultAbort}"
|
||||
Click="BtnAbort_Click"/>
|
||||
<Button x:Name="btnRetry" Content=" Retry " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnRetry"
|
||||
Content=" Retry "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowRetry}"
|
||||
IsDefault="{Binding Path=IsDefaultRetry}"
|
||||
Click="BtnRetry_Click"/>
|
||||
<Button x:Name="btnIgnore" Content=" Ignore " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnIgnore"
|
||||
Content=" Ignore "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowIgnore}"
|
||||
IsDefault="{Binding Path=IsDefaultIgnore}"
|
||||
Click="BtnIgnore_Click"/>
|
||||
<Button x:Name="btnCancel" Content=" Cancel " MinWidth="75" Margin="5,0,5,0"
|
||||
<Button x:Name="btnCancel"
|
||||
Content=" Cancel "
|
||||
Width="{Binding Path=ButtonWidth}"
|
||||
MinWidth="75"
|
||||
MinHeight="25"
|
||||
Margin="5,0,5,0"
|
||||
Visibility="{Binding Path=ShowCancel}"
|
||||
IsDefault="{Binding Path=IsDefaultCancel}"
|
||||
Click="BtnCancel_Click"/>
|
||||
|
||||
@@ -96,13 +96,13 @@ public partial class MessageBoxEx : Window, INotifyPropertyChanged
|
||||
|
||||
public static void SetOwner(Window window)
|
||||
{
|
||||
IntPtr ownerHandle = GetOwnerHandle();
|
||||
IntPtr parentHandle = GetParentHandle();
|
||||
|
||||
if (ownerHandle != IntPtr.Zero)
|
||||
new WindowInteropHelper(window).Owner = ownerHandle;
|
||||
if (parentHandle != IntPtr.Zero)
|
||||
new WindowInteropHelper(window).Owner = parentHandle;
|
||||
}
|
||||
|
||||
public static IntPtr GetOwnerHandle()
|
||||
public static IntPtr GetParentHandle()
|
||||
{
|
||||
IntPtr foregroundWindow = GetForegroundWindow();
|
||||
GetWindowThreadProcessId(foregroundWindow, out var procID);
|
||||
|
||||
39
src/MpvNet.Windows/WinForms/MainForm.Designer.cs
generated
@@ -29,36 +29,35 @@ partial class MainForm
|
||||
/// </summary>
|
||||
void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.CursorTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.ProgressTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.SuspendLayout();
|
||||
CursorTimer = new System.Windows.Forms.Timer(components);
|
||||
ProgressTimer = new System.Windows.Forms.Timer(components);
|
||||
SuspendLayout();
|
||||
//
|
||||
// CursorTimer
|
||||
//
|
||||
this.CursorTimer.Enabled = true;
|
||||
this.CursorTimer.Interval = 1000;
|
||||
this.CursorTimer.Tick += new System.EventHandler(this.CursorTimer_Tick);
|
||||
CursorTimer.Enabled = true;
|
||||
CursorTimer.Interval = 1000;
|
||||
CursorTimer.Tick += CursorTimer_Tick;
|
||||
//
|
||||
// ProgressTimer
|
||||
//
|
||||
this.ProgressTimer.Tick += new System.EventHandler(this.ProgressTimer_Tick);
|
||||
ProgressTimer.Tick += ProgressTimer_Tick;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AllowDrop = true;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.BackColor = System.Drawing.Color.Black;
|
||||
this.ClientSize = new System.Drawing.Size(857, 444);
|
||||
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.Name = "MainForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.ResumeLayout(false);
|
||||
|
||||
AllowDrop = true;
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
BackColor = System.Drawing.Color.Black;
|
||||
ClientSize = new System.Drawing.Size(1243, 720);
|
||||
Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
Icon = (System.Drawing.Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
Name = "MainForm";
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -27,7 +27,6 @@ public partial class MainForm : Form
|
||||
public SnapManager SnapManager = new SnapManager();
|
||||
public IntPtr MpvWindowHandle { get; set; }
|
||||
public ElementHost? CommandPaletteHost { get; set; }
|
||||
public Dictionary<string, WpfControls.MenuItem> MenuItemDuplicate = new Dictionary<string, WpfControls.MenuItem>();
|
||||
public bool WasShown { get; set; }
|
||||
public static MainForm? Instance { get; set; }
|
||||
WpfControls.ContextMenu ContextMenu { get; } = new WpfControls.ContextMenu();
|
||||
@@ -211,7 +210,7 @@ public partial class MainForm : Form
|
||||
{
|
||||
BeginInvoke(() => {
|
||||
Screen screen = Screen.FromControl(this);
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
@@ -286,7 +285,7 @@ public partial class MainForm : Form
|
||||
|
||||
lock (Player.MediaTracksLock)
|
||||
{
|
||||
var trackMenuItem = FindMenuItem(_("Track"));
|
||||
var trackMenuItem = FindMenuItem(_("Track"), "Track");
|
||||
|
||||
if (trackMenuItem != null)
|
||||
{
|
||||
@@ -348,7 +347,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var chaptersMenuItem = FindMenuItem(_("Chapter"));
|
||||
var chaptersMenuItem = FindMenuItem(_("Chapter"), "Chapters");
|
||||
|
||||
if (chaptersMenuItem != null)
|
||||
{
|
||||
@@ -369,7 +368,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var recentMenuItem = FindMenuItem(_("Recent Files"));
|
||||
var recentMenuItem = FindMenuItem(_("Recent Files"), "Recent");
|
||||
|
||||
if (recentMenuItem != null)
|
||||
{
|
||||
@@ -391,7 +390,7 @@ public partial class MainForm : Form
|
||||
recentMenuItem.Items.Add(clearMenuItem);
|
||||
}
|
||||
|
||||
var titlesMenuItem = FindMenuItem(_("Title"));
|
||||
var titlesMenuItem = FindMenuItem(_("Title"), "Titles");
|
||||
|
||||
if (titlesMenuItem != null)
|
||||
{
|
||||
@@ -424,7 +423,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var profilesMenuItem = FindMenuItem(_("Profile"));
|
||||
var profilesMenuItem = FindMenuItem(_("Profile"), "Profile");
|
||||
|
||||
if (profilesMenuItem != null && !profilesMenuItem.HasItems)
|
||||
{
|
||||
@@ -446,7 +445,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
var customMenuItem = FindMenuItem(_("Custom"));
|
||||
var customMenuItem = FindMenuItem(_("Custom"), "Custom");
|
||||
|
||||
if (customMenuItem != null)
|
||||
{
|
||||
@@ -476,7 +475,14 @@ public partial class MainForm : Form
|
||||
}
|
||||
}
|
||||
|
||||
public WpfControls.MenuItem? FindMenuItem(string text) => FindMenuItem(text, ContextMenu.Items);
|
||||
public WpfControls.MenuItem? FindMenuItem(string text, string text2 = "") {
|
||||
var ret = FindMenuItem(text, ContextMenu.Items);
|
||||
|
||||
if (ret == null && text2 != "")
|
||||
return FindMenuItem(text2, ContextMenu.Items);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WpfControls.MenuItem? FindMenuItem(string text, WpfControls.ItemCollection? items)
|
||||
{
|
||||
@@ -515,7 +521,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
|
||||
Screen screen = Screen.FromControl(this);
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
int autoFitHeight = Convert.ToInt32(workingArea.Height * Player.Autofit);
|
||||
|
||||
if (App.AutofitAudio > 1)
|
||||
@@ -604,7 +610,7 @@ public partial class MainForm : Form
|
||||
|
||||
void SetSize(int width, int height, Screen screen, bool checkAutofit = true)
|
||||
{
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
|
||||
int maxHeight = workingArea.Height - (Height - ClientSize.Height) - 2;
|
||||
int maxWidth = workingArea.Width - (Width - ClientSize.Width);
|
||||
@@ -647,7 +653,7 @@ public partial class MainForm : Form
|
||||
|
||||
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
||||
var rect = new Rect(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
||||
AddWindowBorders(Handle, ref rect, GetDpi(Handle));
|
||||
WinApiHelp.AddWindowBorders(Handle, ref rect, GetDpi(Handle));
|
||||
|
||||
int left = middlePos.X - rect.Width / 2;
|
||||
int top = middlePos.Y - rect.Height / 2;
|
||||
@@ -662,10 +668,10 @@ public partial class MainForm : Form
|
||||
|
||||
Screen[] screens = Screen.AllScreens;
|
||||
|
||||
int minLeft = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).X).Min();
|
||||
int maxRight = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Right).Max();
|
||||
int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min();
|
||||
int maxBottom = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
|
||||
int minLeft = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).X).Min();
|
||||
int maxRight = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Right).Max();
|
||||
int minTop = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Y).Min();
|
||||
int maxBottom = screens.Select(val => WinApiHelp.GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
|
||||
|
||||
if (left < minLeft)
|
||||
left = minLeft;
|
||||
@@ -728,7 +734,7 @@ public partial class MainForm : Form
|
||||
|
||||
public int GetHorizontalLocation(Screen screen)
|
||||
{
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
|
||||
|
||||
if (workingArea.Width / (float)Width < 1.1)
|
||||
@@ -745,7 +751,7 @@ public partial class MainForm : Form
|
||||
|
||||
public int GetVerticalLocation(Screen screen)
|
||||
{
|
||||
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, screen.WorkingArea);
|
||||
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
|
||||
|
||||
if (workingArea.Height / (float)Height < 1.1)
|
||||
@@ -767,17 +773,12 @@ public partial class MainForm : Form
|
||||
|
||||
var (menuBindings, confBindings) = App.InputConf.GetBindings();
|
||||
_confBindings = confBindings;
|
||||
var activeBindings = InputHelp.GetActiveBindings(menuBindings);
|
||||
|
||||
foreach (Binding binding in menuBindings)
|
||||
{
|
||||
Binding tempBinding = binding;
|
||||
|
||||
if (MenuItemDuplicate.ContainsKey(tempBinding.Command) && tempBinding.Input != "")
|
||||
{
|
||||
var mi = MenuItemDuplicate[tempBinding.Command];
|
||||
mi.InputGestureText = mi.InputGestureText + ", " + tempBinding.Input;
|
||||
}
|
||||
|
||||
if (!binding.IsMenu)
|
||||
continue;
|
||||
|
||||
@@ -785,9 +786,6 @@ public partial class MainForm : Form
|
||||
|
||||
if (menuItem != null)
|
||||
{
|
||||
if (tempBinding.Input != "")
|
||||
MenuItemDuplicate[tempBinding.Command] = menuItem;
|
||||
|
||||
menuItem.Click += (sender, args) => {
|
||||
try {
|
||||
TaskHelp.Run(() => {
|
||||
@@ -803,7 +801,7 @@ public partial class MainForm : Form
|
||||
}
|
||||
};
|
||||
|
||||
menuItem.InputGestureText = tempBinding.Input;
|
||||
menuItem.InputGestureText = InputHelp.GetBindingsForCommand(activeBindings, tempBinding.Command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,7 +1018,7 @@ public partial class MainForm : Form
|
||||
{
|
||||
Rect rc = Marshal.PtrToStructure<Rect>(m.LParam);
|
||||
Rect r = rc;
|
||||
SubtractWindowBorders(Handle, ref r, GetDpi(Handle));
|
||||
WinApiHelp.SubtractWindowBorders(Handle, ref r, GetDpi(Handle));
|
||||
|
||||
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
|
||||
Size videoSize = Player.VideoSize;
|
||||
@@ -1034,7 +1032,7 @@ public partial class MainForm : Form
|
||||
|
||||
int[] d_corners = { d_w, d_h, -d_w, -d_h };
|
||||
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
|
||||
int corner = GetResizeBorder(m.WParam.ToInt32());
|
||||
int corner = WinApiHelp.GetResizeBorder(m.WParam.ToInt32());
|
||||
|
||||
if (corner >= 0)
|
||||
corners[corner] -= d_corners[corner];
|
||||
@@ -1252,9 +1250,14 @@ public partial class MainForm : Form
|
||||
InitAndBuildContextMenu();
|
||||
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
|
||||
GlobalHotkey.RegisterGlobalHotkeys(Handle);
|
||||
TaskHelp.Run(WinMpvHelp.CopyMpvNetCom);
|
||||
WasShown = true;
|
||||
StrongReferenceMessenger.Default.Send(new MainWindowIsLoadedMessage());
|
||||
|
||||
TaskHelp.Run(() => {
|
||||
System.Windows.Application.Current.Dispatcher.BeginInvoke(() => {
|
||||
WinMpvHelp.AddToPath();
|
||||
}, DispatcherPriority.Background);
|
||||
});
|
||||
}
|
||||
|
||||
void ContextMenu_Closed(object sender, System.Windows.RoutedEventArgs e) => MenuAutoResetEvent.Set();
|
||||
@@ -1386,7 +1389,7 @@ public partial class MainForm : Form
|
||||
|
||||
public static int GetDpi(IntPtr hwnd)
|
||||
{
|
||||
if (Environment.OSVersion.Version >= WindowsTen1607 && hwnd != IntPtr.Zero)
|
||||
if (Environment.OSVersion.Version >= WinApiHelp.WindowsTen1607 && hwnd != IntPtr.Zero)
|
||||
return GetDpiForWindow(hwnd);
|
||||
else
|
||||
using (Graphics gx = Graphics.FromHwnd(hwnd))
|
||||
|
||||
@@ -1,4 +1,64 @@
|
||||
<root>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using MpvNet.Windows.Help;
|
||||
using MpvNet.Windows.Native;
|
||||
|
||||
using static MpvNet.Windows.Native.WinApi;
|
||||
|
||||
namespace MpvNet.Windows.WinForms;
|
||||
|
||||
public class SnapManager
|
||||
@@ -35,7 +34,7 @@ public class SnapManager
|
||||
void FindSnap(ref Rectangle effectiveBounds)
|
||||
{
|
||||
Screen currentScreen = Screen.FromPoint(effectiveBounds.Location);
|
||||
Rectangle workingArea = GetWorkingArea(Handle, currentScreen.WorkingArea);
|
||||
Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, currentScreen.WorkingArea);
|
||||
|
||||
if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance))
|
||||
effectiveBounds.X = workingArea.Left + AnchorDistance;
|
||||
|
||||
@@ -20,21 +20,77 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -20,6 +20,7 @@ public class AppClass
|
||||
public string StartSize { get; set; } = "height-session";
|
||||
public string Language { get; set; } = "system";
|
||||
public string CommandLine { get; set; } = Environment.CommandLine;
|
||||
public string MenuSyntax { get; set; } = "#menu:";
|
||||
|
||||
public bool AutoLoadFolder { get; set; } = true;
|
||||
public bool DebugMode { get; set; }
|
||||
@@ -145,6 +146,7 @@ public class AppClass
|
||||
case "language": Language = value; return true;
|
||||
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
|
||||
case "media-info": MediaInfo = value == "yes"; return true;
|
||||
case "menu-syntax": MenuSyntax = value; return true;
|
||||
case "minimum-aspect-ratio-audio": MinimumAspectRatioAudio = value.ToFloat(); return true;
|
||||
case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true;
|
||||
case "process-instance": ProcessInstance = value; return true;
|
||||
|
||||
@@ -18,7 +18,6 @@ public class Command
|
||||
["play-pause"] = PlayPause,
|
||||
["shell-execute"] = args => ProcessHelp.ShellExecute(args[0]),
|
||||
["show-text"] = args => ShowText(args[0], Convert.ToInt32(args[1]), Convert.ToInt32(args[2])),
|
||||
["show-commands"] = args => ShowCommands(),
|
||||
["cycle-audio"] = args => CycleAudio(),
|
||||
["cycle-subtitles"] = args => CycleSubtitles(),
|
||||
["playlist-first"] = args => PlaylistFirst(),
|
||||
@@ -52,37 +51,6 @@ public class Command
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowCommands()
|
||||
{
|
||||
string json = Core.GetPropertyString("command-list");
|
||||
var enumerator = JsonDocument.Parse(json).RootElement.EnumerateArray();
|
||||
var commands = enumerator.OrderBy(it => it.GetProperty("name").GetString());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (var cmd in commands)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(cmd.GetProperty("name").GetString());
|
||||
|
||||
foreach (var args in cmd.GetProperty("args").EnumerateArray())
|
||||
{
|
||||
string value = args.GetProperty("name").GetString() + " <" +
|
||||
args.GetProperty("type").GetString()!.ToLower() + ">";
|
||||
|
||||
if (args.GetProperty("optional").GetBoolean())
|
||||
value = "[" + value + "]";
|
||||
|
||||
sb.AppendLine(" " + value);
|
||||
}
|
||||
}
|
||||
|
||||
string header = BR +
|
||||
"https://mpv.io/manual/master/#list-of-input-commands" + BR2 +
|
||||
"https://github.com/stax76/mpv-scripts#command_palette" + BR;
|
||||
|
||||
ShowTextWithEditor("Input Commands", header + sb.ToString());
|
||||
}
|
||||
|
||||
public static void ShowText(string text, int duration = 0, int fontSize = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
@@ -98,14 +66,6 @@ public class Command
|
||||
"}${osd-ass-cc/1}" + text + "\" " + duration);
|
||||
}
|
||||
|
||||
public static void ShowTextWithEditor(string name, string text)
|
||||
{
|
||||
string file = Path.Combine(Path.GetTempPath(), name + ".txt");
|
||||
App.TempFiles.Add(file);
|
||||
File.WriteAllText(file, BR + text.Trim() + BR);
|
||||
ProcessHelp.ShellExecute(file);
|
||||
}
|
||||
|
||||
public static void CycleAudio()
|
||||
{
|
||||
Player.UpdateExternalTracks();
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
namespace MpvNet.Help;
|
||||
|
||||
namespace MpvNet.Help;
|
||||
|
||||
public static class ProcessHelp
|
||||
{
|
||||
public static void Execute(string file, string arguments = "", bool shellExecute = false)
|
||||
{
|
||||
using Process proc = new Process();
|
||||
proc.StartInfo.FileName = file;
|
||||
proc.StartInfo.Arguments = arguments;
|
||||
proc.StartInfo.UseShellExecute = shellExecute;
|
||||
proc.Start();
|
||||
try
|
||||
{
|
||||
using Process proc = new Process();
|
||||
proc.StartInfo.FileName = file;
|
||||
proc.StartInfo.Arguments = arguments;
|
||||
proc.StartInfo.UseShellExecute = shellExecute;
|
||||
proc.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Terminal.WriteError(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShellExecute(string file, string arguments = "") => Execute(file, arguments, true);
|
||||
|
||||
@@ -20,7 +20,7 @@ public class InputConf
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasMenu => Content.Contains("#menu:") || Content.Contains("#! ");
|
||||
public bool HasMenu => Content.Contains(App.MenuSyntax + " ");
|
||||
|
||||
public (List<Binding> menuBindings, List<Binding>? confBindings) GetBindings()
|
||||
{
|
||||
|
||||
@@ -149,11 +149,16 @@ public static class InputHelp
|
||||
|
||||
new (_("Settings"), _("Show Config Editor"), "script-message-to mpvnet show-conf-editor", "Ctrl+,"),
|
||||
new (_("Settings"), _("Show Input Editor"), "script-message-to mpvnet show-input-editor", "Ctrl+i"),
|
||||
new (_("Settings"), "-"),
|
||||
new (_("Settings"), _("Edit mpv.conf"), "script-message-to mpvnet edit-conf-file mpv.conf", "c"),
|
||||
new (_("Settings"), _("Edit input.conf"), "script-message-to mpvnet edit-conf-file input.conf", "k"),
|
||||
new (_("Settings"), "-"),
|
||||
new (_("Settings"), _("Open Config Folder"), "script-message-to mpvnet open-conf-folder", "Ctrl+f"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Register video file associations"), "script-message-to mpvnet reg-file-assoc video"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Register audio file associations"), "script-message-to mpvnet reg-file-assoc audio"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Register image file associations"), "script-message-to mpvnet reg-file-assoc image"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Unregister file associations"), "script-message-to mpvnet reg-file-assoc unreg"),
|
||||
new (_("Settings") + " > " + _("Setup"), _("Add mpv.net to Path environment variable"), "script-message-to mpvnet add-to-path"),
|
||||
|
||||
new (_("Tools"), _("Set/clear A-B loop points"), "ab-loop", "l"),
|
||||
new (_("Tools"), _("Toggle infinite file looping"), "cycle-values loop-file inf no", "L"),
|
||||
@@ -174,11 +179,10 @@ public static class InputHelp
|
||||
|
||||
new ("", "", "quit", "q", _("Exit")),
|
||||
new ("", "", "script-message-to mpvnet show-menu", "MBTN_Right", _("Show Menu")),
|
||||
new ("", "", "quit", "Power", _("Exit")),
|
||||
new ("", "", "cycle pause", "Play", _("Play/Pause")),
|
||||
new ("", "", "cycle pause", "Pause", _("Play/Pause")),
|
||||
new ("", "", "cycle pause", "PlayPause", _("Play/Pause")),
|
||||
new ("", "", "cycle pause", "MBTN_Mid", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "Play", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "Pause", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "PlayPause", _("Play/Pause")),
|
||||
new ("", "", "script-message-to mpvnet play-pause", "MBTN_Mid", _("Play/Pause")),
|
||||
new ("", "", "stop", "Stop", _("Stop")),
|
||||
new ("", "", "seek 60", "Forward", _("Forward")),
|
||||
new ("", "", "seek -60", "Rewind", _("Backward")),
|
||||
@@ -207,6 +211,8 @@ public static class InputHelp
|
||||
new ("", "", "no-osd seek -5", "Ctrl+Wheel_Down", _("Seek Backward")),
|
||||
new ("", "", "quit 4", "Esc", _("Quit encoding")),
|
||||
new ("", "", "quit 4", "q", _("Quit encoding")),
|
||||
new ("", "", "quit", "Power", _("Exit")),
|
||||
|
||||
//new (_("Command Palette"), _("Commands"), "script-message-to mpvnet show-command-palette", "F1"),
|
||||
};
|
||||
|
||||
@@ -321,18 +327,11 @@ public static class InputHelp
|
||||
|
||||
line = line[(line.IndexOf(" ") + 1)..];
|
||||
|
||||
if (line.Contains("#menu:"))
|
||||
if (line.Contains(App.MenuSyntax))
|
||||
{
|
||||
binding.Comment = line[(line.IndexOf("#menu:") + 6)..].Trim();
|
||||
binding.Comment = line[(line.IndexOf(App.MenuSyntax) + App.MenuSyntax.Length)..].Trim();
|
||||
binding.IsMenu = true;
|
||||
line = line[..line.IndexOf("#menu:")];
|
||||
}
|
||||
else if (line.Contains("#!"))
|
||||
{
|
||||
binding.Comment = line[(line.IndexOf("#!") + 2)..].Trim();
|
||||
binding.IsMenu = true;
|
||||
binding.IsShortMenuSyntax = true;
|
||||
line = line[..line.IndexOf("#!")];
|
||||
line = line[..line.IndexOf(App.MenuSyntax)];
|
||||
}
|
||||
else if (line.Contains("#custom-menu:"))
|
||||
{
|
||||
@@ -432,10 +431,10 @@ public static class InputHelp
|
||||
|
||||
value = value[(value.IndexOf(" ") + 1)..];
|
||||
|
||||
if (value.Contains("#menu:"))
|
||||
if (value.Contains(App.MenuSyntax))
|
||||
{
|
||||
binding.Comment = value[(value.IndexOf("#menu:") + 6)..].Trim();
|
||||
value = value[..value.IndexOf("#menu:")];
|
||||
binding.Comment = value[(value.IndexOf(App.MenuSyntax) + App.MenuSyntax.Length)..].Trim();
|
||||
value = value[..value.IndexOf(App.MenuSyntax)];
|
||||
|
||||
if (binding.Comment.Contains(';'))
|
||||
binding.Comment = binding.Comment[(binding.Comment.IndexOf(";") + 1)..].Trim();
|
||||
@@ -454,4 +453,41 @@ public static class InputHelp
|
||||
}
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public static Dictionary<string, Binding> GetActiveBindings(List<Binding> bindings)
|
||||
{
|
||||
Dictionary<string, Binding> ret = new();
|
||||
|
||||
foreach (Binding binding in bindings)
|
||||
{
|
||||
if (binding.Input == "" || binding.Command == "")
|
||||
continue;
|
||||
|
||||
ret[binding.Input] = binding;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string GetBindingsForCommand(Dictionary<string, Binding> activeBindings, string command)
|
||||
{
|
||||
List<string> keys = new();
|
||||
int charCount = 0;
|
||||
|
||||
foreach (var it in activeBindings)
|
||||
{
|
||||
if (it.Value.Command != command)
|
||||
continue;
|
||||
|
||||
Binding binding = it.Value;
|
||||
|
||||
if (!keys.Contains(binding.Input) && (charCount + binding.Input.Length) < 20 && keys.Count < 2)
|
||||
{
|
||||
keys.Add(binding.Input);
|
||||
charCount += binding.Input.Length;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(", ", keys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ public class MainPlayer : MpvClient
|
||||
SetPropertyBool("input-default-bindings", true);
|
||||
SetPropertyBool("input-builtin-bindings", false);
|
||||
|
||||
SetPropertyString("watch-later-options", "mute");
|
||||
SetPropertyString("screenshot-directory", "~~desktop/");
|
||||
SetPropertyString("osd-playing-msg", "${media-title}");
|
||||
SetPropertyString("osc", "yes");
|
||||
@@ -269,38 +268,47 @@ public class MainPlayer : MpvClient
|
||||
Dictionary<string, string>? _Conf;
|
||||
|
||||
public Dictionary<string, string> Conf {
|
||||
get {
|
||||
if (_Conf == null)
|
||||
get
|
||||
{
|
||||
if (_Conf != null)
|
||||
return _Conf;
|
||||
|
||||
App.ApplyInputDefaultBindingsFix();
|
||||
|
||||
_Conf = new Dictionary<string, string>();
|
||||
|
||||
if (File.Exists(ConfPath))
|
||||
{
|
||||
App.ApplyInputDefaultBindingsFix();
|
||||
|
||||
_Conf = new Dictionary<string, string>();
|
||||
|
||||
if (File.Exists(ConfPath))
|
||||
foreach (string? it in File.ReadAllLines(ConfPath))
|
||||
{
|
||||
foreach (string? it in File.ReadAllLines(ConfPath))
|
||||
string line = it.TrimStart(' ', '-').TrimEnd();
|
||||
|
||||
if (line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
if (!line.Contains('='))
|
||||
{
|
||||
string line = it.TrimStart(' ', '-').TrimEnd();
|
||||
|
||||
if (!line.Contains('=') || line.StartsWith("#"))
|
||||
if (Regex.Match(line, "^[\\w-]+$").Success)
|
||||
line += "=yes";
|
||||
else
|
||||
continue;
|
||||
|
||||
string key = line[..line.IndexOf("=")].Trim();
|
||||
string value = line[(line.IndexOf("=") + 1)..].Trim();
|
||||
|
||||
if (value.Contains('#') && !value.StartsWith("#") &&
|
||||
!value.StartsWith("'#") && !value.StartsWith("\"#"))
|
||||
|
||||
value = value[..value.IndexOf("#")].Trim();
|
||||
|
||||
_Conf[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var i in _Conf)
|
||||
ProcessProperty(i.Key, i.Value);
|
||||
string key = line[..line.IndexOf("=")].Trim();
|
||||
string value = line[(line.IndexOf("=") + 1)..].Trim();
|
||||
|
||||
if (value.Contains('#') && !value.StartsWith("#") &&
|
||||
!value.StartsWith("'#") && !value.StartsWith("\"#"))
|
||||
|
||||
value = value[..value.IndexOf("#")].Trim();
|
||||
|
||||
_Conf[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var i in _Conf)
|
||||
ProcessProperty(i.Key, i.Value);
|
||||
|
||||
return _Conf;
|
||||
}
|
||||
}
|
||||
|
||||
26
src/Setup/Inno/inno-setup.iss
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#define MyAppName "mpv.net"
|
||||
#define MyAppExeName "mpvnet.exe"
|
||||
#define MyAppSourceDir "..\..\MpvNet.Windows\bin\Debug"
|
||||
#define MyAppVersion GetFileVersion("..\..\MpvNet.Windows\bin\Debug\mpvnet.exe")
|
||||
|
||||
[Setup]
|
||||
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher=Frank Skare (stax76)
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
Compression=lzma2
|
||||
DefaultDirName={commonpf}\{#MyAppName}
|
||||
OutputBaseFilename=mpv.net-v{#MyAppVersion}-setup
|
||||
OutputDir=E:\Desktop
|
||||
DefaultGroupName={#MyAppName}
|
||||
SetupIconFile=..\..\MpvNet.Windows\mpv-icon.ico
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
|
||||
[Files]
|
||||
Source: "{#MyAppSourceDir}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;
|
||||