Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d321ab477f | ||
|
|
1cd0f87278 | ||
|
|
936274fc3b | ||
|
|
2bbaa30322 | ||
|
|
cedd54d64d | ||
|
|
38604459a6 | ||
|
|
0a48a0dc6f | ||
|
|
85a23fbae1 | ||
|
|
01da76bdc4 | ||
|
|
1f1553e159 | ||
|
|
2af84941ca | ||
|
|
a82f558acf | ||
|
|
d13f7201ba | ||
|
|
89aa0c6133 | ||
|
|
1699467e0d | ||
|
|
7a27ab0513 | ||
|
|
2a0c68e4ec | ||
|
|
91c42d4d3f | ||
|
|
49d56166d7 | ||
|
|
1ac603b904 | ||
|
|
d5b2923c68 | ||
|
|
b80b375df1 | ||
|
|
2b2b60b90f | ||
|
|
3977283ecb | ||
|
|
d27778775d |
38
Changelog.md
38
Changelog.md
@@ -1,3 +1,37 @@
|
||||
### 4.7.7
|
||||
|
||||
- on Win 7 the theme color was hardcoded to DarkSlateGrey because
|
||||
WPF was returning a bad color on Win 7, this was fixed by reading
|
||||
the theme color from the Registry on Win 7. If the theme color
|
||||
is identical to the background color it's corrected
|
||||
- dark-color setting was added to overwrite the OS theme color used in dark mode,
|
||||
find the setting on the General tab
|
||||
- light-color setting was added to overwrite the OS theme color used in non dark mode,
|
||||
find the setting on the General tab
|
||||
- various changes regarding input handling, multi media keys and
|
||||
mouse forward/backward were successfully tested
|
||||
- it's now possible to use a custom folder as config folder,
|
||||
A TaskDialog shows five options: 1. appdata mpv.net, 2. appdata mpv (shared with mpv),
|
||||
3. portable_config, 4. startup, 5. custom
|
||||
- slightly increased startup performance, start-threshold setting added.
|
||||
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
|
||||
- autofit-smaller setting added. Minimum window height in percent. Default: 40%
|
||||
- autofit-larger setting added. Maximum window height in percent. Default: 75%
|
||||
|
||||
### 4.7.3
|
||||
|
||||
- fix cursor showing load activity on startup
|
||||
- added file size and type to info command using audio files
|
||||
- added image format support to the info command, to file
|
||||
association management, to folder loading, to Everything
|
||||
- readme/github have a updated features and architecture section
|
||||
|
||||
### 4.7.1
|
||||
|
||||
- few layout problems were fixed, autosize for instance did not work
|
||||
|
||||
### 4.7
|
||||
|
||||
- remember-height was replaced with start-size, when start-size is set
|
||||
@@ -7,10 +41,10 @@
|
||||
- on exit the window location can be saved with remember-position
|
||||
- in the learn window of the input editor underscores were stripped
|
||||
because they have a special meaning in WPF labels
|
||||
- keys/input not working for MBTN_LEFT_DBL, MBTN_BACK, MBTN_FORWARD
|
||||
- fix for keys/input not working for MBTN_LEFT_DBL, MBTN_BACK, MBTN_FORWARD
|
||||
- in the learn window of the input editor support was added for
|
||||
mouse left, mouse left double, mouse mid, mouse forward, mouse back
|
||||
- libmpv updated to shinchiro 2019-07-07
|
||||
- libmpv was updated to shinchiro 2019-07-07
|
||||
- when border is none it wasn't possible to minimize the window from
|
||||
the task bar because this is the WinForms default behavier. This
|
||||
was fixed by calling Spy++ to the rescue and adding WS_MINIMIZEBOX
|
||||
|
||||
28
Manual.md
28
Manual.md
@@ -90,7 +90,6 @@
|
||||
+ [Exit](#exit)
|
||||
+ [Exit Watch Later](#exit-watch-later)
|
||||
* [Command Line Interface](#command-line-interface)
|
||||
* [Settings](#settings)
|
||||
|
||||
## About mpv.net
|
||||
|
||||
@@ -734,7 +733,7 @@ Shows the command palette window which allows to find mpv.net commands, it shows
|
||||
|
||||
### Tools > Show History
|
||||
|
||||
When enabled shows a file that contains the playback history containing the time and filename.
|
||||
Shows a text file that contains the file history. If the file don't exist it asks if the file should be created in the settings folder. Once the file exist then the history is logged. It logges the playback history containing the time and filename.
|
||||
|
||||
### Tools > Set/clear A-B loop points
|
||||
|
||||
@@ -819,28 +818,3 @@ mpvnet implements a basic CLI to set mpv commands.
|
||||
Example:
|
||||
|
||||
mpvnet --mute=yes <file|URL>
|
||||
|
||||
## Settings
|
||||
|
||||
mpv.net is able to share the settings with mpv and mpv.net uses the same logic to decide from where the settings are loaded. The default location is:
|
||||
|
||||
```Text
|
||||
C:\Users\%username%\AppData\Roaming\mpv\mpv.conf
|
||||
```
|
||||
|
||||
If a directory named portable_config next to the mpvnet.exe exists, all config will be loaded from this directory only.
|
||||
|
||||
```Text
|
||||
<startup>\portable_config\mpv.conf
|
||||
```
|
||||
|
||||
In case there isn't any config folder mpv.net asks where to create it. If no mpv.conf file exists mpv.net generates it with the following defaults:
|
||||
|
||||
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt>
|
||||
|
||||
Config files located in the same directory as mpvnet.exe are loaded with lower priority. Some config files are loaded only once, which means that e.g. of 2 input.conf files located in two config directories, only the one from the directory with higher priority will be loaded.
|
||||
|
||||
The key bindings and the context menu definitions are stored in the input.conf file,
|
||||
if it's missing mpv.net generates it with the following defaults:
|
||||
|
||||
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
|
||||
64
README.md
64
README.md
@@ -46,19 +46,38 @@ Table of contents
|
||||
|
||||
### Features
|
||||
|
||||
- Very high degree of mpv compatibility, almost all mpv features are available
|
||||
- Great usability due to everything in the application being searchable
|
||||
- Open source built with modern tools
|
||||
- Customizable context menu defined in the same file as the key bindings ([Screenshot](#context-menu-screenshot), [Defaults](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt))
|
||||
- Searchable config dialog ([Screenshot](#config-editor-screenshot), [Defaults](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt))
|
||||
- Searchable input (key/mouse) binding editor ([Screenshot](#input-editor-screenshot), [Defaults](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt))
|
||||
- Configuration files that are easy to read and edit
|
||||
- Searchable command palette to quickly launch commands and look for keys ([Screenshot](#command-palette-screenshot))
|
||||
- Modern UI with dark mode ([Screenshot](#config-editor-screenshot))
|
||||
- Modern WPF based graphical user interface with dark mode ([Screenshot](#config-editor-screenshot))
|
||||
- Addon/extension API for .NET languages
|
||||
- Scripting API for Python, C#, Lua, JavaScript and PowerShell ([Wiki](https://github.com/stax76/mpv.net/wiki/Scripting))
|
||||
- mpv's OSC, IPC and conf files
|
||||
- Language agnostic JSON IPC to control the player with a external programs
|
||||
- On Screen Controler (OSC, play control buttons)
|
||||
- [Command Line Interface](https://mpv.io/manual/master/#options)
|
||||
- DXVA2 video decoding acceleration
|
||||
- OpenGL based video output capable of features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more
|
||||
- Search feature powered by [Everything](https://www.voidtools.com) to find and play media ([Screenshot](#media-search-screenshot))
|
||||
- Extension to start mpv.net from Google Chrome ([Manual](Manual.md#chrome-extension))
|
||||
- Extremely fast seek performance
|
||||
- Very fast startup performance, video is usally ready to play in less then a second
|
||||
- Usable as video player, audio player and image viewer with a wide range of supported formats
|
||||
- All decoders are built-in, no external codecs have to be installed
|
||||
- Setup and portable download options, setup is recommended but not required
|
||||
- Build-in media streaming via youtube-dl
|
||||
- x64 and x86 Support (64-bit and 32-bit)
|
||||
- File associations can be created by the setup and from the player
|
||||
- External audio and subtitle files can either be loaded manually or automatically
|
||||
- Screenshot feature with many options
|
||||
- File history feature to log time and filename
|
||||
- A-B loop feature
|
||||
- watch later feature to save the position
|
||||
- [Manual](#manual)
|
||||
|
||||
### Screenshots
|
||||
|
||||
@@ -117,30 +136,32 @@ input.conf defines mpv's key and mouse bindings and mpv.net uses comments to def
|
||||
|
||||
### Settings
|
||||
|
||||
mpv.net is able to share the settings with mpv and mpv.net uses the same logic to decide from where the settings are loaded. The default location is:
|
||||
mpv.net is able to share the settings with mpv.
|
||||
|
||||
If a directory named portable_config next to the mpvnet.exe exists,
|
||||
all config will be loaded from this directory only.
|
||||
|
||||
```Text
|
||||
C:\Users\%username%\AppData\Roaming\mpv\mpv.conf
|
||||
<startup>\portable_config\
|
||||
```
|
||||
|
||||
If a directory named portable_config next to the mpvnet.exe exists, all config will be loaded from this directory only.
|
||||
On first start if no portable config folder exists mpv.net asks
|
||||
which folder should be used as config folder.
|
||||
|
||||
```Text
|
||||
<startup>\portable_config\mpv.conf
|
||||
```
|
||||
|
||||
In case there isn't any config folder mpv.net asks where to create it. If no mpv.conf file exists mpv.net generates it with the following defaults:
|
||||
mpv specific settings are stored in the file mpv.conf, if no mpv.conf file exists
|
||||
mpv.net generates it with the following defaults:
|
||||
|
||||
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt>
|
||||
|
||||
Config files located in the same directory as mpvnet.exe are loaded with lower priority. Some config files are loaded only once, which means that e.g. of 2 input.conf files located in two config directories, only the one from the directory with higher priority will be loaded.
|
||||
mpv.net specific settings are stored in the file mpvnet.conf
|
||||
|
||||
The key bindings and the context menu definitions are stored in the input.conf file,
|
||||
if it's missing mpv.net generates it with the following defaults:
|
||||
The input (key/mouse) bindings and the context menu definitions are stored in the
|
||||
input.conf file, if it's missing mpv.net generates it with the following defaults:
|
||||
|
||||
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
|
||||
|
||||
mpv.net supports almost all mpv settings and features, [limitations are listed in the wiki](https://github.com/stax76/mpv.net/wiki/Limitations).
|
||||
mpv.net supports almost all mpv settings and features,
|
||||
[limitations are listed in the wiki](https://github.com/stax76/mpv.net/wiki/Limitations).
|
||||
|
||||
### Scripting
|
||||
|
||||
@@ -152,7 +173,15 @@ mpv.net supports almost all mpv settings and features, [limitations are listed i
|
||||
|
||||
### Architecture
|
||||
|
||||
mpv.net is written in C# 7.0 and runs on the .NET framework 4.7 or higher.
|
||||
Coding mpv.net was great fun because libmpv is such a awesome
|
||||
library with a very clever design, I'm having a great experience
|
||||
with libmpv.
|
||||
|
||||
The player does not contain any feature that was more work than 1-2 days or
|
||||
was difficult to build, the hard parts are totally covered by libmpv.
|
||||
|
||||
mpv.net is written in C# 7 and runs on .NET 4.7, I've not yet decided
|
||||
if I will port it to C# 8 and .NET 5 once available.
|
||||
|
||||
The Add-on implementation is based on the [Managed Extensibility Framework](https://docs.microsoft.com/en-us/dotnet/framework/mef/).
|
||||
|
||||
@@ -162,9 +191,10 @@ this decision was made to keep the code simple and lightweight.
|
||||
|
||||
Python scripting is implemented with IronPython which uses Python 2.7.
|
||||
|
||||
The main/video window is WinForms based, all other windows are WPF based.
|
||||
The main window is WinForms based and uses less than 600 lines of code,
|
||||
all other windows are WPF based and use even less code.
|
||||
|
||||
The config editor adds it's controls dynamically and uses TOML to define it's
|
||||
The config editor adds it's controls dynamically and uses [TOML](https://en.wikipedia.org/wiki/TOML) to define it's
|
||||
content, there are only two simple types, StringSetting and OptionSetting.
|
||||
|
||||
mpv.net was started 2017 and consists of about 6000 lines of code and markup.
|
||||
|
||||
@@ -16,8 +16,8 @@ Public Class CSScriptAddon
|
||||
Sub New()
|
||||
Dim scriptFiles As New List(Of String)
|
||||
|
||||
If Directory.Exists(mp.ConfFolder + "scripts") Then
|
||||
scriptFiles.AddRange(Directory.GetFiles(mp.ConfFolder + "scripts", "*.cs"))
|
||||
If Directory.Exists(mp.ConfigFolder + "scripts") Then
|
||||
scriptFiles.AddRange(Directory.GetFiles(mp.ConfigFolder + "scripts", "*.cs"))
|
||||
End If
|
||||
|
||||
If Directory.Exists(Application.StartupPath + "\scripts") Then
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// this addon writes a rating to the filename of the current video,
|
||||
// the input.conf defaults contain key bindings for this addon
|
||||
// sometimes the add-on don't work, it's containing a lot of trace code at the moment
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
@@ -7,30 +6,36 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using mpvnet;
|
||||
using System.Diagnostics;
|
||||
|
||||
// the assembly name must end with 'Addon'
|
||||
namespace RatingAddon
|
||||
{
|
||||
[Export(typeof(IAddon))]
|
||||
public class RatingAddon : IAddon
|
||||
{
|
||||
// dictionory to store the filename and the rating
|
||||
Dictionary<string, int> Dic = new Dictionary<string, int>();
|
||||
|
||||
public RatingAddon()
|
||||
public RatingAddon() // plugin initialization
|
||||
{
|
||||
mp.ClientMessage += ClientMessage; //handles keys defined in input.conf
|
||||
mp.Shutdown += Shutdown;
|
||||
mp.Shutdown += Shutdown; // handles MPV_EVENT_SHUTDOWN
|
||||
}
|
||||
|
||||
// handles MPV_EVENT_SHUTDOWN
|
||||
void Shutdown()
|
||||
{
|
||||
if (App.DebugMode) Trace.WriteLine("aaa");
|
||||
|
||||
foreach (var i in Dic)
|
||||
{
|
||||
string filepath = i.Key;
|
||||
int rating = i.Value;
|
||||
|
||||
if (App.DebugMode) Trace.WriteLine("bbb");
|
||||
if (String.IsNullOrEmpty(filepath) || ! File.Exists(filepath))
|
||||
return;
|
||||
|
||||
if (App.DebugMode) Trace.WriteLine("ccc");
|
||||
string basename = Path.GetFileNameWithoutExtension(filepath);
|
||||
|
||||
for (int x = 0; x < 6; x++)
|
||||
@@ -39,21 +44,29 @@ namespace RatingAddon
|
||||
|
||||
basename += $" ({rating}stars)";
|
||||
string newPath = Path.Combine(Path.GetDirectoryName(filepath), basename + Path.GetExtension(filepath));
|
||||
|
||||
if (App.DebugMode) Trace.WriteLine("ddd");
|
||||
if (filepath.ToLower() != newPath.ToLower())
|
||||
File.Move(filepath, newPath);
|
||||
|
||||
if (App.DebugMode) Trace.WriteLine("eee");
|
||||
File.SetLastWriteTime(newPath, DateTime.Now);
|
||||
if (App.DebugMode) Trace.WriteLine("fff");
|
||||
}
|
||||
}
|
||||
|
||||
//handles keys defined in input.conf
|
||||
void ClientMessage(string[] args)
|
||||
{
|
||||
if (args[0] != "rate-file" || ! int.TryParse(args[1], out int rating))
|
||||
return;
|
||||
Dic[mp.get_property_string("path")] = rating;
|
||||
if (args[0] != "rate-file") return;
|
||||
|
||||
if (int.TryParse(args[1], out int rating))
|
||||
{
|
||||
string path = mp.get_property_string("path");
|
||||
if (!File.Exists(path)) return;
|
||||
Dic[path] = rating;
|
||||
mp.commandv("show-text", $"Rating: {rating}");
|
||||
}
|
||||
else if (args[1] == "about")
|
||||
Msg.Show("Rating Extension", "This extension writes a rating to the filename of rated videos when mpv.net shuts down.\n\nThe input.conf defaults contain key bindings for this addon to set ratings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
img/Main.png
BIN
img/Main.png
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 MiB After Width: | Height: | Size: 2.5 MiB |
@@ -15,7 +15,7 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="ValueTextBox" Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" HorizontalAlignment="Left" Height="20" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" TextChanged="ValueTextBox_TextChanged"/>
|
||||
<TextBox x:Name="ValueTextBox" Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" HorizontalAlignment="Left" Height="20" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" CaretBrush="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" TextChanged="ValueTextBox_TextChanged"/>
|
||||
<Button x:Name="Button" Height="20" Grid.Column="1" Visibility="{Binding Path=Text, ElementName=StringSettingControl1}" Margin="5,0,0,0" Width="20" Click="Button_Click">...</Button>
|
||||
</Grid>
|
||||
<TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" BorderThickness="0" IsReadOnly="True" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -55,7 +56,7 @@ namespace DynamicGUI
|
||||
{
|
||||
d.Description = "Choose a folder.";
|
||||
d.SelectedPath = ValueTextBox.Text;
|
||||
if (d.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||
if (d.ShowDialog() == WinForms.DialogResult.OK)
|
||||
ValueTextBox.Text = d.SelectedPath;
|
||||
}
|
||||
break;
|
||||
@@ -64,11 +65,14 @@ namespace DynamicGUI
|
||||
{
|
||||
d.FullOpen = true;
|
||||
try {
|
||||
if (!string.IsNullOrEmpty(ValueTextBox.Text))
|
||||
{
|
||||
Color col = GetColor(ValueTextBox.Text);
|
||||
d.Color = System.Drawing.Color.FromArgb(col.A, col.R, col.G, col.B);
|
||||
} catch { }
|
||||
}
|
||||
} catch {}
|
||||
if (d.ShowDialog() == WinForms.DialogResult.OK)
|
||||
ValueTextBox.Text = System.Drawing.ColorTranslator.ToHtml(d.Color);
|
||||
ValueTextBox.Text = "#" + d.Color.ToArgb().ToString("X8");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace mpvnet
|
||||
foreach (string i in Directory.GetDirectories(dir))
|
||||
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Addon.dll"));
|
||||
|
||||
dir = mp.ConfFolder + "\\Addons";
|
||||
dir = mp.ConfigFolder + "\\Addons";
|
||||
|
||||
if (Directory.Exists(dir))
|
||||
foreach (string i in Directory.GetDirectories(dir))
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace mpvnet
|
||||
case "show-about": ShowDialog(typeof(AboutWindow)); break;
|
||||
case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break;
|
||||
case "show-input-editor": ShowDialog(typeof(InputWindow)); break;
|
||||
case "open-conf-folder": Process.Start(mp.ConfFolder); break;
|
||||
case "open-conf-folder": Process.Start(mp.ConfigFolder); break;
|
||||
case "open-files": OpenFiles(args); break;
|
||||
case "shell-execute": Process.Start(args[0]); break;
|
||||
case "show-info": ShowInfo(); break;
|
||||
@@ -68,7 +68,7 @@ namespace mpvnet
|
||||
|
||||
public static void ShowHistory()
|
||||
{
|
||||
var fp = mp.ConfFolder + "history.txt";
|
||||
var fp = mp.ConfigFolder + "history.txt";
|
||||
|
||||
if (File.Exists(fp))
|
||||
Process.Start(fp);
|
||||
@@ -109,6 +109,22 @@ namespace mpvnet
|
||||
if (genre != "") text += "Genre: " + genre + "\n";
|
||||
if (date != "") text += "Year: " + date + "\n";
|
||||
if (duration != "") text += "Length: " + duration + "\n";
|
||||
text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n";
|
||||
text += "Type: " + Path.GetExtension(path).ToUpper().TrimStart('.');
|
||||
|
||||
mp.commandv("show-text", text, "5000");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (App.ImageTypes.Contains(Path.GetExtension(path).ToLower().TrimStart('.')))
|
||||
{
|
||||
using (MediaInfo mediaInfo = new MediaInfo(path))
|
||||
{
|
||||
text =
|
||||
"Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" +
|
||||
"Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" +
|
||||
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
|
||||
"Type: " + Path.GetExtension(path).ToUpper().TrimStart('.');
|
||||
|
||||
mp.commandv("show-text", text, "5000");
|
||||
return;
|
||||
@@ -170,7 +186,8 @@ namespace mpvnet
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
using (var d = new OpenFileDialog())
|
||||
{
|
||||
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
|
||||
string path = mp.get_property_string("path");
|
||||
if (File.Exists(path)) d.InitialDirectory = Path.GetDirectoryName(path);
|
||||
d.Multiselect = true;
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
foreach (string i in d.FileNames)
|
||||
@@ -184,7 +201,9 @@ namespace mpvnet
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
using (var d = new OpenFileDialog())
|
||||
{
|
||||
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
|
||||
string path = mp.get_property_string("path");
|
||||
if (File.Exists(path))
|
||||
d.InitialDirectory = Path.GetDirectoryName(path);
|
||||
d.Multiselect = true;
|
||||
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
@@ -196,10 +215,10 @@ namespace mpvnet
|
||||
|
||||
public static void CycleAudio()
|
||||
{
|
||||
string filePath = mp.get_property_string("path", false);
|
||||
if (!File.Exists(filePath)) return;
|
||||
string path = mp.get_property_string("path");
|
||||
if (!File.Exists(path)) return;
|
||||
|
||||
using (MediaInfo mi = new MediaInfo(filePath))
|
||||
using (MediaInfo mi = new MediaInfo(path))
|
||||
{
|
||||
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
|
||||
if (audTracks.Length < 2) return;
|
||||
@@ -220,6 +239,7 @@ namespace mpvnet
|
||||
|
||||
td.AddCommandLink("Register video file extensions", "video");
|
||||
td.AddCommandLink("Register audio file extensions", "audio");
|
||||
td.AddCommandLink("Register audio file extensions", "image");
|
||||
td.AddCommandLink("Unregister file extensions", "unreg");
|
||||
|
||||
string result = td.Show();
|
||||
|
||||
@@ -18,19 +18,24 @@ namespace mpvnet
|
||||
{
|
||||
public class App
|
||||
{
|
||||
public static string ConfFilePath { get; } = mp.ConfFolder + "\\mpvnet.conf";
|
||||
public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName;
|
||||
public static string ConfFilePath { get; } = mp.ConfigFolder + "\\mpvnet.conf";
|
||||
public static string DarkMode { get; set; } = "always";
|
||||
public static string ProcessInstance { get; set; } = "single";
|
||||
public static string DarkColor { get; set; }
|
||||
public static string LightColor { get; set; }
|
||||
|
||||
public static string[] VideoTypes { get; } = "mkv mp4 mpg avi mov webm vob wmv flv avs 264 h264 asf webm mpeg mpv y4m avc hevc 265 h265 m2v m2ts vpy mts m4v".Split(' ');
|
||||
public static string[] AudioTypes { get; } = "mp3 mp2 ac3 ogg opus flac wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 mka aac mpa".Split(' ');
|
||||
public static string[] ImageTypes { get; } = "jpg bmp gif".Split(' ');
|
||||
public static string[] SubtitleTypes { get; } = "srt ass idx sup ttxt ssa smi".Split(' ');
|
||||
public static string[] UrlWhitelist { get; set; } = { "tube", "vimeo", "ard", "zdf" };
|
||||
|
||||
public static bool RememberHeight { get; set; } = true;
|
||||
public static bool RememberPosition { get; set; }
|
||||
public static bool DebugMode { get; set; } = false;
|
||||
public static bool DebugMode { get; set; }
|
||||
|
||||
public static int StartThreshold { get; set; } = 1500;
|
||||
|
||||
public static bool IsDarkMode {
|
||||
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
|
||||
@@ -38,7 +43,7 @@ namespace mpvnet
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
string dummy = mp.ConfFolder;
|
||||
string dummy = mp.ConfigFolder;
|
||||
var dummy2 = mp.Conf;
|
||||
|
||||
foreach (var i in Conf)
|
||||
@@ -48,12 +53,10 @@ namespace mpvnet
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\mpvnet-debug.log";
|
||||
string filePath = mp.ConfigFolder + "\\mpvnet-debug.log";
|
||||
if (File.Exists(filePath)) File.Delete(filePath);
|
||||
Trace.Listeners.Clear();
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
|
||||
foreach (Screen screen in Screen.AllScreens)
|
||||
Trace.WriteLine(screen);
|
||||
Trace.AutoFlush = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -62,11 +65,6 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
|
||||
public static void Exit()
|
||||
{
|
||||
if (Trace.Listeners.Count > 0) Trace.Listeners[0].Close();
|
||||
}
|
||||
|
||||
static Dictionary<string, string> _Conf;
|
||||
|
||||
public static Dictionary<string, string> Conf {
|
||||
@@ -93,9 +91,15 @@ namespace mpvnet
|
||||
case "process-instance": ProcessInstance = value; break;
|
||||
case "dark-mode": DarkMode = value; break;
|
||||
case "debug-mode": DebugMode = value == "yes"; break;
|
||||
case "dark-color": DarkColor = value.Trim('\'', '"'); break;
|
||||
case "light-color": LightColor = value.Trim('\'', '"'); break;
|
||||
case "url-whitelist":
|
||||
UrlWhitelist = value.Split(' ', ',', ';');
|
||||
break;
|
||||
case "start-threshold":
|
||||
int.TryParse(value, out int result);
|
||||
StartThreshold = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +193,8 @@ namespace mpvnet
|
||||
RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "video");
|
||||
if (App.AudioTypes.Contains(ext))
|
||||
RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "audio");
|
||||
if (App.ImageTypes.Contains(ext))
|
||||
RegHelp.SetObject($"HKCR\\" + "." + ext, "PerceivedType", "image");
|
||||
RegHelp.SetObject($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open", null, "Play with " + Application.ProductName);
|
||||
RegHelp.SetObject($"HKCR\\" + ExeFilenameNoExt + "." + ext + "\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\"");
|
||||
RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext);
|
||||
|
||||
@@ -15,12 +15,16 @@ namespace mpvnet
|
||||
{
|
||||
try
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
string[] args = Environment.GetCommandLineArgs().Skip(1).ToArray();
|
||||
|
||||
if (args.Length == 2 && args[0] == "--reg-file-assoc")
|
||||
{
|
||||
if (args[1] == "audio") FileAssociation.Register(App.AudioTypes);
|
||||
if (args[1] == "video") FileAssociation.Register(App.VideoTypes);
|
||||
if (args[1] == "image") FileAssociation.Register(App.ImageTypes);
|
||||
if (args[1] == "unreg") FileAssociation.Unregister();
|
||||
return;
|
||||
}
|
||||
@@ -60,8 +64,6 @@ namespace mpvnet
|
||||
return;
|
||||
}
|
||||
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MainForm());
|
||||
mutex.Dispose();
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("4.7.0.0")]
|
||||
[assembly: AssemblyFileVersion("4.7.0.0")]
|
||||
[assembly: AssemblyVersion("4.7.7.0")]
|
||||
[assembly: AssemblyFileVersion("4.7.7.0")]
|
||||
|
||||
@@ -131,6 +131,8 @@
|
||||
KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
|
||||
KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
|
||||
KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
|
||||
_ ignore #menu: Extensions > Rating > -
|
||||
_ script-message rate-file about #menu: Extensions > Rating > About
|
||||
|
||||
Ctrl+t set ontop yes #menu: View > On Top > Enable
|
||||
Ctrl+T set ontop no #menu: View > On Top > Disable
|
||||
@@ -166,12 +168,11 @@
|
||||
Esc quit #menu: Exit
|
||||
Q quit-watch-later #menu: Exit Watch Later
|
||||
|
||||
> playlist-next
|
||||
< playlist-prev
|
||||
Power quit
|
||||
Play cycle pause
|
||||
Pause cycle pause
|
||||
PlayPause cycle pause
|
||||
MBTN_Mid cycle pause
|
||||
Stop stop
|
||||
Forward seek 60
|
||||
Rewind seek -60
|
||||
@@ -182,7 +183,11 @@
|
||||
Wheel_Down add volume -10
|
||||
Prev playlist-prev
|
||||
Next playlist-next
|
||||
MBTN_Forward playlist-next
|
||||
MBTN_Back playlist-prev
|
||||
> playlist-next
|
||||
< playlist-prev
|
||||
Ctrl+Wheel_Up no-osd seek 7
|
||||
Ctrl+Wheel_Down no-osd seek -7
|
||||
MBTN_LEFT_DBL cycle fullscreen
|
||||
KP_ENTER cycle fullscreen
|
||||
MBTN_Left_DBL cycle fullscreen
|
||||
KP_Enter cycle fullscreen
|
||||
@@ -250,9 +250,18 @@ help = "Store screenshots in this directory. This path is joined with the filena
|
||||
|
||||
[[settings]]
|
||||
name = "autofit"
|
||||
default = "50%"
|
||||
filter = "Screen"
|
||||
help = "Set the initial window size in percent. Please note that this setting is only partly implemented in mpv.net, accepted are only integer values with percent sign added. Default: 50%"
|
||||
help = "<int> Initial window height in percent. Default: 50%"
|
||||
|
||||
[[settings]]
|
||||
name = "autofit-smaller"
|
||||
filter = "Screen"
|
||||
help = "<int> Minimum window height in percent. Default: 40%"
|
||||
|
||||
[[settings]]
|
||||
name = "autofit-larger"
|
||||
filter = "Screen"
|
||||
help = "<int> Maximum window height in percent. Default: 75%"
|
||||
|
||||
[[settings]]
|
||||
name = "keep-open-pause"
|
||||
@@ -274,7 +283,7 @@ options = [{ name = "yes", help = "Don't terminate if the current file is the
|
||||
[[settings]]
|
||||
name = "loop-file"
|
||||
filter = "Playback"
|
||||
help = "Loop a single file N times. inf means forever, no means normal playback.\n\nThe difference to loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file. loop is an alias for this option."
|
||||
help = "<N|inf|no> Loop a single file N times. inf means forever, no means normal playback.\n\nThe difference to loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file. loop is an alias for this option."
|
||||
|
||||
[[settings]]
|
||||
name = "save-position-on-quit"
|
||||
|
||||
@@ -2,22 +2,34 @@
|
||||
name = "dark-mode"
|
||||
default = "always"
|
||||
filter = "General"
|
||||
help = "Enables a dark theme."
|
||||
help = "Enables a dark theme. (mpv.net specific setting)"
|
||||
options = [{ name = "always" },
|
||||
{ name = "system" , help = "Available on Windows 10 or higher" },
|
||||
{ name = "never" }]
|
||||
|
||||
[[settings]]
|
||||
name = "dark-color"
|
||||
type = "color"
|
||||
filter = "General"
|
||||
help = "Theme color used in dark-mode. Leave empty to use OS theme. (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "light-color"
|
||||
type = "color"
|
||||
filter = "General"
|
||||
help = "Theme color used when dark-mode is disabled. Leave empty to use OS theme. (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "url-whitelist"
|
||||
filter = "General"
|
||||
type = "string"
|
||||
help = "mpv.net specific whitelist setting to monitor the clipboard for URLs to play.\n\nDefault: tube vimeo ard zdf"
|
||||
help = "Whitelist setting to monitor the clipboard for URLs to play. (mpv.net specific setting)\n\nDefault: tube vimeo ard zdf"
|
||||
|
||||
[[settings]]
|
||||
name = "process-instance"
|
||||
default = "single"
|
||||
filter = "General"
|
||||
help = "mpv.net specific setting that defines if more then one mpv.net process is allowed.\n\nTip: Whenever the control key is pressed when files or URLs are opened, the playlist is not cleared but the files or URLs are appended to the playlist."
|
||||
help = "Defines if more then one mpv.net process is allowed. (mpv.net specific setting)\n\nTip: Whenever the control key is pressed when files or URLs are opened, the playlist is not cleared but the files or URLs are appended to the playlist. This not only works on process startup but in all mpv.net features that open files."
|
||||
options = [{ name = "multi", help = "Create a new process everytime the shell starts mpv.net" },
|
||||
{ name = "single", help = "Force a single process everytime the shell starts mpv.net" },
|
||||
{ name = "queue", help = "Force a single process and add files to playlist" }]
|
||||
@@ -26,7 +38,7 @@ options = [{ name = "multi", help = "Create a new process everytime the shell s
|
||||
name = "debug-mode"
|
||||
default = "no"
|
||||
filter = "General"
|
||||
help = "mpv.net specific setting that writes debug info to a file located on the desktop."
|
||||
help = "Enable this only when a developer asks for it. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
@@ -34,14 +46,19 @@ options = [{ name = "yes" },
|
||||
name = "start-size"
|
||||
default = "previous"
|
||||
filter = "Screen"
|
||||
help = "mpv.net specific setting to remember the window height in the current session, otherwise the video's native resolution is used."
|
||||
help = "Setting to remember the window height in the current session, otherwise the video's native resolution is used. (mpv.net specific setting)"
|
||||
options = [{ name = "video", help = "Window size is set to native video resolution" },
|
||||
{ name = "previous", help = "Window size is remembered but only from the current session" }]
|
||||
|
||||
[[settings]]
|
||||
name = "start-threshold"
|
||||
filter = "Screen"
|
||||
help = "Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. (mpv.net specific setting) Default: 1500"
|
||||
|
||||
[[settings]]
|
||||
name = "remember-position"
|
||||
default = "no"
|
||||
filter = "Screen"
|
||||
help = "mpv.net specific setting to save the window position on exit."
|
||||
help = "Setting to save the window position on exit. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
@@ -9,7 +10,6 @@ namespace mpvnet
|
||||
{
|
||||
InitializeComponent();
|
||||
Version.Text = $"Version {System.Windows.Forms.Application.ProductVersion}";
|
||||
Foreground = WPF.WPF.ThemeBrush;
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e) => Close();
|
||||
|
||||
@@ -141,8 +141,12 @@ namespace mpvnet
|
||||
{
|
||||
Everything_GetResultFullPathName(i, buf, bufsize);
|
||||
string ext = Path.GetExtension(buf.ToString()).TrimStart('.').ToLower();
|
||||
if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext))
|
||||
|
||||
if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext) ||
|
||||
App.ImageTypes.Contains(ext))
|
||||
|
||||
items.Add(buf.ToString());
|
||||
|
||||
if (items.Count > 100) break;
|
||||
}
|
||||
Application.Current.Dispatcher.Invoke(() => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
@@ -61,59 +60,59 @@ namespace mpvnet
|
||||
case WF.Keys.NumPad9:
|
||||
text = "KP" + e.KeyCode.ToString()[6].ToString(); break;
|
||||
case WF.Keys.Space:
|
||||
text = "Space"; break;
|
||||
text = "SPACE"; break;
|
||||
case WF.Keys.Enter:
|
||||
text = "Enter"; break;
|
||||
text = "ENTER"; break;
|
||||
case WF.Keys.Tab:
|
||||
text = "Tab"; break;
|
||||
text = "TAB"; break;
|
||||
case WF.Keys.Back:
|
||||
text = "BS"; break;
|
||||
case WF.Keys.Delete:
|
||||
text = "Del"; break;
|
||||
text = "DEL"; break;
|
||||
case WF.Keys.Insert:
|
||||
text = "Ins"; break;
|
||||
text = "INS"; break;
|
||||
case WF.Keys.Home:
|
||||
text = "Home"; break;
|
||||
text = "HOME"; break;
|
||||
case WF.Keys.End:
|
||||
text = "End"; break;
|
||||
text = "END"; break;
|
||||
case WF.Keys.PageUp:
|
||||
text = "PGUP"; break;
|
||||
case WF.Keys.PageDown:
|
||||
text = "PGDWN"; break;
|
||||
case WF.Keys.Escape:
|
||||
text = "Esc"; break;
|
||||
text = "ESC"; break;
|
||||
case WF.Keys.PrintScreen:
|
||||
text = "Print"; break;
|
||||
text = "PRINT"; break;
|
||||
case WF.Keys.Play:
|
||||
text = "Play"; break;
|
||||
text = "PLAY"; break;
|
||||
case WF.Keys.Pause:
|
||||
text = "Pause"; break;
|
||||
text = "PAUSE"; break;
|
||||
case WF.Keys.MediaPlayPause:
|
||||
text = "PlayPause"; break;
|
||||
text = "PLAYPAUSE"; break;
|
||||
case WF.Keys.MediaStop:
|
||||
text = "Stop"; break;
|
||||
text = "STOP"; break;
|
||||
case WF.Keys.MediaNextTrack:
|
||||
text = "Next"; break;
|
||||
text = "NEXT"; break;
|
||||
case WF.Keys.MediaPreviousTrack:
|
||||
text = "Prev"; break;
|
||||
text = "PREV"; break;
|
||||
case WF.Keys.VolumeUp:
|
||||
text = "Volume_Up"; break;
|
||||
text = "VOLUME_UP"; break;
|
||||
case WF.Keys.VolumeDown:
|
||||
text = "Volume_Down"; break;
|
||||
text = "VOLUME_DOWN"; break;
|
||||
case WF.Keys.VolumeMute:
|
||||
text = "Mute"; break;
|
||||
text = "MUTE"; break;
|
||||
case WF.Keys.BrowserHome:
|
||||
text = "Homepage"; break;
|
||||
text = "HOMEPAGE"; break;
|
||||
case WF.Keys.LaunchMail:
|
||||
text = "Mail"; break;
|
||||
text = "MAIL"; break;
|
||||
case WF.Keys.BrowserFavorites:
|
||||
text = "Favorites"; break;
|
||||
text = "FAVORITES"; break;
|
||||
case WF.Keys.BrowserSearch:
|
||||
text = "Search"; break;
|
||||
text = "SEARCH"; break;
|
||||
case WF.Keys.Sleep:
|
||||
text = "Sleep"; break;
|
||||
text = "SLEEP"; break;
|
||||
case WF.Keys.Cancel:
|
||||
text = "Cancel"; break;
|
||||
text = "CANCEL"; break;
|
||||
}
|
||||
|
||||
bool shiftWasHandled = false;
|
||||
@@ -138,11 +137,14 @@ namespace mpvnet
|
||||
SetKey(text);
|
||||
}
|
||||
|
||||
DateTime LastKeyUp;
|
||||
|
||||
void SetKey(string key)
|
||||
{
|
||||
NewKey = key;
|
||||
MenuTextBlock.Text = InputItem.Path;
|
||||
KeyTextBlock.Text = key;
|
||||
LastKeyUp = DateTime.Now;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
@@ -187,49 +189,66 @@ namespace mpvnet
|
||||
OnKeyUp(new WF.KeyEventArgs((WF.Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys));
|
||||
else if (m.Msg == WM_APPCOMMAND)
|
||||
{
|
||||
switch ((AppCommand)(m.LParam.ToInt32() >> 16))
|
||||
var value = (AppCommand)(m.LParam.ToInt64() >> 16 & ~0xf000);
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case AppCommand.MEDIA_CHANNEL_DOWN:
|
||||
SetKey("Channel_Down");
|
||||
case AppCommand.APPCOMMAND_MEDIA_CHANNEL_DOWN:
|
||||
SetKey("CHANNEL_DOWN");
|
||||
break;
|
||||
case AppCommand.MEDIA_CHANNEL_UP:
|
||||
SetKey("Channel_Up");
|
||||
case AppCommand.APPCOMMAND_MEDIA_CHANNEL_UP:
|
||||
SetKey("CHANNEL_UP");
|
||||
break;
|
||||
case AppCommand.MEDIA_FAST_FORWARD:
|
||||
SetKey("Forward");
|
||||
case AppCommand.APPCOMMAND_MEDIA_FAST_FORWARD:
|
||||
SetKey("FORWARD");
|
||||
break;
|
||||
case AppCommand.MEDIA_REWIND:
|
||||
SetKey("Rewind");
|
||||
case AppCommand.APPCOMMAND_MEDIA_REWIND:
|
||||
SetKey("REWIND");
|
||||
break;
|
||||
case AppCommand.MEDIA_PAUSE:
|
||||
SetKey("Pause");
|
||||
case AppCommand.APPCOMMAND_MEDIA_PAUSE:
|
||||
SetKey("PAUSE");
|
||||
break;
|
||||
case AppCommand.MEDIA_PLAY:
|
||||
SetKey("Play");
|
||||
case AppCommand.APPCOMMAND_MEDIA_PLAY:
|
||||
SetKey("PLAY");
|
||||
break;
|
||||
case AppCommand.MEDIA_PLAY_PAUSE:
|
||||
SetKey("PlayPause");
|
||||
case AppCommand.APPCOMMAND_MEDIA_PLAY_PAUSE:
|
||||
SetKey("PLAYPAUSE");
|
||||
break;
|
||||
case AppCommand.MEDIA_NEXTTRACK:
|
||||
SetKey("Next");
|
||||
case AppCommand.APPCOMMAND_MEDIA_NEXTTRACK:
|
||||
SetKey("NEXT");
|
||||
break;
|
||||
case AppCommand.MEDIA_PREVIOUSTRACK:
|
||||
SetKey("Prev");
|
||||
case AppCommand.APPCOMMAND_MEDIA_PREVIOUSTRACK:
|
||||
SetKey("PREV");
|
||||
break;
|
||||
case AppCommand.MEDIA_RECORD:
|
||||
SetKey("Record");
|
||||
case AppCommand.APPCOMMAND_MEDIA_RECORD:
|
||||
SetKey("RECORD");
|
||||
break;
|
||||
case AppCommand.MEDIA_STOP:
|
||||
SetKey("Stop");
|
||||
case AppCommand.APPCOMMAND_MEDIA_STOP:
|
||||
SetKey("STOP");
|
||||
break;
|
||||
case AppCommand.VolumeUp:
|
||||
SetKey("Volume_Up");
|
||||
case AppCommand.APPCOMMAND_VOLUME_UP:
|
||||
SetKey("VOLUME_UP");
|
||||
break;
|
||||
case AppCommand.VolumeDown:
|
||||
SetKey("Volume_Down");
|
||||
case AppCommand.APPCOMMAND_VOLUME_DOWN:
|
||||
SetKey("VOLUME_DOWN");
|
||||
break;
|
||||
case AppCommand.VolumeMute:
|
||||
SetKey("Mute");
|
||||
case AppCommand.APPCOMMAND_VOLUME_MUTE:
|
||||
SetKey("MUTE");
|
||||
break;
|
||||
case AppCommand.APPCOMMAND_BROWSER_HOME:
|
||||
SetKey("HOMEPAGE");
|
||||
break;
|
||||
case AppCommand.APPCOMMAND_LAUNCH_MAIL:
|
||||
SetKey("MAIL");
|
||||
break;
|
||||
case AppCommand.APPCOMMAND_BROWSER_FAVORITES:
|
||||
SetKey("FAVORITES");
|
||||
break;
|
||||
case AppCommand.APPCOMMAND_BROWSER_SEARCH:
|
||||
SetKey("SEARCH");
|
||||
break;
|
||||
case AppCommand.APPCOMMAND_PRINT:
|
||||
SetKey("PRINT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -237,20 +256,58 @@ namespace mpvnet
|
||||
|
||||
internal enum AppCommand
|
||||
{
|
||||
MEDIA_CHANNEL_DOWN = 52,
|
||||
MEDIA_CHANNEL_UP = 51,
|
||||
MEDIA_FAST_FORWARD = 49,
|
||||
MEDIA_NEXTTRACK = 11,
|
||||
MEDIA_PAUSE = 47,
|
||||
MEDIA_PLAY = 46,
|
||||
MEDIA_PLAY_PAUSE = 14,
|
||||
MEDIA_PREVIOUSTRACK = 12,
|
||||
MEDIA_RECORD = 48,
|
||||
MEDIA_REWIND = 50,
|
||||
MEDIA_STOP = 13,
|
||||
VolumeMute = 8,
|
||||
VolumeDown = 9,
|
||||
VolumeUp = 10
|
||||
APPCOMMAND_BASS_BOOST = 20,
|
||||
APPCOMMAND_BASS_DOWN = 19,
|
||||
APPCOMMAND_BASS_UP = 21,
|
||||
APPCOMMAND_BROWSER_BACKWARD = 1,
|
||||
APPCOMMAND_BROWSER_FAVORITES = 6,
|
||||
APPCOMMAND_BROWSER_FORWARD = 2,
|
||||
APPCOMMAND_BROWSER_HOME = 7,
|
||||
APPCOMMAND_BROWSER_REFRESH = 3,
|
||||
APPCOMMAND_BROWSER_SEARCH = 5,
|
||||
APPCOMMAND_BROWSER_STOP = 4,
|
||||
APPCOMMAND_CLOSE = 31,
|
||||
APPCOMMAND_COPY = 36,
|
||||
APPCOMMAND_CORRECTION_LIST = 45,
|
||||
APPCOMMAND_CUT = 37,
|
||||
APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE = 43,
|
||||
APPCOMMAND_FIND = 28,
|
||||
APPCOMMAND_FORWARD_MAIL = 40,
|
||||
APPCOMMAND_HELP = 27,
|
||||
APPCOMMAND_LAUNCH_APP1 = 17,
|
||||
APPCOMMAND_LAUNCH_APP2 = 18,
|
||||
APPCOMMAND_LAUNCH_MAIL = 15,
|
||||
APPCOMMAND_LAUNCH_MEDIA_SELECT = 16,
|
||||
APPCOMMAND_MEDIA_CHANNEL_DOWN = 52,
|
||||
APPCOMMAND_MEDIA_CHANNEL_UP = 51,
|
||||
APPCOMMAND_MEDIA_FAST_FORWARD = 49,
|
||||
APPCOMMAND_MEDIA_NEXTTRACK = 11,
|
||||
APPCOMMAND_MEDIA_PAUSE = 47,
|
||||
APPCOMMAND_MEDIA_PLAY = 46,
|
||||
APPCOMMAND_MEDIA_PLAY_PAUSE = 14,
|
||||
APPCOMMAND_MEDIA_PREVIOUSTRACK = 12,
|
||||
APPCOMMAND_MEDIA_RECORD = 48,
|
||||
APPCOMMAND_MEDIA_REWIND = 50,
|
||||
APPCOMMAND_MEDIA_STOP = 13,
|
||||
APPCOMMAND_MIC_ON_OFF_TOGGLE = 44,
|
||||
APPCOMMAND_MICROPHONE_VOLUME_DOWN = 25,
|
||||
APPCOMMAND_MICROPHONE_VOLUME_MUTE = 24,
|
||||
APPCOMMAND_MICROPHONE_VOLUME_UP = 26,
|
||||
APPCOMMAND_NEW = 29,
|
||||
APPCOMMAND_OPEN = 30,
|
||||
APPCOMMAND_PASTE = 38,
|
||||
APPCOMMAND_PRINT = 33,
|
||||
APPCOMMAND_REDO = 35,
|
||||
APPCOMMAND_REPLY_TO_MAIL = 39,
|
||||
APPCOMMAND_SAVE = 32,
|
||||
APPCOMMAND_SEND_MAIL = 41,
|
||||
APPCOMMAND_SPELL_CHECK = 42,
|
||||
APPCOMMAND_TREBLE_DOWN = 22,
|
||||
APPCOMMAND_TREBLE_UP = 23,
|
||||
APPCOMMAND_UNDO = 34,
|
||||
APPCOMMAND_VOLUME_DOWN = 9,
|
||||
APPCOMMAND_VOLUME_MUTE = 8,
|
||||
APPCOMMAND_VOLUME_UP = 10
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
using Microsoft.Win32;
|
||||
using mpvnet;
|
||||
|
||||
namespace WPF
|
||||
{
|
||||
public class WPF
|
||||
@@ -22,12 +26,43 @@ namespace WPF
|
||||
}
|
||||
}
|
||||
|
||||
public static Brush ThemeBrush {
|
||||
public static Brush ThemeBrush { get; } = new SolidColorBrush(ThemeColor);
|
||||
|
||||
static bool WasThemeColorSet;
|
||||
|
||||
static Color _ThemeColor;
|
||||
|
||||
public static Color ThemeColor {
|
||||
get {
|
||||
if (!WasThemeColorSet)
|
||||
{
|
||||
Color? color = null;
|
||||
|
||||
try {
|
||||
if (App.IsDarkMode && !string.IsNullOrEmpty(App.DarkColor))
|
||||
color = (Color)ColorConverter.ConvertFromString(App.DarkColor);
|
||||
else if (!App.IsDarkMode && !string.IsNullOrEmpty(App.LightColor))
|
||||
color = (Color)ColorConverter.ConvertFromString(App.LightColor);
|
||||
} catch { }
|
||||
|
||||
if (!color.HasValue)
|
||||
{
|
||||
if (Environment.OSVersion.Version.Major < 10)
|
||||
return new SolidColorBrush(Colors.DarkSlateGray);
|
||||
{
|
||||
int argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0));
|
||||
var wfc = System.Drawing.Color.FromArgb(argb);
|
||||
color = Color.FromArgb(wfc.A, wfc.R, wfc.G, wfc.B);
|
||||
}
|
||||
else
|
||||
return SystemParameters.WindowGlassBrush;
|
||||
color = SystemParameters.WindowGlassColor;
|
||||
}
|
||||
|
||||
if (App.IsDarkMode && color == Colors.Black) color = Colors.Orange;
|
||||
if (!App.IsDarkMode && color == Colors.White) color = Colors.Orange;
|
||||
_ThemeColor = color.Value;
|
||||
WasThemeColorSet = true;
|
||||
}
|
||||
return _ThemeColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
mpv.net/WinForms/MainForm.Designer.cs
generated
3
mpv.net/WinForms/MainForm.Designer.cs
generated
@@ -45,13 +45,12 @@
|
||||
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(1777, 1109);
|
||||
this.ClientSize = new System.Drawing.Size(542, 0);
|
||||
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
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.Text = "mpv.net";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace mpvnet
|
||||
@@ -30,14 +31,13 @@ namespace mpvnet
|
||||
|
||||
try
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
Application.ThreadException += Application_ThreadException;
|
||||
Msg.SupportURL = "https://github.com/stax76/mpv.net#support";
|
||||
Instance = this;
|
||||
WPF.WPF.Init();
|
||||
System.Windows.Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
|
||||
Hwnd = Handle;
|
||||
Text += " " + Application.ProductVersion;
|
||||
mp.Init();
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, e) => Msg.ShowError(e.ExceptionObject.ToString());
|
||||
Application.ThreadException += (sender, e) => Msg.ShowException(e.Exception);
|
||||
Msg.SupportURL = "https://github.com/stax76/mpv.net#support";
|
||||
Text = "mpv.net " + Application.ProductVersion;
|
||||
|
||||
object recent = RegHelp.GetObject(App.RegPath, "Recent");
|
||||
|
||||
@@ -46,6 +46,10 @@ namespace mpvnet
|
||||
else
|
||||
RecentFiles = new List<string>();
|
||||
|
||||
ContextMenu = new ContextMenuStripEx(components);
|
||||
ContextMenu.Opened += ContextMenu_Opened;
|
||||
ContextMenu.Opening += ContextMenu_Opening;
|
||||
|
||||
App.ProcessCommandLineEarly();
|
||||
|
||||
if (mp.Screen == -1) mp.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
|
||||
@@ -71,8 +75,8 @@ namespace mpvnet
|
||||
mp.VideoSizeChanged += VideoSizeChanged;
|
||||
mp.FileLoaded += FileLoaded;
|
||||
mp.Idle += Idle;
|
||||
Task.Run(() => mp.Init());
|
||||
mp.VideoSizeAutoResetEvent.WaitOne(1000);
|
||||
mp.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
|
||||
if (Height < FontHeight * 4) SetFormPosAndSize();
|
||||
mp.observe_property_bool("fullscreen", PropChangeFullscreen);
|
||||
mp.observe_property_bool("ontop", PropChangeOnTop);
|
||||
mp.observe_property_bool("border", PropChangeBorder);
|
||||
@@ -221,6 +225,8 @@ namespace mpvnet
|
||||
return null;
|
||||
}
|
||||
|
||||
bool WasInitialSizeSet;
|
||||
|
||||
void SetFormPosAndSize()
|
||||
{
|
||||
if (mp.Fullscreen)
|
||||
@@ -229,25 +235,55 @@ namespace mpvnet
|
||||
return;
|
||||
}
|
||||
|
||||
Size size = mp.VideoSize;
|
||||
Screen screen = Screen.FromControl(this);
|
||||
int fixedHeight = Convert.ToInt32(screen.Bounds.Height * mp.Autofit);
|
||||
int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * mp.Autofit);
|
||||
|
||||
if (size.Height == 0 || size.Width == 0 || size.Width / (float)size.Height < 1.3)
|
||||
{
|
||||
size.Height = fixedHeight;
|
||||
size.Width = (int)(fixedHeight * 1.7);
|
||||
}
|
||||
if (mp.VideoSize.Height == 0 || mp.VideoSize.Width == 0 ||
|
||||
mp.VideoSize.Width / (float)mp.VideoSize.Height < 1.3)
|
||||
|
||||
mp.VideoSize = new Size((int)(autoFitHeight * (16 / 9.0)), autoFitHeight);
|
||||
|
||||
Size size = mp.VideoSize;
|
||||
|
||||
int height = size.Height;
|
||||
|
||||
if (App.RememberHeight)
|
||||
{
|
||||
if (WasInitialSizeSet)
|
||||
height = ClientSize.Height;
|
||||
|
||||
if (height > screen.Bounds.Height * 0.9)
|
||||
height = fixedHeight;
|
||||
else
|
||||
{
|
||||
height = autoFitHeight;
|
||||
WasInitialSizeSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
int width = Convert.ToInt32(height * size.Width / (double)size.Height);
|
||||
|
||||
if (height > screen.WorkingArea.Height * 0.9)
|
||||
{
|
||||
height = Convert.ToInt32(screen.WorkingArea.Height * 0.9);
|
||||
width = Convert.ToInt32(height * size.Width / (double)size.Height);
|
||||
}
|
||||
|
||||
if (width > screen.WorkingArea.Width * 0.9)
|
||||
{
|
||||
width = Convert.ToInt32(screen.WorkingArea.Width * 0.9);
|
||||
height = Convert.ToInt32(width * size.Height / (double)size.Width);
|
||||
}
|
||||
|
||||
if (height < screen.WorkingArea.Height * mp.AutofitSmaller)
|
||||
{
|
||||
height = Convert.ToInt32(screen.WorkingArea.Height * mp.AutofitSmaller);
|
||||
width = Convert.ToInt32(height * size.Width / (double)size.Height);
|
||||
}
|
||||
|
||||
if (height > screen.WorkingArea.Height * mp.AutofitLarger)
|
||||
{
|
||||
height = Convert.ToInt32(screen.WorkingArea.Height * mp.AutofitLarger);
|
||||
width = Convert.ToInt32(height * size.Width / (double)size.Height);
|
||||
}
|
||||
|
||||
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
||||
var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
||||
NativeHelp.AddWindowBorders(Handle, ref rect);
|
||||
@@ -340,16 +376,6 @@ namespace mpvnet
|
||||
if (RecentFiles.Count > 15) RecentFiles.RemoveAt(15);
|
||||
}
|
||||
|
||||
void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
|
||||
{
|
||||
Msg.ShowException(e.Exception);
|
||||
}
|
||||
|
||||
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Msg.ShowError(e.ExceptionObject.ToString());
|
||||
}
|
||||
|
||||
protected override CreateParams CreateParams {
|
||||
get {
|
||||
CreateParams cp = base.CreateParams;
|
||||
@@ -360,7 +386,7 @@ namespace mpvnet
|
||||
|
||||
protected override void WndProc(ref Message m)
|
||||
{
|
||||
//System.Diagnostics.Debug.WriteLine(m);
|
||||
//Debug.WriteLine(m);
|
||||
|
||||
switch (m.Msg)
|
||||
{
|
||||
@@ -368,13 +394,14 @@ namespace mpvnet
|
||||
case 0x0202: // WM_LBUTTONUP
|
||||
case 0x0207: // WM_MBUTTONDOWN
|
||||
case 0x0208: // WM_MBUTTONUP
|
||||
case 0x020b: // WM_XBUTTONDOWN
|
||||
case 0x020c: // WM_XBUTTONUP
|
||||
case 0x020A: // WM_MOUSEWHEEL
|
||||
case 0x020C: // WM_XBUTTONUP
|
||||
case 0x020B: // WM_XBUTTONDOWN
|
||||
case 0x0100: // WM_KEYDOWN
|
||||
case 0x0101: // WM_KEYUP
|
||||
case 0x0104: // WM_SYSKEYDOWN
|
||||
case 0x0105: // WM_SYSKEYUP
|
||||
case 0x319: // WM_APPCOMMAND
|
||||
if (mp.WindowHandle != IntPtr.Zero)
|
||||
Native.SendMessage(mp.WindowHandle, m.Msg, m.WParam, m.LParam);
|
||||
break;
|
||||
@@ -388,10 +415,6 @@ namespace mpvnet
|
||||
case 0x2a3: // WM_MOUSELEAVE
|
||||
mp.command_string("mouse 1 1"); // osc won't always auto hide
|
||||
break;
|
||||
case 0x319: // WM_APPCOMMAND
|
||||
if (mp.WindowHandle != IntPtr.Zero)
|
||||
Native.PostMessage(mp.WindowHandle, m.Msg, m.WParam, m.LParam);
|
||||
break;
|
||||
case 0x203: // Native.WM.LBUTTONDBLCLK
|
||||
{
|
||||
Point pos = PointToClient(Cursor.Position);
|
||||
@@ -408,7 +431,9 @@ namespace mpvnet
|
||||
var r = rc;
|
||||
NativeHelp.SubtractWindowBorders(Handle, ref r);
|
||||
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
|
||||
float aspect = mp.VideoSize.Width / (float)mp.VideoSize.Height;
|
||||
Size s = mp.VideoSize;
|
||||
if (s == Size.Empty) s = new Size(16, 9);
|
||||
float aspect = s.Width / (float)s.Height;
|
||||
int d_w = Convert.ToInt32(c_h * aspect - c_w);
|
||||
int d_h = Convert.ToInt32(c_w / aspect - c_h);
|
||||
int[] d_corners = { d_w, d_h, -d_w, -d_h };
|
||||
@@ -499,14 +524,16 @@ namespace mpvnet
|
||||
protected override void OnShown(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
if (App.IsDarkMode) ToolStripRendererEx.ColorTheme = Color.Black;
|
||||
ContextMenu = new ContextMenuStripEx(components);
|
||||
ContextMenu.Opened += ContextMenu_Opened;
|
||||
ContextMenu.Opening += ContextMenu_Opening;
|
||||
var wpfColor = WPF.WPF.ThemeColor;
|
||||
Color color = Color.FromArgb(wpfColor.A, wpfColor.R, wpfColor.G, wpfColor.B);
|
||||
ToolStripRendererEx.InitColors(color, App.IsDarkMode);
|
||||
BuildMenu();
|
||||
ContextMenuStrip = ContextMenu;
|
||||
WPF.WPF.Init();
|
||||
System.Windows.Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
|
||||
IgnoreDpiChanged = false;
|
||||
CheckClipboardForURL();
|
||||
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
@@ -534,7 +561,6 @@ namespace mpvnet
|
||||
}
|
||||
|
||||
RegHelp.SetObject(App.RegPath, "Recent", RecentFiles.ToArray());
|
||||
App.Exit();
|
||||
mp.commandv("quit");
|
||||
mp.ShutdownAutoResetEvent.WaitOne(3000);
|
||||
}
|
||||
|
||||
@@ -131,8 +131,10 @@ public class MenuItem : ToolStripMenuItem
|
||||
|
||||
public class ToolStripRendererEx : ToolStripSystemRenderer
|
||||
{
|
||||
public static bool IsDarkMode { get; set; }
|
||||
|
||||
public static Color ColorForeground { get; set; } = Color.Black;
|
||||
public static Color ColorTheme { get; set; } = Color.Empty;
|
||||
public static Color ColorTheme { get; set; }
|
||||
public static Color ColorChecked { get; set; }
|
||||
public static Color ColorBorder { get; set; }
|
||||
public static Color ColorTop { get; set; }
|
||||
@@ -146,19 +148,7 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
||||
|
||||
int TextOffset;
|
||||
|
||||
public ToolStripRendererEx()
|
||||
{
|
||||
var argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0));
|
||||
|
||||
if (argb == 0)
|
||||
argb = Color.LightBlue.ToArgb();
|
||||
if (ColorTheme == Color.Empty)
|
||||
InitColors(Color.FromArgb(argb));
|
||||
else
|
||||
InitColors(ColorTheme);
|
||||
}
|
||||
|
||||
public static void InitColors(Color c)
|
||||
public static void InitColors(Color c, bool darkMode)
|
||||
{
|
||||
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
|
||||
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(160);
|
||||
@@ -166,7 +156,7 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
||||
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(210);
|
||||
ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240);
|
||||
|
||||
if (ColorTheme == Color.Black)
|
||||
if (darkMode)
|
||||
{
|
||||
ColorBorder = Color.White;
|
||||
ColorBackground = Color.FromArgb(50, 50, 50);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
@@ -12,6 +13,8 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using WinForms = System.Windows.Forms;
|
||||
|
||||
using static mpvnet.libmpv;
|
||||
using static mpvnet.Native;
|
||||
|
||||
@@ -65,8 +68,8 @@ namespace mpvnet
|
||||
public static List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
|
||||
public static List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>();
|
||||
|
||||
public static string InputConfPath { get; } = ConfFolder + "\\input.conf";
|
||||
public static string ConfPath { get; } = ConfFolder + "\\mpv.conf";
|
||||
public static string InputConfPath { get; } = ConfigFolder + "\\input.conf";
|
||||
public static string ConfPath { get; } = ConfigFolder + "\\mpv.conf";
|
||||
public static string Sid { get; set; } = "";
|
||||
public static string Aid { get; set; } = "";
|
||||
public static string Vid { get; set; } = "";
|
||||
@@ -78,11 +81,14 @@ namespace mpvnet
|
||||
public static int Edition { get; set; }
|
||||
|
||||
public static float Autofit { get; set; } = 0.5f;
|
||||
public static float AutofitSmaller { get; set; } = 0.4f;
|
||||
public static float AutofitLarger { get; set; } = 0.75f;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
LoadLibrary("mpv-1.dll");
|
||||
Handle = mpv_create();
|
||||
set_property_string("config-dir", ConfigFolder);
|
||||
set_property_string("osc", "yes");
|
||||
set_property_string("config", "yes");
|
||||
set_property_string("wid", MainForm.Hwnd.ToString());
|
||||
@@ -101,10 +107,17 @@ namespace mpvnet
|
||||
switch (name)
|
||||
{
|
||||
case "autofit":
|
||||
if (value.Length == 3 && value.EndsWith("%"))
|
||||
if (int.TryParse(value.Substring(0, 2), out int result))
|
||||
if (int.TryParse(value.Trim('%'), out int result))
|
||||
Autofit = result / 100f;
|
||||
break;
|
||||
case "autofit-smaller":
|
||||
if (int.TryParse(value.Trim('%'), out int result2))
|
||||
AutofitSmaller = result2 / 100f;
|
||||
break;
|
||||
case "autofit-larger":
|
||||
if (int.TryParse(value.Trim('%'), out int result3))
|
||||
AutofitLarger = result3 / 100f;
|
||||
break;
|
||||
case "fs":
|
||||
case "fullscreen": Fullscreen = value == "yes"; break;
|
||||
case "border": Border = value == "yes"; break;
|
||||
@@ -112,48 +125,62 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
|
||||
static string _ConfFolder;
|
||||
static string _ConfigFolder;
|
||||
|
||||
public static string ConfFolder {
|
||||
public static string ConfigFolder {
|
||||
get {
|
||||
if (_ConfFolder == null)
|
||||
if (_ConfigFolder == null)
|
||||
{
|
||||
_ConfigFolder = Application.StartupPath + "\\portable_config\\";
|
||||
|
||||
if (!Directory.Exists(_ConfigFolder))
|
||||
_ConfigFolder = RegHelp.GetString(App.RegPath, "ConfigFolder");
|
||||
|
||||
if (!Directory.Exists(_ConfigFolder))
|
||||
{
|
||||
string portableFolder = Application.StartupPath + "\\portable_config\\";
|
||||
string appdataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
|
||||
string appdataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv.net\\";
|
||||
string appdataFolderMpv = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
|
||||
string startupFolder = Application.StartupPath + "\\";
|
||||
|
||||
if (!Directory.Exists(appdataFolder) && !Directory.Exists(portableFolder) &&
|
||||
Sys.IsDirectoryWritable(Application.StartupPath) &&
|
||||
!File.Exists(startupFolder + "mpv.conf"))
|
||||
{
|
||||
using (TaskDialog<string> td = new TaskDialog<string>())
|
||||
{
|
||||
td.MainInstruction = "Choose a settings folder.";
|
||||
td.Content = "[MPV documentation about files on Windows.](https://mpv.io/manual/master/#files-on-windows)";
|
||||
td.AddCommandLink("appdata", appdataFolder, appdataFolder);
|
||||
td.AddCommandLink("portable", portableFolder, portableFolder);
|
||||
td.AddCommandLink("startup", startupFolder, startupFolder);
|
||||
td.AddCommandLink(@"AppData\Roaming\mpv.net", appdataFolder, appdataFolder);
|
||||
td.AddCommandLink(@"AppData\Roaming\mpv", appdataFolderMpv, appdataFolderMpv);
|
||||
td.AddCommandLink("<startup>\\portable_config", portableFolder, portableFolder);
|
||||
td.AddCommandLink("<startup>", startupFolder, startupFolder);
|
||||
td.AddCommandLink("Choose custom folder", "custom");
|
||||
td.AllowCancel = false;
|
||||
_ConfFolder = td.Show();
|
||||
_ConfigFolder = td.Show();
|
||||
}
|
||||
|
||||
if (_ConfigFolder == "custom")
|
||||
{
|
||||
using (var d = new WinForms.FolderBrowserDialog())
|
||||
{
|
||||
d.Description = "Choose a folder.";
|
||||
if (d.ShowDialog() == WinForms.DialogResult.OK)
|
||||
_ConfigFolder = d.SelectedPath + "\\";
|
||||
else
|
||||
_ConfigFolder = appdataFolder;
|
||||
}
|
||||
}
|
||||
else if (Directory.Exists(portableFolder))
|
||||
_ConfFolder = portableFolder;
|
||||
else if (Directory.Exists(appdataFolder))
|
||||
_ConfFolder = appdataFolder;
|
||||
else if (File.Exists(Application.StartupPath + "\\mpv.conf"))
|
||||
_ConfFolder = Application.StartupPath + "\\";
|
||||
|
||||
if (string.IsNullOrEmpty(_ConfFolder)) _ConfFolder = appdataFolder;
|
||||
if (!Directory.Exists(_ConfFolder)) Directory.CreateDirectory(_ConfFolder);
|
||||
|
||||
if (!File.Exists(_ConfFolder + "\\input.conf"))
|
||||
File.WriteAllText(_ConfFolder + "\\input.conf", Properties.Resources.inputConf);
|
||||
|
||||
if (!File.Exists(_ConfFolder + "\\mpv.conf"))
|
||||
File.WriteAllText(_ConfFolder + "\\mpv.conf", Properties.Resources.mpvConf);
|
||||
}
|
||||
return _ConfFolder;
|
||||
|
||||
if (!Directory.Exists(_ConfigFolder))
|
||||
Directory.CreateDirectory(_ConfigFolder);
|
||||
|
||||
if (!_ConfigFolder.Contains("portable_config"))
|
||||
RegHelp.SetObject(App.RegPath, "ConfigFolder", _ConfigFolder);
|
||||
|
||||
if (!File.Exists(_ConfigFolder + "\\input.conf"))
|
||||
File.WriteAllText(_ConfigFolder + "\\input.conf", Properties.Resources.inputConf);
|
||||
|
||||
if (!File.Exists(_ConfigFolder + "\\mpv.conf"))
|
||||
File.WriteAllText(_ConfigFolder + "\\mpv.conf", Properties.Resources.mpvConf);
|
||||
}
|
||||
return _ConfigFolder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +205,9 @@ namespace mpvnet
|
||||
}
|
||||
|
||||
public static void LoadScripts()
|
||||
{
|
||||
|
||||
if (Directory.Exists(Application.StartupPath + "\\Scripts"))
|
||||
{
|
||||
string[] startupScripts = Directory.GetFiles(Application.StartupPath + "\\Scripts");
|
||||
|
||||
@@ -192,9 +222,10 @@ namespace mpvnet
|
||||
foreach (string scriptPath in startupScripts)
|
||||
if (Path.GetExtension(scriptPath) == ".ps1")
|
||||
PowerShellScript.Init(scriptPath);
|
||||
}
|
||||
|
||||
if (Directory.Exists(ConfFolder + "Scripts"))
|
||||
foreach (string scriptPath in Directory.GetFiles(ConfFolder + "Scripts"))
|
||||
if (Directory.Exists(ConfigFolder + "Scripts"))
|
||||
foreach (string scriptPath in Directory.GetFiles(ConfigFolder + "Scripts"))
|
||||
if (Path.GetExtension(scriptPath) == ".py")
|
||||
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
|
||||
else if (Path.GetExtension(scriptPath) == ".ps1")
|
||||
@@ -211,14 +242,16 @@ namespace mpvnet
|
||||
if (WindowHandle == IntPtr.Zero)
|
||||
WindowHandle = FindWindowEx(MainForm.Hwnd, IntPtr.Zero, "mpv", null);
|
||||
|
||||
//System.Diagnostics.Debug.WriteLine(evt.event_id.ToString());
|
||||
// Debug.WriteLine(evt.event_id.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
switch (evt.event_id)
|
||||
{
|
||||
case mpv_event_id.MPV_EVENT_SHUTDOWN:
|
||||
if (App.DebugMode) Trace.WriteLine("before Shutdown.Invoke");
|
||||
Shutdown?.Invoke();
|
||||
if (App.DebugMode) Trace.WriteLine("after Shutdown.Invoke");
|
||||
WriteHistory(null);
|
||||
ShutdownAutoResetEvent.Set();
|
||||
return;
|
||||
@@ -245,6 +278,16 @@ namespace mpvnet
|
||||
case mpv_event_id.MPV_EVENT_FILE_LOADED:
|
||||
HideLogo();
|
||||
FileLoaded?.Invoke();
|
||||
Size vidSize = new Size(get_property_int("width"), get_property_int("height"));
|
||||
if (vidSize.Width == 0 || vidSize.Height == 0)
|
||||
vidSize = new Size(1, 1);
|
||||
if (VideoSize != vidSize)
|
||||
{
|
||||
VideoSize = vidSize;
|
||||
VideoSizeChanged?.Invoke();
|
||||
}
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
Task.Run(new Action(() => ReadMetaData()));
|
||||
WriteHistory(get_property_string("path"));
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_TRACKS_CHANGED:
|
||||
@@ -309,17 +352,6 @@ namespace mpvnet
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART:
|
||||
PlaybackRestart?.Invoke();
|
||||
Size vidSize = new Size(get_property_int("dwidth"), get_property_int("dheight"));
|
||||
|
||||
if (VideoSize != vidSize && vidSize != Size.Empty)
|
||||
{
|
||||
VideoSize = vidSize;
|
||||
VideoSizeChanged?.Invoke();
|
||||
}
|
||||
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
|
||||
Task.Run(new Action(() => ReadMetaData()));
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_CHAPTER_CHANGE:
|
||||
ChapterChange?.Invoke();
|
||||
@@ -401,16 +433,14 @@ namespace mpvnet
|
||||
{
|
||||
if (Handle == IntPtr.Zero) return;
|
||||
int err = mpv_command_string(Handle, command);
|
||||
if (err < 0 && throwException)
|
||||
throw new Exception($"{(mpv_error)err}\r\n\r\n" + command);
|
||||
if (err < 0 && throwException) throw new Exception($"{(mpv_error)err}\n\n" + command);
|
||||
}
|
||||
|
||||
public static void set_property_string(string name, string value, bool throwOnException = false)
|
||||
{
|
||||
byte[] bytes = GetUtf8Bytes(value);
|
||||
int err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, ref bytes);
|
||||
if (err < 0 && throwOnException)
|
||||
throw new Exception($"{name}: {(mpv_error)err}");
|
||||
if (err < 0 && throwOnException) throw new Exception($"{name}: {(mpv_error)err}");
|
||||
}
|
||||
|
||||
public static string get_property_string(string name, bool throwOnException = false)
|
||||
@@ -418,7 +448,13 @@ namespace mpvnet
|
||||
try
|
||||
{
|
||||
int err = mpv_get_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, out IntPtr lpBuffer);
|
||||
if (err < 0 && throwOnException) throw new Exception($"{name}: {(mpv_error)err}");
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
if (throwOnException) throw new Exception($"{name}: {(mpv_error)err}");
|
||||
return "";
|
||||
}
|
||||
|
||||
string ret = StringFromNativeUtf8(lpBuffer);
|
||||
mpv_free(lpBuffer);
|
||||
return ret;
|
||||
@@ -434,9 +470,12 @@ namespace mpvnet
|
||||
{
|
||||
int err = mpv_get_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_INT64, out IntPtr lpBuffer);
|
||||
|
||||
if (err < 0 && throwOnException)
|
||||
throw new Exception($"{name}: {(mpv_error)err}");
|
||||
else
|
||||
if (err < 0)
|
||||
{
|
||||
if (throwOnException) throw new Exception($"{name}: {(mpv_error)err}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return lpBuffer.ToInt32();
|
||||
}
|
||||
|
||||
@@ -445,9 +484,12 @@ namespace mpvnet
|
||||
double val = 0;
|
||||
int err = mpv_get_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_DOUBLE, ref val);
|
||||
|
||||
if (err < 0 && throwOnException)
|
||||
throw new Exception($"{name}: {(mpv_error)err}");
|
||||
else
|
||||
if (err < 0)
|
||||
{
|
||||
if (throwOnException) throw new Exception($"{name}: {(mpv_error)err}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -465,9 +507,7 @@ namespace mpvnet
|
||||
{
|
||||
Int64 val = value;
|
||||
int err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_INT64, ref val);
|
||||
|
||||
if (err < 0 && throwOnException)
|
||||
throw new Exception($"{name}: {(mpv_error)err}");
|
||||
if (err < 0 && throwOnException) throw new Exception($"{name}: {(mpv_error)err}");
|
||||
}
|
||||
|
||||
public static void observe_property_int(string name, Action<int> action)
|
||||
@@ -516,7 +556,11 @@ namespace mpvnet
|
||||
|
||||
Load(files.ToArray(), App.ProcessInstance != "queue", Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
|
||||
if (files.Count == 0) VideoSizeAutoResetEvent.Set();
|
||||
if (files.Count == 0 || files[0].Contains("://"))
|
||||
{
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
VideoSizeChanged?.Invoke();
|
||||
}
|
||||
|
||||
foreach (string i in args)
|
||||
{
|
||||
@@ -564,6 +608,7 @@ namespace mpvnet
|
||||
|
||||
if (string.IsNullOrEmpty(get_property_string("path")))
|
||||
set_property_int("playlist-pos", 0);
|
||||
|
||||
if (loadFolder && !append) Task.Run(() => LoadFolder()); // user reported race condition
|
||||
}
|
||||
|
||||
@@ -575,7 +620,8 @@ namespace mpvnet
|
||||
List<string> files = Directory.GetFiles(Path.GetDirectoryName(path)).ToList();
|
||||
files = files.Where((file) =>
|
||||
App.VideoTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower()) ||
|
||||
App.AudioTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower())).ToList();
|
||||
App.AudioTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower()) ||
|
||||
App.ImageTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower())).ToList();
|
||||
files.Sort(new StringLogicalComparer());
|
||||
int index = files.IndexOf(path);
|
||||
files.Remove(path);
|
||||
@@ -628,20 +674,21 @@ namespace mpvnet
|
||||
static string LastHistoryPath;
|
||||
static DateTime LastHistoryStartDateTime;
|
||||
|
||||
static void WriteHistory(string filePath)
|
||||
static void WriteHistory(string path)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
int totalMinutes = Convert.ToInt32((DateTime.Now - LastHistoryStartDateTime).TotalMinutes);
|
||||
|
||||
if (File.Exists(LastHistoryPath) && totalMinutes > 1)
|
||||
{
|
||||
string historyFilepath = ConfFolder + "history.txt";
|
||||
string historyFilepath = ConfigFolder + "history.txt";
|
||||
|
||||
File.AppendAllText(historyFilepath, DateTime.Now.ToString().Substring(0, 16) +
|
||||
" " + totalMinutes.ToString().PadLeft(3) + " " +
|
||||
Path.GetFileNameWithoutExtension(LastHistoryPath) + "\r\n");
|
||||
}
|
||||
|
||||
LastHistoryPath = filePath;
|
||||
LastHistoryPath = path;
|
||||
LastHistoryStartDateTime = DateTime.Now;
|
||||
}
|
||||
|
||||
@@ -649,8 +696,8 @@ namespace mpvnet
|
||||
{
|
||||
if (MainForm.Instance is null) return;
|
||||
Rectangle cr = MainForm.Instance.ClientRectangle;
|
||||
if (cr.Width == 0 || cr.Height == 0) return;
|
||||
int len = cr.Height / 5;
|
||||
if (len == 0) return;
|
||||
|
||||
using (Bitmap b = new Bitmap(len, len))
|
||||
{
|
||||
@@ -675,8 +722,11 @@ namespace mpvnet
|
||||
lock (MediaTracks)
|
||||
{
|
||||
MediaTracks.Clear();
|
||||
string path = get_property_string("path");
|
||||
|
||||
using (MediaInfo mi = new MediaInfo(get_property_string("path")))
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using (MediaInfo mi = new MediaInfo(path))
|
||||
{
|
||||
int count = mi.GetCount(MediaInfoStreamKind.Video);
|
||||
|
||||
@@ -752,6 +802,7 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lock (Chapters)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@ Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesub
|
||||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "Associate video file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc video"
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "Associate audio file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc audio"
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "Associate image file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc image"
|
||||
|
||||
[UninstallRun]
|
||||
Filename: "{app}\{#MyAppExeName}"; Flags: runascurrentuser runhidden; Parameters: "--reg-file-assoc unreg"
|
||||
48
setup.ps1
48
setup.ps1
@@ -1,48 +0,0 @@
|
||||
# exit the script if the exit code is greater than 0
|
||||
function CheckExitCode {
|
||||
if ($LastExitCode -gt 0) {
|
||||
Write-Host "`nExit code $LastExitCode was returned.`n" -ForegroundColor Red
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
# exit the script if the file don't exist
|
||||
function CheckFileExist($path) {
|
||||
if (![IO.File]::Exists($path)) {
|
||||
Write-Host "`nFile is missing:`n`n$path`n" -ForegroundColor Red
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
$msbuild = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe"
|
||||
$innoSetup = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
||||
$sevenZip = "C:\Program Files\7-Zip\7z.exe"
|
||||
|
||||
# exit the script if one of the executables don't exist
|
||||
CheckFileExist($msbuild); CheckFileExist($innoSetup); CheckFileExist($sevenZip);
|
||||
|
||||
# build the projects using msbuild
|
||||
& $msbuild mpv.net.sln /p:Configuration=Debug /p:Platform=x64; CheckExitCode
|
||||
& $msbuild mpv.net.sln /p:Configuration=Debug /p:Platform=x86; CheckExitCode
|
||||
|
||||
# build the setups using inno setup
|
||||
& $innoSetup /Darch="x64" setup.iss; CheckExitCode
|
||||
& $innoSetup /Darch="x86" setup.iss; CheckExitCode
|
||||
|
||||
# create the x64 portable archives using 7zip
|
||||
$scriptDir = Split-Path -Path $PSCommandPath -Parent
|
||||
$desktopDir = [Environment]::GetFolderPath("Desktop")
|
||||
$exePath = $scriptDir + "\mpv.net\bin\x64\mpvnet.exe"
|
||||
$version = [Diagnostics.FileVersionInfo]::GetVersionInfo($exePath).FileVersion
|
||||
$targetDir = $desktopDir + "\mpv.net-portable-x64-" + $version
|
||||
Copy-Item $scriptDir\mpv.net\bin\x64 $targetDir -Recurse -Exclude System.Management.Automation.xml -Force
|
||||
& $sevenZip a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"; CheckExitCode
|
||||
& $sevenZip a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"; CheckExitCode
|
||||
|
||||
# create the x86 portable archives using 7zip
|
||||
$exePath = $scriptDir + "\mpv.net\bin\x86\mpvnet.exe"
|
||||
$version = [Diagnostics.FileVersionInfo]::GetVersionInfo($exePath).FileVersion
|
||||
$targetDir = $desktopDir + "\mpv.net-portable-x86-" + $version
|
||||
Copy-Item $scriptDir\mpv.net\bin\x86 $targetDir -Recurse -Exclude System.Management.Automation.xml -Force
|
||||
& $sevenZip a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"; CheckExitCode
|
||||
& $sevenZip a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"; CheckExitCode
|
||||
Reference in New Issue
Block a user