Compare commits

...

46 Commits

Author SHA1 Message Date
stax76
ad74acae0f v7.1.0.0 2024-01-12 11:29:47 +01:00
stax76
d325cf1165 Japanese translation added 2024-01-08 05:42:24 +01:00
stax76
39bace76d3 removal of hidden mouse exit feature 2024-01-07 11:20:10 +01:00
stax76
44e8ef7cd8 fix #639 2024-01-06 23:13:33 +01:00
stax76
85e4e3f9df fix geometry 2024-01-06 12:03:28 +01:00
stax76
ad94042a2c Chinese translation updated 2024-01-06 10:45:14 +01:00
stax76
304fe58f27 misc 2024-01-04 03:53:24 +01:00
stax76
edcd8be662 improved audio device support 2024-01-03 06:39:25 +01:00
stax76
3970d5c0c2 v7.0.0.6 Beta 2024-01-02 09:09:16 +01:00
stax76
4451eafe71 Merge branch 'main' of https://github.com/mpvnet-player/mpv.net 2023-12-28 06:18:10 +01:00
stax76
1c799fd474 hwdec description 2023-12-28 06:17:57 +01:00
stax76
17e25619da Merge pull request #626 from nkh0472/patch-3
change screenshot-tag-colorspace default value to `yes`
2023-12-28 06:16:06 +01:00
stax76
a4376b1492 Merge pull request #627 from nkh0472/patch-4
Detailed description for hwdec
2023-12-28 06:13:37 +01:00
stax76
d41faad9d9 v7.0.0.5 Beta 2023-12-28 06:11:42 +01:00
nkh0472
0e6116b478 Detailed description for hwdec 2023-12-27 22:29:31 +08:00
nkh0472
789127e8ff change screenshot-tag-colorspace default value to yes 2023-12-27 22:17:45 +08:00
stax76
6ef9f32d4f misc 2023-12-26 16:58:12 +01:00
stax76
1048dbed40 New menu item and binding: File > Add files to playlist from clipboard (Ctrl+Shift+v) 2023-12-26 09:22:27 +01:00
stax76
86c823bfde misc 2023-12-24 07:34:12 +01:00
stax76
764f00ed3a misc 2023-12-23 10:20:57 +01:00
stax76
3e4ea03437 Support of the mpv option title-bar 2023-12-22 18:35:07 +01:00
stax76
0ef679e00d argh 2023-12-21 10:01:59 +01:00
stax76
7f2bf2e905 misc 2023-12-20 05:19:50 +01:00
stax76
ab8a8d5a35 Command line parser fix using list options with -add suffix 2023-12-19 12:12:34 +01:00
stax76
a3b9c653fa v7.0.0.4 Beta 2023-12-19 09:37:46 +01:00
stax76
ed48f5c559 Command line parser supports list options with -add suffix. Fixex #619. 2023-12-19 03:18:55 +01:00
stax76
d328f6b7ec Main window: Limited geometry support 2023-12-17 19:08:55 +01:00
stax76
16ba94d67d updated manual and new libplacebo GUI options 2023-12-16 13:48:27 +01:00
stax76
7978170133 Merge pull request #617 from FantasqueX/fix-typo-1
fix typo in changelog
2023-12-16 08:44:03 +01:00
stax76
ab313eb442 new libplacebo options 2023-12-16 08:43:22 +01:00
Letu Ren
f40008d94a fix typo in changelog 2023-12-16 15:31:50 +08:00
stax76
75e19d8d18 newly developed combo box control 2023-12-16 04:57:49 +01:00
stax76
9bb978f612 new combo box control 2023-12-16 04:52:16 +01:00
stax76
7ea3fbc917 v7.0.0.3 2023-12-15 15:21:35 +01:00
stax76
3af5b458ba misc 2023-12-15 14:58:32 +01:00
stax76
b23542d681 Conf editor crash fixed 2023-12-15 08:35:01 +01:00
stax76
e0616dee76 misc 2023-12-15 01:24:43 +01:00
stax76
cd54e67b87 new menu items and bindings to open mpv.conf and input.conf with a text editor 2023-12-14 13:48:23 +01:00
stax76
9d4779fd96 Conf editor support for: reset-on-next-file, input-ipc-server, background, title 2023-12-14 11:08:36 +01:00
stax76
d4d147e5fc Improved conf file reader/writer. 2023-12-14 07:31:39 +01:00
stax76
35b17bc620 New menu item added to add mpv.net to the path environment variable. 2023-12-13 09:46:17 +01:00
stax76
3eb4af5e75 v7.0.0.2 2023-12-13 08:45:20 +01:00
stax76
49f22a1f81 misc 2023-12-13 03:38:23 +01:00
stax76
7cd5686488 Trying getting decent menu input display 2023-12-13 00:57:59 +01:00
stax76
0d63feec57 Remove MS Store package from solution 2023-12-12 18:29:35 +01:00
stax76
0ee8318ca4 some bug fixes 2023-12-12 18:15:20 +01:00
67 changed files with 5701 additions and 2876 deletions

View File

@@ -54,7 +54,7 @@ jobs:
- name: Download libmpv # In principle, only update this binary file when significant feature changes occur in mpv/mpv.net - name: Download libmpv # In principle, only update this binary file when significant feature changes occur in mpv/mpv.net
shell: msys2 {0} shell: msys2 {0}
run: | run: |
wget -nv -O libmpv.7z https://downloads.sourceforge.net/mpv-player-windows/mpv-dev-x86_64-20231203-git-f551a9d.7z wget -nv -O libmpv.7z https://github.com/zhongfly/mpv-winbuild/releases/download/2024-01-02-ab5b250/mpv-dev-x86_64-20240102-git-ab5b250.7z
7z x -y libmpv.7z -olibmpv 7z x -y libmpv.7z -olibmpv
cp -f libmpv/libmpv-2.dll src/MpvNet.Windows/bin/Debug/ || true cp -f libmpv/libmpv-2.dll src/MpvNet.Windows/bin/Debug/ || true
- name: Download MediaInfo - name: Download MediaInfo

View File

