Compare commits

...

165 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
135 changed files with 11447 additions and 5101 deletions

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

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

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

@@ -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,54 +43,59 @@ 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
- Global hotkeys
- 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 installer, portable and Chocolatey
- Build-in media streaming (requires youtube-dl being installed)
- 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](docs/Manual.md#support)
@@ -111,7 +118,7 @@ Screenshots
#### Main Window
![Main Window](docs/img/Main.png)
![Main Window](docs/img/Main.webp)
#### Context Menu
@@ -139,11 +146,24 @@ OSD console and status printed on the terminal.
Searchable key and mouse binding editor.
![Input Editor](docs/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](docs/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,4 +1,134 @@
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)
====================

View File

@@ -1,24 +0,0 @@
MIT License
Copyright (C) 2017-2021 mpv.net/mpv/mplayer
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.

View File

@@ -2,6 +2,8 @@
mpv.net manual
==============
**ENGLISH** | **[简体中文](Manual_chs.md)**
Table of contents
-----------------
@@ -42,49 +44,30 @@ 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 exe and a portable zip file download.
For internet streaming youtube-dl must be downloaded and installed manually,
meaning it must be located in the PATH environment variable or in the startup directory.
mpvnet.exe is platform agnostic, users that need x86 have to replace 4 native tools:
- Everything.dll
- mpv-1.dll
- MediaInfo.dll
- mpvnet.com
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 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](https://github.com/stax76/OpenWithPlusPlus#play-with-mpvnet) and
@@ -97,7 +80,7 @@ the files are opened in mpv.net in random order, this works with maximum 15 file
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.
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.
@@ -111,25 +94,11 @@ Settings
mpv.net searches the config folder at:
1. startup\portable_config
2. %APPDATA%\mpv.net
2. %APPDATA%\mpv.net (`C:\Users\%USERNAME%\AppData\Roaming\mpv.net`)
In order to use a custom directory create following file:
startup\settings-directory.txt
Put your custom directory in that file.
The custom directory path can be relative to the startup directory path.
This custom directory is only used if the portable_config and %APPDATA% directory does not exist.
mpv specific settings are stored in the file mpv.conf, if no mpv.conf file exists
mpv.net generates it with the following defaults:
[mpv.conf defaults](../../../tree/master/src/Resources/mpv.conf.txt)
mpv.net specific settings are stored in the file mpvnet.conf,
these options are documented [here](#mpvnet-specific-options).
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).
Input and context menu
@@ -140,10 +109,33 @@ input.conf file, if it's missing mpv.net generates it with the following default
[input.conf defaults](../../../tree/master/src/Resources/input.conf.txt)
Global hotkeys are supported via global-input.conf file.
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.
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
----------------------
@@ -204,9 +196,8 @@ Adds files to the playlist, requires [--process-instance=single](#--process-inst
#### --command=\<input command\>
Sends a input command. Useful to control mpv.net from the command line, for instance
to create global hotkeys with AutoHotkey, for that [process-instance=single](#--process-instancevalue)
must be used. Spaces have to be escaped with quotes and quotes have to be escaped with double quotes.
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
@@ -221,9 +212,6 @@ Save volume and mute on exit and restore it on start. Default: yes
Setting to remember the window size.
**video**
Window size is set to video resolution.
**width-session**
Width is remembered in the current session.
@@ -236,8 +224,14 @@ 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**
Size is always remembered.
Window size is always remembered.
#### --start-threshold=\<milliseconds\>
@@ -269,11 +263,6 @@ Can be suppressed via shift key. Default: yes
### General
#### --update-check=\<yes|no\>
Daily check for new version. (requires PowerShell 5 and curl.) Default: no
#### --process-instance=\<value\>
Defines if more then one mpv.net process is allowed.
@@ -370,6 +359,31 @@ Alternatively the Chrome/Firefox extension [Open With](../../../issues/119) can
[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).
### Universal Remote Android app
Universal Remote is Android remote control app which costs 5 €.
https://www.unifiedremote.com
https://play.google.com/store/apps/details?id=com.Relmtech.Remote
https://play.google.com/store/apps/details?id=com.Relmtech.RemotePaid
https://www.unifiedremote.com/tutorials/how-to-create-a-custom-keyboard-shortcuts-remote
https://www.unifiedremote.com/tutorials/how-to-install-a-custom-remote
[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
---------
@@ -549,29 +563,32 @@ features are supported that have an own implementation in mpv.net.
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
mpv.net has currently implemented the following window features:
**mpv.net has currently implemented the following window properties:**
- [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
@@ -593,8 +610,8 @@ need an own implementation in mpv.net, so far implemented are:
### 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, in the manual they are documented
[here](#mpvnet-specific-options).
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.
@@ -611,16 +628,10 @@ The Extension implementation is based on the
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.
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)
- [Everything, a fast file search service](https://www.voidtools.com)
Context Menu
@@ -633,7 +644,7 @@ If the input.conf file does not exists mpv.net generates it with the following d
<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
input.conf defines mpv's key and mouse bindings and mpv.net uses
comments to define the context menu.
@@ -661,20 +672,12 @@ 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).
For internet streaming youtube-dl must be downloaded and installed manually,
meaning it must be located in the PATH environment variable or in the startup directory.
### Open > Open DVD/Blu-ray Drive/Folder
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
@@ -1333,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)
@@ -1371,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.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

BIN
docs/img/InputEditor.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

BIN
docs/img/Main.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 603 KiB

After

Width:  |  Height:  |  Size: 536 KiB

BIN
docs/img/Playlist.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 355 KiB

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

File diff suppressed because it is too large Load Diff

View File

@@ -80,7 +80,7 @@ namespace RatingExtension // the assembly name must end with 'Extension'!
if (int.TryParse(args[1], out int rating))
{
string path = Core.get_property_string("path");
string path = Core.GetPropertyString("path");
if (!File.Exists(path))
return;
@@ -90,7 +90,7 @@ namespace RatingExtension // the assembly name must end with 'Extension'!
else
{
Dic[path] = rating;
Core.commandv("show-text", $"Rating: {rating}");
Core.CommandV("show-text", $"Rating: {rating}");
}
}
else if (args[1] == "about")
@@ -104,26 +104,26 @@ namespace RatingExtension // the assembly name must end with 'Extension'!
{
if (rating == 0)
{
FileToDelete = Core.get_property_string("path");
FileToDelete = Core.GetPropertyString("path");
DeleteTime = DateTime.Now;
Core.commandv("show-text", "Press 1 to delete file", "5000");
Core.CommandV("show-text", "Press 1 to delete file", "5000");
}
else
{
TimeSpan ts = DateTime.Now - DeleteTime;
string path = Core.get_property_string("path");
string path = Core.GetPropertyString("path");
if (FileToDelete == path && ts.TotalSeconds < 5 && File.Exists(FileToDelete))
{
Core.command("playlist-remove current");
int pos = Core.get_property_int("playlist-pos");
Core.Command("playlist-remove current");
int pos = Core.GetPropertyInt("playlist-pos");
if (pos == -1)
{
int count = Core.get_property_int("playlist-count");
int count = Core.GetPropertyInt("playlist-count");
if (count > 0)
Core.set_property_int("playlist-pos", count - 1);
Core.SetPropertyInt("playlist-pos", count - 1);
}
Thread.Sleep(2000);

View File

@@ -12,6 +12,8 @@ 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";
@@ -19,13 +21,13 @@ namespace mpvnet
public static string LightTheme { get; set; } = "light";
public static string StartSize { get; set; } = "height-session";
public static bool RememberWindowPosition { 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 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 UpdateCheck { 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;
@@ -34,9 +36,7 @@ namespace mpvnet
public static Extension Extension { get; set; }
public static bool IsDarkMode {
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
}
public static bool IsDarkMode => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
static AppSettings _Settings;
@@ -80,8 +80,8 @@ namespace mpvnet
InitTheme();
Core.Shutdown += Shutdown;
Core.Initialized += Initialized;
Core.Shutdown += Core_Shutdown;
Core.Initialized += Core_Initialized;
}
public static void InitTheme()
@@ -95,12 +95,26 @@ namespace mpvnet
themeContent,
Properties.Resources.theme,
IsDarkMode ? DarkTheme : LightTheme);
}
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");
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)
@@ -108,62 +122,81 @@ namespace mpvnet
Task.Run(() => {
try {
action.Invoke();
} catch (Exception e) {
}
catch (Exception e) {
ShowException(e);
}
});
}
public static string Version {
get {
return "Copyright (C) 2000-2021 mpv.net/mpv/mplayer\n" +
$"mpv.net {Application.ProductVersion} ({File.GetLastWriteTime(Application.ExecutablePath).ToShortDateString()})\n" +
$"{Core.get_property_string("mpv-version")} ({File.GetLastWriteTime(Folder.Startup + "mpv-1.dll").ToShortDateString()})\nffmpeg {Core.get_property_string("ffmpeg-version")}\nMIT License";
}
}
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 (IsStartedFromTerminal)
if (IsTerminalAttached)
Terminal.WriteError(obj.ToString());
else
{
if (obj is Exception e)
Msg.ShowException(e);
InvokeOnMainThread(() => Msg.ShowException(e));
else
Msg.ShowError(obj.ToString());
InvokeOnMainThread(() => Msg.ShowError(obj.ToString()));
}
}
public static void ShowError(string title, string msg = null)
public static void InvokeOnMainThread(Action action)
{
if (IsStartedFromTerminal)
{
if (title != null)
Terminal.WriteError(title);
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
Msg.ShowError(title, msg);
InvokeOnMainThread(() => Msg.ShowError(msg));
}
static void Initialized()
static void Core_Initialized()
{
if (RememberVolume)
{
Core.set_property_int("volume", Settings.Volume);
Core.set_property_string("mute", Settings.Mute);
Core.SetPropertyInt("volume", Settings.Volume);
Core.SetPropertyString("mute", Settings.Mute);
}
}
static void Shutdown()
static void Core_Shutdown()
{
Settings.Volume = Core.get_property_int("volume");
Settings.Mute = Core.get_property_string("mute");
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;
@@ -187,28 +220,37 @@ namespace mpvnet
{
switch (name)
{
case "remember-window-position": RememberWindowPosition = 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.ToInt(); return true;
case "recent-count": RecentCount = value.ToInt(); return true;
case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true;
case "dark-theme": DarkTheme = value.Trim('\'', '"'); return true;
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
case "video-file-extensions": CorePlayer.VideoTypes = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
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

@@ -1,12 +1,9 @@

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using Microsoft.CSharp;
@@ -28,7 +25,7 @@ namespace mpvnet
static void Execute(string file)
{
string code = File.ReadAllText(file);
string filename = Path.GetFileNameWithoutExtension(file) + " " + GetMD5(code) + ".dll";
string filename = Path.GetFileNameWithoutExtension(file) + " " + StringHelp.GetMD5Hash(code) + ".dll";
string outputFile = Path.Combine(Path.GetTempPath(), filename);
if (!File.Exists(outputFile))
@@ -70,15 +67,5 @@ namespace mpvnet
if (errors.Count() > 0)
Terminal.WriteError(string.Join(BR2, errors), Path.GetFileName(file));
}
static string GetMD5(string code)
{
using (MD5 md5 = MD5.Create())
{
byte[] inputBuffer = Encoding.UTF8.GetBytes(code);
byte[] hashBuffer = md5.ComputeHash(inputBuffer);
return BitConverter.ToString(md5.ComputeHash(inputBuffer)).Replace("-", "");
}
}
}
}

View File

@@ -1,68 +1,75 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows;
using VB = Microsoft.VisualBasic;
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 = null)
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("Command was removed, reset input.conf."); 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": ShowTextWithEditor("audio-device-list", Core.get_property_osd_string("audio-device-list")); break;
case "show-command-palette": ShowDialog(typeof(CommandPaletteWindow)); 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": ShowTextWithEditor("decoder-list", mpvHelp.GetDecoders()); break;
case "show-demuxers": ShowTextWithEditor("demuxer-lavf-list", mpvHelp.GetDemuxers()); 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": ShowTextWithEditor("input-key-list", Core.get_property_string("input-key-list").Replace(",", BR)); break;
case "show-media-search": ShowDialog(typeof(EverythingWindow)); 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": ShowTextWithEditor("profile-list", mpvHelp.GetProfiles()); break;
case "show-profiles": Msg.ShowInfo(mpvHelp.GetProfiles()); break;
case "show-progress": ShowProgress(); break;
case "show-properties": ShowProperties(); break;
case "show-protocols": ShowTextWithEditor("protocol-list", mpvHelp.GetProtocols()); break;
case "show-setup-dialog": ShowDialog(typeof(SetupWindow)); 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 "update-check": UpdateCheck.CheckOnline(true); break;
case "window-scale": WindowScale(float.Parse(args[0], CultureInfo.InvariantCulture)); break;
default: Msg.ShowError($"No command '{id}' found."); break;
default: Terminal.WriteError($"No command '{id}' found."); break;
}
}
public static void InvokeOnMainThread(Action action) => MainForm.Instance.BeginInvoke(action);
public static void ShowDialog(Type winType)
{
InvokeOnMainThread(new Action(() => {
App.InvokeOnMainThread(new Action(() => {
Window win = Activator.CreateInstance(winType) as Window;
new WindowInteropHelper(win).Owner = MainForm.Instance.Handle;
win.ShowDialog();
@@ -76,11 +83,14 @@ namespace mpvnet
foreach (string arg in args)
{
if (arg == "append") append = true;
if (arg == "no-folder") loadFolder = false;
if (arg == "append")
append = true;
if (arg == "no-folder")
loadFolder = false;
}
InvokeOnMainThread(new Action(() => {
App.InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog() { Multiselect = true })
if (d.ShowDialog() == DialogResult.OK)
Core.LoadFiles(d.FileNames, loadFolder, append);
@@ -89,47 +99,48 @@ namespace mpvnet
public static void Open_DVD_Or_BD_Folder()
{
InvokeOnMainThread(new Action(() => {
using (var dialog = new FolderBrowserDialog())
{
dialog.Description = "Select a DVD or Blu-ray folder.";
dialog.ShowNewFolderButton = false;
App.InvokeOnMainThread(new Action(() => {
var dialog = new FolderBrowser();
if (dialog.ShowDialog() == DialogResult.OK)
{
Core.command("stop");
Thread.Sleep(500);
if (Directory.Exists(dialog.SelectedPath + "\\BDMV"))
{
Core.set_property_string("bluray-device", dialog.SelectedPath);
Core.LoadFiles(new[] { @"bd://" }, false, false);
}
else
{
Core.set_property_string("dvd-device", dialog.SelectedPath);
Core.LoadFiles(new[] { @"dvd://" }, false, false);
}
}
}
if (dialog.Show())
Core.LoadDiskFolder(dialog.SelectedPath);
}));
}
public static void PlaylistFirst()
{
int pos = Core.get_property_int("playlist-pos");
int pos = Core.GetPropertyInt("playlist-pos");
if (pos != 0)
Core.set_property_int("playlist-pos", 0);
Core.SetPropertyInt("playlist-pos", 0);
}
public static void PlaylistLast()
{
int pos = Core.get_property_int("playlist-pos");
int count = Core.get_property_int("playlist-count");
int pos = Core.GetPropertyInt("playlist-pos");
int count = Core.GetPropertyInt("playlist-count");
if (pos < count - 1)
Core.set_property_int("playlist-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()
@@ -138,8 +149,8 @@ namespace mpvnet
ProcessHelp.ShellExecute(Core.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.") == DialogResult.OK)
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", "");
}
@@ -151,13 +162,13 @@ namespace mpvnet
{
string performer, title, album, genre, date, duration, text = "";
long fileSize = 0;
string path = Core.get_property_string("path");
string path = Core.GetPropertyString("path");
if (path.Contains("://"))
path = Core.get_property_string("media-title");
path = Core.GetPropertyString("media-title");
int width = Core.get_property_int("video-params/w");
int height = Core.get_property_int("video-params/h");
int width = Core.GetPropertyInt("video-params/w");
int height = Core.GetPropertyInt("video-params/h");
if (File.Exists(path))
{
@@ -175,15 +186,16 @@ namespace mpvnet
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";
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");
Core.CommandV("show-text", text, "5000");
return;
}
}
@@ -197,60 +209,75 @@ namespace mpvnet
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
"Type: " + path.Ext().ToUpper();
Core.commandv("show-text", text, "5000");
Core.CommandV("show-text", text, "5000");
return;
}
}
}
TimeSpan position = TimeSpan.FromSeconds(Core.get_property_number("time-pos"));
TimeSpan duration2 = TimeSpan.FromSeconds(Core.get_property_number("duration"));
string videoFormat = Core.get_property_string("video-format").ToUpper();
string audioCodec = Core.get_property_string("audio-codec-name").ToUpper();
string videoFormat = Core.GetPropertyString("video-format").ToUpper();
string audioCodec = Core.GetPropertyString("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";
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");
string FormatTime(double value) => ((int)value).ToString("00");
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()
{
InvokeOnMainThread(new Action(() => {
string clipboard = System.Windows.Forms.Clipboard.GetText();
if (string.IsNullOrEmpty(clipboard) || (!clipboard.Contains("://") && !File.Exists(clipboard)) ||
clipboard.Contains("\n"))
App.InvokeOnMainThread(new Action(() => {
if (WinForms.Clipboard.ContainsFileDropList())
{
App.ShowError("No URL found", "The clipboard does not contain a valid URL or file.");
return;
string[] files = WinForms.Clipboard.GetFileDropList().Cast<string>().ToArray();
Core.LoadFiles(files, false, Control.ModifierKeys.HasFlag(Keys.Control));
}
else
{
string clipboard = WinForms.Clipboard.GetText();
Core.LoadFiles(new [] { clipboard }, false, Control.ModifierKeys.HasFlag(Keys.Control));
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()
{
InvokeOnMainThread(new Action(() => {
App.InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog())
{
string path = Core.get_property_string("path");
string path = Core.GetPropertyString("path");
if (File.Exists(path))
d.InitialDirectory = Path.GetDirectoryName(path);
@@ -259,24 +286,26 @@ namespace mpvnet
if (d.ShowDialog() == DialogResult.OK)
foreach (string filename in d.FileNames)
Core.commandv("sub-add", filename);
Core.CommandV("sub-add", filename);
}
}));
}
public static void LoadAudio()
{
InvokeOnMainThread(new Action(() => {
App.InvokeOnMainThread(new Action(() => {
using (var d = new OpenFileDialog())
{
string path = Core.get_property_string("path");
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);
Core.CommandV("audio-add", i);
}
}));
}
@@ -288,59 +317,46 @@ namespace mpvnet
if (len < 1)
{
Core.commandv("show-text", "No audio tracks");
Core.CommandV("show-text", "No audio tracks");
return;
}
int aid = Core.get_property_int("aid");
int aid = Core.GetPropertyInt("aid");
if (len > 1)
{
if (++aid > len)
aid = 1;
Core.commandv("set", "aid", aid.ToString());
Core.CommandV("set", "aid", aid.ToString());
}
Core.commandv("show-text", aid + "/" + len + ": " + audioTracks[aid - 1].Text.Substring(3), "5000");
Core.CommandV("show-text", aid + "/" + len + ": " + audioTracks[aid - 1].Text.Substring(3), "5000");
}
public static void ShowCommands()
{
string code = @"
foreach ($item in ($json | ConvertFrom-Json | foreach { $_ } | sort name))
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>)
{
''
$item.name
string value = i2["name"].ToString() + " <" + i2["type"].ToString().ToLower() + ">";
foreach ($arg in $item.args)
{
$value = $arg.name + ' <' + $arg.type.ToLower() + '>'
if ((bool)i2["optional"] == true)
value = "[" + value + "]";
if ($arg.optional -eq $true)
{
$value = '[' + $value + ']'
}
sb.AppendLine(" " + value);
}
}
' ' + $value
}
}";
string json = Core.get_property_string("command-list");
ShowTextWithEditor("command-list", PowerShell.InvokeAndReturnString(code, "json", json));
}
public static void ShowProperties()
{
var props = Core.get_property_string("property-list").Split(',').OrderBy(prop => prop);
ShowTextWithEditor("property-list", string.Join(BR, props));
}
public static void ShowTextWithEditor(string name, string text)
{
string file = Path.GetTempPath() + $"\\{name}.txt";
File.WriteAllText(file, BR + text.Trim() + BR);
ProcessHelp.ShellExecute(file);
Msg.ShowInfo(sb.ToString());
}
public static void ScaleWindow(float factor) => Core.RaiseScaleWindow(factor);
@@ -353,30 +369,275 @@ namespace mpvnet
return;
if (duration == 0)
duration = Core.get_property_int("osd-duration");
duration = Core.GetPropertyInt("osd-duration");
if (fontSize == 0)
fontSize = Core.get_property_int("osd-font-size");
fontSize = Core.GetPropertyInt("osd-font-size");
Core.command("show-text \"${osd-ass-cc/0}{\\\\fs" + fontSize +
Core.Command("show-text \"${osd-ass-cc/0}{\\\\fs" + fontSize +
"}${osd-ass-cc/1}" + text + "\" " + duration);
}
public static void ShowPlaylist(string[] args = null)
public static void ShowMediaInfo(string[] args)
{
int duration = 5000;
string path = Core.GetPropertyString("path");
if (args?.Length == 1)
duration = Convert.ToInt32(args[0]);
var size = Core.get_property_number("osd-font-size");
Core.set_property_number("osd-font-size", 40);
Core.command("show-text ${playlist} " + duration);
App.RunTask(() => {
Thread.Sleep(6000);
Core.set_property_number("osd-font-size", size);
});
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();
});
}
}

69
src/Misc/Common.cs Normal file
View File

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

using System.Collections.Generic;
using System.Linq;
namespace mpvnet
{
public class StringPair
{
public string Name { get; set; }
public string Value { get; set; }
}
public class ConfParser
{
public static List<ConfSection> Parse(string content)
{
string[] lines = content.Split("\r\n".ToCharArray());
var sections = new List<ConfSection>();
ConfSection currentGroup = null;
foreach (string i in lines)
{
string line = i.Trim();
if (string.IsNullOrEmpty(line))
continue;
if (line.StartsWith("[") && line.EndsWith("]"))
{
currentGroup = new ConfSection() { Name = line.TrimStart('[').TrimEnd(']') };
sections.Add(currentGroup);
}
else if (line.Contains("="))
{
string name = line.Substring(0, line.IndexOf("=")).Trim();
string value = line.Substring(line.IndexOf("=") + 1).Trim();
currentGroup.Items.Add(new StringPair() { Name = name, Value = value });
}
}
return sections;
}
}
public class ConfSection
{
public string Name { get; set; }
public List<StringPair> Items { get; set; } = new List<StringPair>();
public bool HasName(string name)
{
foreach (var i in Items)
if (i.Name == name)
return true;
return false;
}
public string GetValue(string name)
{
foreach (var i in Items)
if (i.Name == name)
return i.Value;
return null;
}
public List<StringPair> GetValues(string name) => Items.Where(i => i.Name == name).ToList();
}
}

View File

@@ -1,49 +1,42 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Navigation;
using Tommy;
using mpvnet;
namespace DynamicGUI
namespace mpvnet
{
public class Settings
public class Conf
{
public static List<SettingBase> LoadSettings(string content)
public static List<SettingBase> LoadConf(string content)
{
TomlTable table;
List<SettingBase> settingsList = new List<SettingBase>();
using (StringReader reader = new StringReader(content))
table = TOML.Parse(reader);
List<SettingBase> settingsList = new List<SettingBase>();
foreach (TomlTable setting in table["settings"])
foreach (ConfSection section in ConfParser.Parse(content))
{
SettingBase baseSetting = null;
if (setting.HasKey("options"))
if (section.HasName("option"))
{
OptionSetting optionSetting = new OptionSetting();
baseSetting = optionSetting;
optionSetting.Default = setting["default"];
optionSetting.Default = section.GetValue("default");
optionSetting.Value = optionSetting.Default;
foreach (TomlTable option in setting["options"])
foreach (var i in section.GetValues("option"))
{
var opt = new OptionSettingOption();
opt.Name = option["name"];
if (option.HasKey("help"))
opt.Help = option["help"];
if (i.Value.Contains(" "))
{
opt.Name = i.Value.Substring(0, i.Value.IndexOf(" "));
opt.Help = i.Value.Substring(i.Value.IndexOf(" ")).Trim();
}
else
opt.Name = i.Value;
if (option.HasKey("text"))
opt.Text = option["text"];
else if (opt.Name == optionSetting.Default)
if (opt.Name == optionSetting.Default)
opt.Text = opt.Name + " (Default)";
opt.OptionSetting = optionSetting;
@@ -54,20 +47,24 @@ namespace DynamicGUI
{
StringSetting stringSetting = new StringSetting();
baseSetting = stringSetting;
stringSetting.Default = setting.HasKey("default") ? setting["default"].ToString() : "";
stringSetting.Default = section.HasName("default") ? section.GetValue("default") : "";
}
baseSetting.Name = setting["name"];
baseSetting.File = setting["file"];
baseSetting.Filter = setting["filter"];
baseSetting.Name = section.GetValue("name");
baseSetting.File = section.GetValue("file");
baseSetting.Filter = section.GetValue("filter");
if (setting.HasKey("help")) baseSetting.Help = setting["help"];
if (setting.HasKey("url")) baseSetting.URL = setting["url"];
if (setting.HasKey("width")) baseSetting.Width = setting["width"];
if (setting.HasKey("type")) baseSetting.Type = setting["type"];
if (section.HasName("help")) baseSetting.Help = section.GetValue("help");
if (section.HasName("url")) baseSetting.URL = section.GetValue("url");
if (section.HasName("width")) baseSetting.Width = Convert.ToInt32(section.GetValue("width"));
if (section.HasName("type")) baseSetting.Type = section.GetValue("type");
if (baseSetting.Help.ContainsEx("\\n"))
baseSetting.Help = baseSetting.Help.Replace("\\n", "\n");
settingsList.Add(baseSetting);
}
return settingsList;
}
}
@@ -155,11 +152,13 @@ namespace DynamicGUI
public void SetURL(string url)
{
if (string.IsNullOrEmpty(url)) return;
if (string.IsNullOrEmpty(url))
return;
NavigateUri = new Uri(url);
RequestNavigate += HyperLinkEx_RequestNavigate;
Inlines.Clear();
Inlines.Add(url);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using static mpvnet.Global;
@@ -22,25 +21,7 @@ namespace mpvnet
try
{
AggregateCatalog catalog = new AggregateCatalog();
string dir = Folder.Startup + "Extensions";
if (Directory.Exists(dir))
{
string[] knownExtensions = { "RatingExtension", "ScriptingExtension" };
foreach (string extDir in Directory.GetDirectories(dir))
{
if (knownExtensions.Contains(Path.GetFileName(extDir)))
catalog.Catalogs.Add(new DirectoryCatalog(extDir, Path.GetFileName(extDir) + ".dll"));
else
Terminal.WriteError("Failed to load extension:" + BR2 + extDir +
BR2 + "Only extensions that ship with mpv.net are allowed in <startup>\\extensions" +
BR2 + "User extensions have to use <config folder>\\extensions" +
BR2 + "Never copy or install a new mpv.net version over a old mpv.net version.");
}
}
dir = Core.ConfigFolder + "extensions";
string dir = Core.ConfigFolder + "extensions";
if (Directory.Exists(dir))
foreach (string extDir in Directory.GetDirectories(dir))

View File

@@ -1,6 +1,7 @@

using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
public static class TestStringExtension
{
@@ -67,7 +68,7 @@ public static class ConvertStringExtension
public static class PathStringExtension
{
// return extension with lower case and without dot.
// returns the extension with lower case and without preceding dot.
public static string Ext(this string instance)
{
if (instance == null)
@@ -94,6 +95,17 @@ public static class PathStringExtension
return instance;
}
public static string ShortPath(this string instance, int maxLength)
{
if (string.IsNullOrEmpty(instance))
return "";
if (instance.Length > maxLength && instance.Substring(1, 2) == ":\\")
instance = instance.Substring(0, 3) + "...\\" + instance.FileName();
return instance;
}
// Ensure trailing directory separator char
public static string AddSep(this string instance)
{
@@ -105,12 +117,4 @@ public static class PathStringExtension
return instance;
}
public static bool IsIdenticalFolder(this string instance, string testFolder)
{
if (string.IsNullOrEmpty(instance) || string.IsNullOrEmpty(testFolder))
return false;
return instance.ToLowerInvariant().AddSep() == testFolder.ToLowerInvariant().AddSep();
}
}

124
src/Misc/FolderBrowser.cs Normal file
View File

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

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace mpvnet
{
public class FolderBrowser
{
public string SelectedPath { get; set; }
string _initialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
public string InitialDirectory {
get => _initialDirectory;
set {
if (Directory.Exists(value))
_initialDirectory = value;
}
}
public bool Show() => Show(GetOwnerHandle());
public bool Show(IntPtr hWndOwner)
{
ShowDialogResult result = VistaDialog.Show(hWndOwner, InitialDirectory);
if (result.Result)
SelectedPath = result.FileName;
return result.Result;
}
struct ShowDialogResult
{
public bool Result { get; set; }
public string FileName { get; set; }
}
public static IntPtr GetOwnerHandle()
{
IntPtr foregroundWindow = GetForegroundWindow();
GetWindowThreadProcessId(foregroundWindow, out var procID);
using (var proc = Process.GetCurrentProcess())
if (proc.Id == procID)
return foregroundWindow;
return IntPtr.Zero;
}
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
static class VistaDialog
{
const string foldersFilter = "Folders|\n";
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
static Assembly windowsFormsAssembly = typeof(FileDialog).Assembly;
static Type iFileDialogType = windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
static MethodInfo createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", flags);
static MethodInfo onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", flags);
static MethodInfo getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", flags);
static MethodInfo setOptionsMethodInfo = iFileDialogType.GetMethod("SetOptions", flags);
static uint fosPickFoldersBitFlag = (uint)windowsFormsAssembly
.GetType("System.Windows.Forms.FileDialogNative+FOS")
.GetField("FOS_PICKFOLDERS")
.GetValue(null);
static ConstructorInfo vistaDialogEventsConstructorInfo = windowsFormsAssembly
.GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
.GetConstructor(flags, null, new[] { typeof(FileDialog) }, null);
static MethodInfo adviseMethodInfo = iFileDialogType.GetMethod("Advise");
static MethodInfo unAdviseMethodInfo = iFileDialogType.GetMethod("Unadvise");
static MethodInfo showMethodInfo = iFileDialogType.GetMethod("Show");
public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory)
{
var openFileDialog = new OpenFileDialog
{
AddExtension = false,
CheckFileExists = false,
DereferenceLinks = true,
Filter = foldersFilter,
InitialDirectory = initialDirectory,
Multiselect = false,
};
var iFileDialog = createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint)getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | fosPickFoldersBitFlag });
var adviseParametersWithOutputConnectionToken = new[] { vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);
try
{
int retVal = (int)showMethodInfo.Invoke(iFileDialog, new object[] { ownerHandle });
return new ShowDialogResult
{
Result = retVal == 0,
FileName = openFileDialog.FileName
};
}
finally
{
unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
}
}
}
class WindowWrapper : IWin32Window
{
IntPtr _handle;
public WindowWrapper(IntPtr handle) { _handle = handle; }
public IntPtr Handle => _handle;
}
}
}

View File

@@ -46,10 +46,10 @@ namespace mpvnet
{
string umod = parts[i].ToUpper();
if (umod == "ALT") mod |= KeyModifiers.Alt;
if (umod == "CTRL") mod |= KeyModifiers.Ctrl;
if (umod == "ALT") mod |= KeyModifiers.Alt;
if (umod == "CTRL") mod |= KeyModifiers.Ctrl;
if (umod == "SHIFT") mod |= KeyModifiers.Shift;
if (umod == "WIN") mod |= KeyModifiers.Win;
if (umod == "WIN") mod |= KeyModifiers.Win;
}
key = parts[parts.Length - 1];
@@ -61,9 +61,6 @@ namespace mpvnet
int hi = result >> 8;
int lo = result & 0xFF;
if (lo == -1)
return;
vk = lo;
if ((hi & 1) == 1) mod |= KeyModifiers.Shift;
@@ -89,7 +86,7 @@ namespace mpvnet
public static void Execute(int id)
{
if (Commands.ContainsKey(id))
Core.command(Commands[id]);
Core.Command(Commands[id]);
}
static int mpv_to_VK(string value)

View File

@@ -1,8 +1,12 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
@@ -11,6 +15,32 @@ using static mpvnet.Global;
namespace mpvnet
{
public static class StringHelp
{
public static string GetMD5Hash(string txt)
{
using (MD5 md5 = MD5.Create())
{
byte[] inputBuffer = Encoding.UTF8.GetBytes(txt);
byte[] hashBuffer = md5.ComputeHash(inputBuffer);
return BitConverter.ToString(md5.ComputeHash(inputBuffer)).Replace("-", "");
}
}
}
public static class FileHelp
{
public static void Delete(string path)
{
try {
if (File.Exists(path))
File.Delete(path);
} catch (Exception ex) {
Terminal.WriteError("Failed to delete file:" + BR + path + BR + ex.Message);
}
}
}
public static class ProcessHelp
{
public static void Execute(string file, string arguments = null)
@@ -60,9 +90,8 @@ namespace mpvnet
public static bool IsPosDifferent(Point screenPos)
{
return
Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
return Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
}
}
@@ -70,45 +99,44 @@ namespace mpvnet
{
public static string GetProfiles()
{
string code = @"
foreach ($item in ($json | ConvertFrom-Json | foreach { $_ } | sort name))
{
$item.name
''
string json = Core.GetPropertyString("profile-list");
var o = json.FromJson<List<Dictionary<string, object>>>().OrderBy(i => i["name"]);
StringBuilder sb = new StringBuilder();
foreach ($option in $item.options)
{
' ' + $option.key + ' = ' + $option.value
}
foreach (Dictionary<string, object> i in o)
{
sb.Append(i["name"].ToString() + BR2);
''
}";
foreach (Dictionary<string, object> i2 in i["options"] as List<object>)
sb.AppendLine(" " + i2["key"] + " = " + i2["value"]);
string json = Core.get_property_string("profile-list");
return PowerShell.InvokeAndReturnString(code, "json", json).Trim();
sb.Append(BR);
}
return sb.ToString();
}
public static string GetDecoders()
{
string code = @"
foreach ($item in ($json | ConvertFrom-Json | foreach { $_ } | sort codec))
{
$item.codec + ' - ' + $item.description
}";
{
string json = Core.GetPropertyString("decoder-list");
var o = json.FromJson<List<Dictionary<string, object>>>().OrderBy(i => i["codec"]);
StringBuilder sb = new StringBuilder();
string json = Core.get_property_string("decoder-list");
return PowerShell.InvokeAndReturnString(code, "json", json).Trim();
foreach (Dictionary<string, object> i in o)
sb.AppendLine(i["codec"] + " - " + i["description"]);
return sb.ToString();
}
public static string GetProtocols()
{
string list = Core.get_property_string("protocol-list");
string list = Core.GetPropertyString("protocol-list");
return string.Join(BR, list.Split(',').OrderBy(a => a));
}
public static string GetDemuxers()
{
string list = Core.get_property_string("demuxer-lavf-list");
string list = Core.GetPropertyString("demuxer-lavf-list");
return string.Join(BR, list.Split(',').OrderBy(a => a));
}
}

415
src/Misc/JSONParser.cs Normal file
View File

@@ -0,0 +1,415 @@

// https://github.com/zanders3/json
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
namespace mpvnet
{
public static class JSONParser
{
[ThreadStatic] static Stack<List<string>> splitArrayPool;
[ThreadStatic] static StringBuilder stringBuilder;
[ThreadStatic] static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache;
[ThreadStatic] static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache;
public static T FromJson<T>(this string json)
{
// Initialize, if needed, the ThreadStatic variables
if (propertyInfoCache == null)
propertyInfoCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();
if (fieldInfoCache == null)
fieldInfoCache = new Dictionary<Type, Dictionary<string, FieldInfo>>();
if (stringBuilder == null)
stringBuilder = new StringBuilder();
if (splitArrayPool == null)
splitArrayPool = new Stack<List<string>>();
//Remove all whitespace not within strings to make parsing simpler
stringBuilder.Length = 0;
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
if (c == '"')
{
i = AppendUntilStringEnd(true, i, json);
continue;
}
if (char.IsWhiteSpace(c))
continue;
stringBuilder.Append(c);
}
//Parse the thing!
return (T)ParseValue(typeof(T), stringBuilder.ToString());
}
static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
{
stringBuilder.Append(json[startIdx]);
for (int i = startIdx + 1; i < json.Length; i++)
{
if (json[i] == '\\')
{
if (appendEscapeCharacter)
stringBuilder.Append(json[i]);
stringBuilder.Append(json[i + 1]);
i++;//Skip next character as it is escaped
}
else if (json[i] == '"')
{
stringBuilder.Append(json[i]);
return i;
}
else
stringBuilder.Append(json[i]);
}
return json.Length - 1;
}
//Splits { <value>:<value>, <value>:<value> } and [ <value>, <value> ] into a list of <value> strings
static List<string> Split(string json)
{
List<string> splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List<string>();
splitArray.Clear();
if (json.Length == 2)
return splitArray;
int parseDepth = 0;
stringBuilder.Length = 0;
for (int i = 1; i < json.Length - 1; i++)
{
switch (json[i])
{
case '[':
case '{':
parseDepth++;
break;
case ']':
case '}':
parseDepth--;
break;
case '"':
i = AppendUntilStringEnd(true, i, json);
continue;
case ',':
case ':':
if (parseDepth == 0)
{
splitArray.Add(stringBuilder.ToString());
stringBuilder.Length = 0;
continue;
}
break;
}
stringBuilder.Append(json[i]);
}
splitArray.Add(stringBuilder.ToString());
return splitArray;
}
internal static object ParseValue(Type type, string json)
{
if (type == typeof(string))
{
if (json.Length <= 2)
return string.Empty;
StringBuilder parseStringBuilder = new StringBuilder(json.Length);
for (int i = 1; i < json.Length - 1; ++i)
{
if (json[i] == '\\' && i + 1 < json.Length - 1)
{
int j = "\"\\nrtbf/".IndexOf(json[i + 1]);
if (j >= 0)
{
parseStringBuilder.Append("\"\\\n\r\t\b\f/"[j]);
++i;
continue;
}
if (json[i + 1] == 'u' && i + 5 < json.Length - 1)
{
uint c = 0;
if (uint.TryParse(json.Substring(i + 2, 4), System.Globalization.NumberStyles.AllowHexSpecifier, null, out c))
{
parseStringBuilder.Append((char)c);
i += 5;
continue;
}
}
}
parseStringBuilder.Append(json[i]);
}
return parseStringBuilder.ToString();
}
if (type.IsPrimitive)
{
var result = Convert.ChangeType(json, type, System.Globalization.CultureInfo.InvariantCulture);
return result;
}
if (type == typeof(decimal))
{
decimal result;
decimal.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result);
return result;
}
if (json == "null")
return null;
if (type.IsEnum)
{
if (json[0] == '"')
json = json.Substring(1, json.Length - 2);
try
{
return Enum.Parse(type, json, false);
}
catch
{
return 0;
}
}
if (type.IsArray)
{
Type arrayType = type.GetElementType();
if (json[0] != '[' || json[json.Length - 1] != ']')
return null;
List<string> elems = Split(json);
Array newArray = Array.CreateInstance(arrayType, elems.Count);
for (int i = 0; i < elems.Count; i++)
newArray.SetValue(ParseValue(arrayType, elems[i]), i);
splitArrayPool.Push(elems);
return newArray;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type listType = type.GetGenericArguments()[0];
if (json[0] != '[' || json[json.Length - 1] != ']')
return null;
List<string> elems = Split(json);
var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count });
for (int i = 0; i < elems.Count; i++)
list.Add(ParseValue(listType, elems[i]));
splitArrayPool.Push(elems);
return list;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type keyType, valueType;
{
Type[] args = type.GetGenericArguments();
keyType = args[0];
valueType = args[1];
}
//Refuse to parse dictionary keys that aren't of type string
if (keyType != typeof(string))
return null;
//Must be a valid dictionary element
if (json[0] != '{' || json[json.Length - 1] != '}')
return null;
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return null;
var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 });
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
continue;
string keyValue = elems[i].Substring(1, elems[i].Length - 2);
object val = ParseValue(valueType, elems[i + 1]);
dictionary[keyValue] = val;
}
return dictionary;
}
if (type == typeof(object))
return ParseAnonymousValue(json);
if (json[0] == '{' && json[json.Length - 1] == '}')
return ParseObject(type, json);
return null;
}
static object ParseAnonymousValue(string json)
{
if (json.Length == 0)
return null;
if (json[0] == '{' && json[json.Length - 1] == '}')
{
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return null;
var dict = new Dictionary<string, object>(elems.Count / 2);
for (int i = 0; i < elems.Count; i += 2)
dict[elems[i].Substring(1, elems[i].Length - 2)] = ParseAnonymousValue(elems[i + 1]);
return dict;
}
if (json[0] == '[' && json[json.Length - 1] == ']')
{
List<string> items = Split(json);
var finalList = new List<object>(items.Count);
for (int i = 0; i < items.Count; i++)
finalList.Add(ParseAnonymousValue(items[i]));
return finalList;
}
if (json[0] == '"' && json[json.Length - 1] == '"')
{
string str = json.Substring(1, json.Length - 2);
return str.Replace("\\", string.Empty);
}
if (char.IsDigit(json[0]) || json[0] == '-')
{
if (json.Contains("."))
{
double result;
double.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out result);
return result;
}
else
{
int result;
int.TryParse(json, out result);
return result;
}
}
if (json == "true")
return true;
if (json == "false")
return false;
// handles json == "null" as well as invalid JSON
return null;
}
static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members) where T : MemberInfo
{
Dictionary<string, T> nameToMember = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < members.Length; i++)
{
T member = members[i];
if (member.IsDefined(typeof(IgnoreDataMemberAttribute), true))
continue;
string name = member.Name;
if (member.IsDefined(typeof(DataMemberAttribute), true))
{
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true);
if (!string.IsNullOrEmpty(dataMemberAttribute.Name))
name = dataMemberAttribute.Name;
}
nameToMember.Add(name, member);
}
return nameToMember;
}
static object ParseObject(Type type, string json)
{
object instance = FormatterServices.GetUninitializedObject(type);
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
return instance;
Dictionary<string, FieldInfo> nameToField;
Dictionary<string, PropertyInfo> nameToProperty;
if (!fieldInfoCache.TryGetValue(type, out nameToField))
{
nameToField = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
fieldInfoCache.Add(type, nameToField);
}
if (!propertyInfoCache.TryGetValue(type, out nameToProperty))
{
nameToProperty = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
propertyInfoCache.Add(type, nameToProperty);
}
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
continue;
string key = elems[i].Substring(1, elems[i].Length - 2);
string value = elems[i + 1];
FieldInfo fieldInfo;
PropertyInfo propertyInfo;
if (nameToField.TryGetValue(key, out fieldInfo))
fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value));
else if (nameToProperty.TryGetValue(key, out propertyInfo))
propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null);
}
return instance;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -48,9 +48,9 @@ namespace mpvnet
{
switch (value)
{
case 5: return "SEARCH"; // BROWSER_SEARCH
case 6: return "FAVORITES"; // BROWSER_FAVORITES
case 7: return "HOMEPAGE"; // BROWSER_HOME
case 5: return "SEARCH"; // BROWSER_SEARCH
case 6: return "FAVORITES"; // BROWSER_FAVORITES
case 7: return "HOMEPAGE"; // BROWSER_HOME
case 15: return "MAIL"; // LAUNCH_MAIL
case 33: return "PRINT"; // PRINT
case 11: return "NEXT"; // MEDIA_NEXTTRACK
@@ -75,38 +75,59 @@ namespace mpvnet
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)
public static void Register(string perceivedType, string[] extensions)
{
Types = types;
string[] protocols = { "ytdl", "rtsp", "srt", "srtp" };
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)
if (perceivedType != "unreg")
{
RegistryHelp.SetValue($@"HKCR\Applications\{ExeFilename}\SupportedTypes", "." + ext, "");
RegistryHelp.SetValue($@"HKCR\" + "." + ext, null, ExeFilenameNoExt + "." + ext);
RegistryHelp.SetValue($@"HKCR\" + "." + ext + @"\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, "");
foreach (string i in protocols)
{
RegistryHelp.SetValue($@"HKCR\{i}", $"{i.ToUpper()} Protocol", "");
RegistryHelp.SetValue($@"HKCR\{i}\shell\open\command", null, $"\"{ExePath}\" \"%1\"");
}
if (CorePlayer.VideoTypes.Contains(ext))
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "video");
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(@"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");
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");
if (CorePlayer.AudioTypes.Contains(ext))
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "audio");
foreach (string ext in extensions)
{
RegistryHelp.SetValue(@"HKCR\Applications\" + ExeFilename + @"\SupportedTypes", "." + ext, "");
RegistryHelp.SetValue(@"HKCR\" + "." + ext, null, ExeFilenameNoExt + "." + ext);
RegistryHelp.SetValue(@"HKCR\" + "." + ext + @"\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, "");
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", perceivedType);
RegistryHelp.SetValue(@"HKCR\" + ExeFilenameNoExt + "." + ext + @"\shell\open\command", null, $"\"{ExePath}\" \"%1\"");
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext);
}
}
else
{
foreach (string i in protocols)
RegistryHelp.RemoveKey($@"HKCR\{i}");
if (CorePlayer.ImageTypes.Contains(ext))
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "image");
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");
RegistryHelp.SetValue($@"HKCR\" + ExeFilenameNoExt + "." + ext + @"\shell\open\command", null, $"\"{ExePath}\" \"%1\"");
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext);
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);
}
}
}
}
@@ -208,24 +229,38 @@ namespace mpvnet
{
public static string Startup { get; } = Application.StartupPath.AddSep();
public static string AppData { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).AddSep();
}
public static string CustomSettings {
get {
string linkFile = Startup + "settings-directory.txt";
public class CommandPaletteItem
{
public CommandPaletteItem() {}
if (File.Exists(linkFile))
{
string linkTarget = File.ReadAllText(linkFile).Trim();
public CommandPaletteItem(string text, Action action)
{
Text = text;
Action = action;
}
if (linkTarget.StartsWithEx("."))
linkTarget = Startup + linkTarget;
public string Text { get; set; } = "";
public string SecondaryText { get; set; } = "";
public Action Action { get; set; }
public CommandItem CommandItem { get; set; }
}
if (Directory.Exists(linkTarget))
return linkTarget.AddSep();
}
public class CommandPalette
{
public static CommandPaletteControl Instance { get; } = new CommandPaletteControl();
return "";
}
public static IEnumerable<CommandPaletteItem> GetItems()
{
return CommandItem.Items
.Where(i => i.Command != "")
.Select(i => new CommandPaletteItem() {
Text = i.Display,
SecondaryText = i.Input,
Action = () => Core.Command(i.Command),
CommandItem = i
});
}
}
}

View File

@@ -1,41 +1,49 @@

using System;
using System.Windows.Forms;
using System.Threading;
using System.Windows;
using static mpvnet.Global;
using WinForms = System.Windows.Forms;
using MsgBoxEx;
public class Msg
{
public static void ShowInfo(object title, object content = null)
{
Show(title, content, MessageBoxIcon.Information);
}
public static void ShowInfo(object msg) => Show(msg, MessageBoxImage.Information);
public static void ShowError(object title, object content = null)
{
Show(title, content, MessageBoxIcon.Error);
}
public static void ShowError(object msg) => Show(msg, MessageBoxImage.Error);
public static void ShowWarning(object title, object content = null)
{
Show(title, content, MessageBoxIcon.Warning);
}
public static void ShowWarning(object msg) => Show(msg, MessageBoxImage.Warning);
public static DialogResult ShowQuestion(object title, object content = null,
MessageBoxButtons buttons = MessageBoxButtons.OKCancel)
public static MessageBoxResult ShowQuestion(object msg,
MessageBoxButton buttons = MessageBoxButton.OKCancel)
{
return Show(title, content, MessageBoxIcon.Question, buttons);
return Show(msg, MessageBoxImage.Question, buttons);
}
public static void ShowException(Exception exception)
{
Show(exception, null, MessageBoxIcon.Error);
Show(exception.Message, MessageBoxImage.Error, MessageBoxButton.OK, exception.ToString());
}
public static DialogResult Show(object title, object content, MessageBoxIcon icon,
MessageBoxButtons buttons = MessageBoxButtons.OK)
public static MessageBoxResult Show(
object msg,
MessageBoxImage img,
MessageBoxButton buttons = MessageBoxButton.OK,
string details = null)
{
string msg = (title?.ToString().TrimEx() + BR2 + content?.ToString().TrimEx()).Trim();
return MessageBox.Show(msg, Application.ProductName, buttons, icon);
MessageBoxResult fn()
{
MessageBoxEx.DetailsText = details;
return MessageBoxEx.OpenMessageBox((msg ?? "").ToString().Trim(),
WinForms.Application.ProductName, buttons, img);
}
ApartmentState state = Thread.CurrentThread.GetApartmentState();
if (state == ApartmentState.STA)
return fn();
else
return Application.Current.Dispatcher.Invoke(fn);
}
}

View File

@@ -58,7 +58,7 @@ namespace mpvnet
Pipeline.Output.DataReady += Output_DataReady;
Pipeline.Error.DataReady += Error_DataReady;
}
return Pipeline.Invoke();
}
catch (RuntimeException e)
@@ -94,7 +94,7 @@ namespace mpvnet
public void Error_DataReady(object sender, EventArgs e)
{
var output = sender as PipelineReader<Object>;
var output = sender as PipelineReader<object>;
while (output.Count > 0)
Terminal.WriteError(output.Read(), Module);
@@ -109,54 +109,59 @@ namespace mpvnet
}
}
public void commandv(params string[] args) => Core.commandv(args);
public void CommandV(params string[] args) => Core.CommandV(args);
public void command(string command) => Core.command(command);
public void Command(string command) => Core.Command(command);
public bool get_property_bool(string name) => Core.get_property_bool(name);
public bool GetPropertyBool(string name) => Core.GetPropertyBool(name);
public void set_property_bool(string name, bool value) => Core.set_property_bool(name, value);
public void SetPropertyBool(string name, bool value) => Core.SetPropertyBool(name, value);
public int get_property_int(string name) => Core.get_property_int(name);
public int GetPropertyInt(string name) => Core.GetPropertyInt(name);
public void set_property_int(string name, int value) => Core.set_property_int(name, value);
public void SetPropertyInt(string name, int value) => Core.SetPropertyInt(name, value);
public double get_property_number(string name) => Core.get_property_number(name);
public double GetPropertyDouble(string name) => Core.GetPropertyDouble(name);
public void set_property_number(string name, double value) => Core.set_property_number(name, value);
public void SetPropertyDouble(string name, double value) => Core.SetPropertyDouble(name, value);
public string get_property_string(string name) => Core.get_property_string(name);
public string GetPropertyString(string name) => Core.GetPropertyString(name);
public void set_property_string(string name, string value) => Core.set_property_string(name, value);
public void SetPropertyString(string name, string value) => Core.SetPropertyString(name, value);
public void observe_property(string name, string type, ScriptBlock sb)
public void ObserveProperty(string name, string type, ScriptBlock sb)
{
PropChangedHandlers.Add(new KeyValuePair<string, ScriptBlock>(name, sb));
switch (type)
{
case "bool": case "boolean":
Core.observe_property_bool(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
Core.ObservePropertyBool(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
break;
case "string":
Core.observe_property_string(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
Core.ObservePropertyString(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
break;
case "int": case "integer":
Core.observe_property_int(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
Core.ObservePropertyInt(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
break;
case "float": case "double":
Core.observe_property_double(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
Core.ObservePropertyDouble(name, value => App.RunTask(() => PropertyChanged.Invoke(name, value)));
break;
case "nil": case "none": case "native":
Core.observe_property(name, () => App.RunTask(() => PropertyChanged.Invoke(name, null)));
Core.ObserveProperty(name, () => App.RunTask(() => PropertyChanged.Invoke(name, null)));
break;
default:
App.ShowError("Invalid Type", "Valid types are: bool or boolean, string, int or integer, float or double, nil or none or native");
App.ShowError("Invalid Type, valid types are: bool or boolean, string, int or integer, float or double, nil or none or native");
break;
}
}
public void register_event(string name, ScriptBlock sb)
public void RegisterEvent(string name, ScriptBlock sb)
{
EventHandlers.Add(new KeyValuePair<string, ScriptBlock>(name, sb));
@@ -198,10 +203,6 @@ namespace mpvnet
Core.FileLoadedAsync += () => Event.Invoke("file-loaded", null);
break;
case "idle":
Core.IdleAsync += () => Event.Invoke("idle", null);
break;
case "video-reconfig":
Core.VideoReconfigAsync += () => Event.Invoke("video-reconfig", null);
break;

View File

@@ -18,27 +18,19 @@ namespace mpvnet
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (App.IsStartedFromTerminal)
if (App.IsTerminalAttached)
Native.AttachConsole(-1 /*ATTACH_PARENT_PROCESS*/);
string[] args = Environment.GetCommandLineArgs().Skip(1).ToArray();
if (args.Length >= 2 && args[0] == "--reg-file-assoc")
if (args.Length > 0 && args[0] == "--register-file-associations")
{
if (args[1] == "audio")
FileAssociation.Register(CorePlayer.AudioTypes);
else if (args[1] == "video")
FileAssociation.Register(CorePlayer.VideoTypes);
else if (args[1] == "image")
FileAssociation.Register(CorePlayer.ImageTypes);
else
FileAssociation.Register(args.Skip(1).ToArray());
FileAssociation.Register(args[1], args.Skip(1).ToArray());
return;
}
App.Init();
Mutex mutex = new Mutex(true, "mpvnetProcessInstance", out bool isFirst);
Mutex mutex = new Mutex(true, StringHelp.GetMD5Hash(App.ConfPath), out bool isFirst);
if ((App.ProcessInstance == "single" || App.ProcessInstance == "queue") && !isFirst)
{
@@ -75,7 +67,7 @@ namespace mpvnet
Native.SendMessage(proc.MainWindowHandle, 0x004A /*WM_COPYDATA*/, IntPtr.Zero, ref data);
mutex.Dispose();
if (App.IsStartedFromTerminal)
if (App.IsTerminalAttached)
Native.FreeConsole();
return;
@@ -91,7 +83,7 @@ namespace mpvnet
Application.Run(new MainForm());
if (App.IsStartedFromTerminal)
if (App.IsTerminalAttached)
Native.FreeConsole();
mutex.Dispose();

View File

@@ -14,6 +14,7 @@ namespace mpvnet
[Serializable()]
public class AppSettings
{
public bool InputDefaultBindingsFixApplied;
public int LastUpdateCheck;
public int Volume = 70;
public List<string> RecentFiles = new List<string>();
@@ -27,29 +28,42 @@ namespace mpvnet
class SettingsManager
{
public static string SettingsFile {
get => Core.ConfigFolder + "settings.xml";
}
public static string SettingsFile => Core.ConfigFolder + "settings.xml";
public static AppSettings Load()
{
if (!File.Exists(SettingsFile))
return new AppSettings();
XmlSerializer serializer = new XmlSerializer(typeof(AppSettings));
try
{
XmlSerializer serializer = new XmlSerializer(typeof(AppSettings));
using (FileStream fs = new FileStream(SettingsFile, FileMode.Open))
return (AppSettings)serializer.Deserialize(fs);
using (FileStream fs = new FileStream(SettingsFile, FileMode.Open))
return (AppSettings)serializer.Deserialize(fs);
}
catch (Exception ex)
{
Terminal.WriteError(ex.ToString());
return new AppSettings();
}
}
public static void Save(object obj)
{
using (XmlTextWriter writer = new XmlTextWriter(SettingsFile, Encoding.UTF8))
try
{
writer.Formatting = Formatting.Indented;
writer.Indentation = 4;
XmlSerializer serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(writer, obj);
using (XmlTextWriter writer = new XmlTextWriter(SettingsFile, Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
writer.Indentation = 4;
XmlSerializer serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(writer, obj);
}
}
catch (Exception ex)
{
Terminal.WriteError(ex.ToString());
}
}
}

View File

@@ -14,21 +14,20 @@ namespace mpvnet
public static Theme Current { get; set; }
public Brush Background { get; set; }
public Brush Foreground { get; set; }
public Brush Foreground2 { get; set; }
public Brush Background { get; set; }
public Brush Heading { get; set; }
public System.Drawing.Color GetWinFormsColor(string key)
{
return System.Drawing.ColorTranslator.FromHtml(Dictionary[key]);
}
public Brush MenuBackground { get; set; }
public Brush MenuHighlight { get; set; }
public Brush GetBrush(string key)
{
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(Dictionary[key]));
}
public Color GetColor(string key) => (Color)ColorConverter.ConvertFromString(Dictionary[key]);
public static void Init(string customContent, string defaultContent, string activeTheme)
{
Current = null;
@@ -67,10 +66,12 @@ namespace mpvnet
if (Current == null)
Current = DefaultThemes[0];
Current.Background = Current.GetBrush("background");
Current.Foreground = Current.GetBrush("foreground");
Current.Foreground2 = Current.GetBrush("foreground2");
Current.Background = Current.GetBrush("background");
Current.Heading = Current.GetBrush("heading");
Current.MenuBackground = Current.GetBrush("menu-background");
Current.MenuHighlight = Current.GetBrush("menu-highlight");
}
static List<Theme> Load(string content)

View File

@@ -1,84 +0,0 @@

using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using static mpvnet.Global;
namespace mpvnet
{
class UpdateCheck
{
public static void DailyCheck()
{
if (App.UpdateCheck && App.Settings.LastUpdateCheck != DateTime.Now.DayOfYear)
CheckOnline();
}
public static async void CheckOnline(bool showUpToDateMessage = false)
{
try
{
using (HttpClient client = new HttpClient())
{
App.Settings.LastUpdateCheck = 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-([\d\.]+)-portable\.zip""");
if (!match.Success)
{
App.ShowError("Update check is currently not available.");
return;
}
Version onlineVersion = Version.Parse(match.Groups[1].Value);
Version currentVersion = Assembly.GetEntryAssembly().GetName().Version;
if (onlineVersion <= currentVersion)
{
if (showUpToDateMessage)
Msg.ShowInfo($"{Application.ProductName} is up to date.");
return;
}
if ((App.Settings.UpdateCheckVersion != onlineVersion.ToString() ||
showUpToDateMessage) && Msg.ShowQuestion(
$"New version {onlineVersion} is available, update now?") == DialogResult.OK)
{
string url = $"https://github.com/stax76/mpv.net/releases/download/{onlineVersion}/mpv.net-{onlineVersion}-portable.zip";
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
proc.StartInfo.FileName = "powershell.exe";
proc.StartInfo.Arguments = $"-NoExit -ExecutionPolicy Bypass -File \"{Folder.Startup + "Setup\\update.ps1"}\" \"{url}\" \"{Folder.Startup.TrimEnd(Path.DirectorySeparatorChar)}\"";
if (Folder.Startup.Contains("Program Files"))
proc.StartInfo.Verb = "runas";
proc.Start();
}
Core.command("quit");
}
App.Settings.UpdateCheckVersion = onlineVersion.ToString();
}
}
catch (Exception ex)
{
if (showUpToDateMessage)
App.ShowException(ex);
}
}
}
}

View File

@@ -41,6 +41,13 @@ public class MediaInfo : IDisposable
stream, parameter, MediaInfoKind.Text, MediaInfoKind.Name));
}
public string GetSummary(bool complete, bool rawView)
{
MediaInfo_Option(Handle, "Language", rawView ? "raw" : "");
MediaInfo_Option(Handle, "Complete", complete ? "1" : "0");
return Marshal.PtrToStringUni(MediaInfo_Inform(Handle, 0)) ?? "";
}
bool Disposed;
public void Dispose()

View File

@@ -57,17 +57,31 @@ namespace mpvnet
[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);
[DllImport("user32.dll")]
static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLong64(hWnd, nIndex);
return GetWindowLongPtr(hWnd, nIndex);
else
return GetWindowLong32(hWnd, nIndex);
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern IntPtr SetWindowLong32(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, uint dwNewLong);
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr(hWnd, nIndex, dwNewLong);
else
return SetWindowLong32(hWnd, nIndex, dwNewLong);
}
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

View File

@@ -5,64 +5,64 @@ using System.Text;
public class libmpv
{
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mpv_create();
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_initialize(IntPtr mpvHandle);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_command(IntPtr mpvHandle, IntPtr strings);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_command_string(IntPtr mpvHandle, [MarshalAs(UnmanagedType.LPUTF8Str)] string command);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_command_ret(IntPtr mpvHandle, IntPtr strings, IntPtr node);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mpv_free_node_contents(IntPtr node);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mpv_error_string(mpv_error error);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_terminate_destroy(IntPtr mpvHandle);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_request_log_messages(IntPtr mpvHandle, [MarshalAs(UnmanagedType.LPUTF8Str)] string min_level);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_set_option(IntPtr mpvHandle, byte[] name, mpv_format format, ref long data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_set_option_string(IntPtr mpvHandle, byte[] name, byte[] value);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_get_property(IntPtr mpvHandle, byte[] name, mpv_format format, out IntPtr data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_get_property(IntPtr mpvHandle, byte[] name, mpv_format format, out double data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_set_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref byte[] data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_set_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref long data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_set_property(IntPtr mpvHandle, byte[] name, mpv_format format, ref double data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_observe_property(IntPtr mpvHandle, ulong reply_userdata, [MarshalAs(UnmanagedType.LPUTF8Str)] string name, mpv_format format);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mpv_unobserve_property(IntPtr mpvHandle, ulong registered_reply_userdata);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mpv_free(IntPtr data);
[DllImport("mpv-1.dll", CallingConvention = CallingConvention.Cdecl)]
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mpv_wait_event(IntPtr mpvHandle, double timeout);
public enum mpv_error
@@ -101,21 +101,15 @@ public class libmpv
MPV_EVENT_START_FILE = 6,
MPV_EVENT_END_FILE = 7,
MPV_EVENT_FILE_LOADED = 8,
MPV_EVENT_TRACKS_CHANGED = 9,
MPV_EVENT_TRACK_SWITCHED = 10,
MPV_EVENT_IDLE = 11,
MPV_EVENT_PAUSE = 12,
MPV_EVENT_UNPAUSE = 13,
MPV_EVENT_TICK = 14,
MPV_EVENT_IDLE = 11, //deprecated
MPV_EVENT_TICK = 14, //deprecated
MPV_EVENT_SCRIPT_INPUT_DISPATCH = 15,
MPV_EVENT_CLIENT_MESSAGE = 16,
MPV_EVENT_VIDEO_RECONFIG = 17,
MPV_EVENT_AUDIO_RECONFIG = 18,
MPV_EVENT_METADATA_UPDATE = 19,
MPV_EVENT_SEEK = 20,
MPV_EVENT_PLAYBACK_RESTART = 21,
MPV_EVENT_PROPERTY_CHANGE = 22,
MPV_EVENT_CHAPTER_CHANGE = 23,
MPV_EVENT_QUEUE_OVERFLOW = 24,
MPV_EVENT_HOOK = 25
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

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

View File

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

View File

@@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("mpv.net")]
[assembly: AssemblyDescription("mpv based media player")]
[assembly: AssemblyDescription("mpv based media player for Windows")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("mpv.net/mpv/mplayer")]
[assembly: AssemblyProduct("mpv.net")]
[assembly: AssemblyCopyright("Copyright (C) 2000-2021 mpv.net/mpv/mplayer")]
[assembly: AssemblyCopyright("Copyright (C) 2000-2022 mpv.net/mpv/mplayer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("5.4.9.0")]
[assembly: AssemblyFileVersion("5.4.9.0")]
[assembly: AssemblyVersion("5.6.2.0")]
[assembly: AssemblyFileVersion("5.6.2.0")]

View File

@@ -19,7 +19,7 @@ namespace mpvnet.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@@ -62,38 +62,39 @@ namespace mpvnet.Properties {
/// <summary>
/// Looks up a localized string similar to
///[[settings]]
///name = &quot;hwdec&quot;
///file = &quot;mpv&quot;
///default = &quot;no&quot;
///filter = &quot;Video&quot;
///url = &quot;https://mpv.io/manual/master/#options-hwdec&quot;
///help = &quot;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:&quot;
///options = [{ name = &quot;no&quot;, help = &quot;always use software decoding&quot; },
/// { name = &quot;auto&quot;, h [rest of string was truncated]&quot;;.
///[setting]
///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:
///
///option = no always use software decoding
///option = auto enable best hw decoder
///option = yes exact [rest of string was truncated]&quot;;.
/// </summary>
internal static string editor_toml {
internal static string editor_conf {
get {
return ResourceManager.GetString("editor_toml", resourceCulture);
return ResourceManager.GetString("editor_conf", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to
/// # This file defines the key and mouse bindings and the context menu of mpv.net.
///
/// # A input and config editor can be found in the context menu under &apos;Settings&apos;.
///
/// # The mpv.conf defaults of mpv.net contain: &apos;input-default-bindings = no&apos;
/// # which disables the input defaults of mpv.
///
/// # Every line in this file begins with a space character to make search easier,
/// # if you want to know if &apos;o&apos; has already a binding you can search for &apos; o &apos;.
///# This file defines the key and mouse bindings and also the context menu of mpv.net.
///
/// # input test mode:
/// # mpvnet --input-test
///# A input and config editor can be found in the context menu under &apos;Settings&apos;.
///
/// # The [rest of string was truncated]&quot;;.
///# The mpv.conf defaults of mpv.net contain input-default-bindings=yes and
///# input-builtin-bindings=no which disables the input defaults of mpv.
///
///# 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 &gt; Show Keys
///
///# m [rest of string was truncated]&quot;;.
/// </summary>
internal static string input_conf {
get {
@@ -101,28 +102,6 @@ namespace mpvnet.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to
///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 = &apos;${filename}&apos;
///script-opts = osc-scalewindowed=1.5,osc-hidetimeout=2000,osc-greenandgrumpy=yes,console-scale=1
///screenshot-directory = &apos;~~desktop/&apos;
///
///[protocol.https]
///osd-playing-msg = &apos;${media-title}&apos;
///.
/// </summary>
internal static string mpv_conf {
get {
return ResourceManager.GetString("mpv_conf", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
@@ -151,12 +130,11 @@ namespace mpvnet.Properties {
///foreground = #DDDDDD
///foreground2 = #AAAAAA
///background = #323232
///highlight = #404040
///
///menu-foreground = #DDDDDD
///menu-background = #323232
///menu-highlight = #505050
///menu-border = #FFFFFF
///menu-checked = #5A5A5A
///
///
///[light]
@@ -165,12 +143,11 @@ namespace mpvnet.Properties {
///foreground = #000000
///foreground2 = #4C4C4C
///background = #F7F7F7
///highlight = #DFDFDF
///
///menu-foreground = #000000
///menu-background = #DFDFDF
///menu-highlight = #BFBFBF
///menu-border = #6A6A6A
///menu-checked = #AAAAAA
///.
/// </summary>
internal static string theme {

View File

@@ -118,8 +118,8 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="editor_toml" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\editor.toml.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<data name="editor_conf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\editor_conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="input_conf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\input.conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
@@ -130,9 +130,6 @@
<data name="mpvnet_santa" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\mpvnet-santa.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="mpv_conf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\mpv.conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="theme" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\theme.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>

View File

@@ -2,54 +2,11 @@
$tmpDir = 'D:\Work'
$exePath = $PSScriptRoot + '\bin\mpvnet.exe'
$versionInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($exePath)
$inno = 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe'
$7z = 'C:\Program Files\7-Zip\7z.exe'
$cloudDirectories = 'C:\Users\frank\OneDrive\Public\mpv.net\',
'C:\Users\frank\Dropbox\Public\mpv.net\'
function UploadBeta($sourceFile)
{
foreach ($cloudDirectory in $cloudDirectories)
{
if (-not (Test-Path $cloudDirectory))
{
throw $cloudDirectory
}
$targetFile = $cloudDirectory + (Split-Path $sourceFile -Leaf)
if (Test-Path $targetFile)
{
throw $targetFile
}
Copy-Item $sourceFile $targetFile
}
}
if ($versionInfo.FilePrivatePart -eq 0)
{
& $inno $PSScriptRoot\setup.iss
if ($LastExitCode) { throw $LastExitCode }
$targetDir = $tmpDir + "\mpv.net-$($versionInfo.FileVersion)-portable"
Copy-Item $PSScriptRoot\bin $targetDir -Recurse -Exclude 'System.Management.Automation.xml', 'settings-directory.txt'
& $7z a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
}
else
{
$targetDir = "$tmpDir\mpv.net-$($versionInfo.FileVersion)-portable-beta"
Copy-Item $PSScriptRoot\bin $targetDir -Recurse -Exclude 'System.Management.Automation.xml', 'settings-directory.txt'
& $7z a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
UploadBeta "$targetDir.zip"
foreach ($cloudDirectory in $cloudDirectories)
{
Invoke-Item $cloudDirectory
}
}
$targetDir = $tmpDir + "\mpv.net-$($versionInfo.FileVersion)-portable-beta"
Copy-Item $PSScriptRoot\bin $targetDir -Recurse -Exclude 'System.Management.Automation.xml'
& $7z a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"
if ($LastExitCode) { throw $LastExitCode }
Write-Host 'successfully finished' -ForegroundColor Green

View File

@@ -1,619 +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 = "audio-device"
file = "mpv"
filter = "Audio"
type = "string"
url = "https://mpv.io/manual/master/#options-audio-device"
help = "<name> Use the given audio device. This consists of the audio output name, e.g. alsa, followed by /, followed by the audio output specific device name. The default value for this option is auto, which tries every audio output in preference order with the default device.\nAvailable devices can be found in the mpv.net context menu under:\nView > Show Audio Devices"
[[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: 60"
[[settings]]
name = "autofit-smaller"
file = "mpv"
filter = "Screen"
help = "<int> Minimum window height in percent. Default: 10"
[[settings]]
name = "autofit-larger"
file = "mpv"
filter = "Screen"
help = "<int> Maximum window height in percent. Default: 80"
[[settings]]
name = "start-size"
file = "mpvnet"
default = "height-session"
filter = "Screen"
help = "Setting to remember the window size. (mpv.net specific setting)"
options = [{ name = "video", help = "Window size is set to video resolution" },
{ name = "width-session", help = "Width is remembered in the current session" },
{ name = "width-always", help = "Width is always remembered" },
{ name = "height-session", help = "Height is remembered in the current session" },
{ name = "height-always", help = "Height is always remembered" },
{ name = "always", help = "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, 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 (mpv.net specific setting)"
[[settings]]
name = "remember-window-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 = "video-file-extensions"
file = "mpvnet"
filter = "General"
width = 500
help = "Video file extensions used to create file associations and used by the auto-load-folder feature. (mpv.net specific setting)"
[[settings]]
name = "audio-file-extensions"
file = "mpvnet"
filter = "General"
width = 500
help = "Audio file extensions used to create file associations and used by the auto-load-folder feature. (mpv.net specific setting)"
[[settings]]
name = "image-file-extensions"
file = "mpvnet"
filter = "General"
width = 500
help = "Image file extensions used to create file associations and used by the auto-load-folder feature. (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/docs/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/docs/Manual.md#color-theme"
help = "Color theme used in light mode. Default: light"

View File

@@ -0,0 +1,683 @@
[setting]
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
option = gpu General purpose, customizable, GPU-accelerated video output driver. It supports extended scaling methods, dithering, color management, custom shaders, HDR, and more.
option = gpu-next Experimental video renderer based on libplacebo. This supports almost the same set of features as --vo=gpu.
option = direct3d Video output driver that uses the Direct3D interface.
[setting]
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:
option = no always use software decoding
option = auto enable best hw decoder
option = yes exactly the same as auto
option = auto-copy enable best hw decoder with copy-back
option = auto-safe enable any whitelisted hw decoder
option = dxva2 requires vo=gpu with gpu-context=d3d11, gpu-context=angle or gpu-context=dxinterop (Windows only)
option = dxva2-copy copies video back to system RAM (Windows only)
option = d3d11va requires vo=gpu with gpu-context=d3d11 or gpu-context=angle (Windows 8+ only)
option = d3d11va-copy copies video back to system RAM (Windows 8+ only)
option = cuda requires vo=gpu (Any platform CUDA is available)
option = cuda-copy copies video back to system RAM (Any platform CUDA is available)
option = nvdec requires vo=gpu (Any platform CUDA is available)
option = nvdec-copy copies video back to system RAM (Any platform CUDA is available)
[setting]
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.
option = auto Use any available API
option = d3d11 Allow only gpu-context=d3d11
option = opengl Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)
option = vulkan Allow only Vulkan
[setting]
name = gpu-context
file = mpv
default = auto
filter = Video
option = auto auto-select
option = d3d11 Win32, with native Direct3D 11 rendering.
option = angle Direct3D11 through the OpenGL ES translation layer ANGLE. This supports almost everything the win backend does (if the ANGLE build is new enough).
option = win Win32/WGL
option = dxinterop (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.
option = winvk VK_KHR_win32_surface
[setting]
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
option = audio
option = display-resample
option = display-resample-vdrop
option = display-resample-desync
option = display-vdrop
option = display-adrop
option = display-desync
option = desync
[setting]
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
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
option = lanczos 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)
option = ewa_lanczos 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)
option = ewa_lanczossharp 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.
option = mitchell 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).
option = oversample 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).
[setting]
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.
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
option = lanczos 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)
option = ewa_lanczos 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)
option = ewa_lanczossharp 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.
option = mitchell 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).
option = oversample 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).
[setting]
name = dscale
file = mpv
default =
filter = Video
help = Like scale, but apply these filters on downscaling instead. \nIf no option is selected, it will keep the same with the upscaler.
option = bilinear Bilinear hardware texture filtering (fastest, very low quality).
option = spline36 Mid quality and speed. This is the default when using gpu-hq.
option = lanczos 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)
option = ewa_lanczos 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)
option = ewa_lanczossharp 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.
option = mitchell 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).
option = oversample 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).
[setting]
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.
option = no Disable any dithering done by mpv.
option = auto Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed.
option = 8 Dither to 8 bit output.
option = 10 Dither to 10 bit output.
[setting]
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.
option = yes
option = no
[setting]
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.
option = yes
option = no
[setting]
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.
option = yes
option = no
[setting]
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.)
option = yes
option = no
[setting]
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.
option = auto
option = yes
option = no
[setting]
name = allow-delayed-peak-detect
file = mpv
default = yes
filter = Video
help = When using --hdr-compute-peak, allow delaying the detected peak by a frame when beneficial for performance. In particular, this is required to avoid an unnecessary FBO indirection when no advanced rendering is required otherwise. Has no effect if there already is an indirect pass, such as when advanced scaling is enabled. (Only affects --vo=gpu-next, note that --vo=gpu always delays the peak.)
option = yes
option = no
[setting]
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
[setting]
name = remember-volume
file = mpvnet
default = yes
filter = Audio
help = Save volume and mute on exit and restore it on start. (mpv.net specific option)
option = yes
option = no
[setting]
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.
[setting]
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.
option = no Don't automatically load external audio files.
option = exact Load the media filename with audio file extension.
option = fuzzy Load all audio files containing media filename.
option = all Load all audio files in the current and audio-file-paths directories.
[setting]
name = audio-device
file = mpv
filter = Audio
type = string
url = https://mpv.io/manual/master/#options-audio-device
help = <name> Use the given audio device. This consists of the audio output name, e.g. alsa, followed by /, followed by the audio output specific device name. The default value for this option is auto, which tries every audio output in preference order with the default device.\nAvailable devices can be found in the mpv.net context menu under:\nView > Show Audio Devices
[setting]
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.
[setting]
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.
option = no Don't automatically load external subtitle files.
option = exact Load the media filename with subtitle file extension.
option = fuzzy Load all subs containing media filename.
option = all Load all subs in the current and sub-file-paths directories.
[setting]
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.
[setting]
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
[setting]
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
[setting]
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).
[setting]
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.
[setting]
name = fullscreen
file = mpv
default = no
filter = Screen
help = Start the player in fullscreen mode.
option = yes
option = no
[setting]
name = border
file = mpv
default = yes
filter = Screen
help = Show window with decoration (titlebar, border).
option = yes
option = no
[setting]
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.
[setting]
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
[setting]
name = osd-font-size
file = mpv
filter = Screen
help = Specify the OSD font size. See sub-font-size for details. Default: 55
[setting]
name = osd-duration
file = mpv
filter = Screen
help = Set the duration of the OSD messages in ms. Default: 1000
[setting]
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.
option = yes
option = no
[setting]
name = autofit
file = mpv
filter = Screen
help = <int> Initial window height in percent. Default: 60
[setting]
name = autofit-smaller
file = mpv
filter = Screen
help = <int> Minimum window height in percent. Default: 10
[setting]
name = autofit-larger
file = mpv
filter = Screen
help = <int> Maximum window height in percent. Default: 80
[setting]
name = start-size
file = mpvnet
default = height-session
filter = Screen
help = Setting to remember the window size. (mpv.net specific option)
option = width-session Window width is remembered in the current session
option = width-always Window width is always remembered
option = height-session Window height is remembered in the current session
option = height-always Window height is always remembered
option = video Window size is set to video resolution
option = session Window size is remembered in the current session
option = always Window size is always remembered
[setting]
name = keepaspect-window
file = mpv
default = yes
filter = Screen
help = keepaspect-window will lock the window size to the video aspect. Default: yes
option = yes
option = no
[setting]
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 option)
[setting]
name = minimum-aspect-ratio
file = mpvnet
filter = Screen
help = <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 (mpv.net specific option)
[setting]
name = remember-window-position
file = mpvnet
default = no
filter = Screen
help = Save the window position on exit. (mpv.net specific option)
option = yes
option = no
[setting]
name = window-maximized
file = mpv
default = no
filter = Screen
help = Start with a maximized window.
option = yes
option = no
[setting]
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.
[setting]
name = screenshot-format
file = mpv
default = jpg
filter = Screen
help = Set the image file type used for saving screenshots.
option = jpg
option = png
[setting]
name = screenshot-tag-colorspace
file = mpv
default = no
filter = Screen
help = Tag screenshots with the appropriate colorspace. Note that not all formats are supported.
option = yes
option = no
[setting]
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.
option = yes
option = no
[setting]
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.
option = yes
option = no
[setting]
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
[setting]
name = screenshot-jpeg-quality
file = mpv
filter = Screen
help = <0-100> Set the JPEG quality level. Higher means better quality. The default is 90.
[setting]
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.
[setting]
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.
[setting]
name = taskbar-progress
file = mpv
default = yes
filter = Playback
help = Show progress in taskbar.
option = yes
option = no
[setting]
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.
option = yes
option = no
[setting]
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.
option = yes If the current file ends, go to the next file, keep the last file open.
option = no If the current file ends, go to the next file.
option = always Playback will never automatically advance to the next file.
[setting]
name = auto-play
file = mpvnet
default = no
filter = Playback
help = Sets pause=no on file load and selecting from the playlist. (mpv.net specific option)
option = yes
option = no
[setting]
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.
[setting]
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.
option = yes
option = no
[setting]
name = watch-later-options
file = mpv
filter = Playback
help = The options that are saved in "watch later" files if they have been changed since when mpv started. These values will be restored the next time the files are played. This is a string list option. For more information visit:
url = https://mpv.io/manual/master/#options-watch-later-options
[setting]
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.
option = yes Use precise seeks whenever possible.
option = no Never use precise seeks.
option = absolute 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.
option = always Same as yes (for compatibility).
[setting]
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.
option = yes
option = no
[setting]
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.
[setting]
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 option)
option = yes
option = no
[setting]
name = input-ar-delay
file = mpv
filter = Input
help = Delay in milliseconds before we start to autorepeat a key (0 to disable).
[setting]
name = input-ar-rate
file = mpv
filter = Input
help = Number of key presses to generate per second on autorepeat.
[setting]
name = process-instance
file = mpvnet
default = single
filter = General
help = Defines if more then one mpv.net process is allowed. (mpv.net specific option)\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.
option = multi Create a new process everytime the shell starts mpv.net
option = single Force a single process everytime the shell starts mpv.net
option = queue Force a single process and add files to playlist
[setting]
name = recent-count
file = mpvnet
filter = General
help = <int> Amount of recent files to be remembered. Default: 15 (mpv.net specific option)
[setting]
name = video-file-extensions
file = mpvnet
filter = General
width = 500
help = Video file extensions used to create file associations and used by the auto-load-folder feature. (mpv.net specific option)
[setting]
name = audio-file-extensions
file = mpvnet
filter = General
width = 500
help = Audio file extensions used to create file associations and used by the auto-load-folder feature. (mpv.net specific option)
[setting]
name = image-file-extensions
file = mpvnet
filter = General
width = 500
help = Image file extensions used to create file associations and used by the auto-load-folder feature. (mpv.net specific option)
[setting]
name = debug-mode
file = mpvnet
default = no
filter = General
help = Enable this only when a developer asks for it. (mpv.net specific option)
option = yes
option = no
[setting]
name = dark-mode
file = mpvnet
default = always
filter = UI
help = Changes between a light and dark theme.\nmpv.net must be restarted after a change.\nmpv.net specific option.
option = always
option = system Available on Windows 10 or higher
option = never
[setting]
name = dark-theme
file = mpvnet
filter = UI
url = https://github.com/stax76/mpv.net/blob/master/docs/Manual.md#color-theme
help = Color theme used in dark mode.\nmpv.net must be restarted after a change.\nmpv.net specific option. Default: dark
[setting]
name = light-theme
file = mpvnet
filter = UI
url = https://github.com/stax76/mpv.net/blob/master/docs/Manual.md#color-theme
help = Color theme used in light mode.\nmpv.net must be restarted after a change.\nmpv.net specific option. Default: light

View File

@@ -1,208 +1,209 @@
# This file defines the key and mouse bindings and the context menu of mpv.net.
# https://github.com/stax76/mpv.net/blob/master/docs/Manual.md#input-and-context-menu
o script-message mpv.net open-files #menu: Open > Open Files...
Ctrl+v script-message mpv.net open-url #menu: Open > Open URL or file 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...
_ ignore #menu: Open > -
_ ignore #menu: Open > Recent
_ ignore #menu: -
Space script-message mpv.net play-pause #menu: Play/Pause
Ctrl+s stop #menu: Stop
_ ignore #menu: -
Enter cycle fullscreen #menu: Toggle Fullscreen
# A input and config editor can be found in the context menu under 'Settings'.
# The mpv.conf defaults of mpv.net contain: 'input-default-bindings = no'
# which disables the input defaults of mpv.
# Every line in this file begins with a space character to make search easier,
# if you want to know if 'o' has already a binding you can search for ' o '.
F11 playlist-prev; set pause no #menu: Navigate > Previous File
F12 playlist-next; set pause no #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 5 #menu: Navigate > Jump 5 sec forward
Left seek -5 #menu: Navigate > Jump 5 sec backward
_ ignore #menu: Navigate > -
Up seek 30 #menu: Navigate > Jump 30 sec forward
Down seek -30 #menu: Navigate > Jump 30 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 > Titles
_ ignore #menu: Navigate > Chapters
# input test mode:
# mpvnet --input-test
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
# The input key list can be found in the context menu under: View > Show Keys
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 > -
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
Ctrl+r cycle-values video-rotate 90 180 270 0 #menu: Video > Rotate Video
# mpv.net input.conf defaults:
# https://github.com/stax76/mpv.net/blob/master/src/Resources/input.conf.txt
KP7 script-message mpv.net cycle-audio #menu: Audio > Cycle/Next
_ ignore #menu: Audio > -
Ctrl+d add audio-delay 0.1 #menu: Audio > Delay +0.1
Ctrl+D add audio-delay -0.1 #menu: Audio > Delay -0.1
# mpv input.conf defaults:
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
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 > -
F add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size
G add sub-scale 0.1 #menu: Subtitle > Increase Subtitle Font Size
# mpv input commands:
# https://mpv.io/manual/master/#list-of-input-commands
_ ignore #menu: Track
# mpv input options:
# https://mpv.io/manual/master/#input
+ add volume 2 #menu: Volume > Up
- add volume -2 #menu: Volume > Down
_ ignore #menu: Volume > -
m cycle mute #menu: Volume > Mute
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
[ 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
_ ignore #menu: -
Space cycle pause #menu: Play/Pause
s stop #menu: Stop
_ ignore #menu: -
Enter cycle fullscreen #menu: Toggle Fullscreen
F11 playlist-prev; set pause no #menu: Navigate > Previous File
F12 playlist-next; set pause no #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 5 #menu: Navigate > Jump 5 sec forward
Left seek -5 #menu: Navigate > Jump 5 sec backward
_ ignore #menu: Navigate > -
Up seek 30 #menu: Navigate > Jump 30 sec forward
Down seek -30 #menu: Navigate > Jump 30 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 > Titles
_ ignore #menu: Navigate > Chapters
Alt++ script-message mpv.net scale-window 1.2 #menu: View > Zoom > Enlarge
Alt+- script-message mpv.net scale-window 0.8 #menu: View > Zoom > Shrink
_ ignore #menu: View > Zoom > -
Alt+0 script-message mpv.net window-scale 0.5 #menu: View > Zoom > 50 %
Alt+1 script-message mpv.net window-scale 1.0 #menu: View > Zoom > 100 %
Alt+2 script-message mpv.net window-scale 2.0 #menu: View > Zoom > 200 %
Alt+3 script-message mpv.net window-scale 3.0 #menu: View > Zoom > 300 %
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
F8 script-message mpv.net show-playlist #menu: View > Show Playlist
Ctrl+7 script-message mpv.net show-audio-tracks #menu: View > Show Audio Tracks
Ctrl+8 script-message mpv.net show-subtitle-tracks #menu: View > Show Subtitle Tracks
b cycle border #menu: View > Toggle Border
Ctrl+t cycle ontop #menu: View > Toggle On Top
t script-binding stats/display-stats-toggle #menu: View > Toggle Statistics
Del script-binding osc/visibility #menu: View > Toggle OSC Visibility
i script-message mpv.net show-info #menu: View > Show File/Stream Info
p show-progress #menu: View > Show Progress
Ctrl+p script-message mpv.net show-profiles #menu: View > Show Profiles
F9 show-text ${track-list} 5000 #menu: View > Show Tracks
Ctrl+m script-message mpv.net show-media-info #menu: View > Show Media Info
Alt+r script-message mpv.net show-recent #menu: View > Show Recent
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
` script-binding console/enable #menu: View > Advanced > Show Console
_ script-message mpv.net show-audio-devices #menu: View > Advanced > Show Audio Devices
P script-message mpv.net show-properties #menu: View > Advanced > Show Properties
C script-message mpv.net show-commands #menu: View > Advanced > Show Commands
_ script-message mpv.net show-demuxers #menu: View > Advanced > Show Demuxers
_ script-message mpv.net show-decoders #menu: View > Advanced > Show Decoders
_ script-message mpv.net show-protocols #menu: View > Advanced > Show Protocols
_ script-message mpv.net show-keys #menu: View > Advanced > Show Keys
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
_ ignore #menu: Profile
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
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
_ ignore #menu: Track
_ script-message mpv.net reg-file-assoc video #menu: Settings > Setup > Register video file associations
_ script-message mpv.net reg-file-assoc audio #menu: Settings > Setup > Register audio file associations
_ script-message mpv.net reg-file-assoc image #menu: Settings > Setup > Register image file associations
_ script-message mpv.net reg-file-assoc unreg #menu: Settings > Setup > Unregister file associations
+ add volume 10 #menu: Volume > Up
- add volume -10 #menu: Volume > Down
_ ignore #menu: Volume > -
m cycle mute #menu: Volume > Mute
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
_ playlist-shuffle #menu: Tools > Shuffle Playlist
Ctrl+h cycle-values hwdec auto no #menu: Tools > Toggle Hardware Decoding
Q quit-watch-later #menu: Tools > Exit Watch Later
[ 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
_ 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/docs/Manual.md #menu: Help > Manual mpv.net
_ ignore #menu: Help > -
_ script-message mpv.net show-about #menu: Help > About mpv.net
Ctrl+t set ontop yes #menu: View > On Top > Enable
Ctrl+T set ontop no #menu: View > On Top > Disable
Alt++ script-message mpv.net scale-window 1.2 #menu: View > Zoom > Enlarge
Alt+- script-message mpv.net scale-window 0.8 #menu: View > Zoom > Shrink
_ ignore #menu: View > Zoom > -
Alt+0 script-message mpv.net window-scale 0.5 #menu: View > Zoom > 50 %
Alt+1 script-message mpv.net window-scale 1.0 #menu: View > Zoom > 100 %
Alt+2 script-message mpv.net window-scale 2.0 #menu: View > Zoom > 200 %
Alt+3 script-message mpv.net window-scale 3.0 #menu: View > Zoom > 300 %
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
Ctrl+r cycle-values video-rotate 90 180 270 0 #menu: View > Rotate Video
_ script-message mpv.net show-audio-devices #menu: View > Show Audio Devices
Shift+c script-message mpv.net show-commands #menu: View > Show Commands
` script-binding console/enable #menu: View > Show Console
_ script-message mpv.net show-decoders #menu: View > Show Decoders
_ script-message mpv.net show-demuxers #menu: View > Show Demuxers
_ script-message mpv.net show-keys #menu: View > Show Keys
F8 script-message mpv.net show-playlist #menu: View > Show Playlist
Ctrl+p script-message mpv.net show-profiles #menu: View > Show Profiles
p show-progress #menu: View > Show Progress
Shift+p script-message mpv.net show-properties #menu: View > Show Properties
_ script-message mpv.net show-protocols #menu: View > Show Protocols
F9 show-text ${track-list} 5000 #menu: View > Show Tracks
F1 script-message mpv.net show-command-palette #menu: Command Palette
_ ignore #menu: -
Esc quit #menu: Exit
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
_ playlist-shuffle #menu: Tools > Shuffle Playlist
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/docs/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
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
6 script-message mpv.net show-progress
KP6 script-message mpv.net show-progress
7 script-message mpv.net cycle-audio
SHARP script-message mpv.net cycle-audio
8 cycle sub
j cycle sub
q quit
Power quit
Play cycle pause
Pause cycle pause
PlayPause cycle pause
MBTN_Mid cycle pause
Stop stop
Forward seek 60
Rewind seek -60
Wheel_Up add volume 2
Wheel_Down add volume -2
Wheel_Left add volume -2
Wheel_Right add volume 2
Prev playlist-prev
Next playlist-next
MBTN_Forward playlist-next
MBTN_Back playlist-prev
> playlist-next
< playlist-prev
MBTN_Left ignore
f cycle fullscreen
MBTN_Left_DBL cycle fullscreen
KP_Enter cycle fullscreen
Shift+RIGHT no-osd seek 1 exact
Shift+LEFT no-osd seek -1 exact
Shift+UP no-osd seek 5 exact
Shift+DOWN no-osd seek -5 exact
Shift+BS revert-seek # undo the previous (or marked) seek
Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek
Shift+g add sub-scale +0.1 # increase the subtitle font size
Shift+f add sub-scale -0.1 # decrease the subtitle font size
Ctrl+Shift+LEFT no-osd sub-seek -1 # seek to the previous subtitle
Ctrl+Shift+RIGHT no-osd sub-seek 1 # seek to the next subtitle
Ctrl+Wheel_Up no-osd seek 7
Ctrl+Wheel_Down no-osd seek -7

View File

@@ -1,13 +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/'
[protocol.https]
osd-playing-msg = '${media-title}'

View File

@@ -5,12 +5,11 @@ heading = #3C8CC8
foreground = #DDDDDD
foreground2 = #AAAAAA
background = #323232
highlight = #404040
menu-foreground = #DDDDDD
menu-background = #323232
menu-highlight = #505050
menu-border = #FFFFFF
menu-checked = #5A5A5A
[light]
@@ -19,9 +18,8 @@ heading = #0068B2
foreground = #000000
foreground2 = #4C4C4C
background = #F7F7F7
highlight = #DFDFDF
menu-foreground = #000000
menu-background = #DFDFDF
menu-highlight = #BFBFBF
menu-border = #6A6A6A
menu-checked = #AAAAAA

View File

@@ -3,8 +3,11 @@
// In input.conf add:
// KP0 script-message delete-current-file ask #menu: Script > Delete current file > Ask
// KP0 script-message delete-current-file delete #menu: Script > Delete current file > Delete
// 0 script-message delete-current-file delete #menu: Script > Delete current file > Delete
// KP1 script-message delete-current-file confirm #menu: Script > Delete current file > Confirm
// 1 script-message delete-current-file confirm #menu: Script > Delete current file > Confirm
using System;
using System.IO;
@@ -31,32 +34,34 @@ class Script
if (args == null || args.Length != 2 || args[0] != "delete-current-file")
return;
if (args[1] == "ask")
if (args[1] == "delete")
{
FileToDelete = Core.get_property_string("path");
FileToDelete = Core.GetPropertyString("path");
DeleteTime = DateTime.Now;
Core.commandv("show-text", "Press 1 to delete file", "5000");
Core.CommandV("show-text", "Press 1 to delete file", "10000");
}
else if (args[1] == "confirm")
{
TimeSpan ts = DateTime.Now - DeleteTime;
string path = Core.get_property_string("path");
string path = Core.GetPropertyString("path");
if (FileToDelete == path && ts.TotalSeconds < 5 && File.Exists(FileToDelete))
if (FileToDelete == path && ts.TotalSeconds < 10 && File.Exists(FileToDelete))
{
Core.command("playlist-remove current");
int pos = Core.get_property_int("playlist-pos");
Core.CommandV("show-text", "");
if (pos == -1)
{
int count = Core.get_property_int("playlist-count");
int count = Core.GetPropertyInt("playlist-count");
int pos = Core.GetPropertyInt("playlist-pos");
int newPos = pos == count - 1 ? pos - 1 : pos + 1;
if (count > 0)
Core.set_property_int("playlist-pos", count - 1);
}
if (newPos > -1)
Core.SetPropertyNumber("playlist-pos", newPos);
Thread.Sleep(2000);
FileSystem.DeleteFile(FileToDelete, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
Core.Command("playlist-remove " + pos);
App.RunTask(() => {
Thread.Sleep(2000);
FileSystem.DeleteFile(FileToDelete, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
});
}
}
}

View File

@@ -12,8 +12,8 @@ class Script
string content = "ctrl+w script-message my-message-1 my-argument-1";
string sectionName = Assembly.GetExecutingAssembly().GetName().Name;
CorePlayer core = Global.Core;
core.commandv("define-section", sectionName, content, "force");
core.commandv("enable-section", sectionName);
core.CommandV("define-section", sectionName, content, "force");
core.CommandV("enable-section", sectionName);
core.ClientMessage += ClientMessage;
}

View File

@@ -11,11 +11,11 @@ class Script
public Script()
{
Core = Global.Core;
Core.observe_property_bool("fullscreen", FullscreenChange);
Core.ObservePropertyBool("fullscreen", FullscreenChange);
}
void FullscreenChange(bool value)
{
Core.commandv("show-text", "fullscreen: " + value);
Core.CommandV("show-text", "fullscreen: " + value);
}
}

View File

@@ -25,11 +25,11 @@ class Script
{
if (MainForm.WindowState == FormWindowState.Minimized)
{
WasPlaying = !Core.get_property_bool("pause");
WasPlaying = !Core.GetPropertyBool("pause");
if (WasPlaying)
{
Core.set_property_bool("pause", true, true);
Core.SetPropertyBool("pause", true, true);
WasPaused = true;
}
}
@@ -37,7 +37,7 @@ class Script
{
if (WasPaused)
{
Core.set_property_bool("pause", false, true);
Core.SetPropertyBool("pause", false, true);
WasPaused = false;
}
}

View File

@@ -62,20 +62,20 @@ class Script
//handles keys defined in input.conf
void ClientMessage(string[] args)
{
if (args[0] != "rate-file")
if (args == null || args.Length != 2 || args[0] != "rate-file")
return;
int rating;
if (int.TryParse(args[1], out rating))
{
string path = Core.get_property_string("path");
string path = Core.GetPropertyString("path");
if (!File.Exists(path))
return;
Dic[path] = rating;
Core.commandv("show-text", "Rating: " + 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.",

View File

@@ -31,7 +31,7 @@ class Script
foreach (MediaTrack track in editionTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => { Core.commandv("set", "edition", track.ID.ToString()); };
mi.Action = () => { Core.CommandV("set", "edition", track.ID.ToString()); };
mi.Checked = Core.Edition == track.ID;
menuItem.DropDownItems.Add(mi);
}

View File

@@ -0,0 +1,62 @@
-- This script deletes the file that is currently playing.
-- input.conf:
-- KP0 script-binding delete_current_file/delete
-- 0 script-binding delete_current_file/delete
-- KP1 script-binding delete_current_file/confirm
-- 1 script-binding delete_current_file/confirm
function delete()
FileToDelete = mp.get_property("path")
DeleteTime = os.time()
mp.commandv("show-text", "Press 1 to delete file", "10000")
end
function confirm()
local path = mp.get_property("path")
if FileToDelete == path and (os.time() - DeleteTime) < 10 then
mp.commandv("show-text", "")
local count = mp.get_property_number("playlist-count")
local pos = mp.get_property_number("playlist-pos")
local newPos = 0
if pos == count - 1 then
newPos = pos - 1
else
newPos = pos + 1
end
if newPos > -1 then
mp.command("set pause no")
mp.set_property_number("playlist-pos", newPos)
end
mp.command("playlist-remove " .. pos)
local ps_code = [[& {
Start-Sleep -Seconds 2
Add-Type -AssemblyName Microsoft.VisualBasic
[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile('FileToDelete', 'OnlyErrorDialogs', 'SendToRecycleBin')
}]]
local escapedFileToDelete = string.gsub(FileToDelete, "'", "''")
escapedFileToDelete = string.gsub(escapedFileToDelete, "", "")
escapedFileToDelete = string.gsub(escapedFileToDelete, "%%", "%%%%")
ps_code = string.gsub(ps_code, "FileToDelete", escapedFileToDelete)
mp.command_native({
name = "subprocess",
playback_only = false,
detach = true,
args = { 'powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', ps_code },
})
end
end
mp.add_key_binding(nil, "delete", delete)
mp.add_key_binding(nil, "confirm", confirm)

View File

@@ -17,4 +17,4 @@ $code = {
}
}
$mp.register_event("client-message", $code)
$mp.RegisterEvent("client-message", $code)

View File

@@ -1,13 +1,13 @@
$code = {
$isMinimized = $args[0]
$isPaused = $mp.get_property_bool('pause')
$isPaused = $mp.GetPropertyBool('pause')
if ($isMinimized)
{
if (-not $isPaused)
{
$mp.set_property_bool('pause', $true)
$mp.SetPropertyBool('pause', $true)
$script:wasPaused = $true
}
}
@@ -15,11 +15,11 @@ $code = {
{
if ($script:wasPaused -and $isPaused)
{
$mp.set_property_bool('pause', $false)
$mp.SetPropertyBool('pause', $false)
}
$script:wasPaused = $false
}
}
$mp.observe_property('window-minimized', 'bool', $code)
$mp.ObserveProperty('window-minimized', 'bool', $code)

View File

@@ -6,9 +6,8 @@
$code = {
if ($args[0] -eq 'show-in-file-explorer')
{
# probably works only with shell execute for which powershell has no built-in support
[Diagnostics.Process]::Start('explorer.exe', '/n, /select, "' + $mp.get_property_string('path') + '"')
Start-Process explorer.exe '/n,','/select,',"$($mp.GetPropertyString('path'))"
}
}
$mp.register_event("client-message", $code)
$mp.RegisterEvent("client-message", $code)

View File

@@ -1,31 +0,0 @@
#define MyAppName "mpv.net"
#define MyAppExeName "mpvnet.exe"
#define MyAppSourceDir "bin"
#define MyAppVersion GetFileVersion("bin\mpvnet.exe")
[Setup]
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher=Frank Skare (stax76)
ArchitecturesInstallIn64BitMode=x64
Compression=lzma2
DefaultDirName={commonpf}\{#MyAppName}
OutputBaseFilename=mpv.net-{#MyAppVersion}-setup
OutputDir=D:\Work
DefaultGroupName={#MyAppName}
SetupIconFile=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; Excludes: "System.Management.Automation.xml,settings-directory.txt"
[UninstallRun]
Filename: "powershell.exe"; Flags: runhidden; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\Setup\remove file associations.ps1"""
Filename: "powershell.exe"; Flags: runhidden; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\Setup\remove start menu shortcut.ps1"""
Filename: "powershell.exe"; Flags: runhidden; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\Setup\remove environment variable.ps1"""

View File

@@ -16,8 +16,6 @@ namespace mpvnet
protected override void OnPreviewKeyDown(KeyEventArgs e) => Close();
protected override void OnMouseDown(MouseButtonEventArgs e) => Close();
public Theme Theme {
get => Theme.Current;
}
public Theme Theme => Theme.Current;
}
}

View File

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

View File

@@ -0,0 +1,141 @@

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

View File

@@ -1,66 +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"
mc:Ignorable="d"
Title="Command Palette"
Height="295"
Width="400"
FontSize="13"
ResizeMode="NoResize"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox
Name="FilterTextBox"
Foreground="{Binding Theme.Foreground}"
Background="{Binding Theme.Background}"
PreviewKeyDown="FilterTextBox_PreviewKeyDown"
TextChanged="FilterTextBox_TextChanged"
/>
<ListView
Name="ListView"
Grid.Row="1"
Foreground="{Binding Theme.Foreground}"
Background="{Binding 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 Display}"></TextBlock>
<TextBlock
Grid.Column="1"
Text="{Binding Input}"
HorizontalAlignment="Right"
/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>

View File

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

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interop;
using static mpvnet.Global;
namespace mpvnet
{
public partial class CommandPaletteWindow : Window
{
ICollectionView CollectionView;
public CommandPaletteWindow()
{
InitializeComponent();
DataContext = this;
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;
}
public Theme Theme {
get => Theme.Current;
}
bool Filter(CommandItem item)
{
if (item.Command == "")
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;
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();
Core.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,9 +1,11 @@
<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"
x:Name="ConfWindow1"
x:Class="mpvnet.ConfWindow"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:mpvnet"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
mc:Ignorable="d"
Title="Config Editor"
@@ -26,8 +28,8 @@
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Controls:SearchTextBoxUserControl
<local:SearchTextBoxUserControl
x:Name="SearchControl"
HintText="Find a setting"
Width="250"
@@ -55,7 +57,17 @@
Foreground="{Binding Theme.Heading}"
Background="{Binding Theme.Background}"
>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="3"/>
</Style>
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="16" />

View File

@@ -17,10 +17,11 @@ namespace mpvnet
{
public partial class ConfWindow : Window
{
List<SettingBase> SettingsDefinitions = Settings.LoadSettings(Properties.Resources.editor_toml);
List<SettingBase> SettingsDefinitions = Conf.LoadConf(Properties.Resources.editor_conf);
List<ConfItem> ConfItems = new List<ConfItem>();
public ObservableCollection<string> FilterStrings { get; } = new ObservableCollection<string>();
string InitialContent;
string ThemeConf = GetThemeConf();
public ConfWindow()
{
@@ -35,9 +36,9 @@ namespace mpvnet
FilterListBox.SelectedItem = SearchControl.Text.TrimEnd(':');
}
public Theme Theme {
get => Theme.Current;
}
static string GetThemeConf() => App.IsDarkMode + App.DarkTheme + App.LightTheme;
public Theme Theme => Theme.Current;
void LoadSettings()
{
@@ -75,10 +76,10 @@ namespace mpvnet
{
base.OnClosed(e);
App.Settings.ConfigEditorSearch = SearchControl.Text;
if (InitialContent == GetCompareString())
return;
File.WriteAllText(Core.ConfPath, GetContent("mpv"));
File.WriteAllText(App.ConfPath, GetContent("mpvnet"));
@@ -89,10 +90,10 @@ namespace mpvnet
if (item.File == "mpv")
{
Core.ProcessProperty(item.Name, item.Value);
try
{
Core.set_property_string(item.Name, item.Value, true);
Core.SetPropertyString(item.Name, item.Value, true);
}
catch (Exception ex)
{
@@ -105,6 +106,10 @@ namespace mpvnet
}
App.InitTheme();
App.UpdateWpfColors();
if (ThemeConf != GetThemeConf())
MessageBox.Show("Changed theme settings require mpv.net being restarted.", "Info");
}
string GetCompareString()
@@ -324,7 +329,7 @@ namespace mpvnet
ProcessHelp.ShellExecute(Path.GetDirectoryName(Core.ConfPath));
void PreviewTextBlock_MouseUp(object sender, MouseButtonEventArgs e) =>
Msg.ShowInfo("mpv.conf Preview", GetContent("mpv"));
Msg.ShowInfo("mpv.conf Preview" + BR2 + GetContent("mpv"));
void ShowManualTextBlock_MouseUp(object sender, MouseButtonEventArgs e) =>
ProcessHelp.ShellExecute("https://mpv.io/manual/master/");

View File

@@ -1,49 +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"
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="{Binding Theme.Foreground}"
Background="{Binding Theme.Background}"
PreviewKeyDown="FilterTextBox_PreviewKeyDown"
TextChanged="FilterTextBox_TextChanged"
/>
<ListView
Name="ListView"
Foreground="{Binding Theme.Foreground}"
Background="{Binding 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,169 +0,0 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using static mpvnet.Global;
namespace mpvnet
{
public partial class EverythingWindow : Window
{
public EverythingWindow()
{
InitializeComponent();
DataContext = this;
}
public Theme Theme {
get => Theme.Current;
}
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;
if (--index < 0)
index = 0;
ListView.SelectedIndex = index;
ListView.ScrollIntoView(ListView.SelectedItem);
}
break;
case Key.Down:
{
int index = ListView.SelectedIndex;
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)
Core.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;
App.RunTask(() => Search(searchtext));
}
object LockObject = new object();
void Search(string searchText)
{
lock (LockObject)
{
try
{
List<string> items = new List<string>();
StringBuilder sb = new StringBuilder(500);
Everything_SetSearch(searchText);
Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH);
Everything_Query(true);
uint count = Everything_GetNumResults();
for (uint i = 0; i < count; i++)
{
Everything_GetResultFullPathName(i, sb, (uint)sb.Capacity);
string ext = sb.ToString().Ext();
if (CorePlayer.AudioTypes.Contains(ext) || CorePlayer.VideoTypes.Contains(ext) || CorePlayer.ImageTypes.Contains(ext))
items.Add(sb.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

@@ -0,0 +1,52 @@

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using HandyControl.Data;
using HandyControl.Tools.Converter;
namespace HandyControl.Controls
{
public class BorderElement
{
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached(
"CornerRadius", typeof(CornerRadius), typeof(BorderElement), new FrameworkPropertyMetadata(default(CornerRadius), FrameworkPropertyMetadataOptions.Inherits));
public static void SetCornerRadius(DependencyObject element, CornerRadius value) => element.SetValue(CornerRadiusProperty, value);
public static CornerRadius GetCornerRadius(DependencyObject element) => (CornerRadius) element.GetValue(CornerRadiusProperty);
public static readonly DependencyProperty CircularProperty = DependencyProperty.RegisterAttached(
"Circular", typeof(bool), typeof(BorderElement), new PropertyMetadata(ValueBoxes.FalseBox, OnCircularChanged));
private static void OnCircularChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Border border)
{
if ((bool) e.NewValue)
{
var binding = new MultiBinding
{
Converter = new BorderCircularConverter()
};
binding.Bindings.Add(new Binding(FrameworkElement.ActualWidthProperty.Name) { Source = border });
binding.Bindings.Add(new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = border });
border.SetBinding(Border.CornerRadiusProperty, binding);
}
else
{
BindingOperations.ClearBinding(border, FrameworkElement.ActualWidthProperty);
BindingOperations.ClearBinding(border, FrameworkElement.ActualHeightProperty);
BindingOperations.ClearBinding(border, Border.CornerRadiusProperty);
}
}
}
public static void SetCircular(DependencyObject element, bool value)
=> element.SetValue(CircularProperty, ValueBoxes.BooleanBox(value));
public static bool GetCircular(DependencyObject element)
=> (bool) element.GetValue(CircularProperty);
}
}

View File

@@ -0,0 +1,36 @@

using System.Windows;
using System.Windows.Media;
namespace HandyControl.Controls
{
public class IconElement
{
public static readonly DependencyProperty GeometryProperty = DependencyProperty.RegisterAttached(
"Geometry", typeof(Geometry), typeof(IconElement), new PropertyMetadata(default(Geometry)));
public static void SetGeometry(DependencyObject element, Geometry value)
=> element.SetValue(GeometryProperty, value);
public static Geometry GetGeometry(DependencyObject element)
=> (Geometry) element.GetValue(GeometryProperty);
public static readonly DependencyProperty WidthProperty = DependencyProperty.RegisterAttached(
"Width", typeof(double), typeof(IconElement), new PropertyMetadata(double.NaN));
public static void SetWidth(DependencyObject element, double value)
=> element.SetValue(WidthProperty, value);
public static double GetWidth(DependencyObject element)
=> (double) element.GetValue(WidthProperty);
public static readonly DependencyProperty HeightProperty = DependencyProperty.RegisterAttached(
"Height", typeof(double), typeof(IconElement), new PropertyMetadata(double.NaN));
public static void SetHeight(DependencyObject element, double value)
=> element.SetValue(HeightProperty, value);
public static double GetHeight(DependencyObject element)
=> (double) element.GetValue(HeightProperty);
}
}

View File

@@ -0,0 +1,111 @@

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using HandyControl.Tools;
using HandyControl.Tools.Interop;
namespace HandyControl.Controls
{
public class MenuTopLineAttach
{
public static readonly DependencyProperty PopupProperty = DependencyProperty.RegisterAttached(
"Popup", typeof(Popup), typeof(MenuTopLineAttach), new PropertyMetadata(default(Popup), OnPopupChanged));
private static void OnPopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var topLine = (FrameworkElement)d;
if (e.NewValue is Popup)
{
Popup popup = e.NewValue as Popup;
MenuItem menuItem = popup.TemplatedParent as MenuItem;
SetTopLine(menuItem, topLine);
menuItem.Loaded += MenuItem_Loaded;
}
}
private static void MenuItem_Loaded(object sender, RoutedEventArgs e)
{
var menuItem = (FrameworkElement)sender;
menuItem.Unloaded += MenuItem_Unloaded;
var topLine = GetTopLine(menuItem);
var popup = GetPopup(topLine);
if (popup != null)
{
popup.Opened += Popup_Opened;
}
}
private static void MenuItem_Unloaded(object sender, RoutedEventArgs e)
{
var menuItem = (FrameworkElement)sender;
menuItem.Unloaded -= MenuItem_Unloaded;
var topLine = GetTopLine(menuItem);
var popup = GetPopup(topLine);
if (popup != null)
{
popup.Opened -= Popup_Opened;
}
}
private static void Popup_Opened(object sender, EventArgs e)
{
var popup = (Popup)sender;
if (popup.TemplatedParent is MenuItem menuItem)
{
var topLine = GetTopLine(menuItem);
if (topLine == null) return;
topLine.HorizontalAlignment = HorizontalAlignment.Left;
topLine.Width = menuItem.ActualWidth;
topLine.Margin = new Thickness();
var positionLeftTop = menuItem.PointToScreen(new Point());
var positionRightBottom = menuItem.PointToScreen(new Point(menuItem.ActualWidth, menuItem.ActualHeight));
ScreenHelper.FindMonitorRectsFromPoint(InteropMethods.GetCursorPos(), out _, out var workAreaRect);
var panel = VisualHelper.GetParent<Panel>(topLine);
if (positionLeftTop.X < 0)
{
topLine.Margin = new Thickness(positionLeftTop.X - panel.Margin.Left, 0, 0, 0);
}
else if (positionLeftTop.X + panel.ActualWidth > workAreaRect.Right)
{
var overflowWidth = positionRightBottom.X - workAreaRect.Right;
if (overflowWidth > 0)
{
topLine.Width -= overflowWidth + panel.Margin.Right;
}
topLine.HorizontalAlignment = HorizontalAlignment.Left;
topLine.Margin = new Thickness(positionLeftTop.X + panel.ActualWidth - workAreaRect.Right + panel.Margin.Right, 0, 0, 0);
}
if (positionRightBottom.Y > workAreaRect.Bottom)
{
topLine.Width = 0;
topLine.HorizontalAlignment = HorizontalAlignment.Stretch;
topLine.Margin = new Thickness();
}
}
}
public static void SetPopup(DependencyObject element, Popup value)
=> element.SetValue(PopupProperty, value);
public static Popup GetPopup(DependencyObject element)
=> (Popup)element.GetValue(PopupProperty);
internal static readonly DependencyProperty TopLineProperty = DependencyProperty.RegisterAttached(
"TopLine", typeof(FrameworkElement), typeof(MenuTopLineAttach), new PropertyMetadata(default(FrameworkElement)));
internal static void SetTopLine(DependencyObject element, FrameworkElement value)
=> element.SetValue(TopLineProperty, value);
internal static FrameworkElement GetTopLine(DependencyObject element)
=> (FrameworkElement)element.GetValue(TopLineProperty);
}
}

View File

@@ -0,0 +1,19 @@

using System.Windows;
using HandyControl.Data;
namespace HandyControl.Controls
{
public class ScrollViewerAttach
{
public static readonly DependencyProperty AutoHideProperty = DependencyProperty.RegisterAttached(
"AutoHide", typeof(bool), typeof(ScrollViewerAttach), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
public static void SetAutoHide(DependencyObject element, bool value)
=> element.SetValue(AutoHideProperty, value);
public static bool GetAutoHide(DependencyObject element)
=> (bool) element.GetValue(AutoHideProperty);
}
}

View File

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

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using HandyControl.Data;
using HandyControl.Tools;
namespace HandyControl.Controls
{
public class ScrollViewer : System.Windows.Controls.ScrollViewer
{
private double _totalVerticalOffset;
private double _totalHorizontalOffset;
private bool _isRunning;
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
"Orientation", typeof(Orientation), typeof(ScrollViewer), new PropertyMetadata(Orientation.Vertical));
public Orientation Orientation
{
get => (Orientation) GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
public static readonly DependencyProperty CanMouseWheelProperty = DependencyProperty.Register(
"CanMouseWheel", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.TrueBox));
public bool CanMouseWheel
{
get => (bool) GetValue(CanMouseWheelProperty);
set => SetValue(CanMouseWheelProperty, ValueBoxes.BooleanBox(value));
}
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (!CanMouseWheel) return;
if (!IsInertiaEnabled)
{
if (Orientation == Orientation.Vertical)
{
base.OnMouseWheel(e);
}
else
{
_totalHorizontalOffset = HorizontalOffset;
CurrentHorizontalOffset = HorizontalOffset;
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
CurrentHorizontalOffset = _totalHorizontalOffset;
}
return;
}
e.Handled = true;
if (Orientation == Orientation.Vertical)
{
if (!_isRunning)
{
_totalVerticalOffset = VerticalOffset;
CurrentVerticalOffset = VerticalOffset;
}
_totalVerticalOffset = Math.Min(Math.Max(0, _totalVerticalOffset - e.Delta), ScrollableHeight);
ScrollToVerticalOffsetWithAnimation(_totalVerticalOffset);
}
else
{
if (!_isRunning)
{
_totalHorizontalOffset = HorizontalOffset;
CurrentHorizontalOffset = HorizontalOffset;
}
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
ScrollToHorizontalOffsetWithAnimation(_totalHorizontalOffset);
}
}
internal void ScrollToTopInternal(double milliseconds = 500)
{
if (!_isRunning)
{
_totalVerticalOffset = VerticalOffset;
CurrentVerticalOffset = VerticalOffset;
}
ScrollToVerticalOffsetWithAnimation(0, milliseconds);
}
public void ScrollToVerticalOffsetWithAnimation(double offset, double milliseconds = 500)
{
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
animation.EasingFunction = new CubicEase
{
EasingMode = EasingMode.EaseOut
};
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s, e1) =>
{
CurrentVerticalOffset = offset;
_isRunning = false;
};
_isRunning = true;
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
}
public void ScrollToHorizontalOffsetWithAnimation(double offset, double milliseconds = 500)
{
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
animation.EasingFunction = new CubicEase
{
EasingMode = EasingMode.EaseOut
};
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s, e1) =>
{
CurrentHorizontalOffset = offset;
_isRunning = false;
};
_isRunning = true;
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
}
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
IsPenetrating ? null : base.HitTestCore(hitTestParameters);
public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.RegisterAttached(
"IsInertiaEnabled", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
public static void SetIsInertiaEnabled(DependencyObject element, bool value) => element.SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
public static bool GetIsInertiaEnabled(DependencyObject element) => (bool) element.GetValue(IsInertiaEnabledProperty);
public bool IsInertiaEnabled
{
get => (bool) GetValue(IsInertiaEnabledProperty);
set => SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty IsPenetratingProperty = DependencyProperty.RegisterAttached(
"IsPenetrating", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
public bool IsPenetrating
{
get => (bool) GetValue(IsPenetratingProperty);
set => SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
}
public static void SetIsPenetrating(DependencyObject element, bool value) => element.SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
public static bool GetIsPenetrating(DependencyObject element) => (bool) element.GetValue(IsPenetratingProperty);
internal static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register(
"CurrentVerticalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentVerticalOffsetChanged));
private static void OnCurrentVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScrollViewer ctl && e.NewValue is double v)
{
ctl.ScrollToVerticalOffset(v);
}
}
internal double CurrentVerticalOffset
{
get => (double) GetValue(CurrentVerticalOffsetProperty);
set => SetValue(CurrentVerticalOffsetProperty, value);
}
internal static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register(
"CurrentHorizontalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentHorizontalOffsetChanged));
private static void OnCurrentHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScrollViewer ctl && e.NewValue is double v)
{
ctl.ScrollToHorizontalOffset(v);
}
}
internal double CurrentHorizontalOffset
{
get => (double) GetValue(CurrentHorizontalOffsetProperty);
set => SetValue(CurrentHorizontalOffsetProperty, value);
}
}
}

View File

@@ -0,0 +1,37 @@

using System;
using System.Windows;
using System.Windows.Controls;
namespace HandyControl.Controls
{
public class SimplePanel : Panel
{
protected override Size MeasureOverride(Size constraint)
{
var maxSize = new Size();
foreach (UIElement child in InternalChildren)
{
if (child != null)
{
child.Measure(constraint);
maxSize.Width = Math.Max(maxSize.Width, child.DesiredSize.Width);
maxSize.Height = Math.Max(maxSize.Height, child.DesiredSize.Height);
}
}
return maxSize;
}
protected override Size ArrangeOverride(Size arrangeSize)
{
foreach (UIElement child in InternalChildren)
{
child?.Arrange(new Rect(arrangeSize));
}
return arrangeSize;
}
}
}

View File

@@ -0,0 +1,24 @@

namespace HandyControl.Data
{
internal static class ValueBoxes
{
internal static object TrueBox = true;
internal static object FalseBox = false;
internal static object Double0Box = .0;
internal static object Double01Box = .1;
internal static object Double1Box = 1.0;
internal static object Double10Box = 10.0;
internal static object Double20Box = 20.0;
internal static object Double100Box = 100.0;
internal static object Double200Box = 200.0;
internal static object Double300Box = 300.0;
internal static object DoubleNeg1Box = -1.0;
internal static object Int0Box = 0;
internal static object Int1Box = 1;
internal static object Int2Box = 2;
internal static object Int5Box = 5;
internal static object Int99Box = 99;
internal static object BooleanBox(bool value) => value ? TrueBox : FalseBox;
}
}

View File

@@ -0,0 +1,81 @@

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using HandyControl.Tools.Extension;
namespace HandyControl.Tools
{
public class AnimationHelper
{
public static ThicknessAnimation CreateAnimation(Thickness thickness = default, double milliseconds = 200)
{
return new ThicknessAnimation(thickness, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
{
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
};
}
public static DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
{
return new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
{
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
};
}
internal static void DecomposeGeometryStr(string geometryStr, out double[] arr)
{
var collection = Regex.Matches(geometryStr, RegexPatterns.DigitsPattern);
arr = new double[collection.Count];
for (var i = 0; i < collection.Count; i++)
{
arr[i] = collection[i].Value.Value<double>();
}
}
internal static Geometry ComposeGeometry(string[] strings, double[] arr)
{
var builder = new StringBuilder(strings[0]);
for (var i = 0; i < arr.Length; i++)
{
var s = strings[i + 1];
var n = arr[i];
if (!double.IsNaN(n))
{
builder.Append(n).Append(s);
}
}
return Geometry.Parse(builder.ToString());
}
internal static Geometry InterpolateGeometry(double[] from, double[] to, double progress, string[] strings)
{
var accumulated = new double[to.Length];
for (var i = 0; i < to.Length; i++)
{
var fromValue = from[i];
accumulated[i] = fromValue + (to[i] - fromValue) * progress;
}
return ComposeGeometry(strings, accumulated);
}
internal static double[] InterpolateGeometryValue(double[] from, double[] to, double progress)
{
var accumulated = new double[to.Length];
for (var i = 0; i < to.Length; i++)
{
var fromValue = from[i];
accumulated[i] = fromValue + (to[i] - fromValue) * progress;
}
return accumulated;
}
}
}

View File

@@ -0,0 +1,32 @@

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace HandyControl.Tools.Converter
{
public class BorderCircularConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2 && values[0] is double width && values[1] is double height)
{
if (width < double.Epsilon || height < double.Epsilon)
{
return new CornerRadius();
}
var min = Math.Min(width, height);
return new CornerRadius(min / 2);
}
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View File

@@ -0,0 +1,33 @@

using System;
using System.ComponentModel;
namespace HandyControl.Tools.Extension
{
public static class StringExtension
{
public static T Value<T>(this string input)
{
try
{
return (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input);
}
catch
{
return default;
}
}
public static object Value(this string input, Type type)
{
try
{
return TypeDescriptor.GetConverter(type).ConvertFromString(input);
}
catch
{
return null;
}
}
}
}

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