Compare commits

...

144 Commits

Author SHA1 Message Date
stax76
96afc62165 v7.1.2.0 2026-01-09 06:16:51 +01:00
stax76
fd3ea9afe9 Misc 2026-01-09 06:03:08 +01:00
stax76
853d38a427 PS script documentation 2026-01-09 05:21:30 +01:00
stax76
76a2f64fa6 adjust to mpv v.0.41 2026-01-08 17:14:31 +01:00
stax76
6c0e116918 Update readme 2025-11-26 13:51:47 +01:00
stax76
c1abf90559 Update outdated requirements in manual 2025-11-25 06:07:35 +01:00
stax76
eb085a6534 Changelog and version updated 2025-11-23 21:26:51 +01:00
stax76
78b85d59aa Merge pull request #751 from DogancanYr/patch-5
Revise Turkish translations.
2025-11-23 21:21:16 +01:00
stax76
0f900e01fa Merge pull request #752 from tsubasanouta/patch-1
Update ja.po
2025-11-23 21:20:54 +01:00
tsubasanouta
f754d4d865 Update ja.po 2025-11-24 04:47:20 +09:00
DogancanYr
474c4e888d Revise Turkish translations. 2025-11-23 16:10:49 +03:00
stax76
8f8ca453da Fix #748 2025-11-20 01:51:23 +01:00
stax76
8bd00fd2f1 Changelog update 2025-11-20 01:23:09 +01:00
stax76
61958aba2c v7.1.1.5 Beta 2025-11-20 01:11:02 +01:00
stax76
3fa6f44828 Changelog update 2025-11-20 01:07:16 +01:00
stax76
31be72efb2 Update Changelog 2025-11-20 01:00:27 +01:00
stax76
405c20f056 Merge pull request #749 from DogancanYr/patch-4
Update Turkish translations in tr.po file
2025-11-20 00:56:45 +01:00
stax76
5f0fb4ebc3 Update to .NET 10 LTS 2025-11-20 00:56:03 +01:00
DogancanYr
c6a2b06fdf Update Turkish translations in tr.po file 2025-10-29 19:58:56 +03:00
stax76
8f38eba23e Chinese and Japanese translations update 2025-10-14 02:41:25 +02:00
stax76
79164aae72 The German translation was updated 2025-10-06 00:43:18 +02:00
stax76
e5d3ac0d92 Changed default keys and menu items 2025-10-05 16:53:55 +02:00
stax76
f7c8c16344 v7.1.1.4 Beta 2025-10-05 01:12:04 +02:00
stax76
b1fccbf175 misc 2025-10-04 15:07:56 +02:00
stax76
cc1e4bc9f8 misc 2025-09-12 05:11:55 +02:00
stax76
3812f3031c Improved support for select.lua 2025-05-05 17:42:50 +02:00
stax76
837f97d491 Merge branch 'main' of https://github.com/mpvnet-player/mpv.net 2025-05-05 14:38:20 +02:00
stax76
2dab825af4 Update changelog 2025-05-05 14:37:58 +02:00
stax76
a78c1ba50d Merge pull request #725 from benomine/main
feat: dotnet 9, CPM, etc
2025-05-05 14:30:44 +02:00
stax76
50aea3b5ba Update changelog 2025-05-05 14:28:45 +02:00
stax76
6a971595f7 attempted actions/workflow fix 2025-05-04 05:03:17 +02:00
stax76
a1d944a9a0 translation update 2025-05-04 04:51:40 +02:00
stax76
8b49312bad Turkish translation update 2025-05-04 04:26:25 +02:00
stax76
95b279b0e9 Merge pull request #718 from DogancanYr/patch-3
Update tr.po
2025-05-04 04:10:30 +02:00
Benjamin Nomine
01477d8b25 feat: dotnet 9, CPM, etc 2025-01-11 14:05:54 -05:00
DogancanYr
4e5182eb73 Update tr.po 2024-11-28 19:43:56 +02:00
stax76
8d0b70a5dc manual improvements and fixes 2024-11-06 01:50:07 +01:00
stax76
37a241f136 Use MPV_CONFIG_DIR env var for command palette installer script 2024-11-03 11:30:19 +01:00
stax76
ace7566c2a v7.1.1.3 Beta 2024-10-20 09:15:34 +02:00
stax76
0b646cedb5 New command Video > Stream Quality (Alt+q) 2024-10-14 15:18:11 +02:00
stax76
a0d2fb6a4e command palette support 2024-10-13 14:18:04 +02:00
stax76
59a556794f support for autocreate-playlist, video-exts, audio-exts, image-exts 2024-10-12 21:50:46 +02:00
stax76
cca474a5a5 Merge pull request #710 from emmanuel-ferdman/main
update manual guide reference
2024-10-10 19:25:14 +02:00
Emmanuel Ferdman
ae05b997c7 update manual guide reference
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2024-10-10 06:52:50 -07:00
stax76
88a6e18e78 v7.1.1.2 2024-10-10 14:08:21 +02:00
stax76
3de72df806 use autocreate-playlist instead of auto-load-folder 2024-10-10 13:32:19 +02:00
stax76
da176085cd Action fix 2024-10-10 06:27:24 +02:00
stax76
2b0ac7c087 cursor-autohide support #702 2024-10-10 05:44:02 +02:00
stax76
94ecf4a069 try fixing #662 2024-09-05 23:33:13 +02:00
stax76
9355e2f50c Set media-controls=yes 2024-09-05 05:15:00 +02:00
stax76
058ae3d185 auto build fix 2024-08-19 11:37:50 +02:00
stax76
3c1e6395a4 changelog update 2024-08-19 09:59:08 +02:00
stax76
236d10c14a changelog update 2024-08-19 09:56:02 +02:00
stax76
53f350da9a Polish translation fixed 2024-08-19 09:45:56 +02:00
stax76
bb6819f240 translation update 2024-08-19 09:27:18 +02:00
stax76
8f53254dbc Merge branch 'main' of https://github.com/mpvnet-player/mpv.net 2024-08-19 08:58:10 +02:00
stax76
8ed73f6ae0 changelog update 2024-08-19 08:57:54 +02:00
stax76
d59ccd7beb Merge pull request #704 from Ilithy/main
French translation
2024-08-19 08:55:19 +02:00
stax76
aeb11c9be1 changelog update 2024-08-19 08:53:06 +02:00
Ilithy
a1c8e93034 Update fr.po 2024-08-18 12:10:25 +02:00
Ilithy
00a11ea076 Update fr.po 2024-08-18 12:08:43 +02:00
Ilithy
9115f707dc Update fr.po 2024-08-18 12:02:59 +02:00
Ilithy
a2ec8de976 Update fr.po 2024-08-18 11:59:08 +02:00
Ilithy
be7e5aa7d2 Update fr.po 2024-08-18 11:52:03 +02:00
Ilithy
27124c9cdd Update fr.po 2024-08-18 01:57:02 +02:00
Ilithy
44079ed69c first commit for french translation 2024-08-16 01:36:00 +02:00
stax76
07749cb2cc title-bar fix 2024-08-10 11:19:23 +02:00
stax76
9d30acaba6 Japanese translation updated 2024-07-26 00:36:07 +02:00
stax76
f3fdef780d Support relative folders from command line 2024-07-26 00:14:44 +02:00
stax76
1243d1381b Updated changelog 2024-07-25 11:42:01 +02:00
stax76
3602f627e8 manual 2024-07-25 11:06:09 +02:00
stax76
97fab64d32 manual 2024-07-25 11:01:37 +02:00
stax76
e7b7f33b1b translation 2024-07-25 10:53:30 +02:00
stax76
01c2171a62 translation update 2024-07-25 10:34:09 +02:00
stax76
321dc13531 Merge pull request #699 from DogancanYr/patch-2
Update tr.po
2024-07-25 10:13:32 +02:00
DogancanYr
4032e8be7b Update tr.po 2024-07-20 21:21:24 +03:00
stax76
e52de1d1a7 v7.1.1.1 2024-07-20 03:03:42 +02:00
stax76
7c38e823c1 fix #676 2024-07-17 02:44:48 +02:00
stax76
e6defd3e55 #696 2024-07-16 00:04:15 +02:00
stax76
3caf4f2cb3 Bindings and menu item fix 2024-07-15 08:01:21 +02:00
stax76
3f897b12cf Yet another try to fix actions/workflow/auto build 2024-07-15 07:41:47 +02:00
stax76
12d0126dd5 Again try to fix actions/workflow/auto build 2024-07-15 07:32:30 +02:00
stax76
b218619b2b Try fixing auto/action/workflow build 2024-07-15 06:39:02 +02:00
stax76
ae80076f36 Full support for select.lua
select.lua is a new simple command palette script
embedded into mpv/libmpv.

In the context menu select.lua features can be found under 'View > On Screen Menu'.

https://github.com/mpv-player/mpv/blob/master/player/lua/select.lua
2024-07-15 02:10:30 +02:00
stax76
ae9c69e469 Turkish translation added 2024-05-21 13:58:35 +02:00
stax76
cfd2919e88 Merge pull request #683 from DogancanYr/patch-1
Turkish translation.
2024-05-21 13:04:56 +02:00
DogancanYr
985460d98e Update tr.po 2024-05-07 23:56:36 +03:00
DogancanYr
7596d988b9 Update tr.po 2024-05-07 16:51:21 +03:00
DogancanYr
50cad04b47 Update tr.po 2024-05-07 00:16:42 +03:00
DogancanYr
457d93b5c4 Update tr.po 2024-05-06 19:59:09 +03:00
DogancanYr
bb2af95344 Turkish translation. 2024-05-06 19:50:53 +03:00
stax76
34e76946f3 Russian translation added 2024-04-23 06:57:08 +02:00
stax76
3f52c1255e Korean translation added and auto build update 2024-04-03 13:10:19 +02:00
stax76
924e32f027 typo 2024-02-03 06:11:28 +01:00
stax76
2f735215e0 v7.1.1.0 2024-02-03 06:03:54 +01:00
stax76
23ed1457d5 Japanese translation updated 2024-01-20 22:06:15 +01:00
stax76
52214c1e15 new screenshots 2024-01-20 01:10:18 +01:00
stax76
09de4a5e05 Chinese translation updated 2024-01-19 09:05:32 +01:00
stax76
69a6754483 Merge branch 'main' of https://github.com/mpvnet-player/mpv.net 2024-01-13 14:05:59 +01:00
stax76
078756600e misc 2024-01-13 14:05:55 +01:00
stax76
5e2c7055d4 Merge pull request #648 from andywowws/patch-1
Update changelog.md
2024-01-13 14:05:37 +01:00
Andywoww
eb265be0a4 Update changelog.md
Wrong date
2024-01-13 19:33:38 +08:00
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
100 changed files with 13199 additions and 4638 deletions

View File

@@ -50,17 +50,17 @@ jobs:
msbuild MpvNet.sln /m /p:Configuration=Debug
- name: Create .mo files for localization
shell: pwsh
run: Install-Package Gettext.Tools -Force; .\lang\create-mo-files.ps1
run: Install-Package Gettext.Tools -Force; $env:Path = ((Get-Package Gettext.Tools).Source | Split-Path) + '\tools\bin;' + $env:Path; .\lang\create-mo-files.ps1
- name: Download libmpv # In principle, only update this binary file when significant feature changes occur in mpv/mpv.net
shell: msys2 {0}
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/2025-05-03-e663cbc/mpv-dev-x86_64-20250503-git-e663cbc.7z
7z x -y libmpv.7z -olibmpv
cp -f libmpv/libmpv-2.dll src/MpvNet.Windows/bin/Debug/ || true
- name: Download MediaInfo
shell: msys2 {0}
run: |
wget -nv -O MediaInfo.7z https://mediaarea.net/download/binary/libmediainfo0/23.11/MediaInfo_DLL_23.11_Windows_x64_WithoutInstaller.7z
wget -nv -O MediaInfo.7z https://mediaarea.net/download/binary/libmediainfo0/24.03/MediaInfo_DLL_24.03_Windows_x64_WithoutInstaller.7z
7z x -y MediaInfo.7z -oMediaInfo
cp -f MediaInfo/MediaInfo.dll src/MpvNet.Windows/bin/Debug/ || true
- name: Download mpvnet.com file
@@ -69,7 +69,7 @@ jobs:
wget -nv -O mpvnet.com https://github.com/mpvnet-player/file-host/releases/download/tag/mpvnet.com.txt
cp -f mpvnet.com src/MpvNet.Windows/bin/Debug/ || true
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "mpv.net-win64"
path: src/MpvNet.Windows/bin/Debug/

View File