@@ -1,4 +1,87 @@
# v7.1.0.0 Beta (2023-01-12)
- The menu item that shows profiles was moved into the menu item that lists profiles.
- Fix geometry not working when used from mpv.conf and the conf editor.
- GitHub Auto/Action/Workflow builds use a newer libmpv build.
- German and Chinese translation updated. Japanese translation added. Thanks to our translation team!
- New PowerShell script Tools/update-mpv-and-libmpv.ps1 to update mpv and libmpv.
- Context menu supports audio device selection (Audio > Audio Device)
- New option `remember-audio-device` to save and restore the audio device chosen in the context menu.
- New zhongfly libmpv build.
# v7.0.0.6 Beta (2023-01-02)
- Improved backward compatibility with input.conf files created by old versions.
# v7.0.0.5 Beta (2023-12-28)
- Fix mpv.net option `language` not working from command line.
- Chinese and German translation updated.
- More libplacebo options added.
- Support of the mpv option `title-bar`.
- Video being less often rendered with black line at the bottom.
- The conf file reader/writer detects if the user prefers space before and after the equal sign.
- The portable download includes like the installer debug symbols.
- Setup questions on startup removed.
- Pressing shift while drag and drop appends instead of replaces
files in the playlist. mpv supports this as well.
- New menu item and binding: `File > Add files to playlist from clipboard` `Ctrl+Shift+v`.
- All list operation suffixes are available on the command line.
- Improved layout in conf editor.
- New zhongfly libmpv build.
# v7.0.0.4 Beta (2023-12-19)
- When mpv.net is started for the first time from a new startup location,
it asks if file associations should be registered.
- Setup supports installing per user in non admin mode.
- Command line parser supports list options with `-add` suffix.
- Fix window sometimes shown with wrong size.
- Limited support for the mpv option `geometry`, it supports location in percent,
for size use `autofit`. Read the instructions in the mpv.net manual or in the conf editor.
- Improved manual.
- Improved bindings.
- Conf editor reorganized according to options categories used in mpv manual.
- mpv.net is available via command line package manager winget.
- New libplacebo config editor options added.
- The conf editor uses a newly developed combo box control (dropdown menu)
instead of radio buttons whenever an option has more than 3 items,
this improves the look and feel, usability and performance.
The navigation tree view was improved.
- New zhongfly libmpv build.
# v7.0.0.3 Beta (2023-12-15)
- New conf editor option `Video/libplacebo/preset`.
- New conf editor option `Video/libplacebo/Scaling/upscaler`.
- New menu item `Settings/Setup/Add mpv.net to Path environment variable' added.
- New menu item `Settings/Edit mpv.conf` added for opening mpv.conf with a text editor. Default binding `c`.
- New menu item `Settings/Edit input.conf` added for opening input.conf with a text editor. Default binding `k`.
- mpv.net can no longer be downloaded from the Microsoft store due
to a general very poor experience with the package creation and submission.
I've submitted mpv.net to the winget package repository, it's not yet processed.
- Improved conf file reader/writer.
- Conf editor support added for the mpv options:
`reset-on-next-file`, `input-ipc-server`, `background`, `title`
- Conf editor crash fixed.
- When mpv.net is started for the first time from a new startup location,
it asks if mpv.net should be added to the Path environment variable.
# v7.0.0.2 Beta (2023-12-13)
- Besides a portable download there is now again a setup installer.
- Fix dynamic menu items missing in context menu.
- Fix certain binding setups shown poorly or incorrectly in the main menu.
- Fix conf editor not remembering the search text.
- Fix quit-watch-later not working.
- New option `menu-syntax`. Default: `#menu:`
- New zhongfly libmpv build.
# v7.0.0.1 Beta (2023-12-11) # v7.0.0.1 Beta (2023-12-11)
- [.NET 6 is a new requirement](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) - [.NET 6 is a new requirement](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
@@ -12,7 +95,7 @@
- Fix message box exceding working area size. - Fix message box exceding working area size.
- C# and PowerShell scripting was removed because of a compatibility problem - C# and PowerShell scripting was removed because of a compatibility problem
with the .NET 6 platform. .NET extensions are supported with a new host with the .NET 6 platform. .NET extensions are supported with a new host
(not backward compatible). A example extension is available under \src\MpvNet.Extension\ExampleExtension (not backward compatible). An example extension is available under \src\MpvNet.Extension\ExampleExtension
- Redesigned bindings and context menu. - Redesigned bindings and context menu.
- auto-play option removed, mpv supports it with the option reset-on-next-file. - auto-play option removed, mpv supports it with the option reset-on-next-file.
- Dark mode title bar enabled on Windows 10.0.18985 or higher. - Dark mode title bar enabled on Windows 10.0.18985 or higher.

View File

@@ -25,6 +25,7 @@ Table of contents
* [Hidden Features](#hidden-features) * [Hidden Features](#hidden-features)
* [Differences compared to mpv](#differences-compared-to-mpv) * [Differences compared to mpv](#differences-compared-to-mpv)
* [Environment Variables](#environment-variables) * [Environment Variables](#environment-variables)
* [user-data](#user-data)
* [Context Menu Commands](#context-menu) * [Context Menu Commands](#context-menu)
@@ -42,13 +43,9 @@ differences are documented in this manual under [Differences compared to mpv](#d
Download Download
-------- --------
1. [Stable via Microsoft Store](https://www.microsoft.com/store/productId/9N64SQZTB3LM) 1. [Stable and beta portable and setup via GitHub download](../../../releases)
2. Stable via command line with winget: `winget install mpv.net`
2. [Stable and beta portable via GitHub download](../../../releases) 3. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions)
3. Stable via command line from Microsoft Store: `winget install mpv.net`
4. [Automated nightly portable builds](https://github.com/mpvnet-player/mpv.net/actions)
[Changelog](changelog.md) [Changelog](changelog.md)
@@ -56,10 +53,8 @@ Download
Installation Installation
------------ ------------
1. Windows 7 or higher is required (Windows 10 or higher is recommended). 1. Windows 10 or higher.
2. mpv.net since version 7.0 requires the 2. [.NET Desktop Runtime 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
[.NET Desktop Runtime 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
being installed. mpv.net before version 7.0 requires .NET Framework 4.8.
Internet streaming requires: Internet streaming requires:
@@ -71,8 +66,8 @@ Internet streaming requires:
File Associations can be registered using the context menu under 'Settings > Setup'. File Associations can be registered using the context menu under 'Settings > Setup'.
After the file associations were registered, it might be necessary to change the After the file associations were registered, it might still be necessary to change the
default app in the Windows settings (Win+I, ms-settings:defaultapps). default app in the Windows settings.
Another way to register file associations is using Windows File Explorer, Another way to register file associations is using Windows File Explorer,
select a media file and select 'Open with > Choose another app' in the context menu. select a media file and select 'Open with > Choose another app' in the context menu.
@@ -84,6 +79,11 @@ to get menu items for [Play with mpv.net](https://github.com/stax76/OpenWithPlus
When multiple files are selected in File Explorer and enter is pressed then When multiple files are selected in File Explorer and enter is pressed then
the files are opened in mpv.net in random order, this works with maximum 15 files. the files are opened in mpv.net in random order, this works with maximum 15 files.
#### Path environment variable
In order to use mpv.net in a terminal for advanced use cases,
mpv.net must be added to the Path environment variable,
this can be achieved with the context menu (Settings/Setup).
Support Support
------- -------
@@ -92,14 +92,14 @@ Before making a support request, please try the newest [beta version](../../../r
Support can be requested here: Support can be requested here:
Beginner questions:
https://www.reddit.com/r/mpv
mpv.net bug reports, feature requests and advanced questions: mpv.net bug reports, feature requests and advanced questions:
https://github.com/mpvnet-player/mpv.net/issues https://github.com/mpvnet-player/mpv.net/issues
Beginner mpv questions:
https://www.reddit.com/r/mpv
Advanced mpv questions: Advanced mpv questions:
https://github.com/mpv-player/mpv/issues https://github.com/mpv-player/mpv/issues
@@ -110,8 +110,9 @@ Settings
mpv.net searches the config folder at: mpv.net searches the config folder at:
1. startup\portable_config 1. Folder defined via MPVNET_HOME environment variable.
2. %APPDATA%\mpv.net (`C:\Users\%USERNAME%\AppData\Roaming\mpv.net`) 2. startup\portable_config (startup means the directory containing mpvnet.exe)
3. `%APPDATA%\mpv.net` (`C:\Users\Username\AppData\Roaming\mpv.net`)
mpv options are stored in the file mpv.conf, mpv options are stored in the file mpv.conf,
mpv.net options are stored in the file mpvnet.conf, mpv.net options are stored in the file mpvnet.conf,
@@ -121,7 +122,7 @@ mpv.net options are documented [here](#mpvnet-specific-options).
Input and context menu Input and context menu
---------------------- ----------------------
Global keyboard shortcuts are supported via global-input.conf file. Global keyboard shortcuts are supported via `global-input.conf` file.
The config folder can be opened from the context menu: `Settings > Open Config Folder` The config folder can be opened from the context menu: `Settings > Open Config Folder`
@@ -141,24 +142,31 @@ mpv input options:
https://mpv.io/manual/master/#input https://mpv.io/manual/master/#input
Before version v7 all bindings and the context menu definition Before version v7 all bindings and the context menu definition
was contained in the input.conf file, which mpv.net created were defined in the input.conf file, which mpv.net created
in case it didn't exist. This had the disadvantage that mpv.net in case it didn't exist. This had the disadvantage that mpv.net
lost control over all default bindings and the context menu lost control over all default bindings and context menu
defaults. This was unfortunate, v7 introduces a new design defaults. This was unfortunate, v7 introduces a new bindings
fixing it. and context menu design fixing it.
In v7 no input.conf file is created, the default bindings and In v7 no input.conf file is created, the default bindings and
context menu is defined internally. input.conf only contains context menu is defined internally. input.conf only contains
what is different from the internally defined defaults, what is different from the internally defined defaults,
so it's the same how mpv is used. so it works the same as it works in mpv.
For backward compatibility the old input.conf format with the For backward compatibility the old input.conf context menu
menu definition using `#menu: ` is still supported. The new format with the menu definition using `#menu: ` is still
design also allows for a menu customization, in a sub section supported. The new design also allows for a menu customization,
called `Custom`. In input.conf it can be defined like so: in a sub section called `Custom`. In input.conf it can be
defined like so:
`Ctrl+a show-text Test #custom-menu: Test > Test` `Ctrl+a show-text Test #custom-menu: Test > Test`
Users that have their bindings and context menu customized
before v7 can easily migrate to the new design by deleting
bindings they don't use and remember the shortcut and remove
`#menu:` everywhere, it's important to remove `#menu:`
everywhere in order to enable the new mode/design.
Command Line Interface Command Line Interface
---------------------- ----------------------
@@ -194,8 +202,6 @@ Terminal
When mpv.net is started from a terminal it will output status, When mpv.net is started from a terminal it will output status,
error and debug messages to the terminal and accept input keys from the terminal. error and debug messages to the terminal and accept input keys from the terminal.
A common task for the terminal is debugging scripts.
mpv.net specific commands mpv.net specific commands
------------------------- -------------------------
@@ -204,6 +210,15 @@ mpv.net specific commands
mpv.net commands are used when mpv commands don't exist or lack a feature. mpv.net commands are used when mpv commands don't exist or lack a feature.
### add-to-path
Adds mpv.net to the Path environment variable.
### remove-from-path
Removes mpv.net from the Path environment variable.
### edit-conf-file [mpv.conf|input.conf]
Opens mpv.conf or input.conf in a text editor.
### load-audio ### load-audio
Shows a file browser dialog to open external audio files. Shows a file browser dialog to open external audio files.
@@ -229,10 +244,13 @@ Shows a folder browser dialog to open a DVD or BD folder.
ISO images don't have to be mounted, but instead can be ISO images don't have to be mounted, but instead can be
opened directly with the open-files command. opened directly with the open-files command.
### open-clipboard ### open-clipboard [\<flags\>]
Opens a single URL or filepath from the clipboard, Opens a single URL or filepath from the clipboard,
or multiple files in the file clipboard format. or multiple files in the file clipboard format.
**append**
Appends files/URLs to the playlist.
### play-pause ### play-pause
Cycles the pause property. In case the playlist is empty, Cycles the pause property. In case the playlist is empty,
the most recent file from the recent files list is loaded. the most recent file from the recent files list is loaded.
@@ -255,8 +273,14 @@ Shows available audio devices in a message box.
### show-commands ### show-commands
Shows available [mpv input commands](https://mpv.io/manual/master/#list-of-input-commands). Shows available [mpv input commands](https://mpv.io/manual/master/#list-of-input-commands).
### show-conf-editor ### show-properties
Shows the conf editor. Shows available [properties](https://mpv.io/manual/master/#properties).
### show-keys
Shows available [input keys](https://mpv.io/manual/master/#options-input-keylist).
### show-protocols
Shows available [protocols](https://mpv.io/manual/master/#options-list-protocols).
### show-decoders ### show-decoders
Shows available decoders. Shows available decoders.
@@ -264,6 +288,9 @@ Shows available decoders.
### show-demuxers ### show-demuxers
Shows available demuxers. Shows available demuxers.
### show-conf-editor
Shows the conf editor.
### show-input-editor ### show-input-editor
Shows the input editor. Shows the input editor.
@@ -330,6 +357,10 @@ to create global keyboard shortcuts with AutoHotkey. Requires [process-instance=
### Audio ### Audio
#### --remember-audio-device=\<yes|no\>
Save and restore the audio device chosen in the context menu. Default: yes
#### --remember-volume=\<yes|no\> #### --remember-volume=\<yes|no\>
Save volume and mute on exit and restore it on start. Default: yes Save volume and mute on exit and restore it on start. Default: yes
@@ -390,6 +421,10 @@ For single files automatically load the entire directory into the playlist.
### General ### General
#### --menu-syntax=\<value\>
Used menu syntax for defining the context menu in input.conf.\nmpv.net by default uses `#menu:`, uosc uses `#!` by default.
#### --process-instance=\<value\> #### --process-instance=\<value\>
Defines if more then one mpv.net process is allowed. Defines if more then one mpv.net process is allowed.
@@ -508,7 +543,8 @@ Scripting
#### Lua #### Lua
A very large collection of Lua user scripts can be found in the mpv wiki [here](https://github.com/mpv-player/mpv/wiki/User-Scripts). A very large collection of user scripts can be found in the GitHub repository
[awesome-mpv](https://github.com/stax76/awesome-mpv).
Lua scripting is documented in the mpv.net wiki [here](https://github.com/mpvnet-player/mpv.net/wiki/Extending-mpv-and-mpv.net-via-Lua-scripting). Lua scripting is documented in the mpv.net wiki [here](https://github.com/mpvnet-player/mpv.net/wiki/Extending-mpv-and-mpv.net-via-Lua-scripting).
@@ -517,10 +553,10 @@ Lua scripting is documented in the mpv.net wiki [here](https://github.com/mpvnet
[mpv JavaScript documentation](https://mpv.io/manual/master/#javascript) [mpv JavaScript documentation](https://mpv.io/manual/master/#javascript)
Extensions .NET Extensions
---------- ---------------
Extensions are located in a subfolder _extensions_ in the config folder, .NET Extensions are located in a subfolder _extensions_ in the config folder,
the filename must have the same name as the directory: the filename must have the same name as the directory:
```Text ```Text
@@ -592,7 +628,7 @@ visible, even when mpv.net is started from the terminal and music is played.
For mpv.net it's currently not possible to find out where OSC menus are located, For mpv.net it's currently not possible to find out where OSC menus are located,
but there are 3 features that require this information, therefore mpv.net but there are 3 features that require this information, therefore mpv.net
makes the assumption that near the window borders might be OSC menus. As a result makes the assumption that near the window borders might be OSC menus. As a result
the following three features, work only when invokes from the center of the window: the following three features, work only when invoked from the center of the window:
1. Window dragging (moving the window with the mouse). 1. Window dragging (moving the window with the mouse).
2. Showing the context menu. 2. Showing the context menu.
@@ -614,20 +650,44 @@ https://mpv.io/manual/master/#window
- [ontop](https://mpv.io/manual/master/#options-ontop) - [ontop](https://mpv.io/manual/master/#options-ontop)
- [screen](https://mpv.io/manual/master/#options-screen) - [screen](https://mpv.io/manual/master/#options-screen)
- [snap-window](https://mpv.io/manual/master/#options-snap-window) - [snap-window](https://mpv.io/manual/master/#options-snap-window)
- [title-bar](https://mpv.io/manual/master/#options-title-bar)
- [title](https://mpv.io/manual/master/#options-title) - [title](https://mpv.io/manual/master/#options-title)
- [window-maximized](https://mpv.io/manual/master/#options-window-maximized) - [window-maximized](https://mpv.io/manual/master/#options-window-maximized)
- [window-minimized](https://mpv.io/manual/master/#options-window-minimized) - [window-minimized](https://mpv.io/manual/master/#options-window-minimized)
- [window-scale](https://mpv.io/manual/master/#options-window-scale) - [window-scale](https://mpv.io/manual/master/#options-window-scale)
**Partly implemented are:** **Partly implemented or modified:**
- [autofit-larger](https://mpv.io/manual/master/#options-autofit-larger) #### --autofit=\<int\>
Supported is a single integer value in the range 0-100.
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller) \<int\> Initial window height in percent. Default: 60
Supported is a single integer value in the range 0-100.
- [autofit](https://mpv.io/manual/master/#options-autofit) #### --autofit-smaller=\<int\>
Supported is a single integer value in the range 0-100.
\<int\> Minimum window height in percent. Default: 10
#### --autofit-larger=\<int\>
\<int\> Maximum window height in percent. Default: 80
#### --geometry\<x:y\>
Initial window location in percent. Default: 50:50 (centered)
Requires Windows 11, on Windows 10 it works slightly incorrect due to invisible borders.
x=0 docks the window to the left side.
x=100 docks the window to the right side.
y=0 docks the window to the top side.
y=100 docks the window to the bottom side.
#### --title-bar=\<yes|no\>
Shows the window title bar. Default: yes
**mpv.net specific window features:**
mpv.net specific window features are documented in the [screen section](#screen). mpv.net specific window features are documented in the [screen section](#screen).
@@ -672,10 +732,18 @@ Environment Variables
Directory where mpv.net looks for user settings. Directory where mpv.net looks for user settings.
### MPVNET_VERSION
Returns the version of mpv.net. user-data
---------
Script authors can access the following
[user-data](https://mpv.io/manual/master/#command-interface-user-data) properties:
```
user-data/frontend/name
user-data/frontend/version
user-data/frontend/process-path
```
Context Menu Commands Context Menu Commands
--------------------- ---------------------
@@ -694,8 +762,8 @@ Blu-ray and DVD ISO image files are supported.
### Open > Open URL or file path from clipboard ### Open > Open URL or file path from clipboard
Opens files and URLs from the clipboard. How to open URLs directly Opens files and URLs from the clipboard. Shift key appends to the playlist.
from the browser from sites like YouTube is described in the How to open URLs directly from the browser from sites like YouTube is described in the
[External Tools section](#external-tools). [External Tools section](#external-tools).

View File

@@ -1,4 +1,6 @@
$ErrorActionPreference = 'Stop'
$PoFiles = Get-ChildItem $PSScriptRoot/po $PoFiles = Get-ChildItem $PSScriptRoot/po
$ExeFolder = "$PSScriptRoot/../src/MpvNet.Windows/bin/Debug" $ExeFolder = "$PSScriptRoot/../src/MpvNet.Windows/bin/Debug"
@@ -20,15 +22,14 @@ function CreateFolder
foreach ($it in $PoFiles) foreach ($it in $PoFiles)
{ {
$folder = "$ExeFolder/Locale/$($it.BaseName)/LC_MESSAGES" $folder = "$ExeFolder/Locale/$($it.BaseName)/LC_MESSAGES"
New-Item -ItemType Directory -Path $folder
$moPath = "$folder/mpvnet.mo"
New-Item -ItemType File -Path $moPath
msgfmt --output-file=$moPath $it.FullName
if ($LASTEXITCODE -ne 0) if (-not (Test-Path $folder))
{ {
throw New-Item -ItemType Directory -Path $folder
} }
$moPath = "$folder/mpvnet.mo"
msgfmt --output-file=$moPath $it.FullName
if ($LastExitCode) { throw $LastExitCode }
$moPath $moPath
} }

View File

@@ -3,6 +3,7 @@ D:\Projects\CS\mpv.net\src\MpvNet\AppInfo.cs
D:\Projects\CS\mpv.net\src\MpvNet\Binding.cs D:\Projects\CS\mpv.net\src\MpvNet\Binding.cs
D:\Projects\CS\mpv.net\src\MpvNet\Chapter.cs D:\Projects\CS\mpv.net\src\MpvNet\Chapter.cs
D:\Projects\CS\mpv.net\src\MpvNet\Command.cs D:\Projects\CS\mpv.net\src\MpvNet\Command.cs
D:\Projects\CS\mpv.net\src\MpvNet\CommandLine.cs
D:\Projects\CS\mpv.net\src\MpvNet\ExtensionLoader.cs D:\Projects\CS\mpv.net\src\MpvNet\ExtensionLoader.cs
D:\Projects\CS\mpv.net\src\MpvNet\FileTypes.cs D:\Projects\CS\mpv.net\src\MpvNet\FileTypes.cs
D:\Projects\CS\mpv.net\src\MpvNet\Folder.cs D:\Projects\CS\mpv.net\src\MpvNet\Folder.cs
@@ -14,6 +15,7 @@ D:\Projects\CS\mpv.net\src\MpvNet\MediaTrack.cs
D:\Projects\CS\mpv.net\src\MpvNet\MpvClient.cs D:\Projects\CS\mpv.net\src\MpvNet\MpvClient.cs
D:\Projects\CS\mpv.net\src\MpvNet\Player.cs D:\Projects\CS\mpv.net\src\MpvNet\Player.cs
D:\Projects\CS\mpv.net\src\MpvNet\Settings.cs D:\Projects\CS\mpv.net\src\MpvNet\Settings.cs
D:\Projects\CS\mpv.net\src\MpvNet\StringPair.cs
D:\Projects\CS\mpv.net\src\MpvNet\Terminal.cs D:\Projects\CS\mpv.net\src\MpvNet\Terminal.cs
D:\Projects\CS\mpv.net\src\MpvNet\Translator.cs D:\Projects\CS\mpv.net\src\MpvNet\Translator.cs
D:\Projects\CS\mpv.net\src\MpvNet\ExtensionMethod\ObjectExtension.cs D:\Projects\CS\mpv.net\src\MpvNet\ExtensionMethod\ObjectExtension.cs
@@ -35,9 +37,8 @@ D:\Projects\CS\mpv.net\src\MpvNet.Windows\GlobalUsings.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Program.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Program.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Settings.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Settings.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\StringPair.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\RegistryHelp.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\RegistryHelp.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\WinMpvHelp.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Help\WinApiHelp.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\StockIcon.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\StockIcon.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\Taskbar.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\Taskbar.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\WinApi.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\WinApi.cs
@@ -51,6 +52,7 @@ D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.Designer.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.Designer.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\SnapManager.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\SnapManager.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\BindingProxy.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\BindingProxy.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ComboBoxTemplateSelector.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ConfWindow.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ConfWindow.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\InputWindow.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\InputWindow.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ISettingControl.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ISettingControl.cs
@@ -59,6 +61,7 @@ D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\MenuHelp.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Msg.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Msg.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfApplication.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfApplication.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfTranslator.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfTranslator.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\ComboBoxSettingControl.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\CommandPaletteControl.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\CommandPaletteControl.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\HyperlinkEx.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\HyperlinkEx.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\OptionSettingControl.xaml.cs D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\OptionSettingControl.xaml.cs

File diff suppressed because it is too large Load Diff

880
lang/po/ja.po Normal file
View File

@@ -0,0 +1,880 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# ever_green, 2024
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-04 02:51+0100\n"
"PO-Revision-Date: 2023-12-08 00:34+0000\n"
"Last-Translator: ever_green, 2024\n"
"Language-Team: Japanese (https://app.transifex.com/stax76/teams/179964/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ja\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:12
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:13
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:14
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:15
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:16
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:17
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:18
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:19
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:20
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:21
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:22
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:23
msgid "File"
msgstr "ファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:12
msgid "Open Files..."
msgstr "ファイルを開く..."
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:13
msgid "Open URL or file from clipboard"
msgstr "クリップボードから URL またはファイルを開く"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:14
msgid "Open DVD/Blu-ray Drive/Folder..."
msgstr "DVD/Blu-ray ドライブ/フォルダを開く..."
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:16
msgid "Add external audio files..."
msgstr "外部オーディオファイルを追加..."
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:17
msgid "Add external subtitle files..."
msgstr "外部字幕ファイルを追加..."
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:19
msgid "Add files to playlist..."
msgstr "プレイリストにファイルを追加..."
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:20
msgid "Add files/URLs to playlist from clipboard"
msgstr "クリップボードからプレイリストにファイル/URL を追加"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:22
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:379
msgid "Recent Files"
msgstr "最近のファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:23
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:187
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:219
msgid "Exit"
msgstr "終了"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:25
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:26
msgid "Playback"
msgstr "再生"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:25
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:189
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:190
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:191
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:192
msgid "Play/Pause"
msgstr "再生/一時停止"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:26
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:193
msgid "Stop"
msgstr "停止"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:28
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:29
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:30
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:31
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:32
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:34
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:35
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:36
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:37
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:38
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:39
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:40
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:41
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:42
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:43
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:44
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:45
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:46
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:47
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:48
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:49
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:50
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:51
msgid "Navigate"
msgstr "操作"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:28
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:200
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:202
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:204
msgid "Previous File"
msgstr "前のファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:29
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:201
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:203
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:205
msgid "Next File"
msgstr "次のファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:31
msgid "First File"
msgstr "最初のファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:32
msgid "Last File"
msgstr "最後のファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:35
msgid "Next Chapter"
msgstr "次のチャプター"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:36
msgid "Previous Chapter"
msgstr "前のチャプター"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:38
msgid "Jump To Next Frame"
msgstr "次のフレームにジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:39
msgid "Jump To Previous Frame"
msgstr "前のフレームにジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:41
msgid "Jump 5 sec forward"
msgstr "5 秒前方にジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:42
msgid "Jump 5 sec backward"
msgstr "5 秒後方にジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:44
msgid "Jump 30 sec forward"
msgstr "30 秒前方にジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:45
msgid "Jump 30 sec backward"
msgstr "30 秒後方にジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:47
msgid "Jump 5 min forward"
msgstr "5 分前方にジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:48
msgid "Jump 5 min backward"
msgstr "5 分後方にジャンプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:50
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:398
msgid "Title"
msgstr "タイトル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:51
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:358
msgid "Chapter"
msgstr "チャプター"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:53
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:54
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:55
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:56
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:57
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:58
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:59
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:60
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:61
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:62
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:63
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:64
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:65
msgid "Pan & Scan"
msgstr "パン&スキャン"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:53
msgid "Decrease Size"
msgstr "サイズを縮小"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:54
msgid "Increase Size"
msgstr "サイズを拡大"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:56
msgid "Move Left"
msgstr "左に移動"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:57
msgid "Move Right"
msgstr "右に移動"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:59
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:97
msgid "Move Up"
msgstr "上に移動"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:60
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:98
msgid "Move Down"
msgstr "下に移動"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:62
msgid "Decrease Height"
msgstr "高さを縮小"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:63
msgid "Increase Height"
msgstr "高さを拡大"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:65
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:118
msgid "Reset"
msgstr "リセット"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:67
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:68
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:69
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:70
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:71
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:72
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:73
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:74
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:75
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:76
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:77
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:78
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:79
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:80
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:81
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:82
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:83
msgid "Video"
msgstr "ビデオ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:67
msgid "Decrease Contrast"
msgstr "コントラストを下げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:68
msgid "Increase Contrast"
msgstr "コントラストを上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:70
msgid "Decrease Brightness"
msgstr "明るさを下げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:71
msgid "Increase Brightness"
msgstr "明るさを上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:73
msgid "Decrease Gamma"
msgstr "ガンマ値を下げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:74
msgid "Increase Gamma"
msgstr "ガンマ値を上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:76
msgid "Decrease Saturation"
msgstr "彩度を下げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:77
msgid "Increase Saturation"
msgstr "彩度を上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:79
msgid "Take Screenshot"
msgstr "スクリーンショットを撮る"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:80
msgid "Take Screenshot without subtitles"
msgstr "字幕なしでスクリーンショットを撮る"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:81
msgid "Toggle Deinterlace"
msgstr "インターレース解除の切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:82
msgid "Change Aspect Ratio"
msgstr "アスペクト比を変更"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:83
msgid "Rotate Video"
msgstr "ビデオを回転"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:85
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:86
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:87
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:88
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:89
msgid "Audio"
msgstr "オーディオ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:85
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:446
msgid "Audio Device"
msgstr "オーディオデバイス"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:86
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:91
msgid "Next Track"
msgstr "次のトラック"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:88
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:95
msgid "Delay +0.1"
msgstr "遅延 +0.1"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:89
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:94
msgid "Delay -0.1"
msgstr "遅延 -0.1"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:91
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:92
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:93
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:94
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:95
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:96
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:97
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:98
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:99
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:100
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:101
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:102
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:103
msgid "Subtitle"
msgstr "字幕"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:92
msgid "Toggle Visibility"
msgstr "表示の切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:100
msgid "Decrease Font Size"
msgstr "フォントサイズを小さくする"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:101
msgid "Increase Font Size"
msgstr "フォントサイズを大きくする"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:103
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:127
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:128
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:129
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:130
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:131
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:132
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:133
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:134
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:135
msgid "More"
msgstr "詳細"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:103
msgid "Toggle overriding SSA/ASS styles with normal styles"
msgstr "SSA/ASS スタイルを通常のスタイルで上書きする"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:105
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:296
msgid "Track"
msgstr "トラック"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:107
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:108
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:109
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:110
msgid "Volume"
msgstr "音量"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:107
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:147
msgid "Up"
msgstr "上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:108
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:148
msgid "Down"
msgstr "下げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:110
msgid "Mute"
msgstr "ミュート"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:112
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:113
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:114
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:115
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:116
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:117
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:118
msgid "Speed"
msgstr "再生速度"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:112
msgid "-10%"
msgstr "-10%"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:113
msgid "+10%"
msgstr "+10%"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:115
msgid "Half"
msgstr "1/2"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:116
msgid "Double"
msgstr "2 倍"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:120
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:121
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:122
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:123
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:124
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:125
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:126
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:127
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:128
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:129
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:130
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:131
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:132
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:133
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:134
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:135
msgid "View"
msgstr "表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:120
msgid "Show Playlist"
msgstr "プレイリストを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:121
msgid "Show Profiles"
msgstr "プロファイルを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:122
msgid "Toggle Statistics"
msgstr "統計情報の切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:123
msgid "Toggle OSC Visibility"
msgstr "OSC 表示の切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:124
msgid "Show Media Info On-Screen"
msgstr "画面上にメディア情報を表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:125
msgid "Show Media Info Message Box"
msgstr "メディア情報メッセージボックスを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:126
msgid "Show Progress"
msgstr "進行状況を表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:127
msgid "Show Console"
msgstr "コンソールを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:128
msgid "Show Audio Devices"
msgstr "オーディオデバイスを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:129
msgid "Show Commands"
msgstr "コマンドを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:130
msgid "Show Bindings"
msgstr "バインディングを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:131
msgid "Show Properties"
msgstr "プロパティを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:132
msgid "Show Keys"
msgstr "キーを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:133
msgid "Show Protocols"
msgstr "プロトコルを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:134
msgid "Show Decoders"
msgstr "デコーダを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:135
msgid "Show Demuxers"
msgstr "デマルチプレクサを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:137
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:138
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:139
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:140
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:141
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:142
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:143
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:144
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:145
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:146
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:147
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:148
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:149
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:150
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:151
msgid "Window"
msgstr "ウィンドウ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:137
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:207
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:208
msgid "Fullscreen"
msgstr "フルスクリーン"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:138
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:139
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:140
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:141
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:142
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:143
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:144
msgid "Zoom"
msgstr "ズーム"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:138
msgid "Enlarge"
msgstr "拡大"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:139
msgid "Shrink"
msgstr "縮小"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:141
msgid "50 %"
msgstr "50 %"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:142
msgid "100 %"
msgstr "100 %"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:143
msgid "200 %"
msgstr "200 %"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:144
msgid "300 %"
msgstr "300 %"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:145
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:146
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:147
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:148
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:149
msgid "Move"
msgstr "移動"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:145
msgid "Left"
msgstr "左"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:146
msgid "Right"
msgstr "右"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:149
msgid "Center"
msgstr "中央"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:150
msgid "Toggle Border"
msgstr "ボーダーの切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:151
msgid "Toggle On Top"
msgstr "常に手前に表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:153
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:427
msgid "Profile"
msgstr "プロファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:155
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:156
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:157
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:158
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:159
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:160
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:161
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:162
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:163
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:164
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:165
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:166
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:167
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:168
msgid "Settings"
msgstr "設定"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:155
msgid "Show Config Editor"
msgstr "構成エディターを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:156
msgid "Show Input Editor"
msgstr "入力エディターを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:158
msgid "Edit mpv.conf"
msgstr "mpv.conf の編集"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:159
msgid "Edit input.conf"
msgstr "input.conf の編集"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:161
msgid "Open Config Folder"
msgstr "構成フォルダを開く"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:162
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:163
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:164
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:165
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:166
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:167
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:168
msgid "Setup"
msgstr "セットアップ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:162
msgid "Register video file associations"
msgstr "ビデオファイルの関連付けを登録"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:163
msgid "Register audio file associations"
msgstr "オーディオファイルの関連付けを登録"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:164
msgid "Register image file associations"
msgstr "画像ファイルの関連付けを登録"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:165
msgid "Unregister file associations"
msgstr "ファイルの関連付けの登録解除"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:167
msgid "Add mpv.net to Path environment variable"
msgstr "mpv.net を Path 環境変数に追加"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:168
msgid "Remove mpv.net from Path environment variable"
msgstr "mpv.net を Path 環境変数から削除"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:170
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:171
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:172
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:173
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:174
msgid "Tools"
msgstr "ツール"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:170
msgid "Set/clear A-B loop points"
msgstr "A-B 区間ループの設定/解除"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:171
msgid "Toggle infinite file looping"
msgstr "無限ファイルループの切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:172
msgid "Shuffle Playlist"
msgstr "プレイリストをシャッフル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:173
msgid "Toggle Hardware Decoding"
msgstr "ハードウェアデコードの切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:174
msgid "Exit Watch Later"
msgstr "後で見るから終了"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:176
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:466
msgid "Custom"
msgstr "カスタム"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:178
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:179
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:180
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:181
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:182
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:183
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:184
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:185
msgid "Help"
msgstr "ヘルプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:178
msgid "Website mpv"
msgstr "mpv ウェブサイト"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:179
msgid "Website mpv.net"
msgstr "mpv.net ウェブサイト"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:181
msgid "Manual mpv"
msgstr "mpv マニュアル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:182
msgid "Manual mpv.net"
msgstr "mpv.net マニュアル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:184
msgid "awesome-mpv"
msgstr "awesome-mpv"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:185
msgid "About mpv.net"
msgstr "mpv.net のバージョン情報"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:188
msgid "Show Menu"
msgstr "メニューを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:194
msgid "Forward"
msgstr ""
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:195
msgid "Backward"
msgstr ""
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:196
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:198
msgid "Volume Up"
msgstr "音量を上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:197
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:199
msgid "Volume Down"
msgstr "音量を下げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:206
msgid "Ignore left mouse butten"
msgstr "マウスの左ボタンを無視"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:209
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:211
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:217
msgid "Seek Forward"
msgstr "前方にシーク"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:210
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:212
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:218
msgid "Seek Backward"
msgstr "後方にシーク"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:213
msgid "Undo previous (or marked) seek"
msgstr ""
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:214
msgid "Mark position for revert-seek"
msgstr ""
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:215
msgid "Seek to previous subtitle"
msgstr "前の字幕にシーク"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:216
msgid "Seek to next subtitle"
msgstr "次の字幕にシーク"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:189
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:209
msgid "Files/URLs were added to the playlist"
msgstr "ファイル/URL がプレイリストに追加されました"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:202
msgid "The clipboard does not contain a valid URL or file."
msgstr "クリップボードに有効な URL またはファイルが含まれていません。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:253
msgid "File Explorer icons will refresh after process restart."
msgstr "ファイルエクスプローラーのアイコンは、プロセスの再起動後に更新されます。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:256
msgid "File associations were successfully removed."
msgstr "ファイルの関連付けは正常に削除されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:258
msgid "File associations were successfully created."
msgstr "ファイルの関連付けが正常に作成されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:261
msgid "Error creating file associations."
msgstr "ファイルの関連付けの作成中にエラーが発生しました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:358
msgid "mpv.net is already in the Path environment variable."
msgstr "mpv.net は既に Path 環境変数にあります。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:366
msgid "mpv.net was successfully added to the Path environment variable."
msgstr "mpv.net が Path 環境変数に正常に追加されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:375
msgid "mpv.net was not found in the Path environment variable."
msgstr "mpv.net が Path 環境変数に見つかりませんでした。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:384
msgid "mpv.net was successfully removed from the Path environment variable."
msgstr "mpv.net は Path 環境変数から正常に削除されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:389
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:396
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:404
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:411
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:416
msgid "This feature was removed, but there are user scripts:"
msgstr "この機能は削除されましたが、ユーザースクリプトがあります:"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:420
msgid "This feature was removed."
msgstr "この機能は削除されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\Properties\Resources.Designer.cs:79
msgid "editor_conf"
msgstr ""
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\Properties\Resources.Designer.cs:114
msgid "theme"
msgstr "テーマ"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:1398
msgid "Shutdown thread failed to complete within 10 seconds."
msgstr "シャットダウン スレッドが 10 秒以内に完了しませんでした。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\InputWindow.xaml.cs:116
msgid "Changes will be available on next startup."
msgstr "変更は次回の起動時に利用可能になります。"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
$ErrorActionPreference = 'Stop'
# Write list of .cs files into cs-files.txt file # Write list of .cs files into cs-files.txt file
Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' | Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' |
Where-Object { $_ -notmatch '[/\\]obj[/\\]' } | Where-Object { $_ -notmatch '[/\\]obj[/\\]' } |
@@ -7,6 +9,7 @@ Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' |
# Create .pot file # Create .pot file
xgettext --force-po --from-code=UTF-8 '--language=c#' -o $PSScriptRoot/source.pot --files-from=$PSScriptRoot/cs-files.txt --keyword=_ xgettext --force-po --from-code=UTF-8 '--language=c#' -o $PSScriptRoot/source.pot --files-from=$PSScriptRoot/cs-files.txt --keyword=_
if ($LastExitCode) { throw $LastExitCode }
# Backup .po files # Backup .po files
$BackupTargetFolder = $env:TEMP + '/mpv.net po backup ' + (Get-Date -Format 'yyyy-MM-dd HH_mm_ss') $BackupTargetFolder = $env:TEMP + '/mpv.net po backup ' + (Get-Date -Format 'yyyy-MM-dd HH_mm_ss')
@@ -16,3 +19,5 @@ Copy-Item $PSScriptRoot/po $BackupTargetFolder -Force -Recurse
# Update .po files # Update .po files
(Get-ChildItem $PSScriptRoot/PO -Filter '*.po').FullName | (Get-ChildItem $PSScriptRoot/PO -Filter '*.po').FullName |
ForEach-Object { msgmerge --sort-output --backup=none --update $_ $PSScriptRoot/source.pot } ForEach-Object { msgmerge --sort-output --backup=none --update $_ $PSScriptRoot/source.pot }
if ($LastExitCode) { throw $LastExitCode }

View File

@@ -23,3 +23,12 @@ dotnet_diagnostic.IDE0044.severity = silent
# Member does not access instance data and can be marked as static # Member does not access instance data and can be marked as static
dotnet_diagnostic.CA1822.severity = none dotnet_diagnostic.CA1822.severity = none
# IDE0057: Use range operator
csharp_style_prefer_range_operator = false
# CA1401: P/Invokes should not be visible
dotnet_diagnostic.CA1401.severity = none
# IDE0017: Simplify object initialization
dotnet_style_object_initializer = false

View File

@@ -53,6 +53,7 @@ public class Conf
if (section.HasName("help")) baseSetting.Help = section.GetValue("help"); if (section.HasName("help")) baseSetting.Help = section.GetValue("help");
if (section.HasName("url")) baseSetting.URL = section.GetValue("url"); if (section.HasName("url")) baseSetting.URL = section.GetValue("url");
if (section.HasName("width")) baseSetting.Width = Convert.ToInt32(section.GetValue("width")); if (section.HasName("width")) baseSetting.Width = Convert.ToInt32(section.GetValue("width"));
if (section.HasName("option-name-width")) baseSetting.OptionNameWidth = Convert.ToInt32(section.GetValue("option-name-width"));
if (section.HasName("type")) baseSetting.Type = section.GetValue("type"); if (section.HasName("type")) baseSetting.Type = section.GetValue("type");
if (baseSetting.Help.ContainsEx("\\n")) if (baseSetting.Help.ContainsEx("\\n"))
@@ -90,6 +91,9 @@ public class ConfParser
{ {
string line = it.Trim(); string line = it.Trim();
if (line.StartsWith('#'))
continue;
if (line == "") if (line == "")
{ {
currentGroup = new ConfSection(); currentGroup = new ConfSection();

View File

@@ -1,5 +1,6 @@
 
using System.Text; using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Globalization; using System.Globalization;
using System.Windows.Forms; using System.Windows.Forms;
@@ -11,6 +12,9 @@ using MpvNet.Windows.WinForms;
using MpvNet.Windows.WPF.Views; using MpvNet.Windows.WPF.Views;
using MpvNet.Windows.WPF; using MpvNet.Windows.WPF;
using MpvNet.Windows.WPF.MsgBox; using MpvNet.Windows.WPF.MsgBox;
using MpvNet.Windows.Help;
using MpvNet.Help;
using System;
namespace MpvNet; namespace MpvNet;
@@ -27,41 +31,53 @@ public class GuiCommand
public Dictionary<string, Action<IList<string>>> Commands => _commands ??= new() public Dictionary<string, Action<IList<string>>> Commands => _commands ??= new()
{ {
["show-about"] = args => ShowDialog(typeof(AboutWindow)), ["add-to-path"] = args => AddToPath(),
["show-conf-editor"] = args => ShowDialog(typeof(ConfWindow)), ["edit-conf-file"] = EditCongFile,
["show-input-editor"] = args => ShowDialog(typeof(InputWindow)), ["load-audio"] = LoadAudio,
["show-audio-devices"] = args => Msg.ShowInfo(Player.GetPropertyOsdString("audio-device-list")),
["show-profiles"] = args => Msg.ShowInfo(Player.GetProfiles()),
["load-sub"] = LoadSubtitle, ["load-sub"] = LoadSubtitle,
["move-window"] = args => MoveWindow?.Invoke(args[0]),
["open-clipboard"] = OpenFromClipboard,
["open-files"] = OpenFiles, ["open-files"] = OpenFiles,
["open-optical-media"] = Open_DVD_Or_BD_Folder, ["open-optical-media"] = Open_DVD_Or_BD_Folder,
["load-audio"] = LoadAudio,
["open-clipboard"] = OpenFromClipboard,
["reg-file-assoc"] = RegisterFileAssociations, ["reg-file-assoc"] = RegisterFileAssociations,
["remove-from-path"] = args => RemoveFromPath(),
["scale-window"] = args => ScaleWindow?.Invoke(float.Parse(args[0], CultureInfo.InvariantCulture)), ["scale-window"] = args => ScaleWindow?.Invoke(float.Parse(args[0], CultureInfo.InvariantCulture)),
["show-media-info"] = ShowMediaInfo, ["show-about"] = args => ShowDialog(typeof(AboutWindow)),
["move-window"] = args => MoveWindow?.Invoke(args[0]), ["show-audio-devices"] = args => Msg.ShowInfo(Player.GetPropertyOsdString("audio-device-list")),
["window-scale"] = args => WindowScaleNet?.Invoke(float.Parse(args[0], CultureInfo.InvariantCulture)),
["show-menu"] = args => ShowMenu?.Invoke(),
["show-bindings"] = args => ShowBindings(), ["show-bindings"] = args => ShowBindings(),
["show-playlist"] = args => ShowPlaylist(), ["show-commands"] = args => ShowCommands(),
["show-conf-editor"] = args => ShowDialog(typeof(ConfWindow)),
["show-decoders"] = args => ShowDecoders(),
["show-demuxers"] = args => ShowDemuxers(),
["show-info"] = args => ShowMediaInfo(new[] { "osd" }),
["show-input-editor"] = args => ShowDialog(typeof(InputWindow)),
["show-keys"] = args => ShowKeys(),
["show-media-info"] = ShowMediaInfo,
["show-menu"] = args => ShowMenu?.Invoke(),
["show-profiles"] = args => Msg.ShowInfo(Player.GetProfiles()),
["show-properties"] = args => ShowProperties(),
["show-protocols"] = args => ShowProtocols(),
["window-scale"] = args => WindowScaleNet?.Invoke(float.Parse(args[0], CultureInfo.InvariantCulture)),
// deprecated // deprecated
["show-info"] = args => ShowMediaInfo(new[] { "osd" }), // deprecated ["show-recent"] = args => ShowRemoved(), // deprecated
["show-playlist"] = args => ShowPlaylist(), // deprecated
["quick-bookmark"] = args => QuickBookmark(), // deprecated ["quick-bookmark"] = args => QuickBookmark(), // deprecated
["show-history"] = args => ShowHistory(), // deprecated ["show-history"] = args => ShowHistory(), // deprecated
["show-command-palette"] = args => ShowCommandPalette(), // deprecated ["show-command-palette"] = args => ShowCommandPalette(), // deprecated
["show-audio-tracks"] = args => ShowTracks(), // deprecated
["show-subtitle-tracks"] = args => ShowTracks(), // deprecated
}; };
public void ShowDialog(Type winType) void ShowDialog(Type winType)
{ {
Window? win = Activator.CreateInstance(winType) as Window; Window? win = Activator.CreateInstance(winType) as Window;
new WindowInteropHelper(win).Owner = MainForm.Instance!.Handle; new WindowInteropHelper(win).Owner = MainForm.Instance!.Handle;
win?.ShowDialog(); win?.ShowDialog();
} }
public void LoadSubtitle(IList<string> args) void LoadSubtitle(IList<string> args)
{ {
using var dialog = new OpenFileDialog(); using var dialog = new OpenFileDialog();
string path = Player.GetPropertyString("path"); string path = Player.GetPropertyString("path");
@@ -76,7 +92,7 @@ public class GuiCommand
Player.CommandV("sub-add", filename); Player.CommandV("sub-add", filename);
} }
public void OpenFiles(IList<string> args) void OpenFiles(IList<string> args)
{ {
bool append = false; bool append = false;
@@ -90,7 +106,7 @@ public class GuiCommand
Player.LoadFiles(dialog.FileNames, true, append); Player.LoadFiles(dialog.FileNames, true, append);
} }
public void Open_DVD_Or_BD_Folder(IList<string> args) void Open_DVD_Or_BD_Folder(IList<string> args)
{ {
var dialog = new FolderBrowserDialog(); var dialog = new FolderBrowserDialog();
@@ -98,12 +114,79 @@ public class GuiCommand
Player.LoadDiskFolder(dialog.SelectedPath); Player.LoadDiskFolder(dialog.SelectedPath);
} }
public void OpenFromClipboard(IList<string> args) void EditCongFile(IList<string> args)
{ {
string file = Player.ConfigFolder + args[0];
if (File.Exists(file))
ProcessHelp.ShellExecute(WinApiHelp.GetAppPathForExtension("txt"), "\"" + file + "\"");
}
void ShowTextWithEditor(string name, string text)
{
string file = Path.Combine(Path.GetTempPath(), name + ".txt");
App.TempFiles.Add(file);
File.WriteAllText(file, BR + text.Trim() + BR);
ProcessHelp.ShellExecute(WinApiHelp.GetAppPathForExtension("txt"), "\"" + file + "\"");
}
void ShowCommands()
{
string json = Core.GetPropertyString("command-list");
var enumerator = JsonDocument.Parse(json).RootElement.EnumerateArray();
var commands = enumerator.OrderBy(it => it.GetProperty("name").GetString());
StringBuilder sb = new StringBuilder();
foreach (var cmd in commands)
{
sb.AppendLine();
sb.AppendLine(cmd.GetProperty("name").GetString());
foreach (var args in cmd.GetProperty("args").EnumerateArray())
{
string value = args.GetProperty("name").GetString() + " <" +
args.GetProperty("type").GetString()!.ToLower() + ">";
if (args.GetProperty("optional").GetBoolean())
value = "[" + value + "]";
sb.AppendLine(" " + value);
}
}
string header = BR +
"https://mpv.io/manual/master/#list-of-input-commands" + BR2 +
"https://github.com/stax76/mpv-scripts#command_palette" + BR;
ShowTextWithEditor("Input Commands", header + sb.ToString());
}
void ShowProperties() =>
ShowTextWithEditor("Properties", Core.GetPropertyString("property-list").Replace(",", BR));
void ShowKeys() =>
ShowTextWithEditor("Keys", Core.GetPropertyString("input-key-list").Replace(",", BR));
void ShowProtocols() =>
ShowTextWithEditor("Protocols", Core.GetPropertyString("protocol-list").Replace(",", BR));
void ShowDecoders() =>
ShowTextWithEditor("Decoders", Core.GetPropertyOsdString("decoder-list").Replace(",", BR));
void ShowDemuxers() =>
ShowTextWithEditor("Demuxers", Core.GetPropertyOsdString("demuxer-lavf-list").Replace(",", BR));
void OpenFromClipboard(IList<string> args)
{
bool append = args.Count == 1 && args[0] == "append";
if (System.Windows.Forms.Clipboard.ContainsFileDropList()) if (System.Windows.Forms.Clipboard.ContainsFileDropList())
{ {
string[] files = System.Windows.Forms.Clipboard.GetFileDropList().Cast<string>().ToArray(); string[] files = System.Windows.Forms.Clipboard.GetFileDropList().Cast<string>().ToArray();
Player.LoadFiles(files, false, false); Player.LoadFiles(files, false, append);
if (append)
Player.CommandV("show-text", _("Files/URLs were added to the playlist"));
} }
else else
{ {
@@ -116,15 +199,18 @@ public class GuiCommand
if (files.Count == 0) if (files.Count == 0)
{ {
Terminal.WriteError("The clipboard does not contain a valid URL or file."); Terminal.WriteError(_("The clipboard does not contain a valid URL or file."));
return; return;
} }
Player.LoadFiles(files.ToArray(), false, false); Player.LoadFiles(files.ToArray(), false, append);
if (append)
Player.CommandV("show-text", _("Files/URLs were added to the playlist"));
} }
} }
public void LoadAudio(IList<string> args) void LoadAudio(IList<string> args)
{ {
using var dialog = new OpenFileDialog(); using var dialog = new OpenFileDialog();
string path = Player.GetPropertyString("path"); string path = Player.GetPropertyString("path");
@@ -139,7 +225,7 @@ public class GuiCommand
Player.CommandV("audio-add", i); Player.CommandV("audio-add", i);
} }
public void RegisterFileAssociations(IList<string> args) void RegisterFileAssociations(IList<string> args)
{ {
string perceivedType = args[0]; string perceivedType = args[0];
string[] extensions = Array.Empty<string>(); string[] extensions = Array.Empty<string>();
@@ -177,7 +263,7 @@ public class GuiCommand
catch { } catch { }
} }
public void ShowMediaInfo(IList<string> args) void ShowMediaInfo(IList<string> args)
{ {
if (Player.PlaylistPos == -1) if (Player.PlaylistPos == -1)
return; return;
@@ -248,7 +334,7 @@ public class GuiCommand
text = text.TrimEx(); text = text.TrimEx();
if (editor) if (editor)
Command.ShowTextWithEditor("media-info", text); ShowTextWithEditor("media-info", text);
else if (osd) else if (osd)
Command.ShowText(text.Replace("\r", ""), 5000, 16); Command.ShowText(text.Replace("\r", ""), 5000, 16);
else else
@@ -259,57 +345,80 @@ public class GuiCommand
} }
} }
public static string FormatTime(double value) => ((int)value).ToString("00"); string FormatTime(double value) => ((int)value).ToString("00");
public void ShowBindings() => Command.ShowTextWithEditor("Bindings", Player.UsedInputConfContent); void ShowBindings() => ShowTextWithEditor("Bindings", Player.UsedInputConfContent);
public void ShowPlaylist() void AddToPath()
{ {
var count = Player.GetPropertyInt("playlist-count"); string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User)!;
if (count < 1) if (path.ToLower().Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar).ToLower()))
return;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++)
{ {
string name = Player.GetPropertyString($"playlist/{i}/title"); Msg.ShowWarning(_("mpv.net is already in the Path environment variable."));
return;
if (string.IsNullOrEmpty(name))
name = Player.GetPropertyString($"playlist/{i}/filename").FileName();
sb.AppendLine(name);
} }
string header = BR + "For a playlist menu the following user scripts exist:" + BR2 + Environment.SetEnvironmentVariable("Path",
"https://github.com/stax76/mpv-scripts#command_palette" + BR + Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path,
"https://github.com/stax76/mpv-scripts#search_menu" + BR + EnvironmentVariableTarget.User);
"https://github.com/tomasklaen/uosc" + BR +
"https://github.com/jonniek/mpv-playlistmanager" + BR2;
Msg.ShowInfo(header + sb.ToString().TrimEnd()); Msg.ShowInfo(_("mpv.net was successfully added to the Path environment variable."));
}
void RemoveFromPath()
{
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User)!;
if (!path.Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar)))
{
Msg.ShowWarning(_("mpv.net was not found in the Path environment variable."));
return;
}
path = path.Replace(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar), "");
path = path.Replace(";;", ";").Trim(';');
Environment.SetEnvironmentVariable("Path", path, EnvironmentVariableTarget.User);
Msg.ShowInfo(_("mpv.net was successfully removed from the Path environment variable."));
} }
// deprecated // deprecated
public void QuickBookmark() => void ShowTracks() =>
Msg.ShowInfo("This feature was moved to a user script,\nwhich can be found here:\n\n" + Msg.ShowInfo(_("This feature was removed, but there are user scripts:") + BR2 +
"https://github.com/stax76/mpv-scripts/blob/main/misc.lua");
// deprecated
public void ShowHistory() =>
Msg.ShowInfo("This feature was moved to a user script,\nwhich can be found here:\n\n" +
"https://github.com/stax76/mpv-scripts/blob/main/history.lua");
// deprecated
public void ShowCommandPalette() =>
Msg.ShowInfo(
"This feature was removed but is still available in the form of user scripts:" + BR2 +
"https://github.com/stax76/mpv-scripts#command_palette" + BR + "https://github.com/stax76/mpv-scripts#command_palette" + BR +
"https://github.com/stax76/mpv-scripts#search_menu" + BR + "https://github.com/stax76/mpv-scripts#search_menu" + BR +
"https://github.com/tomasklaen/uosc"); "https://github.com/tomasklaen/uosc");
}
// deprecated
void ShowPlaylist() =>
Msg.ShowInfo(_("This feature was removed, but there are user scripts:") + BR2 +
"https://github.com/stax76/mpv-scripts#command_palette" + BR +
"https://github.com/stax76/mpv-scripts#search_menu" + BR +
"https://github.com/tomasklaen/uosc" + BR +
"https://github.com/jonniek/mpv-playlistmanager");
// deprecated
void ShowCommandPalette() =>
Msg.ShowInfo(_("This feature was removed, but there are user scripts:") + BR2 +
"https://github.com/stax76/mpv-scripts#command_palette" + BR +
"https://github.com/stax76/mpv-scripts#search_menu" + BR +
"https://github.com/tomasklaen/uosc");
// deprecated
void QuickBookmark() =>
Msg.ShowInfo(_("This feature was removed, but there are user scripts:") + BR2 +
"https://github.com/stax76/mpv-scripts/blob/main/misc.lua");
// deprecated
void ShowHistory() =>
Msg.ShowInfo(_("This feature was removed, but there are user scripts:") + BR2 +
"https://github.com/stax76/mpv-scripts/blob/main/history.lua");
// deprecated
void ShowRemoved() => Msg.ShowInfo(_("This feature was removed."));
}
//public void ShowCommandPalette() //public void ShowCommandPalette()

View File

@@ -0,0 +1,130 @@

using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using static MpvNet.Windows.Native.WinApi;
namespace MpvNet.Windows.Help;
public static class WinApiHelp
{
public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607
public static int GetResizeBorder(int v)
{
switch (v)
{
case 1 /* WMSZ_LEFT */ : return 3;
case 3 /* WMSZ_TOP */ : return 2;
case 2 /* WMSZ_RIGHT */ : return 3;
case 6 /* WMSZ_BOTTOM */ : return 2;
case 4 /* WMSZ_TOPLEFT */ : return 1;
case 5 /* WMSZ_TOPRIGHT */ : return 1;
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
default: return -1;
}
}
public static void AdjustWindowRect(IntPtr hwnd, ref RECT rc, int dpi)
{
uint style = (uint)GetWindowLongPtr(hwnd, -16); // GWL_STYLE
uint styleEx = (uint)GetWindowLongPtr(hwnd, -20); // GWL_EXSTYLE
if (Environment.OSVersion.Version >= WindowsTen1607)
AdjustWindowRectExForDpi(ref rc, style, false, styleEx, (uint)dpi);
else
Native.WinApi.AdjustWindowRect(ref rc, style, false);
}
public static void AddWindowBorders(IntPtr hwnd, ref RECT rc, int dpi, bool changeTop)
{
RECT win = rc;
AdjustWindowRect(hwnd, ref rc, dpi);
if (changeTop)
{
int top = rc.Top;
top -= rc.Top - win.Top;
rc = new RECT(rc.Left, top, rc.Right, rc.Bottom);
}
}
public static void SubtractWindowBorders(IntPtr hwnd, ref RECT rc, int dpi, bool changeTop)
{
RECT r = new RECT();
AddWindowBorders(hwnd, ref r, dpi, changeTop);
rc.Left -= r.Left;
rc.Top -= r.Top;
rc.Right -= r.Right;
rc.Bottom -= r.Bottom;
}
public static int GetTitleBarHeight(IntPtr hwnd, int dpi)
{
RECT rect = new RECT();
AdjustWindowRect(hwnd, ref rect, dpi);
return -rect.Top;
}
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
{
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out RECT dwmRect) &&
GetWindowRect(handle, out RECT rect))
{
int left = workingArea.Left;
int top = workingArea.Top;
int right = workingArea.Right;
int bottom = workingArea.Bottom;
left += rect.Left - dwmRect.Left;
top -= rect.Top - dwmRect.Top;
right -= dwmRect.Right - rect.Right;
bottom -= dwmRect.Bottom - rect.Bottom;
return new Rectangle(left, top, right - left, bottom - top);
}
return workingArea;
}
public static bool GetDwmWindowRect(IntPtr handle, out RECT rect)
{
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS,
out rect, (uint)Marshal.SizeOf<RECT>());
}
public static string GetAppPathForExtension(params string[] extensions)
{
foreach (string it in extensions)
{
string extension = it;
if (!extension.StartsWith("."))
extension = "." + extension;
uint c = 0U;
if (AssocQueryString(0x40, 2, extension, null, null, ref c) == 1)
{
if (c > 0L)
{
var sb = new StringBuilder((int)c);
if (0 == AssocQueryString(0x40, 2, extension, default, sb, ref c))
{
string ret = sb.ToString();
if (File.Exists(ret))
return ret;
}
}
}
}
return "";
}
}

View File

@@ -1,16 +0,0 @@

using MpvNet.ExtensionMethod;
namespace MpvNet.Windows.Help;
public class WinMpvHelp
{
public static void CopyMpvNetCom()
{
string dir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).AddSep() +
"Microsoft\\WindowsApps\\";
if (File.Exists(dir + "mpvnet.exe") && !File.Exists(dir + "mpvnet.com"))
File.Copy(Folder.Startup + "mpvnet.com", dir + "mpvnet.com");
}
}

View File

@@ -11,11 +11,19 @@
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>mpv-icon.ico</ApplicationIcon> <ApplicationIcon>mpv-icon.ico</ApplicationIcon>
<Product>mpv.net</Product> <Product>mpv.net</Product>
<AssemblyVersion>7.0.0.1</AssemblyVersion> <FileVersion>7.1.0.0</FileVersion>
<FileVersion>7.0.0.1</FileVersion> <AssemblyVersion>7.1.0.0</AssemblyVersion>
<InformationalVersion>7.1.0.0</InformationalVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Misc\**" />
<EmbeddedResource Remove="Misc\**" />
<None Remove="Misc\**" />
<Page Remove="Misc\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="mpv-icon.ico" /> <Content Include="mpv-icon.ico" />
</ItemGroup> </ItemGroup>
@@ -38,8 +46,4 @@
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" /> <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Misc\" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,13 +1,13 @@
 
using System.Drawing; using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using static HandyControl.Tools.Interop.InteropValues;
namespace MpvNet.Windows.Native; namespace MpvNet.Windows.Native;
public static class WinApi public static class WinApi
{ {
public static Version WindowsTen1607 { get; } = new Version(10, 0, 14393); // Windows 10 1607
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
public static extern bool AttachConsole(int dwProcessId); public static extern bool AttachConsole(int dwProcessId);
@@ -21,7 +21,7 @@ public static class WinApi
public static extern uint ActivateKeyboardLayout(IntPtr hkl, uint flags); public static extern uint ActivateKeyboardLayout(IntPtr hkl, uint flags);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hwnd, out Rect lpRect); public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll", CharSet = CharSet.Unicode)] [DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx( public static extern IntPtr FindWindowEx(
@@ -49,89 +49,39 @@ public static class WinApi
public static extern int GetDpiForWindow(IntPtr hwnd); public static extern int GetDpiForWindow(IntPtr hwnd);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool AdjustWindowRect(ref Rect lpRect, uint dwStyle, bool bMenu); public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool AdjustWindowRectExForDpi( public static extern bool AdjustWindowRectExForDpi(
ref Rect lpRect, uint dwStyle, bool bMenu, uint dwExStyle, uint dpi); ref RECT lpRect, uint dwStyle, bool bMenu, uint dwExStyle, uint dpi);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool SetWindowPos( public static extern bool SetWindowPos(
IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")] [DllImport("user32.dll")]
static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLongPtr(hWnd, nIndex);
else
return GetWindowLong32(hWnd, nIndex);
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, uint dwNewLong);
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
else
return SetWindowLong32(hWnd, nIndex, dwNewLong);
}
[DllImport("gdi32.dll")] [DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex); public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("shlwapi", CharSet = CharSet.Auto)]
public static extern uint AssocQueryString(
uint flags, uint str, string? pszAssoc, string? pszExtra, [Out] StringBuilder? pszOut, ref uint pcchOut);
[DllImport("dwmapi.dll")] [DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute( public static extern int DwmGetWindowAttribute(
IntPtr hwnd, uint dwAttribute, out Rect pvAttribute, uint cbAttribute); IntPtr hwnd, uint dwAttribute, out RECT pvAttribute, uint cbAttribute);
public static bool GetDwmWindowRect(IntPtr handle, out Rect rect)
{
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS,
out rect, (uint)Marshal.SizeOf<Rect>());
}
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
{
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out Rect dwmRect) &&
GetWindowRect(handle, out Rect rect))
{
int left = workingArea.Left;
int top = workingArea.Top;
int right = workingArea.Right;
int bottom = workingArea.Bottom;
left += rect.Left - dwmRect.Left;
top -= rect.Top - dwmRect.Top;
right -= dwmRect.Right - rect.Right;
bottom -= dwmRect.Bottom - rect.Bottom;
return new Rectangle(left, top, right - left, bottom - top);
}
return workingArea;
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Rect public struct RECT
{ {
public int Left; public int Left;
public int Top; public int Top;
public int Right; public int Right;
public int Bottom; public int Bottom;
public Rect(Rectangle r) public RECT(Rectangle r)
{ {
Left = r.Left; Left = r.Left;
Top = r.Top; Top = r.Top;
@@ -139,7 +89,7 @@ public static class WinApi
Bottom = r.Bottom; Bottom = r.Bottom;
} }
public Rect(int left, int top, int right, int bottom) public RECT(int left, int top, int right, int bottom)
{ {
Left = left; Left = left;
Top = top; Top = top;
@@ -152,9 +102,9 @@ public static class WinApi
public int Width => Right - Left; public int Width => Right - Left;
public int Height => Bottom - Top; public int Height => Bottom - Top;
public static Rect FromRectangle(Rectangle rect) public static RECT FromRectangle(Rectangle rect)
{ {
return new Rect(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); return new RECT(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
} }
public override string ToString() public override string ToString()
@@ -163,6 +113,20 @@ public static class WinApi
} }
} }
[StructLayout(LayoutKind.Sequential)]
public struct NCCALCSIZE_PARAMS
{
public NCCALCSIZE_PARAMS(RECT[] r, WINDOWPOS wp)
{
rgrc = r;
lppos = wp;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public RECT[] rgrc;
public WINDOWPOS lppos;
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct CopyDataStruct public struct CopyDataStruct
{ {
@@ -171,41 +135,4 @@ public static class WinApi
[MarshalAs(UnmanagedType.LPTStr)] [MarshalAs(UnmanagedType.LPTStr)]
public string lpData; public string lpData;
} }
public static int GetResizeBorder(int v)
{
switch (v)
{
case 1 /* WMSZ_LEFT */ : return 3;
case 3 /* WMSZ_TOP */ : return 2;
case 2 /* WMSZ_RIGHT */ : return 3;
case 6 /* WMSZ_BOTTOM */ : return 2;
case 4 /* WMSZ_TOPLEFT */ : return 1;
case 5 /* WMSZ_TOPRIGHT */ : return 1;
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
default: return -1;
}
}
public static void SubtractWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
{
Rect r = new Rect(0, 0, 0, 0);
AddWindowBorders(hwnd, ref r, dpi);
rc.Left -= r.Left;
rc.Top -= r.Top;
rc.Right -= r.Right;
rc.Bottom -= r.Bottom;
}
public static void AddWindowBorders(IntPtr hwnd, ref Rect rc, int dpi)
{
uint windowStyle = (uint)GetWindowLong(hwnd, -16); // GWL_STYLE
uint windowStyleEx = (uint)GetWindowLong(hwnd, -20); // GWL_EXSTYLE
if (Environment.OSVersion.Version >= WindowsTen1607)
AdjustWindowRectExForDpi(ref rc, windowStyle, false, windowStyleEx, (uint)dpi);
else
AdjustWindowRect(ref rc, windowStyle, false);
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,137 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="5664FrankSkare.mpv.net"
Publisher="CN=6A1A1E69-736C-4C77-B310-7B6D38E32617"
Version="6.0.3.0" />
<Properties>
<DisplayName>mpv.net</DisplayName>
<PublisherDisplayName>Frank Skare</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="mpv.net"
Description="mpv.net is a modern media player based on the popular mpv player."
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<uap3:Extension Category="windows.appExecutionAlias">
<uap3:AppExecutionAlias>
<desktop:ExecutionAlias Alias="MpvNet.exe" />
</uap3:AppExecutionAlias>
</uap3:Extension>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="videotypes">
<uap:SupportedFileTypes>
<uap:FileType>.264</uap:FileType>
<uap:FileType>.265</uap:FileType>
<uap:FileType>.asf</uap:FileType>
<uap:FileType>.avc</uap:FileType>
<uap:FileType>.avi</uap:FileType>
<uap:FileType>.avs</uap:FileType>
<uap:FileType>.dav</uap:FileType>
<uap:FileType>.flv</uap:FileType>
<uap:FileType>.h264</uap:FileType>
<uap:FileType>.h265</uap:FileType>
<uap:FileType>.hevc</uap:FileType>
<uap:FileType>.m2t</uap:FileType>
<uap:FileType>.m2ts</uap:FileType>
<uap:FileType>.m2v</uap:FileType>
<uap:FileType>.m4v</uap:FileType>
<uap:FileType>.mkv</uap:FileType>
<uap:FileType>.mov</uap:FileType>
<uap:FileType>.mp4</uap:FileType>
<uap:FileType>.mpeg</uap:FileType>
<uap:FileType>.mpg</uap:FileType>
<uap:FileType>.mpv</uap:FileType>
<uap:FileType>.mts</uap:FileType>
<uap:FileType>.ts</uap:FileType>
<uap:FileType>.vob</uap:FileType>
<uap:FileType>.vpy</uap:FileType>
<uap:FileType>.webm</uap:FileType>
<uap:FileType>.wmv</uap:FileType>
<uap:FileType>.y4m</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="audiotypes">
<uap:SupportedFileTypes>
<uap:FileType>.aac</uap:FileType>
<uap:FileType>.ac3</uap:FileType>
<uap:FileType>.dts</uap:FileType>
<uap:FileType>.dtshd</uap:FileType>
<uap:FileType>.dtshr</uap:FileType>
<uap:FileType>.dtsma</uap:FileType>
<uap:FileType>.eac3</uap:FileType>
<uap:FileType>.flac</uap:FileType>
<uap:FileType>.m4a</uap:FileType>
<uap:FileType>.mka</uap:FileType>
<uap:FileType>.mp2</uap:FileType>
<uap:FileType>.mp3</uap:FileType>
<uap:FileType>.mpa</uap:FileType>
<uap:FileType>.mpc</uap:FileType>
<uap:FileType>.ogg</uap:FileType>
<uap:FileType>.opus</uap:FileType>
<uap:FileType>.thd</uap:FileType>
<uap:FileType>.w64</uap:FileType>
<uap:FileType>.wav</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="ytdl" />
</uap:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="rtsp" />
</uap:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="srt" />
</uap:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="srtp" />
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

View File

@@ -1,78 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>81daee3a-76ff-4494-9384-d28a651d70bb</ProjectGuid>
<TargetPlatformVersion>10.0.22000.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<EntryPointProjectUniqueName>..\mpv.net.csproj</EntryPointProjectUniqueName>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="..\bin\MediaInfo.dll">
<Link>mpv.net\MediaInfo.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\bin\Microsoft.Management.Infrastructure.dll">
<Link>mpv.net\Microsoft.Management.Infrastructure.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\bin\libmpv-2.dll">
<Link>mpv.net\libmpv-2.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\bin\mpvnet.com">
<Link>mpv.net\mpvnet.com</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Images\SplashScreen.scale-200.png" />
<Content Include="Images\LockScreenLogo.scale-200.png" />
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Images\StoreLogo.png" />
<Content Include="Images\Wide310x150Logo.scale-200.png" />
<None Include="Package.StoreAssociation.xml" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.19041.8" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\mpv.net.csproj" />
</ItemGroup>
</Project>

View File

@@ -7,7 +7,6 @@ using MpvNet.Help;
using MpvNet.Windows.UI; using MpvNet.Windows.UI;
using MpvNet.Windows.Help; using MpvNet.Windows.Help;
using MpvNet.Windows.WPF; using MpvNet.Windows.WPF;
using System.Diagnostics;
namespace MpvNet.Windows; namespace MpvNet.Windows;
@@ -42,7 +41,7 @@ static class Program
Theme.Init(); Theme.Init();
Mutex mutex = new Mutex(true, StringHelp.GetMD5Hash(App.ConfPath), out bool isFirst); Mutex mutex = new Mutex(true, StringHelp.GetMD5Hash(App.ConfPath), out bool isFirst);
if (Control.ModifierKeys.HasFlag(Keys.Shift) || if (Control.ModifierKeys == Keys.Shift ||
App.CommandLine.Contains("--process-instance=multi") || App.CommandLine.Contains("--process-instance=multi") ||
App.CommandLine.Contains("--o=")) App.CommandLine.Contains("--o="))
{ {
@@ -97,10 +96,13 @@ static class Program
return; return;
} }
if (App.CommandLine.Contains("--o=")) if (ProcessCommandLineArguments())
Environment.GetCommandLineArgs();
else if (App.CommandLine.Contains("--o="))
{ {
App.AutoLoadFolder = false; App.AutoLoadFolder = false;
Player.Init(IntPtr.Zero); Player.Init(IntPtr.Zero);
Player.ProcessCommandLineArgsPost();
Player.ProcessCommandLineFiles(); Player.ProcessCommandLineFiles();
Player.SetPropertyString("idle", "no"); Player.SetPropertyString("idle", "no");
Player.EventLoop(); Player.EventLoop();
@@ -119,4 +121,48 @@ static class Program
Terminal.WriteError(ex); Terminal.WriteError(ex);
} }
} }
static bool ProcessCommandLineArguments()
{
foreach (string arg in Environment.GetCommandLineArgs().Skip(1))
{
if (arg == "--profile=help")
{
Player.Init(IntPtr.Zero, false);
Console.WriteLine(Player.GetProfiles());
Player.Destroy();
return true;
}
else if (arg == "--vd=help" || arg == "--ad=help")
{
Player.Init(IntPtr.Zero, false);
Console.WriteLine(Player.GetDecoders());
Player.Destroy();
return true;
}
else if (arg == "--audio-device=help")
{
Player.Init(IntPtr.Zero, false);
Console.WriteLine(Player.GetPropertyOsdString("audio-device-list"));
Player.Destroy();
return true;
}
else if (arg == "--input-keylist")
{
Player.Init(IntPtr.Zero, false);
Console.WriteLine(Player.GetPropertyString("input-key-list").Replace(",", BR));
Player.Destroy();
return true;
}
else if (arg == "--version")
{
Player.Init(IntPtr.Zero, false);
Console.WriteLine(AppClass.About);
Player.Destroy();
return true;
}
}
return false;
}
} }

View File

@@ -0,0 +1,7 @@
{
"profiles": {
"MpvNet.Windows": {
"commandName": "Project"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@ public abstract class Setting
public string? Value { get; set; } public string? Value { get; set; }
public int Width { get; set; } public int Width { get; set; }
public int OptionNameWidth { get; set; } = 100;
public ConfItem? ConfItem { get; set; } public ConfItem? ConfItem { get; set; }
} }
@@ -35,12 +36,13 @@ public class OptionSettingOption
public string? Name { get; set; } public string? Name { get; set; }
public string? Help { get; set; } public string? Help { get; set; }
public int Width { get => OptionSetting!.OptionNameWidth; }
public OptionSetting? OptionSetting { get; set; } public OptionSetting? OptionSetting { get; set; }
public string? Text public string? Text
{ {
get => string.IsNullOrEmpty(_text) ? Name : _text; get => _text ?? Name;
set => _text = value; set => _text = value;
} }

View File

@@ -0,0 +1,18 @@

using System.Windows.Controls;
using System.Windows;
namespace MpvNet.Windows.WPF;
public class ComboBoxTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
ContentPresenter presenter = (ContentPresenter)container;
if (presenter.TemplatedParent is ComboBox)
return (DataTemplate)presenter.FindResource("ComboBoxCollapsedDataTemplate");
else // Templated parent is ComboBoxItem
return (DataTemplate)presenter.FindResource("ComboBoxExpandedDataTemplate");
}
}

View File

@@ -28,8 +28,8 @@
<KeyBinding Key="n" Modifiers="Ctrl" Command="{Binding ShowMpvNetSpecificSettingsCommand}"/> <KeyBinding Key="n" Modifiers="Ctrl" Command="{Binding ShowMpvNetSpecificSettingsCommand}"/>
<KeyBinding Key="F5" Command="{Binding PreviewMpvConfFileCommand}"/> <KeyBinding Key="F5" Command="{Binding PreviewMpvConfFileCommand}"/>
<KeyBinding Key="F6" Command="{Binding PreviewMpvNetConfFileCommand}"/> <KeyBinding Key="F6" Command="{Binding PreviewMpvNetConfFileCommand}"/>
<KeyBinding Key="F1" Command="{Binding ShowMpvManualCommand}"/> <KeyBinding Key="F1" Modifiers="Ctrl" Command="{Binding ShowMpvManualCommand}"/>
<KeyBinding Key="F2" Command="{Binding ShowMpvNetManualCommand}"/> <KeyBinding Key="F2" Modifiers="Ctrl" Command="{Binding ShowMpvNetManualCommand}"/>
</Window.InputBindings> </Window.InputBindings>
<Grid> <Grid>
@@ -40,7 +40,7 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="170" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@@ -48,6 +48,7 @@
x:Name="SearchControl" x:Name="SearchControl"
HintText="Find a setting (Ctrl+F)" HintText="Find a setting (Ctrl+F)"
Margin="20,20,0,10" Margin="20,20,0,10"
MaxWidth="190"
Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/> />
@@ -135,12 +136,12 @@
<Separator /> <Separator />
<MenuItem <MenuItem
Header="Show mpv manual" Header="Show mpv manual"
InputGestureText="F1" InputGestureText="Ctrl+F1"
Command="{Binding Data.ShowMpvManualCommand, Source={StaticResource BindingProxy}}" Command="{Binding Data.ShowMpvManualCommand, Source={StaticResource BindingProxy}}"
/> />
<MenuItem <MenuItem
Header="Show mpv.net manual" Header="Show mpv.net manual"
InputGestureText="F2" InputGestureText="Ctrl+F2"
Command="{Binding Data.ShowMpvNetManualCommand, Source={StaticResource BindingProxy}}" Command="{Binding Data.ShowMpvNetManualCommand, Source={StaticResource BindingProxy}}"
/> />
</ContextMenu> </ContextMenu>

View File

@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
@@ -19,13 +20,16 @@ namespace MpvNet.Windows.WPF;
public partial class ConfWindow : Window, INotifyPropertyChanged public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
List<Setting> Settings = Conf.LoadConf(Properties.Resources.editor_conf.TrimEnd()); List<Setting> _settings = Conf.LoadConf(Properties.Resources.editor_conf.TrimEnd());
List<ConfItem> ConfItems = new List<ConfItem>(); List<ConfItem> _confItems = new List<ConfItem>();
public ObservableCollection<string> FilterStrings { get; } = new(); string _initialContent;
string InitialContent; string _themeConf = GetThemeConf();
string ThemeConf = GetThemeConf();
string? _searchText; string? _searchText;
List<NodeViewModel>? _nodes; List<NodeViewModel>? _nodes;
bool _shown;
int _useSpace;
int _useNoSpace;
public event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
public ConfWindow() public ConfWindow()
@@ -34,21 +38,24 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
DataContext = this; DataContext = this;
LoadConf(Player.ConfPath); LoadConf(Player.ConfPath);
LoadConf(App.ConfPath); LoadConf(App.ConfPath);
LoadLibplaceboConf();
LoadSettings(); LoadSettings();
InitialContent = GetCompareString(); _initialContent = GetCompareString();
if (string.IsNullOrEmpty(App.Settings.ConfigEditorSearch)) if (string.IsNullOrEmpty(App.Settings.ConfigEditorSearch))
SearchControl.Text = "General:"; SearchText = "General:";
else else
SearchControl.Text = App.Settings.ConfigEditorSearch; SearchText = App.Settings.ConfigEditorSearch;
foreach (var node in Nodes) foreach (var node in Nodes)
SelectNodeFromSearchText(node); SelectNodeFromSearchText(node);
foreach (var node in Nodes) foreach (var node in Nodes)
ExpandNode(node); node.IsExpanded = true;
} }
public ObservableCollection<string> FilterStrings { get; } = new();
public Theme? Theme => Theme.Current; public Theme? Theme => Theme.Current;
public string SearchText public string SearchText
@@ -70,7 +77,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
var rootNode = new TreeNode(); var rootNode = new TreeNode();
foreach (Setting setting in Settings) foreach (Setting setting in _settings)
AddNode(rootNode.Children, setting.Directory!); AddNode(rootNode.Children, setting.Directory!);
_nodes = new NodeViewModel(rootNode).Children; _nodes = new NodeViewModel(rootNode).Children;
@@ -82,6 +89,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
public static TreeNode? AddNode(IList<TreeNode> nodes, string path) public static TreeNode? AddNode(IList<TreeNode> nodes, string path)
{ {
if (string.IsNullOrEmpty(path))
return null;
string[] parts = path.Split('/', StringSplitOptions.RemoveEmptyEntries); string[] parts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
for (int x = 0; x < parts.Length; x++) for (int x = 0; x < parts.Length; x++)
@@ -120,21 +130,23 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
void LoadSettings() void LoadSettings()
{ {
foreach (Setting setting in Settings) foreach (Setting setting in _settings)
{ {
setting.StartValue = setting.Value; setting.StartValue = setting.Value;
if (!FilterStrings.Contains(setting.Directory!)) if (!FilterStrings.Contains(setting.Directory!))
FilterStrings.Add(setting.Directory!); FilterStrings.Add(setting.Directory!);
foreach (ConfItem confItem in ConfItems) foreach (ConfItem item in _confItems)
{ {
if (setting.Name == confItem.Name && confItem.Section == "" && !confItem.IsSectionItem) if (setting.Name == item.Name &&
setting.File == item.File &&
item.Section == "" && !item.IsSectionItem)
{ {
setting.Value = confItem.Value.Trim('\'', '"'); setting.Value = item.Value;
setting.StartValue = setting.Value; setting.StartValue = setting.Value;
setting.ConfItem = confItem; setting.ConfItem = item;
confItem.SettingBase = setting; item.SettingBase = setting;
} }
} }
@@ -144,7 +156,10 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
MainStackPanel.Children.Add(new StringSettingControl(s) { Visibility = Visibility.Collapsed }); MainStackPanel.Children.Add(new StringSettingControl(s) { Visibility = Visibility.Collapsed });
break; break;
case OptionSetting s: case OptionSetting s:
MainStackPanel.Children.Add(new OptionSettingControl(s) { Visibility = Visibility.Collapsed }); if (s.Options.Count > 3)
MainStackPanel.Children.Add(new ComboBoxSettingControl(s) { Visibility = Visibility.Collapsed });
else
MainStackPanel.Children.Add(new OptionSettingControl(s) { Visibility = Visibility.Collapsed });
break; break;
} }
} }
@@ -152,59 +167,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
static string GetThemeConf() => Theme.DarkMode + App.DarkTheme + App.LightTheme; static string GetThemeConf() => Theme.DarkMode + App.DarkTheme + App.LightTheme;
protected override void OnClosed(EventArgs e) string GetCompareString() => string.Join("", _settings.Select(item => item.Name + item.Value).ToArray());
{
base.OnClosed(e);
App.Settings.ConfigEditorSearch = SearchControl.Text;
if (InitialContent == GetCompareString())
return;
File.WriteAllText(Player.ConfPath, GetContent("mpv"));
File.WriteAllText(App.ConfPath, GetContent("mpvnet"));
foreach (Setting it in Settings)
{
if (it.Value != it.StartValue)
{
if (it.File == "mpv")
{
Player.ProcessProperty(it.Name, it.Value);
Player.SetPropertyString(it.Name!, it.Value!);
}
else if (it.File == "mpvnet")
App.ProcessProperty(it.Name ?? "", it.Value ?? "", true);
}
}
Theme.Init();
Theme.UpdateWpfColors();
if (ThemeConf != GetThemeConf())
MessageBox.Show("Changed theme settings require mpv.net being restarted.", "Info");
}
bool _shown;
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
if (_shown)
return;
_shown = true;
Application.Current.Dispatcher.BeginInvoke(() => {
SearchControl.SearchTextBox.SelectAll();
},
DispatcherPriority.Background);
}
string GetCompareString()
{
return string.Join("", Settings.Select(item => item.Name + item.Value).ToArray());
}
void LoadConf(string file) void LoadConf(string file)
{ {
@@ -216,31 +179,46 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
bool isSectionItem = false; bool isSectionItem = false;
foreach (string currentLine in File.ReadAllLines(file)) foreach (string it in File.ReadAllLines(file))
{ {
string line = currentLine.Trim(); string line = it.Trim();
if (line.StartsWith("-"))
line = line.TrimStart('-');
if (line == "") if (line == "")
{
comment += "\r\n"; comment += "\r\n";
}
else if (line.StartsWith("#")) else if (line.StartsWith("#"))
{
comment += line.Trim() + "\r\n"; comment += line.Trim() + "\r\n";
} else if (line.StartsWith("[") && line.Contains(']'))
else if (line.StartsWith("[") && line.Contains("]"))
{ {
if (!isSectionItem && comment != "" && comment != "\r\n") if (!isSectionItem && comment != "" && comment != "\r\n")
ConfItems.Add(new ConfItem() { _confItems.Add(new ConfItem() {
Comment = comment, File = Path.GetFileNameWithoutExtension(file)}); Comment = comment, File = Path.GetFileNameWithoutExtension(file)});
section = line.Substring(0, line.IndexOf("]") + 1); section = line.Substring(0, line.IndexOf("]") + 1);
comment = ""; comment = "";
isSectionItem = true; isSectionItem = true;
} }
else if (line.Contains("=")) else if (line.Contains('=') || Regex.Match(line, "^[\\w-]+$").Success)
{ {
ConfItem item = new ConfItem(); if (!line.Contains('='))
{
if (line.StartsWith("no-"))
{
line = line.Substring(3);
line += "=no";
}
else
line += "=yes";
}
if (line.Contains(" =") || line.Contains("= "))
_useSpace += 1;
else
_useNoSpace += 1;
ConfItem item = new();
item.File = Path.GetFileNameWithoutExtension(file); item.File = Path.GetFileNameWithoutExtension(file);
item.IsSectionItem = isSectionItem; item.IsSectionItem = isSectionItem;
item.Comment = comment; item.Comment = comment;
@@ -248,16 +226,22 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
item.Section = section; item.Section = section;
section = ""; section = "";
if (line.Contains("#") && !line.Contains("'") && !line.Contains("\"")) if (line.Contains('#') && !line.Contains('\'') && !line.Contains('"'))
{ {
item.LineComment = line.Substring(line.IndexOf("#")).Trim(); item.LineComment = line.Substring(line.IndexOf("#")).Trim();
line = line.Substring(0, line.IndexOf("#")).Trim(); line = line.Substring(0, line.IndexOf("#")).Trim();
} }
int pos = line.IndexOf("="); int pos = line.IndexOf("=");
string left = line.Substring(0, pos).Trim().ToLower(); string left = line.Substring(0, pos).Trim().ToLower().TrimStart('-');
string right = line.Substring(pos + 1).Trim(); string right = line.Substring(pos + 1).Trim();
if (right.StartsWith('\'') && right.EndsWith('\''))
right = right.Trim('\'');
if (right.StartsWith('"') && right.EndsWith('"'))
right = right.Trim('"');
if (left == "fs") if (left == "fs")
left = "fullscreen"; left = "fullscreen";
@@ -266,17 +250,79 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
item.Name = left; item.Name = left;
item.Value = right; item.Value = right;
ConfItems.Add(item); _confItems.Add(item);
} }
} }
} }
string GetKeyValueContent(string filename)
{
List<string> pairs = new();
foreach (Setting setting in _settings)
{
if (filename != setting.File)
continue;
if ((setting.Value ?? "") != setting.Default)
pairs.Add(setting.Name + "=" + EscapeValue(setting.Value!));
}
return string.Join(',', pairs);
}
void LoadLibplaceboConf()
{
foreach (ConfItem item in _confItems.ToArray())
if (item.Name == "libplacebo-opts")
LoadKeyValueList(item.Value, "libplacebo");
}
void LoadKeyValueList(string options, string file)
{
string[] optionStrings = options.Split(",", StringSplitOptions.RemoveEmptyEntries);
foreach (string pair in optionStrings)
{
if (!pair.Contains('='))
continue;
int pos = pair.IndexOf("=");
string left = pair.Substring(0, pos).Trim().ToLower();
string right = pair.Substring(pos + 1).Trim();
ConfItem item = new();
item.Name = left;
item.Value = right;
item.File = file;
_confItems.Add(item);
}
}
string EscapeValue(string value)
{
if (value.Contains('\''))
return '"' + value + '"';
if (value.Contains('"'))
return '\'' + value + '\'';
if (value.Contains('"') || value.Contains('#') || value.StartsWith("%") ||
value.StartsWith(" ") || value.EndsWith(" "))
{
return '\'' + value + '\'';
}
return value;
}
string GetContent(string filename) string GetContent(string filename)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
List<string> namesWritten = new List<string>(); List<string> namesWritten = new List<string>();
string equalString = _useSpace > _useNoSpace ? " = " : "=";
foreach (ConfItem item in ConfItems) foreach (ConfItem item in _confItems)
{ {
if (filename != item.File || item.Section != "" || item.IsSectionItem) if (filename != item.File || item.Section != "" || item.IsSectionItem)
continue; continue;
@@ -288,7 +334,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{ {
if (item.Name != "") if (item.Name != "")
{ {
sb.Append(item.Name + " = " + item.Value); sb.Append(item.Name + equalString + EscapeValue(item.Value));
if (item.LineComment != "") if (item.LineComment != "")
sb.Append(" " + item.LineComment); sb.Append(" " + item.LineComment);
@@ -299,17 +345,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
} }
else if ((item.SettingBase.Value ?? "") != item.SettingBase.Default) else if ((item.SettingBase.Value ?? "") != item.SettingBase.Default)
{ {
string? value; sb.Append(item.Name + equalString + EscapeValue(item.SettingBase.Value!));
if (item.SettingBase.Type == "string" ||
item.SettingBase.Type == "folder" ||
item.SettingBase.Type == "color")
value = "'" + item.SettingBase.Value + "'";
else
value = item.SettingBase.Value;
sb.Append(item.Name + " = " + value);
if (item.LineComment != "") if (item.LineComment != "")
sb.Append(" " + item.LineComment); sb.Append(" " + item.LineComment);
@@ -319,31 +355,16 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
} }
} }
if (!sb.ToString().Contains("# Editor")) foreach (Setting setting in _settings)
sb.AppendLine("# Editor");
foreach (Setting setting in Settings)
{ {
if (filename != setting.File || namesWritten.Contains(setting.Name!)) if (filename != setting.File || namesWritten.Contains(setting.Name!))
continue; continue;
if ((setting.Value ?? "") != setting.Default) if ((setting.Value ?? "") != setting.Default)
{ sb.AppendLine(setting.Name + equalString + EscapeValue(setting.Value!));
string? value;
if (setting.Type == "string" ||
setting.Type == "folder" ||
setting.Type == "color")
value = "'" + setting.Value + "'";
else
value = setting.Value;
sb.AppendLine(setting.Name + " = " + value);
}
} }
foreach (ConfItem item in ConfItems) foreach (ConfItem item in _confItems)
{ {
if (filename != item.File || (item.Section == "" && !item.IsSectionItem)) if (filename != item.File || (item.Section == "" && !item.IsSectionItem))
continue; continue;
@@ -359,7 +380,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
if (item.Comment != "") if (item.Comment != "")
sb.Append(item.Comment); sb.Append(item.Comment);
sb.Append(item.Name + " = " + item.Value); sb.Append(item.Name + equalString + EscapeValue(item.Value));
if (item.LineComment != "") if (item.LineComment != "")
sb.Append(" " + item.LineComment); sb.Append(" " + item.LineComment);
@@ -409,6 +430,47 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
i.Update(); i.Update();
} }
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
App.Settings.ConfigEditorSearch = SearchText;
if (_initialContent == GetCompareString())
return;
foreach (Setting setting in _settings)
{
if (setting.Name == "libplacebo-opts")
{
setting.Value = GetKeyValueContent("libplacebo");
break;
}
}
File.WriteAllText(Player.ConfPath, GetContent("mpv"));
File.WriteAllText(App.ConfPath, GetContent("mpvnet"));
foreach (Setting it in _settings)
{
if (it.Value != it.StartValue)
{
if (it.File == "mpv")
{
Player.ProcessProperty(it.Name, it.Value);
Player.SetPropertyString(it.Name!, it.Value!);
}
else if (it.File == "mpvnet")
App.ProcessProperty(it.Name ?? "", it.Value ?? "", true);
}
}
Theme.Init();
Theme.UpdateWpfColors();
if (_themeConf != GetThemeConf())
MessageBox.Show("Changed theme settings require mpv.net being restarted.", "Info");
}
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
base.OnKeyDown(e); base.OnKeyDown(e);
@@ -423,9 +485,22 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
} }
} }
protected void OnPropertyChanged([CallerMemberName] string? name = null) protected void OnPropertyChanged([CallerMemberName] string? name = null) =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
if (_shown)
return;
_shown = true;
Application.Current.Dispatcher.BeginInvoke(() => {
SearchControl.SearchTextBox.SelectAll();
},
DispatcherPriority.Background);
} }
void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
@@ -443,9 +518,10 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
void SelectNodeFromSearchText(NodeViewModel node) void SelectNodeFromSearchText(NodeViewModel node)
{ {
if (node.Path + ":" == SearchControl.Text) if (node.Path + ":" == SearchText)
{ {
node.IsSelected = true; node.IsSelected = true;
node.IsExpanded = true;
return; return;
} }
@@ -462,15 +538,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
UnselectNode(it); UnselectNode(it);
} }
void ExpandNode(NodeViewModel node) [RelayCommand] void ShowMpvNetSpecificSettings() => SearchText = "mpv.net";
{
node.IsExpanded = true;
foreach (var it in node.Children)
ExpandNode(it);
}
[RelayCommand] void ShowMpvNetSpecificSettings() => SearchControl.Text = "mpv.net";
[RelayCommand] void PreviewMpvConfFile() => Msg.ShowInfo(GetContent("mpv")); [RelayCommand] void PreviewMpvConfFile() => Msg.ShowInfo(GetContent("mpv"));

View File

@@ -0,0 +1,72 @@
<UserControl
x:Name="ComboBoxSettingControl1"
x:Class="MpvNet.Windows.WPF.ComboBoxSettingControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MpvNet.Windows.WPF"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800">
<Grid Margin="20,0">
<StackPanel>
<TextBox
x:Name="TitleTextBox"
FontSize="24"
Margin="0,10"
BorderThickness="0"
IsReadOnly="True"
Foreground="{Binding Theme.Heading}"
Background="{Binding Theme.Background}"
/>
<ComboBox
Name="ComboBoxControl"
Width="200"
HorizontalAlignment="Left"
MaxDropDownHeight="2000"
Foreground="{Binding Theme.Foreground}"
Background="{Binding Theme.Background}"
SelectionChanged="ComboBoxControl_SelectionChanged"
>
<ComboBox.ItemTemplateSelector>
<local:ComboBoxTemplateSelector/>
</ComboBox.ItemTemplateSelector>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="3"/>
</Style>
</Style.Resources>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<TextBox
x:Name="HelpTextBox"
TextWrapping="WrapWithOverflow"
BorderThickness="0"
IsReadOnly="True"
Margin="0,10,0,0"
Foreground="{Binding Theme.Foreground}"
Background="{Binding Theme.Background}"
/>
<TextBlock
x:Name="LinkTextBlock"
Margin="2,0"
>
<local:HyperlinkEx
x:Name="Link"
Foreground="{Binding Theme.Heading}"
/>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,69 @@

using System.Windows;
using System.Windows.Controls;
using MpvNet.Windows.UI;
namespace MpvNet.Windows.WPF;
public partial class ComboBoxSettingControl : UserControl, ISettingControl
{
OptionSetting OptionSetting;
public ComboBoxSettingControl(OptionSetting optionSetting)
{
OptionSetting = optionSetting;
InitializeComponent();
DataContext = this;
TitleTextBox.Text = optionSetting.Name;
if (string.IsNullOrEmpty(optionSetting.Help))
HelpTextBox.Visibility = Visibility.Collapsed;
HelpTextBox.Text = optionSetting.Help;
ComboBoxControl.ItemsSource = optionSetting.Options;
foreach (var item in optionSetting.Options)
if (item.Name == optionSetting.Value)
ComboBoxControl.SelectedItem = item;
if (string.IsNullOrEmpty(optionSetting.URL))
LinkTextBlock.Visibility = Visibility.Collapsed;
Link.SetURL(optionSetting.URL);
}
public Theme? Theme => Theme.Current;
public Setting Setting => OptionSetting;
public bool Contains(string searchString) => ContainsInternal(searchString.ToLower());
public bool ContainsInternal(string search)
{
if (TitleTextBox.Text.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
return true;
if (HelpTextBox.Text.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
return true;
foreach (var i in OptionSetting.Options)
{
if (i.Text?.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
return true;
if (i.Help?.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
return true;
if (i.Name?.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) > -1)
return true;
}
return false;
}
void ComboBoxControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
OptionSetting.Value = (ComboBoxControl.SelectedItem as OptionSettingOption)?.Name;
}
}

View File

@@ -92,7 +92,6 @@ public partial class CommandPaletteControl : UserControl
if (item.Binding != null) if (item.Binding != null)
{ {
// TODO: CommandItem.Alias
//if (item.CommandItem.Alias.ContainsEx(filter)) //if (item.CommandItem.Alias.ContainsEx(filter))
// return true; // return true;

View File

@@ -4,7 +4,6 @@ using System.Windows.Navigation;
using MpvNet.Help; using MpvNet.Help;
// TODO: change namespace to MpvNet.Windows.WPF.Controls
namespace MpvNet.Windows.WPF; namespace MpvNet.Windows.WPF;
public class HyperlinkEx : Hyperlink public class HyperlinkEx : Hyperlink
@@ -20,6 +19,6 @@ public class HyperlinkEx : Hyperlink
NavigateUri = new Uri(url); NavigateUri = new Uri(url);
RequestNavigate += HyperLinkEx_RequestNavigate; RequestNavigate += HyperLinkEx_RequestNavigate;
Inlines.Clear(); Inlines.Clear();
Inlines.Add(url); Inlines.Add("Manual");
} }
} }

View File

@@ -66,8 +66,14 @@
Background="{Binding Theme.Background}" Background="{Binding Theme.Background}"
/> />
<TextBlock x:Name="LinkTextBlock" Margin="0,10"> <TextBlock
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx> x:Name="LinkTextBlock"
Margin="2,0,0,0"
>
<local:HyperlinkEx
x:Name="Link"
Foreground="{Binding Theme.Heading}"
/>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -21,6 +21,10 @@ public partial class OptionSettingControl : UserControl, ISettingControl
HelpTextBox.Visibility = Visibility.Collapsed; HelpTextBox.Visibility = Visibility.Collapsed;
HelpTextBox.Text = optionSetting.Help; HelpTextBox.Text = optionSetting.Help;
if (string.IsNullOrEmpty(optionSetting.Help))
LinkTextBlock.Margin = new Thickness(2, 6, 0, 0);
ItemsControl.ItemsSource = optionSetting.Options; ItemsControl.ItemsSource = optionSetting.Options;
if (string.IsNullOrEmpty(optionSetting.URL)) if (string.IsNullOrEmpty(optionSetting.URL))

View File

@@ -24,7 +24,7 @@
Name="SearchTextBox" Name="SearchTextBox"
Height="25" Height="25"
BorderThickness="2" BorderThickness="2"
Padding="2" Padding="2,2,20,2"
Background="Transparent" Background="Transparent"
Foreground="{Binding Theme.Foreground}" Foreground="{Binding Theme.Foreground}"
CaretBrush="{Binding Theme.Foreground}" CaretBrush="{Binding Theme.Foreground}"

View File

@@ -39,10 +39,16 @@ public partial class SearchControl : UserControl
{ {
HintTextBlock.Text = string.IsNullOrEmpty(Text) ? HintText : ""; HintTextBlock.Text = string.IsNullOrEmpty(Text) ? HintText : "";
if (string.IsNullOrEmpty(Text) || HideClearButton) if (string.IsNullOrEmpty(Text) || HideClearButton || Text.Length > 30)
{
SearchTextBox.Padding = new Thickness(2);
SearchClearButton.Visibility = Visibility.Hidden; SearchClearButton.Visibility = Visibility.Hidden;
}
else else
{
SearchTextBox.Padding = new Thickness(2, 2, 20, 2);
SearchClearButton.Visibility = Visibility.Visible; SearchClearButton.Visibility = Visibility.Visible;
}
} }
public string Text public string Text

View File

@@ -60,8 +60,14 @@
Background="{Binding Theme.Background}" Background="{Binding Theme.Background}"
/> />
<TextBlock x:Name="LinkTextBlock" Margin="0,10"> <TextBlock
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx> x:Name="LinkTextBlock"
Margin="2,0"
>
<local:HyperlinkEx
x:Name="Link"
Foreground="{Binding Theme.Heading}"
/>
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>

View File

@@ -33,6 +33,9 @@ public partial class StringSettingControl : UserControl, ISettingControl
if (string.IsNullOrEmpty(stringSetting.URL)) if (string.IsNullOrEmpty(stringSetting.URL))
LinkTextBlock.Visibility = Visibility.Collapsed; LinkTextBlock.Visibility = Visibility.Collapsed;
if (string.IsNullOrEmpty(stringSetting.Help))
HelpTextBox.Visibility = Visibility.Collapsed;
} }
public Theme? Theme => Theme.Current; public Theme? Theme => Theme.Current;

View File

@@ -5,7 +5,7 @@ using System.Windows;
namespace HandyControl.Tools.Interop namespace HandyControl.Tools.Interop
{ {
internal class InteropValues public class InteropValues
{ {
internal static class ExternDll internal static class ExternDll
{ {
@@ -290,7 +290,7 @@ namespace HandyControl.Tools.Interop
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal class WINDOWPOS public class WINDOWPOS
{ {
public IntPtr hwnd; public IntPtr hwnd;
public IntPtr hwndInsertAfter; public IntPtr hwndInsertAfter;

View File

@@ -109,7 +109,7 @@ public partial class InputWindow : Window
else else
{ {
newContent = InputHelp.ConvertToString(InputHelp.GetReducedBindings(Bindings)); newContent = InputHelp.ConvertToString(InputHelp.GetReducedBindings(Bindings));
newContent = newContent.Replace("#menu: ", "# "); newContent = newContent.Replace(App.MenuSyntax + " ", "# ");
File.WriteAllText(App.InputConf.Path, App.InputConf.Content = newContent); File.WriteAllText(App.InputConf.Path, App.InputConf.Content = newContent);
} }

View File

@@ -122,39 +122,67 @@
<Border x:Name="stackButtons" Grid.Row="3" Padding="10" <Border x:Name="stackButtons" Grid.Row="3" Padding="10"
Background="{Binding Path=ButtonBackground}" > Background="{Binding Path=ButtonBackground}" >
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" > <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" >
<Button x:Name="btnOK" Content=" OK " MinWidth="75" Margin="5,0,5,0" <Button x:Name="btnOK"
Content=" OK "
MinWidth="75"
Margin="5,0,5,0"
Width="{Binding Path=ButtonWidth}" Width="{Binding Path=ButtonWidth}"
Height="25" Height="25"
MinHeight="25"
Visibility="{Binding Path=ShowOk}" Visibility="{Binding Path=ShowOk}"
IsDefault="{Binding Path=IsDefaultOK}" IsDefault="{Binding Path=IsDefaultOK}"
Click="BtnOK_Click" /> Click="BtnOK_Click" />
<Button x:Name="btnYes" Content=" Yes " MinWidth="75" Margin="5,0,5,0" <Button x:Name="btnYes"
Content=" Yes "
Width="{Binding Path=ButtonWidth}" Width="{Binding Path=ButtonWidth}"
MinWidth="75"
MinHeight="25"
Margin="5,0,5,0"
Visibility="{Binding Path=ShowYes}" Visibility="{Binding Path=ShowYes}"
IsDefault="{Binding Path=IsDefaultYes}" IsDefault="{Binding Path=IsDefaultYes}"
Click="BtnYes_Click"/> Click="BtnYes_Click"/>
<Button x:Name="btnNo" Content=" No " MinWidth="75" Margin="5,0,5,0" <Button x:Name="btnNo"
Content=" No "
Width="{Binding Path=ButtonWidth}" Width="{Binding Path=ButtonWidth}"
MinWidth="75"
MinHeight="25"
Margin="5,0,5,0"
Visibility="{Binding Path=ShowNo}" Visibility="{Binding Path=ShowNo}"
IsDefault="{Binding Path=IsDefaultNo}" IsDefault="{Binding Path=IsDefaultNo}"
Click="BtnNo_Click"/> Click="BtnNo_Click"/>
<Button x:Name="btnAbort" Content=" Abort " MinWidth="75" Margin="5,0,5,0" <Button x:Name="btnAbort"
Content=" Abort "
Width="{Binding Path=ButtonWidth}" Width="{Binding Path=ButtonWidth}"
MinWidth="75"
MinHeight="25"
Margin="5,0,5,0"
Visibility="{Binding Path=ShowAbort}" Visibility="{Binding Path=ShowAbort}"
IsDefault="{Binding Path=IsDefaultAbort}" IsDefault="{Binding Path=IsDefaultAbort}"
Click="BtnAbort_Click"/> Click="BtnAbort_Click"/>
<Button x:Name="btnRetry" Content=" Retry " MinWidth="75" Margin="5,0,5,0" <Button x:Name="btnRetry"
Content=" Retry "
Width="{Binding Path=ButtonWidth}" Width="{Binding Path=ButtonWidth}"
MinWidth="75"
MinHeight="25"
Margin="5,0,5,0"
Visibility="{Binding Path=ShowRetry}" Visibility="{Binding Path=ShowRetry}"
IsDefault="{Binding Path=IsDefaultRetry}" IsDefault="{Binding Path=IsDefaultRetry}"
Click="BtnRetry_Click"/> Click="BtnRetry_Click"/>
<Button x:Name="btnIgnore" Content=" Ignore " MinWidth="75" Margin="5,0,5,0" <Button x:Name="btnIgnore"
Content=" Ignore "
Width="{Binding Path=ButtonWidth}" Width="{Binding Path=ButtonWidth}"
MinWidth="75"
MinHeight="25"
Margin="5,0,5,0"
Visibility="{Binding Path=ShowIgnore}" Visibility="{Binding Path=ShowIgnore}"
IsDefault="{Binding Path=IsDefaultIgnore}" IsDefault="{Binding Path=IsDefaultIgnore}"
Click="BtnIgnore_Click"/> Click="BtnIgnore_Click"/>
<Button x:Name="btnCancel" Content=" Cancel " MinWidth="75" Margin="5,0,5,0" <Button x:Name="btnCancel"
Content=" Cancel "
Width="{Binding Path=ButtonWidth}" Width="{Binding Path=ButtonWidth}"
MinWidth="75"
MinHeight="25"
Margin="5,0,5,0"
Visibility="{Binding Path=ShowCancel}" Visibility="{Binding Path=ShowCancel}"
IsDefault="{Binding Path=IsDefaultCancel}" IsDefault="{Binding Path=IsDefaultCancel}"
Click="BtnCancel_Click"/> Click="BtnCancel_Click"/>

View File

@@ -96,13 +96,13 @@ public partial class MessageBoxEx : Window, INotifyPropertyChanged
public static void SetOwner(Window window) public static void SetOwner(Window window)
{ {
IntPtr ownerHandle = GetOwnerHandle(); IntPtr parentHandle = GetParentHandle();
if (ownerHandle != IntPtr.Zero) if (parentHandle != IntPtr.Zero)
new WindowInteropHelper(window).Owner = ownerHandle; new WindowInteropHelper(window).Owner = parentHandle;
} }
public static IntPtr GetOwnerHandle() public static IntPtr GetParentHandle()
{ {
IntPtr foregroundWindow = GetForegroundWindow(); IntPtr foregroundWindow = GetForegroundWindow();
GetWindowThreadProcessId(foregroundWindow, out var procID); GetWindowThreadProcessId(foregroundWindow, out var procID);

View File

@@ -6,6 +6,183 @@
xmlns:local="clr-namespace:MpvNet.Windows.WPF" xmlns:local="clr-namespace:MpvNet.Windows.WPF"
> >
<DataTemplate x:Key="ComboBoxCollapsedDataTemplate" >
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
<DataTemplate x:Key="ComboBoxExpandedDataTemplate" >
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
<Border>
<TextBlock
Text="{Binding Text}"
Width="{Binding Width}"
VerticalAlignment="Center"
TextWrapping="Wrap"
/>
</Border>
<Border>
<TextBlock
Text="{Binding Help}"
MaxWidth="400"
Padding="0,3"
VerticalAlignment="Center"
TextWrapping="Wrap"
/>
</Border>
</StackPanel>
</DataTemplate>
<Style x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="32" />
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
CornerRadius="3"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
/>
<Path
x:Name="Arrow"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 1,1.5 L 4.5,5 L 8,1.5"
SnapsToDevicePixels="false"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="1.5"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
<Border x:Name="PART_ContentHost" Focusable="True" />
</ControlTemplate>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Foreground" Value="#333" />
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="FontSize" Value="13" />
<Setter Property="MinWidth" Value="150"/>
<Setter Property="MinHeight" Value="25"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton
Cursor="Hand"
Name="ToggleButton"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
Style="{StaticResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"
/>
<ContentPresenter
Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="10,3,30,3"
VerticalAlignment="Center"
HorizontalAlignment="Left"
/>
<TextBox
x:Name="PART_EditableTextBox"
Style="{x:Null}"
Template="{StaticResource ComboBoxTextBox}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="3,3,23,3"
Focusable="True"
Visibility="Hidden"
IsReadOnly="{TemplateBinding IsReadOnly}"
/>
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide"
>
<Grid
Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
>
<Border
CornerRadius="3"
x:Name="DropDownBorder"
Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=Background}"
BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=Foreground}"
BorderThickness="1"
/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel
IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#FF7EB4EA"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Theme.Heading}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="local:HyperlinkEx"> <Style TargetType="local:HyperlinkEx">
<Style.Triggers> <Style.Triggers>
<Trigger Property="IsMouseOver" Value="True"> <Trigger Property="IsMouseOver" Value="True">
@@ -53,20 +230,23 @@
</Style> </Style>
<Style TargetType="TextBox"> <Style TargetType="TextBox">
<Setter Property="MinHeight" Value="25" />
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}"> <ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" <Border
BorderBrush="{DynamicResource PrimaryTextBrush}" x:Name="border"
BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{DynamicResource PrimaryTextBrush}"
Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3" Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"> CornerRadius="3"
SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" <ScrollViewer
Focusable="false" x:Name="PART_ContentHost"
HorizontalScrollBarVisibility="Hidden" Focusable="false"
VerticalScrollBarVisibility="Hidden"/> HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
</Border> </Border>
<ControlTemplate.Triggers> <ControlTemplate.Triggers>

View File

@@ -7,10 +7,13 @@ namespace MpvNet.Windows.WPF;
public class WpfTranslator : ITranslator public class WpfTranslator : ITranslator
{ {
string _localizerLangauge = "";
static Language[] Languages { get; } = new Language[] { static Language[] Languages { get; } = new Language[] {
new("english", "en", "en"), new("english", "en", "en"),
new("chinese-china", "zh-CN", "zh"), // Chinese (Simplified) new("chinese-china", "zh-CN", "zh"), // Chinese (Simplified)
new("german", "de", "de"), new("german", "de", "de"),
new("japanese", "ja", "ja"),
}; };
public string Gettext(string msgId) public string Gettext(string msgId)
@@ -21,8 +24,11 @@ public class WpfTranslator : ITranslator
void InitNGettextWpf() void InitNGettextWpf()
{ {
if (Translation.Localizer == null) if (Translation.Localizer == null || _localizerLangauge != App.Language)
{
CompositionRoot.Compose("mpvnet", GetCulture(App.Language), Folder.Startup + "Locale"); CompositionRoot.Compose("mpvnet", GetCulture(App.Language), Folder.Startup + "Locale");
_localizerLangauge = App.Language;
}
} }
string GetSystemLanguage() string GetSystemLanguage()

View File

@@ -29,36 +29,35 @@ partial class MainForm
/// </summary> /// </summary>
void InitializeComponent() void InitializeComponent()
{ {
this.components = new System.ComponentModel.Container(); components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.CursorTimer = new System.Windows.Forms.Timer(this.components); CursorTimer = new System.Windows.Forms.Timer(components);
this.ProgressTimer = new System.Windows.Forms.Timer(this.components); ProgressTimer = new System.Windows.Forms.Timer(components);
this.SuspendLayout(); SuspendLayout();
// //
// CursorTimer // CursorTimer
// //
this.CursorTimer.Enabled = true; CursorTimer.Enabled = true;
this.CursorTimer.Interval = 1000; CursorTimer.Interval = 1000;
this.CursorTimer.Tick += new System.EventHandler(this.CursorTimer_Tick); CursorTimer.Tick += CursorTimer_Tick;
// //
// ProgressTimer // ProgressTimer
// //
this.ProgressTimer.Tick += new System.EventHandler(this.ProgressTimer_Tick); ProgressTimer.Tick += ProgressTimer_Tick;
// //
// MainForm // MainForm
// //
this.AllowDrop = true; AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F); AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.Black; BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(857, 444); ClientSize = new System.Drawing.Size(1243, 720);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); Icon = (System.Drawing.Icon)resources.GetObject("$this.Icon");
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.Name = "MainForm"; Name = "MainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.ResumeLayout(false); ResumeLayout(false);
} }
#endregion #endregion

View File

@@ -6,6 +6,7 @@ using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Threading; using System.Windows.Threading;
using System.Windows.Forms.Integration; using System.Windows.Forms.Integration;
using System.Text.RegularExpressions;
using MpvNet.Windows.WPF; using MpvNet.Windows.WPF;
using MpvNet.Windows.UI; using MpvNet.Windows.UI;
@@ -18,7 +19,7 @@ using WpfControls = System.Windows.Controls;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using static MpvNet.Windows.Native.WinApi; using static MpvNet.Windows.Native.WinApi;
using MpvNet.Windows.Help; using static MpvNet.Windows.Help.WinApiHelp;
namespace MpvNet.Windows.WinForms; namespace MpvNet.Windows.WinForms;
@@ -27,7 +28,6 @@ public partial class MainForm : Form
public SnapManager SnapManager = new SnapManager(); public SnapManager SnapManager = new SnapManager();
public IntPtr MpvWindowHandle { get; set; } public IntPtr MpvWindowHandle { get; set; }
public ElementHost? CommandPaletteHost { get; set; } public ElementHost? CommandPaletteHost { get; set; }
public Dictionary<string, WpfControls.MenuItem> MenuItemDuplicate = new Dictionary<string, WpfControls.MenuItem>();
public bool WasShown { get; set; } public bool WasShown { get; set; }
public static MainForm? Instance { get; set; } public static MainForm? Instance { get; set; }
WpfControls.ContextMenu ContextMenu { get; } = new WpfControls.ContextMenu(); WpfControls.ContextMenu ContextMenu { get; } = new WpfControls.ContextMenu();
@@ -43,13 +43,13 @@ public partial class MainForm : Form
bool _contextMenuIsReady; bool _contextMenuIsReady;
bool _wasMaximized; bool _wasMaximized;
bool _maxSizeSet;
public MainForm() public MainForm()
{ {
InitializeComponent(); InitializeComponent();
if (Environment.OSVersion.Version >= new Version(10, 0, 18985) && Theme.DarkMode) UpdateDarkMode();
DwmSetWindowAttribute(Handle, 20, new[] { 1 }, 4); // DWMWA_USE_IMMERSIVE_DARK_MODE = 20
try try
{ {
@@ -68,8 +68,7 @@ public partial class MainForm : Form
GuiCommand.Current.WindowScaleNet += GuiCommand_WindowScaleNet; GuiCommand.Current.WindowScaleNet += GuiCommand_WindowScaleNet;
GuiCommand.Current.ShowMenu += GuiCommand_ShowMenu; GuiCommand.Current.ShowMenu += GuiCommand_ShowMenu;
if (Player.GPUAPI != "vulkan") Init();
Init();
_taskbarButtonCreatedMessage = RegisterWindowMessage("TaskbarButtonCreated"); _taskbarButtonCreatedMessage = RegisterWindowMessage("TaskbarButtonCreated");
@@ -126,6 +125,12 @@ public partial class MainForm : Form
} }
} }
void UpdateDarkMode()
{
if (Environment.OSVersion.Version >= new Version(10, 0, 18985))
DwmSetWindowAttribute(Handle, 20, new[] { Theme.DarkMode ? 1 : 0 }, 4); // DWMWA_USE_IMMERSIVE_DARK_MODE = 20
}
void Player_ClientMessage(string[] args) void Player_ClientMessage(string[] args)
{ {
if (Command.Current.Commands.ContainsKey(args[0])) if (Command.Current.Commands.ContainsKey(args[0]))
@@ -152,6 +157,7 @@ public partial class MainForm : Form
Player.ObservePropertyBool("fullscreen", PropChangeFullscreen); Player.ObservePropertyBool("fullscreen", PropChangeFullscreen);
Player.ObservePropertyBool("keepaspect-window", value => Player.KeepaspectWindow = value); Player.ObservePropertyBool("keepaspect-window", value => Player.KeepaspectWindow = value);
Player.ObservePropertyBool("ontop", PropChangeOnTop); Player.ObservePropertyBool("ontop", PropChangeOnTop);
Player.ObservePropertyBool("title-bar", PropChangeTitleBar);
Player.ObservePropertyString("sid", PropChangeSid); Player.ObservePropertyString("sid", PropChangeSid);
Player.ObservePropertyString("aid", PropChangeAid); Player.ObservePropertyString("aid", PropChangeAid);
@@ -163,6 +169,7 @@ public partial class MainForm : Form
Player.ObservePropertyDouble("window-scale", PropChangeWindowScale); Player.ObservePropertyDouble("window-scale", PropChangeWindowScale);
Player.ProcessCommandLineArgsPost();
Player.ProcessCommandLineFiles(); Player.ProcessCommandLineFiles();
} }
@@ -174,7 +181,7 @@ public partial class MainForm : Form
BeginInvoke(() => { BeginInvoke(() => {
SetSize( SetSize(
(int)(Player.VideoSize.Width * scale), (int)(Player.VideoSize.Width * scale),
(int)Math.Ceiling(Player.VideoSize.Height * scale), (int)Math.Floor(Player.VideoSize.Height * scale),
Screen.FromControl(this), false); Screen.FromControl(this), false);
}); });
} }
@@ -200,7 +207,7 @@ public partial class MainForm : Form
else else
{ {
w = (int)(ClientSize.Width * scale); w = (int)(ClientSize.Width * scale);
h = (int)Math.Ceiling(w * Player.VideoSize.Height / (double)Player.VideoSize.Width); h = (int)Math.Floor(w * Player.VideoSize.Height / (double)Player.VideoSize.Width);
} }
SetSize(w, h, Screen.FromControl(this), false); SetSize(w, h, Screen.FromControl(this), false);
@@ -240,7 +247,7 @@ public partial class MainForm : Form
BeginInvoke(() => { BeginInvoke(() => {
SetSize( SetSize(
(int)(Player.VideoSize.Width * scale), (int)(Player.VideoSize.Width * scale),
(int)Math.Ceiling(Player.VideoSize.Height * scale), (int)Math.Floor(Player.VideoSize.Height * scale),
Screen.FromControl(this), false); Screen.FromControl(this), false);
Player.Command($"show-text \"window-scale {scale.ToString(CultureInfo.InvariantCulture)}\""); Player.Command($"show-text \"window-scale {scale.ToString(CultureInfo.InvariantCulture)}\"");
}); });
@@ -286,7 +293,7 @@ public partial class MainForm : Form
lock (Player.MediaTracksLock) lock (Player.MediaTracksLock)
{ {
var trackMenuItem = FindMenuItem(_("Track")); var trackMenuItem = FindMenuItem(_("Track"), "Track");
if (trackMenuItem != null) if (trackMenuItem != null)
{ {
@@ -348,7 +355,7 @@ public partial class MainForm : Form
} }
} }
var chaptersMenuItem = FindMenuItem(_("Chapter")); var chaptersMenuItem = FindMenuItem(_("Chapter"), "Chapters");
if (chaptersMenuItem != null) if (chaptersMenuItem != null)
{ {
@@ -369,7 +376,7 @@ public partial class MainForm : Form
} }
} }
var recentMenuItem = FindMenuItem(_("Recent Files")); var recentMenuItem = FindMenuItem(_("Recent Files"), "Recent");
if (recentMenuItem != null) if (recentMenuItem != null)
{ {
@@ -381,17 +388,16 @@ public partial class MainForm : Form
var menuItem = MenuHelp.Add(recentMenuItem.Items, file.Title.ShortPath(100)); var menuItem = MenuHelp.Add(recentMenuItem.Items, file.Title.ShortPath(100));
if (menuItem != null) if (menuItem != null)
menuItem.Click += (sender, args) => menuItem.Click += (sender, args) => Player.LoadFiles(new[] { file.Path }, true, false);
Player.LoadFiles(new[] { file.Path }, true, false);
} }
recentMenuItem.Items.Add(new WpfControls.Separator()); recentMenuItem.Items.Add(new WpfControls.Separator());
var clearMenuItem = new WpfControls.MenuItem() { Header = "Clear List" }; var clearMenuItem = new WpfControls.MenuItem() { Header = _("Clear List") };
clearMenuItem.Click += (sender, args) => App.Settings.RecentFiles.Clear(); clearMenuItem.Click += (sender, args) => App.Settings.RecentFiles.Clear();
recentMenuItem.Items.Add(clearMenuItem); recentMenuItem.Items.Add(clearMenuItem);
} }
var titlesMenuItem = FindMenuItem(_("Title")); var titlesMenuItem = FindMenuItem(_("Title"), "Titles");
if (titlesMenuItem != null) if (titlesMenuItem != null)
{ {
@@ -424,7 +430,7 @@ public partial class MainForm : Form
} }
} }
var profilesMenuItem = FindMenuItem(_("Profile")); var profilesMenuItem = FindMenuItem(_("Profile"), "Profile");
if (profilesMenuItem != null && !profilesMenuItem.HasItems) if (profilesMenuItem != null && !profilesMenuItem.HasItems)
{ {
@@ -444,39 +450,72 @@ public partial class MainForm : Form
} }
} }
} }
profilesMenuItem.Items.Add(new WpfControls.Separator());
var showProfilesMenuItem = new WpfControls.MenuItem() { Header = _("Show Profiles") };
showProfilesMenuItem.Click += (sender, args) => Player.Command("script-message-to mpvnet show-profiles");
profilesMenuItem.Items.Add(showProfilesMenuItem);
} }
var customMenuItem = FindMenuItem(_("Custom")); var audioDevicesMenuItem = FindMenuItem(_("Audio Device"), "Audio Device");
if (customMenuItem != null) if (audioDevicesMenuItem != null)
{ {
if (!customMenuItem.HasItems) audioDevicesMenuItem.Items.Clear();
foreach (var pair in Player.AudioDevices)
{ {
var customBindings = _confBindings!.Where(it => it.IsCustomMenu); var menuItem = MenuHelp.Add(audioDevicesMenuItem.Items, pair.Value);
if (customBindings.Any()) if (menuItem != null)
{ {
foreach (Binding binding in customBindings) menuItem.IsChecked = pair.Name == Player.GetPropertyString("audio-device");
{
var menuItem = MenuHelp.Add(customMenuItem.Items, binding.Comment);
if (menuItem != null) menuItem.Click += (sender, args) =>
{ {
menuItem.Click += (sender, args) => Player.Command(binding.Command); Player.SetPropertyString("audio-device", pair.Name);
menuItem.InputGestureText = binding.Input; Player.CommandV("show-text", pair.Value);
} App.Settings.AudioDevice = pair.Name;
};
}
}
}
var customMenuItem = FindMenuItem(_("Custom"), "Custom");
if (customMenuItem != null && !customMenuItem.HasItems)
{
var customBindings = _confBindings!.Where(it => it.IsCustomMenu);
if (customBindings.Any())
{
foreach (Binding binding in customBindings)
{
var menuItem = MenuHelp.Add(customMenuItem.Items, binding.Comment);
if (menuItem != null)
{
menuItem.Click += (sender, args) => Player.Command(binding.Command);
menuItem.InputGestureText = binding.Input;
} }
} }
else }
{ else
if (ContextMenu.Items.Contains(customMenuItem)) {
ContextMenu.Items.Remove(customMenuItem); if (ContextMenu.Items.Contains(customMenuItem))
} ContextMenu.Items.Remove(customMenuItem);
} }
} }
} }
public WpfControls.MenuItem? FindMenuItem(string text) => FindMenuItem(text, ContextMenu.Items); public WpfControls.MenuItem? FindMenuItem(string text, string text2 = "") {
var ret = FindMenuItem(text, ContextMenu.Items);
if (ret == null && text2 != "")
return FindMenuItem(text2, ContextMenu.Items);
return ret;
}
WpfControls.MenuItem? FindMenuItem(string text, WpfControls.ItemCollection? items) WpfControls.MenuItem? FindMenuItem(string text, WpfControls.ItemCollection? items)
{ {
@@ -500,7 +539,7 @@ public partial class MainForm : Form
return null; return null;
} }
void SetFormPosAndSize(bool force = false, bool checkAutofit = true) void SetFormPosAndSize(bool force = false, bool checkAutofit = true, bool load = false)
{ {
if (!force) if (!force)
{ {
@@ -558,12 +597,12 @@ public partial class MainForm : Form
else if (App.StartSize == "height-always" || App.StartSize == "height-session") else if (App.StartSize == "height-always" || App.StartSize == "height-session")
{ {
height = ClientSize.Height; height = ClientSize.Height;
width = height * videoSize.Width / videoSize.Height; width = (int)Math.Ceiling(height * videoSize.Width / (double)videoSize.Height);
} }
else if (App.StartSize == "width-always" || App.StartSize == "width-session") else if (App.StartSize == "width-always" || App.StartSize == "width-session")
{ {
width = ClientSize.Width; width = ClientSize.Width;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width); height = (int)Math.Floor(width * videoSize.Height / (double)videoSize.Width);
} }
} }
else else
@@ -573,22 +612,22 @@ public partial class MainForm : Form
if (App.StartSize == "height-always" && windowSize.Height != 0) if (App.StartSize == "height-always" && windowSize.Height != 0)
{ {
height = windowSize.Height; height = windowSize.Height;
width = height * videoSize.Width / videoSize.Height; width = (int)Math.Ceiling(height * videoSize.Width / (double)videoSize.Height);
} }
else if (App.StartSize == "height-session" || App.StartSize == "session") else if (App.StartSize == "height-session" || App.StartSize == "session")
{ {
height = autoFitHeight; height = autoFitHeight;
width = height * videoSize.Width / videoSize.Height; width = (int)Math.Ceiling(height * videoSize.Width / (double)videoSize.Height);
} }
else if(App.StartSize == "width-always" && windowSize.Height != 0) else if(App.StartSize == "width-always" && windowSize.Height != 0)
{ {
width = windowSize.Width; width = windowSize.Width;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width); height = (int)Math.Floor(width * videoSize.Height / (double)videoSize.Width);
} }
else if (App.StartSize == "width-session") else if (App.StartSize == "width-session")
{ {
width = autoFitHeight / 9 * 16; width = autoFitHeight / 9 * 16;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width); height = (int)Math.Floor(width * videoSize.Height / (double)videoSize.Width);
} }
else if (App.StartSize == "always" && windowSize.Height != 0) else if (App.StartSize == "always" && windowSize.Height != 0)
{ {
@@ -599,10 +638,10 @@ public partial class MainForm : Form
Player.WasInitialSizeSet = true; Player.WasInitialSizeSet = true;
} }
SetSize(width, height, screen, checkAutofit); SetSize(width, height, screen, checkAutofit, load);
} }
void SetSize(int width, int height, Screen screen, bool checkAutofit = true) void SetSize(int width, int height, Screen screen, bool checkAutofit = true, bool load = false)
{ {
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea); Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
@@ -616,49 +655,53 @@ public partial class MainForm : Form
{ {
if (height < maxHeight * Player.AutofitSmaller) if (height < maxHeight * Player.AutofitSmaller)
{ {
height = Convert.ToInt32(maxHeight * Player.AutofitSmaller); height = (int)(maxHeight * Player.AutofitSmaller);
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
if (height > maxHeight * Player.AutofitLarger) if (height > maxHeight * Player.AutofitLarger)
{ {
height = Convert.ToInt32(maxHeight * Player.AutofitLarger); height = (int)(maxHeight * Player.AutofitLarger);
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
} }
if (width > maxWidth) if (width > maxWidth)
{ {
width = maxWidth; width = maxWidth;
height = (int)Math.Ceiling(width * startHeight / (double)startWidth); height = (int)Math.Floor(width * startHeight / (double)startWidth);
} }
if (height > maxHeight) if (height > maxHeight)
{ {
height = maxHeight; height = maxHeight;
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
if (height < maxHeight * 0.1) if (height < maxHeight * 0.1)
{ {
height = Convert.ToInt32(maxHeight * 0.1); height = (int)(maxHeight * 0.1);
width = Convert.ToInt32(height * startWidth / (double)startHeight); width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
} }
Point middlePos = new Point(Left + Width / 2, Top + Height / 2); Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var rect = new Rect(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height)); var rect = new RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
AddWindowBorders(Handle, ref rect, GetDpi(Handle));
int left = middlePos.X - rect.Width / 2; AddWindowBorders(Handle, ref rect, GetDpi(Handle), !Player.TitleBar);
int top = middlePos.Y - rect.Height / 2;
width = rect.Width;
height = rect.Height;
int left = middlePos.X - width / 2;
int top = middlePos.Y - height / 2;
Rectangle currentRect = new Rectangle(Left, Top, Width, Height); Rectangle currentRect = new Rectangle(Left, Top, Width, Height);
if (GetHorizontalLocation(screen) == -1) left = Left; if (GetHorizontalLocation(screen) == -1) left = Left;
if (GetHorizontalLocation(screen) == 1) left = currentRect.Right - rect.Width; if (GetHorizontalLocation(screen) == 1) left = currentRect.Right - width;
if (GetVerticalLocation(screen) == -1) top = Top; if (GetVerticalLocation(screen) == -1) top = Top;
if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - rect.Height; if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - height;
Screen[] screens = Screen.AllScreens; Screen[] screens = Screen.AllScreens;
@@ -667,20 +710,57 @@ public partial class MainForm : Form
int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min(); int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min();
int maxBottom = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Bottom).Max(); int maxBottom = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
if (load)
{
string geometryString = Player.GetPropertyString("geometry");
if (!string.IsNullOrEmpty(geometryString))
{
var pos = ParseGeometry(geometryString, width, height);
if (pos.X != int.MaxValue)
left = pos.X;
if (pos.Y != int.MaxValue)
top = pos.Y;
}
}
if (left < minLeft) if (left < minLeft)
left = minLeft; left = minLeft;
if (left + rect.Width > maxRight) if (left + width > maxRight)
left = maxRight - rect.Width; left = maxRight - width;
if (top < minTop) if (top < minTop)
top = minTop; top = minTop;
if (top + rect.Height > maxBottom) if (top + height > maxBottom)
top = maxBottom - rect.Height; top = maxBottom - height;
uint SWP_NOACTIVATE = 0x0010; uint SWP_NOACTIVATE = 0x0010;
SetWindowPos(Handle, IntPtr.Zero, left, top, rect.Width, rect.Height, SWP_NOACTIVATE); SetWindowPos(Handle, IntPtr.Zero, left, top, width, height, SWP_NOACTIVATE);
}
Point ParseGeometry(string input, int width, int height)
{
int x = int.MaxValue;
int y = int.MaxValue;
Match match = Regex.Match(input, @"^\+(\d+)%?\+(\d+)%?$");
if (match.Success)
{
Rectangle workingArea = GetWorkingArea(Handle, Screen.FromHandle(Handle).WorkingArea);
x = int.Parse(match.Groups[1].Value);
y = int.Parse(match.Groups[2].Value);
x = workingArea.Left + Convert.ToInt32((workingArea.Width - width) / 100.0 * x);
y = workingArea.Top + Convert.ToInt32((workingArea.Height - height) / 100.0 * y);
}
return new Point(x, y);
} }
public void CycleFullscreen(bool enabled) public void CycleFullscreen(bool enabled)
@@ -767,17 +847,12 @@ public partial class MainForm : Form
var (menuBindings, confBindings) = App.InputConf.GetBindings(); var (menuBindings, confBindings) = App.InputConf.GetBindings();
_confBindings = confBindings; _confBindings = confBindings;
var activeBindings = InputHelp.GetActiveBindings(menuBindings);
foreach (Binding binding in menuBindings) foreach (Binding binding in menuBindings)
{ {
Binding tempBinding = binding; Binding tempBinding = binding;
if (MenuItemDuplicate.ContainsKey(tempBinding.Command) && tempBinding.Input != "")
{
var mi = MenuItemDuplicate[tempBinding.Command];
mi.InputGestureText = mi.InputGestureText + ", " + tempBinding.Input;
}
if (!binding.IsMenu) if (!binding.IsMenu)
continue; continue;
@@ -785,9 +860,6 @@ public partial class MainForm : Form
if (menuItem != null) if (menuItem != null)
{ {
if (tempBinding.Input != "")
MenuItemDuplicate[tempBinding.Command] = menuItem;
menuItem.Click += (sender, args) => { menuItem.Click += (sender, args) => {
try { try {
TaskHelp.Run(() => { TaskHelp.Run(() => {
@@ -803,7 +875,7 @@ public partial class MainForm : Form
} }
}; };
menuItem.InputGestureText = tempBinding.Input; menuItem.InputGestureText = InputHelp.GetBindingsForCommand(activeBindings, tempBinding.Command);
} }
} }
@@ -839,7 +911,7 @@ public partial class MainForm : Form
path = path + "|" + title; path = path + "|" + title;
} }
if (!string.IsNullOrEmpty(path) && path != @"bd://" && path != @"dvd://") if (!string.IsNullOrEmpty(path) && path != "-" && path != @"bd://" && path != @"dvd://")
{ {
if (App.Settings.RecentFiles.Contains(path)) if (App.Settings.RecentFiles.Contains(path))
App.Settings.RecentFiles.Remove(path); App.Settings.RecentFiles.Remove(path);
@@ -972,6 +1044,9 @@ public partial class MainForm : Form
m.Result = SendMessage(MpvWindowHandle, m.Msg, m.WParam, m.LParam); m.Result = SendMessage(MpvWindowHandle, m.Msg, m.WParam, m.LParam);
} }
break; break;
case 0x001A: // WM_SETTINGCHANGE
UpdateDarkMode();
break;
case 0x51: // WM_INPUTLANGCHANGE case 0x51: // WM_INPUTLANGCHANGE
ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/); ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/);
break; break;
@@ -1011,16 +1086,45 @@ public partial class MainForm : Form
if (!WasShown) if (!WasShown)
break; break;
Rect rect = Marshal.PtrToStructure<Rect>(m.LParam); RECT rect = Marshal.PtrToStructure<RECT>(m.LParam);
SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, 0); SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, 0);
} }
break; break;
case 0x0112: // WM_SYSCOMMAND
{
// with title-bar=no when the window is restored from minimizing the height is too high
if (!Player.TitleBar)
{
int SC_MINIMIZE = 0xF020;
if (m.WParam == (nint)SC_MINIMIZE)
{
MaximumSize = Size;
_maxSizeSet = true;
}
}
}
break;
case 0x0083: // WM_NCCALCSIZE
if ((int)m.WParam == 1 && !Player.TitleBar && !IsFullscreen)
{
var nccalcsize_params = Marshal.PtrToStructure<NCCALCSIZE_PARAMS>(m.LParam);
RECT[] rects = nccalcsize_params.rgrc;
rects[0].Top = rects[0].Top - GetTitleBarHeight(Handle, GetDpi(Handle));
Marshal.StructureToPtr(nccalcsize_params, m.LParam, false);
}
break;
case 0x231: // WM_ENTERSIZEMOVE
case 0x005: // WM_SIZE
if (Player.SnapWindow)
SnapManager.OnSizeAndEnterSizeMove(this);
break;
case 0x214: // WM_SIZING case 0x214: // WM_SIZING
if (Player.KeepaspectWindow) if (Player.KeepaspectWindow)
{ {
Rect rc = Marshal.PtrToStructure<Rect>(m.LParam); RECT rc = Marshal.PtrToStructure<RECT>(m.LParam);
Rect r = rc; RECT r = rc;
SubtractWindowBorders(Handle, ref r, GetDpi(Handle)); SubtractWindowBorders(Handle, ref r, GetDpi(Handle), !Player.TitleBar);
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top; int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
Size videoSize = Player.VideoSize; Size videoSize = Player.VideoSize;
@@ -1028,9 +1132,9 @@ public partial class MainForm : Form
if (videoSize == Size.Empty) if (videoSize == Size.Empty)
videoSize = new Size(16, 9); videoSize = new Size(16, 9);
float aspect = videoSize.Width / (float)videoSize.Height; double aspect = videoSize.Width / (double)videoSize.Height;
int d_w = (int)(c_h * aspect - c_w); int d_w = (int)Math.Ceiling(c_h * aspect - c_w);
int d_h = (int)(c_w / aspect - c_h); int d_h = (int)Math.Floor(c_w / aspect - c_h);
int[] d_corners = { d_w, d_h, -d_w, -d_h }; int[] d_corners = { d_w, d_h, -d_w, -d_h };
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom }; int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
@@ -1039,37 +1143,14 @@ public partial class MainForm : Form
if (corner >= 0) if (corner >= 0)
corners[corner] -= d_corners[corner]; corners[corner] -= d_corners[corner];
Marshal.StructureToPtr(new Rect(corners[0], corners[1], corners[2], corners[3]), m.LParam, false); Marshal.StructureToPtr(new RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false);
m.Result = new IntPtr(1); m.Result = new IntPtr(1);
} }
return; return;
case 0x4A: // WM_COPYDATA
{
var copyData = (CopyDataStruct)m.GetLParam(typeof(CopyDataStruct))!;
string[] args = copyData.lpData.Split('\n');
string mode = args[0];
args = args.Skip(1).ToArray();
switch (mode)
{
case "single":
Player.LoadFiles(args, true, false);
break;
case "queue":
foreach (string file in args)
Player.CommandV("loadfile", file, "append");
break;
case "command":
Player.Command(args[0]);
break;
}
Activate();
}
return;
case 0x84: // WM_NCHITTEST case 0x84: // WM_NCHITTEST
// resize borderless window // resize borderless window
if (!Player.Border && !Player.Fullscreen) { if ((!Player.Border || !Player.TitleBar) && !Player.Fullscreen)
{
const int HTCLIENT = 1; const int HTCLIENT = 1;
const int HTLEFT = 10; const int HTLEFT = 10;
const int HTRIGHT = 11; const int HTRIGHT = 11;
@@ -1108,11 +1189,30 @@ public partial class MainForm : Form
return; return;
} }
break; break;
case 0x231: // WM_ENTERSIZEMOVE case 0x4A: // WM_COPYDATA
case 0x005: // WM_SIZE {
if (Player.SnapWindow) var copyData = (CopyDataStruct)m.GetLParam(typeof(CopyDataStruct))!;
SnapManager.OnSizeAndEnterSizeMove(this); string[] args = copyData.lpData.Split('\n');
break; string mode = args[0];
args = args.Skip(1).ToArray();
switch (mode)
{
case "single":
Player.LoadFiles(args, true, false);
break;
case "queue":
foreach (string file in args)
Player.CommandV("loadfile", file, "append");
break;
case "command":
Player.Command(args[0]);
break;
}
Activate();
}
return;
case 0x216: // WM_MOVING case 0x216: // WM_MOVING
if (Player.SnapWindow) if (Player.SnapWindow)
SnapManager.OnMoving(ref m); SnapManager.OnMoving(ref m);
@@ -1130,6 +1230,25 @@ public partial class MainForm : Form
base.WndProc(ref m); base.WndProc(ref m);
} }
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
if (_maxSizeSet)
{
TaskHelp.Run(() => {
Thread.Sleep(200);
BeginInvoke(() => {
if (!IsDisposed && !Disposing)
{
MaximumSize = new Size(int.MaxValue, int.MaxValue);
_maxSizeSet = false;
}
});
});
}
}
void CursorTimer_Tick(object sender, EventArgs e) void CursorTimer_Tick(object sender, EventArgs e)
{ {
if (IsCursorPosDifferent(_lastCursorPosition)) if (IsCursorPosDifferent(_lastCursorPosition))
@@ -1213,6 +1332,20 @@ public partial class MainForm : Form
}); });
} }
void PropChangeTitleBar(bool enabled)
{
if (enabled == Player.TitleBar)
return;
Player.TitleBar = enabled;
BeginInvoke(() => {
SetSize(ClientSize.Width, ClientSize.Height, Screen.FromControl(this), false);
Height += 1;
Height -= 1;
});
}
void Player_Pause() void Player_Pause()
{ {
if (_taskbar != null && Player.TaskbarProgress) if (_taskbar != null && Player.TaskbarProgress)
@@ -1222,10 +1355,8 @@ public partial class MainForm : Form
protected override void OnLoad(EventArgs e) protected override void OnLoad(EventArgs e)
{ {
base.OnLoad(e); base.OnLoad(e);
if (Player.GPUAPI != "vulkan")
Player.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
_lastCycleFullscreen = Environment.TickCount; _lastCycleFullscreen = Environment.TickCount;
SetFormPosAndSize(); SetFormPosAndSize(false, true, true);
} }
protected override void OnLostFocus(EventArgs e) protected override void OnLostFocus(EventArgs e)
@@ -1238,9 +1369,6 @@ public partial class MainForm : Form
{ {
base.OnShown(e); base.OnShown(e);
if (Player.GPUAPI == "vulkan")
Init();
if (WindowState == FormWindowState.Maximized) if (WindowState == FormWindowState.Maximized)
Player.SetPropertyBool("window-maximized", true); Player.SetPropertyBool("window-maximized", true);
@@ -1252,9 +1380,8 @@ public partial class MainForm : Form
InitAndBuildContextMenu(); InitAndBuildContextMenu();
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y); Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
GlobalHotkey.RegisterGlobalHotkeys(Handle); GlobalHotkey.RegisterGlobalHotkeys(Handle);
TaskHelp.Run(WinMpvHelp.CopyMpvNetCom);
WasShown = true;
StrongReferenceMessenger.Default.Send(new MainWindowIsLoadedMessage()); StrongReferenceMessenger.Default.Send(new MainWindowIsLoadedMessage());
WasShown = true;
} }
void ContextMenu_Closed(object sender, System.Windows.RoutedEventArgs e) => MenuAutoResetEvent.Set(); void ContextMenu_Closed(object sender, System.Windows.RoutedEventArgs e) => MenuAutoResetEvent.Set();
@@ -1302,11 +1429,7 @@ public partial class MainForm : Form
protected override void OnMouseDown(MouseEventArgs e) protected override void OnMouseDown(MouseEventArgs e)
{ {
base.OnMouseDown(e); base.OnMouseDown(e);
_mouseDownLocation = PointToScreen(e.Location); _mouseDownLocation = PointToScreen(e.Location);
if (Width - e.Location.X < 10 && e.Location.Y < 10)
Player.CommandV("quit");
} }
protected override void OnMouseMove(MouseEventArgs e) protected override void OnMouseMove(MouseEventArgs e)
@@ -1343,10 +1466,12 @@ public partial class MainForm : Form
{ {
base.OnDragDrop(e); base.OnDragDrop(e);
bool append = ModifierKeys == Keys.Shift;
if (e.Data!.GetDataPresent(DataFormats.FileDrop)) if (e.Data!.GetDataPresent(DataFormats.FileDrop))
Player.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as string[], true, false); Player.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as string[], true, append);
else if (e.Data.GetDataPresent(DataFormats.Text)) else if (e.Data.GetDataPresent(DataFormats.Text))
Player.LoadFiles(new[] { e.Data.GetData(DataFormats.Text)!.ToString()! }, true, false); Player.LoadFiles(new[] { e.Data.GetData(DataFormats.Text)!.ToString()! }, true, append);
} }
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)

