Compare commits

...

275 Commits

Author SHA1 Message Date
stax76
c56855bbc7 5.6.2.0 Beta 2022-03-05 21:05:50 +01:00
stax76
9377804b06 fixing reintroduced osc issue, sorry 2022-03-05 15:39:56 +01:00
stax76
c50ac7a53b manual update again 2022-03-05 15:23:23 +01:00
stax76
677e7b5a59 manual update 2022-03-05 15:21:33 +01:00
stax76
8066d07a76 5.6.1.0 Beta 2022-03-05 14:59:05 +01:00
stax76
e8d6081f9f ms store issue fix 2022-03-05 09:51:39 +01:00
stax76
5fb888262e Merge pull request #370 from KaranKad/conf
Added config location for Microsoft Store version
2022-03-05 08:32:13 +01:00
stax76
a4ffab7b50 misc 2022-03-05 07:55:34 +01:00
stax76
8d25803b71 #369 #367 protocol registration 2022-03-05 04:36:09 +01:00
stax76
df4baca6bc protocol fix 2022-03-05 04:05:04 +01:00
stax76
dc43ab4c8f rtsp protocol support 2022-03-05 03:48:47 +01:00
stax76
2249174f96 misc... 2022-03-04 21:49:05 +01:00
stax76
6916a63de6 several improvements 2022-03-02 21:19:55 +01:00
stax76
1064a80dad gpu-next fix 2022-03-02 14:33:47 +01:00
Karan09
4844215462 Add config location for msstore 2022-02-15 21:08:02 +05:30
stax76
b84889b03d manual download instruction updated 2022-01-03 20:57:54 +01:00
stax76
b38bfd9c65 Fix libmpv API changes 2021-12-19 18:40:34 +01:00
stax76
b807ad8002 Merge pull request #357 from hooke007/libmpv
support mpv-2
2021-12-19 16:01:57 +01:00
hooke007
f5854cde1b support mpv-2
drop the support of mpv-1
2021-12-17 07:43:31 +08:00
stax76
bde4849465 menu issue fix 2021-12-01 14:09:31 +01:00
stax76
8677efdb06 Update Main.webp 2021-11-20 21:29:22 +01:00
stax76
2bbd5705c2 readme update 2021-11-20 21:02:04 +01:00
stax76
0bf9b73ba8 manual update 2021-11-19 16:12:10 +01:00
stax76
42fd54269e improved manual 2021-11-19 14:04:46 +01:00
stax76
28f1c5c132 register ytdl protocol with file associations 2021-11-19 12:48:12 +01:00
stax76
30b60a5b4e Merge pull request #343 from hooke007/dev
Update doc
2021-11-18 10:44:50 +01:00
stax76
f0c9dd7956 docs improvement 2021-11-18 10:36:32 +01:00
hooke007
78ee4fbba2 Update Manual_chs.md
follow orginal commit 243b45326e
2021-11-17 02:54:24 +08:00
stax76
243b45326e Auto update feature removed 2021-11-14 00:05:31 +01:00
stax76
4efe85aad7 misc... 2021-11-13 23:43:47 +01:00
stax76
975f918703 changelog update 2021-11-06 16:15:05 +01:00
stax76
d9f4218bb4 Merge pull request #336 from hooke007/dev
update editor
2021-11-06 16:03:36 +01:00
stax76
671c15385a manual fix 2021-11-05 15:58:25 +01:00
stax76
091b9aad5b manual fix 2021-11-05 15:56:14 +01:00
stax76
e51b745a13 5.5.0.4 Beta 2021-11-05 15:53:57 +01:00
stax76
ad1ea92cbd window-scale property support 2021-11-05 15:23:47 +01:00
hooke007
66bfb80f3c update editor
mainly support `gpu-next`
2021-11-04 08:13:28 +08:00
stax76
ef6b453673 readme update 2021-11-02 11:47:32 +01:00
stax76
5496d22c48 readme update 2021-11-02 11:45:20 +01:00
stax76
7cd3a8276d WPF blur issue fix? 2021-10-26 12:24:23 +02:00
stax76
99ea7285ba manual fix 2021-10-24 17:19:47 +02:00
stax76
9722d46d00 support input-default-bindings 2021-10-24 17:08:07 +02:00
stax76
b115cf82d9 manual fix 2021-10-21 00:24:45 +02:00
stax76
f4e72b5a99 typo 2021-10-11 12:50:27 +02:00
stax76
24596626bd misc 2021-10-11 12:29:30 +02:00
stax76
6e761c0a4e minor change 2021-10-10 15:55:51 +02:00
stax76
2a3738f79e Improved handling of default options. 2021-10-10 15:20:12 +02:00
stax76
1a475f9fe8 Support input-builtin-bindings 2021-10-09 14:31:34 +02:00
Frank Skare
819b026ec7 Window size flicker issue fix when changing files 2021-09-23 19:46:38 +02:00
Frank Skare
38a816a255 5.5.0.3 Beta 2021-09-23 12:45:09 +02:00
Frank Skare
e8af1d2ccf cosmetic 2021-09-16 16:13:06 +02:00
Frank Skare
33cd881ae6 #321 new auto-play option 2021-09-16 16:02:59 +02:00
Frank Skare
a3b6af9f22 5.5.0.2 Beta 2021-09-15 13:25:58 +02:00
Frank Skare
458007862e 5.5.0.1 Beta 2021-09-15 11:57:01 +02:00
Frank Skare
2fac5d76e9 5.4.9.9 Beta 2021-09-14 17:26:05 +02:00
Frank Skare
1e886fc124 remove console-scale fix 2021-09-05 22:51:09 +02:00
Frank Skare
c075278180 5.4.9.8 Beta 2021-09-05 22:27:01 +02:00
Frank Skare
333d0ee62f better folder browser code 2021-09-05 21:59:05 +02:00
Frank Skare
7a6b2011e4 improved menu performance and folder browser fix 2021-09-05 08:23:42 +02:00
Frank Skare
e4c65cd84e Use Vista folder browser 2021-09-05 06:06:15 +02:00
Frank Skare
10e2a2cf3b #318 Fix message box not working when ontop is enabled 2021-09-04 12:39:28 +02:00
Frank Skare
0d72731ce7 PS ConvertFrom-Json replaced with JSONParser 2021-09-03 13:04:06 +02:00
Frank Skare
33fb645694 fix watch-later-options default 2021-09-02 15:01:11 +02:00
Frank Skare
d369c9db8e Merge branch 'master' of https://github.com/stax76/mpv.net 2021-09-02 14:42:56 +02:00
Frank Skare
a935cac791 misc 2021-09-02 14:42:53 +02:00
stax76
a08a4b4f92 Merge pull request #317 from hooke007/dev
update misc
2021-09-02 14:42:18 +02:00
hooke007
bd2ba612de a tiny optimize for console output 2021-09-02 19:45:04 +08:00
hooke007
306d186bef revert keep-open 2021-09-02 19:24:17 +08:00
hooke007
da67d62946 fix mpvconf
disable `start`
2021-09-02 00:35:49 +08:00
hooke007
50cc295e9e fix editor 2021-09-01 01:06:38 +08:00
hooke007
bec97545d1 Update CorePlayer.cs 2021-08-30 21:01:00 +08:00
hooke007
db5f0334c4 update&fix manuals 2021-08-30 02:41:06 +08:00
Frank Skare
42c623c8ca 5.4.9.7 Beta 2021-08-28 12:47:24 +02:00
Frank Skare
d3c1e2ab56 5.4.9.6 Beta 2021-08-26 13:11:07 +02:00
Frank Skare
57e60287ff msgbox fix 2021-08-26 12:51:20 +02:00
Frank Skare
007fbf8be5 5.4.9.5 Beta 2021-08-25 14:12:45 +02:00
Frank Skare
d3baa47f93 Message boxes are themed 2021-08-25 11:31:20 +02:00
Frank Skare
225905ebff menu fix 2021-08-24 16:00:16 +02:00
Frank Skare
c08ddd5057 menu performance 2021-08-24 15:20:54 +02:00
Frank Skare
970dfc069d 5.4.9.4 Beta 2021-08-24 08:22:59 +02:00
Frank Skare
9b5f9a64fd readme fix 2021-08-23 01:19:02 +02:00
Frank Skare
6720e2429e Button style in input editor. 2021-08-23 01:14:25 +02:00
Frank Skare
5070b166d9 new images 2021-08-23 00:15:17 +02:00
Frank Skare
8b6d12d57b new image 2021-08-23 00:10:45 +02:00
Frank Skare
8888747137 new images 2021-08-23 00:02:58 +02:00
Frank Skare
d83b5b14a8 5.4.9.3 Beta 2021-08-22 23:50:42 +02:00
Frank Skare
17ecd9cb82 Major UI rework! 2021-08-22 18:50:11 +02:00
Frank Skare
0829b4bd9e lua string escape fix 2021-08-16 22:28:02 +02:00
Frank Skare
fbc9652f20 update changelog 2021-08-16 11:18:42 +02:00
Frank Skare
c7d9d658f2 libmpv shinchiro 2021-08-15 2021-08-16 11:18:00 +02:00
Frank Skare
1c525618e2 #291 Leaving fullscreen using keepaspect-window=no restores the correct size 2021-08-16 11:12:53 +02:00
Frank Skare
9ead5dbd19 #309 support hwdec=auto-safe 2021-08-16 09:07:33 +02:00
Frank Skare
625e887dc1 string escape issue fix 2021-08-15 20:21:43 +02:00
Frank Skare
60cbf894e5 5.4.9.2 Beta 2021-08-08 15:26:54 +02:00
Frank Skare
95a3403898 5.4.9.2 Beta 2021-08-08 14:31:43 +02:00
Frank Skare
fbf50e7466 themed scroll bars, rounded courners, libmpv update 2021-08-08 11:55:43 +02:00
Frank Skare
e9b6988a69 window fix 2021-07-30 08:57:52 +02:00
Frank Skare
8d49c96c57 Drawing flicker in the command palette (playlist) was fixed 2021-07-29 14:25:37 +02:00
Frank Skare
ea56dcdda8 conf editor support for keepaspect-window 2021-07-28 12:28:43 +02:00
stax76
5ef8340ba3 Merge pull request #290 from hooke007/dev
fix a potential bug when switching back to `auto`
2021-07-28 11:37:07 +02:00
hooke007
51e1e85867 fix a potential bug when switching back to auto 2021-07-27 19:08:47 +08:00
Frank Skare
b24f740129 Merge branch 'master' of https://github.com/stax76/mpv.net 2021-07-27 08:50:21 +02:00
Frank Skare
653d66c343 #289 fix line break issue in conf editor 2021-07-27 08:50:19 +02:00
stax76
3dd4ae1bfc Create FUNDING.yml 2021-07-24 10:16:31 +02:00
Frank Skare
27c8ae79e0 update readme 2021-07-24 08:32:43 +02:00
Frank Skare
53e3231452 update readme 2021-07-24 08:31:30 +02:00
Frank Skare
bcf98d847a update readme 2021-07-24 08:28:51 +02:00
Frank Skare
b6ee67d506 Delete License.txt 2021-07-22 19:05:29 +02:00
Frank Skare
3f13747413 Change license from MIT to GPL v2 2021-07-22 17:50:40 +02:00
Frank Skare
54046d5c9d Merge branch 'master' of https://github.com/stax76/mpv.net 2021-07-22 08:43:12 +02:00
Frank Skare
8966f25e06 watch-later-options support added to conf editor 2021-07-22 08:43:09 +02:00
stax76
27fca2cb82 Merge pull request #286 from hooke007/dev
add watch-later-options
2021-07-22 08:41:44 +02:00
hooke007
0d1a17a41a add watch-later-options 2021-07-21 23:06:48 +08:00
Frank Skare
517e4a1142 update changelog 2021-07-19 16:15:16 +02:00
Frank Skare
a380f87b5f Profile selection in the context menu 2021-07-19 15:22:36 +02:00
Frank Skare
35d9d29d40 Support for --keep-open=no 2021-07-19 10:29:13 +02:00
Frank Skare
e1c9d81496 misc 2021-07-19 02:33:32 +02:00
Frank Skare
fbeeb3f015 manual update 2021-07-18 14:54:07 +02:00
Frank Skare
48735a602a #281 handling settings.xml crash 2021-07-17 16:45:34 +02:00
Frank Skare
886f3349ae use pascal casing everywhere 2021-07-15 14:40:59 +02:00
Frank Skare
43c150a18b set pause no before loading file 2021-07-12 00:58:16 +02:00
Frank Skare
33bbc4a2c4 Update delete-current-file.lua 2021-07-11 22:37:37 +02:00
Frank Skare
6c4a014e57 Update delete-current-file.lua 2021-07-02 16:27:25 +02:00
Frank Skare
ce0dd9ceec globalization bug fix 2021-07-01 16:30:55 +02:00
Frank Skare
3520ce6a3f script update 2021-07-01 14:16:05 +02:00
Frank Skare
376f8226ab playlist shows current file 2021-06-28 23:09:09 +02:00
Frank Skare
6b6ae6bfef Changelog update 2021-06-28 10:42:25 +02:00
stax76
b13dbf0b59 Merge pull request #278 from hooke007/dev
doc-manual:chs
2021-06-28 10:37:54 +02:00
stax76
0f7ac5c0ba Merge pull request #277 from soredake/master
Swap screenshot and stop bindings
2021-06-28 10:28:05 +02:00
Frank Skare
25b94bc2c1 new script delete-current-file.lua 2021-06-28 10:27:24 +02:00
hooke007
445730a833 follow upstream's commit 2021-06-27 20:44:01 +08:00
Frank Skare
fd1590142e toml parser replaced with own conf parser 2021-06-27 13:11:34 +02:00
hooke007
c41adc54c5 tiny fix on orig manual & fully translation 2021-06-27 16:21:52 +08:00
hooke007
a3f6b105de doc-manual:chs 2021-06-27 01:26:39 +08:00
soredake
6e402d4931 Swap screenshot and stop bindings 2021-06-26 13:10:37 +03:00
Frank Skare
c40a0d8835 Merge branch 'master' of https://github.com/stax76/mpv.net 2021-06-24 17:22:33 +02:00
Frank Skare
28416dc3d2 Merge branch 'pr/272-improvements-to-input-conf' 2021-06-24 17:20:03 +02:00
Frank Skare
1bde5b6836 misc 2021-06-24 17:19:20 +02:00
stax76
d1619bca22 Merge pull request #276 from hooke007/patch-2
update editor
2021-06-24 16:37:14 +02:00
hooke007
a123c38dfd update editor 2021-06-24 14:05:05 +08:00
stax76
e02d1850a2 Merge pull request #273 from hooke007/patch-1
fix editor's error
2021-06-23 11:54:10 +02:00
Frank Skare
bd37761fc5 readme update 2021-06-23 11:52:59 +02:00
hooke007
897b901c7c fix editor's error
"If this option is unset, the filter implied by scale will be applied."
2021-06-23 15:32:38 +08:00
Frank Skare
da882c3c11 updating screenshots 2021-06-23 09:01:00 +02:00
Frank Skare
bd1a46d18d 5.4.9.1 2021-06-23 07:28:29 +02:00
Frank Skare
1c23c10c81 #268 Fix exception using named pipes 2021-06-23 06:02:02 +02:00
Frank Skare
55f16d2c53 fancy new command palette 2021-06-22 20:54:14 +02:00
Frank Skare
bac8b2b96c misc 2021-06-22 19:10:27 +02:00
soredake
08328c91c4 Improvements to input.conf 2021-06-22 15:11:10 +03:00
Frank Skare
6634ef094c misc 2021-06-20 16:01:04 +02:00
Frank Skare
3b6e6167b0 misc 2021-06-20 11:34:57 +02:00
Frank Skare
f55dfa7a73 misc 2021-06-20 11:29:58 +02:00
Frank Skare
93f0c970da misc 2021-06-20 11:11:51 +02:00
Frank Skare
aa94da9767 #263 enhancing mpv.net option process-instance 2021-06-18 19:43:30 +02:00
Frank Skare
8340c18257 docs 2021-06-17 23:52:25 +02:00
Frank Skare
075e238c46 docs 2021-06-17 23:51:37 +02:00
Frank Skare
6e6b5ae98c docs 2021-06-17 23:49:00 +02:00
Frank Skare
2078ff867b docs 2021-06-17 23:45:58 +02:00
Frank Skare
446d88e16a trying to fix window issues 2021-06-17 17:46:17 +02:00
Frank Skare
ebacaa0341 #140 Fix window size not being saved 2021-06-17 16:32:35 +02:00
Frank Skare
8420abd915 external audio and subtitle tracks 2021-05-31 10:17:55 +02:00
Frank Skare
650c41eb8a Context menu font render quality fix 2021-05-30 19:42:41 +02:00
Frank Skare
db3018bbf5 Show error message box on main window thread. 2021-05-30 15:08:44 +02:00
Frank Skare
539f94d1c9 New media info command 2021-05-30 14:39:15 +02:00
Frank Skare
f56502d8f3 do not load extensions from startup directory 2021-05-30 12:25:57 +02:00
Frank Skare
57ae0d008b 5.4.9.0 2021-05-29 12:17:20 +02:00
Frank Skare
e128a4868b Improved input editor theming 2021-05-28 21:58:32 +02:00
Frank Skare
3875e1c1bf docs 2021-05-28 12:06:34 +02:00
stax76
dd508907eb Merge pull request #253 from hooke007/master
fix some links
2021-05-28 11:47:58 +02:00
Frank Skare
765854cd10 After using the config editor it's no longer necessary to restart mpv.net. 2021-05-28 11:38:36 +02:00
hooke007
69fe7c091a fix some links 2021-05-26 20:31:09 +08:00
Frank Skare
45a2b7f976 AR fix 2021-05-24 21:31:35 +02:00
Frank Skare
a8cf3407e7 #245 Video rotation support added 2021-05-24 20:06:30 +02:00
Frank Skare
b8163c3c3e logo issue fix 2021-05-24 11:13:49 +02:00
Frank Skare
9d27465492 Store settings in settings.xml instead of registry. 2021-05-24 03:09:23 +02:00
Frank Skare
bba71c3782 fix #249 2021-05-23 22:21:59 +02:00
Frank Skare
eaa8a3ca6c removal of TaskDialog usage... 2021-05-23 19:30:21 +02:00
Frank Skare
0b28770d1a - 2021-05-16 16:49:43 +02:00
Frank Skare
45d3386a88 Improved cycle-audio OSD info 2021-05-13 23:10:45 +02:00
Frank Skare
8df330b7aa High DPI multi monitor fix 2021-05-13 11:53:36 +02:00
Frank Skare
69857e0548 new window features 2021-05-11 17:55:37 +02:00
Frank Skare
b1388e10e5 working on start-size option 2021-05-11 10:19:14 +02:00
Frank Skare
6f7f127279 reworked start-size option 2021-05-10 13:11:39 +02:00
Frank Skare
18c8f5783b 5.4.8.8 Beta 2021-05-09 15:50:09 +02:00
Frank Skare
cdf3eb1373 docs 2021-05-07 11:19:09 +02:00
Frank Skare
e5bcd0fc29 argh 2021-05-07 11:14:53 +02:00
Frank Skare
b0dc44a98e argh 2021-05-07 11:14:32 +02:00
Frank Skare
41a14cd3b7 argh 2021-05-07 11:12:59 +02:00
Frank Skare
b38c7cf834 argh 2021-05-07 11:12:25 +02:00
Frank Skare
2ee4c1e647 manual 2021-05-07 11:04:24 +02:00
Frank Skare
2bcf97a97a option --command to send input commands 2021-05-07 10:55:41 +02:00
Frank Skare
8eaec77b0c manual update 2021-05-06 16:45:55 +02:00
Frank Skare
3161ba1022 rating extension update 2021-05-06 16:42:07 +02:00
Frank Skare
496bba71d4 manual URL fixes 2021-05-06 16:30:09 +02:00
Frank Skare
3e1e822e56 docs URL fix 2021-05-06 16:08:09 +02:00
Frank Skare
b1ea6da39b URL fix 2021-05-06 15:52:26 +02:00
Frank Skare
8d54abae4c URL fix 2021-05-06 15:44:19 +02:00
Frank Skare
3583aa11ed new folder structure and new C# script host 2021-05-06 15:23:28 +02:00
Frank Skare
642c36bacf wpf error handling 2021-04-30 15:09:31 +02:00
Frank Skare
0343b32847 proper mpv title property implementation 2021-04-30 14:53:41 +02:00
Frank Skare
6e2d11952f misc... 2021-04-30 11:50:41 +02:00
Frank Skare
d0ad69656a Command palette shows commands without assigned menu item 2021-03-10 16:40:31 +01:00
Frank Skare
62789fa036 Implementation for the mpv title property.
mpv window-scale property works now exactly like in mpv.
2021-03-10 13:28:39 +01:00
Frank Skare
a7fe444067 manual update 2021-03-09 10:37:59 +01:00
Frank Skare
1ef4740b09 mpv.net specific options added to manual 2021-03-09 10:28:04 +01:00
Frank Skare
c5e445da17 error message removal and release script fix 2021-03-09 09:15:47 +01:00
Frank Skare
a52de9039d 5.4.8.7 Beta 2021-03-09 07:23:26 +01:00
Frank Skare
8db8e497a5 File associations and auto-load-folder can be customized 2021-03-09 06:56:55 +01:00
Frank Skare
28c9b2710c Support of --version command 2021-02-16 10:03:35 +01:00
Frank Skare
6ba9b1f05a Win 10 default code page changed to UTF8 2020-12-30 01:01:48 +01:00
Frank Skare
ea5d3e64ee Web stream audio and subtitle track selection 2020-12-29 06:00:06 +01:00
Frank Skare
636d28ac54 history feature can be configured 2020-12-28 02:30:45 +01:00
Frank Skare
6e54286a60 5.4.8.6 Beta 2020-12-24 11:39:20 +01:00
Frank Skare
b396012934 Santa hat shown in december 2020-12-24 11:24:03 +01:00
Frank Skare
f3909acdfe #218 2020-12-15 18:13:38 +01:00
Frank Skare
3ed71444a7 fix setup dialog issue 2020-12-15 18:12:10 +01:00
Frank Skare
cab7c6d49b update manual 2020-12-15 17:28:53 +01:00
Frank Skare
368641523a new menu image 2020-12-14 20:29:46 +01:00
Frank Skare
42c76d25c6 update readme 2020-12-14 00:52:06 +01:00
Frank Skare
3968fa50f5 #214 Filename not being always shown in title bar. 2020-12-13 23:08:16 +01:00
Frank Skare
4d985c7b7c misc... 2020-12-13 08:12:50 +01:00
Frank Skare
235a52a701 remove 7z from release 2020-12-11 17:54:02 +01:00
Frank Skare
9a63b660de 5.4.8.5 Beta 2020-12-11 17:49:51 +01:00
Frank Skare
8eb0222873 setup redesign 2020-12-10 15:54:32 +01:00
Frank Skare
bf8636135a setup redesign 2020-12-09 22:01:33 +01:00
Frank Skare
33cdee5497 show setup dialog on new startup location 2020-12-09 09:56:51 +01:00
Frank Skare
564d7b10a0 improved setup dialog 2020-12-08 18:54:50 +01:00
Frank Skare
a1a408da1d improved setup dialog 2020-12-06 16:54:06 +01:00
Frank Skare
85a3506403 misc... 2020-12-02 03:40:38 +01:00
Frank Skare
e860cf52c4 Merge branch 'master' of https://github.com/stax76/mpv.net 2020-11-25 16:21:55 +01:00
Frank Skare
32a46e47e2 New feature for rating extension 2020-11-25 16:21:53 +01:00
stax76
538e91aaa9 New option global-media-keys 2020-10-08 18:07:23 +02:00
stax76
94eaf8144f cleanup 2020-10-08 17:56:49 +02:00
stax76
404a8f110d global media keys 2020-10-08 17:34:27 +02:00
Frank Skare
14f5228754 AviSynth portable mode 2020-08-03 20:42:48 +02:00
Frank Skare
5ec2d1b436 Merge branch 'master' of https://github.com/stax76/mpv.net 2020-07-28 15:38:21 +02:00
Frank Skare
32c6ce3a44 docs update 2020-07-28 15:36:57 +02:00
stax76
b86148dfb3 Update issue templates 2020-07-28 15:11:46 +02:00
stax76
26e94fad2b Update issue templates 2020-07-28 15:10:35 +02:00
Frank Skare
c306eb032f 5.4.8.4 Beta 2020-07-26 04:04:35 +02:00
Frank Skare
09944583dd message asking if image is BD or DVD 2020-07-26 04:03:56 +02:00
Frank Skare
8f4ad52469 Cycle audio was not working for BluRay 2020-07-26 03:34:57 +02:00
Frank Skare
5f4eca21e5 BluRay folder path auto detection 2020-07-26 03:19:35 +02:00
Frank Skare
b4632a0b6e fix slow BluRay menu 2020-07-26 02:19:29 +02:00
Frank Skare
c14a11170d 5.4.8.3 Beta 2020-07-25 12:51:16 +02:00
Frank Skare
723005b28f fix issue 188 2020-07-25 12:45:47 +02:00
Frank Skare
72f25a686e default screen and mouse wheel fix 2020-07-25 11:40:33 +02:00
stax76
b1fb940759 Merge pull request #184 from arnesacnussem/master
fix for #124
2020-07-02 14:37:11 +02:00
Arne
1020cd70d1 fix for #124
wheel_left and wheel_right still can't be detected in `Learn Input` window.
2020-06-30 20:41:05 +08:00
Frank Skare
50a2f13dbe 5.4.8.2 Beta 2020-06-23 02:41:29 +02:00
Frank Skare
b1ffb8291f Merge branch 'master' of https://github.com/stax76/mpv.net 2020-06-20 03:35:29 +02:00
Frank Skare
dbc8ddaf2b misc 2020-06-20 03:35:27 +02:00
stax76
b42cb6be05 Merge pull request #170 from Naomi010Sentzke/patch-1
Manual.md : Remove Chocolatey and Appget
2020-05-21 20:43:09 +02:00
Naomi Sentzke
b63363336f Update Manual.md 2020-05-19 10:38:34 +05:30
Frank Skare
b0ef161ed9 fix stdin support 2020-05-12 18:18:04 +02:00
Frank Skare
7d31237d5f fix release script 2020-05-11 17:14:23 +02:00
Frank Skare
3705e2abbf 5.4.8.0 2020-05-11 17:08:01 +02:00
Frank Skare
7d73529c83 fix beep sound when closed from taskbar 2020-05-11 12:16:40 +02:00
Frank Skare
2e59d49ad1 2 bugs fixed 2020-05-11 03:51:52 +02:00
Frank Skare
f61eef8961 5.4.7.4 Beta 2020-05-10 07:01:59 +02:00
Frank Skare
efb4c085d5 fix release script 2020-05-08 15:56:54 +02:00
Frank Skare
4a045d6a91 setting media-keys added 2020-05-08 15:32:47 +02:00
Frank Skare
da1a78cfa3 5.4.7.2 Beta 2020-05-08 09:22:19 +02:00
Frank Skare
5b3697fbde built-in WM_APPCOMMAND support 2020-05-08 08:26:44 +02:00
Frank Skare
726d759589 misc 2020-05-07 13:32:23 +02:00
Frank Skare
ed614332f7 misc 2020-05-07 13:21:59 +02:00
Frank Skare
9d46064dca 5.4.7.1 Beta 2020-05-07 11:47:09 +02:00
Frank Skare
407b49b3ad 5.4.7.0 2020-05-06 18:51:38 +02:00
Frank Skare
0e92d4ec0c 5.4.7.0 2020-05-06 18:43:20 +02:00
Frank Skare
4f96835e19 support avisynth portable 2020-05-06 11:11:09 +02:00
Frank Skare
56d954d94e manual 2020-05-04 16:30:39 +02:00
Frank Skare
a8aeb1e3e9 manual 2020-05-04 16:28:59 +02:00
Frank Skare
415fd266a2 log error fix 2020-05-04 15:15:40 +02:00
Frank Skare
51f9e17380 5.4.6.0 2020-05-04 05:50:29 +02:00
Frank Skare
28045ad33e 5.4.5.1 Beta 2020-05-03 11:10:56 +02:00
211 changed files with 17225 additions and 9652 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
github: stax76
patreon: stax76
ko_fi: stax76

View File

@@ -0,0 +1,10 @@
---
name: Ask a question
about: Ask a question about mpv.net
title: ''
labels: question
assignees: stax76
---
This template is meant for usage questions of mpv.net.

View File

@@ -1,5 +1,5 @@
---
name: Bug report
name: Report a bug
about: Create a report to help us improve
title: ''
labels: bug

View File

@@ -1,8 +1,8 @@
---
name: Feature request
name: Request a feature
about: Suggest an idea for this project
title: ''
labels: enhancement
labels: feature request
assignees: stax76
---

View File

@@ -1,24 +0,0 @@
MIT License
Copyright (C) 2017-2020 Frank Skare (stax76)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and ssociated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.