@@ -6,7 +6,7 @@
🎞 mpv.net
==========
mpv.net is a media player for Windows that has a modern GUI.
mpv.net is a media player for Windows with a modern GUI.
The player is based on the popular [mpv](https://mpv.io) media player.
mpv.net is designed to be mpv compatible, almost all mpv features are available,
@@ -56,6 +56,7 @@ Table of contents
- [Download](#download)
- [Manual](#manual)
- [Screenshots](#screenshots)
- [Contributing](#contributing)
Features that mpv and mpv.net have in common
@@ -66,7 +67,7 @@ Features that mpv and mpv.net have in common
- JSON IPC to control the player with a external programs
- On Screen Controller (OSC, play control buttons) with modern flat design
- Command Line Interface
- Started from a terminal status, error and debug output is printed on the terminal
- Started from a terminal, status, error and debug output is printed on the terminal
- DXVA2 video decoding acceleration
- Video output capable of features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more
- Browser extensions to start mpv.net from the browser
@@ -85,14 +86,11 @@ Features exclusive to mpv.net
- Very high degree of mpv compatibility, almost all mpv features are available
- Modern graphical user interface with customizable color themes
- Customizable context menu defined in the same file as the key bindings
- Customizable context menu
- Searchable config editor
- Searchable input (shorcut keys) editor
- C# and PowerShell Scripting
- Global keyboard shortcuts
- Extension API for .NET languages (C#, VB.NET and F#)
- Portable, MS Store or WinGet download and installation
- File history feature to log time and filename
- Files can be enqueued from File Explorer
@@ -111,6 +109,11 @@ Features exclusive to mpv.net
[The mpv.net documentation.](docs/manual.md)
## [Contributing](docs/contributing.md)
[Contributing section of the manual.](docs/manual.md#contributing)
Screenshots
-----------
@@ -121,27 +124,24 @@ Screenshots
#### Context Menu
Context menu using dark mode.
![Context Menu](docs/img/Menu.jpg)
![Context Menu](docs/img/Menu.webp)
#### Config Editor
Searchable config editor as alternative to edit the conf file manually.
![](docs/img/ConfEditor.png)
![](docs/img/ConfEditor.webp)
#### Terminal
OSD console and status printed on the terminal.
![](docs/img/Terminal.png)
![](docs/img/Terminal.webp)
#### Input Editor
Other projects from me
----------------------
Searchable key and mouse binding editor.
A list of my other projects can be found here:
![Input Editor](docs/img/InputEditor.webp)
https://stax76.github.io/software-list

View File

@@ -1,8 +1,178 @@
# v7.0.0.2 Beta (2023-12-??)
# v7.1.2.0 (2026-01-09)
- libmpv updated to v0.41 2026-01-09.
- Some adjustments to recent mpv changes.
- The Japanese and Turkish translations were updated. Thanks to the translators!
# v7.1.1.5 Beta (2025-11-20)
- Same as in mpv the `?` and `t-4` keys can be used to show the active
key bindings on-screen, it supports scrolling and searching.
In the context menu it's located at:
`View > More > Show Active Bindings On-Screen`
- Bindings of select.lua menus have changed:
`F1` On-Screen menu
`F2` Bindings
`F3` Properties
`F4` Commands
- The German, Chinese, Japanese and Turkish translations were updated. Thanks to the translators!
- Users need to install .NET 10 LTS (Long Term Support), it should run on Windows 10.
It was requested by users to prefer LTS over STS (Short Term Support).
- libmpv and MediaInfo was updated.
# v7.1.1.4 Beta (2025-10-05)
- Support for select.lua has been added. It's a new Lua script built
directly into mpv like the osc or console script. It's similar to command_palete.lua.
- Fix --script-opt not working.
- The mpv.net manual was updated.
- The Turkish translation was updated. A Bulgarian translation was added.
Thanks to the translators!
- The required Dotnet version changed from 6.0 to 9.0. This drops Win 7 support
unfortunately. It was done to use new C# language features and make
the mpv.net project more attractive for new developers to contribute.
Also most users prefer having the newest runtime.
- auto build has been disabled because it requires updating libmpv and
mediainfo all the time which is too much manual work.
- The script src/Tools/update-mpv.ps1 has been improved. It's the easiest way
update mpv and libmpv (x64 and ARM64). Shinshiro has a update script too,
but it's a lot longer and more complex.
- mediainfo and libmpv have been updated.
# v7.1.1.3 Beta (2024-10-20)
- Support for autocreate-playlist, video-exts, audio-exts, image-exts.
Windows 7 support should still work, but needs auto-load-folder to be enabled
or autoload.lua.
- The command palette user script is installable from the context menu under
`Settings > Setup > Install Command Palette`. The command palette features
are shown in the menu under 'View > Command Palette'.
- New command to select the stream quality `Video > Stream Quality (Alt+q)`,
this calls the Stream Quality feature of the command palette.
- The Command Palette interacts with mpv.net to enable the Recent Files
feature in the Command Palette.
- New zhongfly libmpv x64 build.
- New Andarwinux libmpv ARM64 build.
# v7.1.1.2 Beta (2024-10-10)
- Polish translation fixed. German, Turkish and Japanese translation updated.
French translation added! Thanks to the translation team!
- Support of relative folders from command line.
- Support for the mpv option `cursor-autohide`.
- A issue with the support of the mpv property `title-bar` has been fixed,
at the moment this is most useful for users of the popular uosc user script,
the mpv built-in OSC doesn't fully support it yet.
- `media-controls=yes` is now enabled by default, this enables play controls
in the `KDE Connect` android app.
- The mpv.net option `auto-load-folder` by default is now disabled and the
option is deprecated. The reason for this is mpv has new native support
for it using `autocreate-playlist`, which mpv.net uses now instead by default.
- New zhongfly libmpv x64 build.
- New Andarwinux libmpv ARM64 build.
# v7.1.1.1 Beta (2024-07-20)
- Korean, Russian and Turkish translation added, Japanese translation fixed. Thanks to the translation team!
- Action/Workflow/Auto build fix and update.
- New default bindings and menu items for select.lua which is a new simple mpv built-in command palette script.
In the context menu select.lua features can be found under `View > On Screen Menu`.
https://github.com/mpv-player/mpv/blob/master/player/lua/select.lua
- New PowerShell script 'Tools\release-mpv.net.ps1' used to releases mpv.net on GitHub.
- Fix DVD ISO file support.
- MediaInfo updated to version v24.6.
- New ARM64 support.
- New zhongfly libmpv x64 build.
- New Andarwinux libmpv ARM64 build.
# v7.1.1.0 (2024-02-03)
- Chinese and Japanese translation updated. Thanks to the translation team!
- Fix command line arguments being ignored in some situations.
# v7.1.0.0 (2024-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 (2024-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 incorrect in the main 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:`
@@ -21,7 +191,7 @@
- Fix message box exceding working area size.
- C# and PowerShell scripting was removed because of a compatibility problem
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.
- 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.
@@ -1002,4 +1172,4 @@ stable release, no changes since the last beta
- new feature added to manage file associations from within the app. It can be found in the menu at: Tools > Manage... [Default Binding](https://github.com/mpvnet-player/mpv.net/blob/main/mpv.net/Resources/input.conf.txt#L149)
- new zip download option added
- new x86 download option added
- new x86 download option added

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

BIN
docs/img/ConfEditor.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 KiB

After

Width:  |  Height:  |  Size: 429 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

BIN
docs/img/Menu.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 KiB

BIN
docs/img/Terminal.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,20 @@
$ErrorActionPreference = 'Stop'
$PoFiles = Get-ChildItem $PSScriptRoot/po
$ExeFolder = "$PSScriptRoot/../src/MpvNet.Windows/bin/Debug"
function CreateFolder
{
param($path)
if (-not (Test-Path $path))
{
mkdir $path
}
if (-not (Test-Path $path))
{
throw
}
}
foreach ($it in $PoFiles)
{
$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 | Out-Null
}
$moPath = "$folder/mpvnet.mo"
msgfmt --output-file=$moPath $it.FullName
if ($LastExitCode) { throw $LastExitCode }
$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\Chapter.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\FileTypes.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\Player.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\Translator.cs
D:\Projects\CS\mpv.net\src\MpvNet\ExtensionMethod\ObjectExtension.cs
@@ -35,15 +37,12 @@ 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\Program.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\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\Taskbar.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Native\WinApi.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\Properties\Resources.Designer.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\UI\CommandPalette.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\UI\CommandPaletteItem.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\UI\GlobalHotkey.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\UI\Theme.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\UI\TreeNode.cs
@@ -51,6 +50,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\SnapManager.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\InputWindow.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\ISettingControl.cs
@@ -59,7 +59,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\WpfApplication.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\WpfTranslator.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\CommandPaletteControl.xaml.cs
D:\Projects\CS\mpv.net\src\MpvNet.Windows\WPF\Controls\ComboBoxSettingControl.xaml.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\SearchControl.xaml.cs

1013
lang/po/bg.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1028
lang/po/fr.po Normal file

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,997 @@
# 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, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-06 00:24+0200\n"
"PO-Revision-Date: 2023-12-08 00:34+0000\n"
"Last-Translator: ever_green, 2025\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:372
msgid "Recent Files"
msgstr "最近のファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:23
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:201
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:233
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:203
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:204
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:205
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:206
msgid "Play/Pause"
msgstr "再生/一時停止"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:26
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:207
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:214
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:216
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:218
msgid "Previous File"
msgstr "前のファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:29
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:215
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:217
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:219
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:393
msgid "Title"
msgstr "タイトル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:51
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:351
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:453
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: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
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:289
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
msgctxt "Volume"
msgid "Up"
msgstr "上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:108
msgctxt "Volume"
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
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:136
#: 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
msgid "View"
msgstr "表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:120
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:127
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:234
msgid "Playlist"
msgstr "プレイリスト"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:121
msgid "Toggle Statistics"
msgstr "統計情報の切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:122
msgid "Toggle OSC Visibility"
msgstr "OSC 表示の切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:123
msgid "Media Info On-Screen"
msgstr "画面メディア情報"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:124
msgid "Media Info Message Box"
msgstr "メッセージメディア情報"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:125
msgid "Progress"
msgstr "再生位置"
#: 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
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:136
#: 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:248
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:249
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:250
msgid "On-Screen Menu"
msgstr "画面メニュー"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:128
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:246
msgid "Bindings"
msgstr "バインディング"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:129
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:247
msgid "Properties"
msgstr "プロパティ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:130
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:240
msgid "Chapters"
msgstr "チャプター"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:131
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:239
msgid "Tracks"
msgstr "トラック"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:132
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:237
msgid "Audio Tracks"
msgstr "オーディオトラック"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:133
msgid "Subtitle Tracks"
msgstr "字幕トラック"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:134
msgid "Secondary Subtitle"
msgstr "セカンダリ字幕"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:135
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:238
msgid "Video Tracks"
msgstr "ビデオトラック"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:136
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:241
msgid "Editions"
msgstr "エディション"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:137
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:242
msgid "Subtitle Lines"
msgstr "字幕ライン"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:138
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:243
msgid "Audio Devices"
msgstr "オーディオデバイス"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:139
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:244
msgid "Watch History"
msgstr "再生履歴"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:140
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:245
msgid "Watch Later"
msgstr "後で再生"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:142
msgid "Console"
msgstr "コンソール"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:143
msgid "Commands"
msgstr "コマンド"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:144
msgid "Active Bindings In Text Editor"
msgstr "キーバインドをエディタで編集"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:145
msgid "Active Bindings On-Screen"
msgstr "キーバインドを画面に表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:146
msgid "Keys"
msgstr "キー"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:147
msgid "Protocols"
msgstr "プロトコル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:148
msgid "Decoders"
msgstr "デコーダー"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:149
msgid "Demuxers"
msgstr "デマルチプレクサ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:151
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:152
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:153
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:154
#: 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
msgid "Window"
msgstr "ウィンドウ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:151
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:221
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:222
msgid "Fullscreen"
msgstr "フルスクリーン"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:152
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:153
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:154
#: 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
msgid "Zoom"
msgstr "ズーム"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:152
msgid "Enlarge"
msgstr "拡大"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:153
msgid "Shrink"
msgstr "縮小"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:155
msgid "50 %"
msgstr "50 %"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:156
msgid "100 %"
msgstr "100 %"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:157
msgid "200 %"
msgstr "200 %"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:158
msgid "300 %"
msgstr "300 %"
#: 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
msgid "Move"
msgstr "移動"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:159
msgctxt "Move"
msgid "Left"
msgstr "左へ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:160
msgctxt "Move"
msgid "Right"
msgstr "右へ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:161
msgctxt "Move"
msgid "Up"
msgstr "上へ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:162
msgctxt "Move"
msgid "Down"
msgstr "下へ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:163
msgctxt "Move"
msgid "Center"
msgstr "中央"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:164
msgid "Toggle Border"
msgstr "ボーダーの切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:165
msgid "Toggle On Top"
msgstr "常に手前に表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:167
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:426
msgid "Profile"
msgstr "プロファイル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:169
#: 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
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:175
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:176
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:177
#: 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
msgid "Config"
msgstr "設定"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:169
msgid "Show Config Editor"
msgstr "構成エディターを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:170
msgid "Show Input Editor"
msgstr "入力エディターを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:172
msgid "Edit mpv.conf"
msgstr "mpv.conf の編集"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:173
msgid "Edit input.conf"
msgstr "input.conf の編集"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:175
msgid "Open Config Folder"
msgstr "構成フォルダを開く"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:176
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:177
#: 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
msgid "Setup"
msgstr "セットアップ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:176
msgid "Register video file associations"
msgstr "ビデオファイルの関連付けを登録"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:177
msgid "Register audio file associations"
msgstr "オーディオファイルの関連付けを登録"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:178
msgid "Register image file associations"
msgstr "画像ファイルの関連付けを登録"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:179
msgid "Unregister file associations"
msgstr "ファイルの関連付けの登録解除"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:181
msgid "Add mpv.net to Path environment variable"
msgstr "mpv.net を Path 環境変数へ追加"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:182
msgid "Remove mpv.net from Path environment variable"
msgstr "mpv.net を Path 環境変数から削除"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:184
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:185
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:186
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:187
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:188
msgid "Tools"
msgstr "ツール"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:184
msgid "Set/clear A-B loop points"
msgstr "A-B 区間ループの設定/解除"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:185
msgid "Toggle infinite file looping"
msgstr "無限ファイルループの切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:186
msgid "Shuffle Playlist"
msgstr "プレイリストをシャッフル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:187
msgid "Toggle Hardware Decoding"
msgstr "ハードウェアデコードの切り替え"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:188
msgid "Exit Watch Later"
msgstr "後で再生を解除"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:190
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:477
msgid "Custom"
msgstr "カスタム"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:192
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:193
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:194
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:195
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:196
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:197
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:198
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:199
msgid "Help"
msgstr "ヘルプ"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:192
msgid "Website mpv"
msgstr "mpv ウェブサイト"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:193
msgid "Website mpv.net"
msgstr "mpv.net ウェブサイト"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:195
msgid "Manual mpv"
msgstr "mpv マニュアル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:196
msgid "Manual mpv.net"
msgstr "mpv.net マニュアル"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:198
msgid "awesome-mpv"
msgstr "awesome-mpv"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:199
msgid "About mpv.net"
msgstr "mpv.net のバージョン情報"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:202
msgid "Show Menu"
msgstr "メニューを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:208
msgid "Forward"
msgstr "進む"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:209
msgid "Backward"
msgstr "戻る"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:210
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:212
msgid "Volume Up"
msgstr "音量を上げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:211
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:213
msgid "Volume Down"
msgstr "音量を下げる"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:220
msgid "Ignore left mouse butten"
msgstr "マウスの左ボタンを無視"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:223
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:225
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:231
msgid "Seek Forward"
msgstr "早送り"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:224
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:226
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:232
msgid "Seek Backward"
msgstr "早戻し"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:227
msgid "Undo previous (or marked) seek"
msgstr "直前の (またはマークした) シークを元に戻す"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:228
msgid "Mark position for revert-seek"
msgstr "戻り位置をマーク"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:229
msgid "Seek to previous subtitle"
msgstr "前の字幕へ戻る"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:230
msgid "Seek to next subtitle"
msgstr "次の字幕へ進む"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:235
msgid "Subtitles"
msgstr "字幕"
#: D:\Projects\CS\mpv.net\src\MpvNet\InputHelp.cs:236
msgid "Secondary Subtitles"
msgstr "セカンダリ字幕"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:192
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:214
msgid "Files/URLs were added to the playlist"
msgstr "ファイル/URL がプレイリストへ追加されました"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:207
msgid "The clipboard does not contain a valid URL or file."
msgstr "クリップボードに有効な URL またはファイルが含まれていません。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:262
msgid "File Explorer icons will refresh after process restart."
msgstr "ファイルエクスプローラーのアイコンは、プロセスの再起動後に更新されます。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:265
msgid "File associations were successfully removed."
msgstr "ファイルの関連付けは正常に削除されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:267
msgid "File associations were successfully created."
msgstr "ファイルの関連付けが正常に作成されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:270
msgid "Error creating file associations."
msgstr "ファイルの関連付けの作成中にエラーが発生しました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:387
msgid "mpv.net is already in the Path environment variable."
msgstr "mpv.net は既に Path 環境変数にあります。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:395
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:404
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:413
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:418
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:423
msgid "This feature was removed, but there are user scripts:"
msgstr "この機能は削除されましたが、ユーザースクリプトがあります:"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\GuiCommand.cs:427
msgid "This feature was removed."
msgstr "この機能は削除されました。"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\Properties\Resources.Designer.cs:79
msgid "editor_conf"
msgstr "editor_conf"
#: 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:388
msgid "Clear List"
msgstr "リストをクリア"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:448
msgid "Show Profiles"
msgstr "プロファイルを表示"
#: D:\Projects\CS\mpv.net\src\MpvNet.Windows\WinForms\MainForm.cs:1432
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 "変更は次回の起動時に利用可能になります。"

1020
lang/po/ko.po Normal file

File diff suppressed because it is too large Load Diff

1022
lang/po/pl.po Normal file

File diff suppressed because it is too large Load Diff

1022
lang/po/ru.po Normal file

File diff suppressed because it is too large Load Diff

1009
lang/po/tr.po Normal file

File diff suppressed because it is too large Load Diff

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
Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' |
Where-Object { $_ -notmatch '[/\\]obj[/\\]' } |
@@ -6,7 +8,8 @@ Get-ChildItem $PSScriptRoot/.. -Recurse -File -Filter '*.cs' |
Out-File $PSScriptRoot/cs-files.txt
# Create .pot file
xgettext --force-po --from-code=UTF-8 '--language=c#' -o $PSScriptRoot/source.pot --files-from=$PSScriptRoot/cs-files.txt --keyword=_
xgettext -k_ -k_n:1,2 -k_p:1c,2 -k_pn:1c,2,3 --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
$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
(Get-ChildItem $PSScriptRoot/PO -Filter '*.po').FullName |
ForEach-Object { msgmerge --sort-output --backup=none --update $_ $PSScriptRoot/source.pot }
if ($LastExitCode) { throw $LastExitCode }

View File

@@ -5,3 +5,6 @@ csharp_style_implicit_object_creation_when_type_is_apparent = true
# IDE0090: Use 'new(...)'
dotnet_diagnostic.IDE0090.severity = silent
# WFO1000: A property should determine its property content serialization with the DesignerSerializationVisibilityAttribute, DefaultValueAttribute or the ShouldSerializeProperty method
dotnet_diagnostic.WFO1000.severity = silent

View File

@@ -0,0 +1,6 @@
<Project>
<PropertyGroup>
<Product>mpv.net</Product>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,10 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageVersion Include="NGettext" Version="0.6.7" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
</ItemGroup>
</Project>

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,73 +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>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
<EntryPointProjectUniqueName>..\MpvNet.Windows\MpvNet.Windows.csproj</EntryPointProjectUniqueName>
</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="..\MpvNet.Windows\bin\Debug\libmpv-2.dll">
<Link>libmpv-2.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\MpvNet.Windows\bin\Debug\MediaInfo.dll">
<Link>MediaInfo.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\MpvNet.Windows\bin\Debug\mpvnet.com">
<Link>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" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MpvNet.Windows\MpvNet.Windows.csproj" />
</ItemGroup>
</Project>

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

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

View File

@@ -53,6 +53,7 @@ public class Conf
if (section.HasName("help")) baseSetting.Help = section.GetValue("help");
if (section.HasName("url")) baseSetting.URL = section.GetValue("url");
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 (baseSetting.Help.ContainsEx("\\n"))
@@ -90,6 +91,9 @@ public class ConfParser
{
string line = it.Trim();
if (line.StartsWith('#'))
continue;
if (line == "")
{
currentGroup = new ConfSection();
@@ -97,8 +101,8 @@ public class ConfParser
}
else if (line.Contains('='))
{
string name = line[..line.IndexOf("=")].Trim();
string value = line[(line.IndexOf("=") + 1)..].Trim();
string name = line[..line.IndexOf('=')].Trim();
string value = line[(line.IndexOf('=') + 1)..].Trim();
currentGroup?.Items.Add(new StringPair(name, value));
}

View File

@@ -13,7 +13,7 @@ public static class FileAssociation
string exeFilename = Path.GetFileName(exePath);
string exeFilenameNoExt = Path.GetFileNameWithoutExtension(exePath);
string[] protocols = { "ytdl", "rtsp", "srt", "srtp" };
string[] protocols = ["ytdl", "rtsp", "srt", "srtp"];
if (perceivedType != "unreg")
{

View File

@@ -1,5 +1,6 @@

using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Windows.Forms;
@@ -11,6 +12,8 @@ using MpvNet.Windows.WinForms;
using MpvNet.Windows.WPF.Views;
using MpvNet.Windows.WPF;
using MpvNet.Windows.WPF.MsgBox;
using MpvNet.Windows.Help;
using MpvNet.Help;
namespace MpvNet;
@@ -27,41 +30,53 @@ public class GuiCommand
public Dictionary<string, Action<IList<string>>> Commands => _commands ??= new()
{
["show-about"] = args => ShowDialog(typeof(AboutWindow)),
["show-conf-editor"] = args => ShowDialog(typeof(ConfWindow)),
["show-input-editor"] = args => ShowDialog(typeof(InputWindow)),
["show-audio-devices"] = args => Msg.ShowInfo(Player.GetPropertyOsdString("audio-device-list")),
["show-profiles"] = args => Msg.ShowInfo(Player.GetProfiles()),
["add-to-path"] = args => AddToPath(),
["edit-conf-file"] = EditCongFile,
["load-audio"] = LoadAudio,
["load-sub"] = LoadSubtitle,
["move-window"] = args => MoveWindow?.Invoke(args[0]),
["open-clipboard"] = OpenFromClipboard,
["open-files"] = OpenFiles,
["open-optical-media"] = Open_DVD_Or_BD_Folder,
["load-audio"] = LoadAudio,
["open-clipboard"] = OpenFromClipboard,
["reg-file-assoc"] = RegisterFileAssociations,
["remove-from-path"] = args => RemoveFromPath(),
["scale-window"] = args => ScaleWindow?.Invoke(float.Parse(args[0], CultureInfo.InvariantCulture)),
["show-media-info"] = ShowMediaInfo,
["move-window"] = args => MoveWindow?.Invoke(args[0]),
["window-scale"] = args => WindowScaleNet?.Invoke(float.Parse(args[0], CultureInfo.InvariantCulture)),
["show-menu"] = args => ShowMenu?.Invoke(),
["show-about"] = args => ShowDialog(typeof(AboutWindow)),
["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 => Player.Command("script-binding select/show-properties"),
["show-protocols"] = args => ShowProtocols(),
["window-scale"] = args => WindowScaleNet?.Invoke(float.Parse(args[0], CultureInfo.InvariantCulture)),
// deprecated
["show-info"] = args => ShowMediaInfo(new[] { "osd" }), // deprecated
["show-recent"] = args => ShowRemoved(), // deprecated
["quick-bookmark"] = args => QuickBookmark(), // deprecated
["show-history"] = args => ShowHistory(), // deprecated
["show-command-palette"] = args => ShowCommandPalette(), // deprecated
["show-playlist"] = args => Player.Command("script-binding select/select-playlist"), // deprecated
["show-command-palette"] = args => Player.Command("script-binding select/select-binding"), // deprecated
["show-audio-tracks"] = args => Player.Command("script-binding select/select-aid"), // deprecated
["show-subtitle-tracks"] = args => Player.Command("script-binding select/select-sid"), // deprecated
["show-audio-devices"] = args => Player.Command("script-binding select/select-audio-device"), // deprecated
};
public void ShowDialog(Type winType)
void ShowDialog(Type winType)
{
Window? win = Activator.CreateInstance(winType) as Window;
new WindowInteropHelper(win).Owner = MainForm.Instance!.Handle;
win?.ShowDialog();
}
public void LoadSubtitle(IList<string> args)
void LoadSubtitle(IList<string> args)
{
using var dialog = new OpenFileDialog();
string path = Player.GetPropertyString("path");
@@ -76,7 +91,7 @@ public class GuiCommand
Player.CommandV("sub-add", filename);
}
public void OpenFiles(IList<string> args)
void OpenFiles(IList<string> args)
{
bool append = false;
@@ -90,7 +105,7 @@ public class GuiCommand
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();
@@ -98,33 +113,109 @@ public class GuiCommand
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))
{
string msg = $"{args[0]} does not exist. Would you like to create it?";
if (Msg.ShowQuestion(msg) == MessageBoxResult.OK)
File.WriteAllText(file, "");
}
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" + BR;
ShowTextWithEditor("Input Commands", header + sb.ToString());
}
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())
{
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
{
string clipboard = System.Windows.Forms.Clipboard.GetText();
List<string> files = new List<string>();
List<string> files = [];
foreach (string i in clipboard.Split(BR.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
{
if (i.Contains("://") || File.Exists(i))
files.Add(i);
}
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;
}
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();
string path = Player.GetPropertyString("path");
@@ -134,21 +225,25 @@ public class GuiCommand
dialog.Multiselect = true;
if (dialog.ShowDialog() == DialogResult.OK)
foreach (string i in dialog.FileNames)
Player.CommandV("audio-add", i);
if (dialog.ShowDialog() != DialogResult.OK)
return;
foreach (string i in dialog.FileNames)
{
Player.CommandV("audio-add", i);
}
}
public void RegisterFileAssociations(IList<string> args)
void RegisterFileAssociations(IList<string> args)
{
string perceivedType = args[0];
string[] extensions = Array.Empty<string>();
switch (perceivedType)
{
case "video": extensions = FileTypes.Video; break;
case "audio": extensions = FileTypes.Audio; break;
case "image": extensions = FileTypes.Image; break;
case "video": extensions = FileTypes.GetVideoExts(); break;
case "audio": extensions = FileTypes.GetAudioExts(); break;
case "image": extensions = FileTypes.GetImgExts(); break;
}
try
@@ -177,7 +272,21 @@ public class GuiCommand
catch { }
}
public void ShowMediaInfo(IList<string> args)
class Obj
{
public string title { get; set; } = "";
public int selected_index { get; set; } = 0;
public Item[] items { get; set; } = [];
}
class Item
{
public string[] value { get; set; } = [];
public string title { get; set; } = "";
public string hint { get; set; } = "";
}
void ShowMediaInfo(IList<string> args)
{
if (Player.PlaylistPos == -1)
return;
@@ -194,13 +303,13 @@ public class GuiCommand
if (File.Exists(path) && osd)
{
if (FileTypes.Audio.Contains(path.Ext()))
if (FileTypes.IsAudio(path.Ext()))
{
text = Player.GetPropertyOsdString("filtered-metadata");
Player.CommandV("show-text", text, "5000");
return;
}
else if (FileTypes.Image.Contains(path.Ext()))
else if (FileTypes.IsImage(path.Ext()))
{
fileSize = new FileInfo(path).Length;
@@ -234,21 +343,27 @@ public class GuiCommand
}
if (App.MediaInfo && !osd && File.Exists(path) && !path.Contains(@"\\.\pipe\"))
using (MediaInfo mediaInfo = new MediaInfo(path))
text = Regex.Replace(mediaInfo.GetSummary(full, raw), "Unique ID.+", "");
{
using MediaInfo mediaInfo = new MediaInfo(path);
text = Regex.Replace(mediaInfo.GetSummary(full, raw), "Unique ID.+", "");
}
else
{
Player.UpdateExternalTracks();
text = "N: " + Player.GetPropertyString("filename") + BR;
lock (Player.MediaTracksLock)
{
foreach (MediaTrack track in Player.MediaTracks)
{
text += track.Text + BR;
}
}
}
text = text.TrimEx();
if (editor)
Command.ShowTextWithEditor("media-info", text);
ShowTextWithEditor("media-info", text);
else if (osd)
Command.ShowText(text.Replace("\r", ""), 5000, 16);
else
@@ -259,64 +374,55 @@ 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)
return;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++)
if (path.Contains(Folder.Startup.TrimEnd(Path.DirectorySeparatorChar), StringComparison.CurrentCultureIgnoreCase))
{
string name = Player.GetPropertyString($"playlist/{i}/title");
if (string.IsNullOrEmpty(name))
name = Player.GetPropertyString($"playlist/{i}/filename").FileName();
sb.AppendLine(name);
Msg.ShowWarning(_("mpv.net is already in the Path environment variable."));
return;
}
string header = BR + "For a playlist menu the following user scripts exist:" + 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" + BR2;
Environment.SetEnvironmentVariable("Path",
Folder.Startup.TrimEnd(Path.DirectorySeparatorChar) + ";" + path,
EnvironmentVariableTarget.User);
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
public void QuickBookmark() =>
Msg.ShowInfo("This feature was moved to a user script,\nwhich can be found here:\n\n" +
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
public void ShowHistory() =>
Msg.ShowInfo("This feature was moved to a user script,\nwhich can be found here:\n\n" +
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
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#search_menu" + BR +
"https://github.com/tomasklaen/uosc");
void ShowRemoved() => Msg.ShowInfo(_("This feature was removed."));
}
//public void ShowCommandPalette()
//{
// MainForm.Instance?.BeginInvoke(() => {
// CommandPalette.Instance.SetItems(CommandPalette.GetItems());
// MainForm.Instance.ShowCommandPalette();
// CommandPalette.Instance.SelectFirst();
// });
//}

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 AdjustWindowRectangle(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
AdjustWindowRect(ref rc, style, false);
}
public static void AddWindowBorders(IntPtr hwnd, ref RECT rc, int dpi, bool changeTop)
{
RECT win = rc;
AdjustWindowRectangle(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();
AdjustWindowRectangle(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

@@ -1,49 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<RootNamespace>MpvNet.Windows</RootNamespace>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows7.0</TargetFramework>
<RootNamespace>MpvNet.Windows</RootNamespace>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<PublishSingleFile>true</PublishSingleFile>
<AssemblyName>mpvnet</AssemblyName>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>mpv-icon.ico</ApplicationIcon>
<Product>mpv.net</Product>
<FileVersion>7.0.0.1</FileVersion>
<AssemblyVersion>7.0.0.1</AssemblyVersion>
<InformationalVersion>7.0.0.1</InformationalVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<AssemblyName>mpvnet</AssemblyName>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>mpv-icon.ico</ApplicationIcon>
<FileVersion>7.1.2.0</FileVersion>
<AssemblyVersion>7.1.2.0</AssemblyVersion>
<InformationalVersion>7.1.2.0</InformationalVersion>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Misc\**" />
<EmbeddedResource Remove="Misc\**" />
<None Remove="Misc\**" />
<Page Remove="Misc\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Misc\**" />
<EmbeddedResource Remove="Misc\**" />
<None Remove="Misc\**" />
<Page Remove="Misc\**" />
</ItemGroup>
<ItemGroup>
<Content Include="mpv-icon.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="mpv-icon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MpvNet\MpvNet.csproj" />
<ProjectReference Include="..\NGettext.Wpf\NGettext.Wpf.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MpvNet\MpvNet.csproj" />
<ProjectReference Include="..\NGettext.Wpf\NGettext.Wpf.csproj" />
</ItemGroup>
<ItemGroup>
<Page Update="WPF\Views\AboutWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<XamlRuntime>Wpf</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="WPF\Views\AboutWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<XamlRuntime>Wpf</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
</ItemGroup>
</Project>

View File

@@ -1,13 +1,13 @@

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

View File

@@ -7,7 +7,6 @@ using MpvNet.Help;
using MpvNet.Windows.UI;
using MpvNet.Windows.Help;
using MpvNet.Windows.WPF;
using System.Diagnostics;
namespace MpvNet.Windows;
@@ -42,7 +41,7 @@ static class Program
Theme.Init();
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("--o="))
{
@@ -97,11 +96,14 @@ static class Program
return;
}
if (App.CommandLine.Contains("--o="))
if (ProcessCommandLineArguments())
Environment.GetCommandLineArgs();
else if (App.CommandLine.Contains("--o="))
{
App.AutoLoadFolder = false;
Player.Init(IntPtr.Zero);
Player.ProcessCommandLineFiles();
Player.Init(IntPtr.Zero, true);
CommandLine.ProcessCommandLineArgsPostInit();
CommandLine.ProcessCommandLineFiles();
Player.SetPropertyString("idle", "no");
Player.EventLoop();
Player.Destroy();
@@ -119,4 +121,48 @@ static class Program
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 int Width { get; set; }
public int OptionNameWidth { get; set; } = 100;
public ConfItem? ConfItem { get; set; }
}
@@ -35,12 +36,13 @@ public class OptionSettingOption
public string? Name { get; set; }
public string? Help { get; set; }
public int Width { get => OptionSetting!.OptionNameWidth; }
public OptionSetting? OptionSetting { get; set; }
public string? Text
{
get => string.IsNullOrEmpty(_text) ? Name : _text;
get => _text ?? Name;
set => _text = value;
}

View File

@@ -1,22 +0,0 @@

using MpvNet.Windows.WPF.Controls;
namespace MpvNet.Windows.UI;
public class CommandPalette
{
public static CommandPaletteControl Instance { get; } = new CommandPaletteControl();
public static IEnumerable<CommandPaletteItem> GetItems()
{
return InputHelp.GetBindingsFromContent(App.InputConf.GetContent())
.Where(i => i.Command != "")
.Select(i => new CommandPaletteItem()
{
Text = i.Comment,
SecondaryText = i.Input,
Action = () => Core.Command(i.Command),
Binding = i
});
}
}

View File

@@ -1,25 +0,0 @@

namespace MpvNet.Windows.UI;
public class CommandPaletteItem
{
public CommandPaletteItem() { }
public CommandPaletteItem(string text, Action action)
{
Text = text;
Action = action;
}
public CommandPaletteItem(string text, string secondaryText, Action action)
{
Text = text;
Action = action;
SecondaryText = secondaryText;
}
public string Text { get; set; } = "";
public string SecondaryText { get; set; } = "";
public Action? Action { get; set; }
public Binding? Binding { get; set; }
}

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

View File

@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@@ -19,13 +20,16 @@ namespace MpvNet.Windows.WPF;
public partial class ConfWindow : Window, INotifyPropertyChanged
{
List<Setting> Settings = Conf.LoadConf(Properties.Resources.editor_conf.TrimEnd());
List<ConfItem> ConfItems = new List<ConfItem>();
public ObservableCollection<string> FilterStrings { get; } = new();
string InitialContent;
string ThemeConf = GetThemeConf();
List<Setting> _settings = Conf.LoadConf(Properties.Resources.editor_conf.TrimEnd());
List<ConfItem> _confItems = new List<ConfItem>();
string _initialContent;
string _themeConf = GetThemeConf();
string? _searchText;
List<NodeViewModel>? _nodes;
bool _shown;
int _useSpace;
int _useNoSpace;
public event PropertyChangedEventHandler? PropertyChanged;
public ConfWindow()
@@ -34,8 +38,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
DataContext = this;
LoadConf(Player.ConfPath);
LoadConf(App.ConfPath);
LoadLibplaceboConf();
LoadSettings();
InitialContent = GetCompareString();
_initialContent = GetCompareString();
if (string.IsNullOrEmpty(App.Settings.ConfigEditorSearch))
SearchText = "General:";
@@ -46,9 +51,11 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
SelectNodeFromSearchText(node);
foreach (var node in Nodes)
ExpandNode(node);
node.IsExpanded = true;
}
public ObservableCollection<string> FilterStrings { get; } = new();
public Theme? Theme => Theme.Current;
public string SearchText
@@ -70,7 +77,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{
var rootNode = new TreeNode();
foreach (Setting setting in Settings)
foreach (Setting setting in _settings)
AddNode(rootNode.Children, setting.Directory!);
_nodes = new NodeViewModel(rootNode).Children;
@@ -82,6 +89,9 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
public static TreeNode? AddNode(IList<TreeNode> nodes, string path)
{
if (string.IsNullOrEmpty(path))
return null;
string[] parts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
for (int x = 0; x < parts.Length; x++)
@@ -120,21 +130,23 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
void LoadSettings()
{
foreach (Setting setting in Settings)
foreach (Setting setting in _settings)
{
setting.StartValue = setting.Value;
if (!FilterStrings.Contains(setting.Directory!))
FilterStrings.Add(setting.Directory!);
foreach (ConfItem confItem in ConfItems)
foreach (ConfItem item in _confItems)
{
if (setting.Name == confItem.Name && confItem.Section == "" && !confItem.IsSectionItem)
if (setting.Name == item.Name &&
setting.File == item.File &&
item.Section == "" && !item.IsSectionItem)
{
setting.Value = confItem.Value.Trim('\'', '"');
setting.Value = item.Value;
setting.StartValue = setting.Value;
setting.ConfItem = confItem;
confItem.SettingBase = setting;
setting.ConfItem = item;
item.SettingBase = setting;
}
}
@@ -144,7 +156,10 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
MainStackPanel.Children.Add(new StringSettingControl(s) { Visibility = Visibility.Collapsed });
break;
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;
}
}
@@ -152,59 +167,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
static string GetThemeConf() => Theme.DarkMode + App.DarkTheme + App.LightTheme;
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
App.Settings.ConfigEditorSearch = SearchText;
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());
}
string GetCompareString() => string.Join("", _settings.Select(item => item.Name + item.Value).ToArray());
void LoadConf(string file)
{
@@ -216,31 +179,46 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
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 == "")
{
comment += "\r\n";
}
else if (line.StartsWith("#"))
{
comment += line.Trim() + "\r\n";
}
else if (line.StartsWith("[") && line.Contains("]"))
else if (line.StartsWith("[") && line.Contains(']'))
{
if (!isSectionItem && comment != "" && comment != "\r\n")
ConfItems.Add(new ConfItem() {
_confItems.Add(new ConfItem() {
Comment = comment, File = Path.GetFileNameWithoutExtension(file)});
section = line.Substring(0, line.IndexOf("]") + 1);
comment = "";
isSectionItem = true;
}
else if (line.Contains("="))
else if (line.Contains('=') || Regex.Match(line, "^[\\w-]+$").Success)
{
ConfItem item = new ConfItem();
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.IsSectionItem = isSectionItem;
item.Comment = comment;
@@ -248,15 +226,21 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
item.Section = section;
section = "";
if (line.Contains("#") && !line.Contains("'") && !line.Contains("\""))
if (line.Contains('#') && !line.Contains('\'') && !line.Contains('"'))
{
item.LineComment = line.Substring(line.IndexOf("#")).Trim();
line = line.Substring(0, line.IndexOf("#")).Trim();
}
int pos = line.IndexOf("=");
string left = line.Substring(0, pos).Trim().ToLower();
string left = line.Substring(0, pos).Trim().ToLower().TrimStart('-');
string right = line.Substring(pos + 1).Trim();
if (right.StartsWith('\'') && right.EndsWith('\''))
right = right.Trim('\'');
if (right.StartsWith('"') && right.EndsWith('"'))
right = right.Trim('"');
if (left == "fs")
left = "fullscreen";
@@ -266,17 +250,79 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
item.Name = left;
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)
{
StringBuilder sb = new StringBuilder();
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)
continue;
@@ -288,7 +334,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
{
if (item.Name != "")
{
sb.Append(item.Name + " = " + item.Value);
sb.Append(item.Name + equalString + EscapeValue(item.Value));
if (item.LineComment != "")
sb.Append(" " + item.LineComment);
@@ -299,17 +345,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
}
else if ((item.SettingBase.Value ?? "") != item.SettingBase.Default)
{
string? value;
if (item.SettingBase.Type == "string" ||
item.SettingBase.Type == "folder" ||
item.SettingBase.Type == "color")
value = "'" + item.SettingBase.Value + "'";
else
value = item.SettingBase.Value;
sb.Append(item.Name + " = " + value);
sb.Append(item.Name + equalString + EscapeValue(item.SettingBase.Value!));
if (item.LineComment != "")
sb.Append(" " + item.LineComment);
@@ -319,28 +355,16 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
}
}
foreach (Setting setting in Settings)
foreach (Setting setting in _settings)
{
if (filename != setting.File || namesWritten.Contains(setting.Name!))
continue;
if ((setting.Value ?? "") != setting.Default)
{
string? value;
if (setting.Type == "string" ||
setting.Type == "folder" ||
setting.Type == "color")
value = "'" + setting.Value + "'";
else
value = setting.Value;
sb.AppendLine(setting.Name + " = " + value);
}
sb.AppendLine(setting.Name + equalString + EscapeValue(setting.Value!));
}
foreach (ConfItem item in ConfItems)
foreach (ConfItem item in _confItems)
{
if (filename != item.File || (item.Section == "" && !item.IsSectionItem))
continue;
@@ -356,7 +380,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
if (item.Comment != "")
sb.Append(item.Comment);
sb.Append(item.Name + " = " + item.Value);
sb.Append(item.Name + equalString + EscapeValue(item.Value));
if (item.LineComment != "")
sb.Append(" " + item.LineComment);
@@ -406,6 +430,47 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
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)
{
base.OnKeyDown(e);
@@ -420,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));
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)
@@ -443,6 +521,7 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
if (node.Path + ":" == SearchText)
{
node.IsSelected = true;
node.IsExpanded = true;
return;
}
@@ -459,14 +538,6 @@ public partial class ConfWindow : Window, INotifyPropertyChanged
UnselectNode(it);
}
void ExpandNode(NodeViewModel node)
{
node.IsExpanded = true;
foreach (var it in node.Children)
ExpandNode(it);
}
[RelayCommand] void ShowMpvNetSpecificSettings() => SearchText = "mpv.net";
[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

@@ -1,127 +0,0 @@
<UserControl
x:Class="MpvNet.Windows.WPF.Controls.CommandPaletteControl"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:controls="clr-namespace:MpvNet.Windows.WPF.Controls"
mc:Ignorable="d"
FontSize="13"
Loaded="OnLoaded"
Background="#111111"
>
<UserControl.InputBindings>
<KeyBinding Gesture="Esc" Command="{Binding EscapeCommand}"/>
<KeyBinding Gesture="Enter" Command="{Binding ExecuteCommand}"/>
</UserControl.InputBindings>
<Border Name="MainBorder"
BorderThickness="1,0,1,1"
CornerRadius="0,0,5,5"
Padding="0,0,0,5"
BorderBrush="{Binding Theme.MenuHighlight}"
Background="{Binding Theme.Background}"
SnapsToDevicePixels="True"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border BorderBrush="{Binding Theme.Heading}"
BorderThickness="1"
CornerRadius="3"
Margin="7"
>
<controls:SearchControl
HintText="Search"
x:Name="SearchControl"
Grid.ColumnSpan="2"
Padding="1,1,1,0"
/>
</Border>
<ListView
Name="MainListView"
Grid.Row="1"
Foreground="{Binding Theme.Foreground}"
Background="{Binding Theme.Background}"
BorderThickness="0"
MaxHeight="202"
SizeChanged="MainListView_SizeChanged"
MouseUp="MainListView_MouseUp"
>
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
<Setter Property="Height" Value="25"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="BD"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="BD" Value="{DynamicResource HighlightBrush}" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="False" />
<Condition Property="IsSelected" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="BD" Value="{DynamicResource BorderBrush}" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="3"/>
</Style>
</Style.Resources>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Text}"></TextBlock>
<TextBlock
Grid.Column="1"
Text="{Binding SecondaryText}"
HorizontalAlignment="Right"
/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Border>
</UserControl>

View File

@@ -1,151 +0,0 @@

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using MpvNet.Windows.UI;
using MpvNet.Windows.WinForms;
namespace MpvNet.Windows.WPF.Controls;
public partial class CommandPaletteControl : UserControl
{
public ICollectionView CollectionView { get; set; }
public CollectionViewSource CollectionViewSource { get; }
public ObservableCollection<CommandPaletteItem> Items { get; } = new ObservableCollection<CommandPaletteItem>();
public CommandPaletteControl()
{
InitializeComponent();
DataContext = this;
CollectionViewSource = new CollectionViewSource() { Source = Items };
CollectionView = CollectionViewSource.View;
CollectionView.Filter = new Predicate<object>(item => Filter((CommandPaletteItem)item));
MainListView.ItemsSource = CollectionView;
SearchControl.SearchTextBox.PreviewKeyDown += SearchTextBox_PreviewKeyDown;
SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged;
SearchControl.HideClearButton = true;
if (Environment.OSVersion.Version < new Version(10, 0))
MainBorder.CornerRadius = new CornerRadius(0);
}
void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
CollectionView.Refresh();
SelectFirst();
}
void SearchTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
{
int index = MainListView.SelectedIndex;
index -= 1;
if (index < 0)
index = 0;
MainListView.SelectedIndex = index;
MainListView.ScrollIntoView(MainListView.SelectedItem);
}
break;
case Key.Down:
{
int index = MainListView.SelectedIndex;
if (++index > MainListView.Items.Count - 1)
index = MainListView.Items.Count - 1;
MainListView.SelectedIndex = index;
MainListView.ScrollIntoView(MainListView.SelectedItem);
}
break;
}
}
void MainListView_SizeChanged(object sender, SizeChangedEventArgs e) => AdjustHeight();
void MainListView_MouseUp(object sender, MouseButtonEventArgs e) => ExecuteInternal();
[RelayCommand]
void Escape(object param) => MainForm.Instance?.HideCommandPalette();
[RelayCommand]
void Execute() => ExecuteInternal();
void OnLoaded(object sender, RoutedEventArgs e) => Keyboard.Focus(SearchControl.SearchTextBox);
public Theme Theme => Theme.Current!;
bool Filter(CommandPaletteItem item)
{
string filter = SearchControl.SearchTextBox.Text.ToLower();
if (item.Binding != null)
{
// TODO: CommandItem.Alias
//if (item.CommandItem.Alias.ContainsEx(filter))
// return true;
if (filter.Length == 1)
return item.Binding.Input.ToLower()
.Replace("ctrl+", "")
.Replace("shift+", "")
.Replace("alt+", "") == filter.ToLower();
if (item.Binding.Command.ToLower().Contains(filter))
return true;
}
if (filter == "" || item.Text.ToLower().Contains(filter) ||
item.SecondaryText.ToLower().Contains(filter))
return true;
return false;
}
public void SelectFirst()
{
if (MainListView.Items.Count > 0)
{
MainListView.SelectedIndex = 0;
MainListView.ScrollIntoView(MainListView.SelectedItem);
}
}
void ExecuteInternal()
{
if (MainListView.SelectedItem != null)
{
CommandPaletteItem? item = MainListView.SelectedItem as CommandPaletteItem;
MainForm.Instance?.HideCommandPalette();
item?.Action?.Invoke();
//MainForm.Instance.Voodoo(); //TODO: Voodoo
}
}
public void SetItems(IEnumerable<CommandPaletteItem> items)
{
Items.Clear();
foreach (var i in items)
Items.Add(i);
}
public void AdjustHeight()
{
double actualHeight = SearchControl.ActualHeight + MainListView.ActualHeight + 5 + 16;
int dpi = MainForm.GetDpi(MainForm.Instance!.Handle);
MainForm.Instance.CommandPaletteHost.Height = (int)(actualHeight / 96.0 * dpi);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -39,10 +39,16 @@ public partial class SearchControl : UserControl
{
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;
}
else
{
SearchTextBox.Padding = new Thickness(2, 2, 20, 2);
SearchClearButton.Visibility = Visibility.Visible;
}
}
public string Text

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,183 @@
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.Triggers>
<Trigger Property="IsMouseOver" Value="True">
@@ -53,20 +230,23 @@
</Style>
<Style TargetType="TextBox">
<Setter Property="MinHeight" Value="25" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border"
BorderBrush="{DynamicResource PrimaryTextBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="3"
SnapsToDevicePixels="True">
<Border
x:Name="border"
BorderBrush="{DynamicResource PrimaryTextBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="3"
SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
<ScrollViewer
x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
@@ -1042,5 +1222,5 @@
<Style BasedOn="{StaticResource MenuItemBaseStyle}" TargetType="MenuItem"/>
<Style BasedOn="{StaticResource MenuBaseStyle}" TargetType="Menu"/>
</ResourceDictionary>

View File

@@ -7,10 +7,19 @@ namespace MpvNet.Windows.WPF;
public class WpfTranslator : ITranslator
{
string _localizerLangauge = "";
static Language[] Languages { get; } = new Language[] {
new("english", "en", "en"),
new("bulgarian", "bg", "bg"),
new("chinese-china", "zh-CN", "zh"), // Chinese (Simplified)
new("english", "en", "en"),
new("french", "fr", "fr"),
new("german", "de", "de"),
new("japanese", "ja", "ja"),
new("korean", "ko", "ko"),
new("polish", "pl", "pl"),
new("russian", "ru", "ru"),
new("turkish", "tr", "tr"),
};
public string Gettext(string msgId)
@@ -19,10 +28,19 @@ public class WpfTranslator : ITranslator
return Translation._(msgId);
}
public string GetParticularString(string context, string text)
{
InitNGettextWpf();
return Translation.GetParticularString(context, text);
}
void InitNGettextWpf()
{
if (Translation.Localizer == null)
if (Translation.Localizer == null || _localizerLangauge != App.Language)
{
CompositionRoot.Compose("mpvnet", GetCulture(App.Language), Folder.Startup + "Locale");
_localizerLangauge = App.Language;
}
}
string GetSystemLanguage()

View File

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

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Threading;
using System.Windows.Forms.Integration;
using System.Text.RegularExpressions;
using MpvNet.Windows.WPF;
using MpvNet.Windows.UI;
@@ -18,7 +18,7 @@ using WpfControls = System.Windows.Controls;
using CommunityToolkit.Mvvm.Messaging;
using static MpvNet.Windows.Native.WinApi;
using MpvNet.Windows.Help;
using static MpvNet.Windows.Help.WinApiHelp;
namespace MpvNet.Windows.WinForms;
@@ -26,7 +26,6 @@ public partial class MainForm : Form
{
public SnapManager SnapManager = new SnapManager();
public IntPtr MpvWindowHandle { get; set; }
public ElementHost? CommandPaletteHost { get; set; }
public bool WasShown { get; set; }
public static MainForm? Instance { get; set; }
WpfControls.ContextMenu ContextMenu { get; } = new WpfControls.ContextMenu();
@@ -39,16 +38,18 @@ public partial class MainForm : Form
int _lastCursorChanged;
int _lastCycleFullscreen;
int _taskbarButtonCreatedMessage;
int _cursorAutohide = 1000;
bool _contextMenuIsReady;
bool _wasMaximized;
bool _maxSizeSet;
bool _isCursorVisible = true;
public MainForm()
{
InitializeComponent();
if (Environment.OSVersion.Version >= new Version(10, 0, 18985) && Theme.DarkMode)
DwmSetWindowAttribute(Handle, 20, new[] { 1 }, 4); // DWMWA_USE_IMMERSIVE_DARK_MODE = 20
UpdateDarkMode();
try
{
@@ -67,8 +68,30 @@ public partial class MainForm : Form
GuiCommand.Current.WindowScaleNet += GuiCommand_WindowScaleNet;
GuiCommand.Current.ShowMenu += GuiCommand_ShowMenu;
if (Player.GPUAPI != "vulkan")
Init();
Player.Init(Handle, true);
Player.ObserveProperty("window-maximized", PropChangeWindowMaximized); // bool methods not working correctly
Player.ObserveProperty("window-minimized", PropChangeWindowMinimized); // bool methods not working correctly
Player.ObserveProperty("cursor-autohide", PropChangeCursorAutohide);
Player.ObservePropertyBool("border", PropChangeBorder);
Player.ObservePropertyBool("fullscreen", PropChangeFullscreen);
Player.ObservePropertyBool("keepaspect-window", value => Player.KeepaspectWindow = value);
Player.ObservePropertyBool("ontop", PropChangeOnTop);
Player.ObservePropertyBool("title-bar", PropChangeTitleBar);
Player.ObservePropertyString("sid", PropChangeSid);
Player.ObservePropertyString("aid", PropChangeAid);
Player.ObservePropertyString("vid", PropChangeVid);
Player.ObservePropertyString("title", PropChangeTitle);
Player.ObservePropertyInt("edition", PropChangeEdition);
Player.ObservePropertyDouble("window-scale", PropChangeWindowScale);
CommandLine.ProcessCommandLineArgsPostInit();
CommandLine.ProcessCommandLineFiles();
_taskbarButtonCreatedMessage = RegisterWindowMessage("TaskbarButtonCreated");
@@ -125,6 +148,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)
{
if (Command.Current.Commands.ContainsKey(args[0]))
@@ -139,32 +168,6 @@ public partial class MainForm : Form
SetTitle();
}
void Init()
{
Player.Init(Handle);
// bool methods not working correctly
Player.ObserveProperty("window-maximized", PropChangeWindowMaximized);
Player.ObserveProperty("window-minimized", PropChangeWindowMinimized);
Player.ObservePropertyBool("border", PropChangeBorder);
Player.ObservePropertyBool("fullscreen", PropChangeFullscreen);
Player.ObservePropertyBool("keepaspect-window", value => Player.KeepaspectWindow = value);
Player.ObservePropertyBool("ontop", PropChangeOnTop);
Player.ObservePropertyString("sid", PropChangeSid);
Player.ObservePropertyString("aid", PropChangeAid);
Player.ObservePropertyString("vid", PropChangeVid);
Player.ObservePropertyString("title", PropChangeTitle);
Player.ObservePropertyInt("edition", PropChangeEdition);
Player.ObservePropertyDouble("window-scale", PropChangeWindowScale);
Player.ProcessCommandLineFiles();
}
void PropChangeWindowScale(double scale)
{
if (!WasShown)
@@ -173,13 +176,13 @@ public partial class MainForm : Form
BeginInvoke(() => {
SetSize(
(int)(Player.VideoSize.Width * scale),
(int)Math.Ceiling(Player.VideoSize.Height * scale),
(int)Math.Floor(Player.VideoSize.Height * scale),
Screen.FromControl(this), false);
});
}
void Player_Shutdown() => BeginInvoke(Close);
void Player_VideoSizeChanged(Size value) => BeginInvoke(() =>
{
if (!KeepSize())
@@ -199,7 +202,7 @@ public partial class MainForm : Form
else
{
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);
@@ -239,7 +242,7 @@ public partial class MainForm : Form
BeginInvoke(() => {
SetSize(
(int)(Player.VideoSize.Width * scale),
(int)Math.Ceiling(Player.VideoSize.Height * scale),
(int)Math.Floor(Player.VideoSize.Height * scale),
Screen.FromControl(this), false);
Player.Command($"show-text \"window-scale {scale.ToString(CultureInfo.InvariantCulture)}\"");
});
@@ -277,8 +280,6 @@ public partial class MainForm : Form
pos.Y > ClientSize.Height * 0.78;
}
bool IsCommandPaletteVissible() => CommandPaletteHost != null && CommandPaletteHost.Visible;
void UpdateMenu()
{
Player.UpdateExternalTracks();
@@ -380,12 +381,11 @@ public partial class MainForm : Form
var menuItem = MenuHelp.Add(recentMenuItem.Items, file.Title.ShortPath(100));
if (menuItem != null)
menuItem.Click += (sender, args) =>
Player.LoadFiles(new[] { file.Path }, true, false);
menuItem.Click += (sender, args) => Player.LoadFiles(new[] { file.Path }, true, false);
}
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();
recentMenuItem.Items.Add(clearMenuItem);
}
@@ -443,34 +443,60 @@ 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 audioDevicesMenuItem = FindMenuItem(_("Audio Device"), "Audio Device");
if (audioDevicesMenuItem != null)
{
audioDevicesMenuItem.Items.Clear();
foreach (var pair in Player.AudioDevices)
{
var menuItem = MenuHelp.Add(audioDevicesMenuItem.Items, pair.Value);
if (menuItem != null)
{
menuItem.IsChecked = pair.Name == Player.GetPropertyString("audio-device");
menuItem.Click += (sender, args) =>
{
Player.SetPropertyString("audio-device", pair.Name);
Player.CommandV("show-text", pair.Value);
App.Settings.AudioDevice = pair.Name;
};
}
}
}
var customMenuItem = FindMenuItem(_("Custom"), "Custom");
if (customMenuItem != null)
if (customMenuItem != null && !customMenuItem.HasItems)
{
if (!customMenuItem.HasItems)
var customBindings = _confBindings!.Where(it => it.IsCustomMenu);
if (customBindings.Any())
{
var customBindings = _confBindings!.Where(it => it.IsCustomMenu);
if (customBindings.Any())
foreach (Binding binding in customBindings)
{
foreach (Binding binding in customBindings)
{
var menuItem = MenuHelp.Add(customMenuItem.Items, binding.Comment);
var menuItem = MenuHelp.Add(customMenuItem.Items, binding.Comment);
if (menuItem != null)
{
menuItem.Click += (sender, args) => Player.Command(binding.Command);
menuItem.InputGestureText = binding.Input;
}
if (menuItem != null)
{
menuItem.Click += (sender, args) => Player.Command(binding.Command);
menuItem.InputGestureText = binding.Input;
}
}
else
{
if (ContextMenu.Items.Contains(customMenuItem))
ContextMenu.Items.Remove(customMenuItem);
}
}
else
{
if (ContextMenu.Items.Contains(customMenuItem))
ContextMenu.Items.Remove(customMenuItem);
}
}
}
@@ -506,7 +532,7 @@ public partial class MainForm : Form
return null;
}
void SetFormPosAndSize(bool force = false, bool checkAutofit = true)
void SetFormPosAndSize(bool force = false, bool checkAutofit = true, bool load = false)
{
if (!force)
{
@@ -564,12 +590,12 @@ public partial class MainForm : Form
else if (App.StartSize == "height-always" || App.StartSize == "height-session")
{
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")
{
width = ClientSize.Width;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width);
height = (int)Math.Floor(width * videoSize.Height / (double)videoSize.Width);
}
}
else
@@ -579,36 +605,36 @@ public partial class MainForm : Form
if (App.StartSize == "height-always" && windowSize.Height != 0)
{
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")
{
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)
{
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")
{
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)
{
height = windowSize.Height;
width = windowSize.Width;
}
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);
@@ -622,49 +648,56 @@ public partial class MainForm : Form
{
if (height < maxHeight * Player.AutofitSmaller)
{
height = Convert.ToInt32(maxHeight * Player.AutofitSmaller);
width = Convert.ToInt32(height * startWidth / (double)startHeight);
height = (int)(maxHeight * Player.AutofitSmaller);
width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
}
if (height > maxHeight * Player.AutofitLarger)
{
height = Convert.ToInt32(maxHeight * Player.AutofitLarger);
width = Convert.ToInt32(height * startWidth / (double)startHeight);
height = (int)(maxHeight * Player.AutofitLarger);
width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
}
}
if (width > maxWidth)
{
width = maxWidth;
height = (int)Math.Ceiling(width * startHeight / (double)startWidth);
height = (int)Math.Floor(width * startHeight / (double)startWidth);
}
if (height > maxHeight)
{
height = maxHeight;
width = Convert.ToInt32(height * startWidth / (double)startHeight);
width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
}
if (height < maxHeight * 0.1)
{
height = Convert.ToInt32(maxHeight * 0.1);
width = Convert.ToInt32(height * startWidth / (double)startHeight);
height = (int)(maxHeight * 0.1);
width = (int)Math.Ceiling(height * startWidth / (double)startHeight);
}
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var rect = new Rect(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
AddWindowBorders(Handle, ref rect, GetDpi(Handle));
var rect = new RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
int left = middlePos.X - rect.Width / 2;
int top = middlePos.Y - rect.Height / 2;
AddWindowBorders(Handle, ref rect, GetDpi(Handle), !Player.TitleBar);
width = rect.Width;
height = rect.Height;
int left = Convert.ToInt32(middlePos.X - width / 2.0);
int top = Convert.ToInt32(middlePos.Y - height / 2.0);
if (!Player.TitleBar)
top -= Convert.ToInt32(GetTitleBarHeight(Handle, GetDpi(Handle)) / 2.0);
Rectangle currentRect = new Rectangle(Left, Top, Width, Height);
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 = currentRect.Bottom - rect.Height;
if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - height;
Screen[] screens = Screen.AllScreens;
@@ -673,20 +706,57 @@ public partial class MainForm : Form
int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min();
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)
left = minLeft;
if (left + rect.Width > maxRight)
left = maxRight - rect.Width;
if (left + width > maxRight)
left = maxRight - width;
if (top < minTop)
top = minTop;
if (top + rect.Height > maxBottom)
top = maxBottom - rect.Height;
if (top + height > maxBottom)
top = maxBottom - height;
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)
@@ -719,7 +789,7 @@ public partial class MainForm : Form
else
{
WindowState = FormWindowState.Normal;
if (!Player.WasInitialSizeSet)
SetFormPosAndSize();
}
@@ -781,7 +851,7 @@ public partial class MainForm : Form
if (!binding.IsMenu)
continue;
var menuItem = MenuHelp.Add(ContextMenu.Items, tempBinding.Comment);
if (menuItem != null)
@@ -837,7 +907,7 @@ public partial class MainForm : Form
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))
App.Settings.RecentFiles.Remove(path);
@@ -970,16 +1040,20 @@ public partial class MainForm : Form
m.Result = SendMessage(MpvWindowHandle, m.Msg, m.WParam, m.LParam);
}
break;
case 0x001A: // WM_SETTINGCHANGE
UpdateDarkMode();
break;
case 0x51: // WM_INPUTLANGCHANGE
ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/);
break;
case 0x319: // WM_APPCOMMAND
{
string? value = MpvHelp.WM_APPCOMMAND_to_mpv_key((int)(m.LParam.ToInt64() >> 16 & ~0xf000));
string? key = MpvHelp.WM_APPCOMMAND_to_mpv_key((int)(m.LParam.ToInt64() >> 16 & ~0xf000));
bool inputMediaKeys = Player.GetPropertyBool("input-media-keys");
if (value != null)
if (key != null && inputMediaKeys)
{
Player.Command("keypress " + value);
Player.Command("keypress " + key);
m.Result = new IntPtr(1);
return;
}
@@ -1009,16 +1083,46 @@ public partial class MainForm : Form
if (!WasShown)
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);
}
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;
int h = GetTitleBarHeight(Handle, GetDpi(Handle));
rects[0].Top = rects[0].Top - h;
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
if (Player.KeepaspectWindow)
{
Rect rc = Marshal.PtrToStructure<Rect>(m.LParam);
Rect r = rc;
SubtractWindowBorders(Handle, ref r, GetDpi(Handle));
RECT rc = Marshal.PtrToStructure<RECT>(m.LParam);
RECT r = rc;
SubtractWindowBorders(Handle, ref r, GetDpi(Handle), !Player.TitleBar);
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
Size videoSize = Player.VideoSize;
@@ -1026,9 +1130,9 @@ public partial class MainForm : Form
if (videoSize == Size.Empty)
videoSize = new Size(16, 9);
float aspect = videoSize.Width / (float)videoSize.Height;
int d_w = (int)(c_h * aspect - c_w);
int d_h = (int)(c_w / aspect - c_h);
double aspect = videoSize.Width / (double)videoSize.Height;
int d_w = (int)Math.Ceiling(c_h * aspect - c_w);
int d_h = (int)Math.Floor(c_w / aspect - c_h);
int[] d_corners = { d_w, d_h, -d_w, -d_h };
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
@@ -1037,37 +1141,14 @@ public partial class MainForm : Form
if (corner >= 0)
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);
}
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
// resize borderless window
if (!Player.Border && !Player.Fullscreen) {
if ((!Player.Border || !Player.TitleBar) && !Player.Fullscreen)
{
const int HTCLIENT = 1;
const int HTLEFT = 10;
const int HTRIGHT = 11;
@@ -1106,11 +1187,30 @@ public partial class MainForm : Form
return;
}
break;
case 0x231: // WM_ENTERSIZEMOVE
case 0x005: // WM_SIZE
if (Player.SnapWindow)
SnapManager.OnSizeAndEnterSizeMove(this);
break;
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 0x216: // WM_MOVING
if (Player.SnapWindow)
SnapManager.OnMoving(ref m);
@@ -1128,6 +1228,25 @@ public partial class MainForm : Form
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)
{
if (IsCursorPosDifferent(_lastCursorPosition))
@@ -1135,11 +1254,9 @@ public partial class MainForm : Form
_lastCursorPosition = MousePosition;
_lastCursorChanged = Environment.TickCount;
}
else if ((Environment.TickCount - _lastCursorChanged > 1500 ||
Environment.TickCount - _lastCursorChanged > 5000) &&
else if ((Environment.TickCount - _lastCursorChanged > _cursorAutohide) &&
ClientRectangle.Contains(PointToClient(MousePosition)) &&
ActiveForm == this && !ContextMenu.IsVisible && !IsMouseInOsc() &&
!IsCommandPaletteVissible())
ActiveForm == this && !ContextMenu.IsVisible && !IsMouseInOsc())
HideCursor();
}
@@ -1196,6 +1313,18 @@ public partial class MainForm : Form
});
}
void PropChangeCursorAutohide()
{
string strValue = Player.GetPropertyString("cursor-autohide");
if (strValue == "no")
_cursorAutohide = 0;
else if (strValue == "always")
_cursorAutohide = -1;
else if (int.TryParse(strValue, out var intValue))
_cursorAutohide = intValue;
}
void PropChangeBorder(bool enabled) {
Player.Border = enabled;
@@ -1211,6 +1340,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()
{
if (_taskbar != null && Player.TaskbarProgress)
@@ -1220,10 +1363,8 @@ public partial class MainForm : Form
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (Player.GPUAPI != "vulkan")
Player.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
_lastCycleFullscreen = Environment.TickCount;
SetFormPosAndSize();
SetFormPosAndSize(false, true, true);
}
protected override void OnLostFocus(EventArgs e)
@@ -1236,9 +1377,6 @@ public partial class MainForm : Form
{
base.OnShown(e);
if (Player.GPUAPI == "vulkan")
Init();
if (WindowState == FormWindowState.Maximized)
Player.SetPropertyBool("window-maximized", true);
@@ -1250,9 +1388,8 @@ public partial class MainForm : Form
InitAndBuildContextMenu();
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
GlobalHotkey.RegisterGlobalHotkeys(Handle);
TaskHelp.Run(WinMpvHelp.CopyMpvNetCom);
WasShown = true;
StrongReferenceMessenger.Default.Send(new MainWindowIsLoadedMessage());
WasShown = true;
}
void ContextMenu_Closed(object sender, System.Windows.RoutedEventArgs e) => MenuAutoResetEvent.Set();
@@ -1300,11 +1437,7 @@ public partial class MainForm : Form
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
_mouseDownLocation = PointToScreen(e.Location);
if (Width - e.Location.X < 10 && e.Location.Y < 10)
Player.CommandV("quit");
}
protected override void OnMouseMove(MouseEventArgs e)
@@ -1341,10 +1474,12 @@ public partial class MainForm : Form
{
base.OnDragDrop(e);
bool append = ModifierKeys == Keys.Shift;
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))
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)
@@ -1356,20 +1491,18 @@ public partial class MainForm : Form
base.OnKeyDown(e);
}
static bool _isCursorVisible = true;
static void ShowCursor()
void ShowCursor()
{
if (!_isCursorVisible)
if (!_isCursorVisible && _cursorAutohide != -1)
{
Cursor.Show();
_isCursorVisible = true;
}
}
static void HideCursor()
void HideCursor()
{
if (_isCursorVisible)
if (_isCursorVisible && _cursorAutohide != 0)
{
Cursor.Hide();
_isCursorVisible = false;
@@ -1393,103 +1526,4 @@ public partial class MainForm : Form
[DllImport("DwmApi")]
static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, int[] attrValue, int attrSize);
//protected override void OnLayout(LayoutEventArgs args)
//{
// base.OnLayout(args);
// AdjustCommandPaletteLeftAndWidth();
//}
//class ElementHostEx : ElementHost
//{
// protected override void OnHandleCreated(EventArgs e)
// {
// base.OnHandleCreated(e);
// const int LWA_ColorKey = 1;
// if (Environment.OSVersion.Version > new Version(10, 0))
// SetLayeredWindowAttributes(Handle, 0x111111, 255, LWA_ColorKey);
// }
// protected override CreateParams CreateParams
// {
// get
// {
// CreateParams cp = base.CreateParams;
// if (Environment.OSVersion.Version > new Version(10, 0))
// cp.ExStyle |= 0x00080000; // WS_EX_LAYERED
// cp.ExStyle |= 0x00000008; // WS_EX_TOPMOST
// cp.Style |= 0x04000000; //WS_CLIPSIBLINGS
// cp.Style |= 0x02000000; //WS_CLIPCHILDREN
// return cp;
// }
// }
// protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
// {
// try
// {
// return base.ProcessCmdKey(ref msg, keyData);
// }
// catch (Exception)
// {
// return true;
// }
// }
// [DllImport("user32.dll")]
// public static extern bool SetLayeredWindowAttributes(IntPtr hWnd, int crKey, byte alpha, int dwFlags);
//}
//public void ShowCommandPalette()
//{
// if (CommandPaletteHost == null)
// {
// CommandPaletteHost = new ElementHostEx();
// CommandPaletteHost.Dock = DockStyle.Fill;
// CommandPaletteHost.BackColor = Color.FromArgb(0x111111);
// AdjustCommandPaletteLeftAndWidth();
// CommandPaletteHost.Child = CommandPalette.Instance;
// CommandPalette.Instance.AdjustHeight();
// Controls.Add(CommandPaletteHost);
// CommandPaletteHost.BringToFront();
// }
//}
public void HideCommandPalette()
{
if (CommandPaletteHost != null)
{
CommandPaletteHost.Visible = false;
CommandPalette.Instance.Items.Clear();
CommandPalette.Instance.SearchControl.SearchTextBox.Text = "";
CommandPalette.Instance.UpdateLayout();
ActiveControl = null;
Controls.Remove(CommandPaletteHost);
CommandPaletteHost.Child = null;
CommandPaletteHost.Dispose();
CommandPaletteHost = null;
}
}
//void AdjustCommandPaletteLeftAndWidth()
//{
// if (CommandPaletteHost == null)
// return;
// CommandPaletteHost.Width = FontHeight * 26;
// if (CommandPaletteHost.Width > ClientSize.Width)
// CommandPaletteHost.Width = ClientSize.Width;
// CommandPaletteHost.Left = (ClientSize.Width - CommandPaletteHost.Size.Width) / 2;
//}
}

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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">