View File

@@ -1,4 +1,64 @@
<root> <?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">

View File

@@ -2,10 +2,9 @@
using System.Drawing; using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows.Forms; using System.Windows.Forms;
using MpvNet.Windows.Help;
using MpvNet.Windows.Native; using MpvNet.Windows.Native;
using static MpvNet.Windows.Native.WinApi;
namespace MpvNet.Windows.WinForms; namespace MpvNet.Windows.WinForms;
public class SnapManager public class SnapManager
@@ -35,7 +34,7 @@ public class SnapManager
void FindSnap(ref Rectangle effectiveBounds) void FindSnap(ref Rectangle effectiveBounds)
{ {
Screen currentScreen = Screen.FromPoint(effectiveBounds.Location); Screen currentScreen = Screen.FromPoint(effectiveBounds.Location);
Rectangle workingArea = GetWorkingArea(Handle, currentScreen.WorkingArea); Rectangle workingArea = WinApiHelp.GetWorkingArea(Handle, currentScreen.WorkingArea);
if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance)) if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance))
effectiveBounds.X = workingArea.Left + AnchorDistance; effectiveBounds.X = workingArea.Left + AnchorDistance;
@@ -52,7 +51,7 @@ public class SnapManager
if (Handle == IntPtr.Zero) if (Handle == IntPtr.Zero)
return; return;
WinApi.Rect boundsLtrb = Marshal.PtrToStructure<WinApi.Rect>(m.LParam); WinApi.RECT boundsLtrb = Marshal.PtrToStructure<WinApi.RECT>(m.LParam);
Rectangle bounds = boundsLtrb.ToRectangle(); Rectangle bounds = boundsLtrb.ToRectangle();
// This is where the window _would_ be located if snapping // This is where the window _would_ be located if snapping
// had not occurred. This prevents the cursor from sliding // had not occurred. This prevents the cursor from sliding
@@ -63,7 +62,7 @@ public class SnapManager
bounds.Width, bounds.Width,
bounds.Height); bounds.Height);
FindSnap(ref effectiveBounds); FindSnap(ref effectiveBounds);
WinApi.Rect newLtrb = WinApi.Rect.FromRectangle(effectiveBounds); WinApi.RECT newLtrb = WinApi.RECT.FromRectangle(effectiveBounds);
Marshal.StructureToPtr(newLtrb, m.LParam, false); Marshal.StructureToPtr(newLtrb, m.LParam, false);
m.Result = new IntPtr(1); m.Result = new IntPtr(1);
} }