340
License.txt Normal file
View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1,5 +1,5 @@
![](https://raw.githubusercontent.com/stax76/mpv.net/master/img/mpvnet.png)
![](docs/img/mpvnet.png)
![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/stax76/mpv.net) ![GitHub closed issues](https://img.shields.io/github/issues-closed/stax76/mpv.net) ![GitHub All Releases](https://img.shields.io/github/downloads/stax76/mpv.net/total) ![GitHub tag (latest by date)](https://img.shields.io/github/tag-date/stax76/mpv.net) ![GitHub stars](https://img.shields.io/github/stars/stax76/mpv.net)
@@ -16,12 +16,14 @@ Modern GUI with customizable color themes.
#### Command Line Interface
mpv.net supports mpvs property based command line switches.
mpv.net supports mpvs command line interface.
#### High quality video output
Video output that is capable of many features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more.
Video output that is capable of many features loved by videophiles,
such as video scaling with popular high quality algorithms,
color management, frame timing, interpolation, HDR, and more.
#### On Screen Controller
@@ -41,68 +43,74 @@ mpv.net is under active development.
#### Based on libmpv
mpv.net is based on libmpv which offers a straightforward C API that was designed from the ground up to make mpv usable as a library and facilitate easy integration into other applications. mpv is like VLC not based on DirectShow or Media Foundation.
mpv.net is based on libmpv which offers a straightforward C API that
was designed from the ground up to make mpv usable as a library and
facilitate easy integration into other applications.
mpv is like VLC not based on DirectShow or Media Foundation.
Table of contents
-----------------
- [Features](#features)
- [Features](#features-that-mpv-and-mpvnet-have-in-common)
- [Support](#support)
- [Download](#download)
- [Manual](#manual)
- [Screenshots](#screenshots)
Features
--------
Features that mpv and mpv.net have in common
--------------------------------------------
- High degree of mpv compatibility, almost all mpv features are available
- Customizable context menu defined in the same file as the key bindings
- Config dialog
- Shorcut key editor
- Many features like the config editor and shortcut key editor are fully searchable
- Configuration files that are easy to read and edit
- Command palette to quickly find commands and keys
- Modern graphical user interface with customizable color themes
- Extension API for .NET languages (C#, VB.NET and F#)
- Scripting API for C#, Lua, JavaScript and PowerShell
- Lua and JavaScript Scripting
- Simple config files that are easy to read and edit
- JSON IPC to control the player with a external programs
- On Screen Controler (OSC, play control buttons) with modern flat design
- Command Line Interface
- Started from a terminal status 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
- File search feature powered by the popular search and index tool Everything
- Browser extensions to start mpv.net from the browser
- Fast seek performance
- Fast startup performance
- Usable as video player, audio player and image viewer with a wide range of supported formats
- Built-in decoders, no external codecs have to be installed
- Setup as x64, x86, installer, portable, Chocolatey and Scoop
- Build-in media streaming via youtube-dl
- File associations can be created by the setup and from the player
- Build-in media streaming (requires yt-dlp being installed)
- External audio and subtitle files can be loaded manually or automatically
- Screenshot feature
- Watch later feature to save the video position
Features exclusiv 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
- Searchable config editor
- Searchable input (shorcut keys) editor
- C# and PowerShell Scripting
- Global keyboard shortcuts
- Command palette to quickly and easily find commands and keys
- 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
- Watch later feature to save the position
- Files can be enqueued from File Explorer
- Update check and update routine
## [Support](Manual.md#support)
## [Support](docs/Manual.md#support)
[Support section of the manual.](Manual.md#support)
[Support section of the manual.](docs/Manual.md#support)
## [Download](Manual.md#download)
## [Download](docs/Manual.md#download)
[Download section of the manual.](Manual.md#download)
[Download section of the manual.](docs/Manual.md#download)
## [Manual](Manual.md)
## [Manual](docs/Manual.md)
[The mpv.net documentation.](Manual.md)
[The mpv.net documentation.](docs/Manual.md)
Screenshots
@@ -110,39 +118,52 @@ Screenshots
#### Main Window
![Main Window](https://raw.githubusercontent.com/stax76/mpv.net/master/img/Main.png)
![Main Window](docs/img/Main.webp)
#### Context Menu
Context menu using dark mode.
![Context Menu](https://raw.githubusercontent.com/stax76/mpv.net/master/img/Menu.png)
![Context Menu](docs/img/Menu.jpg)
#### Config Editor
Searchable config editor as alternative to edit the conf file manually.
![](https://raw.githubusercontent.com/stax76/mpv.net/master/img/ConfEditor.png)
![](docs/img/ConfEditor.png)
#### Terminal
OSD console and status printed on the terminal.
![](https://raw.githubusercontent.com/stax76/mpv.net/master/img/Terminal.png)
![](docs/img/Terminal.png)
#### Input Editor
Searchable key and mouse binding editor.
![Input Editor](https://raw.githubusercontent.com/stax76/mpv.net/master/img/InputEditor.png)
![Input Editor](docs/img/InputEditor.webp)
#### Command Palette
Command Palette to find commands and shortcut keys easily.
Command Palette to easily find commands and shortcut keys.
![Command Palette](https://raw.githubusercontent.com/stax76/mpv.net/master/img/CommandPalette.png)
![Command Palette](docs/img/CommandPalette.webp)
#### Playlist
The command palette based playlist showing my favorite artist of the stax record label.
![Playlist](docs/img/Playlist.png)
List of my apps
---------------
https://stax76.github.io/frankskare

View File

@@ -1,114 +0,0 @@
$ErrorActionPreference = 'Stop'
$include = @(
'*.cs',
'*.csproj',
'*.iss',
'*.js',
'*.lua',
'*.md',
'*.ps1',
'*.resx',
'*.sln',
'*.txt',
'*.xaml'
)
$files = Get-ChildItem -Path $PSScriptRoot -Recurse -File -Include $include
foreach ($file in $files)
{
$lines = Get-Content $file
foreach ($line in $lines)
{
foreach ($char in $line.ToCharArray())
{
$codePoint = [int]$char
if ($codePoint -gt 127)
{
throw "Non ASCII char $char in file '$($file.FullName)' in line: $line"
}
}
}
}
$desktopDir = [Environment]::GetFolderPath('Desktop')
$exePath = $PSScriptRoot + '\mpv.net\bin\x64\mpvnet.exe'
$versionInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($exePath)
$vsDir = 'C:\Program Files (x86)\Microsoft Visual Studio\2019'
$msBuild = $vsDir + '\Community\MSBuild\Current\Bin\MSBuild.exe'
$inno = 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe'
$7z = 'C:\Program Files\7-Zip\7z.exe'
if ($versionInfo.FilePrivatePart -eq 0)
{
& $msBuild mpv.net.sln -t:Rebuild -p:Configuration=Debug -p:Platform=x64
if ($LastExitCode) { throw $LastExitCode }
& $msBuild mpv.net.sln -t:Rebuild -p:Configuration=Debug -p:Platform=x86
if ($LastExitCode) { throw $LastExitCode }
& $inno /Darch=x64 setup.iss
if ($LastExitCode) { throw $LastExitCode }
& $inno /Darch=x86 setup.iss
if ($LastExitCode) { throw $LastExitCode }
$targetDir = $desktopDir + "\mpv.net-portable-x64-$($versionInfo.FileVersion)"
Copy-Item .\mpv.net\bin\x64 $targetDir -Recurse -Exclude System.Management.Automation.xml
& $7z a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
& $7z a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
$targetDir = $desktopDir + "\mpv.net-portable-x86-$($versionInfo.FileVersion)"
Copy-Item .\mpv.net\bin\x86 $targetDir -Recurse -Exclude System.Management.Automation.xml
& $7z a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
& $7z a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
}
else
{
& $msBuild mpv.net.sln -t:Rebuild -p:Configuration=Debug -p:Platform=x64
if ($LastExitCode) { throw $LastExitCode }
$targetDir = "$desktopDir\mpv.net-portable-x64-$($versionInfo.FileVersion)-beta"
Copy-Item .\mpv.net\bin\x64 $targetDir -Recurse -Exclude System.Management.Automation.xml
& $7z a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
$cloudDirectories = 'C:\Users\frank\OneDrive\Public\mpv.net\',
'C:\Users\frank\Dropbox\Public\mpv.net\'
foreach ($cloudDirectory in $cloudDirectories)
{
if (-not (Test-Path $cloudDirectory))
{
throw $cloudDirectory
}
$targetFile = $cloudDirectory + (Split-Path $targetDir -Leaf) + '.7z'
if (Test-Path $targetFile)
{
throw $targetFile
}
Copy-Item ($targetDir + '.7z') $targetFile
Invoke-Item $cloudDirectory
}
}
Set-Clipboard ($versionInfo.FileVersion + "`n`n" +
'https://github.com/stax76/mpv.net/blob/master/Changelog.md' + "`n`n" +
'https://github.com/stax76/mpv.net#download')
Write-Host 'successfully finished' -ForegroundColor Green

View File

@@ -1,8 +1,336 @@
5.4.4.7 Beta (not yet released)
5.6.2.0 Beta (2022-03-05)
- Fix script-opts files being ignored, removed options are:
script-opts = osc-scalewindowed=1.5,osc-hidetimeout=2000,console-scale=1.5
- Update MediaInfo to version 21.9.0.0 and
write version and date in About dialog.
- Provide setup options in command palette to ensure backward
compatibility with previous input.conf definitions.
5.6.1.0 Beta (2022-03-05)
- Various conf editor improvements. (hooke007)
- Custom conf folder location feature removed.
- Inno Setup replaced with Microsoft Store setup.
- Fix script-opts files being ignored.
- Showing the recent list in the command palette,
the top item gets auto selected.
https://github.com/stax76/mpv.net/issues/328#issuecomment-1057296054
- If the play list is empty, the most recent file
gets loaded when pressing space.
https://github.com/stax76/mpv.net/issues/328#issuecomment-1057296054
- Ctrl+v (previously u) opens files (or URLs) from the clipboard,
previously it had to be a file path (format string) and now
it can also be the clipboard format of type file.
- The usability of the menu structure was improved.
- Audio and subtitle tracks and various other features
are now available in the command palette.
- Single character input in the command palette searches exclusively
key bindings, much like the search field of the input editor.
- Various default key bindings improved.
- New protocol registrations, so far supported are: ytdl, rtsp, srt, srtp
- libmpv zhongfly 2022-02-27
5.5.0.4 Beta (2021-11-05)
- Window size flicker issue fix when changing files.
- Support input-builtin-bindings to make mp.add_key_binding behave same as in mpv.
- window-scale property support.
- libmpv shinchiro 2021-10-31
5.5.0.3 Beta (2021-09-23)
- New mpv.net option auto-play which sets pause=no on file load and
selecting from the playlist. Disabled by default.
- New option start-size=session to freeze the window size per session.
- Changed keepaspect-window behavior.
5.5.0.2 Beta (2021-09-15)
- Fix of keepaspect-window=no.
5.4.9.8 Beta (2021-09-05)
- All PowerShell dependencies except the scipt host were
removed in order to improve Windows 7 compatibility.
- Fix message box not working when ontop is enabled.
- Use Vista folder browser.
- Improved context menu performance.
- libmpv shinchiro 2021-09-05
5.4.9.7 Beta (2021-08-28)
- Fix exception closing command palette on Windows 7.
5.4.9.6 Beta (2021-08-26)
- Message box fix.
5.4.9.5 Beta (2021-08-25)
- Message boxes are themed.
5.4.9.4 Beta (2021-08-24)
- Fix of command palette crash on Windows 7.
5.4.9.3 Beta (2021-08-22)
- Leaving fullscreen using keepaspect-window=no restores the correct size.
- Major UI rework!
- libmpv shinchiro 2021-08-15
5.4.9.2 Beta (2021-08-08)
- Manual translated to simplified Chinese. (hooke007)
- watch-later-options support added to conf editor. (hooke007)
- Showing the playlist selects the currently played file/stream in the playlist.
- Properties are shown in the command palette instead of the text editor
making it very easy to find a property and show/print its value.
- Support for --keep-open=no.
- Profile selection in the context menu.
- Use defaults in case settings.xml fails loading (not reproducible).
- conf editor support for keepaspect-window.
- Drawing flicker in the command palette (playlist) was fixed.
- Saving window size and position was fixed.
- Some scroll bars where replaced with Windows 10 styled scroll bars,
complex code used from HandyControl project.
- Some UI elements use rounded corners.
- The recent list can also be shown in the command palette:
Alt+r script-message mpv.net show-recent #menu: View > Show Recent
- The recent context menu removes the folder info in case of very long paths.
- libmpv shinchiro 2021-08-01
5.4.9.1 Beta (2021-06-23)
=========================
- Fix exception using named pipes.
- The mpv window property keepaspect-window was implemented.
- Everything search removed to keep the core player lightweight,
it might come back as user script or extension.
- The command palette is integrated into the main window.
- Playlist is shown with the command palette and not using the OSD.
- New media info command: `Ctrl+m script-message mpv.net show-media-info #menu: View > Show Media Info`
- Context menu font render quality fix.
- Context menu and `cycle-audio` command supports external audio and subtitle tracks.
- Fix window size not being saved.
- libmpv shinchiro 2021-06-20
5.4.9.0 (2021-05-29)
====================
- `window-scale 1` does not work correctly in mpv,
so I've removed support for it and added my own implementation:
`script-message mpv.net window-scale`.
- The CS-Script library was replaced with my own C# scripting implementation.
- If a player window border is near to a screen border and the window size
changes, the player windows sticks to that near screen border location.
Furthermore the `remember-window-position` option remembers a near screen
border position instead of remembering the window center position.
- Multi monitor fix using different DPI values.
- `start-size` option has new options, see config editor and manual.
- Improved `script-message mpv.net cycle-audio` OSD info.
- The logic for finding the config directory has changed, see manual.
- The dotnet script and extension host was a little redesigned, this breaks
backward compatibility unfortunately, but I can help fixing existing
open source code however. Example scripts and extensions were updated.
- Fix console not working due to incorrect mpv.conf value generated
(script-opts=console-scale=0).
- Settings are stored in the file settings.xml now instead of the Registry.
- Video rotation support added.
- After using the config editor it's no longer necessary to restart mpv.net.
- Improved input editor theming.
5.4.8.8 Beta (2021-05-09)
=========================
- Improved window scaling.
- Title property implementation.
- Command palette shows commands without assigned menu item.
- The code from the included JavaScript file was ported into the core
player because JavaScript is currently broken in the builds of shinshiro.
- New option `--command=<input command>`, can be used in combination
with `process-instance=single` to control mpv.net via command line,
for instance to create global hotkeys with AutoHotkey.
- New global hotkey feature added using the file global-input.conf.
- The global-media-keys option was removed because global-input.conf
can be used instead.
- MediaInfo 21.3
- libmpv shinchiro 2021-04-04
5.4.8.7 Beta (2021-03-09)
=========================
- History feature can be configured to ingore defined strings:
script-opt = history-discard=value1;value2
- Web stream audio and subtitle track selection.
- On Windows 10 1903 and later the default code page was changed to UTF-8.
- Support of --version command.
- File associations and auto-load-folder can be customized with
video-file-extensions, audio-file-extensions and image-file-extensions.
- Fix menu not showing key '&'.
5.4.8.6 Beta (2020-12-24)
=========================
- Santa hat shown in december. (#216)
- Filename not being always shown in title bar. (#214)
- Improved OSD message when cycling audio.
- DVD audio and subtitle track selection.
- Input keylist can be shown on the command-line with --input-keylist
- Profiles can be shown on the command-line with --profile=help
- Decoders can be shown on the command-line with --ad=help and --vd=help
- Decoders can be shown in the menu under: View > Show Decoders
- Demuxers can be shown in the menu under: View > Show Demuxers
- Audio devices can be shown in the menu under: View > Show Audio Devices
- Audio devices can be shown on the command-line with --audio-device=help
- Protocols can be shown in the menu under: View > Show Protocols
- Allow mpv.net to start from different startup locations
without showing the setup dialog. (#218)
- libmpv updated to shinshiro 2020-12-20
5.4.8.5 Beta
============
-
- Load AviSynth DLL from environment variable AviSynthDLL
in order to support AviSynth portable mode.
- New option global-media-keys (next, previous, play/pause, stop).
- Redesigned PowerShell based setup and setup dialog, it was done
because of a bug and upcoming chocolately and winget integration.
- Redesigned auto update using different file name, using zip instead
of 7zip format now, 7zip distribution will shortly get dropped.
- Whenever there is a new startup location, the setup dialog is shown.
- libmpv updated to shinshiro 2020-12-06
- youtube-dl is no longer included, users have to install it
on their own (put it in the startup or a PATH folder).
5.4.8.4 Beta
============
- Blu-rays with dozens of titles showed all titles in the menu
which was difficult to choose and extremely slow.
- Blu-ray folder paths are auto detected when received
from drag & drop and command-line.
- Cycle audio was not working for Blu-ray.
- Message asking if image is BD or DVD in case image is < 10 GB.
5.4.8.3 Beta
============
- Support Wheel_Left and Wheel_Right. (arnesacnussem)
- Default screen was changed from primary to OS default to start
from the same screen where the File Explorer window is located.
- When mpv.net was started maximized and next was invoked then the
window state was changed to normal instead of staying maximized.
5.4.8.2 Beta
============
- CLI --shuffle issue fix.
- ISO image files can be opened like any other files, files smaller
than 10 GB are handled as DVD and larger as BluRay.
- Menu support for BluRay title, audio and subtitle selection.
- Property input-key-list can be shown with: View > Show Keys
- youtube-dl 2020.06.16.1
- libmpv 2020-06-21 shinchiro
5.4.8.1 Beta
============
- fix stdin support
5.4.8.0
=======
- fix learn window of input editor (much work)
- fix black one pixel bar on right side
- fix beep sound when closed from taskbar
5.4.7.4 Beta (not yet released)
============
- the media key issue should now be fixed!
- libmpv and youtube-dl update
5.4.7.3 Beta
============
- new setting media-keys added, can be found in the config editor in the input tab.
5.4.7.2 Beta
============
- another attempt to fix a app command issue. WM_APPCOMMAND (mpv calls this media keys)
based input is no longer directly passed to mpv but rather handled in mpv.net directly
translating the native commands to mpv keys and sent via keypress input command to mpv
- another attempt to fix a crash caused by powershell 5.1 not being installed
5.4.7.1 Beta
============
- log error fix, mpv.net does now ignore all log messages because libmpv already
prints the log messages to the the terminal
- the release script now also outputs x86 beta versions so x86 users can test betas
5.4.7.0
=======
- log error fix
- workaround to support AviSynth portable (ffmpeg blocks loading AviSynth from path env var)
- attempt to fix not reproducible volume input issue
- attempt to fix exception caused by powershell being not available on Win 7
5.4.6.0
=======
- youtube-dl update
- auto update routine fix
5.4.5.1 Beta
============
- extensions no longer need to end with *Extension.dll but rather
the file name and the directory name must be identical
- text encoding exception fix
- the PowerShell script host is more feature complete, easier to use
and more efficient, there were however many PowerShell and C# breaking
changes requrired to make the core more robust and efficient
- Python 2 script host removed, Python 3 support is planned for summer
5.4.5.0
=======
stable release, no changes since the last beta
5.4.4.6 Beta
@@ -203,7 +531,7 @@
- libmpv was updated to shinchiro 2019-08-04
- in case mpv.net was started from a terminal it sets now the mpv property input-terminal to yes,
this means mpv.net will now receive and handle input keys from the terminal
- certain command line properties didn't work (input-terminal, terminal, input-file,
- certain command-line properties didn't work (input-terminal, terminal, input-file,
config, config-dir, input-conf, load-scripts, script, scripts, player-operation-mode)
- the about dialog shows now the mpv version and build date
- the dialog that asks for a config folder has now a cancel option
@@ -214,7 +542,7 @@
- the logo/icon had a very small cosmetic change
- the help in the context menu was improved,
for quick access consider the command palette (F1 key)
- config options specific to mpv.net are now available from the command line
- config options specific to mpv.net are now available from the command-line
- the input editor no longer has known limitations, 'alt gr' and ctrl+alt are working now
- the help in the input editor was simplified and the filter logic was improved
- fixed issue in file associations causing mpv.net not to appear in OS default apps
@@ -230,10 +558,10 @@
- the search field in the config editor was not always remembered
- new setting remember-volume added, saves volume and mute on exit
and restores it on start.
- it's now enforced that mpv properties on the command line and in
- it's now enforced that mpv properties on the command-line and in
the mpv.conf config file are lowercase, if not a error is shown
- gpu-api vulkan was not working if media files were opened via
command line (that included Explorer)
command-line (that included Explorer)
- new setting minimum-aspect-ratio added, minimum aspect ratio for the window,
this was previously hard coded to 1.3
- new setting auto-load-folder added, for single files automatically load
@@ -348,7 +676,7 @@
thanks to 44vince44 for pointing this out!!!
- new Python and C# script examples were added to the wiki and the scripting and
extension documentation was improved
- invalid command line arguments were ignored, now an error message is shown
- invalid command-line arguments were ignored, now an error message is shown
- a description on how to start mpv.net from Google Chrome was added to the
manual, it's useful to play videos from sites like YouTube, find the
description [here](https://github.com/stax76/mpv.net/blob/master/Manual.md#chrome-extension)
@@ -394,7 +722,7 @@
- drag & drop support for subtitles was added
- libmpv was updated
- command line support for stdin and URLs was added
- command-line support for stdin and URLs was added
- there was a crash happening when the player is
minimized in the taskbar
@@ -407,7 +735,7 @@
- the info command (i key) shows the audio format
- new options osd-font-size, sub-font, sub-font-size
- new color options with dedicated GUI support: sub-color, sub-border-color, sub-back-color
- the config editor no longer shows the command line switches
- the config editor no longer shows the command-line switches
- the github start page was greatly improved
- the setup.ps1 PowerShell script was greatly improved in regard of error handling and readability
- a [manual to mpv.net](Manual.md) was created

View File

@@ -2,6 +2,8 @@
mpv.net manual
==============
**ENGLISH** | **[简体中文](Manual_chs.md)**
Table of contents
-----------------
@@ -10,96 +12,19 @@ Table of contents
* [Installation](#installation)
* [Support](#support)
* [Settings](#settings)
* [Input and context menu](#input-and-context-menu)
* [Command Line Interface](#command-line-interface)
* [Terminal](#terminal)
* [mpv.net specific options](#mpvnet-specific-options)
* [External Tools](#external-tools)
* [Scripting](#scripting)
* [Extensions](#extensions)
* [Color Theme](#color-theme)
* [Advanced Features](#advanced-features)
* [Hidden Features](#hidden-features)
* [Differences](#differences)
* [Differences compared to mpv](#differences-compared-to-mpv)
* [Technical Overview](#technical-overview)
* [Context Menu](#context-menu)
+ [Open > Open Files](#open--open-files)
+ [Open > Open URL or file path from clipboard](#open--open-url-or-file-path-from-clipboard)
+ [Open > Open DVD/Blu-ray Drive/Folder](#open--open-dvd-blu-ray-drive-folder)
+ [Open > Show media search](#open--show-media-search)
+ [Open > Load external audio files](#open--load-external-audio-files)
+ [Open > Load external subtitle files](#open--load-external-subtitle-files)
+ [Play/Pause](#play-pause)
+ [Stop](#stop)
+ [Toggle Fullscreen](#toggle-fullscreen)
+ [Navigate > Previous File](#navigate--previous-file)
+ [Navigate > Next File](#navigate--next-file)
+ [Navigate > Next Chapter](#navigate--next-chapter)
+ [Navigate > Previous Chapter](#navigate--previous-chapter)
+ [Navigate > Jump Next Frame](#navigate--jump-next-frame)
+ [Navigate > Jump Previous Frame](#navigate--jump-previous-frame)
+ [Navigate > Jump](#navigate--jump)
+ [Pan & Scan > Increase Size](#pan--scan--increase-size)
+ [Pan & Scan > Decrease Size](#pan--scan--decrease-size)
+ [Pan & Scan > Move Left](#pan--scan--move-left)
+ [Pan & Scan > Move Right](#pan--scan--move-right)
+ [Pan & Scan > Move Up](#pan--scan--move-up)
+ [Pan & Scan > Move Down](#pan--scan--move-down)
+ [Pan & Scan > Decrease Height](#pan--scan--decrease-height)
+ [Pan & Scan > Increase Height](#pan--scan--increase-height)
+ [Pan & Scan > Reset](#pan--scan--reset)
+ [Video > Decrease Contrast](#video--decrease-contrast)
+ [Video > Increase Contrast](#video--increase-contrast)
+ [Video > Decrease Brightness](#video--decrease-brightness)
+ [Video > Increase Brightness](#video--increase-brightness)
+ [Video > Decrease Gamma](#video--decrease-gamma)
+ [Video > Increase Gamma](#video--increase-gamma)
+ [Video > Decrease Saturation](#video--decrease-saturation)
+ [Video > Increase Saturation](#video--increase-saturation)
+ [Video > Take Screenshot](#video--take-screenshot)
+ [Video > Toggle Deinterlace](#video--toggle-deinterlace)
+ [Video > Cycle Aspect Ratio](#video--cycle-aspect-ratio)
+ [Audio > Cycle/Next](#audio--cycle-next)
+ [Audio > Delay +0.1](#audio--delay--01)
+ [Audio > Delay -0.1](#audio--delay--01)
+ [Subtitle > Cycle/Next](#subtitle--cycle-next)
+ [Subtitle > Toggle Visibility](#subtitle--toggle-visibility)
+ [Subtitle > Delay -0.1](#subtitle--delay--01)
+ [Subtitle > Delay 0.1](#subtitle--delay-01)
+ [Subtitle > Move Up](#subtitle--move-up)
+ [Subtitle > Move Down](#subtitle--move-down)
+ [Subtitle > Decrease Subtitle Font Size](#subtitle--decrease-subtitle-font-size)
+ [Subtitle > Increase Subtitle Font Size](#subtitle--increase-subtitle-font-size)
+ [Volume > Up](#volume--up)
+ [Volume > Down](#volume--down)
+ [Volume > Mute](#volume--mute)
+ [Speed > -10%](#speed---10-)
+ [Speed > 10%](#speed--10-)
+ [Speed > Half](#speed--half)
+ [Speed > Double](#speed--double)
+ [Speed > Reset](#speed--reset)
+ [Extensions > Rating > 0stars](#extensions--rating--0stars)
+ [View > On Top > Enable](#view--on-top--enable)
+ [View > On Top > Disable](#view--on-top--disable)
+ [View > File Info](#view--file-info)
+ [View > Show Statistics](#view--show-statistics)
+ [View > Toggle Statistics](#view--toggle-statistics)
+ [View > Toggle OSC Visibility](#view--toggle-osc-visibility)
+ [View > Show Playlist](#view--show-playlist)
+ [View > Show Audio/Video/Subtitle List](#view--show-audio-video-subtitle-list)
+ [Settings > Show Config Editor](#settings--show-config-editor)
+ [Settings > Show Input Editor](#settings--show-input-editor)
+ [Settings > Open Config Folder](#settings--open-config-folder)
+ [Tools > Command Palette](#tools--command-palette)
+ [Tools > Show History](#tools--show-history)
+ [Tools > Set/clear A-B loop points](#tools--set-clear-a-b-loop-points)
+ [Tools > Toggle infinite file looping](#tools--toggle-infinite-file-looping)
+ [Tools > Toggle Hardware Decoding](#tools--toggle-hardware-decoding)
+ [Tools > Setup](#tools--setup)
+ [Help > Show mpv manual](#help--show-mpv-manual)
+ [Help > Show mpv.net manual](#help--show-mpvnet-manual)
+ [Help > Check for Updates](#help--check-for-updates)
+ [Help > About mpv.net](#help--about-mpvnet)
+ [Exit](#exit)
+ [Exit Watch Later](#exit-watch-later)
* [Context Menu Commands](#context-menu)
About
@@ -107,106 +32,110 @@ About
mpv.net is a modern desktop media player for Windows based on the popular mpv player.
mpv.net is designed to be mpv compatible, almost all mpv features are available because they are all contained in libmpv, this means the official [mpv manual](https://mpv.io/manual/master/) applies to mpv.net.
mpv.net is designed to be mpv compatible, almost all mpv features are available
because they are all contained in libmpv, this means the official
[mpv manual](https://mpv.io/manual/master/) applies to mpv.net.
mpv focuses on the usage of the command line and the terminal, mpv.net retains the ability to be used from the command line and the terminal and adds a modern Windows GUI on top of it.
mpv focuses on the usage of the command line and the terminal,
mpv.net retains the ability to be used from the command line and
the terminal and adds a modern Windows GUI on top of it.
Download
--------
1. [Stable via Microsoft Store](https://www.microsoft.com/store/productId/9N64SQZTB3LM)
2. [Stable and beta via GitHub download](../../../releases)
3. `winget install mpv.net`
[Changelog](Changelog.md)
### Stable
[Release page](../../releases)
### Beta
[OneDrive](https://1drv.ms/u/s!ArwKS_ZUR01g1ldoLA90tX9DzKTj?e=xITXbC)
[DropBox](https://www.dropbox.com/sh/t54p9igdwvllbpl/AADKyWpaFnIhdyosxyP5d3_xa?dl=0)
Installation
------------
mpv.net requires the .NET Framework 4.8 and Windows 7 or 10 and a modern graphics card.
There is a setup and a portable download in the 7zip and Zip archive format.
x64 editions have the advantage of being typically better optimized and tested.
### Scoop
```
scoop bucket add extras
scoop install mpv.net
```
### AppGet
`appget install mpv-net`
### Chocolatey
`choco install mpvnet.install`
mpv.net requires the .NET Framework 4.8 and Windows 7 or higher and a modern graphics card.
For internet streaming yt-dlp must be downloaded and installed manually.
#### File Associations
File Associations can be created using the setup or with the context menu under 'Tools > Setup'.
File Associations can be registered using the context menu under 'Settings > Setup'.
After the file associations were registered, go to the Windows settings under 'Settings > Apps > Default apps' or shell execute `ms-settings:defaultapps` and choose mpv.net as default app for Video and optionally for Audio and Images.
After the file associations were registered, it might be necessary to change the
default app in the Windows settings (Win+I, ms-settings:defaultapps).
It's possible to change the default application using the 'Open with' feature of the context menu in File Explorer.
Another way to register file associations is using Windows File Explorer,
select a media file and select 'Open with > Choose another app' in the context menu.
[Open with++](#open-with) can be used to extend the File Explorer context menu to get menu items for 'Play with mpv.net' and 'Add to mpv.net playlist'.
[Open with++](#open-with) can be used to extend the File Explorer context menu
to get menu items for [Play with mpv.net](https://github.com/stax76/OpenWithPlusPlus#play-with-mpvnet) and
[Add to mpv.net playlist](https://github.com/stax76/OpenWithPlusPlus#add-to-mpvnet-playlist).
When multiple files are selected in File Explorer and enter is pressed then
the files are opened in mpv.net in random order, this works with maximum 15 files.
Support
-------
Before making a support request, please try a newer [beta version](#beta) first.
Before making a support request, please try a newer beta version first.
[Support thread in VideoHelp forum](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows)
Bugs and feature requests can be made on the github [issue tracker](../../../issues),
feel free to use for anything mpv.net related, usage questions are welcome.
[Issue tracker](https://github.com/stax76/mpv.net/issues), feel free to use for anything mpv.net related.
Or use the [support thread](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows) in the VideoHelp forum.
Settings
--------
When mpv.net finds no config folder on startup it will ask for a location.
mpv.net searches the config folder at:
If a folder named portable_config next to the mpvnet.exe exists,
all config will be loaded from this folder only.
1. startup\portable_config
2. %APPDATA%\mpv.net (`C:\Users\%USERNAME%\AppData\Roaming\mpv.net`)
```Text
<startup>\portable_config\
```
mpv options are stored in the file mpv.conf,
mpv.net options are stored in the file mpvnet.conf,
mpv.net options are documented [here](#mpvnet-specific-options).
mpv specific settings are stored in the file mpv.conf, if no mpv.conf file exists
mpv.net generates it with the following defaults:
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpv.conf.txt>
mpv.net specific settings are stored in the file mpvnet.conf.
Input and context menu
----------------------
The input (key/mouse) bindings and the context menu definitions are stored in the
input.conf file, if it's missing mpv.net generates it with the following defaults:
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt>
[input.conf defaults](../../../tree/master/src/Resources/input.conf.txt)
mpv.net supports almost all mpv settings and features.
Please be aware that once input.conf exists, mpv.net cannot update it, this means
the menu becomes outdated when mpv.net is updated with new or changed default menu
items. The only way to get an up-to-date menu is either resetting the menu by
deleting input.conf or updating it by manually editing input.conf.
The config folder can be opened from the context menu (`Settings > Open Config Folder`).
Global keyboard shortcuts are supported via global-input.conf file.
The config folder can be opened from the context menu: `Settings > Open Config Folder`
A input and config editor can be found in the context menu under 'Settings'.
The input test mode can be started via command line: --input-test
The input key list can be printed with --input-keylist or
shown from the context menu under: View > Advanced > Show Keys
mpv.net input.conf defaults:
https://github.com/stax76/mpv.net/blob/master/src/Resources/input.conf.txt
mpv input.conf defaults:
https://github.com/mpv-player/mpv/blob/master/etc/input.conf
mpv input commands:
https://mpv.io/manual/master/#list-of-input-commands
mpv input options:
https://mpv.io/manual/master/#input
Command Line Interface
----------------------
@@ -230,7 +159,7 @@ To disable the border property:
Supported are all mpv properties, they are documented here:
<https://mpv.io/manual/master/#properties>
https://mpv.io/manual/master/#properties
mpv.net has a feature to list all properties:
@@ -244,13 +173,168 @@ Non property switches are generally not supported in mpv.net!
Terminal
--------
When mpv.net is started from a terminal it will output status, error and debug messages to the terminal and accept input keys from the terminal.
When mpv.net is started from a terminal it will output status,
error and debug messages to the terminal and accept input keys from the terminal.
In the context menu under _Tools > Setup_ a button can be found to add mpv.net to the path environment variable.
In the context menu under _Tools > Setup_ a button can be found to add
mpv.net to the path environment variable.
A common task for the terminal is debugging scripts.
mpv.net specific options
------------------------
mpv.net specific options can be found in the conf editor searching for 'mpv.net'.
The options are saved in the mpvnet.conf file.
#### --queue \<files\>
Adds files to the playlist, requires [--process-instance=single](#--process-instancevalue).
[Open with++](#open-with) can be used to add files to the playlist using File Explorer.
#### --command=\<input command\>
Sends a input command to a running mpv.net instance via command line, for instance
to create global keyboard shortcuts with AutoHotkey. Requires [process-instance=single](#--process-instancevalue).
### Audio
#### --remember-volume=\<yes|no\>
Save volume and mute on exit and restore it on start. Default: yes
### Screen
#### --start-size=\<value\>
Setting to remember the window size.
**width-session**
Width is remembered in the current session.
**width-always**
Width is always remembered.
**height-session**
Height is remembered in the current session. Default
**height-always**
Height is always remembered.
**video**
Window size is set to video resolution.
**session**
Window size is remembered in the current session.
**always**
Window size is always remembered.
#### --start-threshold=\<milliseconds\>
Threshold in milliseconds to wait for libmpv returning the video
resolution before the window is shown, otherwise default dimensions
are used as defined by autofit and start-size. Default: 1500
#### --minimum-aspect-ratio=\<float\>
Minimum aspect ratio, if the AR is smaller than the defined value then
the window AR is set to 16/9. This avoids a square window for Music
with cover art. Default: 1.2
#### --remember-window-position=\<yes|no\>
Save the window position on exit. Default: no
### Playback
#### --auto-load-folder=\<yes|no\>
For single files automatically load the entire directory into the playlist.
Can be suppressed via shift key. Default: yes
### General
#### --process-instance=\<value\>
Defines if more then one mpv.net process is allowed.
Tip: Whenever the control key is pressed when files or URLs are opened,
the playlist is not cleared but the files or URLs are appended to the playlist.
This not only works on process startup but in all mpv.net features that open files and URLs.
**multi**
Create a new process everytime the shell starts mpv.net.
**single**
Force a single process everytime the shell starts mpv.net. Default
**queue**
Force a single process and add files to playlist.
#### --recent-count=\<int\>
Amount of recent files to be remembered. Default: 15
#### --video-file-extensions=\<string\>
Video file extensions used to create file associations and used by the auto-load-folder feature.
#### --audio-file-extensions=\<string\>
Audio file extensions used to create file associations and used by the auto-load-folder feature.
#### --image-file-extensions=\<string\>
Image file extensions used to create file associations and used by the auto-load-folder feature.
#### --debug-mode=\<yes|no\>
Enable this only when a developer asks for it. Default: no
### UI
#### --dark-mode=\<value\>
Enables a dark theme.
**always**
Default
**system**
Available on Windows 10 or higher.
**never**
#### ---dark-theme=\<string\>
Color theme used in dark mode. Default: dark
[Color Themes](#color-theme)
#### --light-theme=\<string\>
Color theme used in light mode. Default: light
[Color Themes](#color-theme)
External Tools
--------------
@@ -267,51 +351,53 @@ This will start the app on system start and have it running in the background. W
### Open With
Alternatively he Chrome/Firefox extension [Open With](https://github.com/stax76/mpv.net/issues/119) can be used.
Alternatively the Chrome/Firefox extension [Open With](../../../issues/119) can be used.
### Open with++
Open with++ allows to customize the File Explorer context menu to add menu items 'Play with mpv.net' and 'Add to mpv.net playlist'.
https://github.com/stax76/OpenWithPlusPlus
https://github.com/stax76/OpenWithPlusPlus#mpvnet
https://github.com/stax76/OpenWithPlusPlus#add-to-mpvnet-playlist
[Open with++](https://github.com/stax76/OpenWithPlusPlus) can be used to extend the File Explorer context menu to get menu items for [Play with mpv.net](https://github.com/stax76/OpenWithPlusPlus#play-with-mpvnet) and [Add to mpv.net playlist](https://github.com/stax76/OpenWithPlusPlus#add-to-mpvnet-playlist).
### MediaInfo.NET
### Universal Remote Android app
MediaInfo.NET is a media info GUI.
Universal Remote is Android remote control app which costs 5 €.
https://github.com/stax76/MediaInfo.NET
https://www.unifiedremote.com
To start a external application mpv has the run input command (it does not use shell execute).
https://play.google.com/store/apps/details?id=com.Relmtech.Remote
If the path has spaces then it must be enclosed in quotes and then double backslashes must be used for escaping or alternatively forward slashes.
https://play.google.com/store/apps/details?id=com.Relmtech.RemotePaid
`_ run D:\Software\MediaInfoNET.exe "${path}" #menu: Tools > Open file with MediaInfo.NET`
https://www.unifiedremote.com/tutorials/how-to-create-a-custom-keyboard-shortcuts-remote
`_ run "D:\\Soft ware\\MediaInfoNET.exe" "${path}" #menu: Tools > Open file with MediaInfo.NET`
https://www.unifiedremote.com/tutorials/how-to-install-a-custom-remote
`_ run "D:/Soft ware/MediaInfoNET.exe" "${path}" #menu: Tools > Open file with MediaInfo.NET`
[My config](./Universal%20Remote)
Very useful is the Universal Remote File Browser feature.
### One For All Contour URC1210 and FLIRC USB
My primary remote control solution however is a One For All Contour URC1210
using Philips code 0556 together with FLIRC USB (gen2).
Scripting
---------
There is no debugger support available for the scripting hosts, mpv.net can be started from a terminal,
script errors and debug messages are printed then on the terminal.
#### Lua
File Type: `lua`
Location: `<config folder>\scripts`
Lua and JavaScript scripts are loaded before the first media file loads.
The Lua script host is built into libmpv.
There is no debugging support, only error and debug messages printed on the terminal.
Lua scripts are loaded before the first media file loads.
[mpv Lua documentation](https://mpv.io/manual/master/#lua-scripting)
@@ -324,7 +410,11 @@ File Type: `js`
Location: `<config folder>\scripts`
Lua and JavaScript scripts are loaded before the first media file loads.
The JavaScript script host is built into libmpv.
There is no debugging support, only error and debug messages printed on the terminal.
JavaScript scripts are loaded before the first media file loads.
[mpv JavaScript documentation](https://mpv.io/manual/master/#javascript)
@@ -337,11 +427,13 @@ File Type: `ps1`
Location: `<config folder>\scripts-ps`
The PowerShell scripting host is like extensions not initialized before media files are loaded.
The PowerShell scripting host is like extensions not
initialized before media files are loaded.
mpv.net does not define scripting interfaces but instead exposed its complete internals, there are no compatibility guaranties.
mpv.net does not define scripting interfaces but instead exposed
its complete internals, there are no compatibility guaranties.
[Example Scripts](scripts/examples)
[Example Scripts](../../../tree/master/src/Scripts)
#### C#
@@ -350,57 +442,61 @@ File Type: `cs`
Location: `<config folder>\scripts-cs`
C# scripting in mpv.net is implemented with a C# [extension](#extensions) and [CS-Script](https://www.cs-script.net/).
mpv.net does not define scripting interfaces but instead exposed
its complete internals, there are no compatibility guaranties.
mpv.net does not define scripting interfaces but instead exposed its complete internals, there are no compatibility guaranties.
Script code can be written within a C# [extension](../../../tree/master/src/Extensions),
that way full code completion and debugger support is available.
Once the code was developed and debugged, it can be moved
from the extension to a lightweight standalone script.
Script code can be written within a C# [extension](#extensions), that way full code completion and debugger support is available. Once the code was developed and debugged, the code can be moved from the extension to a lightweight standalone script.
The C# scripting host is like [extensions](../../../tree/master/src/Extensions)
not initialized before media files are loaded.
The C# scripting host is like [extensions](#extensions) not initialized before media files are loaded.
[Example Scripts](scripts/examples)
[Example Scripts](../../../tree/master/src/Scripts)
Extensions
----------
Extensions are located in the config folder and the filename must end with 'Extension.dll':
Extensions are located in a subfolder _extensions_ in the config folder
and the filename must have the same name as the directory:
```Text
<config folder>\Extensions\ExampleExtension\ExampleExtension.dll
<config folder>\extensions\ExampleExtension\ExampleExtension.dll
```
mpv.net does not define extension interfaces but instead exposed its complete internals, there are no compatibility guaranties.
mpv.net does not define extension interfaces but instead exposed
its complete internals, there are no compatibility guaranties.
### Walkthrough creating an extension
- Download and install [Visual Studio Community](https://visualstudio.microsoft.com).
- Create a new project of type **Class Library .NET Framework** and ensure the project name ends with **Extension**.
- Create a new project of type **Class Library .NET Framework**
and ensure the project name ends with **Extension**.
- Add a reference to **System.ComponentModel.Composition**.
- Add a reference to mpvnet.exe, select the mpvnet reference in the Solution Explorer, open the Properties window and set **Copy Local** to false to prevent mpvnet.exe being copied to the output directory when the project is built.
- Now open the project properties and set the output path in the Build tab, extensions are like scripts located in your config folder, example: `<config folder>\extensions\ExampleExtension\ExampleExtension.dll`
- Also in the project properties choose the option **Start external program** in the Debug tab and define the path to mpvnet.exe. In the Debug tab you may also define command line arguments like a video file to be played when you start debugging.
- Add a reference to mpvnet.exe, select the mpvnet reference
in the Solution Explorer, open the Properties window and set
**Copy Local** to false to prevent mpvnet.exe being copied
to the output directory when the project is built.
- Now open the project properties and set the output path in the Build tab,
extensions are like scripts located in your config folder, example:
`<config folder>\extensions\ExampleExtension\ExampleExtension.dll`
- Also in the project properties choose the option **Start external program**
in the Debug tab and define the path to mpvnet.exe. In the Debug tab you may also
define command line arguments like a video file to be played when you start debugging.
### Sample Code
#### ScriptingExtension
The ScriptingExtension implements the C# scripting host using [CS-Script](https://www.cs-script.net/).
I use this extension as well to develop and debug C# scripts. Once the code was developed and debugged, I move the code from the extension to a standalone script.
[Source Code](extensions)
#### RatingExtension
This extension writes a rating to the filename of rated videos when mpv.net shuts down.
The input.conf defaults contain key bindings for this extension to set ratings.
[Source Code](extensions)
[Source Code](../../../tree/master/src/Extensions)
Color Theme
@@ -408,7 +504,7 @@ Color Theme
mpv.net supports custom color themes, the definition of the built-in themes can be found at:
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/theme.txt>
[theme.txt](../../../tree/master/src/Resources/theme.txt)
Custom themes can be saved at:
@@ -417,7 +513,8 @@ Custom themes can be saved at:
The theme.conf file may contain an unlimited amount of themes.
In the config editor under UI there are the settings dark-theme and light-theme to define the themes used in dark and in light mode.
In the config editor under UI there are the settings dark-theme and
light-theme to define the themes used in dark and in light mode.
Advanced Features
@@ -438,66 +535,86 @@ Python and VapourSynth must be in the path environment variable.
Hidden Features
---------------
Selecting multiple files in File Explorer and pressing enter will open the files in mpv.net. Explorer restricts this to maximum 15 files and the order will be random.
Selecting multiple files in File Explorer and pressing enter will
open the files in mpv.net. Explorer restricts this to maximum 15 files
and the order will be random.
Whenever the control key is pressed when files or URLs are opened, the playlist is not cleared but the files or URLs are appended to the playlist. This works in all mpv.net features that open files or URLs.
Whenever the control key is pressed when files or URLs are opened,
the playlist is not cleared but the files or URLs are appended to the playlist.
This works in all mpv.net features that open files or URLs.
Pressing the shift key while opening a single file will suppress loading all files in the folder.
Pressing the shift key while opening a single file will suppress loading
all files of the folder into the playlist.
In fullscreen mode clicking the top right corner closes the player.
Differences
-----------
Differences compared to mpv
---------------------------
mpv.net is designed to work exactly like mpv, there are a few limitations:
### Window Limitations
mpv.net implements an own main window which means only mpv window features are supported that have an own implementation in mpv.net.
mpv.net implements an own main window which means only mpv window
features are supported that have an own implementation in mpv.net.
A window free mode is currently not supported.
A window free mode is currently not supported, the main window is always
visible, even when mpv.net is started from the terminal and music is played.
The documentation of mpvs window features can be found here:
The documentation of mpv's window features can be found here:
<https://mpv.io/manual/master/#window>
https://mpv.io/manual/master/#window
mpv.net has currently implemented the following window features:
**mpv.net has currently implemented the following window properties:**
[screen](https://mpv.io/manual/master/#options-screen)
[fullscreen](https://mpv.io/manual/master/#options-fullscreen)
[ontop](https://mpv.io/manual/master/#options-ontop)
[border](https://mpv.io/manual/master/#options-border)
[window-minimized](https://mpv.io/manual/master/#options-window-minimized)
[window-maximized](https://mpv.io/manual/master/#options-window-maximized)
- [border](https://mpv.io/manual/master/#options-border)
- [fullscreen](https://mpv.io/manual/master/#options-fullscreen)
- [keepaspect-window](https://mpv.io/manual/master/#options-keepaspect-window)
- [ontop](https://mpv.io/manual/master/#options-ontop)
- [screen](https://mpv.io/manual/master/#options-screen)
- [title](https://mpv.io/manual/master/#options-title)
- [window-maximized](https://mpv.io/manual/master/#options-window-maximized)
- [window-minimized](https://mpv.io/manual/master/#options-window-minimized)
- [window-scale](https://mpv.io/manual/master/#options-window-scale)
**Partly implemented are:**
[autofit](https://mpv.io/manual/master/#options-autofit)
- [autofit-larger](https://mpv.io/manual/master/#options-autofit-larger)
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller)
- [autofit](https://mpv.io/manual/master/#options-autofit)
[autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller)
[autofit-larger](https://mpv.io/manual/master/#options-autofit-larger)
mpv.net specific window features are documented in the [screen section](#screen).
### Command Line Limitations
mpv.net supports only property switches, it does not support non property switches.
mpv.net supports property based mpv command line options which means it supports
almost all mpv command line options.
What is not supported are non property bases options. Non property based options
need an own implementation in mpv.net, so far implemented are:
--ad=help
--audio-device=help
--input-keylist
--profile=help
--vd=help
--version
### mpv.net specific options
Options that are specific to mpv.net can be found by entering _mpv.net_ in the search field of the config editor.
Options that are specific to mpv.net can be found by entering _mpv.net_
in the search field of the config editor, in the mpv.net manual they are
documented [here](#mpvnet-specific-options).
mpv.net specific options are saved in the file mpvnet.conf and are just as mpv properties available on the command line.
mpv.net specific options are saved in the file mpvnet.conf and are just
as mpv properties available on the command line.
Technical Overview
@@ -505,53 +622,55 @@ Technical Overview
mpv.net is written in C# 7 and runs on the .NET Framework 4.8.
The Extension implementation is based on the [Managed Extensibility Framework](https://docs.microsoft.com/en-us/dotnet/framework/mef/).
The main window is WinForms based because WinForms allows better libmpv integration compared to WPF, all other windows are WPF based.
The config editor adds it's controls dynamically and uses [TOML](https://en.wikipedia.org/wiki/TOML) to define it's
content.
The Extension implementation is based on the
[Managed Extensibility Framework](https://docs.microsoft.com/en-us/dotnet/framework/mef/).
The main window is WinForms based because WinForms allows better libmpv integration
compared to WPF, all other windows are WPF based.
Third party components are:
- [libmpv provides the core functionality](https://mpv.io/)
- [MediaInfo](https://mediaarea.net/en/MediaInfo)
- [Tommy, a single file TOML parser](https://github.com/dezhidki/Tommy)
- [CS-Script, scripting with C#](http://www.csscript.net/)
- [Everything, a fast file search service](https://www.voidtools.com)
Context Menu
------------
The context menu of mpv.net is defined in the file input.conf which is located in the config directory.
The context menu of mpv.net is defined in the file input.conf which is
located in the config directory.
If the input.conf file does not exists mpv.net generates it with the following defaults:
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt>
<https://github.com/stax76/mpv.net/tree/master/src/Resources/input.conf.txt>
input.conf defines mpvs key and mouse bindings and mpv.net uses comments to define the context menu.
input.conf defines mpv's key and mouse bindings and mpv.net uses
comments to define the context menu.
### Open > Open Files
The Open Files menu entry is one way to open files in mpv.net, it supports multi selection.
Another way to open files is the command line, it is used by the File Explorer if file associations exist.
When mpv.net is started from a terminal, mpv.net outputs status and debug messages on the terminal.
Another way to open files is the command line which is used by
File Explorer for existing associations.
A third way is to drag and drop files on the main window.
Whenever the control key is pressed when files or URLs are opened, the playlist is not cleared but the files or URLs are appended to the playlist. This works in all mpv.net features that open files or URLs.
Whenever the control key is pressed when files or URLs are opened,
the playlist is not cleared but the files or URLs are appended to the
playlist. This works in all mpv.net features that open files or URLs.
Pressing the shift key while opening a single file will suppress loading all files in the folder.
Blu-ray and DVD ISO image files are supported.
### Open > Open URL or file path from clipboard
Opens files and URLs from the clipboard. How to open URLs directly from the browser from sites like YouTube is described in the [External Tools section](#external-tools).
Opens files and URLs from the clipboard. How to open URLs directly
from the browser from sites like YouTube is described in the
[External Tools section](#external-tools).
### Open > Open DVD/Blu-ray Drive/Folder
@@ -559,19 +678,18 @@ Opens files and URLs from the clipboard. How to open URLs directly from the brow
Opens a DVD/Blu-ray Drive/Folder.
### Open > Show media search
mpv.net supports system wide media searches using the Everything indexing service installed by the popular file search tool [Everything](www.voidtools.com).
### Open > Load external audio files
Allows to load an external audio file. It's also possible to auto detect external audio files based on the file name, the option for this can be found in the settings under 'Settings > Show Config Editor > Audio > audio-file-auto'.
Allows to load an external audio file. It's also possible to auto detect
external audio files based on the file name, the option for this can be
found in the settings under 'Settings > Show Config Editor > Audio > audio-file-auto'.
### Open > Load external subtitle files
Allows to load an external subtitle file. It's also possible to auto detect external subtitle files based on the file name, the option for this can be found in the settings under 'Settings > Show Config Editor > Subtitles > sub-auto'.
Allows to load an external subtitle file. It's also possible to auto detect
external subtitle files based on the file name, the option for this can be
found in the settings under 'Settings > Show Config Editor > Subtitles > sub-auto'.
### Play/Pause
@@ -878,7 +996,7 @@ Cycles the deinterlace property using the following command:
Cycles the aspect ratio using the following command:
`cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1"`
`cycle-values video-aspect 16:9 4:3 2.35:1 -1`
[cycle-values command](https://mpv.io/manual/master/#command-interface-cycle-values)
@@ -1196,8 +1314,14 @@ Shows the command palette window which allows to quickly find and execute comman
### Tools > Show History
Shows a text file that contains the file history. If the file don't exist it asks if the file should be created in the settings folder. Once the file exist then the history is logged. It logges the playback history containing the time and filename.
Shows a text file that contains the file history. If the file don't exist
it asks if the file should be created in the settings folder. Once the file
exist then the history is logged. It logges the playback history containing
the time and filename.
To ignore certain paths:
script-opt = history-discard=path1;path2
### Tools > Set/clear A-B loop points
@@ -1212,7 +1336,7 @@ Enables to set loop start and end points using the following command:
Loops the current file infinitely using the following command:
cycle-values loop-file "inf" "no"
`cycle-values loop-file "inf" "no"`
[cycle-values command](https://mpv.io/manual/master/#command-interface-cycle-values)
@@ -1250,16 +1374,9 @@ Shows the [mpv.net web site](https://mpv-net.github.io/mpv.net-web-site/).
Shows the [mpv.net manual](https://github.com/stax76/mpv.net/blob/master/Manual.md).
### Help > Check for Updates
Checks for updates and allows to execute the update routine.
The update routine requires PowerShell 5 and curl, an up to date Windows 10 system has both included.
### Help > About mpv.net
Shows the mpv.net about dialog which shows a copyright notice, the versions of mpv.net and libmpv and a license notice (MIT).
Shows the mpv.net about dialog which shows a copyright notice, the versions of mpv.net and libmpv and a license notice (GPL v2).
### Exit

1360
docs/Manual_chs.md Normal file

File diff suppressed because it is too large Load Diff

2
docs/Privacy.md Normal file
View File

@@ -0,0 +1,2 @@
mpv.net does not collect any personal information.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<row>
<button text="PLAY" ontap="play" />
<button text="PREV" ontap="prev" />
<button text="NEXT" ontap="next" />
<button text="Enter" ontap="enter" />
</row>
<row>
<button text="LEFT" ontap="left" />
<button text="RIGHT" ontap="right" />
<button text="UP" ontap="up" />
<button text="DOWN" ontap="down" />
</row>
<row>
<button text="VOL-" ontap="vol_minus" />
<button text="VOL+" ontap="vol_plus" />
<button text="MUTE" ontap="mute" />
<button text="INFO" ontap="info" />
</row>
<row>
<button text="KP0" ontap="KP0" />
<button text="KP1" ontap="KP1" />
<button text="KP2" ontap="KP2" />
<button text="KP3" ontap="KP3" />
<button text="KP4" ontap="KP4" />
</row>
<row>
<button text="KP5" ontap="KP5" />
<button text="KP6" ontap="KP6" />
<button text="KP7" ontap="KP7" />
<button text="KP8" ontap="KP8" />
<button text="KP9" ontap="KP9" />
</row>
<row>
<button text="Cycle Audio" ontap="KP7" />
<button text="Cycle Subtitle" ontap="KP8" />
<button text="AB LOOP" ontap="ab_loop" />
</row>
<row>
<button text="ZOOM IN" ontap="zoom_in" />
<button text="ZOOM OUT" ontap="zoom_out" />
</row>
</layout>

View File

@@ -0,0 +1,5 @@
meta.name: custom keys
meta.author: stax76
meta.description: custom keys
meta.tags: mpv

View File

@@ -0,0 +1,106 @@
-- https://github.com/unifiedremote/Docs/blob/master/libs/keyboard.md
-- https://github.com/unifiedremote/Docs/blob/master/res/keys.md
local kb = libs.keyboard;
actions.play = function ()
kb.stroke("space");
end
actions.next = function ()
kb.stroke("F12");
end
actions.prev = function ()
kb.stroke("F11");
end
actions.enter = function ()
kb.stroke("enter");
end
actions.left = function ()
kb.stroke("left");
end
actions.right = function ()
kb.stroke("right");
end
actions.up = function ()
kb.stroke("up");
end
actions.down = function ()
kb.stroke("down");
end
actions.vol_minus = function ()
kb.text("-");
end
actions.vol_plus = function ()
kb.text("+");
end
actions.mute = function ()
kb.stroke("m");
end
actions.info = function ()
kb.stroke("i");
end
actions.KP0 = function ()
kb.stroke("num0");
end
actions.KP1 = function ()
kb.stroke("num1");
end
actions.KP2 = function ()
kb.stroke("num2");
end
actions.KP3 = function ()
kb.stroke("num3");
end
actions.KP4 = function ()
kb.stroke("num4");
end
actions.KP5 = function ()
kb.stroke("num5");
end
actions.KP6 = function ()
kb.stroke("num6");
end
actions.KP7 = function ()
kb.stroke("num7");
end
actions.KP8 = function ()
kb.stroke("num8");
end
actions.KP9 = function ()
kb.stroke("num9");
end
actions.ab_loop = function ()
kb.stroke("l");
end
actions.zoom_in = function ()
kb.stroke("ctrl", "oem_plus");
end
actions.zoom_out = function ()
kb.stroke("ctrl", "oem_minus");
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

BIN
docs/img/ConfEditor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

BIN
docs/img/InputEditor.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

BIN
docs/img/Main.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

BIN
docs/img/Menu.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

BIN
docs/img/Playlist.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

BIN
docs/img/Terminal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

BIN
docs/img/mpvnet-santa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -1,65 +0,0 @@
// This extension writes a rating to the filename of rated videos when mpv.net shuts down.
// The input.conf defaults contain key bindings for this extension to set ratings.
using System;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.IO;
using mpvnet;
namespace RatingExtension // the assembly name must end with 'Extension'
{
[Export(typeof(IExtension))]
public class RatingExtension : IExtension
{
// dictionory to store the filename and the rating
Dictionary<string, int> Dic = new Dictionary<string, int>();
public RatingExtension() // plugin initialization
{
mp.ClientMessage += ClientMessage; //handles keys defined in input.conf
mp.Shutdown += Shutdown; // handles MPV_EVENT_SHUTDOWN
}
// handles MPV_EVENT_SHUTDOWN
void Shutdown()
{
foreach (var i in Dic)
{
string filepath = i.Key;
int rating = i.Value;
if (String.IsNullOrEmpty(filepath) || !File.Exists(filepath))
return;
string basename = Path.GetFileNameWithoutExtension(filepath);
for (int x = 0; x < 6; x++)
if (basename.Contains(" (" + x + "stars)"))
basename = basename.Replace(" (" + x + "stars)", "");
basename += $" ({rating}stars)";
string newPath = Path.Combine(Path.GetDirectoryName(filepath), basename + Path.GetExtension(filepath));
if (filepath.ToLower() != newPath.ToLower())
File.Move(filepath, newPath);
File.SetLastWriteTime(newPath, DateTime.Now);
}
}
//handles keys defined in input.conf
void ClientMessage(string[] args)
{
if (args[0] != "rate-file") return;
if (int.TryParse(args[1], out int rating))
{
string path = mp.get_property_string("path");
if (!File.Exists(path)) return;
Dic[path] = rating;
mp.commandv("show-text", $"Rating: {rating}");
}
else if (args[1] == "about")
Msg.Show("Rating Extension", "This extension writes a rating to the filename of rated videos when mpv.net shuts down.\n\nThe input.conf defaults contain key bindings for this extension to set ratings.");
}
}
}

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RatingExtension")]
[assembly: AssemblyDescription("RatingExtension")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Frank Skare (stax76)")]
[assembly: AssemblyProduct("RatingExtension")]
[assembly: AssemblyCopyright("Copyright (C) 2017-2020 Frank Skare (stax76)")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("55c88710-539d-4402-84c8-31694841c731")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,55 +0,0 @@
// This extension implements the C# scripting feature of mpv.net which
// is based on CS-Script (https://www.cs-script.net).
// I also use this extension to code scripts in order to have full
// code completion and debugger support, once the script code is
// finished I move it from the extension to a standalone script.
using System;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.IO;
using mpvnet;
using CSScriptLibrary;
// the file name of extensions must end with 'Extension'
namespace ScriptingExtension
{
[Export(typeof(IExtension))]
public class ScriptingExtension : IExtension
{
//Script Script;
public ScriptingExtension()
{
//Script = new Script();
List<string> files = new List<string>();
if (Directory.Exists(mp.ConfigFolder + "scripts-cs"))
files.AddRange(Directory.GetFiles(mp.ConfigFolder + "scripts-cs", "*.cs"));
if (Directory.Exists(Folder.Startup + "scripts"))
foreach (string path in Directory.GetFiles(Folder.Startup + "scripts", "*.cs"))
files.AddRange(Directory.GetFiles(Folder.Startup + "scripts", "*.cs"));
if (files.Count == 0)
return;
CSScriptLibrary.CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;
foreach (string file in files)
{
try
{
CSScriptLibrary.CSScript.Evaluator.LoadCode(File.ReadAllText(file));
}
catch (Exception e)
{
App.ShowException(e);
}
}
}
}
}

View File

@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{94255EF2-C823-4D82-9017-0E993CC0F5A1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ScriptingExtension</RootNamespace>
<AssemblyName>ScriptingExtension</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\mpv.net\bin\x86\Extensions\ScriptingExtension\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>..\..\mpv.net\bin\x86\Extensions\ScriptingExtension\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\mpv.net\bin\x64\Extensions\ScriptingExtension\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>..\..\mpv.net\bin\x64\Extensions\ScriptingExtension\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="CSScriptLibrary">
<HintPath>.\CSScriptLibrary.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ScriptingExtension.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="script.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\mpv.net\mpv.net.csproj">
<Project>{1751f378-8edf-4b62-be6d-304c7c287089}</Project>
<Name>mpv.net</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,31 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29123.88
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptingExtension", "ScriptingExtension.csproj", "{55C88710-539D-4402-84C8-31694841C731}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.ActiveCfg = Debug|x64
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.Build.0 = Debug|x64
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.ActiveCfg = Debug|x86
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.Build.0 = Debug|x86
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.ActiveCfg = Release|x64
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.Build.0 = Release|x64
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.ActiveCfg = Release|x86
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C8A53BF6-B00A-4215-B9D7-801ADB9C8F60}
EndGlobalSection
EndGlobal

View File

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

using System.IO;
using mpvnet;
class Script
{
public Script()
{
mp.Shutdown += Shutdown;
}
void Shutdown()
{
foreach (string file in Directory.GetFiles(@"C:\Users\frank\Desktop\aaa"))
File.Delete(file);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

View File

@@ -1,51 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28729.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpv.net", "mpv.net\mpv.net.csproj", "{1751F378-8EDF-4B62-BE6D-304C7C287089}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RatingExtension", "extensions\RatingExtension\RatingExtension.csproj", "{55C88710-539D-4402-84C8-31694841C731}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptingExtension", "extensions\ScriptingExtension\ScriptingExtension.csproj", "{94255EF2-C823-4D82-9017-0E993CC0F5A1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x64.ActiveCfg = Debug|x64
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x64.Build.0 = Debug|x64
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x86.ActiveCfg = Debug|x86
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x86.Build.0 = Debug|x86
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x64.ActiveCfg = Release|x64
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x64.Build.0 = Release|x64
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x86.ActiveCfg = Release|x86
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x86.Build.0 = Release|x86
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.ActiveCfg = Debug|x64
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.Build.0 = Debug|x64
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.ActiveCfg = Debug|x86
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.Build.0 = Debug|x86
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.ActiveCfg = Release|x64
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.Build.0 = Release|x64
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.ActiveCfg = Release|x86
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.Build.0 = Release|x86
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x64.ActiveCfg = Debug|x64
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x64.Build.0 = Debug|x64
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x86.ActiveCfg = Debug|x86
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x86.Build.0 = Debug|x86
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x64.ActiveCfg = Release|x64
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x64.Build.0 = Release|x64
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x86.ActiveCfg = Release|x86
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8DE9E796-619E-44B8-9576-F4DE028701BF}
EndGlobalSection
EndGlobal

View File

@@ -1,64 +0,0 @@
<UserControl x:Name="OptionSettingControl1" x:Class="DynamicGUI.OptionSettingControl"
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:DynamicGUI"
xmlns:UI="clr-namespace:UI"
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="{x:Static UI:Theme.Heading}"
Background="{x:Static UI:Theme.Background}" />
<ItemsControl x:Name="ItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel Orientation="Vertical">
<RadioButton x:Name="RadioButton"
VerticalContentAlignment="Center"
IsChecked="{Binding Checked}"
GroupName="{Binding OptionSetting.Name}"
Content="{Binding Text}"
FontSize="16"
FontWeight="Normal"
VerticalAlignment="Top"
Foreground="{x:Static UI:Theme.Foreground}"/>
<TextBox x:Name="ItemHelpTextBox"
TextWrapping="WrapWithOverflow"
Text="{Binding Help}"
Visibility="{Binding Visibility}"
Margin="10,0,0,0" BorderThickness="0"
IsReadOnly="True" Padding="7,0,0,0"
MinHeight="0"
Foreground="{x:Static UI:Theme.Foreground2}"
Background="{x:Static UI:Theme.Background}"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBox x:Name="HelpTextBox"
TextWrapping="WrapWithOverflow"
BorderThickness="0"
IsReadOnly="True"
Margin="0,10,0,0"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"/>
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -1,58 +0,0 @@
<UserControl x:Name="StringSettingControl1" x:Class="DynamicGUI.StringSettingControl"
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:DynamicGUI"
xmlns:UI="clr-namespace:UI"
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="{x:Static UI:Theme.Heading}"
Background="{x:Static UI:Theme.Background}"/>
<Grid Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="ValueTextBox"
Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="150"
Height="20"
HorizontalAlignment="Left"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
CaretBrush="{x:Static UI:Theme.Foreground}"
TextChanged="ValueTextBox_TextChanged"/>
<Button x:Name="Button"
Height="20"
Grid.Column="1"
Visibility="{Binding Path=Text, ElementName=StringSettingControl1}"
Margin="5,0,0,0"
Width="20"
Click="Button_Click">...</Button>
</Grid>
<TextBox x:Name="HelpTextBox"
TextWrapping="WrapWithOverflow"
BorderThickness="0"
IsReadOnly="True"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"/>
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,192 +0,0 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using UI;
using static libmpv;
using System.Threading.Tasks;
namespace mpvnet
{
public static class App
{
public static string[] VideoTypes { get; } = "264 265 asf avc avi avs flv h264 h265 hevc m2ts m2v m4v mkv mov mp4 mpeg mpg mpv mts ts vob vpy webm wmv y4m".Split(' ');
public static string[] AudioTypes { get; } = "mp3 mp2 ac3 ogg opus flac wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 mka aac mpa".Split(' ');
public static string[] ImageTypes { get; } = {"jpg", "bmp", "gif", "png"};
public static string[] SubtitleTypes { get; } = { "srt", "ass", "idx", "sup", "ttxt", "ssa", "smi" };
public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName;
public static string ConfPath { get => mp.ConfigFolder + "mpvnet.conf"; }
public static string ProcessInstance { get; set; } = "single";
public static string DarkMode { get; set; } = "always";
public static string DarkTheme { get; set; } = "dark";
public static string LightTheme { get; set; } = "light";
public static string StartSize { get; set; } = "previous";
public static bool RememberPosition { get; set; }
public static bool DebugMode { get; set; }
public static bool IsStartedFromTerminal { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
public static bool RememberVolume { get; set; } = true;
public static bool AutoLoadFolder { get; set; } = true;
public static bool Queue { get; set; }
public static bool UpdateCheck { get; set; }
public static int StartThreshold { get; set; } = 1500;
public static int RecentCount { get; set; } = 15;
public static float MinimumAspectRatio { get; set; } = 1.2f;
public static Extension Extension { get; set; }
public static bool IsDarkMode {
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
}
public static void Init()
{
string dummy = mp.ConfigFolder;
var dummy2 = mp.Conf;
foreach (var i in Conf)
ProcessProperty(i.Key, i.Value, true);
if (App.DebugMode)
{
try
{
string filePath = mp.ConfigFolder + "mpvnet-debug.log";
if (File.Exists(filePath))
File.Delete(filePath);
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
Trace.AutoFlush = true;
//if (App.DebugMode)
// Trace.WriteLine("");
}
catch (Exception e)
{
Msg.ShowException(e);
}
}
string themeContent = null;
if (File.Exists(mp.ConfigFolder + "theme.conf"))
themeContent = File.ReadAllText(mp.ConfigFolder + "theme.conf");
Theme.Init(
themeContent,
Properties.Resources.theme,
IsDarkMode ? DarkTheme : LightTheme);
mp.Shutdown += Shutdown;
mp.Initialized += Initialized;
mp.LogMessage += ShowFatalError;
}
static void ShowFatalError(mpv_log_level level, string msg)
{
if (!App.IsStartedFromTerminal && level == mpv_log_level.MPV_LOG_LEVEL_FATAL)
Msg.ShowError(msg);
}
public static void RunAction(Action action)
{
Task.Run(() => {
try
{
action.Invoke();
}
catch (Exception e)
{
ShowException(e);
}
});
}
public static void ShowException(object obj)
{
if (obj is Exception e)
{
if (App.IsStartedFromTerminal)
ConsoleHelp.WriteError(e.ToString(), "mpv.net");
else
Msg.ShowException(e);
}
else
{
if (App.IsStartedFromTerminal)
ConsoleHelp.WriteError(obj.ToString(), "mpv.net");
else
Msg.ShowError(obj.ToString());
}
}
static void Initialized()
{
if (RememberVolume)
{
mp.set_property_int("volume", RegistryHelp.GetInt(App.RegPath, "Volume", 70));
mp.set_property_string("mute", RegistryHelp.GetString(App.RegPath, "Mute", "no"));
}
}
static void Shutdown()
{
if (RememberVolume)
{
RegistryHelp.SetValue(App.RegPath, "Volume", mp.get_property_int("volume"));
RegistryHelp.SetValue(App.RegPath, "Mute", mp.get_property_string("mute"));
}
}
static Dictionary<string, string> _Conf;
public static Dictionary<string, string> Conf {
get {
if (_Conf == null)
{
_Conf = new Dictionary<string, string>();
if (File.Exists(ConfPath))
foreach (string i in File.ReadAllLines(ConfPath))
if (i.Contains("=") && !i.StartsWith("#"))
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
return _Conf;
}
}
public static bool ProcessProperty(string name, string value, bool writeError = false)
{
switch (name)
{
case "remember-position": RememberPosition = value == "yes"; return true;
case "debug-mode": DebugMode = value == "yes"; return true;
case "remember-volume": RememberVolume = value == "yes"; return true;
case "queue": Queue = value == "yes"; return true;
case "auto-load-folder": AutoLoadFolder = value == "yes"; return true;
case "update-check": UpdateCheck = value == "yes"; return true;
case "start-size": StartSize = value; return true;
case "process-instance": ProcessInstance = value; return true;
case "dark-mode": DarkMode = value; return true;
case "start-threshold": StartThreshold = value.Int(); return true;
case "recent-count": RecentCount = value.Int(); return true;
case "minimum-aspect-ratio": MinimumAspectRatio = value.Float(); return true;
case "dark-theme": DarkTheme = value.Trim('\'', '"'); return true;
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
default:
if (writeError)
ConsoleHelp.WriteError($"unknown mpvnet.conf property: {name}", "mpv.net");
return false;
}
}
}
}

View File

@@ -1,361 +0,0 @@

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using VB = Microsoft.VisualBasic;
using ScriptHost;
using static NewLine;
namespace mpvnet
{
public class Command
{
public static void Execute(string id, string[] args)
{
switch (id)
{
case "open-files": OpenFiles(args); break;
case "update-check": UpdateCheck.CheckOnline(true); break;
case "open-url": OpenURL(); break;
case "open-optical-media": Open_DVD_Or_BD_Folder(); break;
case "manage-file-associations": // deprecated 2019
case "show-setup-dialog": ShowDialog(typeof(SetupWindow)); break;
case "cycle-audio": CycleAudio(); break;
case "load-audio": LoadAudio(); break;
case "load-sub": LoadSubtitle(); break;
case "execute-mpv-command": ExecuteMpvCommand(); break;
case "show-history": ShowHistory(); break;
case "show-media-search": ShowDialog(typeof(EverythingWindow)); break;
case "show-command-palette": ShowDialog(typeof(CommandPaletteWindow)); break;
case "show-about": ShowDialog(typeof(AboutWindow)); break;
case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break;
case "show-input-editor": ShowDialog(typeof(InputWindow)); break;
case "open-conf-folder": Process.Start(mp.ConfigFolder); break;
case "shell-execute": Process.Start(args[0]); break;
case "show-info": ShowInfo(); break;
case "playlist-first": PlaylistFirst(); break;
case "playlist-last": PlaylistLast(); break;
case "show-profiles": ShowProfiles(); break;
case "show-properties": ShowProperties(); break;
case "show-commands": ShowCommands(); break;
case "add-files-to-playlist": OpenFiles("append"); break; // deprecated 2019
default: Msg.ShowError($"No command '{id}' found."); break;
}
}
public static void InvokeOnMainThread(Action action) => MainForm.Instance.Invoke(action);
public static void ShowDialog(Type winType)
{
InvokeOnMainThread(new Action(() => {
Window win = Activator.CreateInstance(winType) as Window;
new WindowInteropHelper(win).Owner = MainForm.Instance.Handle;
win.ShowDialog();
}));
}
public static void OpenFiles(params string[] args)
{
bool append = Control.ModifierKeys.HasFlag(Keys.Control);
bool loadFolder = true;
foreach (string arg in args)
{
if (arg == "append") append = true;
if (arg == "no-folder") loadFolder = false;
}
InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog() { Multiselect = true })
if (d.ShowDialog() == DialogResult.OK)
mp.LoadFiles(d.FileNames, loadFolder, append);
}));
}
public static void Open_DVD_Or_BD_Folder()
{
InvokeOnMainThread(new Action(() => {
using (var d = new FolderBrowserDialog())
{
d.Description = "Select a DVD or Blu-ray folder.";
d.ShowNewFolderButton = false;
if (d.ShowDialog() == DialogResult.OK)
{
if (Directory.Exists(d.SelectedPath + "\\BDMV"))
{
mp.set_property_string("bluray-device", d.SelectedPath);
mp.LoadFiles(new[] { @"bd://" }, false, false);
}
else
{
mp.set_property_string("dvd-device", d.SelectedPath);
mp.LoadFiles(new[] { @"dvd://" }, false, false);
}
}
}
}));
}
public static void PlaylistFirst()
{
int pos = mp.get_property_int("playlist-pos");
if (pos != 0)
mp.set_property_int("playlist-pos", 0);
}
public static void PlaylistLast()
{
int pos = mp.get_property_int("playlist-pos");
int count = mp.get_property_int("playlist-count");
if (pos < count - 1)
mp.set_property_int("playlist-pos", count - 1);
}
public static void ShowHistory()
{
if (File.Exists(mp.ConfigFolder + "history.txt"))
Process.Start(mp.ConfigFolder + "history.txt");
else
{
if (Msg.ShowQuestion("Create history.txt file in config folder?",
"mpv.net will write the date, time and filename of opened files to it.") == MsgResult.OK)
File.WriteAllText(mp.ConfigFolder + "history.txt", "");
}
}
public static void ShowInfo()
{
try
{
string performer, title, album, genre, date, duration, text = "";
long fileSize = 0;
string path = mp.get_property_string("path");
if (path.Contains("://"))
path = mp.get_property_string("media-title");
int width = mp.get_property_int("video-params/w");
int height = mp.get_property_int("video-params/h");
if (File.Exists(path))
{
fileSize = new FileInfo(path).Length;
if (App.AudioTypes.Contains(path.ShortExt()))
{
using (MediaInfo mediaInfo = new MediaInfo(path))
{
performer = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Performer");
title = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Title");
album = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Album");
genre = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Genre");
date = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Recorded_Date");
duration = mediaInfo.GetInfo(MediaInfoStreamKind.Audio, "Duration/String");
if (performer != "") text += "Artist: " + performer + "\n";
if (title != "") text += "Title: " + title + "\n";
if (album != "") text += "Album: " + album + "\n";
if (genre != "") text += "Genre: " + genre + "\n";
if (date != "") text += "Year: " + date + "\n";
if (duration != "") text += "Length: " + duration + "\n";
text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n";
text += "Type: " + path.ShortExt().ToUpper();
mp.commandv("show-text", text, "5000");
return;
}
}
else if (App.ImageTypes.Contains(path.ShortExt()))
{
using (MediaInfo mediaInfo = new MediaInfo(path))
{
text =
"Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" +
"Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" +
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
"Type: " + path.ShortExt().ToUpper();
mp.commandv("show-text", text, "5000");
return;
}
}
}
TimeSpan position = TimeSpan.FromSeconds(mp.get_property_number("time-pos"));
TimeSpan duration2 = TimeSpan.FromSeconds(mp.get_property_number("duration"));
string videoFormat = mp.get_property_string("video-format").ToUpper();
string audioCodec = mp.get_property_string("audio-codec-name").ToUpper();
text = path.FileName() + "\n" +
FormatTime(position.TotalMinutes) + ":" +
FormatTime(position.Seconds) + " / " +
FormatTime(duration2.TotalMinutes) + ":" +
FormatTime(duration2.Seconds) + "\n" +
$"{width} x {height}\n";
if (fileSize > 0)
text += Convert.ToInt32(fileSize / 1024.0 / 1024.0) + " MB\n";
text += $"{videoFormat}\n{audioCodec}";
mp.commandv("show-text", text, "5000");
string FormatTime(double value) => ((int)value).ToString("00");
}
catch (Exception e)
{
Msg.ShowException(e);
}
}
public static void ExecuteMpvCommand() // deprecated 2019
{
InvokeOnMainThread(new Action(() => {
string command = VB.Interaction.InputBox("Enter a mpv command to be executed.", "Execute Command", RegistryHelp.GetString(App.RegPath, "RecentExecutedCommand"));
if (string.IsNullOrEmpty(command)) return;
RegistryHelp.SetValue(App.RegPath, "RecentExecutedCommand", command);
mp.command(command, false);
}));
}
public static void OpenURL()
{
InvokeOnMainThread(new Action(() => {
string clipboard = System.Windows.Forms.Clipboard.GetText();
if (string.IsNullOrEmpty(clipboard) || (!clipboard.Contains("://") && !File.Exists(clipboard)) || clipboard.Contains("\n"))
{
Msg.ShowError("The clipboard does not contain a valid URL or file, URLs have to contain :// and are not allowed to contain a newline character.");
return;
}
mp.LoadFiles(new [] { clipboard }, false, Control.ModifierKeys.HasFlag(Keys.Control));
}));
}
public static void LoadSubtitle()
{
InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog())
{
string path = mp.get_property_string("path");
if (File.Exists(path))
d.InitialDirectory = Path.GetDirectoryName(path);
d.Multiselect = true;
if (d.ShowDialog() == DialogResult.OK)
foreach (string filename in d.FileNames)
mp.commandv("sub-add", filename);
}
}));
}
public static void LoadAudio()
{
InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog())
{
string path = mp.get_property_string("path");
if (File.Exists(path))
d.InitialDirectory = Path.GetDirectoryName(path);
d.Multiselect = true;
if (d.ShowDialog() == DialogResult.OK)
foreach (string i in d.FileNames)
mp.commandv("audio-add", i);
}
}));
}
public static void CycleAudio()
{
string path = mp.get_property_string("path");
if (!File.Exists(path))
return;
using (MediaInfo mi = new MediaInfo(path))
{
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
if (audTracks.Length < 2)
return;
int aid = mp.get_property_int("aid");
aid += 1;
if (aid > audTracks.Length)
aid = 1;
mp.commandv("set", "aid", aid.ToString());
mp.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000");
}
}
static void ShowProfiles()
{
string code = @"
foreach ($item in ($json | ConvertFrom-Json | foreach { $_ } | sort name))
{
$item.name
''
foreach ($option in $item.options)
{
' ' + $option.key + ' = ' + $option.value
}
''
}";
string json = mp.get_property_string("profile-list");
string file = Path.GetTempPath() + @"\mpv profile-list.txt";
File.WriteAllText(file, BR + PowerShell.InvokeAndReturnString(code, "json", json));
Process.Start(file);
}
static void ShowCommands()
{
string code = @"
foreach ($item in ($json | ConvertFrom-Json | foreach { $_ } | sort name))
{
''
$item.name
foreach ($arg in $item.args)
{
$value = $arg.name + ' <' + $arg.type.ToLower() + '>'
if ($arg.optional -eq $true)
{
$value = '[' + $value + ']'
}
' ' + $value
}
}";
string json = mp.get_property_string("command-list");
string file = Path.GetTempPath() + @"\mpv command-list.txt";
File.WriteAllText(file, PowerShell.InvokeAndReturnString(code, "json", json) + BR);
Process.Start(file);
}
static void ShowProperties()
{
string file = Path.GetTempPath() + @"\mpv property-list.txt";
var props = mp.get_property_string("property-list").Split(',').OrderBy(prop => prop);
File.WriteAllText(file, BR + string.Join(BR, props) + BR);
Process.Start(file);
}
}
}

View File

@@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
namespace mpvnet
{
public class Extension
{
[ImportMany]
public IEnumerable<IExtension> Extensions = null;
readonly CompositionContainer CompositionContainer;
public Extension()
{
try
{
AggregateCatalog catalog = new AggregateCatalog();
string dir = Folder.Startup + "Extensions";
if (Directory.Exists(dir))
{
string[] knownExtensions = { "RatingExtension", "ScriptingExtension" };
foreach (string path in Directory.GetDirectories(dir))
{
if (knownExtensions.Contains(Path.GetFileName(path)))
catalog.Catalogs.Add(new DirectoryCatalog(path, "*Extension.dll"));
else
Msg.ShowError("Failed to load extension", path + "\n\nOnly extensions that ship with mpv.net are allowed in <startup>\\extensions\n\nUser extensions have to use <config folder>\\extensions\n\nNever copy or install a new mpv.net version over a old mpv.net version.");
}
}
dir = mp.ConfigFolder + "extensions";
if (Directory.Exists(dir))
foreach (string i in Directory.GetDirectories(dir))
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Extension.dll"));
if (catalog.Catalogs.Count > 0)
{
CompositionContainer = new CompositionContainer(catalog);
CompositionContainer.ComposeParts(this);
}
}
catch (Exception ex)
{
Msg.ShowException(ex);
}
}
}
public interface IExtension
{
}
}

View File

@@ -1,32 +0,0 @@
using System.Globalization;
using System.IO;
public static class Extensions
{
public static string FileName(this string path)
{
if (string.IsNullOrEmpty(path)) return "";
int index = path.LastIndexOf('\\');
if (index > -1) return path.Substring(index + 1);
index = path.LastIndexOf('/');
if (index > -1) return path.Substring(index + 1);
return path;
}
public static string ShortExt(this string path)
{
return Path.GetExtension(path).ToLower().TrimStart('.');
}
public static int Int(this string value)
{
int.TryParse(value, out int result);
return result;
}
public static float Float(this string value)
{
float.TryParse(value.Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out float result);
return result;
}
}

View File

@@ -1,45 +0,0 @@

using System;
using System.Diagnostics;
public static class ConsoleHelp
{
public static int Padding { get; set; }
public static void WriteError(object obj, string module = null) => Write(obj, module, ConsoleColor.Red, false);
public static void Write(object obj, string module = "mpv.net")
{
Write(obj, module, ConsoleColor.Black, true);
}
public static void Write(object obj, string module, ConsoleColor color)
{
Write(obj, module, color, false);
}
public static void Write(object obj, string module, ConsoleColor color, bool useDefaultColor)
{
if (obj == null)
return;
string value = obj.ToString();
if (!string.IsNullOrEmpty(module))
module = "[" + module + "] ";
if (useDefaultColor)
Console.ResetColor();
else
Console.ForegroundColor = color;
value = module + value;
if (Padding > 0 && value.Length < Padding)
value = value.PadRight(Padding);
Console.WriteLine(value);
Console.ResetColor();
Trace.WriteLine(obj);
}
}

View File

@@ -1,230 +0,0 @@

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Windows.Forms;
using Microsoft.Win32;
namespace mpvnet
{
public class Sys
{
public static bool IsDarkTheme {
get {
object value = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
if (value is null)
value = 1;
return (int)value == 0;
}
}
}
public class StringLogicalComparer : IComparer, IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogical(string x, string y);
int IComparer_Compare(object x, object y) => StrCmpLogical(x.ToString(), y.ToString());
int IComparer.Compare(object x, object y) => IComparer_Compare(x, y);
int IComparerOfString_Compare(string x, string y) => StrCmpLogical(x, y);
int IComparer<string>.Compare(string x, string y) => IComparerOfString_Compare(x, y);
}
public class FileAssociation
{
static string ExePath = Application.ExecutablePath;
static string ExeFilename = Path.GetFileName(Application.ExecutablePath);
static string ExeFilenameNoExt = Path.GetFileNameWithoutExtension(Application.ExecutablePath);
static string[] Types;
public static void Register(string[] types)
{
Types = types;
RegistryHelp.SetValue(@"HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename, null, ExePath);
RegistryHelp.SetValue(@"HKCR\Applications\" + ExeFilename, "FriendlyAppName", "mpv.net media player");
RegistryHelp.SetValue($@"HKCR\Applications\{ExeFilename}\shell\open\command", null, $"\"{ExePath}\" \"%1\"");
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationDescription", "mpv.net media player");
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationName", "mpv.net");
RegistryHelp.SetValue(@"HKCR\SystemFileAssociations\video\OpenWithList\" + ExeFilename, null, "");
RegistryHelp.SetValue(@"HKCR\SystemFileAssociations\audio\OpenWithList\" + ExeFilename, null, "");
RegistryHelp.SetValue(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net", @"SOFTWARE\Clients\Media\mpv.net\Capabilities");
foreach (string ext in Types)
{
RegistryHelp.SetValue($@"HKCR\Applications\{ExeFilename}\SupportedTypes", "." + ext, "");
RegistryHelp.SetValue($@"HKCR\" + "." + ext, null, ExeFilenameNoExt + "." + ext);
RegistryHelp.SetValue($@"HKCR\" + "." + ext + @"\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, "");
if (App.VideoTypes.Contains(ext))
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "video");
if (App.AudioTypes.Contains(ext))
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "audio");
if (App.ImageTypes.Contains(ext))
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "image");
RegistryHelp.SetValue($@"HKCR\" + ExeFilenameNoExt + "." + ext + @"\shell\open\command", null, $"\"{ExePath}\" \"%1\"");
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext);
}
}
public static void Unregister()
{
RegistryHelp.RemoveKey($@"HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename);
RegistryHelp.RemoveKey($@"HKCR\Applications\" + ExeFilename);
RegistryHelp.RemoveKey($@"HKLM\SOFTWARE\Clients\Media\mpv.net");
RegistryHelp.RemoveKey($@"HKCR\SystemFileAssociations\video\OpenWithList\" + ExeFilename);
RegistryHelp.RemoveKey($@"HKCR\SystemFileAssociations\audio\OpenWithList\" + ExeFilename);
RegistryHelp.RemoveValue(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net");
foreach (string id in Registry.ClassesRoot.GetSubKeyNames())
{
if (id.StartsWith(ExeFilenameNoExt + "."))
Registry.ClassesRoot.DeleteSubKeyTree(id);
RegistryHelp.RemoveValue($@"HKCR\Software\Classes\{id}\OpenWithProgIDs", ExeFilenameNoExt + id);
RegistryHelp.RemoveValue($@"HKLM\Software\Classes\{id}\OpenWithProgIDs", ExeFilenameNoExt + id);
}
}
}
public class MediaTrack
{
public string Text { get; set; }
public string Type { get; set; }
public int ID { get; set; }
}
public class CommandItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Path { get; set; } = "";
public string Command { get; set; } = "";
public CommandItem() { }
public CommandItem(SerializationInfo info, StreamingContext context) { }
void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
string _Input = "";
public string Input {
get => _Input;
set {
_Input = value;
NotifyPropertyChanged();
}
}
public static ObservableCollection<CommandItem> GetItems(string content)
{
var items = new ObservableCollection<CommandItem>();
if (!string.IsNullOrEmpty(content))
{
foreach (string line in content.Split('\r', '\n'))
{
string val = line.Trim();
if (val.StartsWith("#"))
continue;
if (!val.Contains(" "))
continue;
CommandItem item = new CommandItem();
item.Input = val.Substring(0, val.IndexOf(" "));
if (item.Input == "_")
item.Input = "";
val = val.Substring(val.IndexOf(" ") + 1);
if (val.Contains("#menu:"))
{
item.Path = val.Substring(val.IndexOf("#menu:") + 6).Trim();
val = val.Substring(0, val.IndexOf("#menu:"));
if (item.Path.Contains(";"))
item.Path = item.Path.Substring(item.Path.IndexOf(";") + 1).Trim();
}
item.Command = val.Trim();
if (item.Command == "")
continue;
if (item.Command.ToLower() == "ignore")
item.Command = "";
items.Add(item);
}
}
return items;
}
static ObservableCollection<CommandItem> _Items;
public static ObservableCollection<CommandItem> Items {
get {
if (_Items is null)
_Items = GetItems(File.ReadAllText(mp.InputConfPath));
return _Items;
}
}
}
public class CursorHelp
{
static bool IsVisible = true;
public static void Show()
{
if (!IsVisible)
{
Cursor.Show();
IsVisible = true;
}
}
public static void Hide()
{
if (IsVisible)
{
Cursor.Hide();
IsVisible = false;
}
}
public static bool IsPosDifferent(Point screenPos)
{
return
Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
}
}
public class Folder
{
public static string Startup { get; } = Application.StartupPath + @"\";
}
}

View File

@@ -1,8 +0,0 @@

using System;
public static class NewLine
{
public static string BR = Environment.NewLine;
public static string BR2 = Environment.NewLine + Environment.NewLine;
}

View File

@@ -1,70 +0,0 @@

using System;
using Microsoft.Win32;
using System.Windows.Forms;
public class RegistryHelp
{
public static string ApplicationKey { get; } = @"HKCU\Software\" + Application.ProductName;
public static void SetValue(string path, string name, object value)
{
using (RegistryKey regKey = GetRootKey(path).CreateSubKey(path.Substring(5), RegistryKeyPermissionCheck.ReadWriteSubTree))
regKey.SetValue(name, value);
}
public static string GetString(string path, string name, string defaultValue = "")
{
object value = GetValue(path, name, defaultValue);
return !(value is string) ? defaultValue : value.ToString();
}
public static int GetInt(string path, string name, int defaultValue = 0)
{
object value = GetValue(path, name, defaultValue);
return !(value is int) ? defaultValue : (int)value;
}
public static bool GetBool(string path, string name, bool defaultValue = false)
{
object val = GetValue(path, name, defaultValue);
return val is bool ? (bool)val : defaultValue;
}
public static object GetValue(string path, string name, object defaultValue = null)
{
using (RegistryKey regKey = GetRootKey(path).OpenSubKey(path.Substring(5)))
return regKey == null ? null : regKey.GetValue(name, defaultValue);
}
public static void RemoveKey(string path)
{
try
{
GetRootKey(path).DeleteSubKeyTree(path.Substring(5), false);
}
catch { }
}
public static void RemoveValue(string path, string name)
{
try
{
using (RegistryKey regKey = GetRootKey(path).OpenSubKey(path.Substring(5), true))
if (regKey != null)
regKey.DeleteValue(name, false);
}
catch { }
}
static RegistryKey GetRootKey(string path)
{
switch (path.Substring(0, 4))
{
case "HKLM": return Registry.LocalMachine;
case "HKCU": return Registry.CurrentUser;
case "HKCR": return Registry.ClassesRoot;
default: throw new Exception();
}
}
}

View File

@@ -1,77 +0,0 @@

using System;
using System.Diagnostics;
using System.Net.Http;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace mpvnet
{
class UpdateCheck
{
public static void DailyCheck()
{
if (App.UpdateCheck && RegistryHelp.GetInt(RegistryHelp.ApplicationKey, "UpdateCheckLast")
!= DateTime.Now.DayOfYear)
CheckOnline();
}
public static async void CheckOnline(bool showUpToDateMessage = false)
{
try
{
using (HttpClient client = new HttpClient())
{
RegistryHelp.SetValue(RegistryHelp.ApplicationKey, "UpdateCheckLast", DateTime.Now.DayOfYear);
client.DefaultRequestHeaders.Add("User-Agent", "mpv.net");
var response = await client.GetAsync("https://api.github.com/repos/stax76/mpv.net/releases/latest");
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
Match match = Regex.Match(content, @"""mpv\.net-portable-x64-([\d\.]+)\.7z""");
Version onlineVersion = Version.Parse(match.Groups[1].Value);
Version currentVersion = Assembly.GetEntryAssembly().GetName().Version;
if (onlineVersion <= currentVersion)
{
if (showUpToDateMessage)
Msg.Show($"{Application.ProductName} is up to date.");
return;
}
if ((RegistryHelp.GetString(RegistryHelp.ApplicationKey, "UpdateCheckVersion")
!= onlineVersion.ToString() || showUpToDateMessage) && Msg.ShowQuestion(
$"New version {onlineVersion} is available, update now?") == MsgResult.OK)
{
string arch = IntPtr.Size == 8 ? "64" : "86";
string url = $"https://github.com/stax76/mpv.net/releases/download/{onlineVersion}/mpv.net-portable-x{arch}-{onlineVersion}.7z";
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
proc.StartInfo.FileName = "PowerShell";
proc.StartInfo.Arguments = $"-NoLogo -NoExit -File \"{Folder.Startup + "Update.ps1"}\" \"{url}\" \"{Application.StartupPath.TrimEnd('\\')}\"";
if (Folder.Startup.Contains("Program Files"))
proc.StartInfo.Verb = "runas";
proc.Start();
}
mp.command("quit");
}
RegistryHelp.SetValue(RegistryHelp.ApplicationKey, "UpdateCheckVersion", onlineVersion.ToString());
}
}
catch (Exception ex)
{
if (showUpToDateMessage)
Msg.ShowException(ex);
}
}
}
}

View File

@@ -1,99 +0,0 @@

using System;
using System.Drawing;
using System.Runtime.InteropServices;
public class WinAPI
{
[DllImport("kernel32.dll")]
public static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool FreeConsole();
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string path);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int RegisterWindowMessage(string id);
[DllImport("user32.dll")]
public static extern bool AllowSetForegroundWindow(int dwProcessId);
[DllImport("user32.dll")]
public static extern void ReleaseCapture();
[DllImport("user32.dll")]
public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLong64(hWnd, nIndex);
else
return GetWindowLong32(hWnd, nIndex);
}
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(Rectangle r)
{
Left = r.Left;
Top = r.Top;
Right = r.Right;
Bottom = r.Bottom;
}
public RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
public Size Size => new Size(Right - Left, Bottom - Top);
public int Width => Right - Left;
public int Height => Bottom - Top;
}
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpData;
}
}

View File

@@ -1,38 +0,0 @@
using System;
namespace mpvnet
{
public static class NativeHelp
{
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 WinAPI.RECT rc)
{
var b = new WinAPI.RECT(0, 0, 0, 0);
AddWindowBorders(hwnd, ref b);
rc.Left -= b.Left;
rc.Top -= b.Top;
rc.Right -= b.Right;
rc.Bottom -= b.Bottom;
}
public static void AddWindowBorders(IntPtr hwnd, ref WinAPI.RECT rc)
{
WinAPI.AdjustWindowRect(ref rc, (uint)WinAPI.GetWindowLong(hwnd, -16 /* GWL_STYLE */), false);
}
}
}

View File

@@ -1,662 +0,0 @@

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
public class Msg
{
static string ShownMessages;
public static string SupportURL { get; set; }
public static void Show(string mainInstruction, string content = null)
{
Msg.Show(mainInstruction, content, MsgIcon.Info, MsgButtons.Ok, MsgResult.None);
}
public static void ShowError(string mainInstruction, string content = null)
{
try
{
using (TaskDialog<string> td = new TaskDialog<string>())
{
td.AllowCancel = false;
if (string.IsNullOrEmpty(content))
{
if (mainInstruction.Length < 80)
td.MainInstruction = mainInstruction;
else
td.Content = mainInstruction;
}
else
{
td.MainInstruction = mainInstruction;
td.Content = content;
}
td.MainIcon = MsgIcon.Error;
td.Footer = "[Copy Message](copymsg)";
if (!string.IsNullOrEmpty(Msg.SupportURL))
td.Footer += $" [Contact Support]({SupportURL})";
td.Show();
}
}
catch (Exception e)
{
MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public static void ShowException(Exception exception)
{
try
{
using (TaskDialog<string> td = new TaskDialog<string>())
{
td.MainInstruction = exception.GetType().Name;
td.Content = exception.Message;
td.MainIcon = MsgIcon.Error;
td.ExpandedInformation = exception.StackTrace;
td.Footer = "[Copy Message](copymsg)";
if (!string.IsNullOrEmpty(Msg.SupportURL))
td.Footer += $" [Contact Support]({SupportURL})";
td.Show();
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public static void ShowWarning(string mainInstruction,
string content = null,
bool onlyOnce = false)
{
if (onlyOnce && Msg.ShownMessages != null &&
Msg.ShownMessages.Contains(mainInstruction + content))
return;
Msg.Show(mainInstruction, content, MsgIcon.Warning, MsgButtons.Ok, MsgResult.None);
if (!onlyOnce) return;
Msg.ShownMessages += mainInstruction + content;
}
public static MsgResult ShowQuestion(
string mainInstruction, MsgButtons buttons = MsgButtons.OkCancel)
{
return Msg.Show(mainInstruction, null, MsgIcon.None, buttons, MsgResult.None);
}
public static MsgResult ShowQuestion(
string mainInstruction, string content, MsgButtons buttons = MsgButtons.OkCancel)
{
return Msg.Show(mainInstruction, content, MsgIcon.None, buttons, MsgResult.None);
}
public static MsgResult Show(
string mainInstruction,
string content,
MsgIcon icon,
MsgButtons buttons,
MsgResult defaultButton = MsgResult.None)
{
try
{
using (TaskDialog<MsgResult> td = new TaskDialog<MsgResult>())
{
td.AllowCancel = false;
td.DefaultButton = defaultButton;
td.MainIcon = icon;
if (content == null)
{
if (mainInstruction.Length < 80)
td.MainInstruction = mainInstruction;
else
td.Content = mainInstruction;
}
else
{
td.MainInstruction = mainInstruction;
td.Content = content;
}
if (buttons == MsgButtons.OkCancel)
{
td.AddButton("OK", MsgResult.OK);
td.AddButton("Cancel", MsgResult.Cancel);
}
else
td.CommonButtons = buttons;
return td.Show();
}
}
catch (Exception e)
{
return (MsgResult)MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
public class TaskDialog<T> : TaskDialogNative, IDisposable
{
Dictionary<int, T> IdValueDic;
Dictionary<int, string> IdTextDic;
List<int> CommandLinkShieldList;
IntPtr ButtonArray;
IntPtr RadioButtonArray;
T SelectedValueValue;
string SelectedTextValue;
int TimeoutValue;
int ExitTickCount;
bool Disposed;
List<TaskDialogNative.TASKDIALOG_BUTTON> Buttons;
List<TaskDialogNative.TASKDIALOG_BUTTON> RadioButtons;
TaskDialogNative.TASKDIALOGCONFIG Config;
const int TDE_CONTENT = 0;
const int TDE_EXPANDED_INFORMATION = 1;
const int TDE_FOOTER = 2;
const int TDE_MAIN_INSTRUCTION = 3;
const int TDN_CREATED = 0;
const int TDN_NAVIGATED = 1;
const int TDN_BUTTON_CLICKED = 2;
const int TDN_HYPERLINK_CLICKED = 3;
const int TDN_TIMER = 4;
const int TDN_DESTROYED = 5;
const int TDN_RADIO_BUTTON_CLICKED = 6;
const int TDN_DIALOG_CONSTRUCTED = 7;
const int TDN_VERIFICATION_CLICKED = 8;
const int TDN_HELP = 9;
const int TDN_EXPANDO_BUTTON_CLICKED = 10;
const int TDM_NAVIGATE_PAGE = 1125;
const int TDM_CLICK_BUTTON = 1126;
const int TDM_SET_MARQUEE_PROGRESS_BAR = 1127;
const int TDM_SET_PROGRESS_BAR_STATE = 1128;
const int TDM_SET_PROGRESS_BAR_RANGE = 1129;
const int TDM_SET_PROGRESS_BAR_POS = 1130;
const int TDM_SET_PROGRESS_BAR_MARQUEE = 1131;
const int TDM_SET_ELEMENT_TEXT = 1132;
const int TDM_CLICK_RADIO_BUTTON = 1134;
const int TDM_ENABLE_BUTTON = 1135;
const int TDM_ENABLE_RADIO_BUTTON = 1136;
const int TDM_CLICK_VERIFICATION = 1137;
const int TDM_UPDATE_ELEMENT_TEXT = 1138;
const int TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = 1139;
const int TDM_UPDATE_ICON = 1140;
public TaskDialog()
{
IdValueDic = new Dictionary<int, T>();
IdTextDic = new Dictionary<int, string>();
CommandLinkShieldList = new List<int>();
Buttons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
RadioButtons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
_SelectedID = -1;
Config = new TaskDialogNative.TASKDIALOGCONFIG();
Config.cbSize = (uint)Marshal.SizeOf(Config);
Config.hwndParent = GetHandle();
Config.hInstance = IntPtr.Zero;
Config.dwFlags = TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
Config.dwCommonButtons = MsgButtons.None;
Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
Config.FooterIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
Config.cxWidth = 0U;
Config.cButtons = 0U;
Config.cRadioButtons = 0U;
Config.pButtons = IntPtr.Zero;
Config.pRadioButtons = IntPtr.Zero;
Config.nDefaultButton = 0;
Config.nDefaultRadioButton = 0;
Config.pszWindowTitle = ((AssemblyProductAttribute)Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0]).Product;
Config.pszMainInstruction = "";
Config.pszContent = "";
Config.pfCallback = new PFTASKDIALOGCALLBACK(this.DialogProc);
}
public IntPtr GetHandle()
{
StringBuilder lpszFileName = new StringBuilder(260);
IntPtr foregroundWindow = TaskDialogNative.GetForegroundWindow();
TaskDialogNative.GetWindowModuleFileName(foregroundWindow, lpszFileName, 260U);
if (Path.GetFileName(lpszFileName.ToString().Replace(".vshost", "")) ==
Path.GetFileName(Assembly.GetEntryAssembly().Location))
return foregroundWindow;
return IntPtr.Zero;
}
public bool AllowCancel {
set {
if (value)
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
else
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
}
}
public string MainInstruction {
get => Config.pszMainInstruction;
set => Config.pszMainInstruction = value;
}
public string Content {
get => Config.pszContent;
set => Config.pszContent = ExpandMarkdownMarkup(value);
}
public string ExpandedInformation {
get => Config.pszExpandedInformation;
set => Config.pszExpandedInformation = ExpandMarkdownMarkup(value);
}
public string VerificationText {
get => Config.pszVerificationText;
set => Config.pszVerificationText = value;
}
public MsgResult DefaultButton {
get => (MsgResult)Config.nDefaultButton;
set => Config.nDefaultButton = (int)value;
}
public string Footer {
get => Config.pszFooter;
set => Config.pszFooter = ExpandMarkdownMarkup(value);
}
public MsgIcon MainIcon {
set => Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION((int)value);
}
int _SelectedID;
public int SelectedID {
get => _SelectedID;
set {
foreach (var i in IdValueDic)
if (i.Key == value)
_SelectedID = value;
}
}
public T SelectedValue {
get {
if (IdValueDic.ContainsKey(SelectedID))
return IdValueDic[SelectedID];
return SelectedValueValue;
}
set => SelectedValueValue = value;
}
public string SelectedText {
get {
if (IdTextDic.ContainsKey(SelectedID))
return IdTextDic[SelectedID];
return SelectedTextValue;
}
set => SelectedTextValue = value;
}
public bool CheckBoxChecked {
get => (Config.dwFlags & TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED)
== TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
set {
if (value)
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
else
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
}
}
public MsgButtons CommonButtons {
get => Config.dwCommonButtons;
set => Config.dwCommonButtons = value;
}
public int Timeout {
get => Convert.ToInt32(TimeoutValue / 1000.0);
set {
TimeoutValue = value * 1000;
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER;
}
}
public void AddButton(string text, T value)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value;
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
}
public string ExpandMarkdownMarkup(string value)
{
if (value.Contains("["))
{
Regex regex = new Regex(@"\[(.+)\]\((.+)\)");
if (regex.Match(value).Success)
{
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS;
value = regex.Replace(value, "<a href=\"$2\">$1</a>");
}
}
return value;
}
public void AddCommand(string text, T value)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value;
IdTextDic[n] = text;
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
}
public void AddCommand(string text, string description, T value, bool setShield = false)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value;
if (setShield)
CommandLinkShieldList.Add(n);
if (!string.IsNullOrEmpty(description))
text += "\n" + description;
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
}
public void AddRadioButton(string text, T value)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value;
RadioButtons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
}
public T Show()
{
MarshalDialogControlStructs();
TaskDialogNative.TASKDIALOGCONFIG config = Config;
int hr = TaskDialogNative.TaskDialogIndirect(
config, out int dummy1, out int dummy2, out bool isChecked);
if (hr < 0)
Marshal.ThrowExceptionForHR(hr);
CheckBoxChecked = isChecked;
if (SelectedValue is MsgResult)
SelectedValue = (T)(object)SelectedID;
return SelectedValue;
}
public int DialogProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, IntPtr lpRefData)
{
switch (msg)
{
case 0: //TDN_CREATED
foreach (var i in CommandLinkShieldList)
SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, new IntPtr(i), new IntPtr(1));
break;
case 2: //TDN_BUTTON_CLICKED
case 6: //TDN_RADIO_BUTTON_CLICKED
if (SelectedValue is MsgResult)
_SelectedID = wParam.ToInt32();
else
SelectedID = wParam.ToInt32();
break;
case 3: //TDN_HYPERLINK_CLICKED
string stringUni = Marshal.PtrToStringUni(lParam);
if (stringUni.StartsWith("mailto") || stringUni.StartsWith("http"))
Process.Start(stringUni);
if (stringUni == "copymsg")
{
Thread thread = new Thread((ThreadStart)(() => {
Clipboard.SetText(MainInstruction + "\r\n\r\n" + Content + "\r\n\r\n" + ExpandedInformation);
MessageBox.Show("Message was copied to clipboard.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
break;
case 4: //TDN_TIMER
if (ExitTickCount == 0) ExitTickCount = Environment.TickCount + Timeout * 1000;
if (Environment.TickCount > ExitTickCount)
TaskDialogNative.SendMessage(hwnd, 1126, new IntPtr(1), IntPtr.Zero);
break;
}
return 0;
}
public void MarshalDialogControlStructs()
{
if (Buttons != null && Buttons.Count > 0)
{
ButtonArray = TaskDialog<T>.AllocateAndMarshalButtons(Buttons);
Config.pButtons = ButtonArray;
Config.cButtons = (uint)Buttons.Count;
}
if (RadioButtons == null || RadioButtons.Count <= 0) return;
RadioButtonArray = TaskDialog<T>.AllocateAndMarshalButtons(RadioButtons);
Config.pRadioButtons = RadioButtonArray;
Config.cRadioButtons = (uint)RadioButtons.Count;
}
public static IntPtr AllocateAndMarshalButtons(List<TaskDialogNative.TASKDIALOG_BUTTON> structs)
{
var initialPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TASKDIALOG_BUTTON)) * structs.Count);
var currentPtr = initialPtr;
foreach (var button in structs)
{
Marshal.StructureToPtr(button, currentPtr, false);
currentPtr = (IntPtr)(currentPtr.ToInt64() + Marshal.SizeOf(button));
}
return initialPtr;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~TaskDialog()
{
Dispose(false);
}
protected void Dispose(bool disposing)
{
if (Disposed)
return;
Disposed = true;
if (ButtonArray != IntPtr.Zero)
{
Marshal.FreeHGlobal(ButtonArray);
ButtonArray = IntPtr.Zero;
}
if (RadioButtonArray != IntPtr.Zero)
{
Marshal.FreeHGlobal(RadioButtonArray);
RadioButtonArray = IntPtr.Zero;
}
}
}
public delegate int PFTASKDIALOGCALLBACK(
IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, IntPtr lpRefData);
public class TaskDialogNative
{
[DllImport("comctl32", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int TaskDialogIndirect(
TaskDialogNative.TASKDIALOGCONFIG pTaskConfig,
out int pnButton,
out int pnRadioButton,
out bool pVerificationFlagChecked);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetWindowModuleFileName(
IntPtr hwnd, StringBuilder lpszFileName, uint cchFileNameMax);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(
IntPtr handle, int message, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
public class TASKDIALOGCONFIG
{
public uint cbSize;
public IntPtr hwndParent;
public IntPtr hInstance;
public TaskDialogNative.TASKDIALOG_FLAGS dwFlags;
public MsgButtons dwCommonButtons;
public string pszWindowTitle;
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION MainIcon;
public string pszMainInstruction;
public string pszContent;
public uint cButtons;
public IntPtr pButtons;
public int nDefaultButton;
public uint cRadioButtons;
public IntPtr pRadioButtons;
public int nDefaultRadioButton;
public string pszVerificationText;
public string pszExpandedInformation;
public string pszExpandedControlText;
public string pszCollapsedControlText;
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION FooterIcon;
public string pszFooter;
public PFTASKDIALOGCALLBACK pfCallback;
public IntPtr lpCallbackData;
public uint cxWidth;
}
public enum TASKDIALOG_FLAGS
{
NONE = 0,
TDF_ENABLE_HYPERLINKS = 1,
TDF_USE_HICON_MAIN = 2,
TDF_USE_HICON_FOOTER = 4,
TDF_ALLOW_DIALOG_CANCELLATION = 8,
TDF_USE_COMMAND_LINKS = 16,
TDF_USE_COMMAND_LINKS_NO_ICON = 32,
TDF_EXPAND_FOOTER_AREA = 64,
TDF_EXPANDED_BY_DEFAULT = 128,
TDF_VERIFICATION_FLAG_CHECKED = 256,
TDF_SHOW_PROGRESS_BAR = 512,
TDF_SHOW_MARQUEE_PROGRESS_BAR = 1024,
TDF_CALLBACK_TIMER = 2048,
TDF_POSITION_RELATIVE_TO_WINDOW = 4096,
TDF_RTL_LAYOUT = 8192,
TDF_NO_DEFAULT_RADIO_BUTTON = 16384,
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct TASKDIALOGCONFIG_ICON_UNION
{
[FieldOffset(0)]
public int hMainIcon;
[FieldOffset(0)]
public int pszIcon;
[FieldOffset(0)]
public IntPtr spacer;
public TASKDIALOGCONFIG_ICON_UNION(int i)
{
this = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION();
spacer = IntPtr.Zero;
pszIcon = 0;
hMainIcon = i;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
public struct TASKDIALOG_BUTTON
{
public int nButtonID;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszButtonText;
public TASKDIALOG_BUTTON(int n, string txt)
{
this = new TaskDialogNative.TASKDIALOG_BUTTON();
nButtonID = n;
pszButtonText = txt;
}
}
}
public enum MsgButtons
{
None = 0,
Ok = 1,
Yes = 2,
No = 4,
YesNo = 6,
Cancel = 8,
OkCancel = 9,
YesNoCancel = 14,
Retry = 16,
RetryCancel = 24,
Close = 32,
}
public enum MsgResult
{
None,
OK,
Cancel,
Abort,
Retry,
Ignore,
Yes,
No,
}
public enum MsgIcon
{
None = 0,
SecurityShieldGray = 65527,
SecuritySuccess = 65528,
SecurityError = 65529,
SecurityWarning = 65530,
SecurityShieldBlue = 65531,
Shield = 65532,
Info = 65533,
Error = 65534,
Warning = 65535,
}

View File

@@ -1,587 +0,0 @@
[[settings]]
name = "hwdec"
file = "mpv"
default = "no"
filter = "Video"
url = "https://mpv.io/manual/master/#options-hwdec"
help = "Specify the hardware video decoding API that should be used if possible. Whether hardware decoding is actually done depends on the video codec. If hardware decoding is not possible, mpv will fall back on software decoding.\n\nFor more information visit:"
options = [{ name = "no", help = "always use software decoding" },
{ name = "auto", help = "enable best hw decoder (see below)" },
{ name = "yes", help = "exactly the same as auto" },
{ name = "auto-copy", help = "enable best hw decoder with copy-back (see below)" },
{ name = "dxva2", help = "requires vo=gpu with gpu-context=d3d11, gpu-context=angle or gpu-context=dxinterop (Windows only)" },
{ name = "dxva2-copy", help = "copies video back to system RAM (Windows only)" },
{ name = "d3d11va", help = "requires vo=gpu with gpu-context=d3d11 or gpu-context=angle (Windows 8+ only)" },
{ name = "d3d11va-copy", help = "copies video back to system RAM (Windows 8+ only)" },
{ name = "cuda", help = "requires vo=gpu (Any platform CUDA is available)" },
{ name = "cuda-copy", help = "copies video back to system RAM (Any platform CUDA is available)" },
{ name = "nvdec", help = "requires vo=gpu (Any platform CUDA is available)" },
{ name = "nvdec-copy", help = "copies video back to system RAM (Any platform CUDA is available)" },
{ name = "crystalhd", help = "copies video back to system RAM (Any platform supported by hardware)" },
{ name = "rkmpp", help = "requires vo=gpu (some RockChip devices only)" }]
[[settings]]
name = "gpu-api"
file = "mpv"
default = "auto"
filter = "Video"
help = "Controls which type of graphics APIs will be accepted. Auto uses d3d11, it should only be changed in case of problems, Vulkan is not recommended."
options = [{ name = "auto", help = "Use any available API" },
{ name = "opengl", help = "Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)" },
{ name = "vulkan", help = "Allow only Vulkan (not recommended). " },
{ name = "d3d11", help = "Allow only gpu-context=d3d11" }]
[[settings]]
name = "gpu-context"
file = "mpv"
default = "auto"
filter = "Video"
options = [{ name = "auto", help = "auto-select" },
{ name = "win", help = "Win32/WGL" },
{ name = "winvk", help = "VK_KHR_win32_surface" },
{ name = "angle", help = "Direct3D11 through the OpenGL ES translation layer ANGLE. This supports almost everything the win backend does (if the ANGLE build is new enough)." },
{ name = "dxinterop", help = "(experimental) Win32, using WGL for rendering and Direct3D 9Ex for presentation. Works on Nvidia and AMD. Newer Intel chips with the latest drivers may also work." },
{ name = "d3d11", help = "Win32, with native Direct3D 11 rendering." }]
[[settings]]
name = "vo"
file = "mpv"
default = "gpu"
filter = "Video"
help = "Video output drivers to be used.\n\nFor more information visit:"
url = "https://mpv.io/manual/master/#video-output-drivers-vo"
options = [{ name = "gpu", help = "General purpose, customizable, GPU-accelerated video output driver. It supports extended scaling methods, dithering, color management, custom shaders, HDR, and more." },
{ name = "direct3d", help = "Video output driver that uses the Direct3D interface" }]
[[settings]]
name = "video-sync"
file = "mpv"
default = "audio"
filter = "Video"
help = "How the player synchronizes audio and video.\n\nFor more information visit:"
url = "https://mpv.io/manual/master/#options-video-sync"
options = [{ name = "audio" },
{ name = "display-resample" },
{ name = "display-resample-vdrop" },
{ name = "display-resample-desync" },
{ name = "display-vdrop" },
{ name = "display-adrop" },
{ name = "display-desync" },
{ name = "desync" }]
[[settings]]
name = "scale"
file = "mpv"
default = "bilinear"
filter = "Video"
help = "The GPU renderer filter function to use when upscaling video. There are some more filters, but most are not as useful. For a complete list, pass help as value, e.g.: mpv --scale=help"
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality)." },
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale)." },
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see tscale)." },
{ name = "linear", help = "A tscale filter." }]
[[settings]]
name = "cscale"
file = "mpv"
default = "bilinear"
filter = "Video"
help = "As scale, but for interpolating chroma information. If the image is not subsampled, this option is ignored entirely."
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality)." },
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale)." },
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see tscale)." },
{ name = "linear", help = "A tscale filter." }]
[[settings]]
name = "dscale"
file = "mpv"
default = "bilinear"
filter = "Video"
help = "Like scale, but apply these filters on downscaling instead. If this option is unset, the filter implied by scale will be applied."
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality)." },
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale)." },
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see tscale)." },
{ name = "linear", help = "A tscale filter." }]
[[settings]]
name = "dither-depth"
file = "mpv"
default = "no"
filter = "Video"
help = "Set dither target depth to N. Note that the depth of the connected video display device cannot be detected. Often, LCD panels will do dithering on their own, which conflicts with this option and leads to ugly output."
options = [{ name = "no", help = "Disable any dithering done by mpv." },
{ name = "auto", help = "Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed." },
{ name = "8", help = "Dither to 8 bit output." }]
[[settings]]
name = "correct-downscaling"
file = "mpv"
default = "no"
filter = "Video"
help = "When using convolution based filters, extend the filter size when downscaling. Increases quality, but reduces performance while downscaling.\n\nThis will perform slightly sub-optimally for anamorphic video (but still better than without it) since it will extend the size to match only the milder of the scale factors between the axes."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "sigmoid-upscaling"
file = "mpv"
default = "no"
filter = "Video"
help = "When upscaling, use a sigmoidal color transform to avoid emphasizing ringing artifacts. This also implies linear-scaling."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "deband"
file = "mpv"
default = "no"
filter = "Video"
help = "Enable the debanding algorithm. This greatly reduces the amount of visible banding, blocking and other quantization artifacts, at the expense of very slightly blurring some of the finest details. In practice, it's virtually always an improvement - the only reason to disable it would be for performance."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "d3d11va-zero-copy"
file = "mpv"
default = "no"
filter = "Video"
help = "By default, when using hardware decoding with --gpu-api=d3d11, the video image will be copied (GPU-to-GPU) from the decoder surface to a shader resource. Set this option to avoid that copy by sampling directly from the decoder image. This may increase performance and reduce power usage, but can cause the image to be sampled incorrectly on the bottom and right edges due to padding, and may invoke driver bugs, since Direct3D 11 technically does not allow sampling from a decoder surface (though most drivers support it.)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "hdr-compute-peak"
file = "mpv"
default = "auto"
filter = "Video"
help = "Compute the HDR peak and frame average brightness per-frame instead of relying on tagged metadata. These values are averaged over local regions as well as over several frames to prevent the value from jittering around too much. This option basically gives you dynamic, per-scene tone mapping. Requires compute shaders, which is a fairly recent OpenGL feature, and will probably also perform horribly on some drivers, so enable at your own risk. The special value auto (default) will enable HDR peak computation automatically if compute shaders and SSBOs are supported."
options = [{ name = "auto" },
{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "volume"
file = "mpv"
filter = "Audio"
help = "Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. Negative values can be passed for compatibility, but are treated as 0. Since mpv 0.18.1, this always controls the internal mixer (aka \"softvol\"). Default: 100"
[[settings]]
name = "remember-volume"
file = "mpvnet"
default = "yes"
filter = "Audio"
help = "Save volume and mute on exit and restore it on start. (mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "alang"
file = "mpv"
filter = "Audio"
type = "string"
help = "Specify a priority list of audio languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two-letter language codes, Matroska, MPEG-TS and NUT use ISO 639-2 three-letter language codes, while OGM uses a free-form identifier. See also aid.\n\nExamples\n\nmpv dvd://1 alang=hu,en chooses the Hungarian language track on a DVD and falls back on English if Hungarian is not available.\n\nmpv alang=jpn example.mkv plays a Matroska file with Japanese audio."
[[settings]]
name = "audio-file-auto"
file = "mpv"
default = "no"
filter = "Audio"
help = "Load additional audio files matching the video filename. The parameter specifies how external audio files are matched."
options = [{ name = "no", help = "Don't automatically load external audio files." },
{ name = "exact", help = "Load the media filename with audio file extension." },
{ name = "fuzzy", help = "Load all audio files containing media filename." },
{ name = "all", help = "Load all audio files in the current and audio-file-paths directories." }]
[[settings]]
name = "slang"
file = "mpv"
filter = "Subtitle"
type = "string"
help = "Specify a priority list of subtitle languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two letter language codes, Matroska uses ISO 639-2 three letter language codes while OGM uses a free-form identifier. See also sid."
[[settings]]
name = "sub-auto"
file = "mpv"
default = "exact"
filter = "Subtitle"
help = "Load additional subtitle files matching the video filename. The parameter specifies how external subtitle files are matched. exact is enabled by default."
options = [{ name = "no", help = "Don't automatically load external subtitle files." },
{ name = "exact", help = "Load the media filename with subtitle file extension." },
{ name = "fuzzy", help = "Load all subs containing media filename." },
{ name = "all", help = "Load all subs in the current and sub-file-paths directories." }]
[[settings]]
name = "sub-font"
file = "mpv"
filter = "Subtitle"
type = "string"
help = "Specify font to use for subtitles that do not themselves specify a particular font. The default is sans-serif."
[[settings]]
name = "sub-font-size"
file = "mpv"
filter = "Subtitle"
help = "Specify the sub font size. The unit is the size in scaled pixels at a window height of 720. The actual pixel size is scaled with the window height: if the window height is larger or smaller than 720, the actual size of the text increases or decreases as well. Default: 55"
[[settings]]
name = "sub-color"
file = "mpv"
type = "color"
filter = "Subtitle"
help = "Specify the color used for unstyled text subtitles.\n\nThe color is specified in the form r/g/b, where each color component is specified as number in the range 0.0 to 1.0. It's also possible to specify the transparency by using r/g/b/a, where the alpha value 0 means fully transparent, and 1.0 means opaque. If the alpha component is not given, the color is 100% opaque.\n\nPassing a single number to the option sets the sub to gray, and the form gray/a lets you specify alpha additionally.\n\nExamples\n\n1.0/0.0/0.0 set sub to opaque red\n1.0/0.0/0.0/0.75 set sub to opaque red with 75% alpha\n0.5/0.75 set sub to 50% gray with 75% alpha\n\nAlternatively, the color can be specified as a RGB hex triplet in the form #RRGGBB, where each 2-digit group expresses a color value in the range 0 (00) to 255 (FF). For example, #FF0000 is red. This is similar to web colors. Alpha is given with #AARRGGBB.\n\nExamples\n\n#FF0000 set sub to opaque red\n#C0808080 set sub to 50% gray with 75% alpha"
[[settings]]
name = "sub-border-color"
file = "mpv"
type = "color"
filter = "Subtitle"
help = "See sub-color. Color used for the sub font border. Ignored when sub-back-color is specified (or more exactly: when that option is not set to completely transparent)."
[[settings]]
name = "sub-back-color"
file = "mpv"
type = "color"
filter = "Subtitle"
help = "See sub-color. Color used for sub text background. You can use sub-shadow-offset to change its size relative to the text."
[[settings]]
name = "fullscreen"
file = "mpv"
default = "no"
filter = "Screen"
help = "Start the player in fullscreen mode."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "border"
file = "mpv"
default = "yes"
filter = "Screen"
help = "Show window with decoration (titlebar, border)."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "screen"
file = "mpv"
filter = "Screen"
help = "<0-32> In multi-monitor configurations (i.e. a single desktop that spans across multiple displays), this option tells mpv which screen to display the video on."
[[settings]]
name = "osd-playing-msg"
file = "mpv"
width = 300
filter = "Screen"
type = "string"
help = "Show a message on OSD when playback starts. The string is expanded for properties, e.g. osd-playing-msg='file: ${filename}' will show the message file: followed by a space and the currently played filename. For more information visit:"
url = "https://mpv.io/manual/master/#property-expansion"
[[settings]]
name = "osd-font-size"
file = "mpv"
filter = "Screen"
help = "Specify the OSD font size. See sub-font-size for details. Default: 55"
[[settings]]
name = "osd-duration"
file = "mpv"
filter = "Screen"
help = "Set the duration of the OSD messages in ms. Default: 1000"
[[settings]]
name = "osd-scale-by-window"
file = "mpv"
default = "yes"
filter = "Screen"
help = "Whether to scale the OSD with the window size. If this is disabled, osd-font-size and other OSD options that use scaled pixels are always in actual pixels. The effect is that changing the window size won't change the OSD font size."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "autofit"
file = "mpv"
filter = "Screen"
help = "<int> Initial window height in percent. Default: 50"
[[settings]]
name = "autofit-smaller"
file = "mpv"
filter = "Screen"
help = "<int> Minimum window height in percent. Default: 30"
[[settings]]
name = "autofit-larger"
file = "mpv"
filter = "Screen"
help = "<int> Maximum window height in percent. Default: 80"
[[settings]]
name = "start-size"
file = "mpvnet"
default = "previous"
filter = "Screen"
help = "Setting to remember the window height. (mpv.net specific setting)"
options = [{ name = "video", help = "Window size is set to video resolution" },
{ name = "previous", help = "Window size is remembered but only in the current session" },
{ name = "always", help = "Window size is always remembered"}]
[[settings]]
name = "start-threshold"
file = "mpvnet"
filter = "Screen"
help = "Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. Default: 1500 (mpv.net specific setting)"
[[settings]]
name = "minimum-aspect-ratio"
file = "mpvnet"
filter = "Screen"
help = "<float> Minimum aspect ratio for the window. Default: 1.2 (mpv.net specific setting)"
[[settings]]
name = "remember-position"
file = "mpvnet"
default = "no"
filter = "Screen"
help = "Save the window position on exit. (mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "window-maximized"
file = "mpv"
default = "no"
filter = "Screen"
help = "Start with a maximized window."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "screenshot-directory"
file = "mpv"
width = 500
type = "folder"
filter = "Screen"
help = "Store screenshots in this directory. This path is joined with the filename generated by screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot."
[[settings]]
name = "screenshot-format"
file = "mpv"
default = "jpg"
filter = "Screen"
help = "Set the image file type used for saving screenshots."
options = [{ name = "jpg" },
{ name = "png" }]
[[settings]]
name = "screenshot-tag-colorspace"
file = "mpv"
default = "no"
filter = "Screen"
help = "Tag screenshots with the appropriate colorspace. Note that not all formats are supported."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "screenshot-high-bit-depth"
file = "mpv"
default = "yes"
filter = "Screen"
help = "If possible, write screenshots with a bit depth similar to the source video. This is interesting in particular for PNG, as this sometimes triggers writing 16 bit PNGs with huge file sizes. This will also include an unused alpha channel in the resulting files if 16 bit is used."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "screenshot-jpeg-source-chroma"
file = "mpv"
default = "yes"
filter = "Screen"
help = "Write JPEG files with the same chroma subsampling as the video. If disabled, the libjpeg default is used."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "screenshot-template"
file = "mpv"
filter = "Screen"
type = "string"
help = "Specify the filename template used to save screenshots. The template specifies the filename without file extension, and can contain format specifiers, which will be substituted when taking a screenshot. By default, the template is mpv-shot%n, which results in filenames like mpv-shot0012.png for example.\n\nFind the full documentation here:"
url = "https://mpv.io/manual/master/#options-screenshot-template"
[[settings]]
name = "screenshot-jpeg-quality"
file = "mpv"
filter = "Screen"
help = "<0-100> Set the JPEG quality level. Higher means better quality. The default is 90."
[[settings]]
name = "screenshot-png-compression"
file = "mpv"
filter = "Screen"
help = "<0-9> Set the PNG compression level. Higher means better compression. This will affect the file size of the written screenshot file and the time it takes to write a screenshot. Too high compression might occupy enough CPU time to interrupt playback. The default is 7."
[[settings]]
name = "screenshot-png-filter"
file = "mpv"
filter = "Screen"
help = "<0-5> Set the filter applied prior to PNG compression. 0 is none, 1 is 'sub', 2 is 'up', 3 is 'average', 4 is 'Paeth', and 5 is 'mixed'. This affects the level of compression that can be achieved. For most images, 'mixed' achieves the best compression ratio, hence it is the default."
[[settings]]
name = "taskbar-progress"
file = "mpv"
default = "yes"
filter = "Playback"
help = "Show progress in taskbar."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "keep-open-pause"
file = "mpv"
default = "yes"
filter = "Playback"
help = "If set to no, instead of pausing when keep-open is active, just stop at end of file and continue playing forward when you seek backwards until end where it stops again."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "keep-open"
file = "mpv"
default = "no"
filter = "Playback"
help = "Using no, mpv would terminate after the last file but mpv.net never terminates automatically."
options = [{ name = "yes", help = "If the current file ends, go to the next file, keep the last file open."},
{ name = "no", help = "If the current file ends, go to the next file." },
{ name = "always", help = "Playback will never automatically advance to the next file."}]
[[settings]]
name = "loop-file"
file = "mpv"
filter = "Playback"
help = "<N|inf|no> Loop a single file N times. inf means forever, no means normal playback.\n\nThe difference to loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file. loop is an alias for this option."
[[settings]]
name = "save-position-on-quit"
file = "mpv"
default = "no"
filter = "Playback"
help = "Always save the current playback position on quit. When this file is played again later, the player will seek to the old playback position on start. This does not happen if playback of a file is stopped in any other way than quitting. For example, going to the next file in the playlist will not save the position, and start playback at beginning the next time the file is played.\n\nThis behavior is disabled by default, but is always available when quitting the player with Shift+Q."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "hr-seek"
file = "mpv"
default = "absolute"
filter = "Playback"
help = "Select when to use precise seeks that are not limited to keyframes. Such seeks require decoding video from the previous keyframe up to the target position and so can take some time depending on decoding performance. For some video formats, precise seeks are disabled. This option selects the default choice to use for seeks; it is possible to explicitly override that default in the definition of key bindings and in input commands."
options = [{ name = "yes", help = "Use precise seeks whenever possible." },
{ name = "no", help = "Never use precise seeks." },
{ name = "absolute", help = "Use precise seeks if the seek is to an absolute position in the file, such as a chapter seek, but not for relative seeks like the default behavior of arrow keys." },
{ name = "always", help = "Same as yes (for compatibility)." }]
[[settings]]
name = "track-auto-selection"
file = "mpv"
default = "yes"
filter = "Playback"
help = "Enable the default track auto-selection. Enabling this will make the player select streams according to aid, alang, and others. If it is disabled, no tracks are selected. In addition, the player will not exit if no tracks are selected, and wait instead (this wait mode is similar to pausing, but the pause option is not set).\n\nThis is useful with lavfi-complex: you can start playback in this mode, and then set select tracks at runtime by setting the filter graph. Note that if lavfi-complex is set before playback is started, the referenced tracks are always selected."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "loop-playlist"
file = "mpv"
filter = "Playback"
help = "<N|inf|force|no> Loops playback N times. A value of 1 plays it one time (default), 2 two times, etc. inf means forever. no is the same as 1 and disables looping. If several files are specified on command line, the entire playlist is looped. The force mode is like inf, but does not skip playlist entries which have been marked as failing. This means the player might waste CPU time trying to loop a file that doesn't exist. But it might be useful for playing webradios under very bad network conditions."
[[settings]]
name = "auto-load-folder"
file = "mpvnet"
default = "yes"
filter = "Playback"
help = "For single files automatically load the entire directory into the playlist. Can be suppressed via shift key. (mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "input-ar-delay"
file = "mpv"
filter = "Input"
help = "Delay in milliseconds before we start to autorepeat a key (0 to disable)."
[[settings]]
name = "input-ar-rate"
file = "mpv"
filter = "Input"
help = "Number of key presses to generate per second on autorepeat."
[[settings]]
name = "update-check"
file = "mpvnet"
default = "no"
filter = "General"
help = "Daily check for new version. (requires PowerShell 5 and curl. mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "process-instance"
file = "mpvnet"
default = "single"
filter = "General"
help = "Defines if more then one mpv.net process is allowed. (mpv.net specific setting)\n\nTip: Whenever the control key is pressed when files or URLs are opened, the playlist is not cleared but the files or URLs are appended to the playlist. This not only works on process startup but in all mpv.net features that open files and URLs."
options = [{ name = "multi", help = "Create a new process everytime the shell starts mpv.net" },
{ name = "single", help = "Force a single process everytime the shell starts mpv.net" },
{ name = "queue", help = "Force a single process and add files to playlist" }]
[[settings]]
name = "recent-count"
file = "mpvnet"
filter = "General"
help = "<int> Amount of recent files to be remembered. Default: 15 (mpv.net specific setting)"
[[settings]]
name = "debug-mode"
file = "mpvnet"
default = "no"
filter = "General"
help = "Enable this only when a developer asks for it. (mpv.net specific setting)"
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "dark-mode"
file = "mpvnet"
default = "always"
filter = "UI"
help = "Enables a dark theme. (mpv.net specific setting)"
options = [{ name = "always" },
{ name = "system" , help = "Available on Windows 10 or higher" },
{ name = "never" }]
[[settings]]
name = "dark-theme"
file = "mpvnet"
filter = "UI"
url = "https://github.com/stax76/mpv.net/blob/master/Manual.md#color-theme"
help = "Color theme used in dark mode. Default: dark"
[[settings]]
name = "light-theme"
file = "mpvnet"
filter = "UI"
url = "https://github.com/stax76/mpv.net/blob/master/Manual.md#color-theme"
help = "Color theme used in light mode. Default: light"

View File

@@ -1,200 +0,0 @@
# This file defines the key and mouse bindings and the context menu
# of mpv.net. A input and config editor can be found in mpv.nets
# context menu under 'Settings'. The defaults of this file can be found at:
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
# The defaults of mpv can be found at:
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
# which disables mpv's input defaults. Every line in this file begins with a
# space character to make it easier to do a text search, so if you want to know
# if 'o' has already a binding you can do a text search on ' o '.
# mpv input commands: https://mpv.io/manual/master/#list-of-input-commands
# run mpv.net in input test mode with: mpvnet --input-test
o script-message mpv.net open-files #menu: Open > Open Files...
u script-message mpv.net open-url #menu: Open > Open URL or file path from clipboard
_ script-message mpv.net open-optical-media #menu: Open > Open DVD/Blu-ray Drive/Folder...
_ ignore #menu: Open > -
Alt+a script-message mpv.net load-audio #menu: Open > Load external audio files...
Alt+s script-message mpv.net load-sub #menu: Open > Load external subtitle files...
_ ignore #menu: Open > -
_ script-message mpv.net open-files append #menu: Open > Add files to playlist...
F3 script-message mpv.net show-media-search #menu: Open > Show media search...
_ ignore #menu: Open > -
_ ignore #menu: Open > Recent
_ ignore #menu: -
Space cycle pause #menu: Play/Pause
s stop #menu: Stop
_ ignore #menu: -
Enter cycle fullscreen #menu: Toggle Fullscreen
F11 playlist-prev #menu: Navigate > Previous File
F12 playlist-next #menu: Navigate > Next File
_ ignore #menu: Navigate > -
Home script-message mpv.net playlist-first #menu: Navigate > First File
End script-message mpv.net playlist-last #menu: Navigate > Last File
_ ignore #menu: Navigate > -
PGUP add chapter 1 #menu: Navigate > Next Chapter
PGDWN add chapter -1 #menu: Navigate > Previous Chapter
_ ignore #menu: Navigate > -
. frame-step #menu: Navigate > Jump Next Frame
, frame-back-step #menu: Navigate > Jump Previous Frame
_ ignore #menu: Navigate > -
Right seek 7 #menu: Navigate > Jump 7 sec forward
Left seek -7 #menu: Navigate > Jump 7 sec backward
_ ignore #menu: Navigate > -
Up seek 40 #menu: Navigate > Jump 40 sec forward
Down seek -40 #menu: Navigate > Jump 40 sec backward
_ ignore #menu: Navigate > -
Ctrl+Right seek 300 #menu: Navigate > Jump 5 min forward
Ctrl+Left seek -300 #menu: Navigate > Jump 5 min backward
_ ignore #menu: Navigate > -
_ ignore #menu: Navigate > Chapters
Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size
Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size
_ ignore #menu: Pan & Scan > -
Ctrl+KP4 add video-pan-x -0.01 #menu: Pan & Scan > Move Left
Ctrl+KP6 add video-pan-x 0.01 #menu: Pan & Scan > Move Right
_ ignore #menu: Pan & Scan > -
Ctrl+KP8 add video-pan-y -0.01 #menu: Pan & Scan > Move Up
Ctrl+KP2 add video-pan-y 0.01 #menu: Pan & Scan > Move Down
_ ignore #menu: Pan & Scan > -
w add panscan -0.1 #menu: Pan & Scan > Decrease Height
W add panscan 0.1 #menu: Pan & Scan > Increase Height
_ ignore #menu: Pan & Scan > -
Ctrl+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0 #menu: Pan & Scan > Reset
Ctrl+1 add contrast -1 #menu: Video > Decrease Contrast
Ctrl+2 add contrast 1 #menu: Video > Increase Contrast
_ ignore #menu: Video > -
Ctrl+3 add brightness -1 #menu: Video > Decrease Brightness
Ctrl+4 add brightness 1 #menu: Video > Increase Brightness
_ ignore #menu: Video > -
Ctrl+5 add gamma -1 #menu: Video > Decrease Gamma
Ctrl+6 add gamma 1 #menu: Video > Increase Gamma
_ ignore #menu: Video > -
Ctrl+7 add saturation -1 #menu: Video > Decrease Saturation
Ctrl+8 add saturation 1 #menu: Video > Increase Saturation
_ ignore #menu: Video > -
Ctrl+s async screenshot #menu: Video > Take Screenshot
d cycle deinterlace #menu: Video > Toggle Deinterlace
a cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1" #menu: Video > Cycle Aspect Ratio
KP7 script-message mpv.net cycle-audio #menu: Audio > Cycle/Next
_ ignore #menu: Audio > -
KP6 add audio-delay 0.1 #menu: Audio > Delay +0.1
KP9 add audio-delay -0.1 #menu: Audio > Delay -0.1
KP8 cycle sub #menu: Subtitle > Cycle/Next
v cycle sub-visibility #menu: Subtitle > Toggle Visibility
_ ignore #menu: Subtitle > -
z add sub-delay -0.1 #menu: Subtitle > Delay -0.1
Z add sub-delay 0.1 #menu: Subtitle > Delay +0.1
_ ignore #menu: Subtitle > -
r add sub-pos -1 #menu: Subtitle > Move Up
R add sub-pos +1 #menu: Subtitle > Move Down
_ ignore #menu: Subtitle > -
_ add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size
_ add sub-scale 0.1 #menu: Subtitle > Increase Subtitle Font Size
_ ignore #menu: Track
+ add volume 10 #menu: Volume > Up
- add volume -10 #menu: Volume > Down
_ ignore #menu: Volume > -
m cycle mute #menu: Volume > Mute
[ multiply speed 1/1.1 #menu: Speed > -10%
] multiply speed 1.1 #menu: Speed > +10%
_ ignore #menu: Speed > -
{ multiply speed 0.5 #menu: Speed > Half
} multiply speed 2.0 #menu: Speed > Double
_ ignore #menu: Speed > -
BS set speed 1 #menu: Speed > Reset
KP0 script-message rate-file 0 #menu: Extensions > Rating > 0stars
KP1 script-message rate-file 1 #menu: Extensions > Rating > 1stars
KP2 script-message rate-file 2 #menu: Extensions > Rating > 2stars
KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
_ ignore #menu: Extensions > Rating > -
_ script-message rate-file about #menu: Extensions > Rating > About
Ctrl+t set ontop yes #menu: View > On Top > Enable
Ctrl+T set ontop no #menu: View > On Top > Disable
Alt++ no-osd set window-scale 1.2 #menu: View > Window Size > Enlarge
Alt+- no-osd set window-scale 0.8 #menu: View > Window Size > Shrink
b cycle border #menu: View > Toggle Border
i script-message mpv.net show-info #menu: View > File/Stream Info
t script-binding stats/display-stats #menu: View > Show Statistics
T script-binding stats/display-stats-toggle #menu: View > Toggle Statistics
Del script-binding osc/visibility #menu: View > Toggle OSC Visibility
F8 script-binding show-playlist #menu: View > Show Playlist
F9 show-text ${track-list} 5000 #menu: View > Show Audio/Video/Subtitle List
p show-progress #menu: View > Show Progress
Ctrl+p script-message mpv.net show-profiles #menu: View > Show Profiles
Shift+p script-message mpv.net show-properties #menu: View > Show Properties
Shift+c script-message mpv.net show-commands #menu: View > Show Commands
` script-binding console/enable #menu: View > Show Console
c script-message mpv.net show-conf-editor #menu: Settings > Show Config Editor
Ctrl+i script-message mpv.net show-input-editor #menu: Settings > Show Input Editor
Ctrl+f script-message mpv.net open-conf-folder #menu: Settings > Open Config Folder
F1 script-message mpv.net show-command-palette #menu: Tools > Show All Commands
h script-message mpv.net show-history #menu: Tools > Show History
l ab-loop #menu: Tools > Set/clear A-B loop points
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping
_ cycle shuffle #menu: Tools > Toggle Shuffle
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Toggle Hardware Decoding
_ script-message mpv.net show-setup-dialog #menu: Tools > Setup...
_ script-message mpv.net shell-execute https://mpv.io #menu: Help > Website mpv
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net #menu: Help > Website mpv.net
_ ignore #menu: Help > -
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Manual mpv
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/Manual.md #menu: Help > Manual mpv.net
_ ignore #menu: Help > -
_ script-message mpv.net update-check #menu: Help > Check for Updates
_ script-message mpv.net show-about #menu: Help > About mpv.net
_ ignore #menu: -
Esc quit #menu: Exit
Q quit-watch-later #menu: Exit Watch Later
Power quit
Play cycle pause
Pause cycle pause
PlayPause cycle pause
MBTN_Mid cycle pause
Stop stop
Forward seek 60
Rewind seek -60
Mute cycle mute
Volume_Up add volume 10
Volume_Down add volume -10
Wheel_Up add volume 10
Wheel_Down add volume -10
Wheel_Left add volume -10
Wheel_Right add volume 10
Prev playlist-prev
Next playlist-next
MBTN_Forward playlist-next
MBTN_Back playlist-prev
> playlist-next
< playlist-prev
Ctrl+Wheel_Up no-osd seek 7
Ctrl+Wheel_Down no-osd seek -7
MBTN_Left_DBL cycle fullscreen
KP_Enter cycle fullscreen

View File

@@ -1,14 +0,0 @@
input-default-bindings = no
input-ar-delay = 500
input-ar-rate = 20
keep-open = yes
keep-open-pause = no
osd-duration = 2000
osd-playing-msg = '${filename}'
script-opts = osc-scalewindowed=1.5,osc-hidetimeout=2000,console-scale=1
screenshot-directory = '~~desktop/'
hwdec = yes
[protocol.https]
osd-playing-msg = '${media-title}'

View File

@@ -1,61 +0,0 @@

using System;
using System.IO;
using System.Reflection;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
using IronPython.Runtime;
using IronPython.Runtime.Operations;
namespace mpvnet
{
public class PythonScript
{
ScriptEngine engine;
ScriptScope scope;
public PythonScript(string scriptPath)
{
try
{
engine = Python.CreateEngine();
scope = engine.CreateScope();
scope.ImportModule("clr");
engine.Execute("import clr", scope);
engine.Execute("clr.AddReference(\"mpvnet\")", scope);
engine.Execute("import mpvnet", scope);
engine.Execute("from mpvnet import *", scope);
engine.Execute(File.ReadAllText(scriptPath), scope);
}
catch (Exception ex)
{
if (ex is SyntaxErrorException e)
Msg.ShowError(e.GetType().Name,$"{e.Line}, {e.Column}: " + e.Message + "\n\n" + Path.GetFileName(scriptPath));
else
Msg.ShowError(ex.GetType().Name, ex.Message + "\n\n" + Path.GetFileName(scriptPath));
}
}
}
public class PythonEventObject
{
public PythonFunction PythonFunction { get; set; }
public EventInfo EventInfo { get; set; }
public Delegate Delegate { get; set; }
public void Invoke() => PythonCalls.Call(PythonFunction);
public void InvokeEndFileEventMode(EndFileEventMode arg)
{
PythonCalls.Call(PythonFunction, new[] { arg });
}
public void InvokeStrings(string[] arg)
{
PythonCalls.Call(PythonFunction, new[] { arg });
}
}
}

View File

@@ -1,123 +0,0 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Threading;
namespace ScriptHost
{
public class PowerShell
{
public Runspace Runspace { get; set; }
public Pipeline Pipeline { get; set; }
public string Module { get; set; }
public bool Print { get; set; }
public List<string> Scripts { get; } = new List<string>();
public string[] Parameters { get; }
public static List<PowerShell> Instances { get; } = new List<PowerShell>();
string NL = Environment.NewLine;
public object Invoke() => Invoke(null, null);
public object Invoke(string variable, object obj)
{
try
{
Runspace = RunspaceFactory.CreateRunspace();
Runspace.ApartmentState = ApartmentState.STA;
Runspace.Open();
Pipeline = Runspace.CreatePipeline();
foreach (string script in Scripts)
Pipeline.Commands.AddScript(script);
if (Parameters != null)
foreach (string param in Parameters)
foreach (Command command in Pipeline.Commands)
command.Parameters.Add(null, param);
Runspace.SessionStateProxy.SetVariable("ScriptHost", this);
if (!string.IsNullOrEmpty(variable))
Runspace.SessionStateProxy.SetVariable(variable, obj);
if (Print)
{
Pipeline.Output.DataReady += Output_DataReady;
Pipeline.Error.DataReady += Error_DataReady;
}
return Pipeline.Invoke();
}
catch (RuntimeException e)
{
string message = e.Message + NL + NL + e.ErrorRecord.ScriptStackTrace.Replace(
" <ScriptBlock>, <No file>", "") + NL + NL + Module + NL;
throw new PowerShellException(message);
}
catch (Exception e)
{
throw e;
}
}
public static string InvokeAndReturnString(string code, string varName, object varValue)
{
PowerShell ps = new PowerShell() { Print = false };
ps.Scripts.Add(code);
string ret = string.Join(Environment.NewLine, (ps.Invoke(varName, varValue)
as IEnumerable<object>).Select(item => item.ToString())).ToString();
ps.Runspace.Dispose();
return ret;
}
public void Output_DataReady(object sender, EventArgs e)
{
var output = sender as PipelineReader<PSObject>;
while (output.Count > 0)
ConsoleHelp.Write(output.Read(), Module);
}
public void Error_DataReady(object sender, EventArgs e)
{
var output = sender as PipelineReader<Object>;
while (output.Count > 0)
ConsoleHelp.WriteError(output.Read(), Module);
}
public void RedirectEventJobStreams(PSEventJob job)
{
if (Print)
{
job.Output.DataAdded += Output_DataAdded;
job.Error.DataAdded += Error_DataAdded;
}
}
void Output_DataAdded(object sender, DataAddedEventArgs e)
{
var output = sender as PSDataCollection<PSObject>;
ConsoleHelp.Write(output[e.Index], Module);
}
void Error_DataAdded(object sender, DataAddedEventArgs e)
{
var error = sender as PSDataCollection<ErrorRecord>;
ConsoleHelp.WriteError(error[e.Index], Module);
}
}
public class PowerShellException : Exception
{
public PowerShellException(string message) : base(message)
{
}
}
}

View File

@@ -1,23 +0,0 @@
$ErrorActionPreference = 'Stop'
$targetDir = (Split-Path $args[1]) + "\new version"
$targetFile = $targetDir + '.7z'
Write-Host 'Download new version' -ForegroundColor Green
curl.exe $args[0] --location --output $targetFile
if ($LastExitCode) { throw $LastExitCode }
Write-Host 'Unpack new version' -ForegroundColor Green
& ($args[1] + '\7z\7za.exe') x -y $targetFile -o"$targetDir"
if ($LastExitCode) { throw $LastExitCode }
Write-Host 'Delete downloaded file' -ForegroundColor Green
Remove-Item $targetFile -Force -Recurse
Write-Host 'Delete current version' -ForegroundColor Green
Remove-Item $args[1] -Force -Recurse
Write-Host 'Rename directory' -ForegroundColor Green
Rename-Item $targetDir (Split-Path $args[1] -Leaf)
Write-Host 'Update is complete' -ForegroundColor Green

View File

@@ -1,28 +0,0 @@
<Window x:Class="mpvnet.AboutWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:UI="clr-namespace:UI"
mc:Ignorable="d"
Title="About mpv.net"
Height="230"
Width="400"
FontSize="16"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
ResizeMode="NoResize"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="48" HorizontalAlignment="Center" Margin="0,0,0,10">mpv.net</TextBlock>
<TextBlock HorizontalAlignment="Center">Copyright (C) 2017-2020 Frank Skare (stax76)</TextBlock>
<TextBlock Name="Version" HorizontalAlignment="Center" />
<TextBlock Name="mpvVersion" HorizontalAlignment="Center" />
<TextBlock HorizontalAlignment="Center" Margin="0,0,0,20">MIT License</TextBlock>
</StackPanel>
</Grid>
</Window>

View File

@@ -1,59 +0,0 @@
<Window x:Class="mpvnet.CommandPaletteWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:UI="clr-namespace:UI"
mc:Ignorable="d"
Title="Command Palette"
Height="295"
Width="400"
FontSize="13"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBox Name="FilterTextBox"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
PreviewKeyDown="FilterTextBox_PreviewKeyDown"
TextChanged="FilterTextBox_TextChanged"/>
<ListView Name="ListView"
Grid.Row="1"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
MouseUp="ListView_MouseUp">
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path}"></TextBlock>
<TextBlock Grid.Column="1"
Text="{Binding Input}"
HorizontalAlignment="Right"></TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>

View File

@@ -1,124 +0,0 @@

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interop;
namespace mpvnet
{
public partial class CommandPaletteWindow : Window
{
ICollectionView CollectionView;
public CommandPaletteWindow()
{
InitializeComponent();
CollectionViewSource collectionViewSource = new CollectionViewSource() { Source = CommandItem.Items };
CollectionView = collectionViewSource.View;
var yourCostumFilter = new Predicate<object>(item => Filter((CommandItem)item));
CollectionView.Filter = yourCostumFilter;
ListView.ItemsSource = CollectionView;
}
bool Filter(CommandItem item)
{
if (item.Command == "" || item.Path == "")
return false;
string filter = FilterTextBox.Text.ToLower();
if (filter == "")
return true;
if (item.Command.ToLower().Contains(filter) ||
item.Input.ToLower().Contains(filter) ||
item.Path.ToLower().Contains(filter))
return true;
return false;
}
void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
Keyboard.Focus(FilterTextBox);
SelectFirst();
}
void SelectFirst()
{
if (ListView.Items.Count > 0)
ListView.SelectedIndex = 0;
}
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x200 /*WM_MOUSEMOVE*/ && Mouse.LeftButton != MouseButtonState.Pressed)
handled = true;
return IntPtr.Zero;
}
void FilterTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
{
int index = ListView.SelectedIndex;
index -= 1;
if (index < 0)
index = 0;
ListView.SelectedIndex = index;
ListView.ScrollIntoView(ListView.SelectedItem);
}
break;
case Key.Down:
{
int index = ListView.SelectedIndex;
index += 1;
if (index > ListView.Items.Count - 1)
index = ListView.Items.Count - 1;
ListView.SelectedIndex = index;
ListView.ScrollIntoView(ListView.SelectedItem);
}
break;
case Key.Escape:
Close();
break;
case Key.Enter:
Execute();
break;
}
}
void Execute()
{
if (ListView.SelectedItem != null)
{
CommandItem item = ListView.SelectedItem as CommandItem;
Close();
mp.command(item.Command);
}
}
void ListView_MouseUp(object sender, MouseButtonEventArgs e)
{
Execute();
}
void FilterTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
CollectionView.Refresh();
SelectFirst();
}
}
}

View File

@@ -1,66 +0,0 @@
<Window xmlns:Controls="clr-namespace:Controls" x:Name="ConfWindow1" x:Class="mpvnet.ConfWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:UI="clr-namespace:UI"
mc:Ignorable="d"
Title="Config Editor"
Height="530"
Width="700"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
ShowInTaskbar="False"
WindowStartupLocation="CenterScreen"
Loaded="ConfWindow1_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Controls:SearchTextBoxUserControl
x:Name="SearchControl"
HintText="Find a setting"
Width="250"
Margin="0,20,0,0"
Grid.ColumnSpan="2"/>
<ScrollViewer Name="MainScrollViewer"
VerticalScrollBarVisibility="Auto"
Grid.Row="1"
Grid.Column="2"
Margin="0,0,0,10">
<StackPanel x:Name="MainStackPanel"></StackPanel>
</ScrollViewer>
<StackPanel Margin="20,0,0,0" Grid.Row="1">
<ListBox Name="FilterListBox"
ItemsSource="{Binding FilterStrings}"
BorderThickness="0"
SelectionChanged="FilterListBox_SelectionChanged"
Foreground="{x:Static UI:Theme.Heading}"
Background="{x:Static UI:Theme.Background}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="16" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Name="OpenSettingsTextBlock" Margin="0,30,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static UI:Theme.Heading}" MouseUp="OpenSettingsTextBlock_MouseUp">Open config folder</TextBlock>
<TextBlock Name="PreviewTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static UI:Theme.Heading}" MouseUp="PreviewTextBlock_MouseUp">Preview mpv.conf</TextBlock>
<TextBlock Name="ShowManualTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static UI:Theme.Heading}" MouseUp="ShowManualTextBlock_MouseUp">Show mpv manual</TextBlock>
<TextBlock Name="SupportTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static UI:Theme.Heading}" MouseUp="SupportTextBlock_MouseUp">Show support forum</TextBlock>
</StackPanel>
</Grid>
</Window>

View File

@@ -1,44 +0,0 @@
<Window x:Class="mpvnet.EverythingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:UI="clr-namespace:UI"
mc:Ignorable="d"
Title="Media File Search"
FontSize="13"
Height="300"
Width="600"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBox Name="FilterTextBox"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
PreviewKeyDown="FilterTextBox_PreviewKeyDown"
TextChanged="FilterTextBox_TextChanged"/>
<ListView Name="ListView"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
Grid.Row="1"
MouseUp="ListView_MouseUp"
PreviewKeyDown="ListView_PreviewKeyDown">
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</Window>

View File

@@ -1,162 +0,0 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
namespace mpvnet
{
public partial class EverythingWindow : Window
{
public EverythingWindow()
{
InitializeComponent();
}
const int EVERYTHING_REQUEST_FILE_NAME = 0x00000001;
const int EVERYTHING_REQUEST_PATH = 0x00000002;
[DllImport("Everything.dll", CharSet = CharSet.Unicode)]
public static extern int Everything_SetSearch(string lpSearchString);
[DllImport("Everything.dll")]
public static extern void Everything_SetRequestFlags(UInt32 dwRequestFlags);
[DllImport("Everything.dll")]
public static extern void Everything_SetSort(UInt32 dwSortType);
[DllImport("Everything.dll", CharSet = CharSet.Unicode)]
public static extern bool Everything_Query(bool bWait);
[DllImport("Everything.dll", CharSet = CharSet.Unicode)]
public static extern void Everything_GetResultFullPathName(UInt32 nIndex, StringBuilder lpString, UInt32 nMaxCount);
[DllImport("Everything.dll")]
public static extern bool Everything_GetResultSize(UInt32 nIndex, out long lpFileSize);
[DllImport("Everything.dll")]
public static extern UInt32 Everything_GetNumResults();
void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
Keyboard.Focus(FilterTextBox);
}
void SelectFirst()
{
if (ListView.Items.Count > 0)
ListView.SelectedIndex = 0;
}
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x200 /*WM_MOUSEMOVE*/ && Mouse.LeftButton != MouseButtonState.Pressed)
handled = true;
return IntPtr.Zero;
}
void FilterTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
{
int index = ListView.SelectedIndex;
index -= 1;
if (index < 0) index = 0;
ListView.SelectedIndex = index;
ListView.ScrollIntoView(ListView.SelectedItem);
}
break;
case Key.Down:
{
int index = ListView.SelectedIndex;
index += 1;
if (index > ListView.Items.Count - 1) index = ListView.Items.Count - 1;
ListView.SelectedIndex = index;
ListView.ScrollIntoView(ListView.SelectedItem);
}
break;
case Key.Escape: Close(); break;
case Key.Enter: Execute(); break;
}
}
void ListView_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
Close();
if (e.Key == Key.Enter)
Execute();
}
void Execute()
{
if (ListView.SelectedItem != null)
mp.LoadFiles(new[] { ListView.SelectedItem as string }, true, Keyboard.Modifiers == ModifierKeys.Control);
Keyboard.Focus(FilterTextBox);
}
void ListView_MouseUp(object sender, MouseButtonEventArgs e) => Execute();
void FilterTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
string searchtext = FilterTextBox.Text;
Task.Run(() => Search(searchtext));
}
object LockObject = new object();
void Search(string searchtext)
{
lock (LockObject)
{
try
{
List<string> items = new List<string>();
UInt32 i;
const int bufsize = 500;
StringBuilder buf = new StringBuilder(bufsize);
Everything_SetSearch(searchtext);
Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH);
Everything_Query(true);
for (i = 0; i < Everything_GetNumResults(); i++)
{
Everything_GetResultFullPathName(i, buf, bufsize);
string ext = buf.ToString().ShortExt();
if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext)
|| App.ImageTypes.Contains(ext))
items.Add(buf.ToString());
if (items.Count > 100)
break;
}
Application.Current.Dispatcher.Invoke(() => {
ListView.ItemsSource = items;
SelectFirst();
});
}
catch (Exception)
{
Msg.ShowError("Search query failed.",
"The search feature depends on [Everything](https://www.voidtools.com) being installed.");
}
}
}
}
}

View File

@@ -1,70 +0,0 @@
<Window xmlns:Controls="clr-namespace:Controls" x:Class="mpvnet.InputWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:UI="clr-namespace:UI"
mc:Ignorable="d"
Title="Input Editor"
Height="500"
Width="750"
FontSize="13"
ShowInTaskbar="False"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
Loaded="Window_Loaded"
Closed="Window_Closed">
<Window.Resources>
<Style x:Key="DataGrid_Font_Centering" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Controls:SearchTextBoxUserControl
HintText="Type ? to get help."
x:Name="SearchControl"
Width="300"
Margin="0,20,0,20"
Grid.ColumnSpan="2" />
<DataGrid x:Name="DataGrid"
Grid.Row="1"
CommandManager.PreviewCanExecute="DataGrid_PreviewCanExecute"
AutoGenerateColumns="False"
CellStyle="{StaticResource DataGrid_Font_Centering}" >
<DataGrid.Columns>
<DataGridTextColumn Header="Menu" Binding="{Binding Path}"/>
<DataGridTemplateColumn Header="Input">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button MinHeight="20" Click="ButtonClick">
<TextBlock Text="{Binding Input}"></TextBlock>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Command" Binding="{Binding Command}" MaxWidth="330" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>

View File

@@ -1,50 +0,0 @@
<Window x:Class="mpvnet.LearnWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:UI="clr-namespace:UI"
mc:Ignorable="d"
Title="Learn Input"
Height="200"
Width="400"
WindowStartupLocation="CenterOwner"
ResizeMode="NoResize"
Loaded="Window_Loaded"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
MouseWheel="Window_MouseWheel"
MouseUp="Window_MouseUp"
MouseDoubleClick="Window_MouseDoubleClick"
TextInput="Window_TextInput">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="MenuTextBlock"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontSize="16"></TextBlock>
<TextBlock x:Name="KeyTextBlock"
Grid.Row="1"
Grid.ColumnSpan="2"
VerticalAlignment="Top"
HorizontalAlignment="Center"
FontSize="16" />
<Button x:Name="ConfirmButton" Grid.Row="2" Click="ConfirmButton_Click">Confirm</Button>
<Button x:Name="ClearButton" Grid.Row="2" Click="ClearButton_Click" Grid.Column="1">Clear</Button>
</Grid>
</Window>

View File

@@ -1,388 +0,0 @@

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using WinForms = System.Windows.Forms;
namespace mpvnet
{
public partial class LearnWindow : Window
{
public CommandItem InputItem { get; set; }
string NewKey = "";
string KeyChar = "";
public LearnWindow() => InitializeComponent();
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
WinForms.Message m = new WinForms.Message();
m.HWnd = hwnd;
m.Msg = msg;
m.WParam = wParam;
m.LParam = lParam;
ProcessKeyEventArgs(ref m);
return m.Result;
}
void OnKeyUp(WinForms.KeyEventArgs e)
{
if (e.KeyCode == WinForms.Keys.ControlKey || e.KeyCode == WinForms.Keys.ShiftKey ||
e.KeyCode == WinForms.Keys.Menu || e.KeyCode == WinForms.Keys.None)
return;
string text = "";
uint charValue = MapVirtualKey((uint)e.KeyCode, 2);
if (charValue == 0 || (charValue & 1 << 31) == 1 << 31)
text = e.KeyCode.ToString().Trim();
else
try {
text = Convert.ToChar(charValue).ToString().ToLower().Trim();
} catch {}
for (int i = 0; i < 13; i++)
if ("D" + i == text)
text = text.Substring(1);
switch (e.KeyCode)
{
case WinForms.Keys.NumPad0:
case WinForms.Keys.NumPad1:
case WinForms.Keys.NumPad2:
case WinForms.Keys.NumPad3:
case WinForms.Keys.NumPad4:
case WinForms.Keys.NumPad5:
case WinForms.Keys.NumPad6:
case WinForms.Keys.NumPad7:
case WinForms.Keys.NumPad8:
case WinForms.Keys.NumPad9:
text = "KP" + e.KeyCode.ToString()[6]; break;
case WinForms.Keys.Space:
text = "Space"; break;
case WinForms.Keys.Enter:
text = "Enter"; break;
case WinForms.Keys.Tab:
text = "TAB"; break;
case WinForms.Keys.Back:
text = "BS"; break;
case WinForms.Keys.Delete:
text = "DEL"; break;
case WinForms.Keys.Insert:
text = "INS"; break;
case WinForms.Keys.Home:
text = "Home"; break;
case WinForms.Keys.End:
text = "END"; break;
case WinForms.Keys.PageUp:
text = "PGUP"; break;
case WinForms.Keys.PageDown:
text = "PGDWN"; break;
case WinForms.Keys.Escape:
text = "ESC"; break;
case WinForms.Keys.PrintScreen:
text = "Print"; break;
case WinForms.Keys.Play:
text = "Play"; break;
case WinForms.Keys.Pause:
text = "Pause"; break;
case WinForms.Keys.MediaPlayPause:
text = "PlayPause"; break;
case WinForms.Keys.MediaStop:
text = "Stop"; break;
case WinForms.Keys.MediaNextTrack:
text = "Next"; break;
case WinForms.Keys.MediaPreviousTrack:
text = "Prev"; break;
case WinForms.Keys.VolumeUp:
text = "Volume_Up"; break;
case WinForms.Keys.VolumeDown:
text = "Volume_Down"; break;
case WinForms.Keys.VolumeMute:
text = "Mute"; break;
case WinForms.Keys.BrowserHome:
text = "Homepage"; break;
case WinForms.Keys.LaunchMail:
text = "Mail"; break;
case WinForms.Keys.BrowserFavorites:
text = "Favorites"; break;
case WinForms.Keys.BrowserSearch:
text = "Search"; break;
case WinForms.Keys.Sleep:
text = "Sleep"; break;
case WinForms.Keys.Cancel:
text = "Cancel"; break;
}
bool wasModified = false;
bool isAlt = GetKeyState(18) < (short)0;
bool isShift = GetKeyState(16) < (short)0;
bool isCtrl = GetKeyState(17) < (short)0;
if (text.Length == 1 && KeyChar != text)
{
text = KeyChar;
wasModified = true;
}
if (text == "#") text = "SHARP";
if (isAlt && !wasModified)
text = "ALT+" + text;
if (isShift && !wasModified)
text = "SHIFT+" + text;
if (isCtrl && !wasModified)
text = "CTRL+" + text;
if (!string.IsNullOrEmpty(text))
SetKey(text);
}
DateTime LastKeyUp;
void SetKey(string key)
{
NewKey = key;
MenuTextBlock.Text = InputItem.Path;
KeyTextBlock.Text = key;
LastKeyUp = DateTime.Now;
}
[DllImport("user32.dll")]
static extern uint MapVirtualKey(uint uCode, uint uMapType);
public static WinForms.Keys ModifierKeys {
get {
WinForms.Keys keys = WinForms.Keys.None;
if (GetKeyState(17) < (short)0)
keys |= WinForms.Keys.Control;
if (GetKeyState(16) < (short)0)
keys |= WinForms.Keys.Shift;
if (GetKeyState(18) < (short)0)
keys |= WinForms.Keys.Alt;
return keys;
}
}
void ProcessKeyEventArgs(ref WinForms.Message m)
{
int WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319;
if (m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP)
OnKeyUp(new WinForms.KeyEventArgs((WinForms.Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys));
else if (m.Msg == WM_APPCOMMAND)
{
if (!mp.get_property_bool("input-media-keys"))
return;
var value = (AppCommand)(m.LParam.ToInt64() >> 16 & ~0xf000);
switch (value)
{
case AppCommand.APPCOMMAND_MEDIA_CHANNEL_DOWN:
SetKey("CHANNEL_DOWN");
break;
case AppCommand.APPCOMMAND_MEDIA_CHANNEL_UP:
SetKey("CHANNEL_UP");
break;
case AppCommand.APPCOMMAND_MEDIA_FAST_FORWARD:
SetKey("FORWARD");
break;
case AppCommand.APPCOMMAND_MEDIA_REWIND:
SetKey("REWIND");
break;
case AppCommand.APPCOMMAND_MEDIA_PAUSE:
SetKey("PAUSE");
break;
case AppCommand.APPCOMMAND_MEDIA_PLAY:
SetKey("PLAY");
break;
case AppCommand.APPCOMMAND_MEDIA_PLAY_PAUSE:
SetKey("PLAYPAUSE");
break;
case AppCommand.APPCOMMAND_MEDIA_NEXTTRACK:
SetKey("NEXT");
break;
case AppCommand.APPCOMMAND_MEDIA_PREVIOUSTRACK:
SetKey("PREV");
break;
case AppCommand.APPCOMMAND_MEDIA_RECORD:
SetKey("RECORD");
break;
case AppCommand.APPCOMMAND_MEDIA_STOP:
SetKey("STOP");
break;
case AppCommand.APPCOMMAND_VOLUME_UP:
SetKey("VOLUME_UP");
break;
case AppCommand.APPCOMMAND_VOLUME_DOWN:
SetKey("VOLUME_DOWN");
break;
case AppCommand.APPCOMMAND_VOLUME_MUTE:
SetKey("MUTE");
break;
case AppCommand.APPCOMMAND_BROWSER_HOME:
SetKey("HOMEPAGE");
break;
case AppCommand.APPCOMMAND_LAUNCH_MAIL:
SetKey("MAIL");
break;
case AppCommand.APPCOMMAND_BROWSER_FAVORITES:
SetKey("FAVORITES");
break;
case AppCommand.APPCOMMAND_BROWSER_SEARCH:
SetKey("SEARCH");
break;
case AppCommand.APPCOMMAND_PRINT:
SetKey("PRINT");
break;
}
}
}
internal enum AppCommand
{
APPCOMMAND_BASS_BOOST = 20,
APPCOMMAND_BASS_DOWN = 19,
APPCOMMAND_BASS_UP = 21,
APPCOMMAND_BROWSER_BACKWARD = 1,
APPCOMMAND_BROWSER_FAVORITES = 6,
APPCOMMAND_BROWSER_FORWARD = 2,
APPCOMMAND_BROWSER_HOME = 7,
APPCOMMAND_BROWSER_REFRESH = 3,
APPCOMMAND_BROWSER_SEARCH = 5,
APPCOMMAND_BROWSER_STOP = 4,
APPCOMMAND_CLOSE = 31,
APPCOMMAND_COPY = 36,
APPCOMMAND_CORRECTION_LIST = 45,
APPCOMMAND_CUT = 37,
APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE = 43,
APPCOMMAND_FIND = 28,
APPCOMMAND_FORWARD_MAIL = 40,
APPCOMMAND_HELP = 27,
APPCOMMAND_LAUNCH_APP1 = 17,
APPCOMMAND_LAUNCH_APP2 = 18,
APPCOMMAND_LAUNCH_MAIL = 15,
APPCOMMAND_LAUNCH_MEDIA_SELECT = 16,
APPCOMMAND_MEDIA_CHANNEL_DOWN = 52,
APPCOMMAND_MEDIA_CHANNEL_UP = 51,
APPCOMMAND_MEDIA_FAST_FORWARD = 49,
APPCOMMAND_MEDIA_NEXTTRACK = 11,
APPCOMMAND_MEDIA_PAUSE = 47,
APPCOMMAND_MEDIA_PLAY = 46,
APPCOMMAND_MEDIA_PLAY_PAUSE = 14,
APPCOMMAND_MEDIA_PREVIOUSTRACK = 12,
APPCOMMAND_MEDIA_RECORD = 48,
APPCOMMAND_MEDIA_REWIND = 50,
APPCOMMAND_MEDIA_STOP = 13,
APPCOMMAND_MIC_ON_OFF_TOGGLE = 44,
APPCOMMAND_MICROPHONE_VOLUME_DOWN = 25,
APPCOMMAND_MICROPHONE_VOLUME_MUTE = 24,
APPCOMMAND_MICROPHONE_VOLUME_UP = 26,
APPCOMMAND_NEW = 29,
APPCOMMAND_OPEN = 30,
APPCOMMAND_PASTE = 38,
APPCOMMAND_PRINT = 33,
APPCOMMAND_REDO = 35,
APPCOMMAND_REPLY_TO_MAIL = 39,
APPCOMMAND_SAVE = 32,
APPCOMMAND_SEND_MAIL = 41,
APPCOMMAND_SPELL_CHECK = 42,
APPCOMMAND_TREBLE_DOWN = 22,
APPCOMMAND_TREBLE_UP = 23,
APPCOMMAND_UNDO = 34,
APPCOMMAND_VOLUME_DOWN = 9,
APPCOMMAND_VOLUME_MUTE = 8,
APPCOMMAND_VOLUME_UP = 10
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern short GetKeyState(int keyCode);
[DllImport("user32.dll")]
static extern short VkKeyScan(char c);
[DllImport("user32.dll", SetLastError = true)]
static extern int ToAscii(uint uVirtKey,
uint uScanCode,
byte[] lpKeyState,
out uint lpChar,
uint flags);
void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
SetKey(InputItem.Input);
}
void ConfirmButton_Click(object sender, RoutedEventArgs e)
{
InputItem.Input = NewKey;
Close();
}
void ClearButton_Click(object sender, RoutedEventArgs e)
{
InputItem.Input = "_";
Close();
}
void Window_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
SetKey("WHEEL_UP");
else
SetKey("WHEEL_DOWN");
}
void Window_MouseUp(object sender, MouseButtonEventArgs e)
{
switch (e.ChangedButton)
{
case MouseButton.Left:
if (BlockMBTN_LEFT)
BlockMBTN_LEFT = false;
else
SetKey("MBTN_LEFT");
break;
case MouseButton.Middle:
SetKey("MBTN_MID");
break;
case MouseButton.XButton1:
SetKey("MBTN_BACK");
break;
case MouseButton.XButton2:
SetKey("MBTN_FORWARD");
break;
}
}
bool BlockMBTN_LEFT;
void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
SetKey("MBTN_LEFT_DBL");
BlockMBTN_LEFT = true;
}
}
void Window_TextInput(object sender, TextCompositionEventArgs e)
{
KeyChar = e.Text;
}
}
}

View File

@@ -1,120 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UI="clr-namespace:UI">
<Style TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static UI:Theme.Heading}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="RadioButton">
<Setter Property="Padding" Value="6 0 0 0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="LeftCol" Width="18" />
<ColumnDefinition x:Name="RightCol" Width="*" />
</Grid.ColumnDefinitions>
<Grid x:Name="PART_CHECKBOX">
<Ellipse
x:Name="normal"
Width="18"
Height="18"
Fill="{x:Static UI:Theme.Background}"
Stroke="{x:Static UI:Theme.Heading}"
StrokeThickness="2" />
<Ellipse
x:Name="Checked1"
Width="8"
Height="8"
Fill="{TemplateBinding Foreground}"
Opacity="0" />
<Ellipse
x:Name="disabled"
Width="18"
Height="18"
Fill="{DynamicResource SemiTransparentWhiteBrush}"
Opacity="0"
StrokeThickness="{TemplateBinding BorderThickness}" />
</Grid>
<ContentPresenter
x:Name="contentPresenter"
Grid.Column="1"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
RecognizesAccessKey="True" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="contentPresenter"
Storyboard.TargetProperty="(UIElement.Opacity)"
To=".55"
Duration="0" />
<DoubleAnimation
Storyboard.TargetName="disabled"
Storyboard.TargetProperty="(UIElement.Opacity)"
To="1"
Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Checked1"
Storyboard.TargetProperty="(UIElement.Opacity)"
To="1"
Duration="0" />
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked" />
<VisualState x:Name="Indeterminate" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
</ResourceDictionary>

View File

@@ -1,68 +0,0 @@
<UserControl x:Class="Controls.SearchTextBoxUserControl"
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:UI="clr-namespace:UI"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800">
<Grid Name="SearchTextBoxUserControl1"
Background="{x:Static UI:Theme.Background}">
<TextBlock Name="HintTextBlock"
Margin="5,2"
Text="Find a setting"
VerticalAlignment="Center"
Foreground="{x:Static UI:Theme.Foreground2}"
Background="{x:Static UI:Theme.Background}" />
<TextBox Name="SearchTextBox"
Height="25"
Padding="1,2,0,0"
BorderThickness="2"
Background="Transparent"
TextChanged="SearchTextBox_TextChanged"
Foreground="{x:Static UI:Theme.Foreground}"
CaretBrush="{x:Static UI:Theme.Foreground}" />
<Button Name="SearchClearButton"
Background="Transparent"
HorizontalAlignment="Right"
FontFamily="Marlett"
FontSize="10"
Width="17"
Height="17"
Margin="2,0,4,0"
Visibility="Hidden"
Click="SearchClearButton_Click" >r
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="{x:Static UI:Theme.Background}"/>
<Setter Property="Foreground" Value="{x:Static UI:Theme.Foreground2}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border BorderThickness="1"
BorderBrush="{TemplateBinding Foreground}"
SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{x:Static UI:Theme.Heading}"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</UserControl>

View File

@@ -1,33 +0,0 @@
<Window x:Class="mpvnet.SetupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:UI="clr-namespace:UI"
mc:Ignorable="d"
Title="mpv.net Setup"
FontSize="13"
Foreground="{x:Static UI:Theme.Foreground}"
Background="{x:Static UI:Theme.Background}"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner" >
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Padding" Value="10"></Setter>
<Setter Property="Margin" Value="5"></Setter>
</Style>
</Window.Resources>
<Grid>
<StackPanel Margin="10">
<Button Name="RegisterVideo" Click="RegisterVideo_Click">Register video file extensions (requires admin rights)</Button>
<Button Name="RegisterAudio" Click="RegisterAudio_Click">Register audio file extensions (requires admin rights)</Button>
<Button Name="RegisterImage" Click="RegisterImage_Click">Register image file extensions (requires admin rights)</Button>
<Button Name="UnregisterFileAssociations" Click="UnregisterFileAssociations_Click">Unregister file extensions (requires admin rights)</Button>
<Button Name="AddToPathEnvVar" Click="AddToPathEnvVar_Click">Add mpv.net to Path environment variable</Button>
<Button Name="RemoveFromPathEnvVar" Click="RemoveFromPathEnvVar_Click">Remove mpv.net from Path environment variable</Button>
</StackPanel>
</Grid>
</Window>

View File

@@ -1,64 +0,0 @@

using System;
using System.Diagnostics;
using System.Windows;
using WinForms = System.Windows.Forms;
namespace mpvnet
{
public partial class SetupWindow : Window
{
public SetupWindow() => InitializeComponent();
void RegisterFileAssociations(string value)
{
try
{
using (Process proc = new Process())
{
proc.StartInfo.FileName = WinForms.Application.ExecutablePath;
proc.StartInfo.Arguments = "--reg-file-assoc " + value;
proc.StartInfo.Verb = "runas";
proc.Start();
}
Process.Start("ms-settings:defaultapps");
} catch {}
}
void RegisterVideo_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("video");
void RegisterAudio_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("audio");
void RegisterImage_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("image");
void UnregisterFileAssociations_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("unreg");
void AddToPathEnvVar_Click(object sender, RoutedEventArgs e)
{
string var = WinForms.Application.StartupPath + ";";
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
if (path.Contains(var))
Msg.ShowWarning("Path was already containing mpv.net.");
else
{
Environment.SetEnvironmentVariable("Path", var + path, EnvironmentVariableTarget.User);
Msg.Show("mpv.net was successfully added to Path.", (var + path).Replace(";","\n"));
}
}
void RemoveFromPathEnvVar_Click(object sender, RoutedEventArgs e)
{
string var = WinForms.Application.StartupPath + ";";
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
if (path.Contains(var))
{
Environment.SetEnvironmentVariable("Path", path.Replace(var, ""), EnvironmentVariableTarget.User);
Msg.Show("mpv.net was successfully removed from Path.");
}
else
Msg.ShowWarning("Path was not containing mpv.net.");
}
}
}

View File

@@ -1,846 +0,0 @@

using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Diagnostics;
using System.Threading.Tasks;
using UI;
using ScriptHost;
namespace mpvnet
{
public partial class MainForm : Form
{
public static MainForm Instance { get; set; }
public static IntPtr Hwnd { get; set; }
public new ContextMenuStripEx ContextMenu { get; set; }
Point LastCursorPosition;
int LastCursorChanged;
int LastCycleFullscreen;
int TaskbarButtonCreatedMessage;
int ShownTickCount;
Taskbar Taskbar;
List<string> RecentFiles;
bool WasMaximized;
public MainForm()
{
InitializeComponent();
try
{
object recent = RegistryHelp.GetValue(App.RegPath, "Recent");
if (recent is string[] r)
RecentFiles = new List<string>(r);
else
RecentFiles = new List<string>();
Instance = this;
Hwnd = Handle;
ConsoleHelp.Padding = 60;
mp.Init();
mp.Shutdown += Shutdown;
mp.VideoSizeChanged += VideoSizeChanged;
mp.FileLoaded += FileLoaded;
mp.Idle += Idle;
mp.Seek += () => UpdateProgressBar();
mp.observe_property("window-maximized", PropChangeWindowMaximized);
mp.observe_property("window-minimized", PropChangeWindowMinimized);
mp.observe_property_bool("pause", PropChangePause);
mp.observe_property_bool("fullscreen", PropChangeFullscreen);
mp.observe_property_bool("ontop", PropChangeOnTop);
mp.observe_property_bool("border", PropChangeBorder);
mp.observe_property_string("sid", PropChangeSid);
mp.observe_property_string("aid", PropChangeAid);
mp.observe_property_string("vid", PropChangeVid);
mp.observe_property_int("edition", PropChangeEdition);
mp.observe_property_double("window-scale", PropChangeWindowScale);
if (mp.GPUAPI != "vulkan")
mp.ProcessCommandLine(false);
AppDomain.CurrentDomain.UnhandledException += (sender, e) => App.ShowException(e.ExceptionObject);
Application.ThreadException += (sender, e) => App.ShowException(e.Exception);
Msg.SupportURL = "https://github.com/stax76/mpv.net#support";
Text = "mpv.net " + Application.ProductVersion;
TaskbarButtonCreatedMessage = WinAPI.RegisterWindowMessage("TaskbarButtonCreated");
ContextMenu = new ContextMenuStripEx(components);
ContextMenu.Opened += ContextMenu_Opened;
ContextMenu.Opening += ContextMenu_Opening;
if (mp.Screen == -1)
mp.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
int targetIndex = mp.Screen;
Screen[] screens = Screen.AllScreens;
if (targetIndex < 0)
targetIndex = 0;
if (targetIndex > screens.Length - 1)
targetIndex = screens.Length - 1;
Screen screen = screens[Array.IndexOf(screens, screens[targetIndex])];
Rectangle target = screen.Bounds;
Left = target.X + (target.Width - Width) / 2;
Top = target.Y + (target.Height - Height) / 2;
if (!mp.Border)
FormBorderStyle = FormBorderStyle.None;
int posX = RegistryHelp.GetInt(App.RegPath, "PosX");
int posY = RegistryHelp.GetInt(App.RegPath, "PosY");
if (posX != 0 && posY != 0 && App.RememberPosition)
{
Left = posX - Width / 2;
Top = posY - Height / 2;
}
if (mp.WindowMaximized)
{
SetFormPosAndSize(1, true);
WindowState = FormWindowState.Maximized;
}
if (mp.WindowMinimized)
{
SetFormPosAndSize(1, true);
WindowState = FormWindowState.Minimized;
}
}
catch (Exception ex)
{
Msg.ShowException(ex);
}
}
public MenuItem FindMenuItem(string text) => FindMenuItem(text, ContextMenu.Items);
void Shutdown() => BeginInvoke(new Action(() => Close()));
void Idle()
{
BeginInvoke(new Action(() => Text = "mpv.net " + Application.ProductVersion));
}
bool WasShown() => ShownTickCount != 0 && Environment.TickCount > ShownTickCount + 500;
void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
void VideoSizeChanged() => BeginInvoke(new Action(() => SetFormPosAndSize()));
void PropChangeFullscreen(bool value) => BeginInvoke(new Action(() => CycleFullscreen(value)));
void ContextMenu_Opened(object sender, EventArgs e) => CursorHelp.Show();
bool IsFullscreen => WindowState == FormWindowState.Maximized && FormBorderStyle == FormBorderStyle.None;
bool IsMouseInOSC()
{
Point pos = PointToClient(Control.MousePosition);
float top = 0;
if (FormBorderStyle == FormBorderStyle.None)
top = ClientSize.Height * 0.1f;
return pos.Y > ClientSize.Height * 0.85 || pos.Y < top;
}
void ContextMenu_Opening(object sender, CancelEventArgs e)
{
lock (mp.MediaTracks)
{
MenuItem trackMenuItem = FindMenuItem("Track");
if (trackMenuItem != null)
{
trackMenuItem.DropDownItems.Clear();
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
MediaTrack[] subTracks = mp.MediaTracks.Where(track => track.Type == "s").ToArray();
MediaTrack[] vidTracks = mp.MediaTracks.Where(track => track.Type == "v").ToArray();
MediaTrack[] ediTracks = mp.MediaTracks.Where(track => track.Type == "e").ToArray();
foreach (MediaTrack track in vidTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => mp.commandv("set", "vid", track.ID.ToString());
mi.Checked = mp.Vid == track.ID.ToString();
trackMenuItem.DropDownItems.Add(mi);
}
if (vidTracks.Length > 0)
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
foreach (MediaTrack track in audTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => mp.commandv("set", "aid", track.ID.ToString());
mi.Checked = mp.Aid == track.ID.ToString();
trackMenuItem.DropDownItems.Add(mi);
}
if (subTracks.Length > 0)
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
foreach (MediaTrack track in subTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => mp.commandv("set", "sid", track.ID.ToString());
mi.Checked = mp.Sid == track.ID.ToString();
trackMenuItem.DropDownItems.Add(mi);
}
if (subTracks.Length > 0)
{
MenuItem mi = new MenuItem("S: No subtitles");
mi.Action = () => mp.commandv("set", "sid", "no");
mi.Checked = mp.Sid == "no";
trackMenuItem.DropDownItems.Add(mi);
}
if (ediTracks.Length > 0)
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
foreach (MediaTrack track in ediTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => mp.commandv("set", "edition", track.ID.ToString());
mi.Checked = mp.Edition == track.ID;
trackMenuItem.DropDownItems.Add(mi);
}
}
}
lock (mp.Chapters)
{
MenuItem chaptersMenuItem = FindMenuItem("Chapters");
if (chaptersMenuItem != null)
{
chaptersMenuItem.DropDownItems.Clear();
foreach (var i in mp.Chapters)
{
MenuItem mi = new MenuItem(i.Key);
mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " ";
mi.Action = () => mp.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute");
chaptersMenuItem.DropDownItems.Add(mi);
}
}
}
MenuItem recent = FindMenuItem("Recent");
if (recent != null)
{
recent.DropDownItems.Clear();
foreach (string path in RecentFiles)
MenuItem.Add(recent.DropDownItems, path, () => mp.LoadFiles(new[] { path }, true, Control.ModifierKeys.HasFlag(Keys.Control)));
recent.DropDownItems.Add(new ToolStripSeparator());
MenuItem mi = new MenuItem("Clear List");
mi.Action = () => RecentFiles.Clear();
recent.DropDownItems.Add(mi);
}
}
MenuItem FindMenuItem(string text, ToolStripItemCollection items)
{
foreach (var item in items)
{
if (item is MenuItem mi)
{
if (mi.Text.StartsWith(text) && mi.Text.Trim() == text)
return mi;
if (mi.DropDownItems.Count > 0)
{
MenuItem val = FindMenuItem(text, mi.DropDownItems);
if (val != null) return val;
}
}
}
return null;
}
void SetFormPosAndSize(double scale = 1, bool force = false)
{
if (!force)
{
if (WindowState != FormWindowState.Normal)
return;
if (mp.Fullscreen)
{
CycleFullscreen(true);
return;
}
}
Screen screen = Screen.FromControl(this);
int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * mp.Autofit);
if (mp.VideoSize.Height == 0 || mp.VideoSize.Width == 0 ||
mp.VideoSize.Width / (float)mp.VideoSize.Height < App.MinimumAspectRatio)
mp.VideoSize = new Size((int)(autoFitHeight * (16 / 9.0)), autoFitHeight);
Size videoSize = mp.VideoSize;
int height = videoSize.Height;
if (mp.WasInitialSizeSet || scale != 1)
height = ClientSize.Height;
else
{
int savedHeight = RegistryHelp.GetInt(App.RegPath, "Height");
if (App.StartSize == "always" && savedHeight != 0)
height = savedHeight;
else
if (App.StartSize != "video")
height = autoFitHeight;
mp.WasInitialSizeSet = true;
}
height = Convert.ToInt32(height * scale);
int width = Convert.ToInt32(height * videoSize.Width / (double)videoSize.Height);
int maxHeight = screen.WorkingArea.Height - (Height - ClientSize.Height);
int maxWidth = screen.WorkingArea.Width - (Width - ClientSize.Width);
if (height < maxHeight * mp.AutofitSmaller)
{
height = Convert.ToInt32(maxHeight * mp.AutofitSmaller);
width = Convert.ToInt32(height * videoSize.Width / (double)videoSize.Height);
}
if (height > maxHeight * mp.AutofitLarger)
{
height = Convert.ToInt32(maxHeight * mp.AutofitLarger);
width = Convert.ToInt32(height * videoSize.Width / (double)videoSize.Height);
}
if (width > maxWidth)
{
width = maxWidth;
height = Convert.ToInt32(width * videoSize.Height / (double)videoSize.Width);
}
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var rect = new WinAPI.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
NativeHelp.AddWindowBorders(Handle, ref rect);
int left = middlePos.X - rect.Width / 2;
int top = middlePos.Y - rect.Height / 2;
Screen[] screens = Screen.AllScreens;
int minLeft = screens.Select(val => val.WorkingArea.X).Min();
int maxRight = screens.Select(val => val.WorkingArea.Right).Max();
int minTop = screens.Select(val => val.WorkingArea.Y).Min();
int maxBottom = screens.Select(val => val.WorkingArea.Bottom).Max();
if (left < minLeft)
left = minLeft;
if (left + rect.Width > maxRight)
left = maxRight - rect.Width;
if (top < minTop)
top = minTop;
if (top + rect.Height > maxBottom)
top = maxBottom - rect.Height;
WinAPI.SetWindowPos(Handle, IntPtr.Zero /* HWND_TOP */,
left, top, rect.Width, rect.Height, 4 /* SWP_NOZORDER */);
}
public void CycleFullscreen(bool enabled)
{
LastCycleFullscreen = Environment.TickCount;
mp.Fullscreen = enabled;
if (enabled)
{
if (WindowState != FormWindowState.Maximized || FormBorderStyle != FormBorderStyle.None)
{
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
if (WasMaximized)
{
Rectangle b = Screen.FromControl(this).Bounds;
uint SWP_SHOWWINDOW = 0x0040;
IntPtr HWND_TOP= IntPtr.Zero;
WinAPI.SetWindowPos(Handle, HWND_TOP, b.X, b.Y, b.Width, b.Height, SWP_SHOWWINDOW);
}
}
}
else
{
if (WindowState == FormWindowState.Maximized && FormBorderStyle == FormBorderStyle.None)
{
if (WasMaximized)
WindowState = FormWindowState.Maximized;
else
WindowState = FormWindowState.Normal;
if (mp.Border)
FormBorderStyle = FormBorderStyle.Sizable;
else
FormBorderStyle = FormBorderStyle.None;
SetFormPosAndSize();
SaveWindowProperties();
}
}
}
public void BuildMenu()
{
string content = File.ReadAllText(mp.InputConfPath);
var items = CommandItem.GetItems(content);
if (!content.Contains("#menu:"))
{
var defaultItems = CommandItem.GetItems(Properties.Resources.input_conf);
foreach (CommandItem item in items)
foreach (CommandItem defaultItem in defaultItems)
if (item.Command == defaultItem.Command)
defaultItem.Input = item.Input;
items = defaultItems;
}
foreach (CommandItem item in items)
{
if (string.IsNullOrEmpty(item.Path))
continue;
string path = item.Path.Replace("&", "&&");
MenuItem menuItem = ContextMenu.Add(path, () => {
try {
mp.command(item.Command);
} catch (Exception ex) {
Msg.ShowException(ex);
}
});
if (menuItem != null)
menuItem.ShortcutKeyDisplayString = item.Input + " ";
}
}
void FileLoaded()
{
string path = mp.get_property_string("path");
BeginInvoke(new Action(() => {
if (path.Contains("://"))
Text = mp.get_property_string("media-title") + " - mpv.net " + Application.ProductVersion;
else if (path.Contains(":\\") || path.StartsWith("\\\\"))
Text = path.FileName() + " - mpv.net " + Application.ProductVersion;
else
Text = "mpv.net " + Application.ProductVersion;
int interval = (int)(mp.Duration.TotalMilliseconds / 100);
if (interval < 100) interval = 100;
if (interval > 1000) interval = 1000;
ProgressTimer.Interval = interval;
UpdateProgressBar();
}));
if (RecentFiles.Contains(path))
RecentFiles.Remove(path);
RecentFiles.Insert(0, path);
while (RecentFiles.Count > App.RecentCount)
RecentFiles.RemoveAt(App.RecentCount);
}
void SaveWindowProperties()
{
if (WindowState == FormWindowState.Normal)
{
RegistryHelp.SetValue(App.RegPath, "PosX", Left + Width / 2);
RegistryHelp.SetValue(App.RegPath, "PosY", Top + Height / 2);
RegistryHelp.SetValue(App.RegPath, "Height", ClientSize.Height);
}
}
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.Style |= 0x00020000 /* WS_MINIMIZEBOX */;
return cp;
}
}
protected override void WndProc(ref Message m)
{
//Debug.WriteLine(m);
switch (m.Msg)
{
case 0x201: // WM_LBUTTONDOWN
case 0x202: // WM_LBUTTONUP
case 0x207: // WM_MBUTTONDOWN
case 0x208: // WM_MBUTTONUP
case 0x20b: // WM_XBUTTONDOWN
case 0x20c: // WM_XBUTTONUP
case 0x20A: // WM_MOUSEWHEEL
case 0x100: // WM_KEYDOWN
case 0x101: // WM_KEYUP
case 0x102: // WM_CHAR
case 0x104: // WM_SYSKEYDOWN
case 0x105: // WM_SYSKEYUP
case 0x106: // WM_SYSCHAR
case 0x319: // WM_APPCOMMAND
if (mp.WindowHandle != IntPtr.Zero)
m.Result = WinAPI.SendMessage(mp.WindowHandle, m.Msg, m.WParam, m.LParam);
break;
case 0x0200: // WM_MOUSEMOVE
if (Environment.TickCount - LastCycleFullscreen > 500)
{
Point pos = PointToClient(Cursor.Position);
mp.command($"mouse {pos.X} {pos.Y}");
}
if (CursorHelp.IsPosDifferent(LastCursorPosition))
CursorHelp.Show();
break;
case 0x2a3: // WM_MOUSELEAVE
//osc won't auto hide after mouse left window in borderless mode
mp.command($"mouse {ClientSize.Width / 2} {ClientSize.Height / 3}");
break;
case 0x203: // WM_LBUTTONDBLCLK
{
Point pos = PointToClient(Cursor.Position);
mp.command($"mouse {pos.X} {pos.Y} 0 double");
}
break;
case 0x02E0: // WM_DPICHANGED
{
if (!WasShown())
break;
WinAPI.RECT rect = Marshal.PtrToStructure<WinAPI.RECT>(m.LParam);
WinAPI.SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, 0);
}
break;
case 0x0214: // WM_SIZING
{
var rc = Marshal.PtrToStructure<WinAPI.RECT>(m.LParam);
var r = rc;
NativeHelp.SubtractWindowBorders(Handle, ref r);
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
Size s = mp.VideoSize;
if (s == Size.Empty)
s = new Size(16, 9);
float aspect = s.Width / (float)s.Height;
int d_w = Convert.ToInt32(c_h * aspect - c_w);
int d_h = Convert.ToInt32(c_w / aspect - c_h);
int[] d_corners = { d_w, d_h, -d_w, -d_h };
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
int corner = NativeHelp.GetResizeBorder(m.WParam.ToInt32());
if (corner >= 0)
corners[corner] -= d_corners[corner];
Marshal.StructureToPtr<WinAPI.RECT>(new WinAPI.RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false);
m.Result = new IntPtr(1);
}
return;
case 0x004A: // WM_COPYDATA
{
var copyData = (WinAPI.COPYDATASTRUCT)m.GetLParam(typeof(WinAPI.COPYDATASTRUCT));
string[] files = copyData.lpData.Split('\n');
string mode = files[0];
files = files.Skip(1).ToArray();
switch (mode)
{
case "single":
mp.LoadFiles(files, true, Control.ModifierKeys.HasFlag(Keys.Control));
break;
case "queue":
foreach (string file in files)
mp.commandv("loadfile", file, "append");
break;
}
Activate();
}
return;
}
if (m.Msg == TaskbarButtonCreatedMessage && mp.TaskbarProgress)
{
Taskbar = new Taskbar(Handle);
ProgressTimer.Start();
}
base.WndProc(ref m);
}
void CursorTimer_Tick(object sender, EventArgs e)
{
if (CursorHelp.IsPosDifferent(LastCursorPosition))
{
LastCursorPosition = Control.MousePosition;
LastCursorChanged = Environment.TickCount;
}
else if (Environment.TickCount - LastCursorChanged > 1500 &&
!IsMouseInOSC() && ClientRectangle.Contains(PointToClient(MousePosition)) &&
Form.ActiveForm == this && !ContextMenu.Visible)
CursorHelp.Hide();
}
void ProgressTimer_Tick(object sender, EventArgs e) => UpdateProgressBar();
void UpdateProgressBar()
{
if (mp.TaskbarProgress && Taskbar != null)
Taskbar.SetValue(mp.get_property_number("time-pos"), mp.Duration.TotalSeconds);
}
void PropChangeOnTop(bool value) => BeginInvoke(new Action(() => TopMost = value));
void PropChangeAid(string value) => mp.Aid = value;
void PropChangeSid(string value) => mp.Sid = value;
void PropChangeVid(string value) => mp.Vid = value;
void PropChangeEdition(int value) => mp.Edition = value;
void PropChangeWindowScale(double value)
{
if (value != 1)
{
BeginInvoke(new Action(() => SetFormPosAndSize(value)));
mp.command("no-osd set window-scale 1");
}
}
void PropChangeWindowMaximized()
{
if (!WasShown())
return;
BeginInvoke(new Action(() =>
{
mp.WindowMaximized = mp.get_property_bool("window-maximized");
if (mp.WindowMaximized && WindowState != FormWindowState.Maximized)
WindowState = FormWindowState.Maximized;
else if (!mp.WindowMaximized && WindowState == FormWindowState.Maximized)
WindowState = FormWindowState.Normal;
}));
}
void PropChangeWindowMinimized()
{
if (!WasShown())
return;
BeginInvoke(new Action(() =>
{
mp.WindowMinimized = mp.get_property_bool("window-minimized");
if (mp.WindowMinimized && WindowState != FormWindowState.Minimized)
WindowState = FormWindowState.Minimized;
else if (!mp.WindowMinimized && WindowState == FormWindowState.Minimized)
WindowState = FormWindowState.Normal;
}));
}
void PropChangeBorder(bool enabled) {
mp.Border = enabled;
BeginInvoke(new Action(() => {
if (!IsFullscreen)
{
if (mp.Border && FormBorderStyle == FormBorderStyle.None)
FormBorderStyle = FormBorderStyle.Sizable;
if (!mp.Border && FormBorderStyle == FormBorderStyle.Sizable)
FormBorderStyle = FormBorderStyle.None;
}
}));
}
void PropChangePause(bool enabled)
{
if (Taskbar != null && mp.TaskbarProgress)
{
if (enabled)
Taskbar.SetState(TaskbarStates.Paused);
else
Taskbar.SetState(TaskbarStates.Normal);
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (mp.GPUAPI != "vulkan")
mp.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
LastCycleFullscreen = Environment.TickCount;
SetFormPosAndSize();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
if (mp.GPUAPI == "vulkan")
mp.ProcessCommandLine(false);
ToolStripRendererEx.ForegroundColor = Theme.Current.GetWinFormsColor("menu-foreground");
ToolStripRendererEx.BackgroundColor = Theme.Current.GetWinFormsColor("menu-background");
ToolStripRendererEx.SelectionColor = Theme.Current.GetWinFormsColor("menu-highlight");
ToolStripRendererEx.BorderColor = Theme.Current.GetWinFormsColor("menu-border");
ToolStripRendererEx.CheckedColor = Theme.Current.GetWinFormsColor("menu-checked");
BuildMenu();
ContextMenuStrip = ContextMenu;
WPF.WPF.Init();
System.Windows.Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
UpdateCheck.DailyCheck();
mp.LoadScripts();
Task.Run(() => App.Extension = new Extension());
ShownTickCount = Environment.TickCount;
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
Message m = new Message() { Msg = 0x0202 }; // WM_LBUTTONUP
WinAPI.SendMessage(MainForm.Instance.Handle, m.Msg, m.WParam, m.LParam);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
if (mp.IsLogoVisible)
mp.ShowLogo();
if (FormBorderStyle != FormBorderStyle.None)
{
if (WindowState == FormWindowState.Maximized)
WasMaximized = true;
else if (WindowState == FormWindowState.Normal)
WasMaximized = false;
}
if (WasShown())
{
if (WindowState == FormWindowState.Minimized)
{
mp.set_property_string("window-minimized", "yes");
}
else if (WindowState == FormWindowState.Normal)
{
mp.set_property_string("window-maximized", "no");
mp.set_property_string("window-minimized", "no");
}
else if (WindowState == FormWindowState.Maximized)
{
mp.set_property_string("window-maximized", "yes");
}
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
SaveWindowProperties();
RegistryHelp.SetValue(App.RegPath, "Recent", RecentFiles.ToArray());
if (mp.IsQuitNeeded)
mp.commandv("quit");
if (!mp.ShutdownAutoResetEvent.WaitOne(10000))
Msg.ShowError("Shutdown thread failed to complete within 10 seconds.");
try { // PowerShell 5.1 might not be available
foreach (PowerShell ps in PowerShell.Instances)
ps.Runspace.Dispose();
} catch {}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (WindowState == FormWindowState.Normal &&
e.Button == MouseButtons.Left && !IsMouseInOSC())
{
var HTCAPTION = new IntPtr(2);
WinAPI.ReleaseCapture();
WinAPI.PostMessage(Handle, 0xA1 /* WM_NCLBUTTONDOWN */, HTCAPTION, IntPtr.Zero);
}
if (Width - e.Location.X < 10 && e.Location.Y < 10)
mp.commandv("quit");
}
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(DataFormats.Text))
e.Effect = DragDropEffects.Copy;
}
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
if (e.Data.GetDataPresent(DataFormats.FileDrop))
mp.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control));
if (e.Data.GetDataPresent(DataFormats.Text))
mp.LoadFiles(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control));
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
CursorHelp.Show();
}
protected override void OnKeyDown(KeyEventArgs e)
{
e.SuppressKeyPress = true; // prevent beep using alt key
base.OnKeyDown(e);
}
}
}

View File

@@ -1,395 +0,0 @@
using System;
using System.Linq;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using System.Drawing;
public class ContextMenuStripEx : ContextMenuStrip
{
public ContextMenuStripEx()
{
}
public ContextMenuStripEx(IContainer container) : base(container)
{
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
Renderer = new ToolStripRendererEx();
}
public MenuItem Add(string path)
{
return Add(path, null);
}
public MenuItem Add(string path, Action action, bool enabled = true)
{
MenuItem ret = MenuItem.Add(Items, path, action);
if (ret == null) return null;
ret.Enabled = enabled;
return ret;
}
}
public class MenuItem : ToolStripMenuItem
{
public Action Action { get; set; }
public MenuItem()
{
}
public MenuItem(string text) : base(text)
{
}
public MenuItem(string text, Action action) : base(text)
{
Action = action;
}
protected override void OnClick(EventArgs e)
{
Application.DoEvents();
Action?.Invoke();
base.OnClick(e);
}
public static MenuItem Add(ToolStripItemCollection items, string path, Action action)
{
string[] a = path.Split(new[] { " > ", " | " }, StringSplitOptions.RemoveEmptyEntries);
var itemsCollection = items;
for (int x = 0; x < a.Length; x++)
{
bool found = false;
foreach (var i in itemsCollection.OfType<ToolStripMenuItem>())
{
if (x < a.Length - 1)
{
if (i.Text == a[x] + " ")
{
found = true;
itemsCollection = i.DropDownItems;
}
}
}
if (!found)
{
if (x == a.Length - 1)
{
if (a[x] == "-")
itemsCollection.Add(new ToolStripSeparator());
else
{
MenuItem item = new MenuItem(a[x] + " ", action);
itemsCollection.Add(item);
itemsCollection = item.DropDownItems;
return item;
}
}
else
{
MenuItem item = new MenuItem();
item.Text = a[x] + " ";
itemsCollection.Add(item);
itemsCollection = item.DropDownItems;
}
}
}
return null;
}
public override Size GetPreferredSize(Size constrainingSize)
{
Size size = base.GetPreferredSize(constrainingSize);
size.Height = Convert.ToInt32(Font.Height * 1.4);
return size;
}
public void CloseAll(object item)
{
if (item is ToolStripItem)
CloseAll(((ToolStripItem)item).Owner);
if (item is ToolStripDropDown)
{
var d = (ToolStripDropDown)item;
d.Close();
CloseAll(d.OwnerItem);
}
}
}
public class ToolStripRendererEx : ToolStripSystemRenderer
{
public static Color ForegroundColor { get; set; }
public static Color BackgroundColor { get; set; }
public static Color SelectionColor { get; set; }
public static Color CheckedColor { get; set; }
public static Color BorderColor { get; set; }
int TextOffset;
public static void SetDefaultColors()
{
ForegroundColor = Color.FromArgb(unchecked((int)0xFF000000));
BackgroundColor = Color.FromArgb(unchecked((int)0xFFDFDFDF));
SelectionColor = Color.FromArgb(unchecked((int)0xFFBFBFBF));
CheckedColor = Color.FromArgb(unchecked((int)0xFFAAAAAA));
BorderColor = Color.FromArgb(unchecked((int)0xFF6A6A6A));
}
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{
Rectangle r = e.AffectedBounds;
r.Inflate(-1, -1);
ControlPaint.DrawBorder(e.Graphics, r, BackgroundColor, ButtonBorderStyle.Solid);
ControlPaint.DrawBorder(e.Graphics, e.AffectedBounds, BorderColor, ButtonBorderStyle.Solid);
}
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
if (e.Item is ToolStripMenuItem && !(e.Item.Owner is MenuStrip))
{
Rectangle rect = e.TextRectangle;
var dropDown = e.ToolStrip as ToolStripDropDownMenu;
if (dropDown == null || dropDown.ShowImageMargin || dropDown.ShowCheckMargin)
TextOffset = Convert.ToInt32(e.Item.Height * 1.1);
else
TextOffset = Convert.ToInt32(e.Item.Height * 0.2);
e.TextColor = ForegroundColor;
e.TextRectangle = new Rectangle(TextOffset, Convert.ToInt32((e.Item.Height - rect.Height) / 2.0), rect.Width, rect.Height);
}
base.OnRenderItemText(e);
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
if (!(e.Item.Owner is MenuStrip))
e.Graphics.Clear(BackgroundColor);
if (e.Item.Selected && e.Item.Enabled)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
rect = new Rectangle(rect.X + 2, rect.Y, rect.Width - 4, rect.Height - 1);
rect.Inflate(-1, -1);
using (SolidBrush b = new SolidBrush(SelectionColor))
e.Graphics.FillRectangle(b, rect);
}
}
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
if (e.Direction == ArrowDirection.Down) throw new NotImplementedException();
float x1 = e.Item.Width - e.Item.Height * 0.6f;
float y1 = e.Item.Height * 0.25f;
float x2 = x1 + e.Item.Height * 0.25f;
float y2 = e.Item.Height / 2f;
float x3 = x1;
float y3 = e.Item.Height * 0.75f;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
using (Brush b = new SolidBrush(ForegroundColor))
{
using (Pen p = new Pen(b, Control.DefaultFont.Height / 20f))
{
e.Graphics.DrawLine(p, x1, y1, x2, y2);
e.Graphics.DrawLine(p, x2, y2, x3, y3);
}
}
}
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
{
if (e.Item.GetType() != typeof(MenuItem))
return;
MenuItem item = e.Item as MenuItem;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (!item.Checked)
return;
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
rect = new Rectangle(rect.X + 2, rect.Y, rect.Height - 1, rect.Height - 1);
rect.Inflate(-1, -1);
using (Brush brush = new SolidBrush(CheckedColor))
e.Graphics.FillRectangle(brush, rect);
float ellipseWidth = rect.Height / 3f;
RectangleF rectF = new RectangleF(rect.X + rect.Height / 2f - ellipseWidth / 2f,
rect.Y + rect.Height / 2f - ellipseWidth / 2f,
ellipseWidth,
ellipseWidth);
using (Brush brush = new SolidBrush(ForegroundColor))
e.Graphics.FillEllipse(brush, rectF);
}
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
{
e.Graphics.Clear(BackgroundColor);
int top = e.Item.Height / 2;
top -= 1;
int offset = Convert.ToInt32(e.Item.Font.Height * 0.7);
using (Pen p = new Pen(BorderColor))
e.Graphics.DrawLine(p,
new Point(offset, top),
new Point(e.Item.Width - offset, top));
}
}
public struct HSLColor
{
public HSLColor(Color color) : this()
{
SetRGB(color.R, color.G, color.B);
}
public HSLColor(int h, int s, int l) : this()
{
Hue = h;
Saturation = s;
Luminosity = l;
}
double _Hue;
public int Hue {
get => System.Convert.ToInt32(_Hue * 240);
set => _Hue = CheckRange(value / 240.0);
}
double _Saturation;
public int Saturation {
get => System.Convert.ToInt32(_Saturation * 240);
set => _Saturation = CheckRange(value / 240.0);
}
double _Luminosity;
public int Luminosity {
get => System.Convert.ToInt32(_Luminosity * 240);
set => _Luminosity = CheckRange(value / 240.0);
}
double CheckRange(double value)
{
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
return value;
}
public Color ToColorAddLuminosity(int luminosity)
{
Luminosity += luminosity;
return ToColor();
}
public Color ToColorSetLuminosity(int luminosity)
{
Luminosity = luminosity;
return ToColor();
}
public Color ToColor()
{
double r = 0, g = 0, b = 0;
if (_Luminosity != 0)
{
if (_Saturation == 0)
{
b = _Luminosity;
g = _Luminosity;
r = _Luminosity;
}
else
{
double temp2 = GetTemp2(this);
double temp1 = 2.0 * _Luminosity - temp2;
r = GetColorComponent(temp1, temp2, _Hue + 1.0 / 3.0);
g = GetColorComponent(temp1, temp2, _Hue);
b = GetColorComponent(temp1, temp2, _Hue - 1.0 / 3.0);
}
}
return Color.FromArgb(
System.Convert.ToInt32(255 * r),
System.Convert.ToInt32(255 * g),
System.Convert.ToInt32(255 * b));
}
static double GetColorComponent(double temp1, double temp2, double temp3)
{
temp3 = MoveIntoRange(temp3);
if (temp3 < 1 / 6.0)
return temp1 + (temp2 - temp1) * 6.0 * temp3;
else if (temp3 < 0.5)
return temp2;
else if (temp3 < 2 / 3.0)
return temp1 + ((temp2 - temp1) * (2 / 3.0 - temp3) * 6);
else
return temp1;
}
static double MoveIntoRange(double temp3)
{
if (temp3 < 0)
temp3 += 1;
else if (temp3 > 1)
temp3 -= 1;
return temp3;
}
static double GetTemp2(HSLColor hslColor)
{
double temp2;
if (hslColor._Luminosity < 0.5)
temp2 = hslColor._Luminosity * (1.0 + hslColor._Saturation);
else
temp2 = hslColor._Luminosity + hslColor._Saturation - (hslColor._Luminosity * hslColor._Saturation);
return temp2;
}
public static HSLColor Convert(Color c)
{
HSLColor r = new HSLColor();
r._Hue = c.GetHue() / 360.0;
r._Luminosity = c.GetBrightness();
r._Saturation = c.GetSaturation();
return r;
}
public void SetRGB(int red, int green, int blue)
{
HSLColor hc = HSLColor.Convert(Color.FromArgb(red, green, blue));
_Hue = hc._Hue;
_Saturation = hc._Saturation;
_Luminosity = hc._Luminosity;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +0,0 @@
// This script shows a message box using the Msg class of mpv.net.
[Msg]::Show("Hello World")

View File

@@ -1,25 +0,0 @@
# Shows the Open File dialog to open a file without loading its folder into the playlist.
# In input.conf add: <key> script-message load-without-folder
$job = Register-ObjectEvent -InputObject ([mpvnet.mp]) -EventName ClientMessage -Action {
# exit if message does not equal 'load-without-folder'
if ($args.Length -ne 1 -or $args[0] -ne 'load-without-folder')
{
exit
}
$dialog = New-Object Windows.Forms.OpenFileDialog
if ($dialog.ShowDialog() -ne "OK") {
$dialog.Dispose()
exit
}
[mp]::Load($dialog.FileNames, $false, $false);
$dialog.Dispose()
}
$ScriptHost.RedirectEventJobStreams($job)

View File

@@ -1,8 +0,0 @@
# Display position in window title bar when seeking
$job = Register-ObjectEvent -InputObject ([mpvnet.mp]) -EventName Seek -Action {
[MainForm]::Instance.Text = [mp]::get_property_number("time-pos")
}
$ScriptHost.RedirectEventJobStreams($job)

View File

@@ -1,48 +0,0 @@
#define MyAppName "mpv.net"
#define MyAppExeName "mpvnet.exe"
#ifndef arch
#define arch "x64"
#endif
#if arch == "x64"
#define MyAppSourceDir "mpv.net\bin\x64"
#define MyAppVersion GetFileVersion("mpv.net\bin\x64\mpvnet.exe")
#else
#define MyAppSourceDir "mpv.net\bin\x86"
#define MyAppVersion GetFileVersion("mpv.net\bin\x86\mpvnet.exe")
#endif
[Setup]
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher=Frank Skare (stax76)
#if arch == "x64"
ArchitecturesInstallIn64BitMode=x64
#endif
Compression=lzma2
DefaultDirName={commonpf}\{#MyAppName}
OutputBaseFilename=mpv.net-setup-{#arch}-{#MyAppVersion}
OutputDir={#GetEnv('USERPROFILE')}\Desktop
DefaultGroupName={#MyAppName}
SetupIconFile=mpv.net\mpvnet.ico
UninstallDisplayIcon={app}\{#MyAppExeName}
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
[Files]
Source: "{#MyAppSourceDir}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "Associate video file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc video"
Filename: "{app}\{#MyAppExeName}"; Description: "Associate audio file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc audio"
Filename: "{app}\{#MyAppExeName}"; Description: "Associate image file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc image"
[UninstallRun]
Filename: "{app}\{#MyAppExeName}"; Flags: runascurrentuser runhidden; Parameters: "--reg-file-assoc unreg"

22
src/.editorconfig Normal file
View File

@@ -0,0 +1,22 @@
[*.cs]
# IDE0058: Expression value is never used
dotnet_diagnostic.IDE0058.severity = none
# IDE0055: Fix formatting
dotnet_diagnostic.IDE0055.severity = none
# IDE0022: Use block body for methods
dotnet_diagnostic.IDE0022.severity = none
# IDE0040: Add accessibility modifiers
dotnet_diagnostic.IDE0040.severity = none
# IDE0011: Add braces
dotnet_diagnostic.IDE0011.severity = none
# IDE0010: Add missing cases
dotnet_diagnostic.IDE0010.severity = none
# IDE0044: Add readonly modifier
dotnet_diagnostic.IDE0044.severity = silent

View File

@@ -5,4 +5,4 @@
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
</configuration>
</configuration>

View File

@@ -0,0 +1,135 @@
// This extension writes a rating to the filename of rated videos when mpv.net shuts down.
// The input.conf setup:
// KP0 script-message rate-file 0 #menu: Extensions > Rating > 0stars
// KP1 script-message rate-file 1 #menu: Extensions > Rating > 1stars
// KP2 script-message rate-file 2 #menu: Extensions > Rating > 2stars
// KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
// KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
// KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
// _ ignore #menu: Extensions > Rating > -
// _ script-message rate-file about #menu: Extensions > Rating > About
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Microsoft.VisualBasic.FileIO;
using mpvnet;
using static mpvnet.Global;
namespace RatingExtension // the assembly name must end with 'Extension'!
{
[Export(typeof(IExtension))]
public class RatingExtension : IExtension
{
//Script script = new Script();
// dictionory to store the filename and the rating
Dictionary<string, int> Dic = new Dictionary<string, int>();
string FileToDelete;
DateTime DeleteTime;
public RatingExtension() // plugin initialization
{
Core.ClientMessage += ClientMessage; //handles keys defined in input.conf
Core.Shutdown += Shutdown; // handles MPV_EVENT_SHUTDOWN
}
// handles MPV_EVENT_SHUTDOWN
void Shutdown()
{
foreach (var i in Dic)
{
string filepath = i.Key;
int rating = i.Value;
if (string.IsNullOrEmpty(filepath) || !File.Exists(filepath))
return;
string basename = Path.GetFileNameWithoutExtension(filepath);
for (int x = 0; x < 6; x++)
if (basename.Contains(" (" + x + "stars)"))
basename = basename.Replace(" (" + x + "stars)", "");
basename += $" ({rating}stars)";
string newPath = Path.Combine(Path.GetDirectoryName(filepath),
basename + Path.GetExtension(filepath));
if (filepath.ToLower() != newPath.ToLower())
File.Move(filepath, newPath);
File.SetLastWriteTime(newPath, DateTime.Now);
}
}
//handles keys defined in input.conf
void ClientMessage(string[] args)
{
if (args[0] != "rate-file")
return;
if (int.TryParse(args[1], out int rating))
{
string path = Core.GetPropertyString("path");
if (!File.Exists(path))
return;
if (rating == 0 || rating == 1)
Delete(rating);
else
{
Dic[path] = rating;
Core.CommandV("show-text", $"Rating: {rating}");
}
}
else if (args[1] == "about")
MessageBox.Show($"This extension writes a rating to the filename of rated videos " +
"when mpv.net shuts down." + BR2 +
"The input.conf defaults contain key bindings for this extension to set ratings.",
"Rating Extension");
}
void Delete(int rating)
{
if (rating == 0)
{
FileToDelete = Core.GetPropertyString("path");
DeleteTime = DateTime.Now;
Core.CommandV("show-text", "Press 1 to delete file", "5000");
}
else
{
TimeSpan ts = DateTime.Now - DeleteTime;
string path = Core.GetPropertyString("path");
if (FileToDelete == path && ts.TotalSeconds < 5 && File.Exists(FileToDelete))
{
Core.Command("playlist-remove current");
int pos = Core.GetPropertyInt("playlist-pos");
if (pos == -1)
{
int count = Core.GetPropertyInt("playlist-count");
if (count > 0)
Core.SetPropertyInt("playlist-pos", count - 1);
}
Thread.Sleep(2000);
FileSystem.DeleteFile(FileToDelete, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
}
}
}
}
}

View File

@@ -13,46 +13,33 @@
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\mpv.net\bin\x86\Extensions\RatingExtension\</OutputPath>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>..\..\mpv.net\bin\x86\Extensions\RatingExtension\</OutputPath>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\mpv.net\bin\x64\Extensions\RatingExtension\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>..\..\mpv.net\bin\x64\Extensions\RatingExtension\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@@ -63,9 +50,10 @@
<ItemGroup>
<Compile Include="RatingExtension.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScriptDevelopment.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\mpv.net\mpv.net.csproj">
<ProjectReference Include="..\..\mpv.net.csproj">
<Project>{1751f378-8edf-4b62-be6d-304c7c287089}</Project>
<Name>mpv.net</Name>
<Private>False</Private>

View File

@@ -0,0 +1,42 @@

//// This script adds dynamic menu items for profile switching.
//// In input.conf add a menu item called 'Profiles'
//using mpvnet;
//using System.ComponentModel;
//using System.Linq;
//class Script
//{
// MainForm MainForm;
// CorePlayer Core;
// public Script()
// {
// Core = Global.Core;
// MainForm = MainForm.Instance;
// MainForm.ContextMenu.Opening += ContextMenu_Opening;
// }
// void ContextMenu_Opening(object sender, CancelEventArgs e)
// {
// MenuItem menuItem = MainForm.FindMenuItem("My Menu");
// if (menuItem == null)
// {
// Terminal.WriteError("Profiles menu item not found.", "switch-profile-context-menu.cs");
// return;
// }
// menuItem.DropDownItems.Clear();
// var editionTracks = Core.MediaTracks.Where(track => track.Type == "e");
// foreach (int i in new[] {1, 2, 3})
// {
// MenuItem mi = new MenuItem(i.ToString());
// mi.Action = () => { Core.commandv("show-text", i.ToString()); };
// menuItem.DropDownItems.Add(mi);
// }
// }
//}

256
src/Misc/App.cs Normal file
View File

@@ -0,0 +1,256 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Threading.Tasks;
using static mpvnet.Global;
namespace mpvnet
{
public static class App
{
public static List<string> TempFiles { get; } = new List<string>();
public static string ConfPath { get => Core.ConfigFolder + "mpvnet.conf"; }
public static string ProcessInstance { get; set; } = "single";
public static string DarkMode { get; set; } = "always";
public static string DarkTheme { get; set; } = "dark";
public static string LightTheme { get; set; } = "light";
public static string StartSize { get; set; } = "height-session";
public static bool AutoLoadFolder { get; set; } = true;
public static bool AutoPlay { get; set; }
public static bool DebugMode { get; set; }
public static bool IsTerminalAttached { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
public static bool Queue { get; set; }
public static bool RememberVolume { get; set; } = true;
public static bool RememberWindowPosition { get; set; }
public static int StartThreshold { get; set; } = 1500;
public static int RecentCount { get; set; } = 15;
public static float MinimumAspectRatio { get; set; } = 1.2f;
public static Extension Extension { get; set; }
public static bool IsDarkMode => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
static AppSettings _Settings;
public static AppSettings Settings {
get {
if (_Settings == null)
_Settings = SettingsManager.Load();
return _Settings;
}
}
public static void Init()
{
var useless1 = Core.ConfigFolder;
var useless2 = Core.Conf;
foreach (var i in Conf)
ProcessProperty(i.Key, i.Value, true);
if (DebugMode)
{
try
{
string filePath = Core.ConfigFolder + "mpvnet-debug.log";
if (File.Exists(filePath))
File.Delete(filePath);
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
Trace.AutoFlush = true;
//if (App.DebugMode)
// Trace.WriteLine("");
}
catch (Exception e)
{
Msg.ShowException(e);
}
}
InitTheme();
Core.Shutdown += Core_Shutdown;
Core.Initialized += Core_Initialized;
}
public static void InitTheme()
{
string themeContent = null;
if (File.Exists(Core.ConfigFolder + "theme.conf"))
themeContent = File.ReadAllText(Core.ConfigFolder + "theme.conf");
Theme.Init(
themeContent,
Properties.Resources.theme,
IsDarkMode ? DarkTheme : LightTheme);
}
public static void UpdateWpfColors()
{
var dic = System.Windows.Application.Current.Resources;
dic.Remove("BorderColor");
dic.Add("BorderColor", Theme.Current.GetColor("menu-highlight"));
dic.Remove("RegionColor");
dic.Add("RegionColor", Theme.Current.GetColor("menu-background"));
dic.Remove("SecondaryRegionColor");
dic.Add("SecondaryRegionColor", Theme.Current.GetColor("menu-highlight"));
dic.Remove("PrimaryTextColor");
dic.Add("PrimaryTextColor", Theme.Current.GetColor("menu-foreground"));
dic.Remove("HighlightColor");
dic.Add("HighlightColor", Theme.Current.GetColor("highlight"));
}
public static void RunTask(Action action)
{
Task.Run(() => {
try {
action.Invoke();
}
catch (Exception e) {
ShowException(e);
}
});
}
public static string Version => "Copyright (C) 2000-2022 mpv.net/mpv/mplayer\n" +
$"mpv.net {Application.ProductVersion} ({File.GetLastWriteTime(Application.ExecutablePath).ToShortDateString()})\n" +
$"{Core.GetPropertyString("mpv-version")} ({File.GetLastWriteTime(Folder.Startup + "mpv-2.dll").ToShortDateString()})\nffmpeg {Core.GetPropertyString("ffmpeg-version")}\nMediaInfo {FileVersionInfo.GetVersionInfo(Path.Combine(Application.StartupPath, "MediaInfo.dll")).FileVersion} ({File.GetLastWriteTime(Path.Combine(Application.StartupPath , "MediaInfo.dll")).ToShortDateString()})\nGPL v2 License";
public static void ShowException(object obj)
{
if (IsTerminalAttached)
Terminal.WriteError(obj.ToString());
else
{
if (obj is Exception e)
InvokeOnMainThread(() => Msg.ShowException(e));
else
InvokeOnMainThread(() => Msg.ShowError(obj.ToString()));
}
}
public static void InvokeOnMainThread(Action action)
{
if (action == null)
return;
if (MainForm.Instance == null)
action.Invoke();
else
MainForm.Instance.BeginInvoke(action);
}
public static void ShowInfo(string msg)
{
if (IsTerminalAttached)
{
if (msg != null)
Terminal.Write(msg);
}
else
InvokeOnMainThread(() => Msg.ShowInfo(msg));
}
public static void ShowError(string msg)
{
if (IsTerminalAttached)
{
if (msg != null)
Terminal.WriteError(msg);
}
else
InvokeOnMainThread(() => Msg.ShowError(msg));
}
static void Core_Initialized()
{
if (RememberVolume)
{
Core.SetPropertyInt("volume", Settings.Volume);
Core.SetPropertyString("mute", Settings.Mute);
}
}
static void Core_Shutdown()
{
Settings.Volume = Core.GetPropertyInt("volume");
Settings.Mute = Core.GetPropertyString("mute");
SettingsManager.Save(Settings);
foreach (string file in TempFiles)
FileHelp.Delete(file);
}
static Dictionary<string, string> _Conf;
public static Dictionary<string, string> Conf {
get {
if (_Conf == null)
{
_Conf = new Dictionary<string, string>();
if (File.Exists(ConfPath))
foreach (string i in File.ReadAllLines(ConfPath))
if (i.Contains("=") && !i.StartsWith("#"))
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
return _Conf;
}
}
public static bool ProcessProperty(string name, string value, bool writeError = false)
{
switch (name)
{
case "audio-file-extensions": CorePlayer.AudioTypes = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
case "auto-load-folder": AutoLoadFolder = value == "yes"; return true;
case "auto-play": AutoPlay = value == "yes"; 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": CorePlayer.ImageTypes = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true;
case "process-instance": ProcessInstance = value; return true;
case "queue": Queue = value == "yes"; return true;
case "recent-count": RecentCount = value.ToInt(); 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(); return true;
case "video-file-extensions": CorePlayer.VideoTypes = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
default:
if (writeError)
Terminal.WriteError($"unknown mpvnet.conf property: {name}");
return false;
}
}
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

@@ -0,0 +1,71 @@

using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CSharp;
using static mpvnet.Global;
namespace mpvnet
{
class CSharpScriptHost
{
static List<object> References = new List<object>();
public static void ExecuteScriptsInFolder(string folder)
{
if (Directory.Exists(folder))
foreach (string file in Directory.GetFiles(folder, "*.cs"))
App.RunTask(() => Execute(file));
}
static void Execute(string file)
{
string code = File.ReadAllText(file);
string filename = Path.GetFileNameWithoutExtension(file) + " " + StringHelp.GetMD5Hash(code) + ".dll";
string outputFile = Path.Combine(Path.GetTempPath(), filename);
if (!File.Exists(outputFile))
Compile(outputFile, file);
if (File.Exists(outputFile))
{
object instance = Assembly.LoadFile(outputFile).CreateInstance("Script");
if (instance != null)
References.Add(instance);
else
Terminal.WriteError("Failed to initialize script.", outputFile.FileName());
}
}
public static void Compile(string outputFile, string file)
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
string[] dependencies = {
Folder.Startup + "mpvnet.exe",
"Microsoft.VisualBasic.dll",
"System.Core.dll", "System.Data.dll", "System.dll", "System.Drawing.dll", "System.Web.dll",
"System.Windows.Forms.dll", "System.Xaml.dll", "System.Xml.dll", "System.Xml.Linq.dll",
"WPF\\PresentationCore.dll", "WPF\\PresentationFramework.dll", "WPF\\WindowsBase.dll"
};
foreach (string i in dependencies)
parameters.ReferencedAssemblies.Add(i);
parameters.OutputAssembly = outputFile;
CompilerResults results = provider.CompileAssemblyFromFile(parameters, file);
var errors = results.Errors.Cast<CompilerError>().Select(i => "Line Number " +
i.Line + "\n" + "Error Number: " + i.ErrorNumber + "\n" + i.ErrorText);
if (errors.Count() > 0)
Terminal.WriteError(string.Join(BR2, errors), Path.GetFileName(file));
}
}
}

643
src/Misc/Commands.cs Normal file
View File

@@ -0,0 +1,643 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using WinForms = System.Windows.Forms;
using static mpvnet.Global;
using System.Windows.Media;
using System.Text.RegularExpressions;
namespace mpvnet
{
public class Commands
{
public static void Execute(string id, string[] args)
{
switch (id)
{
case "add-files-to-playlist": OpenFiles("append"); break; // deprecated 2019
case "cycle-audio": CycleAudio(); break;
case "execute-mpv-command": Msg.ShowError("The command was removed, please reset input.conf by deleting it, in the new menu use the on screen console."); break; // deprecated 2020
case "load-audio": LoadAudio(); break;
case "load-sub": LoadSubtitle(); break;
case "open-conf-folder": ProcessHelp.ShellExecute(Core.ConfigFolder); break;
case "open-files": OpenFiles(args); break;
case "open-optical-media": Open_DVD_Or_BD_Folder(); break;
case "open-url": OpenURL(); break;
case "play-pause": PlayPause(); break;
case "playlist-first": PlaylistFirst(); break;
case "playlist-last": PlaylistLast(); break;
case "reg-file-assoc": RegisterFileAssociations(args[0]); break;
case "scale-window": ScaleWindow(float.Parse(args[0], CultureInfo.InvariantCulture)); break;
case "shell-execute": ProcessHelp.ShellExecute(args[0]); break;
case "show-about": ShowDialog(typeof(AboutWindow)); break;
case "show-audio-devices": Msg.ShowInfo(Core.GetPropertyOsdString("audio-device-list")); break;
case "show-audio-tracks": ShowAudioTracks(); break;
case "show-command-palette": ShowCommandPalette(); break;
case "show-commands": ShowCommands(); break;
case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break;
case "show-decoders": ShowStrings(mpvHelp.GetDecoders().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); break;
case "show-demuxers": ShowStrings(mpvHelp.GetDemuxers().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); break;
case "show-history": ShowHistory(); break;
case "show-info": ShowInfo(); break;
case "show-input-editor": ShowDialog(typeof(InputWindow)); break;
case "show-keys": ShowStrings(Core.GetPropertyString("input-key-list").Split(',')); break;
case "show-media-info": ShowMediaInfo(args); break;
case "show-playlist": ShowPlaylist(); break;
case "show-profiles": Msg.ShowInfo(mpvHelp.GetProfiles()); break;
case "show-progress": ShowProgress(); break;
case "show-properties": ShowProperties(); break;
case "show-protocols": ShowStrings(mpvHelp.GetProtocols().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); break;
case "show-recent": ShowRecent(); break;
case "show-setup-dialog": ShowSetupDialog(); break; // deprecated 2022
case "show-subtitle-tracks": ShowSubtitleTracks(); break;
case "show-text": ShowText(args[0], Convert.ToInt32(args[1]), Convert.ToInt32(args[2])); break;
case "window-scale": WindowScale(float.Parse(args[0], CultureInfo.InvariantCulture)); break;
default: Terminal.WriteError($"No command '{id}' found."); break;
}
}
public static void ShowDialog(Type winType)
{
App.InvokeOnMainThread(new Action(() => {
Window win = Activator.CreateInstance(winType) as Window;
new WindowInteropHelper(win).Owner = MainForm.Instance.Handle;
win.ShowDialog();
}));
}
public static void OpenFiles(params string[] args)
{
bool append = Control.ModifierKeys.HasFlag(Keys.Control);
bool loadFolder = true;
foreach (string arg in args)
{
if (arg == "append")
append = true;
if (arg == "no-folder")
loadFolder = false;
}
App.InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog() { Multiselect = true })
if (d.ShowDialog() == DialogResult.OK)
Core.LoadFiles(d.FileNames, loadFolder, append);
}));
}
public static void Open_DVD_Or_BD_Folder()
{
App.InvokeOnMainThread(new Action(() => {
var dialog = new FolderBrowser();
if (dialog.Show())
Core.LoadDiskFolder(dialog.SelectedPath);
}));
}
public static void PlaylistFirst()
{
int pos = Core.GetPropertyInt("playlist-pos");
if (pos != 0)
Core.SetPropertyInt("playlist-pos", 0);
}
public static void PlaylistLast()
{
int pos = Core.GetPropertyInt("playlist-pos");
int count = Core.GetPropertyInt("playlist-count");
if (pos < count - 1)
Core.SetPropertyInt("playlist-pos", count - 1);
}
public static void PlayPause()
{
int count = Core.GetPropertyInt("playlist-count");
if (count > 0)
Core.Command("cycle pause");
else if (App.Settings.RecentFiles.Count > 0)
{
foreach (string i in App.Settings.RecentFiles)
{
if (i.Contains("://") || File.Exists(i))
{
Core.LoadFiles(new[] { i }, true, false);
break;
}
}
}
}
public static void ShowHistory()
{
if (File.Exists(Core.ConfigFolder + "history.txt"))
ProcessHelp.ShellExecute(Core.ConfigFolder + "history.txt");
else
{
if (Msg.ShowQuestion("Create history.txt file in config folder?" + BR2 +
"mpv.net will write the date, time and filename of opened files to it.") == MessageBoxResult.OK)
File.WriteAllText(Core.ConfigFolder + "history.txt", "");
}
}
public static void ShowInfo()
{
try
{
string performer, title, album, genre, date, duration, text = "";
long fileSize = 0;
string path = Core.GetPropertyString("path");
if (path.Contains("://"))
path = Core.GetPropertyString("media-title");
int width = Core.GetPropertyInt("video-params/w");
int height = Core.GetPropertyInt("video-params/h");
if (File.Exists(path))
{
fileSize = new FileInfo(path).Length;
if (CorePlayer.AudioTypes.Contains(path.Ext()))
{
using (MediaInfo mediaInfo = new MediaInfo(path))
{
performer = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Performer");
title = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Title");
album = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Album");
genre = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Genre");
date = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Recorded_Date");
duration = mediaInfo.GetInfo(MediaInfoStreamKind.Audio, "Duration/String");
if (performer != "") text += "Artist: " + performer + "\n";
if (title != "") text += "Title: " + title + "\n";
if (album != "") text += "Album: " + album + "\n";
if (genre != "") text += "Genre: " + genre + "\n";
if (date != "") text += "Year: " + date + "\n";
if (duration != "") text += "Length: " + duration + "\n";
text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n";
text += "Type: " + path.Ext().ToUpper();
Core.CommandV("show-text", text, "5000");
return;
}
}
else if (CorePlayer.ImageTypes.Contains(path.Ext()))
{
using (MediaInfo mediaInfo = new MediaInfo(path))
{
text =
"Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" +
"Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" +
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
"Type: " + path.Ext().ToUpper();
Core.CommandV("show-text", text, "5000");
return;
}
}
}
string videoFormat = Core.GetPropertyString("video-format").ToUpper();
string audioCodec = Core.GetPropertyString("audio-codec-name").ToUpper();
text = path.FileName() + $"\n{width} x {height}\n";
if (fileSize > 0)
text += Convert.ToInt32(fileSize / 1024.0 / 1024.0) + " MB\n";
text += $"{videoFormat}\n{audioCodec}";
Core.CommandV("show-text", text, "5000");
}
catch (Exception e)
{
App.ShowException(e);
}
}
public static void ShowProgress()
{
TimeSpan position = TimeSpan.FromSeconds(Core.GetPropertyDouble("time-pos"));
TimeSpan duration = TimeSpan.FromSeconds(Core.GetPropertyDouble("duration"));
string text = FormatTime(position.TotalMinutes) + ":" +
FormatTime(position.Seconds) + " / " +
FormatTime(duration.TotalMinutes) + ":" +
FormatTime(duration.Seconds);
Core.CommandV("show-text", text, "5000");
string FormatTime(double value) => ((int)value).ToString("00");
}
public static void OpenURL()
{
App.InvokeOnMainThread(new Action(() => {
if (WinForms.Clipboard.ContainsFileDropList())
{
string[] files = WinForms.Clipboard.GetFileDropList().Cast<string>().ToArray();
Core.LoadFiles(files, false, Control.ModifierKeys.HasFlag(Keys.Control));
}
else
{
string clipboard = WinForms.Clipboard.GetText();
if (string.IsNullOrEmpty(clipboard) || (!clipboard.Contains("://") && !File.Exists(clipboard)) ||
clipboard.Contains("\n"))
{
App.ShowError("No URL found, the clipboard does not contain a valid URL or file.");
return;
}
Core.LoadFiles(new [] { clipboard }, false, Control.ModifierKeys.HasFlag(Keys.Control));
}
}));
}
public static void LoadSubtitle()
{
App.InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog())
{
string path = Core.GetPropertyString("path");
if (File.Exists(path))
d.InitialDirectory = Path.GetDirectoryName(path);
d.Multiselect = true;
if (d.ShowDialog() == DialogResult.OK)
foreach (string filename in d.FileNames)
Core.CommandV("sub-add", filename);
}
}));
}
public static void LoadAudio()
{
App.InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog())
{
string path = Core.GetPropertyString("path");
if (File.Exists(path))
d.InitialDirectory = Path.GetDirectoryName(path);
d.Multiselect = true;
if (d.ShowDialog() == DialogResult.OK)
foreach (string i in d.FileNames)
Core.CommandV("audio-add", i);
}
}));
}
public static void CycleAudio()
{
MediaTrack[] audioTracks = Core.MediaTracks.Where(track => track.Type == "a").ToArray();
int len = audioTracks.Length;
if (len < 1)
{
Core.CommandV("show-text", "No audio tracks");
return;
}
int aid = Core.GetPropertyInt("aid");
if (len > 1)
{
if (++aid > len)
aid = 1;
Core.CommandV("set", "aid", aid.ToString());
}
Core.CommandV("show-text", aid + "/" + len + ": " + audioTracks[aid - 1].Text.Substring(3), "5000");
}
public static void ShowCommands()
{
string json = Core.GetPropertyString("command-list");
var o = json.FromJson<List<Dictionary<string, object>>>().OrderBy(i => i["name"]);
StringBuilder sb = new StringBuilder();
foreach (Dictionary<string, object> i in o)
{
sb.AppendLine();
sb.AppendLine(i["name"].ToString());
foreach (Dictionary<string, object> i2 in i["args"] as List<object>)
{
string value = i2["name"].ToString() + " <" + i2["type"].ToString().ToLower() + ">";
if ((bool)i2["optional"] == true)
value = "[" + value + "]";
sb.AppendLine(" " + value);
}
}
Msg.ShowInfo(sb.ToString());
}
public static void ScaleWindow(float factor) => Core.RaiseScaleWindow(factor);
public static void WindowScale(float value) => Core.RaiseWindowScale(value);
public static void ShowText(string text, int duration = 0, int fontSize = 0)
{
if (string.IsNullOrEmpty(text))
return;
if (duration == 0)
duration = Core.GetPropertyInt("osd-duration");
if (fontSize == 0)
fontSize = Core.GetPropertyInt("osd-font-size");
Core.Command("show-text \"${osd-ass-cc/0}{\\\\fs" + fontSize +
"}${osd-ass-cc/1}" + text + "\" " + duration);
}
public static void ShowMediaInfo(string[] args)
{
string path = Core.GetPropertyString("path");
if (File.Exists(path) && !path.Contains(@"\\.\pipe\"))
{
using (MediaInfo mediaInfo = new MediaInfo(path))
{
bool full = args.Contains("full");
bool raw = args.Contains("raw");
string text = mediaInfo.GetSummary(full, raw);
text = Regex.Replace(text, "Unique ID.+", "");
MsgBoxEx.MessageBoxEx.MsgFontFamily = new FontFamily("Consolas");
Msg.ShowInfo(text);
MsgBoxEx.MessageBoxEx.MsgFontFamily = new FontFamily("Segoe UI");
}
}
}
public static void ShowCommandPalette() => App.InvokeOnMainThread(() =>
{
CommandPalette.Instance.SetItems(CommandPalette.GetItems());
MainForm.Instance.ShowCommandPalette();
CommandPalette.Instance.SelectFirst();
});
public static void ShowAudioTracks() => App.InvokeOnMainThread(() =>
{
MediaTrack[] tracks = Core.MediaTracks.Where(track => track.Type == "a").ToArray();
int len = tracks.Length;
if (len < 1)
{
Core.CommandV("show-text", "No audio tracks");
return;
}
List<CommandPaletteItem> items = new List<CommandPaletteItem>();
foreach (MediaTrack i in tracks)
{
MediaTrack track = i;
CommandPaletteItem item = new CommandPaletteItem()
{
Text = track.Text,
Action = () => {
Core.CommandV("set", "aid", track.ID.ToString());
Core.CommandV("show-text", track.ID + "/" + len + ": " +
tracks[track.ID - 1].Text.Substring(3), "5000");
}
};
items.Add(item);
}
CommandPalette.Instance.SetItems(items);
MainForm.Instance.ShowCommandPalette();
CommandPalette.Instance.SelectFirst();
});
public static void ShowSubtitleTracks() => App.InvokeOnMainThread(() =>
{
MediaTrack[] tracks = Core.MediaTracks.Where(track => track.Type == "s").ToArray();
int len = tracks.Length;
if (len < 1)
{
Core.CommandV("show-text", "No subtitle tracks");
return;
}
List<CommandPaletteItem> items = new List<CommandPaletteItem>();
foreach (MediaTrack i in tracks)
{
MediaTrack track = i;
CommandPaletteItem item = new CommandPaletteItem()
{
Text = track.Text,
Action = () => {
Core.CommandV("set", "sid", track.ID.ToString());
Core.CommandV("show-text", track.ID + "/" + len + ": " +
tracks[track.ID - 1].Text.Substring(3), "5000");
}
};
items.Add(item);
}
CommandPalette.Instance.SetItems(items);
MainForm.Instance.ShowCommandPalette();
CommandPalette.Instance.SelectFirst();
});
public static void ShowPlaylist() => App.InvokeOnMainThread(() =>
{
int count = Core.GetPropertyInt("playlist-count");
string currentPath = Core.GetPropertyString("path");
CommandPaletteItem currentItem = null;
if (count < 1)
return;
List<CommandPaletteItem> items = new List<CommandPaletteItem>();
for (int i = 0; i < count; i++)
{
int index = i;
string file = Core.GetPropertyString($"playlist/{i}/filename");
CommandPaletteItem item = new CommandPaletteItem()
{
Text = file.FileName(),
Action = () => {
Core.SetPropertyInt("playlist-pos", index);
if (App.AutoPlay && Core.Paused)
Core.SetPropertyBool("pause", false);
}
};
items.Add(item);
if (currentPath.ToLowerEx() == file.ToLowerEx())
currentItem = item;
}
CommandPalette.Instance.SetItems(items);
if (currentItem != null)
{
CommandPalette.Instance.MainListView.SelectedItem = currentItem;
CommandPalette.Instance.MainListView.ScrollIntoView(
CommandPalette.Instance.MainListView.SelectedItem);
}
MainForm.Instance.ShowCommandPalette();
});
public static void ShowProperties() => App.InvokeOnMainThread(() =>
{
var props = Core.GetPropertyString("property-list").Split(',').OrderBy(prop => prop);
List<CommandPaletteItem> items = new List<CommandPaletteItem>();
foreach (string i in props)
{
string prop = i;
CommandPaletteItem item = new CommandPaletteItem()
{
Text = prop,
Action = () =>
{
string propValue = Core.GetPropertyString(prop);
if (propValue.ContainsEx("${"))
propValue += BR2 + Core.Expand(propValue);
App.ShowInfo(prop + ": " + propValue);
}
};
items.Add(item);
}
CommandPalette.Instance.SetItems(items);
MainForm.Instance.ShowCommandPalette();
});
public static void ShowRecent() => App.InvokeOnMainThread(() =>
{
List<CommandPaletteItem> items = new List<CommandPaletteItem>();
foreach (string i in App.Settings.RecentFiles)
{
string file = i;
CommandPaletteItem item = new CommandPaletteItem()
{
Text = file.ShortPath(60),
Action = () => Core.LoadFiles(new[] { file }, true, Control.ModifierKeys.HasFlag(Keys.Control))
};
items.Add(item);
}
CommandPalette.Instance.SetItems(items);
MainForm.Instance.ShowCommandPalette();
CommandPalette.Instance.SelectFirst();
});
public static void RegisterFileAssociations(string perceivedType)
{
string[] extensions = { };
switch (perceivedType)
{
case "video": extensions = CorePlayer.VideoTypes; break;
case "audio": extensions = CorePlayer.AudioTypes; break;
case "image": extensions = CorePlayer.ImageTypes; break;
}
try
{
using (Process proc = new Process())
{
proc.StartInfo.FileName = WinForms.Application.ExecutablePath;
proc.StartInfo.Arguments = "--register-file-associations " +
perceivedType + " " + string.Join(" ", extensions);
proc.StartInfo.Verb = "runas";
proc.StartInfo.UseShellExecute = true;
proc.Start();
proc.WaitForExit();
if (proc.ExitCode == 0)
Msg.ShowInfo("File associations were successfully " +
(perceivedType == "unreg" ? "removed" : "created") +
".\n\nFile Explorer icons will refresh after process restart.");
else
Msg.ShowError("Error creating file associations.");
}
} catch { }
}
public static void ShowStrings(string[] strings) => App.InvokeOnMainThread(() =>
{
List<CommandPaletteItem> items = new List<CommandPaletteItem>();
foreach (string i in strings)
{
string str = i;
CommandPaletteItem item = new CommandPaletteItem()
{
Text = str,
Action = () => Msg.ShowInfo(str)
};
items.Add(item);
}
CommandPalette.Instance.SetItems(items);
MainForm.Instance.ShowCommandPalette();
CommandPalette.Instance.SelectFirst();
});
public static void ShowSetupDialog() => App.InvokeOnMainThread(() =>
{
(string, string)[] pairs = {
("Register video file associations", "script-message mpv.net reg-file-assoc video"),
("Register audio file associations", "script-message mpv.net reg-file-assoc audio"),
("Register image file associations", "script-message mpv.net reg-file-assoc image"),
("Unregister file associations", "script-message mpv.net reg-file-assoc unreg") };
var list = pairs.Select(i => new CommandPaletteItem(i.Item1, () => Core.Command(i.Item2)));
CommandPalette.Instance.SetItems(list);
MainForm.Instance.ShowCommandPalette();
CommandPalette.Instance.SelectFirst();
});
}
}

Some files were not shown because too many files have changed in this diff Show More