Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
857926696c | ||
|
|
4451a6c185 | ||
|
|
ea6a71b7c3 | ||
|
|
625dddcfbb | ||
|
|
0cd769fc0c | ||
|
|
f5e0c92824 | ||
|
|
327a097bcf | ||
|
|
68626fa536 | ||
|
|
8935101058 | ||
|
|
6947c925b9 | ||
|
|
4562131078 | ||
|
|
21188f0942 | ||
|
|
1316559ebc | ||
|
|
cd576f9211 | ||
|
|
1bac8e8937 | ||
|
|
e6d0449f8f | ||
|
|
e0e40b7918 | ||
|
|
b59f16a425 | ||
|
|
46b110d93b | ||
|
|
7e8a654ada | ||
|
|
c2c33228a0 | ||
|
|
0a28f13d51 | ||
|
|
9f3a1da931 | ||
|
|
05874ad6be | ||
|
|
078e8046bd | ||
|
|
b07901485e | ||
|
|
a37cbef8a8 | ||
|
|
8debcc171c | ||
|
|
e230f0f474 | ||
|
|
558bd67591 | ||
|
|
a7e4892acf | ||
|
|
a0ba69c1aa | ||
|
|
1e7e80577d | ||
|
|
2177308b02 | ||
|
|
a8c2409ed1 | ||
|
|
1ef9e64a41 | ||
|
|
f0546485cf | ||
|
|
032e91e4b4 | ||
|
|
1447636eb7 | ||
|
|
966f96a02b | ||
|
|
954c014708 | ||
|
|
ad30dc5ae2 | ||
|
|
3f74344b99 | ||
|
|
96d8d88d09 | ||
|
|
8626b8283f | ||
|
|
d90025e8fe | ||
|
|
a572bd8553 | ||
|
|
0f5146e58c | ||
|
|
9c6c0f3506 | ||
|
|
8c36cc8b8c | ||
|
|
44435057d7 | ||
|
|
135bdeb638 | ||
|
|
93c93b620d | ||
|
|
247aefbf07 | ||
|
|
0a8397652f | ||
|
|
ecd5b01161 | ||
|
|
1e9893977d | ||
|
|
4fd6b13e0f | ||
|
|
d21d36c196 | ||
|
|
fbffbea641 | ||
|
|
9899c2cd27 | ||
|
|
10370e9ae2 |
111
Changelog.md
@@ -1,3 +1,106 @@
|
||||
### 5.4.2
|
||||
|
||||
- new: the [scripting wiki page](https://github.com/stax76/mpv.net/wiki/Scripting#powershell) was improved
|
||||
- new: Toggle Shuffle has been added to the menu defaults
|
||||
- new: for URLs the media title is shown in the title bar and in the info command
|
||||
instead of displaying the URL, mpv.conf defaults were changed to use
|
||||
[protocol.https] osd-playing-msg = '${media-title}'
|
||||
|
||||
- fix: on the very first start volume was set to 0 and mute was set to yes
|
||||
- fix: there was a sound when closed from taskbar
|
||||
- fix: the log feature was not working
|
||||
- fix: clipboard monitoring removed because it was causing to many issues
|
||||
- fix: restore resulted in collapsed window when maximized = yes was used
|
||||
|
||||
- update: libmpv shinchiro 2019-10-06
|
||||
- update: youtube-dl 2019-10-01
|
||||
|
||||
### 5.4.1.1
|
||||
|
||||
- a issue with the taskbar-progress feature was fixed
|
||||
- improved PowerShell scrip host
|
||||
|
||||
### 5.4.1
|
||||
|
||||
- fix ArgumentOutOfRangeException
|
||||
|
||||
### 5.4
|
||||
|
||||
- added taskbar-progress implementation
|
||||
- added new setting to start with maximized window
|
||||
- long file paths work now even if not enabled by the OS
|
||||
- fixed history being written even when history file wasn't created prior
|
||||
- libmpv updated to shinchiro 2019-08-31
|
||||
|
||||
### 5.3
|
||||
|
||||
- added new feature: Open > Open DVD/Blu-ray Drive/Folder...
|
||||
- the default of remember-volume has been set to yes
|
||||
- scale, cscale, dscale defaults have been set to spline36,
|
||||
profile=gpu-hq is not used in the defaults because it starts very slow
|
||||
- new menu items have been added to navigate to the first and
|
||||
last playlist position, key bindings: Home, End
|
||||
- new config setting recent-count added, amount of menu items
|
||||
shown under 'Open > Recent'
|
||||
- in the config dialog the description for keep-open was corrected
|
||||
because unlike mpv, mpv.net will never terminate automatically
|
||||
- there was a rare occasion where the mpv.net logo wasn't shown
|
||||
- fix excessive memory usage using `osd-scale-by-window = no`
|
||||
- mpv setting osd-scale-by-window added to config dialog
|
||||
|
||||
### 5.2.1
|
||||
|
||||
- fixed race condition causing various features to fail
|
||||
|
||||
### 5.2
|
||||
|
||||
- bug fix for single-instance not working with unicode filenames
|
||||
- bug fix for logo not shown on start
|
||||
- osd-visibility.js script was removed because the OSC uses too much memory
|
||||
- youtube-dl was updated
|
||||
- libmpv was updated to shinchiro 2019-08-04
|
||||
- in case mpv.net was started from a terminal it sets now the mpv property input-terminal to yes,
|
||||
this means mpv.net will now receive and handle input keys from the terminal
|
||||
- certain command line properties didn't work (input-terminal, terminal, input-file,
|
||||
config, config-dir, input-conf, load-scripts, script, scripts, player-operation-mode)
|
||||
- the about dialog shows now the mpv version and build date
|
||||
- the dialog that asks for a config folder has now a cancel option
|
||||
|
||||
### 5.1
|
||||
|
||||
- 'Tools > Execute mpv command' was replaced with [mpv-repl](https://github.com/rossy/mpv-repl)
|
||||
- many [wiki pages](https://github.com/stax76/mpv.net/wiki) were improved
|
||||
- the logo/icon had a very small cosmetic change
|
||||
- the help in the context menu was improved,
|
||||
for quick access consider the command palette (F1 key)
|
||||
- config options specific to mpv.net are now available from the command line
|
||||
- the input editor no longer has known limitations, 'alt gr' and ctrl+alt are working now
|
||||
- the help in the input editor was simplified and the filter logic was improved
|
||||
- fixed issue in file associations causing mpv.net not to appear in OS default apps
|
||||
- 'Tools > Manage File Associations' was replaced by 'Tools > OS Setup',
|
||||
it has now a feature to add and remove mpv.net to and from the Path
|
||||
environment variable and the OS default apps settings can be opened (Win 10 only)
|
||||
- startup folder and config folder being identical was causing a critical issue
|
||||
as mpv.net was loading extensions twice and scripts four times, now identical
|
||||
folders are no longer permitted
|
||||
- error messages are shown when unknown scripts and extensions are found in the startup folder
|
||||
because user scripts and extensions are supposed to be located in the config folder instead
|
||||
- changing from maximized to fullscreen did not work
|
||||
- the search field in the config editor was not always remembered
|
||||
- new setting remember-volume added, saves volume and mute on exit
|
||||
and restores it on start.
|
||||
- it's now enforced that mpv properties on the command line and in
|
||||
the mpv.conf config file are lowercase, if not a error is shown
|
||||
- gpu-api vulkan was not working if media files were opened via
|
||||
command line (that included Explorer)
|
||||
- new setting minimum-aspect-ratio added, minimum aspect ratio for the window,
|
||||
this was previously hard coded to 1.3
|
||||
- new setting auto-load-folder added, for single files automatically load
|
||||
the entire directory into the playlist, previously this was forced,
|
||||
now it can be disabled
|
||||
- new setting themed-menu added, follow theme color in context menu,
|
||||
default: no. UI related settings have now a separate UI tab in the config editor
|
||||
|
||||
### 5.0
|
||||
|
||||
- [changed icon design](https://github.com/stax76/mpv.net/blob/master/img/mpvnet.png)
|
||||
@@ -12,13 +115,13 @@
|
||||
change is that there exist too many different terms, addons, addins,
|
||||
extensions, modules, packages etc.. mpv.net follows Google Chrome as the worlds
|
||||
most popular extendable app, Chrome uses the term Extension.
|
||||
- a thread synchronisation bug was fixed, the shutdown thread was aborted
|
||||
if it was running more then 3 seconds, this caused the rating extension
|
||||
to fail if it was waiting for a drive to wakeup
|
||||
- a thread synchronization bug was fixed, the shutdown thread was aborted
|
||||
if it was running more than 3 seconds, this caused the rating extension
|
||||
to fail if it was waiting for a drive to wake up
|
||||
- a new JavaScript was included to show the playlist with a smaller font size,
|
||||
the script is located at startup/scripts
|
||||
- terminal support added using mpvnet.com !
|
||||
- script engine performence and error handling was improved
|
||||
- script engine performance and error handling was improved
|
||||
- the [scripting wiki page](https://github.com/stax76/mpv.net/wiki/Scripting) was improved
|
||||
- the C# scripting host extension was converted from VB to C# because it's not
|
||||
only used for hosting but I also use it now to code and debug script code
|
||||
|
||||
10
Manual.md
@@ -133,7 +133,7 @@ It's also possible to change the default application using the Open With feature
|
||||
|
||||
In order to play videos from sites such as YouTube the Chrome Extension [Play with mpv](https://chrome.google.com/webstore/detail/play-with-mpv/hahklcmnfgffdlchjigehabfbiigleji) can be used.
|
||||
|
||||
Due to Chrome Extensions not being able to start a app, another app that communicates with the extension is required, this app can be downloaded [here](http://www.mediafire.com/file/6tmwdjsfknhmsxy/play-with-mpvnet-server.7z/file). The extension works only when the app is running, to have the app always running a link can be created in the auto start folder located at:
|
||||
Due to Chrome Extensions not being able to start a app, another app that communicates with the extension is required, this app can be downloaded [here](http://www.mediafire.com/file/lezj8lwqt5zf75v/play-with-mpvnet-server.7z/file). The extension works only when the app is running, to have the app always running a link can be created in the auto start folder located at:
|
||||
|
||||
`C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup`
|
||||
|
||||
@@ -149,9 +149,11 @@ The Open Files menu entry is one way to open files in mpv.net, it supports multi
|
||||
|
||||
Another way to open files is the command line, it is used by the Windows File Explorer if file associations exist.
|
||||
|
||||
When mpv.net is started from a terminal such as PowerShell, mpv.net attaches to the terminal and outputs status and debug messages.
|
||||
|
||||
A third way is to drag and drop files on the main window.
|
||||
|
||||
Whenever the control key is pressed when files are opened, the playlist is not cleared but the files are appended to the playlist.
|
||||
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 works in all mpv.net features that open files or URLs.
|
||||
|
||||
### Open > Open URL
|
||||
|
||||
@@ -159,7 +161,9 @@ The Open URL menu entry can be used to open URLs for example from YouTube.
|
||||
|
||||
mpv.net monitors the Windows clipboard and ask if URLs should be played in case it finds a URL in the clipboard. This feature uses a keyword whitelist that can be configured in the config editor.
|
||||
|
||||
Whenever the control key is pressed when URLs are opened, the playlist is not cleared but the URLs are appended to the playlist.
|
||||
When mpv.net is started from a terminal such as PowerShell, mpv.net attaches to the terminal and outputs status and debug messages.
|
||||
|
||||
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 works in all mpv.net features that open files or URLs.
|
||||
|
||||
### Open > Show media search
|
||||
|
||||
|
||||
51
README.md
@@ -1,5 +1,7 @@
|
||||

|
||||
|
||||
     [](https://www.paypal.me/stax76)
|
||||
|
||||
# 🎞 mpv.net
|
||||
|
||||
mpv.net is a modern media player for Windows that works just like [mpv](https://mpv.io).
|
||||
@@ -60,6 +62,8 @@ Table of contents
|
||||
- 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)
|
||||
- If started from a PowerShell terminal mpv.net will attach to the terminal and print status and debug output ([Screenshot](#terminal-and-repl-screenshot))
|
||||
- [OSD REPL](https://github.com/rossy/mpv-repl)
|
||||
- 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))
|
||||
@@ -76,7 +80,7 @@ Table of contents
|
||||
- Screenshot feature with many options
|
||||
- File history feature to log time and filename
|
||||
- A-B loop feature
|
||||
- watch later feature to save the position
|
||||
- Watch later feature to save the position
|
||||
- [Manual](#manual)
|
||||
|
||||
### Screenshots
|
||||
@@ -97,6 +101,12 @@ A searchable config editor as alternative to edit the mpv.conf file manually.
|
||||
|
||||

|
||||
|
||||
#### Terminal and REPL Screenshot
|
||||
|
||||
mpv.net attached to a PowerShell terminal showing the [OSD REPL](https://github.com/rossy/mpv-repl).
|
||||
|
||||

|
||||
|
||||
#### Input Editor Screenshot
|
||||
|
||||
A searchable key and mouse binding editor.
|
||||
@@ -218,39 +228,30 @@ Third party components:
|
||||
|
||||
[Support thread in VideoHelp forum](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows)
|
||||
|
||||
[Issue tracker to report bugs and request features](https://github.com/stax76/mpv.net/issues)
|
||||
[Issue tracker](https://github.com/stax76/mpv.net/issues), feel free to use for anything mpv.net related
|
||||
|
||||
[frank.skare.de@gmail.com](mailto:frank.skare.de@gmail.com?Subject=mpv.net%20support)
|
||||
|
||||
Please click on the star at the top of the page and like mpv.net at [alternativeto.net](https://alternativeto.net/software/mpv-net/).
|
||||
|
||||
If you like you can express your appreciation for my player by sending little beer money with paypal.
|
||||
If you want to support the development of mpv.net or express your appreciation you can do so with a donation:
|
||||
|
||||
<https://www.paypal.me/stax76>
|
||||
|
||||
### Links
|
||||
|
||||
mpv manual: <https://mpv.io/manual/master/>
|
||||
|
||||
mpv wiki: <https://github.com/mpv-player/mpv/wiki>
|
||||
|
||||
mpv.net wiki: <https://github.com/stax76/mpv.net/wiki>
|
||||
|
||||
mpv apps: <https://github.com/mpv-player/mpv/wiki/Applications-using-mpv>
|
||||
|
||||
mpv user scripts: <https://github.com/mpv-player/mpv/wiki/User-Scripts>
|
||||
|
||||
mpv default key bindings: <https://github.com/mpv-player/mpv/blob/master/etc/input.conf>
|
||||
|
||||
mpv.net default key bindings: <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
|
||||
|
||||
mpv download: <https://mpv.io/installation/>
|
||||
|
||||
mpv.net download: <https://github.com/stax76/mpv.net/releases>
|
||||
|
||||
mpv bugs and requests: <https://mpv.io/bug-reports/>
|
||||
|
||||
mpv.net bugs and requests: <https://github.com/stax76/mpv.net/issues>
|
||||
- mpv.net wiki: <https://github.com/stax76/mpv.net/wiki>
|
||||
- mpv.net default key bindings: <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
|
||||
- mpv.net download: <https://github.com/stax76/mpv.net/releases>
|
||||
- mpv.net bugs and requests: <https://github.com/stax76/mpv.net/issues>
|
||||
- mpv website: <https://mpv.io/>
|
||||
- mpv manual: <https://mpv.io/manual/master/>
|
||||
- mpv wiki: <https://github.com/mpv-player/mpv/wiki>
|
||||
- mpv apps: <https://github.com/mpv-player/mpv/wiki/Applications-using-mpv>
|
||||
- mpv user scripts: <https://github.com/mpv-player/mpv/wiki/User-Scripts>
|
||||
- mpv default key bindings: <https://github.com/mpv-player/mpv/blob/master/etc/input.conf>
|
||||
- mpv download: <https://mpv.io/installation/>
|
||||
- mpv bugs and requests: <https://mpv.io/bug-reports/>
|
||||
|
||||
### Changelog
|
||||
|
||||
@@ -258,4 +259,4 @@ mpv.net bugs and requests: <https://github.com/stax76/mpv.net/issues>
|
||||
|
||||
### Download
|
||||
|
||||
<https://github.com/stax76/mpv.net/releases>
|
||||
<https://github.com/stax76/mpv.net/releases>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
// This extension writes a rating to the filename of rated videos when mpv.net shuts down.
|
||||
|
||||
// The input.conf defaults contain key bindings for this extension to set ratings.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -26,13 +30,13 @@ namespace RatingExtension // the assembly name must end with 'Extension'
|
||||
{
|
||||
string filepath = i.Key;
|
||||
int rating = i.Value;
|
||||
if (String.IsNullOrEmpty(filepath) || ! File.Exists(filepath))
|
||||
if (String.IsNullOrEmpty(filepath) || !File.Exists(filepath))
|
||||
return;
|
||||
string basename = Path.GetFileNameWithoutExtension(filepath);
|
||||
|
||||
for (int x = 0; x < 6; x++)
|
||||
if (basename.Contains(" (" + x.ToString() + "stars)"))
|
||||
basename = basename.Replace(" (" + x.ToString() + "stars)", "");
|
||||
if (basename.Contains(" (" + x + "stars)"))
|
||||
basename = basename.Replace(" (" + x + "stars)", "");
|
||||
|
||||
basename += $" ({rating}stars)";
|
||||
string newPath = Path.Combine(Path.GetDirectoryName(filepath), basename + Path.GetExtension(filepath));
|
||||
@@ -58,4 +62,4 @@ namespace RatingExtension // the assembly name must end with 'Extension'
|
||||
Msg.Show("Rating Extension", "This extension writes a rating to the filename of rated videos when mpv.net shuts down.\n\nThe input.conf defaults contain key bindings for this extension to set ratings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>RatingExtension</RootNamespace>
|
||||
<AssemblyName>RatingExtension</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//'This extension implements the C# scripting feature of mpv.net which
|
||||
// This extension implements the C# scripting feature of mpv.net which
|
||||
// is based on CS-Script (https://www.cs-script.net).
|
||||
|
||||
// Furthermore the extension is used to code and debug scripts
|
||||
// because writing script code without debugger is not an option :-)
|
||||
// I also use this extension to code scripts in order to have full
|
||||
// code completion and debugger support, once the script code is
|
||||
// finished I move it from the extension to a standalone script.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using mpvnet;
|
||||
using CSScriptLibrary;
|
||||
@@ -18,7 +18,7 @@ namespace ScriptingExtension // the file name of extensions must end with 'Exten
|
||||
[Export(typeof(IExtension))]
|
||||
public class ScriptingExtension : IExtension
|
||||
{
|
||||
Script Script;
|
||||
//Script Script;
|
||||
|
||||
public ScriptingExtension()
|
||||
{
|
||||
@@ -28,8 +28,9 @@ namespace ScriptingExtension // the file name of extensions must end with 'Exten
|
||||
if (Directory.Exists(mp.ConfigFolder + "scripts"))
|
||||
scriptFiles.AddRange(Directory.GetFiles(mp.ConfigFolder + "scripts", "*.cs"));
|
||||
|
||||
if (Directory.Exists(Application.StartupPath + "\\scripts"))
|
||||
scriptFiles.AddRange(Directory.GetFiles(Application.StartupPath + "\\scripts", "*.cs"));
|
||||
if (Directory.Exists(Folder.Startup + "scripts"))
|
||||
foreach (string path in Directory.GetFiles(Folder.Startup + "scripts", "*.cs"))
|
||||
scriptFiles.AddRange(Directory.GetFiles(Folder.Startup + "scripts", "*.cs"));
|
||||
|
||||
if (scriptFiles.Count == 0) return;
|
||||
CSScriptLibrary.CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ScriptingExtension</RootNamespace>
|
||||
<AssemblyName>ScriptingExtension</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,40 +1,17 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
|
||||
using mpvnet;
|
||||
|
||||
class Script
|
||||
{
|
||||
MainForm Form;
|
||||
|
||||
bool WasPlaying;
|
||||
bool WasPaused;
|
||||
|
||||
public Script()
|
||||
{
|
||||
Form = MainForm.Instance;
|
||||
Form.Resize += Form_Resize;
|
||||
mp.Shutdown += Shutdown;
|
||||
}
|
||||
|
||||
private void Form_Resize(object sender, EventArgs e)
|
||||
private void Shutdown()
|
||||
{
|
||||
if (Form.WindowState == FormWindowState.Minimized)
|
||||
{
|
||||
WasPlaying = mp.get_property_string("pause") == "no";
|
||||
|
||||
if (WasPlaying)
|
||||
{
|
||||
mp.command("set pause yes");
|
||||
WasPaused = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WasPaused)
|
||||
{
|
||||
mp.command("set pause no");
|
||||
WasPaused = false;
|
||||
}
|
||||
}
|
||||
foreach (string file in Directory.GetFiles(@"C:\Users\frank\Desktop\aaa"))
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
BIN
img/Avatar.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 628 KiB |
BIN
img/Terminal.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
img/mpvnet.ico
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
BIN
img/mpvnet.pdn
BIN
img/mpvnet.png
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
@@ -3,6 +3,6 @@
|
||||
<configSections>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
||||
128
mpv.net/Misc/App.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public static class App
|
||||
{
|
||||
public static string[] VideoTypes { get; } = "264 265 asf avc avi avs flv h264 h265 hevc m2ts m2v m4v mkv mov mp4 mpeg mpg mpv mts ts vob vpy webm wmv y4m".Split(' ');
|
||||
public static string[] AudioTypes { get; } = "mp3 mp2 ac3 ogg opus flac wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 mka aac mpa".Split(' ');
|
||||
public static string[] ImageTypes { get; } = {"jpg", "bmp", "gif", "png"};
|
||||
public static string[] SubtitleTypes { get; } = { "srt", "ass", "idx", "sup", "ttxt", "ssa", "smi" };
|
||||
|
||||
public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName;
|
||||
public static string ConfPath { get => mp.ConfigFolder + "mpvnet.conf"; }
|
||||
public static string DarkMode { get; set; } = "always";
|
||||
public static string ProcessInstance { get; set; } = "single";
|
||||
public static string DarkColor { get; set; }
|
||||
public static string LightColor { get; set; }
|
||||
|
||||
public static bool RememberHeight { get; set; } = true;
|
||||
public static bool RememberPosition { get; set; }
|
||||
public static bool Maximized { get; set; }
|
||||
public static bool DebugMode { get; set; }
|
||||
public static bool IsStartedFromTerminal { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
|
||||
public static bool RememberVolume { get; set; } = true;
|
||||
public static bool AutoLoadFolder { get; set; } = true;
|
||||
public static bool ThemedMenu { get; set; }
|
||||
|
||||
public static int StartThreshold { get; set; } = 1500;
|
||||
public static int RecentCount { get; set; } = 15;
|
||||
|
||||
public static float MinimumAspectRatio { get; set; } = 1.3f;
|
||||
|
||||
public static Extension Extension { get; set; }
|
||||
|
||||
public static bool IsDarkMode {
|
||||
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
string dummy = mp.ConfigFolder;
|
||||
var dummy2 = mp.Conf;
|
||||
|
||||
foreach (var i in Conf)
|
||||
ProcessProperty(i.Key, i.Value);
|
||||
|
||||
if (App.DebugMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = mp.ConfigFolder + "mpvnet-debug.log";
|
||||
if (File.Exists(filePath)) File.Delete(filePath);
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
|
||||
Trace.AutoFlush = true;
|
||||
//if (App.DebugMode) Trace.WriteLine("");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Msg.ShowException(e);
|
||||
}
|
||||
}
|
||||
|
||||
mp.Shutdown += Shutdown;
|
||||
mp.Initialized += Initialized;
|
||||
}
|
||||
|
||||
private static void Initialized()
|
||||
{
|
||||
if (RememberVolume)
|
||||
{
|
||||
mp.set_property_int("volume", RegHelp.GetInt(App.RegPath, "Volume", 70));
|
||||
mp.set_property_string("mute", RegHelp.GetString(App.RegPath, "Mute", "no"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void Shutdown()
|
||||
{
|
||||
if (RememberVolume)
|
||||
{
|
||||
RegHelp.SetObject(App.RegPath, "Volume", mp.get_property_int("volume"));
|
||||
RegHelp.SetObject(App.RegPath, "Mute", mp.get_property_string("mute"));
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<string, string> _Conf;
|
||||
|
||||
public static Dictionary<string, string> Conf {
|
||||
get {
|
||||
if (_Conf == null)
|
||||
{
|
||||
_Conf = new Dictionary<string, string>();
|
||||
|
||||
if (File.Exists(ConfPath))
|
||||
foreach (string i in File.ReadAllLines(ConfPath))
|
||||
if (i.Contains("=") && !i.StartsWith("#"))
|
||||
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
||||
}
|
||||
return _Conf;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ProcessProperty(string name, string value)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "remember-position": RememberPosition = value == "yes"; return true;
|
||||
case "maximized": Maximized = value == "yes"; return true;
|
||||
case "start-size": RememberHeight = value == "previous"; return true;
|
||||
case "process-instance": ProcessInstance = value; return true;
|
||||
case "dark-mode": DarkMode = value; return true;
|
||||
case "debug-mode": DebugMode = value == "yes"; return true;
|
||||
case "dark-color": DarkColor = value.Trim('\'', '"'); return true;
|
||||
case "light-color": LightColor = value.Trim('\'', '"'); return true;
|
||||
case "remember-volume": RememberVolume = value == "yes"; return true;
|
||||
case "start-threshold": StartThreshold = value.Int(); return true;
|
||||
case "minimum-aspect-ratio": MinimumAspectRatio = value.Float(); return true;
|
||||
case "auto-load-folder": AutoLoadFolder = value == "yes"; return true;
|
||||
case "themed-menu": ThemedMenu = value == "yes"; return true;
|
||||
case "recent-count": RecentCount = value.Int(); return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,14 @@ namespace mpvnet
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case "manage-file-associations": ManageFileAssociations(); break;
|
||||
case "open-files": OpenFiles(args); break;
|
||||
case "open-url": OpenURL(); break;
|
||||
case "open-optical-media": Open_DVD_Or_BD_Folder(); break;
|
||||
case "manage-file-associations": // deprecated 2019
|
||||
case "show-setup-dialog": ShowDialog(typeof(SetupWindow)); break;
|
||||
case "cycle-audio": CycleAudio(); break;
|
||||
case "load-audio": LoadAudio(); break;
|
||||
case "load-sub": LoadSubtitle(); break;
|
||||
case "open-url": OpenURL(); break;
|
||||
case "execute-mpv-command": ExecuteMpvCommand(); break;
|
||||
case "show-history": ShowHistory(); break;
|
||||
case "show-media-search": ShowDialog(typeof(EverythingWindow)); break;
|
||||
@@ -29,12 +32,17 @@ namespace mpvnet
|
||||
case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break;
|
||||
case "show-input-editor": ShowDialog(typeof(InputWindow)); break;
|
||||
case "open-conf-folder": Process.Start(mp.ConfigFolder); break;
|
||||
case "open-files": OpenFiles(args); break;
|
||||
case "shell-execute": Process.Start(args[0]); break;
|
||||
case "show-info": ShowInfo(); break;
|
||||
case "playlist-last": PlaylistLast(); break;
|
||||
case "add-files-to-playlist": OpenFiles("append"); break; // deprecated 2019
|
||||
default: Msg.ShowError($"No command '{id}' found."); break;
|
||||
}
|
||||
|
||||
MainForm.Instance.BeginInvoke(new Action(() => {
|
||||
Message m = new Message() { Msg = 0x0202 }; // WM_LBUTTONUP
|
||||
Native.SendMessage(MainForm.Instance.Handle, m.Msg, m.WParam, m.LParam);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void InvokeOnMainThread(Action action) => MainForm.Instance.Invoke(action);
|
||||
@@ -66,16 +74,44 @@ namespace mpvnet
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Open_DVD_Or_BD_Folder()
|
||||
{
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
using (var d = new FolderBrowserDialog())
|
||||
{
|
||||
d.Description = "Select a DVD or Blu-ray folder.";
|
||||
d.ShowNewFolderButton = false;
|
||||
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (Directory.Exists(d.SelectedPath + "\\BDMV"))
|
||||
{
|
||||
mp.set_property_string("bluray-device", d.SelectedPath);
|
||||
mp.Load(new[] { @"bd://" }, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mp.set_property_string("dvd-device", d.SelectedPath);
|
||||
mp.Load(new[] { @"dvd://" }, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static void PlaylistLast() => mp.set_property_int("playlist-pos", mp.get_property_int("playlist-count") - 1);
|
||||
|
||||
public static void ShowHistory()
|
||||
{
|
||||
var fp = mp.ConfigFolder + "history.txt";
|
||||
|
||||
if (File.Exists(fp))
|
||||
Process.Start(fp);
|
||||
if (File.Exists(mp.ConfigFolder + "history.txt"))
|
||||
Process.Start(mp.ConfigFolder + "history.txt");
|
||||
else
|
||||
{
|
||||
if (Msg.ShowQuestion("Create history.txt file in config folder?",
|
||||
"mpv.net will write the date, time and filename of opened files to it.") == MsgResult.OK)
|
||||
File.WriteAllText(fp, "");
|
||||
|
||||
File.WriteAllText(mp.ConfigFolder + "history.txt", "");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowInfo()
|
||||
@@ -85,6 +121,10 @@ namespace mpvnet
|
||||
string performer, title, album, genre, date, duration, text = "";
|
||||
long fileSize = 0;
|
||||
string path = mp.get_property_string("path");
|
||||
|
||||
if (path.Contains("://"))
|
||||
path = mp.get_property_string("media-title");
|
||||
|
||||
int width = mp.get_property_int("video-params/w");
|
||||
int height = mp.get_property_int("video-params/h");
|
||||
|
||||
@@ -92,7 +132,7 @@ namespace mpvnet
|
||||
{
|
||||
fileSize = new FileInfo(path).Length;
|
||||
|
||||
if (App.AudioTypes.Contains(Path.GetExtension(path).ToLower().TrimStart('.')))
|
||||
if (App.AudioTypes.Contains(path.ShortExt()))
|
||||
{
|
||||
using (MediaInfo mediaInfo = new MediaInfo(path))
|
||||
{
|
||||
@@ -110,13 +150,13 @@ namespace mpvnet
|
||||
if (date != "") text += "Year: " + date + "\n";
|
||||
if (duration != "") text += "Length: " + duration + "\n";
|
||||
text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n";
|
||||
text += "Type: " + Path.GetExtension(path).ToUpper().TrimStart('.');
|
||||
text += "Type: " + path.ShortExt().ToUpper();
|
||||
|
||||
mp.commandv("show-text", text, "5000");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (App.ImageTypes.Contains(Path.GetExtension(path).ToLower().TrimStart('.')))
|
||||
else if (App.ImageTypes.Contains(path.ShortExt()))
|
||||
{
|
||||
using (MediaInfo mediaInfo = new MediaInfo(path))
|
||||
{
|
||||
@@ -124,7 +164,7 @@ namespace mpvnet
|
||||
"Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" +
|
||||
"Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" +
|
||||
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
|
||||
"Type: " + Path.GetExtension(path).ToUpper().TrimStart('.');
|
||||
"Type: " + path.ShortExt().ToUpper();
|
||||
|
||||
mp.commandv("show-text", text, "5000");
|
||||
return;
|
||||
@@ -137,7 +177,7 @@ namespace mpvnet
|
||||
string videoFormat = mp.get_property_string("video-format").ToUpper();
|
||||
string audioCodec = mp.get_property_string("audio-codec-name").ToUpper();
|
||||
|
||||
text = PathHelp.GetFileName(path) + "\n" +
|
||||
text = path.FileName() + "\n" +
|
||||
FormatTime(position.TotalMinutes) + ":" +
|
||||
FormatTime(position.Seconds) + " / " +
|
||||
FormatTime(duration2.TotalMinutes) + ":" +
|
||||
@@ -145,7 +185,7 @@ namespace mpvnet
|
||||
$"{width} x {height}\n";
|
||||
|
||||
if (fileSize > 0)
|
||||
text += Convert.ToInt32(fileSize / 1024.0 / 1024.0).ToString() + " MB\n";
|
||||
text += Convert.ToInt32(fileSize / 1024.0 / 1024.0) + " MB\n";
|
||||
|
||||
text += $"{videoFormat}\n{audioCodec}";
|
||||
|
||||
@@ -158,7 +198,7 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExecuteMpvCommand()
|
||||
public static void ExecuteMpvCommand() // deprecated 2019
|
||||
{
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
string command = VB.Interaction.InputBox("Enter a mpv command to be executed.", "Execute Command", RegHelp.GetString(App.RegPath, "RecentExecutedCommand"));
|
||||
@@ -229,32 +269,5 @@ namespace mpvnet
|
||||
mp.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ManageFileAssociations()
|
||||
{
|
||||
using (var td = new TaskDialog<string>())
|
||||
{
|
||||
td.MainInstruction = "Choose an option.";
|
||||
td.MainIcon = MsgIcon.Shield;
|
||||
|
||||
td.AddCommandLink("Register video file extensions", "video");
|
||||
td.AddCommandLink("Register audio file extensions", "audio");
|
||||
td.AddCommandLink("Register image file extensions", "image");
|
||||
td.AddCommandLink("Unregister file extensions", "unreg");
|
||||
|
||||
string result = td.Show();
|
||||
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
{
|
||||
using (var proc = new Process())
|
||||
{
|
||||
proc.StartInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
|
||||
proc.StartInfo.Arguments = "--reg-file-assoc " + result;
|
||||
proc.StartInfo.Verb = "runas";
|
||||
try { proc.Start(); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Linq;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
@@ -19,14 +19,22 @@ namespace mpvnet
|
||||
try
|
||||
{
|
||||
AggregateCatalog catalog = new AggregateCatalog();
|
||||
|
||||
string dir = Application.StartupPath + "\\Extensions";
|
||||
string dir = Folder.Startup + "Extensions";
|
||||
|
||||
if (Directory.Exists(dir))
|
||||
foreach (string i in Directory.GetDirectories(dir))
|
||||
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Extension.dll"));
|
||||
{
|
||||
string[] knownExtensions = { "RatingExtension", "ScriptingExtension" };
|
||||
|
||||
dir = mp.ConfigFolder + "\\Extensions";
|
||||
foreach (string path in Directory.GetDirectories(dir))
|
||||
{
|
||||
if (knownExtensions.Contains(Path.GetFileName(path)))
|
||||
catalog.Catalogs.Add(new DirectoryCatalog(path, "*Extension.dll"));
|
||||
else
|
||||
Msg.ShowError("Failed to load extension", path + "\n\nOnly extensions that ship with mpv.net are allowed in <startup>\\extensions\n\nUser extensions have to use <config folder>\\extensions\n\nNever copy or install a new mpv.net version over a old mpv.net version.");
|
||||
}
|
||||
}
|
||||
|
||||
dir = mp.ConfigFolder + "extensions";
|
||||
|
||||
if (Directory.Exists(dir))
|
||||
foreach (string i in Directory.GetDirectories(dir))
|
||||
|
||||
32
mpv.net/Misc/ExtensionMethods.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static string FileName(this string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) return "";
|
||||
int index = path.LastIndexOf('\\');
|
||||
if (index > -1) return path.Substring(index + 1);
|
||||
index = path.LastIndexOf('/');
|
||||
if (index > -1) return path.Substring(index + 1);
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string ShortExt(this string path)
|
||||
{
|
||||
return Path.GetExtension(path).ToLower().TrimStart('.');
|
||||
}
|
||||
|
||||
public static int Int(this string value)
|
||||
{
|
||||
int.TryParse(value, out int result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float Float(this string value)
|
||||
{
|
||||
float.TryParse(value.Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out float result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -16,121 +15,6 @@ using Microsoft.Win32;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public class App
|
||||
{
|
||||
public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName;
|
||||
public static string ConfPath { get; } = mp.ConfigFolder + "\\mpvnet.conf";
|
||||
public static string DarkMode { get; set; } = "always";
|
||||
public static string ProcessInstance { get; set; } = "single";
|
||||
public static string DarkColor { get; set; }
|
||||
public static string LightColor { get; set; }
|
||||
|
||||
public static string[] VideoTypes { get; } = "264 265 asf avc avi avs flv h264 h265 hevc m2ts m2v m4v mkv mov mp4 mpeg mpg mpv mts ts vob vpy webm webm wmv y4m".Split(' ');
|
||||
public static string[] AudioTypes { get; } = "mp3 mp2 ac3 ogg opus flac wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 mka aac mpa".Split(' ');
|
||||
public static string[] ImageTypes { get; } = "jpg bmp gif png".Split(' ');
|
||||
public static string[] SubtitleTypes { get; } = "srt ass idx sup ttxt ssa smi".Split(' ');
|
||||
public static string[] UrlWhitelist { get; set; } = { "tube", "vimeo", "ard", "zdf" };
|
||||
|
||||
public static bool RememberHeight { get; set; } = true;
|
||||
public static bool RememberPosition { get; set; }
|
||||
public static bool DebugMode { get; set; }
|
||||
public static bool IsStartedFromTerminal { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
|
||||
|
||||
public static int StartThreshold { get; set; } = 1500;
|
||||
|
||||
public static bool IsDarkMode {
|
||||
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
string dummy = mp.ConfigFolder;
|
||||
var dummy2 = mp.Conf;
|
||||
|
||||
foreach (var i in Conf)
|
||||
ProcessProperty(i.Key, i.Value);
|
||||
|
||||
if (App.DebugMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = mp.ConfigFolder + "\\mpvnet-debug.log";
|
||||
if (File.Exists(filePath)) File.Delete(filePath);
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
|
||||
Trace.AutoFlush = true;
|
||||
//if (App.DebugMode) Trace.WriteLine("");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Msg.ShowException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<string, string> _Conf;
|
||||
|
||||
public static Dictionary<string, string> Conf {
|
||||
get {
|
||||
if (_Conf == null)
|
||||
{
|
||||
_Conf = new Dictionary<string, string>();
|
||||
|
||||
if (File.Exists(ConfPath))
|
||||
foreach (string i in File.ReadAllLines(ConfPath))
|
||||
if (i.Contains("=") && !i.StartsWith("#"))
|
||||
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
||||
}
|
||||
return _Conf;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ProcessProperty(string name, string value)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "remember-position": RememberPosition = value == "yes"; break;
|
||||
case "start-size": RememberHeight = value == "previous"; break;
|
||||
case "process-instance": ProcessInstance = value; break;
|
||||
case "dark-mode": DarkMode = value; break;
|
||||
case "debug-mode": DebugMode = value == "yes"; break;
|
||||
case "dark-color": DarkColor = value.Trim('\'', '"'); break;
|
||||
case "light-color": LightColor = value.Trim('\'', '"'); break;
|
||||
case "url-whitelist":
|
||||
UrlWhitelist = value.Split(' ', ',', ';');
|
||||
break;
|
||||
case "start-threshold":
|
||||
int.TryParse(value, out int result);
|
||||
StartThreshold = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ProcessCommandLineEarly()
|
||||
{
|
||||
var args = Environment.GetCommandLineArgs().Skip(1);
|
||||
|
||||
foreach (string i in args)
|
||||
{
|
||||
if (i.StartsWith("--"))
|
||||
{
|
||||
if (i.Contains("="))
|
||||
{
|
||||
string left = i.Substring(2, i.IndexOf("=") - 2);
|
||||
string right = i.Substring(left.Length + 3);
|
||||
mp.ProcessProperty(left, right);
|
||||
ProcessProperty(left, right);
|
||||
}
|
||||
else
|
||||
{
|
||||
string name = i.Substring(2);
|
||||
mp.ProcessProperty(name, "yes");
|
||||
ProcessProperty(name, "yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Sys
|
||||
{
|
||||
public static bool IsDarkTheme {
|
||||
@@ -178,25 +62,23 @@ namespace mpvnet
|
||||
{
|
||||
Types = types;
|
||||
|
||||
RegHelp.SetObject(@"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename, null, ExePath);
|
||||
RegHelp.SetObject($"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\{ExeFilename}", null, ExePath);
|
||||
RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}", "FriendlyAppName", "mpv.net media player");
|
||||
RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}\\shell\\open\\command", null, $"\"{ExePath}\" \"%1\"");
|
||||
RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationDescription", "mpv.net media player");
|
||||
RegHelp.SetObject(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationName", "mpv.net");
|
||||
RegHelp.SetObject($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}", null, "");
|
||||
RegHelp.SetObject($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}", null, "");
|
||||
RegHelp.SetObject(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net", @"SOFTWARE\Clients\Media\mpv.net\Capabilities");
|
||||
|
||||
foreach (string ext in Types)
|
||||
{
|
||||
RegHelp.SetObject($"HKCR\\Applications\\{ExeFilename}\\SupportedTypes", "." + ext, "");
|
||||
RegHelp.SetObject($"HKCR\\" + "." + ext, null, ExeFilenameNoExt + "." + ext);
|
||||
RegHelp.SetObject($"HKCR\\" + "." + ext + "\\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, "");
|
||||
if (App.VideoTypes.Contains(ext))
|
||||
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");
|
||||
if (App.VideoTypes.Contains(ext)) 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);
|
||||
@@ -205,17 +87,16 @@ namespace mpvnet
|
||||
|
||||
public static void Unregister()
|
||||
{
|
||||
RegHelp.RemoveKey(@"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename);
|
||||
RegHelp.RemoveKey($"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\{ExeFilename}");
|
||||
RegHelp.RemoveKey($"HKCR\\Applications\\{ExeFilename}");
|
||||
RegHelp.RemoveKey(@"HKLM\SOFTWARE\Clients\Media\mpv.net");
|
||||
RegHelp.RemoveKey($"HKLM\\SOFTWARE\\Clients\\Media\\mpv.net");
|
||||
RegHelp.RemoveKey($"HKCR\\SystemFileAssociations\\video\\OpenWithList\\{ExeFilename}");
|
||||
RegHelp.RemoveKey($"HKCR\\SystemFileAssociations\\audio\\OpenWithList\\{ExeFilename}");
|
||||
RegHelp.RemoveValue(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net");
|
||||
|
||||
foreach (string id in Registry.ClassesRoot.GetSubKeyNames())
|
||||
{
|
||||
if (id.StartsWith(ExeFilenameNoExt + "."))
|
||||
Registry.ClassesRoot.DeleteSubKeyTree(id);
|
||||
|
||||
if (id.StartsWith(ExeFilenameNoExt + ".")) Registry.ClassesRoot.DeleteSubKeyTree(id);
|
||||
RegHelp.RemoveValue($"HKCR\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id);
|
||||
RegHelp.RemoveValue($"HKLM\\Software\\Classes\\" + id + "\\OpenWithProgIDs", ExeFilenameNoExt + id);
|
||||
}
|
||||
@@ -230,25 +111,25 @@ namespace mpvnet
|
||||
rk.SetValue(name, value);
|
||||
}
|
||||
|
||||
public static string GetString(string path, string name)
|
||||
public static string GetString(string path, string name, string defaultValue = "")
|
||||
{
|
||||
object val = GetObject(path, name);
|
||||
object val = GetObject(path, name, defaultValue);
|
||||
if (val == null || !(val is string)) return "";
|
||||
return val.ToString();
|
||||
}
|
||||
|
||||
public static int GetInt(string path, string name)
|
||||
public static int GetInt(string path, string name, int defaultValue = 0)
|
||||
{
|
||||
object val = GetObject(path, name);
|
||||
object val = GetObject(path, name, defaultValue);
|
||||
if (val == null || !(val is int)) return 0;
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
public static object GetObject(string path, string name)
|
||||
public static object GetObject(string path, string name, object defaultValue = null)
|
||||
{
|
||||
using (RegistryKey rk = GetRootKey(path).OpenSubKey(path.Substring(5)))
|
||||
if (rk != null)
|
||||
return rk.GetValue(name, "");
|
||||
return rk.GetValue(name, defaultValue);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
@@ -410,16 +291,34 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
|
||||
public class Folder
|
||||
{
|
||||
public static string Startup { get; } = Application.StartupPath + "\\";
|
||||
}
|
||||
|
||||
public class PathHelp
|
||||
{
|
||||
public static string GetFileName(string path)
|
||||
public static string GetBaseName(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) return "";
|
||||
int index = path.LastIndexOf('\\');
|
||||
if (index > -1) return path.Substring(index + 1);
|
||||
index = path.LastIndexOf('/');
|
||||
if (index > -1) return path.Substring(index + 1);
|
||||
return path;
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return "";
|
||||
|
||||
int index = value.IndexOf("/");
|
||||
|
||||
if (index > -1)
|
||||
value = value.Substring(index + 1);
|
||||
|
||||
index = value.IndexOf("\\");
|
||||
|
||||
if (index > -1)
|
||||
value = value.Substring(index + 1);
|
||||
|
||||
index = value.LastIndexOf(".");
|
||||
|
||||
if (index > -1)
|
||||
value = value.Substring(0, index);
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ namespace mpvnet
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
if (mp.ConfigFolder == "") return;
|
||||
|
||||
string[] args = Environment.GetCommandLineArgs().Skip(1).ToArray();
|
||||
|
||||
if (args.Length == 2 && args[0] == "--reg-file-assoc")
|
||||
@@ -38,7 +40,7 @@ namespace mpvnet
|
||||
files.Add(App.ProcessInstance);
|
||||
|
||||
foreach (string arg in args)
|
||||
if (!arg.StartsWith("--") && (arg == "-" || arg.Contains("://") || File.Exists(arg)))
|
||||
if (!arg.StartsWith("--") && (arg == "-" || arg.Contains("://") || arg.Contains(":\\") || arg.StartsWith("\\\\")))
|
||||
files.Add(arg);
|
||||
|
||||
Process[] procs = Process.GetProcessesByName("mpvnet");
|
||||
@@ -64,7 +66,9 @@ namespace mpvnet
|
||||
return;
|
||||
}
|
||||
|
||||
if (App.IsStartedFromTerminal) Native.AttachConsole(-1 /*ATTACH_PARENT_PROCESS*/);
|
||||
if (App.IsStartedFromTerminal)
|
||||
Native.AttachConsole(-1 /*ATTACH_PARENT_PROCESS*/);
|
||||
|
||||
Application.Run(new MainForm());
|
||||
if (App.IsStartedFromTerminal) Native.FreeConsole();
|
||||
mutex.Dispose();
|
||||
|
||||
@@ -10,7 +10,7 @@ public class MediaInfo : IDisposable
|
||||
{
|
||||
if (!Loaded)
|
||||
{
|
||||
if (LoadLibrary("MediaInfo.dll") == IntPtr.Zero)
|
||||
if (Native.LoadLibrary("MediaInfo.dll") == IntPtr.Zero)
|
||||
throw new Exception("Failed to load MediaInfo.dll.");
|
||||
|
||||
Loaded = true;
|
||||
@@ -56,21 +56,27 @@ public class MediaInfo : IDisposable
|
||||
|
||||
~MediaInfo() { Dispose(); }
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
static extern IntPtr LoadLibrary(string path);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr LoadLibrary(string path);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern IntPtr MediaInfo_New();
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern void MediaInfo_Delete(IntPtr handle);
|
||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||
static extern int MediaInfo_Open(IntPtr handle, string path);
|
||||
|
||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||
static extern int MediaInfo_Open(IntPtr handle, string fileName);
|
||||
static extern IntPtr MediaInfo_Option(IntPtr handle, string optionString, string value);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern IntPtr MediaInfo_Inform(IntPtr handle, int reserved);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern int MediaInfo_Close(IntPtr handle);
|
||||
|
||||
[DllImport("MediaInfo.dll")]
|
||||
static extern void MediaInfo_Delete(IntPtr handle);
|
||||
|
||||
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
|
||||
static extern IntPtr MediaInfo_Get(IntPtr handle,
|
||||
MediaInfoStreamKind streamKind,
|
||||
|
||||
@@ -2,94 +2,94 @@
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace mpvnet
|
||||
public class Native
|
||||
{
|
||||
public class Native
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AttachConsole(int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool FreeConsole();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr LoadLibrary(string path);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int RegisterWindowMessage(string id);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AllowSetForegroundWindow(int dwProcessId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern void ReleaseCapture();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
|
||||
private static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
|
||||
private static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AttachConsole(int dwProcessId);
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLong64(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool FreeConsole();
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr LoadLibrary(string dllToLoad);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AllowSetForegroundWindow(int dwProcessId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern void ReleaseCapture();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
|
||||
private static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
|
||||
private static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
public RECT(Rectangle r)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLong64(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
Left = r.Left;
|
||||
Top = r.Top;
|
||||
Right = r.Right;
|
||||
Bottom = r.Bottom;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
public RECT(int left, int top, int right, int bottom)
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
|
||||
public RECT(Rectangle r)
|
||||
{
|
||||
Left = r.Left;
|
||||
Top = r.Top;
|
||||
Right = r.Right;
|
||||
Bottom = r.Bottom;
|
||||
}
|
||||
|
||||
public RECT(int left, int top, int right, int bottom)
|
||||
{
|
||||
Left = left;
|
||||
Top = top;
|
||||
Right = right;
|
||||
Bottom = bottom;
|
||||
}
|
||||
|
||||
public Rectangle ToRectangle() { return Rectangle.FromLTRB(Left, Top, Right, Bottom); }
|
||||
public Size Size => new Size(Right - Left, Bottom - Top);
|
||||
public int Width => Right - Left;
|
||||
public int Height => Bottom - Top;
|
||||
Left = left;
|
||||
Top = top;
|
||||
Right = right;
|
||||
Bottom = bottom;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct COPYDATASTRUCT
|
||||
{
|
||||
public IntPtr dwData;
|
||||
public int cbData;
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
public string lpData;
|
||||
}
|
||||
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
|
||||
public Size Size => new Size(Right - Left, Bottom - Top);
|
||||
public int Width => Right - Left;
|
||||
public int Height => Bottom - Top;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct COPYDATASTRUCT
|
||||
{
|
||||
public IntPtr dwData;
|
||||
public int cbData;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpData;
|
||||
}
|
||||
}
|
||||
@@ -50,23 +50,23 @@ public class Msg
|
||||
td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(ex.GetType().Name + "\n\n" + ex.Message + "\n\n" + ex.ToString(),
|
||||
MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
|
||||
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowException(Exception e)
|
||||
public static void ShowException(Exception exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TaskDialog<string> td = new TaskDialog<string>())
|
||||
{
|
||||
td.MainInstruction = e.GetType().Name;
|
||||
td.Content = e.Message;
|
||||
td.MainInstruction = exception.GetType().Name;
|
||||
td.Content = exception.Message;
|
||||
td.MainIcon = MsgIcon.Error;
|
||||
td.ExpandedInformation = e.ToString();
|
||||
td.ExpandedInformation = exception.ToString();
|
||||
td.Footer = "[Copy Message](copymsg)";
|
||||
|
||||
if (!string.IsNullOrEmpty(Msg.SupportURL))
|
||||
@@ -75,9 +75,9 @@ public class Msg
|
||||
td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(ex.GetType().Name + "\n\n" + ex.Message + "\n\n" + ex.ToString(),
|
||||
MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
|
||||
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
@@ -144,9 +144,9 @@ public class Msg
|
||||
return td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception e)
|
||||
{
|
||||
return (MsgResult)MessageBox.Show(ex.GetType().Name + "\n\n" + ex.Message + "\n\n" + ex.ToString(),
|
||||
return (MsgResult)MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
|
||||
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
@@ -235,6 +235,7 @@ public class TaskDialog<T> : TaskDialogNative, IDisposable
|
||||
|
||||
if (Path.GetFileName(lpszFileName.ToString().Replace(".vshost", "")) ==
|
||||
Path.GetFileName(Assembly.GetEntryAssembly().Location))
|
||||
|
||||
return foregroundWindow;
|
||||
|
||||
return IntPtr.Zero;
|
||||
@@ -359,7 +360,7 @@ public class TaskDialog<T> : TaskDialogNative, IDisposable
|
||||
public void AddCommandLink(string text, T value)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value == null ? (T)(object)text : value;
|
||||
IdValueDic[n] = value;
|
||||
IdTextDic[n] = text;
|
||||
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
|
||||
|
||||
53
mpv.net/Native/Taskbar.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class Taskbar
|
||||
{
|
||||
private ITaskbarList3 Instance = (ITaskbarList3)new TaskBarCommunication();
|
||||
|
||||
public IntPtr Handle { get; set; }
|
||||
|
||||
public Taskbar(IntPtr handle) => Handle = handle;
|
||||
|
||||
[ComImportAttribute]
|
||||
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[GuidAttribute("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")]
|
||||
private interface ITaskbarList3
|
||||
{
|
||||
// ITaskbarList
|
||||
[PreserveSig] void HrInit();
|
||||
[PreserveSig] void AddTab(IntPtr hwnd);
|
||||
[PreserveSig] void DeleteTab(IntPtr hwnd);
|
||||
[PreserveSig] void ActivateTab(IntPtr hwnd);
|
||||
[PreserveSig] void SetActiveAlt(IntPtr hwnd);
|
||||
// ITaskbarList2
|
||||
[PreserveSig] void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
|
||||
// ITaskbarList3
|
||||
[PreserveSig] void SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal);
|
||||
[PreserveSig] void SetProgressState(IntPtr hwnd, TaskbarStates state);
|
||||
}
|
||||
|
||||
[ComImportAttribute]
|
||||
[ClassInterfaceAttribute(ClassInterfaceType.None)]
|
||||
[GuidAttribute("56FDF344-FD6D-11d0-958A-006097C9A090")]
|
||||
private class TaskBarCommunication { }
|
||||
|
||||
public void SetState(TaskbarStates taskbarState)
|
||||
{
|
||||
Instance.SetProgressState(Handle, taskbarState);
|
||||
}
|
||||
|
||||
public void SetValue(double progressValue, double progressMax)
|
||||
{
|
||||
Instance.SetProgressValue(Handle, (UInt64)progressValue, (UInt64)progressMax);
|
||||
}
|
||||
}
|
||||
|
||||
public enum TaskbarStates
|
||||
{
|
||||
NoProgress = 0,
|
||||
Indeterminate = 0x1,
|
||||
Normal = 0x2,
|
||||
Error = 0x4,
|
||||
Paused = 0x8
|
||||
}
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("5.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("5.0.0.0")]
|
||||
[assembly: AssemblyVersion("5.4.2.0")]
|
||||
[assembly: AssemblyFileVersion("5.4.2.0")]
|
||||
|
||||
58
mpv.net/Properties/Resources.Designer.cs
generated
@@ -62,19 +62,18 @@ namespace mpvnet.Properties {
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to
|
||||
/// # This file defines the input (keys and mouse) bindings of mpv and mpv.net
|
||||
/// # and it also defines the context menu of mpv.net. mpv.net has an input
|
||||
/// # editor and an config editor as alternative to editing conf text files.
|
||||
/// # The input and config editor can be found in mpv.net's context menu at:
|
||||
///
|
||||
/// # Settings > Show Config Editor
|
||||
/// # Settings > Show Input Editor
|
||||
///
|
||||
/// # The defaults of this file can be found at:
|
||||
/// # This file defines the key and mouse bindings and the context menu
|
||||
/// # of mpv.net. A input and config editor can be found in mpv.net's
|
||||
/// # context menu under 'Settings'. The defaults of this file can be found at:
|
||||
///
|
||||
/// # https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt
|
||||
///
|
||||
/// # th [rest of string was truncated]";.
|
||||
/// # The defaults of mpv can be found at:
|
||||
///
|
||||
/// # https://github.com/mpv-player/mpv/blob/master/etc/input.conf
|
||||
///
|
||||
/// # mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
|
||||
/// # which disables mpv's [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string inputConf {
|
||||
get {
|
||||
@@ -83,21 +82,21 @@ namespace mpvnet.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to
|
||||
///# manual: https://mpv.io/manual/master/
|
||||
///
|
||||
///# defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt
|
||||
///
|
||||
/// Looks up a localized string similar to input-default-bindings = no
|
||||
///input-ar-delay = 500
|
||||
///input-ar-rate = 20
|
||||
///volume = 50
|
||||
///hwdec = yes
|
||||
///keep-open = yes
|
||||
///keep-open-pause = no
|
||||
///osd-playing-msg = '${filename}'
|
||||
///script-opts=osc-scalewindowed=1.5
|
||||
///screenshot-directory = '~~desktop/'
|
||||
///input-default-bindings = no
|
||||
///script-opts=osc-scalewindowed=1.5.
|
||||
///cscale = spline36
|
||||
///dscale = spline36
|
||||
///scale = spline36
|
||||
///hwdec = yes
|
||||
///
|
||||
///[protocol.https]
|
||||
///osd-playing-msg = '${media-title}'.
|
||||
/// </summary>
|
||||
internal static string mpvConf {
|
||||
get {
|
||||
@@ -143,24 +142,11 @@ namespace mpvnet.Properties {
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to [[settings]]
|
||||
///name = "dark-mode"
|
||||
///default = "always"
|
||||
///name = "process-instance"
|
||||
///default = "single"
|
||||
///filter = "General"
|
||||
///help = "Enables a dark theme. (mpv.net specific setting)"
|
||||
///options = [{ name = "always" },
|
||||
/// { name = "system" , help = "Available on Windows 10 or higher" },
|
||||
/// { name = "never" }]
|
||||
///
|
||||
///[[settings]]
|
||||
///name = "dark-color"
|
||||
///type = "color"
|
||||
///filter = "General"
|
||||
///help = "Theme color used in dark-mode. Leave empty to use OS theme. (mpv.net specific setting)"
|
||||
///
|
||||
///[[settings]]
|
||||
///name = "light-color"
|
||||
///type = "color"
|
||||
///filter = "General" [rest of string was truncated]";.
|
||||
///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 and URLs."
|
||||
///options = [{ name = "multi", help = "Create a new process everytime the shell starts mpv.net [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string mpvNetConfToml {
|
||||
get {
|
||||
|
||||
2
mpv.net/Properties/Settings.Designer.cs
generated
@@ -12,7 +12,7 @@ namespace mpvnet.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
|
||||
# This file defines the input (keys and mouse) bindings of mpv and mpv.net
|
||||
# and it also defines the context menu of mpv.net. mpv.net has an input
|
||||
# editor and an config editor as alternative to editing conf text files.
|
||||
# The input and config editor can be found in mpv.net's context menu at:
|
||||
|
||||
# Settings > Show Config Editor
|
||||
# Settings > Show Input Editor
|
||||
|
||||
# The defaults of this file can be found at:
|
||||
# This file defines the key and mouse bindings and the context menu
|
||||
# of mpv.net. A input and config editor can be found in mpv.net's
|
||||
# context menu under 'Settings'. The defaults of this file can be found at:
|
||||
|
||||
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt
|
||||
|
||||
# the defaults of mpv can be found at:
|
||||
# The defaults of mpv can be found at:
|
||||
|
||||
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
|
||||
|
||||
@@ -26,16 +20,17 @@
|
||||
|
||||
# run mpv.net in input test mode with: mpvnet --input-test
|
||||
|
||||
o script-message mpv.net open-files #menu: Open > Open Files...
|
||||
u script-message mpv.net open-url #menu: Open > Open URL or file path from clipboard
|
||||
_ ignore #menu: Open > -
|
||||
Alt+a script-message mpv.net load-audio #menu: Open > Load external audio files...
|
||||
Alt+s script-message mpv.net load-sub #menu: Open > Load external subtitle files...
|
||||
_ ignore #menu: Open > -
|
||||
_ script-message mpv.net open-files append #menu: Open > Add files to playlist...
|
||||
F3 script-message mpv.net show-media-search #menu: Open > Show media search...
|
||||
_ ignore #menu: Open > -
|
||||
_ ignore #menu: Open > Recent
|
||||
o script-message mpv.net open-files #menu: Open > Open Files...
|
||||
u script-message mpv.net open-url #menu: Open > Open URL or file path from clipboard
|
||||
_ script-message mpv.net open-optical-media #menu: Open > Open DVD/Blu-ray Drive/Folder...
|
||||
_ ignore #menu: Open > -
|
||||
Alt+a script-message mpv.net load-audio #menu: Open > Load external audio files...
|
||||
Alt+s script-message mpv.net load-sub #menu: Open > Load external subtitle files...
|
||||
_ ignore #menu: Open > -
|
||||
_ script-message mpv.net open-files append #menu: Open > Add files to playlist...
|
||||
F3 script-message mpv.net show-media-search #menu: Open > Show media search...
|
||||
_ ignore #menu: Open > -
|
||||
_ ignore #menu: Open > Recent
|
||||
|
||||
_ ignore #menu: -
|
||||
Space cycle pause #menu: Play/Pause
|
||||
@@ -46,6 +41,9 @@
|
||||
F11 playlist-prev #menu: Navigate > Previous File
|
||||
F12 playlist-next #menu: Navigate > Next File
|
||||
_ ignore #menu: Navigate > -
|
||||
Home set playlist-pos 0 #menu: Navigate > First File
|
||||
End script-message mpv.net playlist-last #menu: Navigate > Last File
|
||||
_ ignore #menu: Navigate > -
|
||||
PGUP add chapter 1 #menu: Navigate > Next Chapter
|
||||
PGDWN add chapter -1 #menu: Navigate > Previous Chapter
|
||||
_ ignore #menu: Navigate > -
|
||||
@@ -150,19 +148,28 @@
|
||||
|
||||
F1 script-message mpv.net show-command-palette #menu: Tools > Show All Commands
|
||||
h script-message mpv.net show-history #menu: Tools > Show History
|
||||
Ctrl+r script-message-to repl type "" #menu: Tools > Show REPL
|
||||
l ab-loop #menu: Tools > Set/clear A-B loop points
|
||||
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping
|
||||
_ cycle shuffle #menu: Tools > Toggle Shuffle
|
||||
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Toggle Hardware Decoding
|
||||
_ script-message mpv.net execute-mpv-command #menu: Tools > Execute mpv command...
|
||||
_ script-message mpv.net manage-file-associations #menu: Tools > Manage File Associations...
|
||||
_ script-message mpv.net show-setup-dialog #menu: Tools > OS Setup...
|
||||
|
||||
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Show mpv manual
|
||||
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: Help > Show mpv default keys
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt #menu: Help > Show mpv.net default keys
|
||||
_ script-message mpv.net shell-execute https://mpv-net.github.io/mpv.net-web-site/ #menu: Help > Show mpv.net web site
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/Manual.md #menu: Help > Show mpv.net manual
|
||||
_ ignore #menu: Help > -
|
||||
_ script-message mpv.net show-about #menu: Help > About mpv.net
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/Manual.md #menu: Help > mpv.net Manual
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net #menu: Help > mpv.net GitHub
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/wiki #menu: Help > mpv.net Wiki
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net#support #menu: Help > mpv.net Support
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/releases #menu: Help > mpv.net Download
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt #menu: Help > mpv.net Default Key Bindings
|
||||
_ ignore #menu: Help > -
|
||||
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > mpv Manual
|
||||
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/wiki #menu: Help > mpv Wiki
|
||||
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/wiki/User-Scripts #menu: Help > mpv User Scripts
|
||||
_ script-message mpv.net shell-execute https://mpv.io/bug-reports/ #menu: Help > mpv Bugs and Requests
|
||||
_ script-message mpv.net shell-execute https://mpv.io/installation/ #menu: Help > mpv Download
|
||||
_ script-message mpv.net shell-execute https://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: Help > mpv Default Key Bindings
|
||||
_ ignore #menu: Help > -
|
||||
_ script-message mpv.net show-about #menu: Help > About mpv.net
|
||||
|
||||
_ ignore #menu: -
|
||||
Esc quit #menu: Exit
|
||||
@@ -190,5 +197,4 @@
|
||||
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 ignore
|
||||
KP_Enter cycle fullscreen
|
||||
@@ -1,15 +1,15 @@
|
||||
|
||||
# manual: https://mpv.io/manual/master/
|
||||
|
||||
# defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt
|
||||
|
||||
input-default-bindings = no
|
||||
input-ar-delay = 500
|
||||
input-ar-rate = 20
|
||||
volume = 50
|
||||
hwdec = yes
|
||||
keep-open = yes
|
||||
keep-open-pause = no
|
||||
osd-playing-msg = '${filename}'
|
||||
script-opts=osc-scalewindowed=1.5
|
||||
screenshot-directory = '~~desktop/'
|
||||
input-default-bindings = no
|
||||
script-opts=osc-scalewindowed=1.5
|
||||
cscale = spline36
|
||||
dscale = spline36
|
||||
scale = spline36
|
||||
hwdec = yes
|
||||
|
||||
[protocol.https]
|
||||
osd-playing-msg = '${media-title}'
|
||||
@@ -23,10 +23,10 @@ options = [{ name = "no", help = "always use software decoding" },
|
||||
name = "gpu-api"
|
||||
default = "auto"
|
||||
filter = "Video"
|
||||
help = "Controls which type of graphics APIs will be accepted."
|
||||
help = "Controls which type of graphics APIs will be accepted. Auto uses d3d11, it should only be changed in case of problems, Vulkan is not recommended."
|
||||
options = [{ name = "auto", help = "Use any available API" },
|
||||
{ name = "opengl", help = "Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)" },
|
||||
{ name = "vulkan", help = "Allow only Vulkan (requires a valid/working spirv-compiler)" },
|
||||
{ name = "vulkan", help = "Allow only Vulkan (not recommended). " },
|
||||
{ name = "d3d11", help = "Allow only gpu-context=d3d11" }]
|
||||
|
||||
[[settings]]
|
||||
@@ -241,20 +241,28 @@ default = "55"
|
||||
filter = "Screen"
|
||||
help = "Specify the OSD font size. See sub-font-size for details. Default: 55"
|
||||
|
||||
[[settings]]
|
||||
name = "osd-scale-by-window"
|
||||
default = "yes"
|
||||
filter = "Screen"
|
||||
help = "Whether to scale the OSD with the window size. If this is disabled, osd-font-size and other OSD options that use scaled pixels are always in actual pixels. The effect is that changing the window size won't change the OSD font size."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "autofit"
|
||||
filter = "Screen"
|
||||
help = "<int> Initial window height in percent. 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%"
|
||||
help = "<int> Minimum window height in percent. Default: 40"
|
||||
|
||||
[[settings]]
|
||||
name = "autofit-larger"
|
||||
filter = "Screen"
|
||||
help = "<int> Maximum window height in percent. Default: 75%"
|
||||
help = "<int> Maximum window height in percent. Default: 75"
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-directory"
|
||||
@@ -283,7 +291,7 @@ options = [{ name = "yes" },
|
||||
name = "screenshot-high-bit-depth"
|
||||
default = "yes"
|
||||
filter = "Screen"
|
||||
help = "If possible, write screenshots with a bit depth similar to the source video (default: yes). 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."
|
||||
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."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
@@ -291,7 +299,7 @@ options = [{ name = "yes" },
|
||||
name = "screenshot-jpeg-source-chroma"
|
||||
default = "yes"
|
||||
filter = "Screen"
|
||||
help = "Write JPEG files with the same chroma subsampling as the video (default: yes). If disabled, the libjpeg default is used."
|
||||
help = "Write JPEG files with the same chroma subsampling as the video. If disabled, the libjpeg default is used."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
@@ -317,6 +325,14 @@ name = "screenshot-png-filter"
|
||||
filter = "Screen"
|
||||
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."
|
||||
|
||||
[[settings]]
|
||||
name = "taskbar-progress"
|
||||
default = "yes"
|
||||
filter = "Playback"
|
||||
help = "Show progress in taskbar."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "keep-open-pause"
|
||||
default = "yes"
|
||||
@@ -329,10 +345,10 @@ options = [{ name = "yes" },
|
||||
name = "keep-open"
|
||||
default = "no"
|
||||
filter = "Playback"
|
||||
help = "Do not terminate when playing or seeking beyond the end of the file, and there is not next file to be played (and loop is not used). Instead, pause the player. When trying to seek beyond end of the file, the player will attempt to seek to the last frame.\n\nNormally, this will act like set pause yes on EOF, unless the keep-open-pause=no option is set."
|
||||
options = [{ name = "yes", help = "Don't terminate if the current file is the last playlist entry. Equivalent to keep-open without arguments."},
|
||||
{ name = "no", help = "If the current file ends, go to the next file or terminate." },
|
||||
{ name = "always", help = "Like yes, but also applies to files before the last playlist entry. This means playback will never automatically advance to the next file."}]
|
||||
help = "Using no, mpv would terminate after the last file but mpv.net never terminates automatically."
|
||||
options = [{ name = "yes", help = "If the current file ends, go to the next file, keep the last file open."},
|
||||
{ name = "no", help = "If the current file ends, go to the next file." },
|
||||
{ name = "always", help = "Playback will never automatically advance to the next file."}]
|
||||
|
||||
[[settings]]
|
||||
name = "loop-file"
|
||||
|
||||
@@ -1,46 +1,16 @@
|
||||
[[settings]]
|
||||
name = "dark-mode"
|
||||
default = "always"
|
||||
filter = "General"
|
||||
help = "Enables a dark theme. (mpv.net specific setting)"
|
||||
options = [{ name = "always" },
|
||||
{ name = "system" , help = "Available on Windows 10 or higher" },
|
||||
{ name = "never" }]
|
||||
|
||||
[[settings]]
|
||||
name = "dark-color"
|
||||
type = "color"
|
||||
filter = "General"
|
||||
help = "Theme color used in dark-mode. Leave empty to use OS theme. (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "light-color"
|
||||
type = "color"
|
||||
filter = "General"
|
||||
help = "Theme color used when dark-mode is disabled. Leave empty to use OS theme. (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "url-whitelist"
|
||||
filter = "General"
|
||||
type = "string"
|
||||
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 = "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."
|
||||
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 and URLs."
|
||||
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" }]
|
||||
|
||||
[[settings]]
|
||||
name = "debug-mode"
|
||||
default = "no"
|
||||
name = "recent-count"
|
||||
filter = "General"
|
||||
help = "Enable this only when a developer asks for it. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
help = "<int> Amount of recent files to be remembered. Default: 15 (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "start-size"
|
||||
@@ -53,12 +23,78 @@ options = [{ name = "video", help = "Window size is set to native video resoluti
|
||||
[[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"
|
||||
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 specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "minimum-aspect-ratio"
|
||||
filter = "Screen"
|
||||
help = "<float> Minimum aspect ratio for the window. Default: 1.3 (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "remember-position"
|
||||
default = "no"
|
||||
filter = "Screen"
|
||||
help = "Setting to save the window position on exit. (mpv.net specific setting)"
|
||||
help = "Save the window position on exit. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "maximized"
|
||||
default = "no"
|
||||
filter = "Screen"
|
||||
help = "Start with a maximized window. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "remember-volume"
|
||||
default = "yes"
|
||||
filter = "Audio"
|
||||
help = "Save volume and mute on exit and restore it on start. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "auto-load-folder"
|
||||
default = "yes"
|
||||
filter = "Playback"
|
||||
help = "For single files automatically load the entire directory into the playlist. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "dark-mode"
|
||||
default = "always"
|
||||
filter = "UI"
|
||||
help = "Enables a dark theme. (mpv.net specific setting)"
|
||||
options = [{ name = "always" },
|
||||
{ name = "system" , help = "Available on Windows 10 or higher" },
|
||||
{ name = "never" }]
|
||||
|
||||
[[settings]]
|
||||
name = "dark-color"
|
||||
type = "color"
|
||||
filter = "UI"
|
||||
help = "Theme color used in dark-mode. Leave empty to use OS theme. (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "light-color"
|
||||
type = "color"
|
||||
filter = "UI"
|
||||
help = "Theme color used when dark-mode is disabled. Leave empty to use OS theme. (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "themed-menu"
|
||||
default = "no"
|
||||
filter = "UI"
|
||||
help = "Follow theme color in context menu. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "debug-mode"
|
||||
default = "no"
|
||||
filter = "General"
|
||||
help = "Enable this only when a developer asks for it. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
@@ -3,13 +3,13 @@ using System.IO;
|
||||
using System.Threading;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public class PowerShellScript
|
||||
{
|
||||
public static object Execute(string code, string[] parameters)
|
||||
public static void Execute(string filepath, params string[] parameters)
|
||||
{
|
||||
using (Runspace runspace = RunspaceFactory.CreateRunspace())
|
||||
{
|
||||
@@ -23,57 +23,53 @@ namespace mpvnet
|
||||
"Using namespace System\n" +
|
||||
"[System.Reflection.Assembly]::LoadWithPartialName(\"mpvnet\")\n");
|
||||
|
||||
pipeline.Commands.AddScript(code);
|
||||
pipeline.Commands.AddScript(File.ReadAllText(filepath));
|
||||
|
||||
if (parameters != null)
|
||||
foreach (var i in parameters)
|
||||
foreach (string i in parameters)
|
||||
pipeline.Commands[1].Parameters.Add(null, i);
|
||||
|
||||
try
|
||||
{
|
||||
var ret = pipeline.Invoke();
|
||||
if (ret.Count > 0) return ret[0];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (Pipeline pipeline2 = runspace.CreatePipeline())
|
||||
{
|
||||
pipeline2.Commands.AddScript("$PSVersionTable.PSVersion.Major * 10 +" +
|
||||
"$PSVersionTable.PSVersion.Minor");
|
||||
PowerShellOutput output = new PowerShellOutput();
|
||||
output.ModuleName = Path.GetFileName(filepath);
|
||||
|
||||
if (Convert.ToInt32(pipeline2.Invoke()[0].ToString()) < 51)
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
Msg.ShowError("PowerShell Setup Problem\n\nEnsure you have at least PowerShell 5.1 installed.", e2.ToString());
|
||||
return null;
|
||||
}
|
||||
pipeline.Output.DataReady += output.Output_DataReady;
|
||||
pipeline.Error.DataReady += output.Error_DataReady;
|
||||
|
||||
runspace.SessionStateProxy.SetVariable("Output", output);
|
||||
|
||||
try {
|
||||
pipeline.Invoke();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
Msg.ShowError("PowerShell Exception", e.Message + "\n\n" +
|
||||
e.ErrorRecord.ScriptStackTrace.Replace(" <ScriptBlock>, <No file>", "") +
|
||||
"\n\n" + Path.GetFileName(filepath));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.ShowException(e);
|
||||
}
|
||||
|
||||
pipeline.Output.DataReady -= output.Output_DataReady;
|
||||
pipeline.Error.DataReady -= output.Error_DataReady;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Init(string filePath)
|
||||
public static void Init(string filepath)
|
||||
{
|
||||
foreach (var eventInfo in typeof(mp).GetEvents())
|
||||
{
|
||||
if (eventInfo.Name.ToLower() ==
|
||||
Path.GetFileNameWithoutExtension(filePath).ToLower().Replace("-", ""))
|
||||
Path.GetFileNameWithoutExtension(filepath).ToLower().Replace("-", ""))
|
||||
{
|
||||
PowerShellEventObject eventObject = new PowerShellEventObject();
|
||||
MethodInfo mi;
|
||||
eventObject.FilePath = filePath;
|
||||
eventObject.Filepath = filepath;
|
||||
|
||||
if (eventInfo.EventHandlerType == typeof(Action))
|
||||
mi = eventObject.GetType().GetMethod(nameof(PowerShellEventObject.Invoke));
|
||||
else if (eventInfo.EventHandlerType == typeof(Action<EndFileEventMode>))
|
||||
mi = eventObject.GetType().GetMethod(nameof(PowerShellEventObject.InvokeEndFileEventMode));
|
||||
mi = eventObject.GetType().GetMethod(nameof(PowerShellEventObject.InvokeEndFile));
|
||||
else if (eventInfo.EventHandlerType == typeof(Action<string[]>))
|
||||
mi = eventObject.GetType().GetMethod(nameof(PowerShellEventObject.InvokeStrings));
|
||||
else
|
||||
@@ -86,7 +82,33 @@ namespace mpvnet
|
||||
return;
|
||||
}
|
||||
}
|
||||
Task.Run(() => PowerShellScript.Execute(File.ReadAllText(filePath), null));
|
||||
Execute(filepath);
|
||||
}
|
||||
|
||||
class PowerShellOutput
|
||||
{
|
||||
public string ModuleName { get; set; }
|
||||
|
||||
public bool WriteStandard { get; set; } = true;
|
||||
public bool WriteError { get; set; } = true;
|
||||
|
||||
public void Output_DataReady(object sender, EventArgs e)
|
||||
{
|
||||
if (!WriteStandard) return;
|
||||
var output = sender as PipelineReader<PSObject>;
|
||||
while (output.Count > 0)
|
||||
Console.WriteLine("[" + ModuleName + "] " + output.Read().ToString());
|
||||
}
|
||||
|
||||
public void Error_DataReady(object sender, EventArgs e)
|
||||
{
|
||||
if (!WriteError) return;
|
||||
var output = sender as PipelineReader<Object>;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
while (output.Count > 0)
|
||||
Console.WriteLine("[" + ModuleName + "] " + output.Read().ToString());
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,18 +116,10 @@ namespace mpvnet
|
||||
{
|
||||
public EventInfo EventInfo { get; set; }
|
||||
public Delegate Delegate { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public string Filepath { get; set; }
|
||||
|
||||
public void Invoke() => Task.Run(() => { PowerShellScript.Execute(File.ReadAllText(FilePath), null); });
|
||||
|
||||
public void InvokeEndFileEventMode(EndFileEventMode arg)
|
||||
{
|
||||
Task.Run(() => PowerShellScript.Execute(File.ReadAllText(FilePath), new [] { arg.ToString() }));
|
||||
}
|
||||
|
||||
public void InvokeStrings(string[] args)
|
||||
{
|
||||
Task.Run(() => PowerShellScript.Execute(File.ReadAllText(FilePath), args));
|
||||
}
|
||||
public void Invoke() => PowerShellScript.Execute(Filepath);
|
||||
public void InvokeEndFile(EndFileEventMode arg) => PowerShellScript.Execute(Filepath, arg.ToString());
|
||||
public void InvokeStrings(string[] args) => PowerShellScript.Execute(Filepath, args);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
using Microsoft.Scripting;
|
||||
@@ -15,7 +16,7 @@ namespace mpvnet
|
||||
ScriptEngine engine;
|
||||
ScriptScope scope;
|
||||
|
||||
public PythonScript(string code)
|
||||
public PythonScript(string scriptPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -26,14 +27,14 @@ namespace mpvnet
|
||||
engine.Execute("clr.AddReference(\"mpvnet\")", scope);
|
||||
engine.Execute("import mpvnet", scope);
|
||||
engine.Execute("from mpvnet import *", scope);
|
||||
engine.Execute(code, scope);
|
||||
engine.Execute(File.ReadAllText(scriptPath), scope);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is SyntaxErrorException e)
|
||||
Msg.ShowError($"{e.Line}, {e.Column}: " + ex.Message);
|
||||
Msg.ShowError(e.GetType().Name,$"{e.Line}, {e.Column}: " + e.Message + "\n\n" + Path.GetFileName(scriptPath));
|
||||
else
|
||||
Msg.ShowException(ex);
|
||||
Msg.ShowError(ex.GetType().Name, ex.Message + "\n\n" + Path.GetFileName(scriptPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="About mpv.net" Height="230" Width="420" FontSize="16" ShowInTaskbar="False"
|
||||
Title="About mpv.net" Height="230" Width="400" FontSize="16" ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="NoResize">
|
||||
<Grid>
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock FontSize="48" HorizontalAlignment="Center" Margin="0,0,0,10">mpv.net</TextBlock>
|
||||
<TextBlock HorizontalAlignment="Center">Copyright (c) 2017-2019 Frank Skare (stax76)</TextBlock>
|
||||
<TextBlock Name="Version" HorizontalAlignment="Center" />
|
||||
<TextBlock Name="mpvVersion" HorizontalAlignment="Center" />
|
||||
<TextBlock HorizontalAlignment="Center" Margin="0,0,0,20">MIT License</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Windows;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
@@ -9,7 +9,8 @@ namespace mpvnet
|
||||
public AboutWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Version.Text = $"Version {System.Windows.Forms.Application.ProductVersion}";
|
||||
Version.Text = $"mpv.net Version {System.Windows.Forms.Application.ProductVersion} ({File.GetLastWriteTime(System.Windows.Forms.Application.ExecutablePath).ToShortDateString()})";
|
||||
mpvVersion.Text = $"{mp.get_property_string("mpv-version")} ({File.GetLastWriteTime(Folder.Startup + "mpv-1.dll").ToShortDateString()})";
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e) => Close();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:WPF="clr-namespace:WPF"
|
||||
mc:Ignorable="d"
|
||||
Height="500" Width="700" Loaded="ConfWindow1_Loaded" ShowInTaskbar="False"
|
||||
Height="530" Width="700" Loaded="ConfWindow1_Loaded" ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen" Title="Config Editor">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
@@ -21,7 +21,7 @@
|
||||
<StackPanel x:Name="MainStackPanel"></StackPanel>
|
||||
</ScrollViewer>
|
||||
<StackPanel Margin="20,0,0,0" Grid.Row="1">
|
||||
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static WPF:WPF.ThemeBrush}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
|
||||
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="FilterListBox_SelectionChanged" Foreground="{x:Static WPF:WPF.ThemeBrush}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" FontSize="16" />
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace mpvnet
|
||||
LoadSettings(NetSettingsDefinitions, NetConf);
|
||||
InitialContent = GetContent(mp.ConfPath, Conf, SettingsDefinitions) +
|
||||
GetContent(App.ConfPath, NetConf, NetSettingsDefinitions);
|
||||
SearchControl.Text = RegHelp.GetString(App.RegPath, "config editor search");
|
||||
SearchControl.Text = RegHelp.GetString(App.RegPath, "ConfigEditorSearch");
|
||||
|
||||
if (App.IsDarkMode)
|
||||
{
|
||||
@@ -124,14 +124,13 @@ namespace mpvnet
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
RegHelp.SetObject(App.RegPath, "ConfigEditorSearch", SearchControl.Text);
|
||||
string content = GetContent(mp.ConfPath, Conf, SettingsDefinitions);
|
||||
string netContent = GetContent(App.ConfPath, NetConf, NetSettingsDefinitions);
|
||||
if (InitialContent == content + netContent) return;
|
||||
string header = "\r\n# manual: https://mpv.io/manual/master/\r\n\r\n# defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt\r\n\r\n";
|
||||
File.WriteAllText(mp.ConfPath, header + content);
|
||||
File.WriteAllText(mp.ConfPath, content);
|
||||
File.WriteAllText(App.ConfPath, netContent);
|
||||
Msg.Show("Changes will be available on next mpv.net startup.");
|
||||
RegHelp.SetObject(App.RegPath, "config editor search", SearchControl.Text);
|
||||
}
|
||||
|
||||
string GetContent(string filePath, Dictionary<string, string> confSettings, List<SettingBase> settings)
|
||||
@@ -194,14 +193,14 @@ namespace mpvnet
|
||||
{
|
||||
SearchControl.SearchTextBox.SelectAll();
|
||||
Keyboard.Focus(SearchControl.SearchTextBox);
|
||||
|
||||
foreach (var i in MainStackPanel.Children.OfType<StringSettingControl>())
|
||||
i.Update();
|
||||
}
|
||||
|
||||
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
private void FilterListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (e.AddedItems.Count > 0)
|
||||
SearchControl.Text = e.AddedItems[0].ToString() + ":";
|
||||
if (e.AddedItems.Count > 0) SearchControl.Text = e.AddedItems[0] + ":";
|
||||
}
|
||||
|
||||
private void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
@@ -135,12 +134,12 @@ namespace mpvnet
|
||||
StringBuilder buf = new StringBuilder(bufsize);
|
||||
Everything_SetSearch(searchtext);
|
||||
Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH);
|
||||
Everything_SetSort(EVERYTHING_SORT_SIZE_DESCENDING);
|
||||
Everything_Query(true);
|
||||
|
||||
for (i = 0; i < Everything_GetNumResults(); i++)
|
||||
{
|
||||
Everything_GetResultFullPathName(i, buf, bufsize);
|
||||
string ext = Path.GetExtension(buf.ToString()).TrimStart('.').ToLower();
|
||||
string ext = buf.ToString().ShortExt();
|
||||
|
||||
if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext) ||
|
||||
App.ImageTypes.Contains(ext))
|
||||
@@ -149,6 +148,7 @@ namespace mpvnet
|
||||
|
||||
if (items.Count > 100) break;
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => {
|
||||
ListView.ItemsSource = items;
|
||||
SelectFirst();
|
||||
|
||||
@@ -48,16 +48,21 @@ namespace mpvnet
|
||||
CollectionView.Refresh();
|
||||
|
||||
if (SearchControl.SearchTextBox.Text == "?")
|
||||
Msg.Show("Filtering works by searching in the Input, Menu and Command but it's possible to reduce the filter scope to either of Input, Menu or Command by prefixing as follows:\n\ni <input search>\ni: <input search>\n\nm <menu search>\nm: <menu search>\n\nc <command search>\nc: <command search>\n\nIf only one character is entered the search will be performed only in the input.", "Filtering");
|
||||
{
|
||||
SearchControl.SearchTextBox.Text = "";
|
||||
Msg.Show("Filtering", "Reduce the filter scope with:\n\ni input\n\nm menu\n\nc command\n\nIf only one character is entered input search is performed.");
|
||||
}
|
||||
}
|
||||
|
||||
bool Filter(CommandItem item)
|
||||
{
|
||||
if (item.Command == "") return false;
|
||||
string searchText = SearchControl.SearchTextBox.Text.ToLower();
|
||||
if (searchText == "") return true;
|
||||
if (searchText == "" || searchText == "?") return true;
|
||||
|
||||
if (searchText.StartsWith("i ") || searchText.StartsWith("i:") || searchText.Length == 1)
|
||||
if (searchText.Length == 1)
|
||||
return item.Input.ToLower().Replace("ctrl+", "").Replace("shift+", "").Replace("alt+", "") == searchText.ToLower();
|
||||
else if (searchText.StartsWith("i ") || searchText.StartsWith("i:") || searchText.Length == 1)
|
||||
{
|
||||
if (searchText.Length > 1)
|
||||
searchText = searchText.Substring(2).Trim();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="Learn Input" Height="200" Width="400" WindowStartupLocation="CenterOwner"
|
||||
ResizeMode="NoResize" Loaded="Window_Loaded" Background="Black" MouseWheel="Window_MouseWheel" MouseUp="Window_MouseUp" MouseDoubleClick="Window_MouseDoubleClick">
|
||||
ResizeMode="NoResize" Loaded="Window_Loaded" Background="Black" MouseWheel="Window_MouseWheel" MouseUp="Window_MouseUp" MouseDoubleClick="Window_MouseDoubleClick" TextInput="Window_TextInput">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
|
||||
@@ -10,7 +10,8 @@ namespace mpvnet
|
||||
public partial class LearnWindow : Window
|
||||
{
|
||||
public CommandItem InputItem { get; set; }
|
||||
public string NewKey { get; set; } = "";
|
||||
string NewKey = "";
|
||||
string KeyChar = "";
|
||||
|
||||
public LearnWindow() => InitializeComponent();
|
||||
|
||||
@@ -43,7 +44,7 @@ namespace mpvnet
|
||||
} catch {}
|
||||
|
||||
for (int i = 0; i < 13; i++)
|
||||
if ("D" + i.ToString() == text)
|
||||
if ("D" + i == text)
|
||||
text = text.Substring(1);
|
||||
|
||||
switch (e.KeyCode)
|
||||
@@ -58,11 +59,11 @@ namespace mpvnet
|
||||
case WF.Keys.NumPad7:
|
||||
case WF.Keys.NumPad8:
|
||||
case WF.Keys.NumPad9:
|
||||
text = "KP" + e.KeyCode.ToString()[6].ToString(); break;
|
||||
text = "KP" + e.KeyCode.ToString()[6]; 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;
|
||||
case WF.Keys.Back:
|
||||
@@ -72,7 +73,7 @@ namespace mpvnet
|
||||
case WF.Keys.Insert:
|
||||
text = "INS"; break;
|
||||
case WF.Keys.Home:
|
||||
text = "HOME"; break;
|
||||
text = "Home"; break;
|
||||
case WF.Keys.End:
|
||||
text = "END"; break;
|
||||
case WF.Keys.PageUp:
|
||||
@@ -82,56 +83,56 @@ namespace mpvnet
|
||||
case WF.Keys.Escape:
|
||||
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;
|
||||
bool wasModified = false;
|
||||
|
||||
bool isAlt = GetKeyState(18) < (short)0;
|
||||
bool isShift = GetKeyState(16) < (short)0;
|
||||
bool isCtrl = GetKeyState(17) < (short)0;
|
||||
|
||||
if (text.Length == 1 && isShift && text[0] != GetModifiedKey(text[0]))
|
||||
if (text.Length == 1 && KeyChar != text)
|
||||
{
|
||||
text = GetModifiedKey(text[0]).ToString();
|
||||
shiftWasHandled = true;
|
||||
text = KeyChar;
|
||||
wasModified = true;
|
||||
}
|
||||
|
||||
if (text == "#") text = "Sharp";
|
||||
if (text == "#") text = "SHARP";
|
||||
|
||||
if (isAlt) text = "Alt+" + text;
|
||||
if (isShift && !shiftWasHandled) text = "Shift+" + text;
|
||||
if (isCtrl) text = "Ctrl+" + text;
|
||||
if (isAlt && !wasModified) text = "ALT+" + text;
|
||||
if (isShift && !wasModified) text = "SHIFT+" + text;
|
||||
if (isCtrl && !wasModified) text = "CTRL+" + text;
|
||||
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
SetKey(text);
|
||||
@@ -163,24 +164,6 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
|
||||
public static char GetModifiedKey(char c)
|
||||
{
|
||||
short vkKeyScanResult = VkKeyScan(c);
|
||||
|
||||
if (vkKeyScanResult == -1)
|
||||
return c;
|
||||
|
||||
uint code = (uint)vkKeyScanResult & 0xff;
|
||||
byte[] b = new byte[256];
|
||||
b[0x10] = 0x80;
|
||||
uint r;
|
||||
|
||||
if (1 != ToAscii(code, code, b, out r, 0))
|
||||
return c;
|
||||
|
||||
return (char)r;
|
||||
}
|
||||
|
||||
void ProcessKeyEventArgs(ref WF.Message m)
|
||||
{
|
||||
int WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319;
|
||||
@@ -382,5 +365,10 @@ namespace mpvnet
|
||||
BlockMBTN_LEFT = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_TextInput(object sender, TextCompositionEventArgs e)
|
||||
{
|
||||
KeyChar = e.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
mpv.net/WPF/SetupWindow.xaml
Normal file
@@ -0,0 +1,19 @@
|
||||
<Window x:Class="mpvnet.SetupWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="mpv.net OS Setup" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterOwner">
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<Button Name="RegisterVideo" Margin="5" Click="RegisterVideo_Click">Register video file extensions (requires elevated privileges)</Button>
|
||||
<Button Name="RegisterAudio" Margin="5" Click="RegisterAudio_Click">Register audio file extensions (requires elevated privileges)</Button>
|
||||
<Button Name="RegisterImage" Margin="5" Click="RegisterImage_Click">Register image file extensions (requires elevated privileges)</Button>
|
||||
<Button Name="AddToPathEnvVar" Margin="5" Click="AddToPathEnvVar_Click">Add mpv.net to Path environment variable</Button>
|
||||
<Button Name="ManageDefaultApps" Margin="5" Click="ManageDefaultApps_Click">Manage Default Apps (Win 10 or higher)</Button>
|
||||
<Button Name="UnregisterFileAssociations" Margin="5,20,5,5" Click="UnregisterFileAssociations_Click">Unregister file extensions (requires elevated privileges)</Button>
|
||||
<Button Name="RemoveFromPathEnvVar" Margin="5" Click="RemoveFromPathEnvVar_Click">Remove mpv.net from Path environment variable</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
57
mpv.net/WPF/SetupWindow.xaml.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using WF = System.Windows.Forms;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public partial class SetupWindow : Window
|
||||
{
|
||||
public SetupWindow() => InitializeComponent();
|
||||
|
||||
void RegisterFileAssociations(string value)
|
||||
{
|
||||
using (var proc = new Process())
|
||||
{
|
||||
proc.StartInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
|
||||
proc.StartInfo.Arguments = "--reg-file-assoc " + value;
|
||||
proc.StartInfo.Verb = "runas";
|
||||
try { proc.Start(); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterVideo_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("video");
|
||||
private void RegisterAudio_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("audio");
|
||||
private void RegisterImage_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("image");
|
||||
private void UnregisterFileAssociations_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("unreg");
|
||||
private void ManageDefaultApps_Click(object sender, RoutedEventArgs e) => Process.Start("ms-settings:defaultapps");
|
||||
|
||||
private void AddToPathEnvVar_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string var = WF.Application.StartupPath + ";";
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
|
||||
|
||||
if (path.Contains(var))
|
||||
Msg.ShowWarning("Path was already containing mpv.net.");
|
||||
else
|
||||
{
|
||||
Environment.SetEnvironmentVariable("Path", var + path, EnvironmentVariableTarget.User);
|
||||
Msg.Show("mpv.net was successfully added to Path.", (var + path).Replace(";","\n"));
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveFromPathEnvVar_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string var = WF.Application.StartupPath + ";";
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
|
||||
|
||||
if (path.Contains(var))
|
||||
{
|
||||
Environment.SetEnvironmentVariable("Path", path.Replace(var, ""), EnvironmentVariableTarget.User);
|
||||
Msg.Show("mpv.net was successfully removed from Path.");
|
||||
}
|
||||
else
|
||||
Msg.ShowWarning("Path was not containing mpv.net.");
|
||||
}
|
||||
}
|
||||
}
|
||||
20
mpv.net/WinForms/MainForm.Designer.cs
generated
@@ -30,14 +30,19 @@
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.Timer = new System.Windows.Forms.Timer(this.components);
|
||||
this.CursorTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.ProgressTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// Timer
|
||||
// CursorTimer
|
||||
//
|
||||
this.Timer.Enabled = true;
|
||||
this.Timer.Interval = 1000;
|
||||
this.Timer.Tick += new System.EventHandler(this.Timer_Tick);
|
||||
this.CursorTimer.Enabled = true;
|
||||
this.CursorTimer.Interval = 1000;
|
||||
this.CursorTimer.Tick += new System.EventHandler(this.CursorTimer_Tick);
|
||||
//
|
||||
// ProgressTimer
|
||||
//
|
||||
this.ProgressTimer.Tick += new System.EventHandler(this.ProgressTimer_Tick);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
@@ -45,7 +50,7 @@
|
||||
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(542, 0);
|
||||
this.ClientSize = new System.Drawing.Size(348, 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);
|
||||
@@ -57,6 +62,7 @@
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Timer Timer;
|
||||
private System.Windows.Forms.Timer CursorTimer;
|
||||
private System.Windows.Forms.Timer ProgressTimer;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
@@ -17,12 +16,12 @@ namespace mpvnet
|
||||
{
|
||||
public static MainForm Instance { get; set; }
|
||||
public static IntPtr Hwnd { get; set; }
|
||||
|
||||
public new ContextMenuStripEx ContextMenu { get; set; }
|
||||
|
||||
Point LastCursorPosChanged;
|
||||
int LastCursorChangedTickCount;
|
||||
int TaskbarButtonCreatedMessage;
|
||||
bool WasShown;
|
||||
Taskbar Taskbar;
|
||||
List<string> RecentFiles;
|
||||
|
||||
public MainForm()
|
||||
@@ -34,11 +33,31 @@ namespace mpvnet
|
||||
Instance = this;
|
||||
Hwnd = Handle;
|
||||
mp.Init();
|
||||
|
||||
mp.Shutdown += Shutdown;
|
||||
mp.VideoSizeChanged += VideoSizeChanged;
|
||||
mp.FileLoaded += FileLoaded;
|
||||
mp.Idle += Idle;
|
||||
mp.Seek += () => UpdateProgressBar();
|
||||
|
||||
mp.observe_property_bool("pause", PropChangePause);
|
||||
mp.observe_property_bool("fullscreen", PropChangeFullscreen);
|
||||
mp.observe_property_bool("ontop", PropChangeOnTop);
|
||||
mp.observe_property_bool("border", PropChangeBorder);
|
||||
mp.observe_property_string("sid", PropChangeSid);
|
||||
mp.observe_property_string("aid", PropChangeAid);
|
||||
mp.observe_property_string("vid", PropChangeVid);
|
||||
mp.observe_property_int("edition", PropChangeEdition);
|
||||
|
||||
if (mp.GPUAPI != "vulkan")
|
||||
mp.ProcessCommandLine(false);
|
||||
|
||||
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;
|
||||
|
||||
TaskbarButtonCreatedMessage = Native.RegisterWindowMessage("TaskbarButtonCreated");
|
||||
|
||||
object recent = RegHelp.GetObject(App.RegPath, "Recent");
|
||||
|
||||
if (recent is string[] r)
|
||||
@@ -50,13 +69,18 @@ namespace mpvnet
|
||||
ContextMenu.Opened += ContextMenu_Opened;
|
||||
ContextMenu.Opening += ContextMenu_Opening;
|
||||
|
||||
App.ProcessCommandLineEarly();
|
||||
if (mp.Screen == -1)
|
||||
mp.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
|
||||
|
||||
if (mp.Screen == -1) mp.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
|
||||
int targetIndex = mp.Screen;
|
||||
Screen[] screens = Screen.AllScreens;
|
||||
if (targetIndex < 0) targetIndex = 0;
|
||||
if (targetIndex > screens.Length - 1) targetIndex = screens.Length - 1;
|
||||
|
||||
if (targetIndex < 0)
|
||||
targetIndex = 0;
|
||||
|
||||
if (targetIndex > screens.Length - 1)
|
||||
targetIndex = screens.Length - 1;
|
||||
|
||||
Screen screen = screens[Array.IndexOf(screens, screens[targetIndex])];
|
||||
Rectangle target = screen.Bounds;
|
||||
Left = target.X + (target.Width - Width) / 2;
|
||||
@@ -71,19 +95,8 @@ namespace mpvnet
|
||||
Top = posY - Height / 2;
|
||||
}
|
||||
|
||||
mp.Shutdown += Shutdown;
|
||||
mp.VideoSizeChanged += VideoSizeChanged;
|
||||
mp.FileLoaded += FileLoaded;
|
||||
mp.Idle += Idle;
|
||||
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);
|
||||
mp.observe_property_string("sid", PropChangeSid);
|
||||
mp.observe_property_string("aid", PropChangeAid);
|
||||
mp.observe_property_string("vid", PropChangeVid);
|
||||
mp.observe_property_int("edition", PropChangeEdition);
|
||||
if (App.Maximized)
|
||||
WindowState = FormWindowState.Maximized;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -93,19 +106,22 @@ namespace mpvnet
|
||||
|
||||
public MenuItem FindMenuItem(string text) => FindMenuItem(text, ContextMenu.Items);
|
||||
|
||||
void Idle() => BeginInvoke(new Action(() => Text = "mpv.net " + Application.ProductVersion));
|
||||
void Shutdown() => BeginInvoke(new Action(() => Close()));
|
||||
|
||||
void Idle()
|
||||
{
|
||||
BeginInvoke(new Action(() => Text = "mpv.net " + Application.ProductVersion));
|
||||
}
|
||||
|
||||
void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
|
||||
|
||||
void VideoSizeChanged() => BeginInvoke(new Action(() => SetFormPosAndSize()));
|
||||
|
||||
void Shutdown() => BeginInvoke(new Action(() => Close()));
|
||||
|
||||
void PropChangeFullscreen(bool value) => BeginInvoke(new Action(() => CycleFullscreen(value)));
|
||||
|
||||
void ContextMenu_Opened(object sender, EventArgs e) => CursorHelp.Show();
|
||||
|
||||
bool IsFullscreen => WindowState == FormWindowState.Maximized;
|
||||
bool IsFullscreen => WindowState == FormWindowState.Maximized && FormBorderStyle == FormBorderStyle.None;
|
||||
|
||||
bool IsMouseInOSC() => PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
|
||||
|
||||
@@ -127,7 +143,7 @@ namespace mpvnet
|
||||
foreach (MediaTrack track in vidTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => { mp.commandv("set", "vid", track.ID.ToString()); };
|
||||
mi.Action = () => mp.commandv("set", "vid", track.ID.ToString());
|
||||
mi.Checked = mp.Vid == track.ID.ToString();
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
@@ -138,7 +154,7 @@ namespace mpvnet
|
||||
foreach (MediaTrack track in audTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => { mp.commandv("set", "aid", track.ID.ToString()); };
|
||||
mi.Action = () => mp.commandv("set", "aid", track.ID.ToString());
|
||||
mi.Checked = mp.Aid == track.ID.ToString();
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
@@ -149,7 +165,7 @@ namespace mpvnet
|
||||
foreach (MediaTrack track in subTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => { mp.commandv("set", "sid", track.ID.ToString()); };
|
||||
mi.Action = () => mp.commandv("set", "sid", track.ID.ToString());
|
||||
mi.Checked = mp.Sid == track.ID.ToString();
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
@@ -157,7 +173,7 @@ namespace mpvnet
|
||||
if (subTracks.Length > 0)
|
||||
{
|
||||
MenuItem mi = new MenuItem("S: No subtitles");
|
||||
mi.Action = () => { mp.commandv("set", "sid", "no"); };
|
||||
mi.Action = () => mp.commandv("set", "sid", "no");
|
||||
mi.Checked = mp.Sid == "no";
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
@@ -168,7 +184,7 @@ namespace mpvnet
|
||||
foreach (MediaTrack track in ediTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => { mp.commandv("set", "edition", track.ID.ToString()); };
|
||||
mi.Action = () => mp.commandv("set", "edition", track.ID.ToString());
|
||||
mi.Checked = mp.Edition == track.ID;
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
@@ -187,7 +203,7 @@ namespace mpvnet
|
||||
{
|
||||
MenuItem mi = new MenuItem(i.Key);
|
||||
mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " ";
|
||||
mi.Action = () => { mp.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute"); };
|
||||
mi.Action = () => mp.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute");
|
||||
chaptersMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
}
|
||||
@@ -198,8 +214,10 @@ namespace mpvnet
|
||||
if (recent != null)
|
||||
{
|
||||
recent.DropDownItems.Clear();
|
||||
|
||||
foreach (string path in RecentFiles)
|
||||
MenuItem.Add(recent.DropDownItems, path, () => mp.Load(new[] { path }, true, Control.ModifierKeys.HasFlag(Keys.Control)));
|
||||
|
||||
recent.DropDownItems.Add(new ToolStripSeparator());
|
||||
MenuItem mi = new MenuItem("Clear List");
|
||||
mi.Action = () => RecentFiles.Clear();
|
||||
@@ -229,6 +247,9 @@ namespace mpvnet
|
||||
|
||||
void SetFormPosAndSize()
|
||||
{
|
||||
if (WindowState == FormWindowState.Maximized)
|
||||
return;
|
||||
|
||||
if (mp.Fullscreen)
|
||||
{
|
||||
CycleFullscreen(true);
|
||||
@@ -239,7 +260,7 @@ namespace mpvnet
|
||||
int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * mp.Autofit);
|
||||
|
||||
if (mp.VideoSize.Height == 0 || mp.VideoSize.Width == 0 ||
|
||||
mp.VideoSize.Width / (float)mp.VideoSize.Height < 1.3)
|
||||
mp.VideoSize.Width / (float)mp.VideoSize.Height < App.MinimumAspectRatio)
|
||||
|
||||
mp.VideoSize = new Size((int)(autoFitHeight * (16 / 9.0)), autoFitHeight);
|
||||
|
||||
@@ -310,22 +331,25 @@ namespace mpvnet
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (WindowState != FormWindowState.Maximized)
|
||||
if (WindowState != FormWindowState.Maximized || FormBorderStyle != FormBorderStyle.None)
|
||||
{
|
||||
if (WindowState == FormWindowState.Maximized)
|
||||
WindowState = FormWindowState.Minimized;
|
||||
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
WindowState = FormWindowState.Maximized;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WindowState == FormWindowState.Maximized)
|
||||
if (WindowState == FormWindowState.Maximized && FormBorderStyle == FormBorderStyle.None)
|
||||
{
|
||||
WindowState = FormWindowState.Normal;
|
||||
|
||||
if (mp.Border)
|
||||
FormBorderStyle = FormBorderStyle.Sizable;
|
||||
else
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
|
||||
SetFormPosAndSize();
|
||||
}
|
||||
@@ -365,15 +389,25 @@ namespace mpvnet
|
||||
private void FileLoaded()
|
||||
{
|
||||
string path = mp.get_property_string("path");
|
||||
|
||||
BeginInvoke(new Action(() => {
|
||||
if (File.Exists(path) || path.Contains("://"))
|
||||
Text = PathHelp.GetFileName(path) + " - mpv.net " + Application.ProductVersion;
|
||||
if (path.Contains("://"))
|
||||
Text = mp.get_property_string("media-title") + " - mpv.net " + Application.ProductVersion;
|
||||
else if (path.Contains(":\\") || path.StartsWith("\\\\"))
|
||||
Text = path.FileName() + " - mpv.net " + Application.ProductVersion;
|
||||
else
|
||||
Text = "mpv.net " + Application.ProductVersion;
|
||||
|
||||
int interval = (int)(mp.Duration.TotalMilliseconds / 100);
|
||||
if (interval < 100) interval = 100;
|
||||
if (interval > 1000) interval = 1000;
|
||||
ProgressTimer.Interval = interval;
|
||||
UpdateProgressBar();
|
||||
}));
|
||||
|
||||
if (RecentFiles.Contains(path)) RecentFiles.Remove(path);
|
||||
RecentFiles.Insert(0, path);
|
||||
if (RecentFiles.Count > 15) RecentFiles.RemoveAt(15);
|
||||
while (RecentFiles.Count > App.RecentCount) RecentFiles.RemoveAt(App.RecentCount);
|
||||
}
|
||||
|
||||
protected override CreateParams CreateParams {
|
||||
@@ -386,7 +420,7 @@ namespace mpvnet
|
||||
|
||||
protected override void WndProc(ref Message m)
|
||||
{
|
||||
//Debug.WriteLine(m);
|
||||
Debug.WriteLine(m);
|
||||
|
||||
switch (m.Msg)
|
||||
{
|
||||
@@ -422,24 +456,31 @@ namespace mpvnet
|
||||
}
|
||||
break;
|
||||
case 0x02E0: // WM_DPICHANGED
|
||||
if (!WasShown) break;
|
||||
if (!WasShown)
|
||||
break;
|
||||
var r2 = Marshal.PtrToStructure<Native.RECT>(m.LParam);
|
||||
Native.SetWindowPos(Handle, IntPtr.Zero, r2.Left, r2.Top, r2.Width, r2.Height, 0);
|
||||
break;
|
||||
case 0x112: // WM_SYSCOMMAND
|
||||
if (m.WParam.ToInt32() == 0xf120) // SC_RESTORE
|
||||
SetFormPosAndSize();
|
||||
break;
|
||||
case 0x0214: // WM_SIZING
|
||||
var rc = Marshal.PtrToStructure<Native.RECT>(m.LParam);
|
||||
var r = rc;
|
||||
NativeHelp.SubtractWindowBorders(Handle, ref r);
|
||||
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
|
||||
Size s = mp.VideoSize;
|
||||
if (s == Size.Empty) s = new Size(16, 9);
|
||||
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 };
|
||||
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
|
||||
int corner = NativeHelp.GetResizeBorder(m.WParam.ToInt32());
|
||||
if (corner >= 0) corners[corner] -= d_corners[corner];
|
||||
if (corner >= 0)
|
||||
corners[corner] -= d_corners[corner];
|
||||
Marshal.StructureToPtr<Native.RECT>(new Native.RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false);
|
||||
m.Result = new IntPtr(1);
|
||||
return;
|
||||
@@ -464,26 +505,16 @@ namespace mpvnet
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.Msg == TaskbarButtonCreatedMessage && mp.TaskbarProgress)
|
||||
{
|
||||
Taskbar = new Taskbar(Handle);
|
||||
ProgressTimer.Start();
|
||||
}
|
||||
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
protected override void OnDragEnter(DragEventArgs e)
|
||||
{
|
||||
base.OnDragEnter(e);
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(DataFormats.Text))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
}
|
||||
|
||||
protected override void OnDragDrop(DragEventArgs e)
|
||||
{
|
||||
base.OnDragDrop(e);
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
mp.Load(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
if (e.Data.GetDataPresent(DataFormats.Text))
|
||||
mp.Load(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
}
|
||||
|
||||
void Timer_Tick(object sender, EventArgs e)
|
||||
void CursorTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
|
||||
{
|
||||
@@ -497,6 +528,14 @@ namespace mpvnet
|
||||
CursorHelp.Hide();
|
||||
}
|
||||
|
||||
private void ProgressTimer_Tick(object sender, EventArgs e) => UpdateProgressBar();
|
||||
|
||||
void UpdateProgressBar()
|
||||
{
|
||||
if (mp.TaskbarProgress && Taskbar != null)
|
||||
Taskbar.SetValue(mp.get_property_number("time-pos"), mp.Duration.TotalSeconds);
|
||||
}
|
||||
|
||||
void PropChangeOnTop(bool value) => BeginInvoke(new Action(() => TopMost = value));
|
||||
|
||||
void PropChangeAid(string value) => mp.Aid = value;
|
||||
@@ -521,35 +560,47 @@ namespace mpvnet
|
||||
}));
|
||||
}
|
||||
|
||||
void PropChangePause(bool enabled)
|
||||
{
|
||||
if (Taskbar != null && mp.TaskbarProgress)
|
||||
{
|
||||
if (enabled)
|
||||
Taskbar.SetState(TaskbarStates.Paused);
|
||||
else
|
||||
Taskbar.SetState(TaskbarStates.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
if (mp.GPUAPI != "vulkan") mp.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
|
||||
SetFormPosAndSize();
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
if (mp.GPUAPI == "vulkan") mp.ProcessCommandLine(false);
|
||||
var wpfColor = WPF.WPF.ThemeColor;
|
||||
Color color = Color.FromArgb(wpfColor.A, wpfColor.R, wpfColor.G, wpfColor.B);
|
||||
ToolStripRendererEx.InitColors(color, App.IsDarkMode);
|
||||
ToolStripRendererEx.InitColors(color, App.IsDarkMode, App.ThemedMenu);
|
||||
BuildMenu();
|
||||
ContextMenuStrip = ContextMenu;
|
||||
WPF.WPF.Init();
|
||||
System.Windows.Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
|
||||
CheckClipboardForURL();
|
||||
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
|
||||
WasShown = true;
|
||||
Task.Run(() => { mp.LoadScripts(); });
|
||||
Task.Run(() => { mp.Extension = new Extension(); });
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
base.OnActivated(e);
|
||||
CheckClipboardForURL();
|
||||
Message m = new Message() { Msg = 0x0202 }; // WM_LBUTTONUP
|
||||
Native.SendMessage(Handle, m.Msg, m.WParam, m.LParam);
|
||||
mp.LoadScripts();
|
||||
Task.Run(() => App.Extension = new Extension());
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
if (mp.IsLogoVisible) mp.ShowLogo();
|
||||
|
||||
if (mp.IsLogoVisible)
|
||||
mp.ShowLogo();
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
@@ -588,28 +639,26 @@ namespace mpvnet
|
||||
mp.commandv("quit");
|
||||
}
|
||||
|
||||
protected override void OnDragEnter(DragEventArgs e)
|
||||
{
|
||||
base.OnDragEnter(e);
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(DataFormats.Text))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
}
|
||||
|
||||
protected override void OnDragDrop(DragEventArgs e)
|
||||
{
|
||||
base.OnDragDrop(e);
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
mp.Load(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
if (e.Data.GetDataPresent(DataFormats.Text))
|
||||
mp.Load(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
}
|
||||
|
||||
protected override void OnLostFocus(EventArgs e)
|
||||
{
|
||||
base.OnLostFocus(e);
|
||||
CursorHelp.Show();
|
||||
}
|
||||
|
||||
void CheckClipboardForURL()
|
||||
{
|
||||
string clipboard = Clipboard.GetText();
|
||||
|
||||
foreach (string url in App.UrlWhitelist)
|
||||
{
|
||||
if (clipboard.Contains("://") && ! clipboard.Contains("\n") &&
|
||||
! clipboard.Contains(" ") && clipboard.Contains(url.ToLower().Trim()) &&
|
||||
RegHelp.GetString(App.RegPath, "LastURL") != clipboard && Visible)
|
||||
{
|
||||
RegHelp.SetObject(App.RegPath, "LastURL", clipboard);
|
||||
|
||||
if (Msg.ShowQuestion("Play URL?", clipboard) == MsgResult.OK)
|
||||
mp.Load(new[] { clipboard }, true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,9 +117,12 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="Timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<metadata name="CursorTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>30, 12</value>
|
||||
</metadata>
|
||||
<metadata name="ProgressTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>321, 12</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using Microsoft.Win32;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
@@ -131,8 +130,6 @@ 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; }
|
||||
public static Color ColorChecked { get; set; }
|
||||
@@ -141,34 +138,33 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
||||
public static Color ColorSelection { get; set; }
|
||||
public static Color ColorBackground { get; set; }
|
||||
|
||||
public static Color ColorToolStrip1 { get; set; }
|
||||
public static Color ColorToolStrip2 { get; set; }
|
||||
public static Color ColorToolStrip3 { get; set; }
|
||||
public static Color ColorToolStrip4 { get; set; }
|
||||
|
||||
int TextOffset;
|
||||
|
||||
public static void InitColors(Color c, bool darkMode)
|
||||
public static void InitColors(Color themeColor, bool darkMode, bool themed)
|
||||
{
|
||||
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
|
||||
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(160);
|
||||
ColorSelection = HSLColor.Convert(c).ToColorSetLuminosity(180);
|
||||
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(210);
|
||||
ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240);
|
||||
|
||||
if (darkMode)
|
||||
{
|
||||
ColorBorder = Color.White;
|
||||
ColorBackground = Color.FromArgb(50, 50, 50);
|
||||
ColorSelection = Color.FromArgb(80, 80, 80);
|
||||
ColorForeground = Color.White;
|
||||
|
||||
if (themed)
|
||||
ColorForeground = themeColor;
|
||||
else
|
||||
ColorForeground = Color.White;
|
||||
|
||||
ColorChecked = Color.FromArgb(90, 90, 90);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!themed) themeColor = Color.FromArgb(238, 238, 238);
|
||||
|
||||
ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1)));
|
||||
ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f)));
|
||||
ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f)));
|
||||
ColorToolStrip4 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.4f)));
|
||||
ColorBorder = HSLColor.Convert(themeColor).ToColorSetLuminosity(100);
|
||||
ColorChecked = HSLColor.Convert(themeColor).ToColorSetLuminosity(160);
|
||||
ColorSelection = HSLColor.Convert(themeColor).ToColorSetLuminosity(180);
|
||||
ColorBackground = HSLColor.Convert(themeColor).ToColorSetLuminosity(210);
|
||||
ColorTop = HSLColor.Convert(themeColor).ToColorSetLuminosity(240);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
|
||||
@@ -200,17 +196,6 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
|
||||
base.OnRenderItemText(e);
|
||||
}
|
||||
|
||||
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
|
||||
{
|
||||
if (!(e.ToolStrip is ToolStripDropDownMenu) && !(e.ToolStrip.LayoutStyle == ToolStripLayoutStyle.VerticalStackWithOverflow))
|
||||
{
|
||||
Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height);
|
||||
|
||||
using (SolidBrush b = new SolidBrush(ColorToolStrip2))
|
||||
e.Graphics.FillRectangle(b, r);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
|
||||
{
|
||||
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>mpvnet</RootNamespace>
|
||||
<AssemblyName>mpvnet</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
@@ -114,11 +114,16 @@
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Misc\App.cs" />
|
||||
<Compile Include="Misc\Extension.cs" />
|
||||
<Page Include="Controls\SearchTextBoxUserControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="WPF\SetupWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="WPF\AboutWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
@@ -146,7 +151,9 @@
|
||||
<DependentUpon>StringSettingControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="DynamicGUI\Tommy.cs" />
|
||||
<Compile Include="Misc\ExtensionMethods.cs" />
|
||||
<Compile Include="Native\MediaInfo.cs" />
|
||||
<Compile Include="Native\Taskbar.cs" />
|
||||
<Compile Include="WinForms\Menu.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
@@ -172,6 +179,9 @@
|
||||
<Compile Include="Misc\Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Native\TaskDialog.cs" />
|
||||
<Compile Include="WPF\SetupWindow.xaml.cs">
|
||||
<DependentUpon>SetupWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WPF\EverythingWindow.xaml.cs">
|
||||
<DependentUpon>EverythingWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
||||
@@ -16,7 +16,7 @@ using System.Windows.Forms;
|
||||
using WinForms = System.Windows.Forms;
|
||||
|
||||
using static mpvnet.libmpv;
|
||||
using static mpvnet.Native;
|
||||
using static Native;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
@@ -54,29 +54,33 @@ namespace mpvnet
|
||||
public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW
|
||||
public static event Action Hook; // MPV_EVENT_HOOK
|
||||
|
||||
public static IntPtr Handle { get; set; }
|
||||
public static IntPtr WindowHandle { get; set; }
|
||||
public static Extension Extension { get; set; }
|
||||
public static bool IsLogoVisible { set; get; }
|
||||
public static bool IsQuitNeeded { set; get; } = true;
|
||||
public static event Action Initialized;
|
||||
|
||||
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<bool>>>();
|
||||
public static List<KeyValuePair<string, Action<int>>> IntPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<int>>>();
|
||||
public static List<KeyValuePair<string, Action<string>>> StringPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<string>>>();
|
||||
public static Size VideoSize { get; set; }
|
||||
public static List<PythonScript> PythonScripts { get; set; } = new List<PythonScript>();
|
||||
public static AutoResetEvent ShutdownAutoResetEvent { get; set; } = new AutoResetEvent(false);
|
||||
public static AutoResetEvent VideoSizeAutoResetEvent { get; set; } = new AutoResetEvent(false);
|
||||
public static List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
|
||||
public static List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>();
|
||||
public static IntPtr Handle { get; set; }
|
||||
public static IntPtr WindowHandle { get; set; }
|
||||
public static List<PythonScript> PythonScripts { get; set; } = new List<PythonScript>();
|
||||
public static Size VideoSize { get; set; }
|
||||
public static TimeSpan Duration;
|
||||
public static AutoResetEvent ShutdownAutoResetEvent { get; set; } = new AutoResetEvent(false);
|
||||
public static AutoResetEvent VideoSizeAutoResetEvent { get; set; } = new AutoResetEvent(false);
|
||||
|
||||
public static string InputConfPath { get; } = ConfigFolder + "\\input.conf";
|
||||
public static string ConfPath { get; } = ConfigFolder + "\\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; } = "";
|
||||
public static string GPUAPI { get; set; } = "auto";
|
||||
|
||||
public static bool IsLogoVisible { set; get; }
|
||||
public static bool IsQuitNeeded { set; get; } = true;
|
||||
public static bool Fullscreen { get; set; }
|
||||
public static bool Border { get; set; } = true;
|
||||
public static bool TaskbarProgress { get; set; } = true;
|
||||
|
||||
public static int Screen { get; set; } = -1;
|
||||
public static int Edition { get; set; }
|
||||
@@ -89,27 +93,32 @@ namespace mpvnet
|
||||
{
|
||||
LoadLibrary("mpv-1.dll");
|
||||
Handle = mpv_create();
|
||||
Task.Run(() => EventLoop());
|
||||
|
||||
if (App.IsStartedFromTerminal)
|
||||
{
|
||||
set_property_string("terminal", "yes");
|
||||
set_property_string("input-terminal", "yes");
|
||||
set_property_string("msg-level", "osd/libass=fatal");
|
||||
}
|
||||
|
||||
set_property_string("config-dir", ConfigFolder);
|
||||
set_property_string("osc", "yes");
|
||||
set_property_string("config", "yes");
|
||||
set_property_string("wid", MainForm.Hwnd.ToString());
|
||||
set_property_string("force-window", "yes");
|
||||
set_property_string("osc", "yes");
|
||||
set_property_string("input-media-keys", "yes");
|
||||
set_property_string("force-window", "yes");
|
||||
set_property_string("config-dir", ConfigFolder);
|
||||
set_property_string("config", "yes");
|
||||
|
||||
ProcessCommandLine(true);
|
||||
mpv_initialize(Handle);
|
||||
ShowLogo();
|
||||
ProcessCommandLine();
|
||||
Task.Run(() => { EventLoop(); });
|
||||
Initialized?.Invoke();
|
||||
LoadMpvScripts();
|
||||
}
|
||||
|
||||
public static void ProcessProperty(string name, string value)
|
||||
{
|
||||
if (name.Any(char.IsUpper)) Msg.ShowError("Uppercase char detected: " + name, "mpv properties using the command line and the mpv.conf config file are required to be lowercase.");
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "autofit":
|
||||
@@ -127,7 +136,9 @@ namespace mpvnet
|
||||
case "fs":
|
||||
case "fullscreen": Fullscreen = value == "yes"; break;
|
||||
case "border": Border = value == "yes"; break;
|
||||
case "taskbar-progress": TaskbarProgress = value == "yes"; break;
|
||||
case "screen": Screen = Convert.ToInt32(value); break;
|
||||
case "gpu-api": GPUAPI = value; break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,17 +148,16 @@ namespace mpvnet
|
||||
get {
|
||||
if (_ConfigFolder == null)
|
||||
{
|
||||
_ConfigFolder = Application.StartupPath + "\\portable_config\\";
|
||||
string portableFolder = Folder.Startup + "portable_config\\";
|
||||
_ConfigFolder = portableFolder;
|
||||
|
||||
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.net\\";
|
||||
string appdataFolderMpv = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
|
||||
string startupFolder = Application.StartupPath + "\\";
|
||||
|
||||
using (TaskDialog<string> td = new TaskDialog<string>())
|
||||
{
|
||||
@@ -155,17 +165,22 @@ namespace mpvnet
|
||||
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;
|
||||
_ConfigFolder = td.Show();
|
||||
}
|
||||
|
||||
if (_ConfigFolder == null)
|
||||
{
|
||||
_ConfigFolder = "";
|
||||
return "";
|
||||
}
|
||||
|
||||
if (_ConfigFolder == "custom")
|
||||
{
|
||||
using (var d = new WinForms.FolderBrowserDialog())
|
||||
{
|
||||
d.Description = "Choose a folder.";
|
||||
|
||||
if (d.ShowDialog() == WinForms.DialogResult.OK)
|
||||
_ConfigFolder = d.SelectedPath + "\\";
|
||||
else
|
||||
@@ -174,20 +189,26 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
|
||||
if (Folder.Startup == _ConfigFolder)
|
||||
{
|
||||
Msg.ShowError("Startup folder and config folder cannot be identical, using portable_config instead.");
|
||||
_ConfigFolder = portableFolder;
|
||||
}
|
||||
|
||||
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 + "input.conf"))
|
||||
File.WriteAllText(_ConfigFolder + "input.conf", Properties.Resources.inputConf);
|
||||
|
||||
if (!File.Exists(_ConfigFolder + "\\mpv.conf"))
|
||||
File.WriteAllText(_ConfigFolder + "\\mpv.conf", Properties.Resources.mpvConf);
|
||||
if (!File.Exists(_ConfigFolder + "mpv.conf"))
|
||||
File.WriteAllText(_ConfigFolder + "mpv.conf", Properties.Resources.mpvConf);
|
||||
|
||||
if (!File.Exists(_ConfigFolder + "\\mpvnet.conf"))
|
||||
File.WriteAllText(_ConfigFolder + "\\mpvnet.conf", Properties.Resources.mpvNetConf);
|
||||
if (!File.Exists(_ConfigFolder + "mpvnet.conf"))
|
||||
File.WriteAllText(_ConfigFolder + "mpvnet.conf", Properties.Resources.mpvNetConf);
|
||||
}
|
||||
return _ConfigFolder;
|
||||
}
|
||||
@@ -203,42 +224,54 @@ namespace mpvnet
|
||||
|
||||
if (File.Exists(ConfPath))
|
||||
foreach (var i in File.ReadAllLines(ConfPath))
|
||||
if (i.Contains("=") && ! i.StartsWith("#"))
|
||||
if (i.Contains("=") && !i.TrimStart().StartsWith("#"))
|
||||
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
||||
|
||||
foreach (var i in Conf)
|
||||
foreach (var i in _Conf)
|
||||
ProcessProperty(i.Key, i.Value);
|
||||
}
|
||||
return _Conf;
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadMpvScripts()
|
||||
{
|
||||
if (Directory.Exists(Folder.Startup + "Scripts"))
|
||||
{
|
||||
string[] startupScripts = Directory.GetFiles(Folder.Startup + "Scripts");
|
||||
|
||||
foreach (string path in startupScripts)
|
||||
if ((path.EndsWith(".lua") || path.EndsWith(".js")) && KnownScripts.Contains(Path.GetFileName(path)))
|
||||
commandv("load-script", $"{path}");
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] KnownScripts { get; } = { "osc-visibility.js", "show-playlist.js", "seek-show-position.py", "repl.lua" };
|
||||
|
||||
public static void LoadScripts()
|
||||
{
|
||||
|
||||
if (Directory.Exists(Application.StartupPath + "\\Scripts"))
|
||||
if (Directory.Exists(Folder.Startup + "Scripts"))
|
||||
{
|
||||
string[] startupScripts = Directory.GetFiles(Application.StartupPath + "\\Scripts");
|
||||
|
||||
foreach (string scriptPath in startupScripts)
|
||||
if (scriptPath.EndsWith(".lua") || scriptPath.EndsWith(".js"))
|
||||
commandv("load-script", $"{scriptPath}");
|
||||
|
||||
foreach (string scriptPath in startupScripts)
|
||||
if (Path.GetExtension(scriptPath) == ".py")
|
||||
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
|
||||
|
||||
foreach (string scriptPath in startupScripts)
|
||||
if (Path.GetExtension(scriptPath) == ".ps1")
|
||||
PowerShellScript.Init(scriptPath);
|
||||
foreach (string scriptPath in Directory.GetFiles(Folder.Startup + "Scripts"))
|
||||
{
|
||||
if (KnownScripts.Contains(Path.GetFileName(scriptPath)))
|
||||
{
|
||||
if (scriptPath.EndsWith(".py"))
|
||||
Task.Run(() => PythonScripts.Add(new PythonScript(scriptPath)));
|
||||
else if (scriptPath.EndsWith(".ps1"))
|
||||
Task.Run(() => PowerShellScript.Init(scriptPath));
|
||||
}
|
||||
else
|
||||
Msg.ShowError("Failed to load script", scriptPath + "\n\nOnly scripts that ship with mpv.net are allowed in <startup>\\scripts\n\nUser scripts have to use <config folder>\\scripts\n\nNever copy or install a new mpv.net version over a old mpv.net version.");
|
||||
}
|
||||
}
|
||||
|
||||
if (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")
|
||||
PowerShellScript.Init(scriptPath);
|
||||
if (Directory.Exists(ConfigFolder + "scripts"))
|
||||
foreach (string scriptPath in Directory.GetFiles(ConfigFolder + "scripts"))
|
||||
if (scriptPath.EndsWith(".py"))
|
||||
Task.Run(() => PythonScripts.Add(new PythonScript(scriptPath)));
|
||||
else if (scriptPath.EndsWith(".ps1"))
|
||||
Task.Run(() => PowerShellScript.Init(scriptPath));
|
||||
}
|
||||
|
||||
public static void EventLoop()
|
||||
@@ -285,7 +318,7 @@ namespace mpvnet
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_FILE_LOADED:
|
||||
HideLogo();
|
||||
FileLoaded?.Invoke();
|
||||
Duration = TimeSpan.FromSeconds(get_property_number("duration"));
|
||||
Size vidSize = new Size(get_property_int("width"), get_property_int("height"));
|
||||
if (vidSize.Width == 0 || vidSize.Height == 0)
|
||||
vidSize = new Size(1, 1);
|
||||
@@ -296,7 +329,11 @@ namespace mpvnet
|
||||
}
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
Task.Run(new Action(() => ReadMetaData()));
|
||||
WriteHistory(get_property_string("path"));
|
||||
string path = mp.get_property_string("path");
|
||||
if (path.Contains("://"))
|
||||
path = mp.get_property_string("media-title");
|
||||
WriteHistory(path);
|
||||
FileLoaded?.Invoke();
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_TRACKS_CHANGED:
|
||||
TracksChanged?.Invoke();
|
||||
@@ -306,7 +343,7 @@ namespace mpvnet
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_IDLE:
|
||||
Idle?.Invoke();
|
||||
if (get_property_int("playlist-count") == 0) ShowLogo();
|
||||
ShowLogo();
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_PAUSE:
|
||||
Pause?.Invoke();
|
||||
@@ -344,19 +381,22 @@ namespace mpvnet
|
||||
var propData = (mpv_event_property)Marshal.PtrToStructure(evt.data, typeof(mpv_event_property));
|
||||
|
||||
if (propData.format == mpv_format.MPV_FORMAT_FLAG)
|
||||
foreach (var i in BoolPropChangeActions)
|
||||
if (i.Key== propData.name)
|
||||
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data) == 1);
|
||||
lock (BoolPropChangeActions)
|
||||
foreach (var i in BoolPropChangeActions)
|
||||
if (i.Key== propData.name)
|
||||
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data) == 1);
|
||||
|
||||
if (propData.format == mpv_format.MPV_FORMAT_STRING)
|
||||
foreach (var i in StringPropChangeActions)
|
||||
if (i.Key == propData.name)
|
||||
i.Value.Invoke(StringFromNativeUtf8(Marshal.PtrToStructure<IntPtr>(propData.data)));
|
||||
lock (StringPropChangeActions)
|
||||
foreach (var i in StringPropChangeActions)
|
||||
if (i.Key == propData.name)
|
||||
i.Value.Invoke(StringFromNativeUtf8(Marshal.PtrToStructure<IntPtr>(propData.data)));
|
||||
|
||||
if (propData.format == mpv_format.MPV_FORMAT_INT64)
|
||||
foreach (var i in IntPropChangeActions)
|
||||
if (i.Key == propData.name)
|
||||
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data));
|
||||
lock (IntPropChangeActions)
|
||||
foreach (var i in IntPropChangeActions)
|
||||
if (i.Key == propData.name)
|
||||
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data));
|
||||
break;
|
||||
case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART:
|
||||
PlaybackRestart?.Invoke();
|
||||
@@ -381,11 +421,8 @@ namespace mpvnet
|
||||
|
||||
static void HideLogo()
|
||||
{
|
||||
if (IsLogoVisible)
|
||||
{
|
||||
commandv("overlay-remove", "0");
|
||||
IsLogoVisible = false;
|
||||
}
|
||||
command("overlay-remove 0");
|
||||
IsLogoVisible = false;
|
||||
}
|
||||
|
||||
static List<PythonEventObject> PythonEventObjects = new List<PythonEventObject>();
|
||||
@@ -515,7 +552,8 @@ namespace mpvnet
|
||||
if (err < 0)
|
||||
throw new Exception($"{name}: {(mpv_error)err}");
|
||||
else
|
||||
IntPropChangeActions.Add(new KeyValuePair<string, Action<int>>(name, action));
|
||||
lock (IntPropChangeActions)
|
||||
IntPropChangeActions.Add(new KeyValuePair<string, Action<int>>(name, action));
|
||||
}
|
||||
|
||||
public static void observe_property_bool(string name, Action<bool> action)
|
||||
@@ -525,7 +563,8 @@ namespace mpvnet
|
||||
if (err < 0)
|
||||
throw new Exception($"{name}: {(mpv_error)err}");
|
||||
else
|
||||
BoolPropChangeActions.Add(new KeyValuePair<string, Action<bool>>(name, action));
|
||||
lock (BoolPropChangeActions)
|
||||
BoolPropChangeActions.Add(new KeyValuePair<string, Action<bool>>(name, action));
|
||||
}
|
||||
|
||||
public static void observe_property_string(string name, Action<string> action)
|
||||
@@ -535,37 +574,48 @@ namespace mpvnet
|
||||
if (err < 0)
|
||||
throw new Exception($"{name}: {(mpv_error)err}");
|
||||
else
|
||||
StringPropChangeActions.Add(new KeyValuePair<string, Action<string>>(name, action));
|
||||
lock (StringPropChangeActions)
|
||||
StringPropChangeActions.Add(new KeyValuePair<string, Action<string>>(name, action));
|
||||
}
|
||||
|
||||
protected static void ProcessCommandLine()
|
||||
public static void ProcessCommandLine(bool preInit)
|
||||
{
|
||||
var args = Environment.GetCommandLineArgs().Skip(1);
|
||||
List<string> files = new List<string>();
|
||||
|
||||
//Msg.Show(string.Join("\n", args));
|
||||
|
||||
string[] preInitProperties = { "input-terminal", "terminal", "input-file", "config", "config-dir", "input-conf", "load-scripts", "scripts", "player-operation-mode" };
|
||||
|
||||
foreach (string i in args)
|
||||
{
|
||||
if (!i.StartsWith("--") && (i == "-" || i.Contains("://") || File.Exists(i)))
|
||||
{
|
||||
files.Add(i);
|
||||
if (i.Contains("://")) RegHelp.SetObject(App.RegPath, "LastURL", i);
|
||||
}
|
||||
}
|
||||
string arg = i;
|
||||
|
||||
foreach (string i in args)
|
||||
{
|
||||
if (i.StartsWith("--"))
|
||||
if (arg.StartsWith("--"))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (i.Contains("="))
|
||||
if (!arg.Contains("=")) arg += "=yes";
|
||||
|
||||
string left = arg.Substring(2, arg.IndexOf("=") - 2);
|
||||
string right = arg.Substring(left.Length + 3);
|
||||
|
||||
if (left == "script") left = "scripts";
|
||||
|
||||
if (preInit && preInitProperties.Contains(left))
|
||||
{
|
||||
string left = i.Substring(2, i.IndexOf("=") - 2);
|
||||
string right = i.Substring(left.Length + 3);
|
||||
set_property_string(left, right, true);
|
||||
mp.ProcessProperty(left, right);
|
||||
if (!App.ProcessProperty(left, right))
|
||||
set_property_string(left, right, true);
|
||||
}
|
||||
else if (!preInit && !preInitProperties.Contains(left))
|
||||
{
|
||||
if (!PrintCommandLineArgument(arg))
|
||||
{
|
||||
mp.ProcessProperty(left, right);
|
||||
if (!App.ProcessProperty(left, right))
|
||||
set_property_string(left, right, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
set_property_string(i.Substring(2), "yes", true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -574,15 +624,43 @@ namespace mpvnet
|
||||
}
|
||||
}
|
||||
|
||||
Load(files.ToArray(), App.ProcessInstance != "queue", Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
|
||||
if (files.Count == 0 || files[0].Contains("://"))
|
||||
if (!preInit)
|
||||
{
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
VideoSizeChanged?.Invoke();
|
||||
List<string> files = new List<string>();
|
||||
|
||||
foreach (string i in args)
|
||||
{
|
||||
if (!i.StartsWith("--") && (i == "-" || i.Contains("://") ||
|
||||
i.Contains(":\\") || i.StartsWith("\\\\") || File.Exists(i)))
|
||||
{
|
||||
files.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
Load(files.ToArray(), App.ProcessInstance != "queue", Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
|
||||
if (files.Count == 0 || files[0].Contains("://"))
|
||||
{
|
||||
VideoSizeChanged?.Invoke();
|
||||
VideoSizeAutoResetEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool PrintCommandLineArgument(string argument)
|
||||
{
|
||||
switch (argument)
|
||||
{
|
||||
case "--list-properties=yes":
|
||||
var list = get_property_string("property-list").Split(',').ToList();
|
||||
list.Sort();
|
||||
Console.WriteLine(string.Join("\r\n", list.ToArray()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static DateTime LastLoad;
|
||||
|
||||
public static void Load(string[] files, bool loadFolder, bool append)
|
||||
@@ -596,7 +674,7 @@ namespace mpvnet
|
||||
LastLoad = DateTime.Now;
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
if (App.SubtitleTypes.Contains(Path.GetExtension(files[i]).TrimStart('.').ToLower()))
|
||||
if (App.SubtitleTypes.Contains(files[i].ShortExt()))
|
||||
commandv("sub-add", files[i]);
|
||||
else
|
||||
if (i == 0 && !append)
|
||||
@@ -612,14 +690,15 @@ namespace mpvnet
|
||||
|
||||
public static void LoadFolder()
|
||||
{
|
||||
if (!App.AutoLoadFolder) return;
|
||||
Thread.Sleep(200); // user reported race condition
|
||||
string path = get_property_string("path");
|
||||
if (!File.Exists(path) || get_property_int("playlist-count") != 1) return;
|
||||
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()) ||
|
||||
App.ImageTypes.Contains(Path.GetExtension(file).TrimStart('.').ToLower())).ToList();
|
||||
files = files.Where(file =>
|
||||
App.VideoTypes.Contains(file.ShortExt()) ||
|
||||
App.AudioTypes.Contains(file.ShortExt()) ||
|
||||
App.ImageTypes.Contains(file.ShortExt())).ToList();
|
||||
files.Sort(new StringLogicalComparer());
|
||||
int index = files.IndexOf(path);
|
||||
files.Remove(path);
|
||||
@@ -628,7 +707,7 @@ namespace mpvnet
|
||||
if (index > 0) commandv("playlist-move", "0", (index + 1).ToString());
|
||||
}
|
||||
|
||||
static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
|
||||
public static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
|
||||
{
|
||||
int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel)
|
||||
byteArrayPointers = new IntPtr[numberOfStrings];
|
||||
@@ -646,7 +725,7 @@ namespace mpvnet
|
||||
return rootPointer;
|
||||
}
|
||||
|
||||
static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr unmanagedStringArray, int StringCount)
|
||||
public static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr unmanagedStringArray, int StringCount)
|
||||
{
|
||||
IntPtr[] intPtrArray = new IntPtr[StringCount];
|
||||
string[] stringArray = new string[StringCount];
|
||||
@@ -658,7 +737,7 @@ namespace mpvnet
|
||||
return stringArray;
|
||||
}
|
||||
|
||||
static string StringFromNativeUtf8(IntPtr nativeUtf8)
|
||||
public static string StringFromNativeUtf8(IntPtr nativeUtf8)
|
||||
{
|
||||
int len = 0;
|
||||
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
|
||||
@@ -667,24 +746,21 @@ namespace mpvnet
|
||||
return Encoding.UTF8.GetString(buffer);
|
||||
}
|
||||
|
||||
static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
|
||||
public static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
|
||||
|
||||
static string LastHistoryPath;
|
||||
static DateTime LastHistoryStartDateTime;
|
||||
|
||||
static void WriteHistory(string path)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
if (!File.Exists(ConfigFolder + "history.txt"))
|
||||
return;
|
||||
|
||||
int totalMinutes = Convert.ToInt32((DateTime.Now - LastHistoryStartDateTime).TotalMinutes);
|
||||
|
||||
if (File.Exists(LastHistoryPath) && totalMinutes > 1)
|
||||
{
|
||||
string historyFilepath = ConfigFolder + "history.txt";
|
||||
|
||||
File.AppendAllText(historyFilepath, DateTime.Now.ToString().Substring(0, 16) +
|
||||
" " + totalMinutes.ToString().PadLeft(3) + " " +
|
||||
Path.GetFileNameWithoutExtension(LastHistoryPath) + "\r\n");
|
||||
}
|
||||
if (PathHelp.GetBaseName(LastHistoryPath) != "" && totalMinutes > 1)
|
||||
File.AppendAllText(ConfigFolder + "history.txt", DateTime.Now.ToString().Substring(0, 16) +
|
||||
" " + totalMinutes.ToString().PadLeft(3) + " " + PathHelp.GetBaseName(LastHistoryPath) + "\r\n");
|
||||
|
||||
LastHistoryPath = path;
|
||||
LastHistoryStartDateTime = DateTime.Now;
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |