Compare commits
165 Commits
5.4.9.0
...
v5.6.2.0-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c56855bbc7 | ||
|
|
9377804b06 | ||
|
|
c50ac7a53b | ||
|
|
677e7b5a59 | ||
|
|
8066d07a76 | ||
|
|
e8d6081f9f | ||
|
|
5fb888262e | ||
|
|
a4ffab7b50 | ||
|
|
8d25803b71 | ||
|
|
df4baca6bc | ||
|
|
dc43ab4c8f | ||
|
|
2249174f96 | ||
|
|
6916a63de6 | ||
|
|
1064a80dad | ||
|
|
4844215462 | ||
|
|
b84889b03d | ||
|
|
b38bfd9c65 | ||
|
|
b807ad8002 | ||
|
|
f5854cde1b | ||
|
|
bde4849465 | ||
|
|
8677efdb06 | ||
|
|
2bbd5705c2 | ||
|
|
0bf9b73ba8 | ||
|
|
42fd54269e | ||
|
|
28f1c5c132 | ||
|
|
30b60a5b4e | ||
|
|
f0c9dd7956 | ||
|
|
78ee4fbba2 | ||
|
|
243b45326e | ||
|
|
4efe85aad7 | ||
|
|
975f918703 | ||
|
|
d9f4218bb4 | ||
|
|
671c15385a | ||
|
|
091b9aad5b | ||
|
|
e51b745a13 | ||
|
|
ad1ea92cbd | ||
|
|
66bfb80f3c | ||
|
|
ef6b453673 | ||
|
|
5496d22c48 | ||
|
|
7cd3a8276d | ||
|
|
99ea7285ba | ||
|
|
9722d46d00 | ||
|
|
b115cf82d9 | ||
|
|
f4e72b5a99 | ||
|
|
24596626bd | ||
|
|
6e761c0a4e | ||
|
|
2a3738f79e | ||
|
|
1a475f9fe8 | ||
|
|
819b026ec7 | ||
|
|
38a816a255 | ||
|
|
e8af1d2ccf | ||
|
|
33cd881ae6 | ||
|
|
a3b6af9f22 | ||
|
|
458007862e | ||
|
|
2fac5d76e9 | ||
|
|
1e886fc124 | ||
|
|
c075278180 | ||
|
|
333d0ee62f | ||
|
|
7a6b2011e4 | ||
|
|
e4c65cd84e | ||
|
|
10e2a2cf3b | ||
|
|
0d72731ce7 | ||
|
|
33fb645694 | ||
|
|
d369c9db8e | ||
|
|
a935cac791 | ||
|
|
a08a4b4f92 | ||
|
|
bd2ba612de | ||
|
|
306d186bef | ||
|
|
da67d62946 | ||
|
|
50cc295e9e | ||
|
|
bec97545d1 | ||
|
|
db5f0334c4 | ||
|
|
42c623c8ca | ||
|
|
d3c1e2ab56 | ||
|
|
57e60287ff | ||
|
|
007fbf8be5 | ||
|
|
d3baa47f93 | ||
|
|
225905ebff | ||
|
|
c08ddd5057 | ||
|
|
970dfc069d | ||
|
|
9b5f9a64fd | ||
|
|
6720e2429e | ||
|
|
5070b166d9 | ||
|
|
8b6d12d57b | ||
|
|
8888747137 | ||
|
|
d83b5b14a8 | ||
|
|
17ecd9cb82 | ||
|
|
0829b4bd9e | ||
|
|
fbc9652f20 | ||
|
|
c7d9d658f2 | ||
|
|
1c525618e2 | ||
|
|
9ead5dbd19 | ||
|
|
625e887dc1 | ||
|
|
60cbf894e5 | ||
|
|
95a3403898 | ||
|
|
fbf50e7466 | ||
|
|
e9b6988a69 | ||
|
|
8d49c96c57 | ||
|
|
ea56dcdda8 | ||
|
|
5ef8340ba3 | ||
|
|
51e1e85867 | ||
|
|
b24f740129 | ||
|
|
653d66c343 | ||
|
|
3dd4ae1bfc | ||
|
|
27c8ae79e0 | ||
|
|
53e3231452 | ||
|
|
bcf98d847a | ||
|
|
b6ee67d506 | ||
|
|
3f13747413 | ||
|
|
54046d5c9d | ||
|
|
8966f25e06 | ||
|
|
27fca2cb82 | ||
|
|
0d1a17a41a | ||
|
|
517e4a1142 | ||
|
|
a380f87b5f | ||
|
|
35d9d29d40 | ||
|
|
e1c9d81496 | ||
|
|
fbeeb3f015 | ||
|
|
48735a602a | ||
|
|
886f3349ae | ||
|
|
43c150a18b | ||
|
|
33bbc4a2c4 | ||
|
|
6c4a014e57 | ||
|
|
ce0dd9ceec | ||
|
|
3520ce6a3f | ||
|
|
376f8226ab | ||
|
|
6b6ae6bfef | ||
|
|
b13dbf0b59 | ||
|
|
0f7ac5c0ba | ||
|
|
25b94bc2c1 | ||
|
|
445730a833 | ||
|
|
fd1590142e | ||
|
|
c41adc54c5 | ||
|
|
a3f6b105de | ||
|
|
6e402d4931 | ||
|
|
c40a0d8835 | ||
|
|
28416dc3d2 | ||
|
|
1bde5b6836 | ||
|
|
d1619bca22 | ||
|
|
a123c38dfd | ||
|
|
e02d1850a2 | ||
|
|
bd37761fc5 | ||
|
|
897b901c7c | ||
|
|
da882c3c11 | ||
|
|
bd1a46d18d | ||
|
|
1c23c10c81 | ||
|
|
55f16d2c53 | ||
|
|
bac8b2b96c | ||
|
|
08328c91c4 | ||
|
|
6634ef094c | ||
|
|
3b6e6167b0 | ||
|
|
f55dfa7a73 | ||
|
|
93f0c970da | ||
|
|
aa94da9767 | ||
|
|
8340c18257 | ||
|
|
075e238c46 | ||
|
|
6e6b5ae98c | ||
|
|
2078ff867b | ||
|
|
446d88e16a | ||
|
|
ebacaa0341 | ||
|
|
8420abd915 | ||
|
|
650c41eb8a | ||
|
|
db3018bbf5 | ||
|
|
539f94d1c9 | ||
|
|
f56502d8f3 |
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
github: stax76
|
||||
patreon: stax76
|
||||
ko_fi: stax76
|
||||
340
License.txt
Normal 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.
|
||||
76
README.md
@@ -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
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
#### Context Menu
|
||||
@@ -139,11 +146,24 @@ OSD console and status printed on the terminal.
|
||||
|
||||
Searchable key and mouse binding editor.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
#### Command Palette
|
||||
|
||||
Command Palette to find commands and shortcut keys easily.
|
||||
Command Palette to easily find commands and shortcut keys.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
#### Playlist
|
||||
|
||||
The command palette based playlist showing my favorite artist of the stax record label.
|
||||
|
||||

|
||||
|
||||
|
||||
List of my apps
|
||||
---------------
|
||||
|
||||
https://stax76.github.io/frankskare
|
||||
|
||||
@@ -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)
|
||||
====================
|
||||
|
||||
|
||||
@@ -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.
|
||||
186
docs/Manual.md
@@ -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
2
docs/Privacy.md
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
mpv.net does not collect any personal information.
|
||||
BIN
docs/Universal Remote/icon.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
docs/Universal Remote/icon_hires.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
44
docs/Universal Remote/layout.xml
Normal 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>
|
||||
5
docs/Universal Remote/meta.prop
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
meta.name: custom keys
|
||||
meta.author: stax76
|
||||
meta.description: custom keys
|
||||
meta.tags: mpv
|
||||
106
docs/Universal Remote/remote.lua
Normal 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
|
||||
|
Before Width: | Height: | Size: 1.2 MiB |
BIN
docs/img/CommandPalette.webp
Normal file
|
After Width: | Height: | Size: 672 KiB |
|
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 272 KiB |
|
Before Width: | Height: | Size: 214 KiB |
BIN
docs/img/InputEditor.webp
Normal file
|
After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 2.5 MiB |
BIN
docs/img/Main.webp
Normal file
|
After Width: | Height: | Size: 442 KiB |
|
Before Width: | Height: | Size: 628 KiB |
|
Before Width: | Height: | Size: 603 KiB After Width: | Height: | Size: 536 KiB |
BIN
docs/img/Playlist.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 355 KiB |
22
src/.editorconfig
Normal 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
|
||||
@@ -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);
|
||||
|
||||
148
src/Misc/App.cs
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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("-", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
115
src/Misc/Misc.cs
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
BIN
src/Package/Images/LockScreenLogo.scale-200.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/Package/Images/SplashScreen.scale-200.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
src/Package/Images/Square150x150Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/Package/Images/Square44x44Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/Package/Images/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
src/Package/Images/Wide310x150Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
137
src/Package/Package.appxmanifest
Normal 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>
|
||||
134
src/Package/mpv.net.package.wapproj
Normal 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)' < '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>
|
||||
@@ -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")]
|
||||
|
||||
77
src/Properties/Resources.Designer.cs
generated
@@ -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 = "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", h [rest of string was truncated]";.
|
||||
///[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]";.
|
||||
/// </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 '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 '.
|
||||
///# 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 'Settings'.
|
||||
///
|
||||
/// # The [rest of string was truncated]";.
|
||||
///# 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 > Show Keys
|
||||
///
|
||||
///# m [rest of string was truncated]";.
|
||||
/// </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 = '${filename}'
|
||||
///script-opts = osc-scalewindowed=1.5,osc-hidetimeout=2000,osc-greenandgrumpy=yes,console-scale=1
|
||||
///screenshot-directory = '~~desktop/'
|
||||
///
|
||||
///[protocol.https]
|
||||
///osd-playing-msg = '${media-title}'
|
||||
///.
|
||||
/// </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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
683
src/Resources/editor_conf.txt
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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}'
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
62
src/Scripts/Lua/delete-current-file.lua
Normal 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)
|
||||
@@ -17,4 +17,4 @@ $code = {
|
||||
}
|
||||
}
|
||||
|
||||
$mp.register_event("client-message", $code)
|
||||
$mp.RegisterEvent("client-message", $code)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"""
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
126
src/WPF/CommandPaletteControl.xaml
Normal 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>
|
||||
141
src/WPF/CommandPaletteControl.xaml.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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/");
|
||||
|
||||
@@ -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>
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/WPF/HandyControl/Controls/Attach/BorderElement.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
36
src/WPF/HandyControl/Controls/Attach/IconElement.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
111
src/WPF/HandyControl/Controls/Attach/MenuTopLineAttach.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
19
src/WPF/HandyControl/Controls/Attach/ScrollViewerAttach.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
192
src/WPF/HandyControl/Controls/ScrollViewer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/WPF/HandyControl/Controls/SimplePanel.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/WPF/HandyControl/Data/ValueBoxes.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
81
src/WPF/HandyControl/Tools/AnimationHelper.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/WPF/HandyControl/Tools/Extension/StringExtension.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||