View File

@@ -20,21 +20,77 @@ EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.Build.0 = Debug|Any CPU {ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM.ActiveCfg = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM.Build.0 = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|ARM64.Build.0 = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x64.ActiveCfg = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x64.Build.0 = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x86.ActiveCfg = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Debug|x86.Build.0 = Debug|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.Build.0 = Release|Any CPU {ADC341B5-863A-4DFB-9352-475518FABE91}.Release|Any CPU.Build.0 = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM.ActiveCfg = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM.Build.0 = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM64.ActiveCfg = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|ARM64.Build.0 = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x64.ActiveCfg = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x64.Build.0 = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x86.ActiveCfg = Release|Any CPU
{ADC341B5-863A-4DFB-9352-475518FABE91}.Release|x86.Build.0 = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM.ActiveCfg = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM.Build.0 = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|ARM64.Build.0 = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x64.ActiveCfg = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x64.Build.0 = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x86.ActiveCfg = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Debug|x86.Build.0 = Debug|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.ActiveCfg = Release|Any CPU {0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.Build.0 = Release|Any CPU {0B524801-DA28-433F-808D-3F74EF81EB53}.Release|Any CPU.Build.0 = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM.ActiveCfg = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM.Build.0 = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM64.ActiveCfg = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|ARM64.Build.0 = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x64.ActiveCfg = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x64.Build.0 = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x86.ActiveCfg = Release|Any CPU
{0B524801-DA28-433F-808D-3F74EF81EB53}.Release|x86.Build.0 = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM.ActiveCfg = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM.Build.0 = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|ARM64.Build.0 = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x64.ActiveCfg = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x64.Build.0 = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x86.ActiveCfg = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Debug|x86.Build.0 = Debug|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.ActiveCfg = Release|Any CPU {0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.Build.0 = Release|Any CPU {0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|Any CPU.Build.0 = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM.ActiveCfg = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM.Build.0 = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM64.ActiveCfg = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|ARM64.Build.0 = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x64.ActiveCfg = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x64.Build.0 = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x86.ActiveCfg = Release|Any CPU
{0B7958FD-2138-482A-A21B-481AE7A0F851}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -10,7 +10,6 @@ namespace MpvNet;
public class AppClass public class AppClass
{ {
public List<string> TempFiles { get; } = new (); public List<string> TempFiles { get; } = new ();
public Dictionary<string, string> CommandLineArguments { get; } = new ();
public string ConfPath { get => Player.ConfigFolder + "mpvnet.conf"; } public string ConfPath { get => Player.ConfigFolder + "mpvnet.conf"; }
public string ProcessInstance { get; set; } = "single"; public string ProcessInstance { get; set; } = "single";
@@ -20,6 +19,7 @@ public class AppClass
public string StartSize { get; set; } = "height-session"; public string StartSize { get; set; } = "height-session";
public string Language { get; set; } = "system"; public string Language { get; set; } = "system";
public string CommandLine { get; set; } = Environment.CommandLine; public string CommandLine { get; set; } = Environment.CommandLine;
public string MenuSyntax { get; set; } = "#menu:";
public bool AutoLoadFolder { get; set; } = true; public bool AutoLoadFolder { get; set; } = true;
public bool DebugMode { get; set; } public bool DebugMode { get; set; }
@@ -27,10 +27,10 @@ public class AppClass
public bool IsTerminalAttached { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes"; public bool IsTerminalAttached { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
public bool MediaInfo { get; set; } = true; public bool MediaInfo { get; set; } = true;
public bool Queue { get; set; } public bool Queue { get; set; }
public bool RememberAudioDevice { get; set; } = true;
public bool RememberVolume { get; set; } = true; public bool RememberVolume { get; set; } = true;
public bool RememberWindowPosition { get; set; } public bool RememberWindowPosition { get; set; }
public int StartThreshold { get; set; } = 1500;
public int RecentCount { get; set; } = 15; public int RecentCount { get; set; } = 15;
public float AutofitAudio { get; set; } = 0.7f; public float AutofitAudio { get; set; } = 0.7f;
@@ -80,7 +80,7 @@ public class AppClass
public static string About => "Copyright (C) 2000-2023 mpv.net/mpv/mplayer\n" + public static string About => "Copyright (C) 2000-2023 mpv.net/mpv/mplayer\n" +
$"{AppInfo.Product} {AppInfo.Version}" + GetLastWriteTime(Environment.ProcessPath!) + "\n" + $"{AppInfo.Product} {AppInfo.Version}" + GetLastWriteTime(Environment.ProcessPath!) + "\n" +
$"{Player.GetPropertyString("mpv-version")}" + GetLastWriteTime(Folder.Startup + "libmpv-2.dll") + "\n" + $"{Player.GetPropertyString("mpv-version")}" + GetLastWriteTime(Folder.Startup + "libmpv-2.dll") + "\n" +
$"ffmpeg {Player.GetPropertyString("ffmpeg-version")}\n" + "\nGPL v2 License"; $"ffmpeg {Player.GetPropertyString("ffmpeg-version")}\n" + "GPL v2 License";
static string GetLastWriteTime(string path) static string GetLastWriteTime(string path)
{ {
@@ -99,6 +99,9 @@ public class AppClass
Player.SetPropertyInt("volume", Settings.Volume); Player.SetPropertyInt("volume", Settings.Volume);
Player.SetPropertyString("mute", Settings.Mute); Player.SetPropertyString("mute", Settings.Mute);
} }
if (RememberAudioDevice && Settings.AudioDevice != "")
Player.SetPropertyString("audio-device", Settings.AudioDevice);
} }
void Player_Shutdown() void Player_Shutdown()
@@ -145,15 +148,16 @@ public class AppClass
case "language": Language = value; return true; case "language": Language = value; return true;
case "light-theme": LightTheme = value.Trim('\'', '"'); return true; case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
case "media-info": MediaInfo = value == "yes"; return true; case "media-info": MediaInfo = value == "yes"; return true;
case "menu-syntax": MenuSyntax = value; return true;
case "minimum-aspect-ratio-audio": MinimumAspectRatioAudio = value.ToFloat(); return true; case "minimum-aspect-ratio-audio": MinimumAspectRatioAudio = value.ToFloat(); return true;
case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true; case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true;
case "process-instance": ProcessInstance = value; return true; case "process-instance": ProcessInstance = value; return true;
case "queue": Queue = value == "yes"; return true; case "queue": Queue = value == "yes"; return true;
case "recent-count": RecentCount = value.ToInt(15); return true; case "recent-count": RecentCount = value.ToInt(15); return true;
case "remember-audio-device": RememberAudioDevice = value == "yes"; return true;
case "remember-volume": RememberVolume = value == "yes"; return true; case "remember-volume": RememberVolume = value == "yes"; return true;
case "remember-window-position": RememberWindowPosition = value == "yes"; return true; case "remember-window-position": RememberWindowPosition = value == "yes"; return true;
case "start-size": StartSize = value; return true; case "start-size": StartSize = value; return true;
case "start-threshold": StartThreshold = value.ToInt(1500); return true;
case "video-file-extensions": FileTypes.Video = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true; case "video-file-extensions": FileTypes.Video = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
default: default:

View File

@@ -1,7 +1,5 @@
 
using System.Globalization; using System.Globalization;
using System.Text;
using System.Text.Json;
using MpvNet.Help; using MpvNet.Help;
namespace MpvNet; namespace MpvNet;
@@ -18,7 +16,6 @@ public class Command
["play-pause"] = PlayPause, ["play-pause"] = PlayPause,
["shell-execute"] = args => ProcessHelp.ShellExecute(args[0]), ["shell-execute"] = args => ProcessHelp.ShellExecute(args[0]),
["show-text"] = args => ShowText(args[0], Convert.ToInt32(args[1]), Convert.ToInt32(args[2])), ["show-text"] = args => ShowText(args[0], Convert.ToInt32(args[1]), Convert.ToInt32(args[2])),
["show-commands"] = args => ShowCommands(),
["cycle-audio"] = args => CycleAudio(), ["cycle-audio"] = args => CycleAudio(),
["cycle-subtitles"] = args => CycleSubtitles(), ["cycle-subtitles"] = args => CycleSubtitles(),
["playlist-first"] = args => PlaylistFirst(), ["playlist-first"] = args => PlaylistFirst(),
@@ -27,13 +24,13 @@ public class Command
// deprecated // deprecated
["playlist-add"] = args => PlaylistAdd(Convert.ToInt32(args[0])), // deprecated ["playlist-add"] = args => PlaylistAdd(Convert.ToInt32(args[0])), // deprecated
["show-progress"] = args => ShowProgress(), // deprecated ["show-progress"] = args => Player.Command("show-progress"), // deprecated
["playlist-random"] = args => PlaylistRandom(), // deprecated ["playlist-random"] = args => PlaylistRandom(), // deprecated
}; };
public string FormatTime(double value) => ((int)value).ToString("00"); string FormatTime(double value) => ((int)value).ToString("00");
public static void PlayPause(IList<string> args) void PlayPause(IList<string> args)
{ {
int count = Player.GetPropertyInt("playlist-count"); int count = Player.GetPropertyInt("playlist-count");
@@ -52,37 +49,6 @@ public class Command
} }
} }
public static void ShowCommands()
{
string json = Core.GetPropertyString("command-list");
var enumerator = JsonDocument.Parse(json).RootElement.EnumerateArray();
var commands = enumerator.OrderBy(it => it.GetProperty("name").GetString());
StringBuilder sb = new StringBuilder();
foreach (var cmd in commands)
{
sb.AppendLine();
sb.AppendLine(cmd.GetProperty("name").GetString());
foreach (var args in cmd.GetProperty("args").EnumerateArray())
{
string value = args.GetProperty("name").GetString() + " <" +
args.GetProperty("type").GetString()!.ToLower() + ">";
if (args.GetProperty("optional").GetBoolean())
value = "[" + value + "]";
sb.AppendLine(" " + value);
}
}
string header = BR +
"https://mpv.io/manual/master/#list-of-input-commands" + BR2 +
"https://github.com/stax76/mpv-scripts#command_palette" + BR;
ShowTextWithEditor("Input Commands", header + sb.ToString());
}
public static void ShowText(string text, int duration = 0, int fontSize = 0) public static void ShowText(string text, int duration = 0, int fontSize = 0)
{ {
if (string.IsNullOrEmpty(text)) if (string.IsNullOrEmpty(text))
@@ -98,15 +64,7 @@ public class Command
"}${osd-ass-cc/1}" + text + "\" " + duration); "}${osd-ass-cc/1}" + text + "\" " + duration);
} }
public static void ShowTextWithEditor(string name, string text) void CycleAudio()
{
string file = Path.Combine(Path.GetTempPath(), name + ".txt");
App.TempFiles.Add(file);
File.WriteAllText(file, BR + text.Trim() + BR);
ProcessHelp.ShellExecute(file);
}
public static void CycleAudio()
{ {
Player.UpdateExternalTracks(); Player.UpdateExternalTracks();
@@ -134,7 +92,7 @@ public class Command
} }
} }
public static void CycleSubtitles() void CycleSubtitles()
{ {
Player.UpdateExternalTracks(); Player.UpdateExternalTracks();
@@ -166,7 +124,7 @@ public class Command
} }
// deprecated // deprecated
public static void PlaylistAdd(int value) void PlaylistAdd(int value)
{ {
int pos = Player.PlaylistPos; int pos = Player.PlaylistPos;
int count = Player.GetPropertyInt("playlist-count"); int count = Player.GetPropertyInt("playlist-count");
@@ -185,13 +143,13 @@ public class Command
Player.SetPropertyInt("playlist-pos", pos); Player.SetPropertyInt("playlist-pos", pos);
} }
public static void PlaylistFirst() void PlaylistFirst()
{ {
if (Player.PlaylistPos != 0) if (Player.PlaylistPos != 0)
Player.SetPropertyInt("playlist-pos", 0); Player.SetPropertyInt("playlist-pos", 0);
} }
public static void PlaylistLast() void PlaylistLast()
{ {
int count = Player.GetPropertyInt("playlist-count"); int count = Player.GetPropertyInt("playlist-count");
@@ -200,14 +158,14 @@ public class Command
} }
// deprecated // deprecated
public static void PlaylistRandom() void PlaylistRandom()
{ {
int count = Player.GetPropertyInt("playlist-count"); int count = Player.GetPropertyInt("playlist-count");
Player.SetPropertyInt("playlist-pos", new Random().Next(count)); Player.SetPropertyInt("playlist-pos", new Random().Next(count));
} }
// deprecated // deprecated
public void ShowProgress() void ShowProgress()
{ {
TimeSpan position = TimeSpan.FromSeconds(Player.GetPropertyDouble("time-pos")); TimeSpan position = TimeSpan.FromSeconds(Player.GetPropertyDouble("time-pos"));
TimeSpan duration = TimeSpan.FromSeconds(Player.GetPropertyDouble("duration")); TimeSpan duration = TimeSpan.FromSeconds(Player.GetPropertyDouble("duration"));

73
src/MpvNet/CommandLine.cs Normal file
View File

@@ -0,0 +1,73 @@

namespace MpvNet;
public class CommandLine
{
static List<StringPair>? _arguments;
public static List<StringPair> Arguments
{
get
{
if (_arguments != null)
return _arguments;
_arguments = new();
foreach (string i in Environment.GetCommandLineArgs().Skip(1))
{
string arg = i;
if (!arg.StartsWith("--"))
continue;
if (!arg.Contains('='))
{
if (arg.Contains("--no-"))
{
arg = arg.Replace("--no-", "--");
arg += "=no";
}
else
arg += "=yes";
}
string left = arg[2..arg.IndexOf("=")];
string right = arg[(left.Length + 3)..];
if (string.IsNullOrEmpty(left))
continue;
switch (left)
{
case "script": left = "scripts"; break;
case "audio-file": left = "audio-files"; break;
case "sub-file": left = "sub-files"; break;
case "external-file": left = "external-files"; break;
}
_arguments.Add(new StringPair(left, right));
}
return _arguments;
}
}
public static bool Contains(string name)
{
foreach (StringPair pair in Arguments)
if (pair.Name == name)
return true;
return false;
}
public static string GetValue(string name)
{
foreach (StringPair pair in Arguments)
if (pair.Name == name)
return pair.Value;
return "";
}
}

View File

@@ -1,14 +1,22 @@
namespace MpvNet.Help; 
namespace MpvNet.Help;
public static class ProcessHelp public static class ProcessHelp
{ {
public static void Execute(string file, string arguments = "", bool shellExecute = false) public static void Execute(string file, string arguments = "", bool shellExecute = false)
{ {
using Process proc = new Process(); try
proc.StartInfo.FileName = file; {
proc.StartInfo.Arguments = arguments; using Process proc = new Process();
proc.StartInfo.UseShellExecute = shellExecute; proc.StartInfo.FileName = file;
proc.Start(); proc.StartInfo.Arguments = arguments;
proc.StartInfo.UseShellExecute = shellExecute;
proc.Start();
}
catch (Exception ex)
{
Terminal.WriteError(ex.ToString());
}
} }
public static void ShellExecute(string file, string arguments = "") => Execute(file, arguments, true); public static void ShellExecute(string file, string arguments = "") => Execute(file, arguments, true);

View File

@@ -1,5 +1,4 @@
 
using MpvNet.ExtensionMethod;
using MpvNet.Help; using MpvNet.Help;
namespace MpvNet; namespace MpvNet;
@@ -15,12 +14,15 @@ public class InputConf
public string Path { public string Path {
get => _path ?? ""; get => _path ?? "";
set { set {
_path = value; if (_path != value)
Content = File.Exists(_path) ? FileHelp.ReadTextFile(_path) : ""; {
_path = value;
Content = File.Exists(_path) ? FileHelp.ReadTextFile(_path) : "";
}
} }
} }
public bool HasMenu => Content.Contains("#menu:") || Content.Contains("#! "); public bool HasMenu => Content.Contains(App.MenuSyntax + " ");
public (List<Binding> menuBindings, List<Binding>? confBindings) GetBindings() public (List<Binding> menuBindings, List<Binding>? confBindings) GetBindings()
{ {
@@ -50,7 +52,29 @@ public class InputConf
public string GetContent() public string GetContent()
{ {
if (HasMenu) if (HasMenu)
{
try
{
if (App.Settings.MenuUpdateVersion != 1)
{
string updatedContent = UpdateContent(Content);
if (updatedContent != Content)
{
File.Copy(Path, Path + ".backup", true);
File.WriteAllText(Path, Content = updatedContent);
}
App.Settings.MenuUpdateVersion = 1;
}
}
catch (Exception ex)
{
Terminal.WriteError("Failed to update menu." + BR + ex.Message);
}
return Content; return Content;
}
else else
{ {
var defaults = InputHelp.GetDefaults(); var defaults = InputHelp.GetDefaults();
@@ -73,4 +97,9 @@ public class InputConf
return InputHelp.ConvertToString(defaults); return InputHelp.ConvertToString(defaults);
} }
} }
static string UpdateContent(string content) => content
.Replace("script-message mpv.net", "script-message-to mpvnet")
.Replace("/docs/Manual.md", "/docs/manual.md")
.Replace("https://github.com/stax76/mpv.net", "https://github.com/mpvnet-player/mpv.net");
} }

View File

@@ -17,8 +17,9 @@ public static class InputHelp
new (_("File"), _("Add external subtitle files..."), "script-message-to mpvnet load-sub", "Alt+s"), new (_("File"), _("Add external subtitle files..."), "script-message-to mpvnet load-sub", "Alt+s"),
new (_("File"), "-"), new (_("File"), "-"),
new (_("File"), _("Add files to playlist..."), "script-message-to mpvnet open-files append"), new (_("File"), _("Add files to playlist..."), "script-message-to mpvnet open-files append"),
new (_("File"), _("Recent Files")), new (_("File"), _("Add files/URLs to playlist from clipboard"), "script-message-to mpvnet open-clipboard append", "Ctrl+Shift+v"),
new (_("File"), "-"), new (_("File"), "-"),
new (_("File"), _("Recent Files")),
new (_("File"), _("Exit"), "quit", "Esc"), new (_("File"), _("Exit"), "quit", "Esc"),
new (_("Playback"), _("Play/Pause"), "script-message-to mpvnet play-pause", "Space"), new (_("Playback"), _("Play/Pause"), "script-message-to mpvnet play-pause", "Space"),
@@ -81,6 +82,7 @@ public static class InputHelp
new (_("Video"), _("Change Aspect Ratio"), "cycle-values video-aspect-override 16:9 4:3 2.35:1 -1", "a"), new (_("Video"), _("Change Aspect Ratio"), "cycle-values video-aspect-override 16:9 4:3 2.35:1 -1", "a"),
new (_("Video"), _("Rotate Video"), "cycle-values video-rotate 90 180 270 0", "Ctrl+r"), new (_("Video"), _("Rotate Video"), "cycle-values video-rotate 90 180 270 0", "Ctrl+r"),
new (_("Audio"), _("Audio Device")),
new (_("Audio"), _("Next Track"), "script-message-to mpvnet cycle-audio", "KP7"), new (_("Audio"), _("Next Track"), "script-message-to mpvnet cycle-audio", "KP7"),
new (_("Audio"), "-"), new (_("Audio"), "-"),
new (_("Audio"), _("Delay +0.1"), "add audio-delay 0.1", "Ctrl+d"), new (_("Audio"), _("Delay +0.1"), "add audio-delay 0.1", "Ctrl+d"),
@@ -116,7 +118,6 @@ public static class InputHelp
new (_("Speed"), _("Reset"), "set speed 1", "BS"), new (_("Speed"), _("Reset"), "set speed 1", "BS"),
new (_("View"), _("Show Playlist"), "script-message-to mpvnet show-playlist", "F8"), new (_("View"), _("Show Playlist"), "script-message-to mpvnet show-playlist", "F8"),
new (_("View"), _("Show Profiles"), "script-message-to mpvnet show-profiles", "Ctrl+P"),
new (_("View"), _("Toggle Statistics"), "script-binding stats/display-stats-toggle", "t"), new (_("View"), _("Toggle Statistics"), "script-binding stats/display-stats-toggle", "t"),
new (_("View"), _("Toggle OSC Visibility"), "script-binding osc/visibility", "Del"), new (_("View"), _("Toggle OSC Visibility"), "script-binding osc/visibility", "Del"),
new (_("View"), _("Show Media Info On-Screen"), "script-message-to mpvnet show-media-info osd", "i"), new (_("View"), _("Show Media Info On-Screen"), "script-message-to mpvnet show-media-info osd", "i"),
@@ -125,9 +126,12 @@ public static class InputHelp
new (_("View") + " > " + _("More"), _("Show Console"), "script-binding console/enable", "`"), new (_("View") + " > " + _("More"), _("Show Console"), "script-binding console/enable", "`"),
new (_("View") + " > " + _("More"), _("Show Audio Devices"), "script-message-to mpvnet show-audio-devices"), new (_("View") + " > " + _("More"), _("Show Audio Devices"), "script-message-to mpvnet show-audio-devices"),
new (_("View") + " > " + _("More"), _("Show Commands"), "script-message-to mpvnet show-commands", "F2"), new (_("View") + " > " + _("More"), _("Show Commands"), "script-message-to mpvnet show-commands", "F2"),
new (_("View") + " > " + _("More"), _("Show Demuxers"), "script-message-to mpvnet show-demuxers"),
new (_("View") + " > " + _("More"), _("Show Decoders"), "script-message-to mpvnet show-decoders"),
new (_("View") + " > " + _("More"), _("Show Bindings"), "script-message-to mpvnet show-bindings"), new (_("View") + " > " + _("More"), _("Show Bindings"), "script-message-to mpvnet show-bindings"),
new (_("View") + " > " + _("More"), _("Show Properties"), "script-message-to mpvnet show-properties", "F3"),
new (_("View") + " > " + _("More"), _("Show Keys"), "script-message-to mpvnet show-keys", "Alt+k"),
new (_("View") + " > " + _("More"), _("Show Protocols"), "script-message-to mpvnet show-protocols", "Alt+p"),
new (_("View") + " > " + _("More"), _("Show Decoders"), "script-message-to mpvnet show-decoders", "Alt+d"),
new (_("View") + " > " + _("More"), _("Show Demuxers"), "script-message-to mpvnet show-demuxers"),
new (_("Window"), _("Fullscreen"), "cycle fullscreen", "Enter"), new (_("Window"), _("Fullscreen"), "cycle fullscreen", "Enter"),
new (_("Window") + " > " + _("Zoom"), _("Enlarge"), "script-message-to mpvnet scale-window 1.2", "Alt++"), new (_("Window") + " > " + _("Zoom"), _("Enlarge"), "script-message-to mpvnet scale-window 1.2", "Alt++"),
@@ -149,11 +153,18 @@ public static class InputHelp
new (_("Settings"), _("Show Config Editor"), "script-message-to mpvnet show-conf-editor", "Ctrl+,"), new (_("Settings"), _("Show Config Editor"), "script-message-to mpvnet show-conf-editor", "Ctrl+,"),
new (_("Settings"), _("Show Input Editor"), "script-message-to mpvnet show-input-editor", "Ctrl+i"), new (_("Settings"), _("Show Input Editor"), "script-message-to mpvnet show-input-editor", "Ctrl+i"),
new (_("Settings"), "-"),
new (_("Settings"), _("Edit mpv.conf"), "script-message-to mpvnet edit-conf-file mpv.conf", "c"),
new (_("Settings"), _("Edit input.conf"), "script-message-to mpvnet edit-conf-file input.conf", "k"),
new (_("Settings"), "-"),
new (_("Settings"), _("Open Config Folder"), "script-message-to mpvnet open-conf-folder", "Ctrl+f"), new (_("Settings"), _("Open Config Folder"), "script-message-to mpvnet open-conf-folder", "Ctrl+f"),
new (_("Settings") + " > " + _("Setup"), _("Register video file associations"), "script-message-to mpvnet reg-file-assoc video"), new (_("Settings") + " > " + _("Setup"), _("Register video file associations"), "script-message-to mpvnet reg-file-assoc video"),
new (_("Settings") + " > " + _("Setup"), _("Register audio file associations"), "script-message-to mpvnet reg-file-assoc audio"), new (_("Settings") + " > " + _("Setup"), _("Register audio file associations"), "script-message-to mpvnet reg-file-assoc audio"),
new (_("Settings") + " > " + _("Setup"), _("Register image file associations"), "script-message-to mpvnet reg-file-assoc image"), new (_("Settings") + " > " + _("Setup"), _("Register image file associations"), "script-message-to mpvnet reg-file-assoc image"),
new (_("Settings") + " > " + _("Setup"), _("Unregister file associations"), "script-message-to mpvnet reg-file-assoc unreg"), new (_("Settings") + " > " + _("Setup"), _("Unregister file associations"), "script-message-to mpvnet reg-file-assoc unreg"),
new (_("Settings") + " > " + _("Setup"), "-"),
new (_("Settings") + " > " + _("Setup"), _("Add mpv.net to Path environment variable"), "script-message-to mpvnet add-to-path"),
new (_("Settings") + " > " + _("Setup"), _("Remove mpv.net from Path environment variable"), "script-message-to mpvnet remove-from-path"),
new (_("Tools"), _("Set/clear A-B loop points"), "ab-loop", "l"), new (_("Tools"), _("Set/clear A-B loop points"), "ab-loop", "l"),
new (_("Tools"), _("Toggle infinite file looping"), "cycle-values loop-file inf no", "L"), new (_("Tools"), _("Toggle infinite file looping"), "cycle-values loop-file inf no", "L"),
@@ -174,11 +185,10 @@ public static class InputHelp
new ("", "", "quit", "q", _("Exit")), new ("", "", "quit", "q", _("Exit")),
new ("", "", "script-message-to mpvnet show-menu", "MBTN_Right", _("Show Menu")), new ("", "", "script-message-to mpvnet show-menu", "MBTN_Right", _("Show Menu")),
new ("", "", "quit", "Power", _("Exit")), new ("", "", "script-message-to mpvnet play-pause", "Play", _("Play/Pause")),
new ("", "", "cycle pause", "Play", _("Play/Pause")), new ("", "", "script-message-to mpvnet play-pause", "Pause", _("Play/Pause")),
new ("", "", "cycle pause", "Pause", _("Play/Pause")), new ("", "", "script-message-to mpvnet play-pause", "PlayPause", _("Play/Pause")),
new ("", "", "cycle pause", "PlayPause", _("Play/Pause")), new ("", "", "script-message-to mpvnet play-pause", "MBTN_Mid", _("Play/Pause")),
new ("", "", "cycle pause", "MBTN_Mid", _("Play/Pause")),
new ("", "", "stop", "Stop", _("Stop")), new ("", "", "stop", "Stop", _("Stop")),
new ("", "", "seek 60", "Forward", _("Forward")), new ("", "", "seek 60", "Forward", _("Forward")),
new ("", "", "seek -60", "Rewind", _("Backward")), new ("", "", "seek -60", "Rewind", _("Backward")),
@@ -205,8 +215,8 @@ public static class InputHelp
new ("", "", "no-osd sub-seek 1", "Ctrl+Shift+Right", _("Seek to next subtitle")), new ("", "", "no-osd sub-seek 1", "Ctrl+Shift+Right", _("Seek to next subtitle")),
new ("", "", "no-osd seek 5", "Ctrl+Wheel_Up", _("Seek Forward")), new ("", "", "no-osd seek 5", "Ctrl+Wheel_Up", _("Seek Forward")),
new ("", "", "no-osd seek -5", "Ctrl+Wheel_Down", _("Seek Backward")), new ("", "", "no-osd seek -5", "Ctrl+Wheel_Down", _("Seek Backward")),
new ("", "", "quit 4", "Esc", _("Quit encoding")), new ("", "", "quit", "Power", _("Exit")),
new ("", "", "quit 4", "q", _("Quit encoding")),
//new (_("Command Palette"), _("Commands"), "script-message-to mpvnet show-command-palette", "F1"), //new (_("Command Palette"), _("Commands"), "script-message-to mpvnet show-command-palette", "F1"),
}; };
@@ -280,6 +290,9 @@ public static class InputHelp
if (string.IsNullOrEmpty(content)) if (string.IsNullOrEmpty(content))
return bindings; return bindings;
if (content.Contains('\t'))
content = content.Replace('\t', ' ');
foreach (string it in content.Split('\n')) foreach (string it in content.Split('\n'))
{ {
string line = it.Trim(); string line = it.Trim();
@@ -321,18 +334,11 @@ public static class InputHelp
line = line[(line.IndexOf(" ") + 1)..]; line = line[(line.IndexOf(" ") + 1)..];
if (line.Contains("#menu:")) if (line.Contains(App.MenuSyntax))
{ {
binding.Comment = line[(line.IndexOf("#menu:") + 6)..].Trim(); binding.Comment = line[(line.IndexOf(App.MenuSyntax) + App.MenuSyntax.Length)..].Trim();
binding.IsMenu = true; binding.IsMenu = true;
line = line[..line.IndexOf("#menu:")]; line = line[..line.IndexOf(App.MenuSyntax)];
}
else if (line.Contains("#!"))
{
binding.Comment = line[(line.IndexOf("#!") + 2)..].Trim();
binding.IsMenu = true;
binding.IsShortMenuSyntax = true;
line = line[..line.IndexOf("#!")];
} }
else if (line.Contains("#custom-menu:")) else if (line.Contains("#custom-menu:"))
{ {
@@ -432,10 +438,10 @@ public static class InputHelp
value = value[(value.IndexOf(" ") + 1)..]; value = value[(value.IndexOf(" ") + 1)..];
if (value.Contains("#menu:")) if (value.Contains(App.MenuSyntax))
{ {
binding.Comment = value[(value.IndexOf("#menu:") + 6)..].Trim(); binding.Comment = value[(value.IndexOf(App.MenuSyntax) + App.MenuSyntax.Length)..].Trim();
value = value[..value.IndexOf("#menu:")]; value = value[..value.IndexOf(App.MenuSyntax)];
if (binding.Comment.Contains(';')) if (binding.Comment.Contains(';'))
binding.Comment = binding.Comment[(binding.Comment.IndexOf(";") + 1)..].Trim(); binding.Comment = binding.Comment[(binding.Comment.IndexOf(";") + 1)..].Trim();
@@ -454,4 +460,41 @@ public static class InputHelp
} }
return bindings; return bindings;
} }
public static Dictionary<string, Binding> GetActiveBindings(List<Binding> bindings)
{
Dictionary<string, Binding> ret = new();
foreach (Binding binding in bindings)
{
if (binding.Input == "" || binding.Command == "")
continue;
ret[binding.Input] = binding;
}
return ret;
}
public static string GetBindingsForCommand(Dictionary<string, Binding> activeBindings, string command)
{
List<string> keys = new();
int charCount = 0;
foreach (var it in activeBindings)
{
if (it.Value.Command != command)
continue;
Binding binding = it.Value;
if (!keys.Contains(binding.Input) && (charCount + binding.Input.Length) < 15)
{
keys.Add(binding.Input);
charCount += binding.Input.Length;
}
}
return string.Join(", ", keys);
}
} }

View File

@@ -64,7 +64,7 @@ public class MpvClient
OnEndFile(data); OnEndFile(data);
} }
break; break;
case mpv_event_id.MPV_EVENT_FILE_LOADED: case mpv_event_id.MPV_EVENT_FILE_LOADED: // triggered after MPV_EVENT_START_FILE
OnFileLoaded(); OnFileLoaded();
break; break;
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE: case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
@@ -82,7 +82,7 @@ public class MpvClient
case mpv_event_id.MPV_EVENT_COMMAND_REPLY: case mpv_event_id.MPV_EVENT_COMMAND_REPLY:
OnCommandReply(); OnCommandReply();
break; break;
case mpv_event_id.MPV_EVENT_START_FILE: case mpv_event_id.MPV_EVENT_START_FILE: // triggered before MPV_EVENT_FILE_LOADED
OnStartFile(); OnStartFile();
break; break;
case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG: case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG:

View File

@@ -36,6 +36,7 @@ public class MainPlayer : MpvClient
public bool Paused { get; set; } public bool Paused { get; set; }
public bool SnapWindow { get; set; } public bool SnapWindow { get; set; }
public bool TaskbarProgress { get; set; } = true; public bool TaskbarProgress { get; set; } = true;
public bool TitleBar { get; set; } = true;
public bool WasInitialSizeSet; public bool WasInitialSizeSet;
public bool WindowMaximized { get; set; } public bool WindowMaximized { get; set; }
public bool WindowMinimized { get; set; } public bool WindowMinimized { get; set; }
@@ -50,7 +51,6 @@ public class MainPlayer : MpvClient
public float AutofitLarger { get; set; } = 0.8f; public float AutofitLarger { get; set; } = 0.8f;
public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false); public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false);
public AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false);
public nint MainHandle { get; set; } public nint MainHandle { get; set; }
public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>(); public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>(); public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>();
@@ -59,12 +59,14 @@ public class MainPlayer : MpvClient
public TimeSpan Duration; public TimeSpan Duration;
public List<MpvClient> Clients { get; } = new List<MpvClient>(); public List<MpvClient> Clients { get; } = new List<MpvClient>();
List<StringPair>? _audioDevices;
public event Action? Initialized; public event Action? Initialized;
public event Action? Pause; public event Action? Pause;
public event Action<int>? PlaylistPosChanged; public event Action<int>? PlaylistPosChanged;
public event Action<Size>? VideoSizeChanged; public event Action<Size>? VideoSizeChanged;
public void Init(IntPtr formHandle) public void Init(IntPtr formHandle, bool processCommandLineArguments = true)
{ {
App.ApplyShowMenuFix(); App.ApplyShowMenuFix();
@@ -98,7 +100,7 @@ public class MainPlayer : MpvClient
SetPropertyBool("input-default-bindings", true); SetPropertyBool("input-default-bindings", true);
SetPropertyBool("input-builtin-bindings", false); SetPropertyBool("input-builtin-bindings", false);
SetPropertyString("watch-later-options", "mute"); SetPropertyString("idle", "yes");
SetPropertyString("screenshot-directory", "~~desktop/"); SetPropertyString("screenshot-directory", "~~desktop/");
SetPropertyString("osd-playing-msg", "${media-title}"); SetPropertyString("osd-playing-msg", "${media-title}");
SetPropertyString("osc", "yes"); SetPropertyString("osc", "yes");
@@ -111,11 +113,12 @@ public class MainPlayer : MpvClient
if (!string.IsNullOrEmpty(UsedInputConfContent)) if (!string.IsNullOrEmpty(UsedInputConfContent))
SetPropertyString("input-conf", @"memory://" + UsedInputConfContent); SetPropertyString("input-conf", @"memory://" + UsedInputConfContent);
ProcessCommandLineArgs(); if (processCommandLineArguments)
ProcessCommandLineArgs();
if (App.CommandLineArguments.ContainsKey("config-dir")) if (CommandLine.Contains("config-dir"))
{ {
string configDir = App.CommandLineArguments["config-dir"]; string configDir = CommandLine.GetValue("config-dir");
string fullPath = System.IO.Path.GetFullPath(configDir); string fullPath = System.IO.Path.GetFullPath(configDir);
App.InputConf.Path = fullPath.AddSep() + "input.conf"; App.InputConf.Path = fullPath.AddSep() + "input.conf";
string content = App.InputConf.GetContent(); string content = App.InputConf.GetContent();
@@ -131,10 +134,6 @@ public class MainPlayer : MpvClient
if (err < 0) if (err < 0)
throw new Exception("mpv_initialize error" + BR2 + GetError(err) + BR); throw new Exception("mpv_initialize error" + BR2 + GetError(err) + BR);
SetPropertyString("user-data/frontend/name", "mpv.net");
SetPropertyString("user-data/frontend/version", AppInfo.Version.ToString());
SetPropertyString("user-data/frontend/process-path", Environment.ProcessPath!);
string idle = GetPropertyString("idle"); string idle = GetPropertyString("idle");
App.Exit = idle == "no" || idle == "once"; App.Exit = idle == "no" || idle == "once";
@@ -152,16 +151,24 @@ public class MainPlayer : MpvClient
// this means Lua scripts that use idle might not work correctly // this means Lua scripts that use idle might not work correctly
SetPropertyString("idle", "yes"); SetPropertyString("idle", "yes");
ObservePropertyString("path", value => Path = value); SetPropertyString("user-data/frontend/name", "mpv.net");
SetPropertyString("user-data/frontend/version", AppInfo.Version.ToString());
SetPropertyString("user-data/frontend/process-path", Environment.ProcessPath!);
ObservePropertyBool("pause", value => { ObservePropertyBool("pause", value => {
Paused = value; Paused = value;
Pause?.Invoke(); Pause?.Invoke();
}); });
ObservePropertyInt("video-rotate", value => { VideoRotate = GetPropertyInt("video-rotate");
VideoRotate = value;
UpdateVideoSize("dwidth", "dheight"); ObservePropertyInt("video-rotate", value =>
{
if (VideoRotate != value)
{
VideoRotate = value;
UpdateVideoSize("dwidth", "dheight");
}
}); });
ObservePropertyInt("playlist-pos", value => { ObservePropertyInt("playlist-pos", value => {
@@ -173,9 +180,6 @@ public class MainPlayer : MpvClient
CommandV("quit"); CommandV("quit");
}); });
if (!GetPropertyBool("osd-scale-by-window"))
App.StartThreshold = 0;
Initialized?.Invoke(); Initialized?.Invoke();
} }
@@ -221,6 +225,7 @@ public class MainPlayer : MpvClient
case "vo": VO = value!; break; case "vo": VO = value!; break;
case "window-maximized": WindowMaximized = value == "yes"; break; case "window-maximized": WindowMaximized = value == "yes"; break;
case "window-minimized": WindowMinimized = value == "yes"; break; case "window-minimized": WindowMinimized = value == "yes"; break;
case "title-bar": TitleBar = value == "yes"; break;
} }
if (AutofitLarger > 1) if (AutofitLarger > 1)
@@ -269,57 +274,65 @@ public class MainPlayer : MpvClient
Dictionary<string, string>? _Conf; Dictionary<string, string>? _Conf;
public Dictionary<string, string> Conf { public Dictionary<string, string> Conf {
get { get
if (_Conf == null) {
if (_Conf != null)
return _Conf;
App.ApplyInputDefaultBindingsFix();
_Conf = new Dictionary<string, string>();
if (File.Exists(ConfPath))
{ {
App.ApplyInputDefaultBindingsFix(); foreach (string? it in File.ReadAllLines(ConfPath))
_Conf = new Dictionary<string, string>();
if (File.Exists(ConfPath))
{ {
foreach (string? it in File.ReadAllLines(ConfPath)) string line = it.TrimStart(' ', '-').TrimEnd();
if (line.StartsWith("#"))
continue;
if (!line.Contains('='))
{ {
string line = it.TrimStart(' ', '-').TrimEnd(); if (Regex.Match(line, "^[\\w-]+$").Success)
line += "=yes";
if (!line.Contains('=') || line.StartsWith("#")) else
continue; continue;
string key = line[..line.IndexOf("=")].Trim();
string value = line[(line.IndexOf("=") + 1)..].Trim();
if (value.Contains('#') && !value.StartsWith("#") &&
!value.StartsWith("'#") && !value.StartsWith("\"#"))
value = value[..value.IndexOf("#")].Trim();
_Conf[key] = value;
} }
}
foreach (var i in _Conf) string key = line[..line.IndexOf("=")].Trim();
ProcessProperty(i.Key, i.Value); string value = line[(line.IndexOf("=") + 1)..].Trim();
if (value.Contains('#') && !value.StartsWith("#") &&
!value.StartsWith("'#") && !value.StartsWith("\"#"))
value = value[..value.IndexOf("#")].Trim();
_Conf[key] = value;
}
} }
foreach (var i in _Conf)
ProcessProperty(i.Key, i.Value);
return _Conf; return _Conf;
} }
} }
void UpdateVideoSize(string w, string h) void UpdateVideoSize(string w, string h)
{ {
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h)); if (string.IsNullOrEmpty(Path))
if (size.Width == 0 || size.Height == 0)
return; return;
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h));
if (VideoRotate == 90 || VideoRotate == 270) if (VideoRotate == 90 || VideoRotate == 270)
size = new Size(size.Height, size.Width); size = new Size(size.Height, size.Width);
if (VideoSize != size) if (size != VideoSize && size != Size.Empty)
{ {
VideoSize = size; VideoSize = size;
VideoSizeChanged?.Invoke(size); VideoSizeChanged?.Invoke(size);
VideoSizeAutoResetEvent.Set();
} }
} }
@@ -349,24 +362,27 @@ public class MainPlayer : MpvClient
base.OnLogMessage(data); base.OnLogMessage(data);
} }
protected override void OnVideoReconfig()
{
UpdateVideoSize("dwidth", "dheight");
base.OnVideoReconfig();
}
protected override void OnEndFile(mpv_event_end_file data) protected override void OnEndFile(mpv_event_end_file data)
{ {
base.OnEndFile(data); base.OnEndFile(data);
FileEnded = true; FileEnded = true;
} }
protected override void OnVideoReconfig()
{
UpdateVideoSize("dwidth", "dheight");
base.OnVideoReconfig();
}
// executed before OnFileLoaded
protected override void OnStartFile() protected override void OnStartFile()
{ {
Path = GetPropertyString("path");
base.OnStartFile(); base.OnStartFile();
TaskHelp.Run(LoadFolder); TaskHelp.Run(LoadFolder);
} }
// executed after OnStartFile
protected override void OnFileLoaded() protected override void OnFileLoaded()
{ {
Duration = TimeSpan.FromSeconds(GetPropertyDouble("duration")); Duration = TimeSpan.FromSeconds(GetPropertyDouble("duration"));
@@ -374,14 +390,6 @@ public class MainPlayer : MpvClient
if (App.StartSize == "video") if (App.StartSize == "video")
WasInitialSizeSet = false; WasInitialSizeSet = false;
string path = GetPropertyString("path");
if (!FileTypes.Video.Contains(path.Ext()) || FileTypes.Audio.Contains(path.Ext()))
{
UpdateVideoSize("width", "height");
VideoSizeAutoResetEvent.Set();
}
TaskHelp.Run(UpdateTracks); TaskHelp.Run(UpdateTracks);
base.OnFileLoaded(); base.OnFileLoaded();
@@ -409,75 +417,43 @@ public class MainPlayer : MpvClient
public void ProcessCommandLineArgs() public void ProcessCommandLineArgs()
{ {
foreach (string i in Environment.GetCommandLineArgs().Skip(1)) foreach (var pair in CommandLine.Arguments)
{ {
string arg = i; if (pair.Name.EndsWith("-add") ||
pair.Name.EndsWith("-set") ||
pair.Name.EndsWith("-pre") ||
pair.Name.EndsWith("-clr") ||
pair.Name.EndsWith("-append") ||
pair.Name.EndsWith("-remove") ||
pair.Name.EndsWith("-toggle"))
if (!arg.StartsWith("--"))
continue; continue;
if (arg == "--profile=help") ProcessProperty(pair.Name, pair.Value);
{
Console.WriteLine(GetProfiles());
continue;
}
else if (arg == "--vd=help" || arg == "--ad=help")
{
Console.WriteLine(GetDecoders());
continue;
}
else if (arg == "--audio-device=help")
{
Console.WriteLine(GetPropertyOsdString("audio-device-list"));
continue;
}
else if (arg == "--version")
{
Console.WriteLine(AppClass.About);
continue;
}
else if (arg == "--input-keylist")
{
Console.WriteLine(GetPropertyString("input-key-list").Replace(",", BR));
continue;
}
else if (arg.StartsWith("--command="))
{
Command(arg[10..]);
continue;
}
if (!arg.Contains('=')) if (!App.ProcessProperty(pair.Name, pair.Value))
{ SetPropertyString(pair.Name, pair.Value);
if (arg.Contains("--no-")) }
{ }
arg = arg.Replace("--no-", "--");
arg += "=no";
}
else
arg += "=yes";
}
string left = arg[2..arg.IndexOf("=")]; public void ProcessCommandLineArgsPost()
string right = arg[(left.Length + 3)..]; {
foreach (var pair in CommandLine.Arguments)
if (string.IsNullOrEmpty(left)) {
continue; if (pair.Name.EndsWith("-add"))
CommandV("change-list", pair.Name[..^4], "add", pair.Value);
switch (left) else if (pair.Name.EndsWith("-set"))
{ CommandV("change-list", pair.Name[..^4], "set", pair.Value);
case "script": left = "scripts"; break; else if (pair.Name.EndsWith("-append"))
case "audio-file": left = "audio-files"; break; CommandV("change-list", pair.Name[..^7], "append", pair.Value);
case "sub-file": left = "sub-files"; break; else if (pair.Name.EndsWith("-pre"))
case "external-file": left = "external-files"; break; CommandV("change-list", pair.Name[..^4], "pre", pair.Value);
} else if (pair.Name.EndsWith("-clr"))
CommandV("change-list", pair.Name[..^4], "clr", "");
App.CommandLineArguments[left] = right; else if (pair.Name.EndsWith("-remove"))
CommandV("change-list", pair.Name[..^7], "remove", pair.Value);
ProcessProperty(left, right); else if (pair.Name.EndsWith("-toggle"))
CommandV("change-list", pair.Name[..^7], "toggle", pair.Value);
if (!App.ProcessProperty(left, right))
SetPropertyString(left, right);
} }
} }
@@ -491,19 +467,13 @@ public class MainPlayer : MpvClient
files.Add(arg); files.Add(arg);
LoadFiles(files.ToArray(), !App.Queue, false || App.Queue); LoadFiles(files.ToArray(), !App.Queue, App.Queue);
if (App.CommandLine.Contains("--shuffle")) if (App.CommandLine.Contains("--shuffle"))
{ {
Command("playlist-shuffle"); Command("playlist-shuffle");
SetPropertyInt("playlist-pos", 0); SetPropertyInt("playlist-pos", 0);
} }
if (files.Count == 0 || files[0].Contains("://"))
{
VideoSizeChanged?.Invoke(VideoSize);
VideoSizeAutoResetEvent.Set();
}
} }
public DateTime LastLoad; public DateTime LastLoad;
@@ -719,6 +689,26 @@ public class MainPlayer : MpvClient
} }
} }
public List<StringPair> AudioDevices {
get {
if (_audioDevices != null)
return _audioDevices;
_audioDevices = new();
string json = GetPropertyString("audio-device-list");
var enumerator = JsonDocument.Parse(json).RootElement.EnumerateArray();
foreach (var element in enumerator)
{
string name = element.GetProperty("name").GetString()!;
string description = element.GetProperty("description").GetString()!;
_audioDevices.Add(new StringPair(name, description));
}
return _audioDevices;
}
}
public List<Chapter> GetChapters() { public List<Chapter> GetChapters() {
List<Chapter> chapters = new List<Chapter>(); List<Chapter> chapters = new List<Chapter>();
int count = GetPropertyInt("chapter-list/count"); int count = GetPropertyInt("chapter-list/count");

View File

@@ -0,0 +1,7 @@
{
"profiles": {
"MpvNet": {
"commandName": "Project"
}
}
}

View File

@@ -11,13 +11,16 @@ public class AppSettings
{ {
public bool InputDefaultBindingsFixApplied; public bool InputDefaultBindingsFixApplied;
public bool ShowMenuFixApplied; public bool ShowMenuFixApplied;
public int MenuUpdateVersion;
public int Volume = 70; public int Volume = 70;
public List<string> RecentFiles = new List<string>(); public List<string> RecentFiles = new List<string>();
public Point WindowLocation; public Point WindowLocation;
public Point WindowPosition; public Point WindowPosition;
public Size WindowSize; public Size WindowSize;
public string AudioDevice = "";
public string ConfigEditorSearch = "Video:"; public string ConfigEditorSearch = "Video:";
public string Mute = "no"; public string Mute = "no";
public string StartupFolder = "";
} }
class SettingsManager class SettingsManager

View File

@@ -1,4 +1,5 @@
namespace MpvNet.Windows; 
namespace MpvNet;
public class StringPair public class StringPair
{ {

View File

@@ -0,0 +1,28 @@
#define MyAppName "mpv.net"
#define MyAppExeName "mpvnet.exe"
#define MyAppSourceDir "..\..\MpvNet.Windows\bin\Debug"
#define MyAppVersion GetFileVersion("..\..\MpvNet.Windows\bin\Debug\mpvnet.exe")
[Setup]
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher=Frank Skare (stax76)
ArchitecturesInstallIn64BitMode=x64
Compression=lzma2
DefaultDirName={autopf}\{#MyAppName}
OutputBaseFilename=mpv.net-v{#MyAppVersion}-setup
OutputDir=E:\Desktop
DefaultGroupName={#MyAppName}
SetupIconFile=..\..\MpvNet.Windows\mpv-icon.ico
UninstallDisplayIcon={app}\{#MyAppExeName}
PrivilegesRequired=admin
PrivilegesRequiredOverridesAllowed=dialog
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
[Files]
Source: "{#MyAppSourceDir}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Excludes: "win-x64"; Flags: ignoreversion recursesubdirs createallsubdirs;

View File

@@ -0,0 +1,73 @@
<#
This script updates mpv and libmpv using github.com/zhongfly/mpv-winbuild
Two positional command line arguments need to be passed into the script:
1. The directory containing libmpv to be updated.
2. The directory containing mpv to be updated.
To skip one of both pass 'no' instead of the path.
Requires 7zip being installed at 'C:\Program Files\7-Zip\7z.exe'
#>
$zip7Path = 'C:\Program Files\7-Zip\7z.exe'
$ScriptArgs = $args
# Stop when the first error occurs
$ErrorActionPreference = 'Stop'
# Throw exception if file or folder does not exist
function Test($path) {
if (-not (Test-Path $path)) {
throw $path
}
return $path
}
# Download file to temp dir and return file path
function Download($pattern) {
$api = "https://api.github.com/repos/zhongfly/mpv-winbuild/releases/latest"
$json = Invoke-WebRequest $api -MaximumRedirection 0 -ErrorAction Ignore -UseBasicParsing | ConvertFrom-Json
$filename = ($json.assets | Where-Object { $_.name -Match $pattern }).name
$path = Join-Path $env:TEMP $filename
$link = ($json.assets | Where-Object { $_.name -Match $pattern }).browser_download_url
Invoke-WebRequest -Uri $link -UserAgent "mpv-win-updater" -OutFile $path
return Test $path
}
function Unpack($archieveFile, $outputRootDir) {
$outputDir = Join-Path $outputRootDir $archieveFile.BaseName
if (Test-Path $outputDir) { Remove-Item $outputDir -Recurse }
$process = Start-Process (Test $zip7Path) @('x', $archieveFile.FullName, "-o$outputDir") -NoNewWindow -Wait
if ($process.ExitCode) { throw $process.ExitCode }
return Test $outputDir
}
function UpdateLibmpv {
$targetFolder = $ScriptArgs[0]
if ($targetFolder -eq 'no') { return }
$archiveFile = Get-Item (Download "mpv-dev-x86_64-[0-9]{8}")
$archiveDir = Unpack $archiveFile $env:TEMP
Copy-Item $archiveDir\libmpv-2.dll (Test $targetFolder) -Force
Remove-Item $archiveFile.FullName
Remove-Item $archiveDir -Recurse
}
function UpdateMpv() {
$targetFolder = $ScriptArgs[1]
if ($targetFolder -eq 'no') { return }
$archiveFile = Get-Item (Download "mpv-x86_64-[0-9]{8}")
$archiveDir = Unpack $archiveFile $env:TEMP
Copy-Item "$archiveDir\mpv\*" $targetFolder -Force -Recurse
Remove-Item $archiveFile.FullName
Remove-Item $archiveDir -Recurse
}
UpdateLibmpv
UpdateMpv
Write-Host 'Script finished successfully' -ForegroundColor Green