View File

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

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.PowerShell.5.ReferenceAssemblies" version="1.1.0" targetFramework="net472" />
</packages>

View File

@@ -13,6 +13,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F97C77E-32E3-46FA-8D7C-3940FD9AA384}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NGettext.Wpf", "NGettext.Wpf\NGettext.Wpf.csproj", "{0B7958FD-2138-482A-A21B-481AE7A0F851}"

View File

@@ -10,7 +10,6 @@ namespace MpvNet;
public class AppClass
{
public List<string> TempFiles { get; } = new ();
public Dictionary<string, string> CommandLineArguments { get; } = new ();
public string ConfPath { get => Player.ConfigFolder + "mpvnet.conf"; }
public string ProcessInstance { get; set; } = "single";
@@ -22,16 +21,16 @@ public class AppClass
public string CommandLine { get; set; } = Environment.CommandLine;
public string MenuSyntax { get; set; } = "#menu:";
public bool AutoLoadFolder { get; set; } = true;
public bool AutoLoadFolder { get; set; }
public bool DebugMode { get; set; }
public bool Exit { get; set; }
public bool IsTerminalAttached { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
public bool MediaInfo { get; set; } = true;
public bool Queue { get; set; }
public bool RememberAudioDevice { get; set; } = true;
public bool RememberVolume { get; set; } = true;
public bool RememberWindowPosition { get; set; }
public int StartThreshold { get; set; } = 1500;
public int RecentCount { get; set; } = 15;
public float AutofitAudio { get; set; } = 0.7f;
@@ -78,20 +77,14 @@ public class AppClass
Player.Initialized += Player_Initialized;
}
public static string About => "Copyright (C) 2000-2023 mpv.net/mpv/mplayer\n" +
$"{AppInfo.Product} {AppInfo.Version}" + GetLastWriteTime(Environment.ProcessPath!) + "\n" +
public static string About => "Copyright (C) 2000-2024 mpv.net/mpv/mplayer\n" +
$"{AppInfo.Product} v{AppInfo.Version}" + GetLastWriteTime(Environment.ProcessPath!) + "\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" +
$"MediaInfo v{FileVersionInfo.GetVersionInfo(Folder.Startup + "MediaInfo.dll").FileVersion}" +
$"{GetLastWriteTime(Folder.Startup + "MediaInfo.dll")}" + "\n" + "GPL v2 License";
static string GetLastWriteTime(string path)
{
if (IsStoreVersion)
return "";
return $" ({File.GetLastWriteTime(path).ToShortDateString()})";
}
static bool IsStoreVersion => Folder.Startup.Contains("FrankSkare.mpvnet");
static string GetLastWriteTime(string path) => $" ({File.GetLastWriteTime(path).ToShortDateString()})";
void Player_Initialized()
{
@@ -100,6 +93,9 @@ public class AppClass
Player.SetPropertyInt("volume", Settings.Volume);
Player.SetPropertyString("mute", Settings.Mute);
}
if (RememberAudioDevice && Settings.AudioDevice != "")
Player.SetPropertyString("audio-device", Settings.AudioDevice);
}
void Player_Shutdown()
@@ -135,14 +131,12 @@ public class AppClass
{
switch (name)
{
case "audio-file-extensions": FileTypes.Audio = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
case "auto-load-folder": AutoLoadFolder = value == "yes"; return true;
case "autofit-audio": AutofitAudio = value.Trim('%').ToInt(70) / 100f; return true;
case "autofit-image": AutofitImage = value.Trim('%').ToInt(80) / 100f; return true;
case "dark-mode": DarkMode = value; return true;
case "dark-theme": DarkTheme = value.Trim('\'', '"'); return true;
case "debug-mode": DebugMode = value == "yes"; return true;
case "image-file-extensions": FileTypes.Image = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
case "language": Language = value; return true;
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
case "media-info": MediaInfo = value == "yes"; return true;
@@ -152,11 +146,10 @@ public class AppClass
case "process-instance": ProcessInstance = value; return true;
case "queue": Queue = value == "yes"; 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-window-position": RememberWindowPosition = value == "yes"; 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;
default:
if (writeError)

View File

@@ -19,7 +19,7 @@ public class Chapter
_timeDisplay = TimeSpan.FromSeconds(Time).ToString();
if (_timeDisplay.ContainsEx("."))
_timeDisplay = _timeDisplay[.._timeDisplay.LastIndexOf(".")];
_timeDisplay = _timeDisplay[.._timeDisplay.LastIndexOf('.')];
}
return _timeDisplay;

View File

@@ -1,7 +1,5 @@

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

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

@@ -0,0 +1,159 @@

namespace MpvNet;
public class CommandLine
{
static List<StringPair>? _arguments;
static string[] _preInitProperties { get; } = {
"input-terminal", "terminal", "input-file", "config", "o", "config-dir", "input-conf",
"load-scripts", "scripts", "script-opts", "player-operation-mode", "idle", "log-file",
"msg-color", "dump-stats", "msg-level", "really-quiet" };
public static List<StringPair> Arguments
{
get
{
if (_arguments != null)
return _arguments;
_arguments = [];
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 "script-opt": left = "script-opts"; 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 void ProcessCommandLineArgsPreInit()
{
foreach (var pair in Arguments)
{
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"))
{
continue;
}
Player.ProcessProperty(pair.Name, pair.Value);
if (!App.ProcessProperty(pair.Name, pair.Value))
Player.SetPropertyString(pair.Name, pair.Value);
}
}
public static void ProcessCommandLineArgsPostInit()
{
foreach (var pair in Arguments)
{
if (_preInitProperties.Contains(pair.Name))
continue;
if (pair.Name.EndsWith("-add"))
Player.CommandV("change-list", pair.Name[..^4], "add", pair.Value);
else if (pair.Name.EndsWith("-set"))
Player.CommandV("change-list", pair.Name[..^4], "set", pair.Value);
else if (pair.Name.EndsWith("-append"))
Player.CommandV("change-list", pair.Name[..^7], "append", pair.Value);
else if (pair.Name.EndsWith("-pre"))
Player.CommandV("change-list", pair.Name[..^4], "pre", pair.Value);
else if (pair.Name.EndsWith("-clr"))
Player.CommandV("change-list", pair.Name[..^4], "clr", "");
else if (pair.Name.EndsWith("-remove"))
Player.CommandV("change-list", pair.Name[..^7], "remove", pair.Value);
else if (pair.Name.EndsWith("-toggle"))
Player.CommandV("change-list", pair.Name[..^7], "toggle", pair.Value);
else
{
Player.ProcessProperty(pair.Name, pair.Value);
if (!App.ProcessProperty(pair.Name, pair.Value))
Player.SetPropertyString(pair.Name, pair.Value);
}
}
}
public static void ProcessCommandLineFiles()
{
List<string> files = [];
foreach (string arg in Environment.GetCommandLineArgs().Skip(1))
{
if (!arg.StartsWith("--") && (arg == "-" || arg.Contains("://") ||
arg.Contains(":\\") || arg.StartsWith("\\\\") || arg.StartsWith('.') ||
File.Exists(arg)))
{
files.Add(arg);
}
}
Player.LoadFiles([.. files], !App.Queue, App.Queue);
if (App.CommandLine.Contains("--shuffle"))
{
Player.Command("playlist-shuffle");
Player.SetPropertyInt("playlist-pos", 0);
}
}
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

@@ -9,7 +9,7 @@ public class ExtensionLoader
{
public event Action<Exception>? UnhandledException;
readonly List<object?> _refs = new();
readonly List<object?> _refs = [];
void LoadDll(string path)
{
@@ -31,8 +31,12 @@ public class ExtensionLoader
public void LoadFolder(string path)
{
if (Directory.Exists(path))
{
foreach (string dir in Directory.GetDirectories(path))
{
LoadDll(dir.AddSep() + Path.GetFileName(dir) + ".dll");
}
}
}
}

View File

@@ -32,12 +32,12 @@ public static class PathStringExtension
int index = instance.LastIndexOf('\\');
if (index > -1)
return instance.Substring(index + 1);
return instance[(index + 1)..];
index = instance.LastIndexOf('/');
if (index > -1)
return instance.Substring(index + 1);
return instance[(index + 1)..];
return instance;
}

View File

@@ -5,16 +5,49 @@ namespace MpvNet;
public static class FileTypes
{
public static string[] Video { get; set; } = "mkv mp4 avi mov flv mpg webm wmv ts vob 264 265 asf avc avs dav h264 h265 hevc m2t m2ts m2v m4v mpeg mpv mts vpy y4m".Split(' ');
public static string[] Audio { get; set; } = "mp3 flac m4a mka mp2 ogg opus aac ac3 dts dtshd dtshr dtsma eac3 mpa mpc thd w64 wav".Split(' ');
public static string[] Image { get; set; } = { "jpg", "bmp", "png", "gif", "webp" };
public static string[] Subtitle { get; } = { "srt", "ass", "idx", "sub", "sup", "ttxt", "txt", "ssa", "smi", "mks" };
public static string[] Subtitle { get; } = ["srt", "ass", "idx", "sub", "sup", "ttxt", "txt", "ssa", "smi", "mks"];
public static bool IsImage(string extension) => Image.Contains(extension);
public static bool IsAudio(string extension) => Audio.Contains(extension);
public static bool IsVideo(string[] exts, string ext) => exts?.Contains(ext) ?? false;
public static bool IsAudio(string[] exts, string ext) => exts?.Contains(ext) ?? false;
public static bool IsImage(string[] exts, string ext) => exts?.Contains(ext) ?? false;
public static bool IsMedia(string extension) =>
Video.Contains(extension) || Audio.Contains(extension) || Image.Contains(extension);
public static bool IsVideo(string ext) => GetVideoExts().Contains(ext);
public static bool IsAudio(string ext) => GetAudioExts().Contains(ext);
public static bool IsImage(string ext) => GetImgExts().Contains(ext);
public static IEnumerable<string> GetMediaFiles(IEnumerable<string> files) => files.Where(i => IsMedia(i.Ext()));
public static string[] GetVideoExts()
{
string exts = Player.GetPropertyString("video-exts");
if (string.IsNullOrEmpty(exts))
return ["mkv", "mp4", "avi", "mov", "flv", "mpg", "webm", "wmv", "ts", "vob", "264", "265", "asf", "avc", "avs", "dav", "h264", "h265", "hevc", "m2t", "m2ts", "m2v", "m4v", "mpeg", "mpv", "mts", "vpy", "y4m"];
return exts.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
public static string[] GetAudioExts()
{
string exts = Player.GetPropertyString("audio-exts");
if (string.IsNullOrEmpty(exts))
return ["mp3", "flac", "m4a", "mka", "mp2", "ogg", "opus", "aac", "ac3", "dts", "dtshd", "dtshr", "dtsma", "eac3", "mpa", "mpc", "thd", "w64", "wav"];
return exts.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
public static string[] GetImgExts()
{
string exts = Player.GetPropertyString("image-exts");
if (string.IsNullOrEmpty(exts))
return ["jpg", "bmp", "png", "gif", "webp"];
return exts.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
public static bool IsMedia(string[] exts, string ext) =>
IsVideo(exts, ext) || IsAudio(exts, ext) || IsImage(exts, ext);
public static IEnumerable<string> GetMediaFiles(string[] files) =>
files.Where(i => IsMedia(files, i.Ext()));
}

View File

@@ -10,4 +10,5 @@ public static class Global
public static readonly AppClass App = new AppClass();
public static string _(string value) => Translator.Current!.Gettext(value);
public static string _p(string context, string value) => Translator.Current!.GetParticularString(context, value);
}

View File

@@ -1,14 +1,22 @@
namespace MpvNet.Help;

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

View File

@@ -8,9 +8,7 @@ public static class StringHelp
{
public static string GetMD5Hash(string txt)
{
using MD5 md5 = MD5.Create();
byte[] inputBuffer = Encoding.UTF8.GetBytes(txt);
byte[] hashBuffer = md5.ComputeHash(inputBuffer);
return BitConverter.ToString(md5.ComputeHash(inputBuffer)).Replace("-", "");
return Convert.ToHexString(MD5.HashData(inputBuffer));
}
}

View File

@@ -1,5 +1,4 @@

using MpvNet.ExtensionMethod;
using MpvNet.Help;
namespace MpvNet;
@@ -15,8 +14,11 @@ public class InputConf
public string Path {
get => _path ?? "";
set {
_path = value;
Content = File.Exists(_path) ? FileHelp.ReadTextFile(_path) : "";
if (_path != value)
{
_path = value;
Content = File.Exists(_path) ? FileHelp.ReadTextFile(_path) : "";
}
}
}
@@ -32,17 +34,25 @@ public class InputConf
var defaultBindings = InputHelp.GetDefaults();
foreach (Binding defaultBinding in defaultBindings)
{
foreach (Binding confBinding in confbindings)
{
if (defaultBinding.Input == confBinding.Input &&
defaultBinding.Command != confBinding.Command)
{
defaultBinding.Input = "";
}
}
}
foreach (Binding defaultBinding in defaultBindings)
{
foreach (Binding confBinding in confbindings)
{
if (defaultBinding.Command == confBinding.Command)
defaultBinding.Input = confBinding.Input;
}
}
return (defaultBindings, confbindings);
}
@@ -50,7 +60,29 @@ public class InputConf
public string GetContent()
{
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;
}
else
{
var defaults = InputHelp.GetDefaults();
@@ -58,19 +90,30 @@ public class InputConf
var conf = InputHelp.Parse(Content);
foreach (Binding defaultBinding in defaults)
{
foreach (Binding confBinding in conf)
{
if (defaultBinding.Command == confBinding.Command &&
defaultBinding.Comment == confBinding.Comment)
{
defaultBinding.Input = confBinding.Input;
removed.Add(confBinding);
}
}
}
foreach (Binding binding in removed)
{
conf.Remove(binding);
}
defaults.AddRange(conf);
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

@@ -7,210 +7,251 @@ public static class InputHelp
{
public static List<Binding> GetDefaults()
{
List<Binding> bindings = new List<Binding>()
{
new (_("File"), _("Open Files..."), "script-message-to mpvnet open-files", "o"),
new (_("File"), _("Open URL or file from clipboard"), "script-message-to mpvnet open-clipboard", "Ctrl+v"),
new (_("File"), _("Open DVD/Blu-ray Drive/Folder..."), "script-message-to mpvnet open-optical-media"),
new (_("File"), "-"),
new (_("File"), _("Add external audio files..."), "script-message-to mpvnet load-audio", "Alt+a"),
new (_("File"), _("Add external subtitle files..."), "script-message-to mpvnet load-sub", "Alt+s"),
new (_("File"), "-"),
new (_("File"), _("Add files to playlist..."), "script-message-to mpvnet open-files append"),
new (_("File"), _("Recent Files")),
new (_("File"), "-"),
new (_("File"), _("Exit"), "quit", "Esc"),
List<Binding> b = [];
new (_("Playback"), _("Play/Pause"), "script-message-to mpvnet play-pause", "Space"),
new (_("Playback"), _("Stop"), "stop", "Ctrl+s"),
Add(b, new (_("File"), _("Open Files..."), "script-message-to mpvnet open-files", "o"));
Add(b, new (_("File"), _("Open URL or file from clipboard"), "script-message-to mpvnet open-clipboard", "Ctrl+v"));
Add(b, new (_("File"), _("Open DVD/Blu-ray Drive/Folder..."), "script-message-to mpvnet open-optical-media"));
Add(b, new (_("File"), "-"));
Add(b, new (_("File"), _("Add external audio files..."), "script-message-to mpvnet load-audio"));
Add(b, new (_("File"), _("Add external subtitle files..."), "script-message-to mpvnet load-sub"));
Add(b, new (_("File"), "-"));
Add(b, new (_("File"), _("Add files to playlist..."), "script-message-to mpvnet open-files append"));
Add(b, new (_("File"), _("Add files/URLs to playlist from clipboard"), "script-message-to mpvnet open-clipboard append", "Ctrl+Shift+v"));
Add(b, new (_("File"), "-"));
Add(b, new (_("File"), _("Recent Files")));
Add(b, new (_("File"), _("Exit"), "quit", "Esc"));
new (_("Navigate"), _("Previous File"), "playlist-prev", "F11"),
new (_("Navigate"), _("Next File"), "playlist-next", "F12"),
new (_("Navigate"), "-"),
new (_("Navigate"), _("First File"), "script-message-to mpvnet playlist-first", "Home"),
new (_("Navigate"), _("Last File"), "script-message-to mpvnet playlist-last", "End"),
Add(b, new (_("Playback"), _("Play/Pause"), "script-message-to mpvnet play-pause", "Space"));
Add(b, new (_("Playback"), _("Stop"), "stop", "Ctrl+s"));
new (_("Navigate"), "-"),
new (_("Navigate"), _("Next Chapter"), "add chapter 1", "PGUP"),
new (_("Navigate"), _("Previous Chapter"), "add chapter -1", "PGDWN"),
new (_("Navigate"), "-"),
new (_("Navigate"), _("Jump To Next Frame"), "frame-step", "."),
new (_("Navigate"), _("Jump To Previous Frame"), "frame-back-step", ","),
new (_("Navigate"), "-"),
new (_("Navigate"), _("Jump 5 sec forward"), "seek 5", "Right"),
new (_("Navigate"), _("Jump 5 sec backward"), "seek -5", "Left"),
new (_("Navigate"), "-"),
new (_("Navigate"), _("Jump 30 sec forward"), "seek 30", "Up"),
new (_("Navigate"), _("Jump 30 sec backward"), "seek -30", "Down"),
new (_("Navigate"), "-"),
new (_("Navigate"), _("Jump 5 min forward"), "seek 300", "Ctrl+Right"),
new (_("Navigate"), _("Jump 5 min backward"), "seek -300", "Ctrl+Left"),
new (_("Navigate"), "-"),
new (_("Navigate"), _("Title")),
new (_("Navigate"), _("Chapter")),
Add(b, new (_("Navigate"), _("Previous File"), "playlist-prev", "F11"));
Add(b, new (_("Navigate"), _("Next File"), "playlist-next", "F12"));
Add(b, new (_("Navigate"), "-"));
Add(b, new (_("Navigate"), _("First File"), "script-message-to mpvnet playlist-first", "Home"));
Add(b, new (_("Navigate"), _("Last File"), "script-message-to mpvnet playlist-last", "End"));
new (_("Pan & Scan"), _("Decrease Size"), "add video-zoom -0.1", "Ctrl+-"),
new (_("Pan & Scan"), _("Increase Size"), "add video-zoom 0.1", "Ctrl++"),
new (_("Pan & Scan"), "-"),
new (_("Pan & Scan"), _("Move Left"), "add video-pan-x -0.01", "Ctrl+KP4"),
new (_("Pan & Scan"), _("Move Right"), "add video-pan-x 0.01", "Ctrl+KP6"),
new (_("Pan & Scan"), "-"),
new (_("Pan & Scan"), _("Move Up"), "add video-pan-y -0.01", "Ctrl+KP8"),
new (_("Pan & Scan"), _("Move Down"), "add video-pan-y 0.01", "Ctrl+KP2"),
new (_("Pan & Scan"), "-"),
new (_("Pan & Scan"), _("Decrease Height"), "add panscan -0.1", "w"),
new (_("Pan & Scan"), _("Increase Height"), "add panscan 0.1", "W"),
new (_("Pan & Scan"), "-"),
new (_("Pan & Scan"), _("Reset"), "set video-zoom 0; set video-pan-x 0; set video-pan-y 0", "Ctrl+BS"),
Add(b, new (_("Navigate"), "-"));
Add(b, new (_("Navigate"), _("Next Chapter"), "add chapter 1", "PGUP"));
Add(b, new (_("Navigate"), _("Previous Chapter"), "add chapter -1", "PGDWN"));
Add(b, new (_("Navigate"), "-"));
Add(b, new (_("Navigate"), _("Jump To Next Frame"), "frame-step", "."));
Add(b, new (_("Navigate"), _("Jump To Previous Frame"), "frame-back-step", ","));
Add(b, new (_("Navigate"), "-"));
Add(b, new (_("Navigate"), _("Jump 5 sec forward"), "seek 5", "Right"));
Add(b, new (_("Navigate"), _("Jump 5 sec backward"), "seek -5", "Left"));
Add(b, new (_("Navigate"), "-"));
Add(b, new (_("Navigate"), _("Jump 30 sec forward"), "seek 30", "Up"));
Add(b, new (_("Navigate"), _("Jump 30 sec backward"), "seek -30", "Down"));
Add(b, new (_("Navigate"), "-"));
Add(b, new (_("Navigate"), _("Jump 5 min forward"), "seek 300", "Ctrl+Right"));
Add(b, new (_("Navigate"), _("Jump 5 min backward"), "seek -300", "Ctrl+Left"));
Add(b, new (_("Navigate"), "-"));
Add(b, new (_("Navigate"), _("Title")));
Add(b, new (_("Navigate"), _("Chapter")));
new (_("Video"), _("Decrease Contrast"), "add contrast -1", "Ctrl+1"),
new (_("Video"), _("Increase Contrast"), "add contrast 1", "Ctrl+2"),
new (_("Video"), "-"),
new (_("Video"), _("Decrease Brightness"), "add brightness -1", "Ctrl+3"),
new (_("Video"), _("Increase Brightness"), "add brightness 1", "Ctrl+4"),
new (_("Video"), "-"),
new (_("Video"), _("Decrease Gamma"), "add gamma -1", "Ctrl+5"),
new (_("Video"), _("Increase Gamma"), "add gamma 1", "Ctrl+6"),
new (_("Video"), "-"),
new (_("Video"), _("Decrease Saturation"), "add saturation -1", "Ctrl+7"),
new (_("Video"), _("Increase Saturation"), "add saturation 1", "Ctrl+8"),
new (_("Video"), "-"),
new (_("Video"), _("Take Screenshot"), "async screenshot", "s"),
new (_("Video"), _("Take Screenshot without subtitles"), "async screenshot video", "S"),
new (_("Video"), _("Toggle Deinterlace"), "cycle deinterlace", "d"),
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"),
Add(b, new (_("Pan & Scan"), _("Decrease Size"), "add video-zoom -0.1", "Ctrl+-"));
Add(b, new (_("Pan & Scan"), _("Increase Size"), "add video-zoom 0.1", "Ctrl++"));
Add(b, new (_("Pan & Scan"), "-"));
Add(b, new (_("Pan & Scan"), _("Move Left"), "add video-pan-x -0.01", "Ctrl+KP4"));
Add(b, new (_("Pan & Scan"), _("Move Right"), "add video-pan-x 0.01", "Ctrl+KP6"));
Add(b, new (_("Pan & Scan"), "-"));
Add(b, new (_("Pan & Scan"), _("Move Up"), "add video-pan-y -0.01", "Ctrl+KP8"));
Add(b, new (_("Pan & Scan"), _("Move Down"), "add video-pan-y 0.01", "Ctrl+KP2"));
Add(b, new (_("Pan & Scan"), "-"));
Add(b, new (_("Pan & Scan"), _("Decrease Height"), "add panscan -0.1", "w"));
Add(b, new (_("Pan & Scan"), _("Increase Height"), "add panscan 0.1", "W"));
Add(b, new (_("Pan & Scan"), "-"));
Add(b, new (_("Pan & Scan"), _("Reset"), "set video-zoom 0; set video-pan-x 0; set video-pan-y 0", "Ctrl+BS"));
new (_("Audio"), _("Next Track"), "script-message-to mpvnet cycle-audio", "KP7"),
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"),
Add(b, new (_("Video"), _("Decrease Contrast"), "add contrast -1", "Ctrl+1"));
Add(b, new (_("Video"), _("Increase Contrast"), "add contrast 1", "Ctrl+2"));
Add(b, new (_("Video"), "-"));
Add(b, new (_("Video"), _("Decrease Brightness"), "add brightness -1", "Ctrl+3"));
Add(b, new (_("Video"), _("Increase Brightness"), "add brightness 1", "Ctrl+4"));
Add(b, new (_("Video"), "-"));
Add(b, new (_("Video"), _("Decrease Gamma"), "add gamma -1", "Ctrl+5"));
Add(b, new (_("Video"), _("Increase Gamma"), "add gamma 1", "Ctrl+6"));
Add(b, new (_("Video"), "-"));
Add(b, new (_("Video"), _("Decrease Saturation"), "add saturation -1", "Ctrl+7"));
Add(b, new (_("Video"), _("Increase Saturation"), "add saturation 1", "Ctrl+8"));
Add(b, new (_("Video"), "-"));
Add(b, new (_("Video"), _("Take Screenshot"), "async screenshot", "s"));
Add(b, new (_("Video"), _("Take Screenshot without subtitles"), "async screenshot video", "S"));
Add(b, new (_("Video"), _("Toggle Deinterlace"), "cycle deinterlace", "d"));
Add(b, new (_("Video"), _("Change Aspect Ratio"), "cycle-values video-aspect-override 16:9 4:3 2.35:1 0 -1", "a"));
Add(b, new (_("Video"), _("Rotate Video"), "cycle-values video-rotate 90 180 270 0", "Ctrl+r"));
new (_("Subtitle"), _("Next Track"), "script-message-to mpvnet cycle-subtitles", "KP8"),
new (_("Subtitle"), _("Toggle Visibility"), "cycle sub-visibility", "v"),
new (_("Subtitle"), "-"),
new (_("Subtitle"), _("Delay -0.1"), "add sub-delay -0.1", "z"),
new (_("Subtitle"), _("Delay +0.1"), "add sub-delay 0.1", "Z"),
new (_("Subtitle"), "-"),
new (_("Subtitle"), _("Move Up"), "add sub-pos -1", "r"),
new (_("Subtitle"), _("Move Down"), "add sub-pos 1", "R"),
new (_("Subtitle"), "-"),
new (_("Subtitle"), _("Decrease Font Size"), "add sub-scale -0.1", "F"),
new (_("Subtitle"), _("Increase Font Size"), "add sub-scale 0.1", "G"),
new (_("Subtitle"), "-"),
new (_("Subtitle") + " > " + _("More"), _("Toggle overriding SSA/ASS styles with normal styles"), "cycle-values sub-ass-override force no", "u"),
Add(b, new (_("Audio"), _("Audio Device")));
Add(b, new (_("Audio"), _("Next Track"), "script-message-to mpvnet cycle-audio", "KP7"));
Add(b, new (_("Audio"), "-"));
Add(b, new (_("Audio"), _("Delay +0.1"), "add audio-delay 0.1", "Ctrl+d"));
Add(b, new (_("Audio"), _("Delay -0.1"), "add audio-delay -0.1", "Ctrl+D"));
new ("", _("Track")),
Add(b, new (_("Subtitle"), _("Next Track"), "script-message-to mpvnet cycle-subtitles", "KP8"));
Add(b, new (_("Subtitle"), _("Toggle Visibility"), "cycle sub-visibility", "v"));
Add(b, new (_("Subtitle"), "-"));
Add(b, new (_("Subtitle"), _("Delay -0.1"), "add sub-delay -0.1", "z"));
Add(b, new (_("Subtitle"), _("Delay +0.1"), "add sub-delay 0.1", "Z"));
Add(b, new (_("Subtitle"), "-"));
Add(b, new (_("Subtitle"), _("Move Up"), "add sub-pos -1", "r"));
Add(b, new (_("Subtitle"), _("Move Down"), "add sub-pos 1", "R"));
Add(b, new (_("Subtitle"), "-"));
Add(b, new (_("Subtitle"), _("Decrease Font Size"), "add sub-scale -0.1", "F"));
Add(b, new (_("Subtitle"), _("Increase Font Size"), "add sub-scale 0.1", "G"));
Add(b, new (_("Subtitle"), "-"));
Add(b, new (_("Subtitle") + " > " + _("More"), _("Toggle overriding SSA/ASS styles with normal styles"), "cycle-values sub-ass-override force no", "u"));
new (_("Volume"), _("Up"), "add volume 2", "+"),
new (_("Volume"), _("Down"), "add volume -2", "-"),
new (_("Volume"), "-"),
new (_("Volume"), _("Mute"), "cycle mute", "m"),
Add(b, new ("", _("Track")));
new (_("Speed"), _("-10%"), "multiply speed 1/1.1", "["),
new (_("Speed"), _("+10%"), "multiply speed 1.1", "]"),
new (_("Speed"), "-"),
new (_("Speed"), _("Half"), "multiply speed 0.5", "{"),
new (_("Speed"), _("Double"), "multiply speed 2.0", "}"),
new (_("Speed"), "-"),
new (_("Speed"), _("Reset"), "set speed 1", "BS"),
Add(b, new (_("Volume"), _p("Volume", "Up"), "add volume 2", "+"));
Add(b, new (_("Volume"), _p("Volume", "Down"), "add volume -2", "-"));
Add(b, new (_("Volume"), "-"));
Add(b, new (_("Volume"), _("Mute"), "cycle mute", "m"));
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 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 Message Box"), "script-message-to mpvnet show-media-info msgbox", "Ctrl+m"),
new (_("View"), _("Show Progress"), "show-progress", "p"),
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 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"),
Add(b, new (_("Speed"), _("-10%"), "multiply speed 1/1.1", "["));
Add(b, new (_("Speed"), _("+10%"), "multiply speed 1.1", "]"));
Add(b, new (_("Speed"), "-"));
Add(b, new (_("Speed"), _("Half"), "multiply speed 0.5", "{"));
Add(b, new (_("Speed"), _("Double"), "multiply speed 2.0", "}"));
Add(b, new (_("Speed"), "-"));
Add(b, new (_("Speed"), _("Reset"), "set speed 1", "BS"));
new (_("Window"), _("Fullscreen"), "cycle fullscreen", "Enter"),
new (_("Window") + " > " + _("Zoom"), _("Enlarge"), "script-message-to mpvnet scale-window 1.2", "Alt++"),
new (_("Window") + " > " + _("Zoom"), _("Shrink"), "script-message-to mpvnet scale-window 0.8", "Alt+-"),
new (_("Window") + " > " + _("Zoom"), "-"),
new (_("Window") + " > " + _("Zoom"), _("50 %"), "script-message-to mpvnet window-scale 0.5", "Alt+0"),
new (_("Window") + " > " + _("Zoom"), _("100 %"), "script-message-to mpvnet window-scale 1.0", "Alt+1"),
new (_("Window") + " > " + _("Zoom"), _("200 %"), "script-message-to mpvnet window-scale 2.0", "Alt+2"),
new (_("Window") + " > " + _("Zoom"), _("300 %"), "script-message-to mpvnet window-scale 3.0", "Alt+3"),
new (_("Window") + " > " + _("Move"), _("Left"), "script-message-to mpvnet move-window left", "Alt+Left"),
new (_("Window") + " > " + _("Move"), _("Right"), "script-message-to mpvnet move-window right", "Alt+Right"),
new (_("Window") + " > " + _("Move"), _("Up"), "script-message-to mpvnet move-window top", "Alt+Up"),
new (_("Window") + " > " + _("Move"), _("Down"), "script-message-to mpvnet move-window bottom", "Alt+Down"),
new (_("Window") + " > " + _("Move"), _("Center"), "script-message-to mpvnet move-window center", "Alt+BS"),
new (_("Window"), _("Toggle Border"), "cycle border", "b"),
new (_("Window"), _("Toggle On Top"), "cycle ontop", "Ctrl+t"),
Add(b, new (_("View"), _("Playlist"), "script-binding select/select-playlist", "F8"));
Add(b, new (_("View"), _("Toggle Statistics"), "script-binding stats/display-stats-toggle", "t"));
Add(b, new (_("View"), _("Toggle OSC Visibility"), "script-binding osc/visibility", "Del"));
Add(b, new (_("View"), _("Media Info On-Screen"), "script-message-to mpvnet show-media-info osd", "i"));
Add(b, new (_("View"), _("Media Info Message Box"), "script-message-to mpvnet show-media-info msgbox", "Ctrl+m"));
Add(b, new (_("View"), _("Progress"), "show-progress", "p"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("On-Screen Menu"), "script-binding select/menu", "F1"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Playlist"), "script-binding select/select-playlist", "F8"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Bindings"), "script-binding select/select-binding", "F2"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Properties"), "script-binding select/show-properties", "F3"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Chapters"), "script-binding select/select-chapter", "Alt+c"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Tracks"), "script-binding select/select-track", "F9"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Audio Tracks"), "script-binding select/select-aid", "Alt+a"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Subtitle Tracks"), "script-binding select/select-sid", "Alt+s"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Secondary Subtitle"), "script-binding select/select-secondary-sid", "Alt+b"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Video Tracks"), "script-binding select/select-vid", "Alt+v"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Editions"), "script-binding select/select-edition", "Alt+e"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Subtitle Lines"), "script-binding select/select-subtitle-line", "Alt+l"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Audio Devices"), "script-binding select/select-audio-device", "Alt+d"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Watch History"), "script-binding select/select-watch-history", "Alt+h"));
Add(b, new (_("View") + " > " + _("On-Screen Menu"), _("Watch Later"), "script-binding select/select-watch-later"));
Add(b, new (_("View"), "-"));
Add(b, new (_("View") + " > " + _("More"), _("Console"), "script-binding console/enable", "`"));
Add(b, new (_("View") + " > " + _("More"), _("Commands"), "script-message-to mpvnet show-commands", "F4"));
Add(b, new (_("View") + " > " + _("More"), _("Active Bindings In Text Editor"), "script-message-to mpvnet show-bindings"));
Add(b, new (_("View") + " > " + _("More"), _("Active Bindings On-Screen"), "script-binding stats/display-page-4-toggle", "?"));
Add(b, new (_("View") + " > " + _("More"), _("Keys"), "script-message-to mpvnet show-keys", "Alt+k"));
Add(b, new (_("View") + " > " + _("More"), _("Protocols"), "script-message-to mpvnet show-protocols", "Alt+p"));
Add(b, new (_("View") + " > " + _("More"), _("Decoders"), "script-message-to mpvnet show-decoders"));
Add(b, new (_("View") + " > " + _("More"), _("Demuxers"), "script-message-to mpvnet show-demuxers"));
new ("", _("Profile")),
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"), _("Open Config Folder"), "script-message-to mpvnet open-conf-folder", "Ctrl+f"),
new (_("Settings") + " > " + _("Setup"), _("Register video file associations"), "script-message-to mpvnet reg-file-assoc video"),
new (_("Settings") + " > " + _("Setup"), _("Register audio file associations"), "script-message-to mpvnet reg-file-assoc audio"),
new (_("Settings") + " > " + _("Setup"), _("Register image file associations"), "script-message-to mpvnet reg-file-assoc image"),
new (_("Settings") + " > " + _("Setup"), _("Unregister file associations"), "script-message-to mpvnet reg-file-assoc unreg"),
new (_("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"), _("Shuffle Playlist"), "playlist-shuffle"),
new (_("Tools"), _("Toggle Hardware Decoding"), "cycle-values hwdec auto no", "Ctrl+h"),
new (_("Tools"), _("Exit Watch Later"), "quit-watch-later", "Q"),
new ("", _("Custom")),
Add(b, new (_("Window"), _("Fullscreen"), "cycle fullscreen", "Enter"));
Add(b, new (_("Window") + " > " + _("Zoom"), _("Enlarge"), "script-message-to mpvnet scale-window 1.2", "Alt++"));
Add(b, new (_("Window") + " > " + _("Zoom"), _("Shrink"), "script-message-to mpvnet scale-window 0.8", "Alt+-"));
Add(b, new (_("Window") + " > " + _("Zoom"), "-"));
Add(b, new (_("Window") + " > " + _("Zoom"), _("50 %"), "script-message-to mpvnet window-scale 0.5", "Alt+0"));
Add(b, new (_("Window") + " > " + _("Zoom"), _("100 %"), "script-message-to mpvnet window-scale 1.0", "Alt+1"));
Add(b, new (_("Window") + " > " + _("Zoom"), _("200 %"), "script-message-to mpvnet window-scale 2.0", "Alt+2"));
Add(b, new (_("Window") + " > " + _("Zoom"), _("300 %"), "script-message-to mpvnet window-scale 3.0", "Alt+3"));
Add(b, new (_("Window") + " > " + _("Move"), _p("Move", "Left"), "script-message-to mpvnet move-window left", "Alt+Left"));
Add(b, new (_("Window") + " > " + _("Move"), _p("Move", "Right"), "script-message-to mpvnet move-window right", "Alt+Right"));
Add(b, new (_("Window") + " > " + _("Move"), _p("Move", "Up"), "script-message-to mpvnet move-window top", "Alt+Up"));
Add(b, new (_("Window") + " > " + _("Move"), _p("Move", "Down"), "script-message-to mpvnet move-window bottom", "Alt+Down"));
Add(b, new (_("Window") + " > " + _("Move"), _p("Move", "Center"), "script-message-to mpvnet move-window center", "Alt+BS"));
Add(b, new (_("Window"), _("Toggle Border"), "cycle border", "b"));
Add(b, new (_("Window"), _("Toggle On Top"), "cycle ontop", "Ctrl+t"));
new (_("Help"), _("Website mpv"), "script-message-to mpvnet shell-execute https://mpv.io", "Ctrl+Home"),
new (_("Help"), _("Website mpv.net"), "script-message-to mpvnet shell-execute https://github.com/mpvnet-player/mpv.net"),
new (_("Help"), "-"),
new (_("Help"), _("Manual mpv"), "script-message-to mpvnet shell-execute https://mpv.io/manual/stable", "Ctrl+F1"),
new (_("Help"), _("Manual mpv.net"), "script-message-to mpvnet shell-execute https://github.com/mpvnet-player/mpv.net/blob/main/docs/manual.md", "Ctrl+F2"),
new (_("Help"), "-"),
new (_("Help"), _("awesome-mpv"), "script-message-to mpvnet shell-execute https://github.com/stax76/awesome-mpv", "Ctrl+a"),
new (_("Help"), _("About mpv.net"), "script-message-to mpvnet show-about"),
Add(b, new ("", _("Profile")));
new ("", "", "quit", "q", _("Exit")),
new ("", "", "script-message-to mpvnet show-menu", "MBTN_Right", _("Show Menu")),
new ("", "", "quit", "Power", _("Exit")),
new ("", "", "cycle pause", "Play", _("Play/Pause")),
new ("", "", "cycle pause", "Pause", _("Play/Pause")),
new ("", "", "cycle pause", "PlayPause", _("Play/Pause")),
new ("", "", "cycle pause", "MBTN_Mid", _("Play/Pause")),
new ("", "", "stop", "Stop", _("Stop")),
new ("", "", "seek 60", "Forward", _("Forward")),
new ("", "", "seek -60", "Rewind", _("Backward")),
new ("", "", "add volume 2", "Wheel_Up", _("Volume Up")),
new ("", "", "add volume -2", "Wheel_Down", _("Volume Down")),
new ("", "", "add volume 2", "Wheel_Right", _("Volume Up")),
new ("", "", "add volume -2", "Wheel_Left", _("Volume Down")),
new ("", "", "playlist-prev", "Prev", _("Previous File")),
new ("", "", "playlist-next", "Next", _("Next File")),
new ("", "", "playlist-prev", "MBTN_Back", _("Previous File")),
new ("", "", "playlist-next", "MBTN_Forward", _("Next File")),
new ("", "", "playlist-prev", "<", _("Previous File")),
new ("", "", "playlist-next", ">", _("Next File")),
new ("", "", "ignore", "MBTN_Left", _("Ignore left mouse butten")),
new ("", "", "cycle fullscreen", "f", _("Fullscreen")),
new ("", "", "cycle fullscreen", "MBTN_Left_DBL", _("Fullscreen")),
new ("", "", "no-osd seek 1 exact", "Shift+Right", _("Seek Forward")),
new ("", "", "no-osd seek -1 exact", "Shift+Left", _("Seek Backward")),
new ("", "", "no-osd seek 5 exact", "Shift+Up", _("Seek Forward")),
new ("", "", "no-osd seek -5 exact", "Shift+Down", _("Seek Backward")),
new ("", "", "revert-seek", "Shift+BS", _("Undo previous (or marked) seek")),
new ("", "", "revert-seek mark", "Shift+Ctrl+BS", _("Mark position for revert-seek")),
new ("", "", "no-osd sub-seek -1", "Ctrl+Shift+Left", _("Seek to previous 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_Down", _("Seek Backward")),
new ("", "", "quit 4", "Esc", _("Quit encoding")),
new ("", "", "quit 4", "q", _("Quit encoding")),
//new (_("Command Palette"), _("Commands"), "script-message-to mpvnet show-command-palette", "F1"),
};
Add(b, new (_("Config"), _("Show Config Editor"), "script-message-to mpvnet show-conf-editor", "Ctrl+,"));
Add(b, new (_("Config"), _("Show Input Editor"), "script-message-to mpvnet show-input-editor", "Ctrl+i"));
Add(b, new (_("Config"), "-"));
Add(b, new (_("Config"), _("Edit mpv.conf"), "script-message-to mpvnet edit-conf-file mpv.conf", "c"));
Add(b, new (_("Config"), _("Edit input.conf"), "script-message-to mpvnet edit-conf-file input.conf", "k"));
Add(b, new (_("Config"), "-"));
Add(b, new (_("Config"), _("Open Config Folder"), "script-message-to mpvnet open-conf-folder", "Ctrl+f"));
Add(b, new (_("Config") + " > " + _("Setup"), _("Register video file associations"), "script-message-to mpvnet reg-file-assoc video"));
Add(b, new (_("Config") + " > " + _("Setup"), _("Register audio file associations"), "script-message-to mpvnet reg-file-assoc audio"));
Add(b, new (_("Config") + " > " + _("Setup"), _("Register image file associations"), "script-message-to mpvnet reg-file-assoc image"));
Add(b, new (_("Config") + " > " + _("Setup"), _("Unregister file associations"), "script-message-to mpvnet reg-file-assoc unreg"));
Add(b, new (_("Config") + " > " + _("Setup"), "-"));
Add(b, new (_("Config") + " > " + _("Setup"), _("Add mpv.net to Path environment variable"), "script-message-to mpvnet add-to-path"));
Add(b, new (_("Config") + " > " + _("Setup"), _("Remove mpv.net from Path environment variable"), "script-message-to mpvnet remove-from-path"));
return bindings;
Add(b, new (_("Tools"), _("Set/clear A-B loop points"), "ab-loop", "l"));
Add(b, new (_("Tools"), _("Toggle infinite file looping"), "cycle-values loop-file inf no", "L"));
Add(b, new (_("Tools"), _("Shuffle Playlist"), "playlist-shuffle"));
Add(b, new (_("Tools"), _("Toggle Hardware Decoding"), "cycle-values hwdec auto no", "Ctrl+h"));
Add(b, new (_("Tools"), _("Exit Watch Later"), "quit-watch-later", "Q"));
Add(b, new ("", _("Custom")));
Add(b, new (_("Help"), _("Website mpv"), "script-message-to mpvnet shell-execute https://mpv.io", "Ctrl+Home"));
Add(b, new (_("Help"), _("Website mpv.net"), "script-message-to mpvnet shell-execute https://github.com/mpvnet-player/mpv.net"));
Add(b, new (_("Help"), "-"));
Add(b, new (_("Help"), _("Manual mpv"), "script-message-to mpvnet shell-execute https://mpv.io/manual/stable", "Ctrl+F1"));
Add(b, new (_("Help"), _("Manual mpv.net"), "script-message-to mpvnet shell-execute https://github.com/mpvnet-player/mpv.net/blob/main/docs/manual.md", "Ctrl+F2"));
Add(b, new (_("Help"), "-"));
Add(b, new (_("Help"), _("awesome-mpv"), "script-message-to mpvnet shell-execute https://github.com/stax76/awesome-mpv", "Ctrl+a"));
Add(b, new (_("Help"), _("About mpv.net"), "script-message-to mpvnet show-about"));
Add(b, new ("", "", "quit", "q", _("Exit")));
Add(b, new ("", "", "script-message-to mpvnet show-menu", "MBTN_Right", _("Show Menu")));
Add(b, new("", "", "script-message-to mpvnet play-pause", "Play", _("Play/Pause")));
Add(b, new("", "", "script-message-to mpvnet play-pause", "Pause", _("Play/Pause")));
Add(b, new("", "", "script-message-to mpvnet play-pause", "PlayPause", _("Play/Pause")));
Add(b, new("", "", "script-message-to mpvnet play-pause", "MBTN_Mid", _("Play/Pause")));
Add(b, new ("", "", "stop", "Stop", _("Stop")));
Add(b, new ("", "", "seek 60", "Forward", _("Forward")));
Add(b, new ("", "", "seek -60", "Rewind", _("Backward")));
Add(b, new ("", "", "add volume 2", "Wheel_Up", _("Volume Up")));
Add(b, new ("", "", "add volume -2", "Wheel_Down", _("Volume Down")));
Add(b, new ("", "", "add volume 2", "Wheel_Right", _("Volume Up")));
Add(b, new ("", "", "add volume -2", "Wheel_Left", _("Volume Down")));
Add(b, new ("", "", "playlist-prev", "Prev", _("Previous File")));
Add(b, new ("", "", "playlist-next", "Next", _("Next File")));
Add(b, new ("", "", "playlist-prev", "MBTN_Back", _("Previous File")));
Add(b, new ("", "", "playlist-next", "MBTN_Forward", _("Next File")));
Add(b, new ("", "", "playlist-prev", "<", _("Previous File")));
Add(b, new ("", "", "playlist-next", ">", _("Next File")));
Add(b, new ("", "", "ignore", "MBTN_Left", _("Ignore left mouse button")));
Add(b, new ("", "", "cycle fullscreen", "f", _("Fullscreen")));
Add(b, new ("", "", "cycle fullscreen", "MBTN_Left_DBL", _("Fullscreen")));
Add(b, new ("", "", "no-osd seek 1 exact", "Shift+Right", _("Seek Forward")));
Add(b, new ("", "", "no-osd seek -1 exact", "Shift+Left", _("Seek Backward")));
Add(b, new ("", "", "no-osd seek 5 exact", "Shift+Up", _("Seek Forward")));
Add(b, new ("", "", "no-osd seek -5 exact", "Shift+Down", _("Seek Backward")));
Add(b, new ("", "", "revert-seek", "Shift+BS", _("Undo previous (or marked) seek")));
Add(b, new ("", "", "revert-seek mark", "Shift+Ctrl+BS", _("Mark position for revert-seek")));
Add(b, new ("", "", "no-osd sub-seek -1", "Ctrl+Shift+Left", _("Seek to previous subtitle")));
Add(b, new ("", "", "no-osd sub-seek 1", "Ctrl+Shift+Right", _("Seek to next subtitle")));
Add(b, new ("", "", "no-osd seek 5", "Ctrl+Wheel_Up", _("Seek Forward")));
Add(b, new ("", "", "no-osd seek -5", "Ctrl+Wheel_Down", _("Seek Backward")));
Add(b, new ("", "", "quit", "Power", _("Exit")));
Add(b, new ("", "", "script-binding select/select-playlist", "g-p", _("Playlist")));
Add(b, new ("", "", "script-binding select/select-sid", "g-s", _("Subtitles")));
Add(b, new ("", "", "script-binding select/select-secondary-sid", "g-S", _("Secondary Subtitles")));
Add(b, new ("", "", "script-binding select/select-aid", "g-a", _("Audio Tracks")));
Add(b, new ("", "", "script-binding select/select-vid", "g-v", _("Video Tracks")));
Add(b, new ("", "", "script-binding select/select-track", "g-t", _("Tracks")));
Add(b, new ("", "", "script-binding select/select-chapter", "g-c", _("Chapters")));
Add(b, new ("", "", "script-binding select/select-edition", "g-e", _("Editions")));
Add(b, new ("", "", "script-binding select/select-subtitle-line", "g-l", _("Subtitle Lines")));
Add(b, new ("", "", "script-binding select/select-audio-device", "g-d", _("Audio Devices")));
Add(b, new ("", "", "script-binding select/select-watch-history", "g-h", _("Watch History")));
Add(b, new ("", "", "script-binding select/select-watch-later", "g-w", _("Watch Later")));
Add(b, new ("", "", "script-binding select/select-binding", "g-b", _("Bindings")));
Add(b, new ("", "", "script-binding select/show-properties", "g-r", _("Properties")));
Add(b, new ("", "", "script-binding select/menu", "g-m", _("On-Screen Menu")));
Add(b, new ("", "", "script-binding select/menu", "MENU", _("On-Screen Menu")));
Add(b, new ("", "", "script-binding select/menu", "Ctrl+p", _("On-Screen Menu")));
return b;
static void Add(List<Binding> bindings, Binding b) => bindings.Add(b);
}
public static string ConvertToString(List<Binding> bindings)
@@ -280,6 +321,9 @@ public static class InputHelp
if (string.IsNullOrEmpty(content))
return bindings;
if (content.Contains('\t'))
content = content.Replace('\t', ' ');
foreach (string it in content.Split('\n'))
{
string line = it.Trim();
@@ -319,7 +363,7 @@ public static class InputHelp
if (binding.Input.Contains("alt+"))
binding.Input = binding.Input.Replace("alt+", "Alt+");
line = line[(line.IndexOf(" ") + 1)..];
line = line[(line.IndexOf(' ') + 1)..];
if (line.Contains(App.MenuSyntax))
{
@@ -335,8 +379,8 @@ public static class InputHelp
}
else if (line.Contains('#'))
{
binding.Comment = line[(line.IndexOf("#") + 1)..].Trim();
line = line[..line.IndexOf("#")];
binding.Comment = line[(line.IndexOf('#') + 1)..].Trim();
line = line[..line.IndexOf('#')];
}
binding.Command = line.Trim();
@@ -400,57 +444,9 @@ public static class InputHelp
return defaults;
}
// only used by dead command palette
public static List<Binding> GetBindingsFromContent(string content)
{
var bindings = new List<Binding>();
if (!string.IsNullOrEmpty(content))
{
foreach (string line in content.Split('\r', '\n'))
{
string value = line.Trim();
if (value.StartsWith("#"))
continue;
if (!value.Contains(' '))
continue;
Binding binding = new Binding();
binding.Input = value[..value.IndexOf(" ")];
if (binding.Input == "_")
binding.Input = "";
value = value[(value.IndexOf(" ") + 1)..];
if (value.Contains(App.MenuSyntax))
{
binding.Comment = value[(value.IndexOf(App.MenuSyntax) + App.MenuSyntax.Length)..].Trim();
value = value[..value.IndexOf(App.MenuSyntax)];
if (binding.Comment.Contains(';'))
binding.Comment = binding.Comment[(binding.Comment.IndexOf(";") + 1)..].Trim();
}
binding.Command = value.Trim();
if (binding.Command == "")
continue;
if (binding.Command.ToLower() == "ignore")
binding.Command = "";
bindings.Add(binding);
}
}
return bindings;
}
public static Dictionary<string, Binding> GetActiveBindings(List<Binding> bindings)
{
Dictionary<string, Binding> ret = new();
Dictionary<string, Binding> ret = [];
foreach (Binding binding in bindings)
{
@@ -475,7 +471,7 @@ public static class InputHelp
Binding binding = it.Value;
if (!keys.Contains(binding.Input) && (charCount + binding.Input.Length) < 20 && keys.Count < 2)
if (!keys.Contains(binding.Input) && (charCount + binding.Input.Length) < 30)
{
keys.Add(binding.Input);
charCount += binding.Input.Length;

View File

@@ -1,13 +1,4 @@

using CommunityToolkit.Mvvm.Messaging.Messages;
namespace MpvNet.MVVM;
public class MainWindowIsLoadedMessage { }
//public class ScaleWindowMessage : ValueChangedMessage<float>
//{
// public ScaleWindowMessage(float value) : base(value)
// {
// }
//}

View File

@@ -21,11 +21,11 @@ public class MpvClient
public event Action? Seek; // seek MPV_EVENT_SEEK
public event Action? PlaybackRestart; // playback-restart MPV_EVENT_PLAYBACK_RESTART
public Dictionary<string, List<Action>> PropChangeActions { get; set; } = new Dictionary<string, List<Action>>();
public Dictionary<string, List<Action<int>>> IntPropChangeActions { get; set; } = new Dictionary<string, List<Action<int>>>();
public Dictionary<string, List<Action<bool>>> BoolPropChangeActions { get; set; } = new Dictionary<string, List<Action<bool>>>();
public Dictionary<string, List<Action<double>>> DoublePropChangeActions { get; set; } = new Dictionary<string, List<Action<double>>>();
public Dictionary<string, List<Action<string>>> StringPropChangeActions { get; set; } = new Dictionary<string, List<Action<string>>>();
public Dictionary<string, List<Action>> PropChangeActions { get; set; } = [];
public Dictionary<string, List<Action<int>>> IntPropChangeActions { get; set; } = [];
public Dictionary<string, List<Action<bool>>> BoolPropChangeActions { get; set; } = [];
public Dictionary<string, List<Action<double>>> DoublePropChangeActions { get; set; } = [];
public Dictionary<string, List<Action<string>>> StringPropChangeActions { get; set; } = [];
public nint Handle { get; set; }
@@ -64,7 +64,7 @@ public class MpvClient
OnEndFile(data);
}
break;
case mpv_event_id.MPV_EVENT_FILE_LOADED:
case mpv_event_id.MPV_EVENT_FILE_LOADED: // triggered after MPV_EVENT_START_FILE
OnFileLoaded();
break;
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
@@ -82,7 +82,7 @@ public class MpvClient
case mpv_event_id.MPV_EVENT_COMMAND_REPLY:
OnCommandReply();
break;
case mpv_event_id.MPV_EVENT_START_FILE:
case mpv_event_id.MPV_EVENT_START_FILE: // triggered before MPV_EVENT_FILE_LOADED
OnStartFile();
break;
case mpv_event_id.MPV_EVENT_AUDIO_RECONFIG:
@@ -132,46 +132,72 @@ public class MpvClient
else if (data.format == mpv_format.MPV_FORMAT_STRING)
{
lock (StringPropChangeActions)
{
foreach (var pair in StringPropChangeActions)
{
if (pair.Key == data.name)
{
string value = ConvertFromUtf8(Marshal.PtrToStructure<IntPtr>(data.data));
foreach (var action in pair.Value)
{
action.Invoke(value);
}
}
}
}
}
else if (data.format == mpv_format.MPV_FORMAT_INT64)
{
lock (IntPropChangeActions)
{
foreach (var pair in IntPropChangeActions)
{
if (pair.Key == data.name)
{
int value = Marshal.PtrToStructure<int>(data.data);
foreach (var action in pair.Value)
{
action.Invoke(value);
}
}
}
}
}
else if (data.format == mpv_format.MPV_FORMAT_NONE)
{
lock (PropChangeActions)
{
foreach (var pair in PropChangeActions)
{
if (pair.Key == data.name)
{
foreach (var action in pair.Value)
{
action.Invoke();
}
}
}
}
}
else if (data.format == mpv_format.MPV_FORMAT_DOUBLE)
{
lock (DoublePropChangeActions)
{
foreach (var pair in DoublePropChangeActions)
{
if (pair.Key == data.name)
{
double value = Marshal.PtrToStructure<double>(data.data);
foreach (var action in pair.Value)
{
action.Invoke(value);
}
}
}
}
}
}
@@ -247,7 +273,9 @@ public class MpvClient
mpv_error err = mpv_command_ret(Handle, rootPtr, resultNodePtr);
foreach (IntPtr ptr in pointers)
{
Marshal.FreeHGlobal(ptr);
}
Marshal.FreeHGlobal(rootPtr);
@@ -346,6 +374,9 @@ public class MpvClient
public string GetPropertyString(string name)
{
if (Handle == IntPtr.Zero)
return "";
mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name),
mpv_format.MPV_FORMAT_STRING, out IntPtr lpBuffer);
@@ -364,6 +395,12 @@ public class MpvClient
public void SetPropertyString(string name, string value)
{
if (Handle == IntPtr.Zero)
{
Terminal.WriteError($"error setting property: {name} = {value}");
return;
}
byte[] bytes = GetUtf8Bytes(value);
mpv_error err = mpv_set_property(Handle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, ref bytes);
@@ -400,7 +437,7 @@ public class MpvClient
if (err < 0)
HandleError(err, "error observing property: " + name);
else
IntPropChangeActions[name] = new List<Action<int>>();
IntPropChangeActions[name] = [];
}
if (IntPropChangeActions.ContainsKey(name))
@@ -419,7 +456,7 @@ public class MpvClient
if (err < 0)
HandleError(err, "error observing property: " + name);
else
DoublePropChangeActions[name] = new List<Action<double>>();
DoublePropChangeActions[name] = [];
}
if (DoublePropChangeActions.ContainsKey(name))
@@ -438,7 +475,7 @@ public class MpvClient
if (err < 0)
HandleError(err, "error observing property: " + name);
else
BoolPropChangeActions[name] = new List<Action<bool>>();
BoolPropChangeActions[name] = [];
}
if (BoolPropChangeActions.ContainsKey(name))
@@ -457,7 +494,7 @@ public class MpvClient
if (err < 0)
HandleError(err, "error observing property: " + name);
else
StringPropChangeActions[name] = new List<Action<string>>();
StringPropChangeActions[name] = [];
}
if (StringPropChangeActions.ContainsKey(name))
@@ -476,7 +513,7 @@ public class MpvClient
if (err < 0)
HandleError(err, "error observing property: " + name);
else
PropChangeActions[name] = new List<Action>();
PropChangeActions[name] = [];
}
if (PropChangeActions.ContainsKey(name))

View File

@@ -1,29 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<AssemblyName>libmpvnet</AssemblyName>
<Product>mpv.net</Product>
<Nullable>enable</Nullable>
<RootNamespace>MpvNet</RootNamespace>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\docs\changelog.md" Link="Docs\changelog.md" />
<None Include="..\..\docs\manual.md" Link="Docs\manual.md" />
<None Include="..\..\README.md" Link="Docs\README.md" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\docs\changelog.md" Link="Docs\changelog.md" />
<None Include="..\..\docs\manual.md" Link="Docs\manual.md" />
<None Include="..\..\README.md" Link="Docs\README.md" />
</ItemGroup>
<ItemGroup>
<Folder Include="Extension\" />
<Folder Include="Input\" />
<Folder Include="Docs\" />
</ItemGroup>
<ItemGroup>
<Folder Include="Docs\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="NGettext" Version="0.6.7" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="NGettext" />
</ItemGroup>
</Project>

View File

@@ -36,6 +36,7 @@ public class MainPlayer : MpvClient
public bool Paused { get; set; }
public bool SnapWindow { get; set; }
public bool TaskbarProgress { get; set; } = true;
public bool TitleBar { get; set; } = true;
public bool WasInitialSizeSet;
public bool WindowMaximized { get; set; }
public bool WindowMinimized { get; set; }
@@ -50,7 +51,6 @@ public class MainPlayer : MpvClient
public float AutofitLarger { get; set; } = 0.8f;
public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false);
public AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false);
public nint MainHandle { get; set; }
public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>();
@@ -59,22 +59,26 @@ public class MainPlayer : MpvClient
public TimeSpan Duration;
public List<MpvClient> Clients { get; } = new List<MpvClient>();
List<StringPair>? _audioDevices;
public event Action? Initialized;
public event Action? Pause;
public event Action<int>? PlaylistPosChanged;
public event Action<Size>? VideoSizeChanged;
public void Init(IntPtr formHandle)
public void Init(IntPtr formHandle, bool processCommandLine)
{
App.ApplyShowMenuFix();
MainHandle = mpv_create();
Handle = MainHandle;
var events = Enum.GetValues(typeof(mpv_event_id)).Cast<mpv_event_id>();
var events = Enum.GetValues<mpv_event_id>().Cast<mpv_event_id>();
foreach (mpv_event_id i in events)
{
mpv_request_event(MainHandle, i, 0);
}
mpv_request_log_messages(MainHandle, "no");
@@ -91,30 +95,37 @@ public class MainPlayer : MpvClient
}
if (formHandle != IntPtr.Zero)
{
SetPropertyString("force-window", "yes");
SetPropertyLong("wid", formHandle.ToInt64());
}
SetPropertyInt("osd-duration", 2000);
SetPropertyBool("input-default-bindings", true);
SetPropertyBool("input-builtin-bindings", false);
SetPropertyBool("input-media-keys", true);
SetPropertyString("autocreate-playlist", "filter");
SetPropertyString("media-controls", "yes");
SetPropertyString("idle", "yes");
SetPropertyString("screenshot-directory", "~~desktop/");
SetPropertyString("osd-playing-msg", "${media-title}");
SetPropertyString("osc", "yes");
SetPropertyString("force-window", "yes");
SetPropertyString("config-dir", ConfigFolder);
SetPropertyString("config", "yes");
UsedInputConfContent = App.InputConf.GetContent();
if (!string.IsNullOrEmpty(UsedInputConfContent))
SetPropertyString("input-conf", @"memory://" + UsedInputConfContent);
ProcessCommandLineArgs();
if (processCommandLine)
CommandLine.ProcessCommandLineArgsPreInit();
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);
App.InputConf.Path = fullPath.AddSep() + "input.conf";
string content = App.InputConf.GetContent();
@@ -130,10 +141,6 @@ public class MainPlayer : MpvClient
if (err < 0)
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");
App.Exit = idle == "no" || idle == "once";
@@ -151,16 +158,24 @@ public class MainPlayer : MpvClient
// this means Lua scripts that use idle might not work correctly
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 => {
Paused = value;
Pause?.Invoke();
});
ObservePropertyInt("video-rotate", value => {
VideoRotate = value;
UpdateVideoSize("dwidth", "dheight");
VideoRotate = GetPropertyInt("video-rotate");
ObservePropertyInt("video-rotate", value =>
{
if (VideoRotate != value)
{
VideoRotate = value;
UpdateVideoSize("dwidth", "dheight");
}
});
ObservePropertyInt("playlist-pos", value => {
@@ -172,9 +187,6 @@ public class MainPlayer : MpvClient
CommandV("quit");
});
if (!GetPropertyBool("osd-scale-by-window"))
App.StartThreshold = 0;
Initialized?.Invoke();
}
@@ -184,7 +196,9 @@ public class MainPlayer : MpvClient
mpv_destroy(Handle);
foreach (var client in Clients)
{
mpv_destroy(client.Handle);
}
}
public void ProcessProperty(string? name, string? value)
@@ -220,6 +234,7 @@ public class MainPlayer : MpvClient
case "vo": VO = value!; break;
case "window-maximized": WindowMaximized = value == "yes"; break;
case "window-minimized": WindowMinimized = value == "yes"; break;
case "title-bar": TitleBar = value == "yes"; break;
}
if (AutofitLarger > 1)
@@ -243,20 +258,7 @@ public class MainPlayer : MpvClient
_configFolder = Folder.AppData + "mpv.net";
if (!Directory.Exists(_configFolder))
{
try {
using Process proc = new Process();
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = "powershell.exe";
proc.StartInfo.Arguments = $@"-Command New-Item -Path '{_configFolder}' -ItemType Directory";
proc.Start();
proc.WaitForExit();
} catch (Exception) {}
if (!Directory.Exists(_configFolder))
Directory.CreateDirectory(_configFolder);
}
Directory.CreateDirectory(_configFolder);
_configFolder = _configFolder.AddSep();
}
@@ -265,39 +267,52 @@ public class MainPlayer : MpvClient
}
}
private readonly Regex ConfRegex = new Regex("^[\\w-]+$", RegexOptions.Compiled);
Dictionary<string, string>? _Conf;
public Dictionary<string, string> Conf {
get {
if (_Conf == null)
get
{
if (_Conf != null)
return _Conf;
App.ApplyInputDefaultBindingsFix();
_Conf = [];
if (File.Exists(ConfPath))
{
App.ApplyInputDefaultBindingsFix();
_Conf = new Dictionary<string, string>();
if (File.Exists(ConfPath))
foreach (string? it in File.ReadAllLines(ConfPath))
{
foreach (string? it in File.ReadAllLines(ConfPath))
string line = it.TrimStart(' ', '-').TrimEnd();
if (line.StartsWith('#'))
continue;
if (!line.Contains('='))
{
string line = it.TrimStart(' ', '-').TrimEnd();
if (!line.Contains('=') || line.StartsWith("#"))
if (ConfRegex.Match(line).Success)
line += "=yes";
else
continue;
string key = line[..line.IndexOf("=")].Trim();
string value = line[(line.IndexOf("=") + 1)..].Trim();
if (value.Contains('#') && !value.StartsWith("#") &&
!value.StartsWith("'#") && !value.StartsWith("\"#"))
value = value[..value.IndexOf("#")].Trim();
_Conf[key] = value;
}
}
foreach (var i in _Conf)
ProcessProperty(i.Key, i.Value);
string key = line[..line.IndexOf("=")].Trim();
string value = line[(line.IndexOf("=") + 1)..].Trim();
if (value.Contains('#') && !value.StartsWith("#") &&
!value.StartsWith("'#") && !value.StartsWith("\"#"))
value = value[..value.IndexOf("#")].Trim();
_Conf[key] = value;
}
}
foreach (var i in _Conf)
{
ProcessProperty(i.Key, i.Value);
}
return _Conf;
@@ -306,26 +321,27 @@ public class MainPlayer : MpvClient
void UpdateVideoSize(string w, string h)
{
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h));
if (size.Width == 0 || size.Height == 0)
if (string.IsNullOrEmpty(Path))
return;
Size size = new Size(GetPropertyInt(w), GetPropertyInt(h));
if (VideoRotate == 90 || VideoRotate == 270)
size = new Size(size.Height, size.Width);
if (VideoSize != size)
if (size != VideoSize && size != Size.Empty)
{
VideoSize = size;
VideoSizeChanged?.Invoke(size);
VideoSizeAutoResetEvent.Set();
}
}
public void MainEventLoop()
{
while (true)
{
mpv_wait_event(MainHandle, -1);
}
}
protected override void OnShutdown()
@@ -348,24 +364,27 @@ public class MainPlayer : MpvClient
base.OnLogMessage(data);
}
protected override void OnVideoReconfig()
{
UpdateVideoSize("dwidth", "dheight");
base.OnVideoReconfig();
}
protected override void OnEndFile(mpv_event_end_file data)
{
base.OnEndFile(data);
FileEnded = true;
}
protected override void OnVideoReconfig()
{
UpdateVideoSize("dwidth", "dheight");
base.OnVideoReconfig();
}
// executed before OnFileLoaded
protected override void OnStartFile()
{
Path = GetPropertyString("path");
base.OnStartFile();
TaskHelp.Run(LoadFolder);
}
// executed after OnStartFile
protected override void OnFileLoaded()
{
Duration = TimeSpan.FromSeconds(GetPropertyDouble("duration"));
@@ -373,14 +392,6 @@ public class MainPlayer : MpvClient
if (App.StartSize == "video")
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);
base.OnFileLoaded();
@@ -406,105 +417,6 @@ public class MainPlayer : MpvClient
public void SetBluRayTitle(int id) => LoadFiles(new[] { @"bd://" + id }, false, false);
public void ProcessCommandLineArgs()
{
foreach (string i in Environment.GetCommandLineArgs().Skip(1))
{
string arg = i;
if (!arg.StartsWith("--"))
continue;
if (arg == "--profile=help")
{
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 (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;
}
App.CommandLineArguments[left] = right;
ProcessProperty(left, right);
if (!App.ProcessProperty(left, right))
SetPropertyString(left, right);
}
}
public void ProcessCommandLineFiles()
{
List<string> files = new List<string>();
foreach (string arg in Environment.GetCommandLineArgs().Skip(1))
if (!arg.StartsWith("--") && (arg == "-" || arg.Contains("://") ||
arg.Contains(":\\") || arg.StartsWith("\\\\") || File.Exists(arg)))
files.Add(arg);
LoadFiles(files.ToArray(), !App.Queue, false || App.Queue);
if (App.CommandLine.Contains("--shuffle"))
{
Command("playlist-shuffle");
SetPropertyInt("playlist-pos", 0);
}
if (files.Count == 0 || files[0].Contains("://"))
{
VideoSizeChanged?.Invoke(VideoSize);
VideoSizeAutoResetEvent.Set();
}
}
public DateTime LastLoad;
public void LoadFiles(string[]? files, bool loadFolder, bool append)
@@ -541,17 +453,9 @@ public class MainPlayer : MpvClient
}
if (ext == "iso")
LoadBluRayISO(file);
LoadISO(file);
else if(FileTypes.Subtitle.Contains(ext))
CommandV("sub-add", file);
else if (!FileTypes.IsMedia(ext) && !file.Contains("://") && Directory.Exists(file) &&
File.Exists(System.IO.Path.Combine(file, "BDMV\\index.bdmv")))
{
Command("stop");
Thread.Sleep(500);
SetPropertyString("bluray-device", file);
CommandV("loadfile", @"bd://");
}
else
{
if (i == 0 && !append)
@@ -576,12 +480,24 @@ public class MainPlayer : MpvClient
return path;
}
public void LoadBluRayISO(string path)
public void LoadISO(string path)
{
Command("stop");
Thread.Sleep(500);
SetPropertyString("bluray-device", path);
LoadFiles(new[] { @"bd://" }, false, false);
using var mi = new MediaInfo(path);
if (mi.GetGeneral("Format") == "ISO 9660 / DVD Video")
{
Command("stop");
Thread.Sleep(500);
SetPropertyString("dvd-device", path);
LoadFiles([@"dvd://"], false, false);
}
else
{
Command("stop");
Thread.Sleep(500);
SetPropertyString("bluray-device", path);
LoadFiles([@"bd://"], false, false);
}
}
public void LoadDiskFolder(string path)
@@ -592,12 +508,12 @@ public class MainPlayer : MpvClient
if (Directory.Exists(path + "\\BDMV"))
{
SetPropertyString("bluray-device", path);
LoadFiles(new[] { @"bd://" }, false, false);
LoadFiles([@"bd://"], false, false);
}
else
{
SetPropertyString("dvd-device", path);
LoadFiles(new[] { @"dvd://" }, false, false);
LoadFiles([@"dvd://"], false, false);
}
}
@@ -626,7 +542,7 @@ public class MainPlayer : MpvClient
dir = System.IO.Path.GetDirectoryName(path)!;
List<string> files = FileTypes.GetMediaFiles(Directory.GetFiles(dir)).ToList();
if (OperatingSystem.IsWindows())
files.Sort(new StringLogicalComparer());
@@ -695,8 +611,10 @@ public class MainPlayer : MpvClient
static string GetNativeLanguage(string name)
{
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.NeutralCultures))
{
if (ci.EnglishName == name)
return ci.NativeName;
}
return name;
}
@@ -718,6 +636,26 @@ public class MainPlayer : MpvClient
}
}
public List<StringPair> AudioDevices {
get {
if (_audioDevices != null)
return _audioDevices;
_audioDevices = [];
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() {
List<Chapter> chapters = new List<Chapter>();
int count = GetPropertyInt("chapter-list/count");
@@ -754,6 +692,8 @@ public class MainPlayer : MpvClient
}
}
private readonly Regex TitleRegex = new Regex(@"^[\._\-]", RegexOptions.Compiled);
public List<MediaTrack> GetTracks(bool includeInternal = true, bool includeExternal = true)
{
List<MediaTrack> tracks = new List<MediaTrack>();
@@ -771,7 +711,7 @@ public class MainPlayer : MpvClient
string filename = GetPropertyString($"filename/no-ext");
string title = GetPropertyString($"track-list/{i}/title").Replace(filename, "");
title = Regex.Replace(title, @"^[\._\-]", "");
title = TitleRegex.Replace(title, "");
if (type == "video")
{
@@ -1117,7 +1057,7 @@ public class MainPlayer : MpvClient
if (_profileNames != null)
return _profileNames;
string[] ignore = { "builtin-pseudo-gui", "encoding", "libmpv", "pseudo-gui", "default" };
string[] ignore = ["builtin-pseudo-gui", "encoding", "libmpv", "pseudo-gui", "default"];
string json = GetPropertyString("profile-list");
return _profileNames = JsonDocument.Parse(json).RootElement.EnumerateArray()
.Select(it => it.GetProperty("name").GetString())

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
namespace MpvNet.Windows;

namespace MpvNet;
public class StringPair
{

View File

@@ -9,4 +9,5 @@ public class Translator
public interface ITranslator
{
public string Gettext(string msgId);
public string GetParticularString(string context, string text);
}

View File

@@ -1,16 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net10.0-windows7.0</TargetFramework>
<UseWPF>true</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
<PackageReference Include="NGettext" Version="0.6.7" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
<PackageReference Include="NGettext" />
</ItemGroup>
</Project>

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-x64
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,win-arm64"; Flags: ignoreversion recursesubdirs createallsubdirs;

View File

@@ -0,0 +1,119 @@
<#
Script that builds mpv.net and releases it on GitHub.
Please note that debug builds are built and released,
for release builds, scripts need to be rewritten.
Needs 2 positional CLI arguments:
1. Directory where the mpv.net source code is located (mpv.net\src)
2. Directory of the output files, for instance the desktop dir.
Dependencies:
7zip installation found at: 'C:\Program Files\7-Zip\7z.exe'.
Inno Setup compiler installation found at: 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe'.
GitHub CLI https://cli.github.com, the env var GH_TOKEN must be defined.
Notes:
Before you run the script you need to update the versions found in the file:
\mpv.net\src\MpvNet.Windows\MpvNet.Windows.csproj
#>
# Stop when the first error occurs
$ErrorActionPreference = 'Stop'
function DeleteDir($path) {
if (Test-Path $path) {
Remove-Item $path -Recurse
}
}
# Throw error if the file/dir don't exist
function Test($path) {
if (-not (Test-Path $path)) {
throw $path
}
return $path
}
# Variables
$SourceDir = Test $args[0]
$OutputRootDir = Test $args[1]
Test (Join-Path $SourceDir 'MpvNet.sln')
$7zFile = Test 'C:\Program Files\7-Zip\7z.exe'
$InnoSetupCompiler = Test 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe'
$ReleaseNotes = "- [.NET Desktop Runtime 10.0](https://dotnet.microsoft.com/en-us/download/dotnet/10.0)`n- [Changelog](https://github.com/mpvnet-player/mpv.net/blob/main/docs/changelog.md)"
$Repo = 'github.com/mpvnet-player/mpv.net'
# Dotnet Publish
$PublishDir64 = Join-Path $SourceDir 'MpvNet.Windows\bin\Debug\win-x64\publish\'
$PublishDirARM64 = Join-Path $SourceDir 'MpvNet.Windows\bin\Debug\win-arm64\publish\'
$ProjectFile = Test (Join-Path $SourceDir 'MpvNet.Windows\MpvNet.Windows.csproj')
dotnet publish $ProjectFile --self-contained false --configuration Debug --runtime win-x64
dotnet publish $ProjectFile --self-contained false --configuration Debug --runtime win-arm64
$PublishedExeFile64 = Test ($PublishDir64 + 'mpvnet.exe')
# Create OutputName
$VersionInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($PublishedExeFile64)
$IsBeta = $VersionInfo.FilePrivatePart -ne 0
$BetaString = if ($IsBeta) { '-beta' } else { '' }
$VersionName = $VersionInfo.FileVersion
$OutputName64 = 'mpv.net-v' + $VersionName + $BetaString + '-portable-x64'
$OutputNameARM64 = 'mpv.net-v' + $VersionName + $BetaString + '-portable-ARM64'
# Create OutputFolder
$OutputDir64 = Join-Path $OutputRootDir ($OutputName64 + '\')
$OutputDirARM64 = Join-Path $OutputRootDir ($OutputNameARM64 + '\')
DeleteDir $OutputDir64
DeleteDir $OutputDirARM64
mkdir $OutputDir64
mkdir $OutputDirARM64
# Copy Files
Copy-Item ($PublishDir64 + '*') $OutputDir64
Copy-Item ($PublishDirARM64 + '*') $OutputDirARM64
$BinDirX64 = Test (Join-Path $SourceDir 'MpvNet.Windows\bin\Debug\')
$BinDirARM64 = Test (Join-Path $SourceDir 'MpvNet.Windows\bin\Debug\win-arm64\')
$ExtraFiles = 'mpvnet.com', 'libmpv-2.dll', 'MediaInfo.dll'
$ExtraFiles | ForEach-Object { Copy-Item ($BinDirX64 + $_) ($OutputDir64 + $_) }
$ExtraFiles | ForEach-Object { Copy-Item ($BinDirARM64 + $_) ($OutputDirARM64 + $_) }
$LocaleDir = Test (Join-Path $SourceDir 'MpvNet.Windows\bin\Debug\Locale\')
Copy-Item $LocaleDir ($OutputDir64 + 'Locale') -Recurse
Copy-Item $LocaleDir ($OutputDirARM64 + 'Locale') -Recurse
# Pack
$ZipOutputFile64 = Join-Path $OutputRootDir ($OutputName64 + '.zip')
$ZipOutputFileARM64 = Join-Path $OutputRootDir ($OutputNameARM64 + '.zip')
& $7zFile a -tzip -mx9 $ZipOutputFile64 -r ($OutputDir64 + '*')
if ($LastExitCode) { throw $LastExitCode }
& $7zFile a -tzip -mx9 $ZipOutputFileARM64 -r ($OutputDirARM64 + '*')
if ($LastExitCode) { throw $LastExitCode }
Test $ZipOutputFile64
Test $ZipOutputFileARM64
# Inno Setup
''; ''
$InnoSetupScript = Test (Join-Path $SourceDir 'Setup\Inno\inno-setup.iss')
& $InnoSetupCompiler $InnoSetupScript
if ($LastExitCode) { throw $LastExitCode }
$SetupFile = Test (Join-Path $OutputRootDir "mpv.net-v$VersionName-setup-x64.exe")
if ($IsBeta) {
$NewSetupFile = Join-Path $OutputRootDir "mpv.net-v$VersionName-beta-setup-x64.exe"
Move-Item $SetupFile $NewSetupFile
$SetupFile = $NewSetupFile
}
# Release
$Title = 'v' + $VersionName + $BetaString
if ($BetaString) {
gh release create $Title -t $Title -n $ReleaseNotes --repo $Repo --prerelease $ZipOutputFile64 $ZipOutputFileARM64 $SetupFile
} else {
gh release create $Title -t $Title -n $ReleaseNotes --repo $Repo $ZipOutputFile64 $ZipOutputFileARM64 $SetupFile
}
if ($LastExitCode) { throw $LastExitCode }

103
src/Tools/update-mpv.ps1 Normal file
View File

@@ -0,0 +1,103 @@
<#
Updates mpv (x64) and libmpv (x64 , ARM64).
Files are downloaded from:
https://github.com/shinchiro/mpv-winbuild-cmake/releases
Requires 7zip being installed at 'C:\Program Files\7-Zip\7z.exe'.
Needs 3 positional CLI arguments:
1. Directory where mpv x64 is located. To skip pass '-'.
2. Directory where libmpv x64 is located. To skip pass '-'.
3. Directory where libmpv ARM64 is located. To skip pass '-'.
#>
$7ZipPath = 'C:\Program Files\7-Zip\7z.exe'
$MpvDirX64 = $args[0]
$LibmpvDirX64 = $args[1]
$LibmpvDirARM64 = $args[2]
# 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($apiURL, $pattern) {
$json = Invoke-WebRequest $apiURL -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
}
# Unpack archive
function Unpack($archieveFile, $outputRootDir) {
$outputDir = Join-Path $outputRootDir $archieveFile.BaseName
if (Test-Path $outputDir) { Remove-Item $outputDir -Recurse }
$process = Start-Process (Test $7ZipPath) @('x', $archieveFile.FullName, "-o$outputDir") -NoNewWindow -Wait
if ($process.ExitCode) { throw $process.ExitCode }
return Test $outputDir
}
# Update mpv x64
if (Test-Path (Join-Path $MpvDirX64 'mpv.exe')) {
$apiURL = "https://api.github.com/repos/shinchiro/mpv-winbuild-cmake/releases/latest"
$archiveFile = Get-Item (Download $apiURL "mpv-x86_64-[0-9]{8}-git-[0-9a-z]+\.7z")
$archiveDir = Unpack $archiveFile $env:TEMP
Remove-Item "$MpvDirX64\*" -Force -Recurse
Copy-Item "$archiveDir\*" $MpvDirX64 -Force -Recurse
Remove-Item $archiveFile.FullName
Remove-Item $archiveDir -Recurse
} else {
"mpv x64 location not found:`n$MpvDirX64"
}
# Update libmpv x64
if (Test-Path (Join-Path $LibmpvDirX64 'libmpv-2.dll')) {
$apiURL = "https://api.github.com/repos/shinchiro/mpv-winbuild-cmake/releases/latest"
$archiveFile = Get-Item (Download $apiURL "mpv-dev-x86_64-[0-9]{8}-git-[0-9a-z]+\.7z")
$archiveDir = Unpack $archiveFile $env:TEMP
Copy-Item $archiveDir\libmpv-2.dll $LibmpvDirX64 -Force
Remove-Item $archiveFile.FullName
Remove-Item $archiveDir -Recurse
} else {
"libmpv x64 location not found:`n$LibmpvDirX64"
}
# Update libmpv ARM64
if (Test-Path (Join-Path $LibmpvDirARM64 'libmpv-2.dll')) {
$apiURL = "https://api.github.com/repos/shinchiro/mpv-winbuild-cmake/releases/latest"
$archiveFile = Get-Item (Download $apiURL "mpv-dev-aarch64-[0-9]{8}-git-[0-9a-z]+\.7z")
$archiveDir = Unpack $archiveFile $env:TEMP
Copy-Item $archiveDir\libmpv-2.dll $LibmpvDirARM64 -Force
Remove-Item $archiveFile.FullName
Remove-Item $archiveDir -Recurse
} else {
"libmpv ARM64 location not found:`n$LibmpvDirARM64"
}
if (Test-Path (Join-Path $MpvDirX64 'mpv.exe')) {
Get-Item (Join-Path $MpvDirX64 'mpv.exe')
}
if (Test-Path (Join-Path $LibmpvDirX64 'libmpv-2.dll')) {
Get-Item (Join-Path $LibmpvDirX64 'libmpv-2.dll')
}
if (Test-Path (Join-Path $LibmpvDirARM64 'libmpv-2.dll')) {
Get-Item (Join-Path $LibmpvDirARM64 'libmpv-2.dll')
}