Compare commits
372 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cadc5d65cf | ||
|
|
3e2f104aa7 | ||
|
|
c87ce3b66f | ||
|
|
3093dd43a4 | ||
|
|
061bb39b60 | ||
|
|
d994c79d5d | ||
|
|
9ca66db07b | ||
|
|
4a382d4e29 | ||
|
|
69a5ba4470 | ||
|
|
4a890a4da7 | ||
|
|
023c1db417 | ||
|
|
7ef1f9315e | ||
|
|
a148c88435 | ||
|
|
f6ad169f9d | ||
|
|
e69a5559e8 | ||
|
|
500fe9abc4 | ||
|
|
55f4a340af | ||
|
|
b17ed3675e | ||
|
|
34031fa15d | ||
|
|
d6d31d8ae9 | ||
|
|
0bfee26418 | ||
|
|
71d6b96c10 | ||
|
|
d1b7250a7a | ||
|
|
39b81d0664 | ||
|
|
6337818dbc | ||
|
|
2257af6294 | ||
|
|
572257b645 | ||
|
|
6eb82b6b7e | ||
|
|
7ef703da42 | ||
|
|
f7f8aa550a | ||
|
|
8d693b5e01 | ||
|
|
e8bc8311e6 | ||
|
|
19c4a1d6c1 | ||
|
|
a53fa7178f | ||
|
|
09aee26cd4 | ||
|
|
0c6e486eb0 | ||
|
|
1561ed90f6 | ||
|
|
c2f965ced9 | ||
|
|
aed524bbc5 | ||
|
|
8cf7e4fd71 | ||
|
|
0ebcf12502 | ||
|
|
2af13e995f | ||
|
|
2e2562fefc | ||
|
|
1860c42114 | ||
|
|
8782ae8ad2 | ||
|
|
5d9cde10ce | ||
|
|
2ee2b31bc0 | ||
|
|
4cd92db141 | ||
|
|
8ee389e8cb | ||
|
|
971fe1fe7c | ||
|
|
e9df0f9f99 | ||
|
|
d465b13a03 | ||
|
|
412d4d7238 | ||
|
|
1dd93bfcff | ||
|
|
4ebf241306 | ||
|
|
1a714a39df | ||
|
|
b2b387c017 | ||
|
|
bf43328e7a | ||
|
|
4cba6bb03c | ||
|
|
72f9f156b8 | ||
|
|
c78719c3bf | ||
|
|
7e4ea640cf | ||
|
|
6ddca6d608 | ||
|
|
0fae17b42a | ||
|
|
7e834cea6d | ||
|
|
6fc546c69c | ||
|
|
e8baa21d42 | ||
|
|
4c3c65dded | ||
|
|
843f7d1a41 | ||
|
|
673d5a8c0e | ||
|
|
6bd4540106 | ||
|
|
5b57e6214e | ||
|
|
27f7935127 | ||
|
|
cd84819a03 | ||
|
|
0efc335232 | ||
|
|
b04fb9b789 | ||
|
|
354d5493c4 | ||
|
|
3e499befbc | ||
|
|
bc0fc2a29d | ||
|
|
229ace708d | ||
|
|
2708937554 | ||
|
|
66654537fe | ||
|
|
5d16d7b2d1 | ||
|
|
b3ebf85772 | ||
|
|
733f0999e1 | ||
|
|
2aec8856c7 | ||
|
|
a0d5a6f234 | ||
|
|
d9afd172f9 | ||
|
|
3b9368230c | ||
|
|
7d510a8ba7 | ||
|
|
e7f08bf0a7 | ||
|
|
ad3235bb96 | ||
|
|
b5b18f2a1a | ||
|
|
28f9df1cee | ||
|
|
cd2f2aeec8 | ||
|
|
a15d2cdbbe | ||
|
|
f489d59168 | ||
|
|
309ddbf08e | ||
|
|
1bc6fb9509 | ||
|
|
88e5628d7b | ||
|
|
27dc98af21 | ||
|
|
ce12eb61fd | ||
|
|
8ed62df8e2 | ||
|
|
f4b4be5466 | ||
|
|
9a33bea7e7 | ||
|
|
3f469897b0 | ||
|
|
1aa380f768 | ||
|
|
b0c3988a9d | ||
|
|
8c02bb59ee | ||
|
|
d60bf050cf | ||
|
|
a0f2e8bd92 | ||
|
|
63db623d07 | ||
|
|
ab0b2c4da2 | ||
|
|
091e159d10 | ||
|
|
91fa89b058 | ||
|
|
36d3543852 | ||
|
|
72ed687390 | ||
|
|
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 | ||
|
|
57ae0d008b | ||
|
|
e128a4868b | ||
|
|
3875e1c1bf | ||
|
|
dd508907eb | ||
|
|
765854cd10 | ||
|
|
69fe7c091a | ||
|
|
45a2b7f976 | ||
|
|
a8cf3407e7 | ||
|
|
b8163c3c3e | ||
|
|
9d27465492 | ||
|
|
bba71c3782 | ||
|
|
eaa8a3ca6c | ||
|
|
0b28770d1a | ||
|
|
45d3386a88 | ||
|
|
8df330b7aa | ||
|
|
69857e0548 | ||
|
|
b1388e10e5 | ||
|
|
6f7f127279 | ||
|
|
18c8f5783b | ||
|
|
cdf3eb1373 | ||
|
|
e5bcd0fc29 | ||
|
|
b0dc44a98e | ||
|
|
41a14cd3b7 | ||
|
|
b38c7cf834 | ||
|
|
2ee4c1e647 | ||
|
|
2bcf97a97a | ||
|
|
8eaec77b0c | ||
|
|
3161ba1022 | ||
|
|
496bba71d4 | ||
|
|
3e1e822e56 | ||
|
|
b1ea6da39b | ||
|
|
8d54abae4c | ||
|
|
3583aa11ed | ||
|
|
642c36bacf | ||
|
|
0343b32847 | ||
|
|
6e2d11952f | ||
|
|
d0ad69656a | ||
|
|
62789fa036 | ||
|
|
a7fe444067 | ||
|
|
1ef4740b09 | ||
|
|
c5e445da17 | ||
|
|
a52de9039d | ||
|
|
8db8e497a5 | ||
|
|
28c9b2710c | ||
|
|
6ba9b1f05a | ||
|
|
ea5d3e64ee | ||
|
|
636d28ac54 | ||
|
|
6e54286a60 | ||
|
|
b396012934 | ||
|
|
f3909acdfe | ||
|
|
3ed71444a7 | ||
|
|
cab7c6d49b | ||
|
|
368641523a | ||
|
|
42c76d25c6 | ||
|
|
3968fa50f5 | ||
|
|
4d985c7b7c | ||
|
|
235a52a701 | ||
|
|
9a63b660de | ||
|
|
8eb0222873 | ||
|
|
bf8636135a | ||
|
|
33cdee5497 | ||
|
|
564d7b10a0 | ||
|
|
a1a408da1d | ||
|
|
85a3506403 | ||
|
|
e860cf52c4 | ||
|
|
32a46e47e2 | ||
|
|
538e91aaa9 | ||
|
|
94eaf8144f | ||
|
|
404a8f110d | ||
|
|
14f5228754 | ||
|
|
5ec2d1b436 | ||
|
|
32c6ce3a44 | ||
|
|
b86148dfb3 | ||
|
|
26e94fad2b | ||
|
|
c306eb032f | ||
|
|
09944583dd | ||
|
|
8f4ad52469 | ||
|
|
5f4eca21e5 | ||
|
|
b4632a0b6e | ||
|
|
c14a11170d | ||
|
|
723005b28f | ||
|
|
72f25a686e | ||
|
|
b1fb940759 | ||
|
|
1020cd70d1 | ||
|
|
50a2f13dbe | ||
|
|
b1ffb8291f | ||
|
|
dbc8ddaf2b | ||
|
|
b42cb6be05 | ||
|
|
b63363336f | ||
|
|
b0ef161ed9 |
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
github: stax76
|
||||
patreon: stax76
|
||||
ko_fi: stax76
|
||||
10
.github/ISSUE_TEMPLATE/ask-a-question.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Ask a question
|
||||
about: Ask a question about mpv.net
|
||||
title: ''
|
||||
labels: question
|
||||
assignees: stax76
|
||||
|
||||
---
|
||||
|
||||
This template is meant for usage questions of mpv.net.
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: Bug report
|
||||
name: Report a bug
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
name: Feature request
|
||||
name: Request a feature
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
labels: feature request
|
||||
assignees: stax76
|
||||
|
||||
---
|
||||
24
LICENSE.txt
@@ -1,24 +0,0 @@
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2017-2020 Frank Skare (stax76)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and ssociated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
340
License.txt
Normal file
@@ -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.
|
||||
109
README.md
@@ -1,13 +1,24 @@
|
||||
|
||||

|
||||

|
||||
|
||||
    
|
||||
|
||||
🎞 mpv.net
|
||||
==========
|
||||
|
||||
mpv.net is a modern media player for Windows based on the popular [mpv](https://mpv.io) player.
|
||||
mpv.net is a modern desktop media player for Windows based on the popular [mpv](https://mpv.io) player.
|
||||
|
||||
mpv.net is designed to be mpv compatible, almost all mpv features are available
|
||||
because they are all contained in libmpv, this means the official
|
||||
[mpv manual](https://mpv.io/manual/master/) applies to mpv.net.
|
||||
|
||||
mpv focuses on the usage of the command line and the terminal,
|
||||
mpv.net retains the ability to be used from the command line and
|
||||
the terminal and adds a modern Windows GUI on top of it.
|
||||
|
||||
Like mpv, mpv.net is designed for power users, for regular users there is a
|
||||
[mpv.net-next](https://github.com/mpv-net-player/mpv.net-next)
|
||||
project under construction.
|
||||
|
||||
#### Graphical User Interface
|
||||
|
||||
@@ -16,12 +27,14 @@ Modern GUI with customizable color themes.
|
||||
|
||||
#### Command Line Interface
|
||||
|
||||
mpv.net supports mpvs property based command line switches.
|
||||
mpv.net supports mpvs command line interface.
|
||||
|
||||
|
||||
#### High quality video output
|
||||
|
||||
Video output that is capable of many features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more.
|
||||
Video output that is capable of many features loved by videophiles,
|
||||
such as video scaling with popular high quality algorithms,
|
||||
color management, frame timing, interpolation, HDR, and more.
|
||||
|
||||
|
||||
#### On Screen Controller
|
||||
@@ -41,68 +54,75 @@ mpv.net is under active development.
|
||||
|
||||
#### Based on libmpv
|
||||
|
||||
mpv.net is based on libmpv which offers a straightforward C API that was designed from the ground up to make mpv usable as a library and facilitate easy integration into other applications. mpv is like VLC not based on DirectShow or Media Foundation.
|
||||
mpv.net is based on libmpv which offers a straightforward C API that
|
||||
was designed from the ground up to make mpv usable as a library and
|
||||
facilitate easy integration into other applications.
|
||||
mpv is like VLC not based on DirectShow or Media Foundation.
|
||||
|
||||
|
||||
Table of contents
|
||||
-----------------
|
||||
|
||||
- [Features](#features)
|
||||
- [Features](#features-that-mpv-and-mpvnet-have-in-common)
|
||||
- [Support](#support)
|
||||
- [Download](#download)
|
||||
- [Manual](#manual)
|
||||
- [Screenshots](#screenshots)
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
Features that mpv and mpv.net have in common
|
||||
--------------------------------------------
|
||||
|
||||
- High degree of mpv compatibility, almost all mpv features are available
|
||||
- Customizable context menu defined in the same file as the key bindings
|
||||
- Config dialog
|
||||
- Shorcut key editor
|
||||
- Many features like the config editor and shortcut key editor are fully searchable
|
||||
- Configuration files that are easy to read and edit
|
||||
- Command palette to quickly find commands and keys
|
||||
- Modern graphical user interface with customizable color themes
|
||||
- Extension API for .NET languages (C#, VB.NET and F#)
|
||||
- Scripting API for C#, Lua, JavaScript and PowerShell
|
||||
- Lua and JavaScript Scripting
|
||||
- Hundreds available user scripts make mpv the most feature rich desktop video player
|
||||
- Simple config files that are easy to read and edit
|
||||
- JSON IPC to control the player with a external programs
|
||||
- On Screen Controler (OSC, play control buttons) with modern flat design
|
||||
- Command Line Interface
|
||||
- Started from a terminal status and debug output is printed on the terminal
|
||||
- Started from a terminal status, error and debug output is printed on the terminal
|
||||
- DXVA2 video decoding acceleration
|
||||
- Video output capable of features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more
|
||||
- File search feature powered by the popular search and index tool Everything
|
||||
- Browser extensions to start mpv.net from the browser
|
||||
- Fast seek performance
|
||||
- Fast startup performance
|
||||
- Usable as video player, audio player and image viewer with a wide range of supported formats
|
||||
- Built-in decoders, no external codecs have to be installed
|
||||
- Setup as x64, x86, installer, portable, Chocolatey and Scoop
|
||||
- Build-in media streaming via youtube-dl
|
||||
- File associations can be created by the setup and from the player
|
||||
- Build-in media streaming (requires yt-dlp being installed)
|
||||
- External audio and subtitle files can be loaded manually or automatically
|
||||
- Screenshot feature
|
||||
- Watch later feature to save the video position
|
||||
|
||||
|
||||
Features exclusiv to mpv.net
|
||||
----------------------------
|
||||
|
||||
- Very high degree of mpv compatibility, almost all mpv features are available
|
||||
- Modern graphical user interface with customizable color themes
|
||||
- Customizable context menu defined in the same file as the key bindings
|
||||
- Searchable config editor
|
||||
- Searchable input (shorcut keys) editor
|
||||
- C# and PowerShell Scripting
|
||||
- Global keyboard shortcuts
|
||||
- Command palette to quickly and easily find commands and keys
|
||||
- Extension API for .NET languages (C#, VB.NET and F#)
|
||||
- Portable, MS Store or WinGet download and installation
|
||||
- File history feature to log time and filename
|
||||
- Watch later feature to save the position
|
||||
- Files can be enqueued from File Explorer
|
||||
- Update check and update routine
|
||||
|
||||
|
||||
## [Support](Manual.md#support)
|
||||
## [Support](docs/Manual.md#support)
|
||||
|
||||
[Support section of the manual.](Manual.md#support)
|
||||
[Support section of the manual.](docs/Manual.md#support)
|
||||
|
||||
|
||||
## [Download](Manual.md#download)
|
||||
## [Download](docs/Manual.md#download)
|
||||
|
||||
[Download section of the manual.](Manual.md#download)
|
||||
[Download section of the manual.](docs/Manual.md#download)
|
||||
|
||||
|
||||
## [Manual](Manual.md)
|
||||
## [Manual](docs/Manual.md)
|
||||
|
||||
[The mpv.net documentation.](Manual.md)
|
||||
[The mpv.net documentation.](docs/Manual.md)
|
||||
|
||||
|
||||
Screenshots
|
||||
@@ -110,39 +130,52 @@ Screenshots
|
||||
|
||||
#### Main Window
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
#### Context Menu
|
||||
|
||||
Context menu using dark mode.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
#### Config Editor
|
||||
|
||||
Searchable config editor as alternative to edit the conf file manually.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
#### Terminal
|
||||
|
||||
OSD console and status printed on the terminal.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
#### Input Editor
|
||||
|
||||
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
|
||||
|
||||
97
Release.ps1
@@ -1,97 +0,0 @@
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$desktopDir = [Environment]::GetFolderPath('Desktop')
|
||||
$exePath = $PSScriptRoot + '\mpv.net\bin\x64\mpvnet.exe'
|
||||
$versionInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($exePath)
|
||||
$vsDir = 'C:\Program Files (x86)\Microsoft Visual Studio\2019'
|
||||
$msBuild = $vsDir + '\Community\MSBuild\Current\Bin\MSBuild.exe'
|
||||
$inno = 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe'
|
||||
$7z = 'C:\Program Files\7-Zip\7z.exe'
|
||||
|
||||
$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)
|
||||
{
|
||||
& $msBuild mpv.net.sln -t:Rebuild -p:Configuration=Debug -p:Platform=x64
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
& $msBuild mpv.net.sln -t:Rebuild -p:Configuration=Debug -p:Platform=x86
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
& $inno /Darch=x64 setup.iss
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
& $inno /Darch=x86 setup.iss
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
$targetDir = $desktopDir + "\mpv.net-portable-x64-$($versionInfo.FileVersion)"
|
||||
Copy-Item .\mpv.net\bin\x64 $targetDir -Recurse -Exclude System.Management.Automation.xml
|
||||
& $7z a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
& $7z a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
$targetDir = $desktopDir + "\mpv.net-portable-x86-$($versionInfo.FileVersion)"
|
||||
Copy-Item .\mpv.net\bin\x86 $targetDir -Recurse -Exclude System.Management.Automation.xml
|
||||
& $7z a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
& $7z a -tzip -mx9 "$targetDir.zip" -r "$targetDir\*"
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
Set-Clipboard ($versionInfo.FileVersion + "`n`nChangelog:`n`n" +
|
||||
'https://github.com/stax76/mpv.net/blob/master/Changelog.md' + "`n`nDownload:`n`n" +
|
||||
'https://github.com/stax76/mpv.net/blob/master/Manual.md#stable')
|
||||
}
|
||||
else
|
||||
{
|
||||
& $msBuild mpv.net.sln -t:Rebuild -p:Configuration=Debug -p:Platform=x64
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
& $msBuild mpv.net.sln -t:Rebuild -p:Configuration=Debug -p:Platform=x86
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
$targetDir = "$desktopDir\mpv.net-portable-x64-$($versionInfo.FileVersion)-beta"
|
||||
Copy-Item .\mpv.net\bin\x64 $targetDir -Recurse -Exclude System.Management.Automation.xml
|
||||
& $7z a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
UploadBeta "$targetDir.7z"
|
||||
|
||||
$targetDir = $desktopDir + "\mpv.net-portable-x86-$($versionInfo.FileVersion)-beta"
|
||||
Copy-Item .\mpv.net\bin\x86 $targetDir -Recurse -Exclude System.Management.Automation.xml
|
||||
& $7z a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
UploadBeta "$targetDir.7z"
|
||||
|
||||
foreach ($cloudDirectory in $cloudDirectories)
|
||||
{
|
||||
Invoke-Item $cloudDirectory
|
||||
}
|
||||
|
||||
Set-Clipboard ($versionInfo.FileVersion + " Beta`n`nChangelog:`n`n" +
|
||||
'https://github.com/stax76/mpv.net/blob/master/Changelog.md' + "`n`nDownload:`n`n" +
|
||||
'https://github.com/stax76/mpv.net/blob/master/Manual.md#beta')
|
||||
}
|
||||
|
||||
Write-Host 'successfully finished' -ForegroundColor Green
|
||||
@@ -1,9 +1,391 @@
|
||||
|
||||
5.4.8.1 Beta (not yet released)
|
||||
# 6.0.1.0
|
||||
|
||||
- New tutorial: [Extending mpv and mpv.net via Lua scripting](https://github.com/stax76/mpv.net/wiki/Extending-mpv-and-mpv.net-via-Lua-scripting)
|
||||
- New options `autofit-image` and `autofit-audio`, like autofit, but used for image and audio files.
|
||||
- New [auto-mode](https://github.com/stax76/mpv-scripts) script to use mpv and mpv.net as image viewer and audio player.
|
||||
- New [smart-volume](https://github.com/stax76/mpv-scripts) script. Records the volume per file in order to restore it
|
||||
in future sessions. What is recorded and restored is the volume offset relative to the session average volume.
|
||||
- New support of the mpv option `snap-window`.
|
||||
- New feature to show chapters in the command palette, see binding and menu definition below.
|
||||
- New option minimum-aspect-ratio-audio, same as minimum-aspect-ratio but used for audio files.
|
||||
- Fix long commands causing key bindings not visible in the command palette.
|
||||
- Fix script compatibility with mordenx and mpv-osc-tethys.
|
||||
- Fix borderless window not resizable with mouse.
|
||||
- Fix start-size=session not working.
|
||||
- Fix chapters that are script created after the media file is loaded.
|
||||
- Width of command palette slightly increased.
|
||||
- The default key bindings for 0 and 9 change the volume, like mpv.
|
||||
- When a menu item is defined multiple times with different key bindings,
|
||||
only one menu item is created, it shows all bindings.
|
||||
- libmpv zhongfly 2022-06-19
|
||||
|
||||
input.conf changes:
|
||||
|
||||
New:
|
||||
|
||||
```
|
||||
Ctrl+c script-message-to mpvnet show-chapters #menu: View > Show Chapters
|
||||
```
|
||||
|
||||
# 6.0.0.0 Beta (2022-06-05)
|
||||
|
||||
- The options `cache` and `demuxer-max-bytes`have been added
|
||||
to the conf editor.
|
||||
- Command messages are dispatched with `script-message-to mpvnet`.
|
||||
- New feature to change profile using the command palette.
|
||||
- New feature to show media info on screen, the command palette shows
|
||||
an osd option and the show-info command shows more detailed info
|
||||
after a second key press. Media info display in the track menu
|
||||
was also improved. Thanks to dyphire helping with code.
|
||||
- New `media-info` option allowing to use mpv `track-list`
|
||||
instead of the media info library.
|
||||
- New show-santa-logo (green and grumpy) option.
|
||||
- New quick bookmark feature, see manual.
|
||||
- Progress command shows time and date.
|
||||
- When input.conf is created on the very first start and a
|
||||
script-opts folder does not exist, a script-opts folder
|
||||
is created with osc and console defaults:
|
||||
`console-scale=1.5`
|
||||
`osc-idlescreen=no` (hides the original mpv logo)
|
||||
`osc-hidetimeout=2000`
|
||||
`osc-scalewindowed=1.5`
|
||||
- Support mpv idle property, see manual for remarks.
|
||||
- Fix external audio and subtitle files not shown in all use cases.
|
||||
- Fix various mpv options not working in case of existing same line comments.
|
||||
- Fix crash choosing Matroska edition in the menu.
|
||||
- Fix auto-play and auto-load-folder not working with user scripts.
|
||||
- Fix slow startup using `osd-scale-by-window=no`.
|
||||
- Fix URL shown instead of media title on file change OSD,
|
||||
in recent menu and in recent command palette.
|
||||
- Fix chapter time display in menu.
|
||||
- Fix incorrect startup window size using gpu-api=vulkan.
|
||||
- Fix logo not hiding sometimes using gpu-api=vulkan.
|
||||
- libmpv shinchiro 2022-06-05
|
||||
|
||||
input.conf changes:
|
||||
|
||||
Old:
|
||||
|
||||
```
|
||||
F9 show-text ${track-list} 5000 #menu: View > Show Tracks
|
||||
```
|
||||
|
||||
New:
|
||||
|
||||
```
|
||||
F9 script-message-to mpvnet show-media-info osd #menu: View > Show Tracks
|
||||
Ctrl+p script-message-to mpvnet select-profile #menu: View > Show Profile Selection
|
||||
Alt+q script-message-to mpvnet quick-bookmark
|
||||
```
|
||||
|
||||
All occurrences of `script-message mpv.net` were changed to `script-message-to mpvnet`.
|
||||
|
||||
|
||||
# 5.9.0.0 Beta (2022-05-08)
|
||||
|
||||
- Fix startup without media file not working with gpu-api=vulkan.
|
||||
- Fix keyboard layout change not working.
|
||||
- Fix multi monitor setup with different DPI values not working.
|
||||
- Fix config editor handling `keep-open` and `keep-open-pause` incorrectly.
|
||||
- New mpv.net specific option `keep-open-exit` added. If set to yes and
|
||||
keep-open is set to no, mpv.net exits after the last file ends.
|
||||
- New `playlist-add` command added to change the playlist position,
|
||||
jumps to the other end when the beginning or end is reached.
|
||||
Ctrl+F11 goes 10 positions backward.
|
||||
Ctrl+F12 goes 10 positions forward.
|
||||
- libmpv zhongfly 2022-05-07
|
||||
|
||||
|
||||
5.8.0.0 Beta (2022-04-02)
|
||||
|
||||
- Fix crash on Windows 7 systems without PowerShell.
|
||||
- Fix showing incorrect timestamps in About dialog of Store version.
|
||||
- Fix Store page showing non-existent ARM and x86 support.
|
||||
- Fix opening zip files.
|
||||
- The list of available input commands is like before shown
|
||||
by the text editor, so it's like everything else searchable.
|
||||
- Media Info isn't shown directly, instead the command palette
|
||||
shows several choices. The command palette can be bypassed
|
||||
using the arguments: msgbox, editor, full, raw.
|
||||
https://github.com/stax76/mpv.net/blob/master/docs/Manual.md#show-media-info-flags
|
||||
- mpv.net specific commands, the command palette, auto-play property
|
||||
and various other things are documented in the manual.
|
||||
- The action used for the right mouse button can be configured.
|
||||
https://github.com/stax76/mpv.net/blob/master/docs/Manual.md#show-menu
|
||||
- Workaround not reproducible logo drawing crash.
|
||||
- Info command shows the length.
|
||||
- New mpv.net specific option `show-logo` that allows to disable
|
||||
the drawing of the blue mpv.net logo on top of the native OSC logo.
|
||||
- MediaInfo 22.03
|
||||
|
||||
|
||||
5.7.0.0 Stable (2022-03-09)
|
||||
|
||||
- Improved title and chapter menu for Blu-Rays.
|
||||
- Fix of conf folder virtualization issue of MS Store version.
|
||||
|
||||
5.6.2.0 Beta (2022-03-05)
|
||||
|
||||
- Fix script-opts files being ignored, removed options are:
|
||||
script-opts = osc-scalewindowed=1.5,osc-hidetimeout=2000,console-scale=1.5
|
||||
- Update MediaInfo to version 21.9.0.0 and
|
||||
write version and date in About dialog.
|
||||
- Provide setup options in command palette to ensure backward
|
||||
compatibility with previous input.conf definitions.
|
||||
|
||||
5.6.1.0 Beta (2022-03-05)
|
||||
|
||||
- Various conf editor improvements. (hooke007)
|
||||
- Custom conf folder location feature removed.
|
||||
- Inno Setup replaced with Microsoft Store setup.
|
||||
- Fix script-opts files being ignored.
|
||||
- Showing the recent list in the command palette,
|
||||
the top item gets auto selected.
|
||||
https://github.com/stax76/mpv.net/issues/328#issuecomment-1057296054
|
||||
- If the play list is empty, the most recent file
|
||||
gets loaded when pressing space.
|
||||
https://github.com/stax76/mpv.net/issues/328#issuecomment-1057296054
|
||||
- Ctrl+v (previously u) opens files (or URLs) from the clipboard,
|
||||
previously it had to be a file path (format string) and now
|
||||
it can also be the clipboard format of type file.
|
||||
- The usability of the menu structure was improved.
|
||||
- Audio and subtitle tracks and various other features
|
||||
are now available in the command palette.
|
||||
- Single character input in the command palette searches exclusively
|
||||
key bindings, much like the search field of the input editor.
|
||||
- Various default key bindings improved.
|
||||
- New protocol registrations, so far supported are: ytdl, rtsp, srt, srtp
|
||||
- libmpv zhongfly 2022-02-27
|
||||
|
||||
|
||||
5.5.0.4 Beta (2021-11-05)
|
||||
|
||||
- Window size flicker issue fix when changing files.
|
||||
- Support input-builtin-bindings to make mp.add_key_binding behave same as in mpv.
|
||||
- window-scale property support.
|
||||
- libmpv shinchiro 2021-10-31
|
||||
|
||||
|
||||
5.5.0.3 Beta (2021-09-23)
|
||||
|
||||
- New mpv.net option auto-play which sets pause=no on file load and
|
||||
selecting from the playlist. Disabled by default.
|
||||
- New option start-size=session to freeze the window size per session.
|
||||
- Changed keepaspect-window behavior.
|
||||
|
||||
|
||||
5.5.0.2 Beta (2021-09-15)
|
||||
|
||||
- Fix of keepaspect-window=no.
|
||||
|
||||
|
||||
5.4.9.8 Beta (2021-09-05)
|
||||
|
||||
- All PowerShell dependencies except the scipt host were
|
||||
removed in order to improve Windows 7 compatibility.
|
||||
- Fix message box not working when ontop is enabled.
|
||||
- Use Vista folder browser.
|
||||
- Improved context menu performance.
|
||||
- libmpv shinchiro 2021-09-05
|
||||
|
||||
|
||||
5.4.9.7 Beta (2021-08-28)
|
||||
|
||||
- Fix exception closing command palette on Windows 7.
|
||||
|
||||
|
||||
5.4.9.6 Beta (2021-08-26)
|
||||
|
||||
- Message box fix.
|
||||
|
||||
|
||||
5.4.9.5 Beta (2021-08-25)
|
||||
|
||||
- Message boxes are themed.
|
||||
|
||||
|
||||
5.4.9.4 Beta (2021-08-24)
|
||||
|
||||
- Fix of command palette crash on Windows 7.
|
||||
|
||||
|
||||
5.4.9.3 Beta (2021-08-22)
|
||||
|
||||
- Leaving fullscreen using keepaspect-window=no restores the correct size.
|
||||
- Major UI rework!
|
||||
- libmpv shinchiro 2021-08-15
|
||||
|
||||
|
||||
5.4.9.2 Beta (2021-08-08)
|
||||
|
||||
- Manual translated to simplified Chinese. (hooke007)
|
||||
- watch-later-options support added to conf editor. (hooke007)
|
||||
- Showing the playlist selects the currently played file/stream in the playlist.
|
||||
- Properties are shown in the command palette instead of the text editor
|
||||
making it very easy to find a property and show/print its value.
|
||||
- Support for --keep-open=no.
|
||||
- Profile selection in the context menu.
|
||||
- Use defaults in case settings.xml fails loading (not reproducible).
|
||||
- conf editor support for keepaspect-window.
|
||||
- Drawing flicker in the command palette (playlist) was fixed.
|
||||
- Saving window size and position was fixed.
|
||||
- Some scroll bars where replaced with Windows 10 styled scroll bars,
|
||||
complex code used from HandyControl project.
|
||||
- Some UI elements use rounded corners.
|
||||
- The recent list can also be shown in the command palette:
|
||||
Alt+r script-message mpv.net show-recent #menu: View > Show Recent
|
||||
- The recent context menu removes the folder info in case of very long paths.
|
||||
- libmpv shinchiro 2021-08-01
|
||||
|
||||
|
||||
5.4.9.1 Beta (2021-06-23)
|
||||
=========================
|
||||
|
||||
- Fix exception using named pipes.
|
||||
- The mpv window property keepaspect-window was implemented.
|
||||
- Everything search removed to keep the core player lightweight,
|
||||
it might come back as user script or extension.
|
||||
- The command palette is integrated into the main window.
|
||||
- Playlist is shown with the command palette and not using the OSD.
|
||||
- New media info command: `Ctrl+m script-message mpv.net show-media-info #menu: View > Show Media Info`
|
||||
- Context menu font render quality fix.
|
||||
- Context menu and `cycle-audio` command supports external audio and subtitle tracks.
|
||||
- Fix window size not being saved.
|
||||
- libmpv shinchiro 2021-06-20
|
||||
|
||||
|
||||
5.4.9.0 (2021-05-29)
|
||||
====================
|
||||
|
||||
- `window-scale 1` does not work correctly in mpv,
|
||||
so I've removed support for it and added my own implementation:
|
||||
`script-message mpv.net window-scale`.
|
||||
- The CS-Script library was replaced with my own C# scripting implementation.
|
||||
- If a player window border is near to a screen border and the window size
|
||||
changes, the player windows sticks to that near screen border location.
|
||||
Furthermore the `remember-window-position` option remembers a near screen
|
||||
border position instead of remembering the window center position.
|
||||
- Multi monitor fix using different DPI values.
|
||||
- `start-size` option has new options, see config editor and manual.
|
||||
- Improved `script-message mpv.net cycle-audio` OSD info.
|
||||
- The logic for finding the config directory has changed, see manual.
|
||||
- The dotnet script and extension host was a little redesigned, this breaks
|
||||
backward compatibility unfortunately, but I can help fixing existing
|
||||
open source code however. Example scripts and extensions were updated.
|
||||
- Fix console not working due to incorrect mpv.conf value generated
|
||||
(script-opts=console-scale=0).
|
||||
- Settings are stored in the file settings.xml now instead of the Registry.
|
||||
- Video rotation support added.
|
||||
- After using the config editor it's no longer necessary to restart mpv.net.
|
||||
- Improved input editor theming.
|
||||
|
||||
|
||||
5.4.8.8 Beta (2021-05-09)
|
||||
=========================
|
||||
|
||||
- Improved window scaling.
|
||||
- Title property implementation.
|
||||
- Command palette shows commands without assigned menu item.
|
||||
- The code from the included JavaScript file was ported into the core
|
||||
player because JavaScript is currently broken in the builds of shinshiro.
|
||||
- New option `--command=<input command>`, can be used in combination
|
||||
with `process-instance=single` to control mpv.net via command line,
|
||||
for instance to create global hotkeys with AutoHotkey.
|
||||
- New global hotkey feature added using the file global-input.conf.
|
||||
- The global-media-keys option was removed because global-input.conf
|
||||
can be used instead.
|
||||
- MediaInfo 21.3
|
||||
- libmpv shinchiro 2021-04-04
|
||||
|
||||
|
||||
5.4.8.7 Beta (2021-03-09)
|
||||
=========================
|
||||
|
||||
- History feature can be configured to ingore defined strings:
|
||||
script-opt = history-discard=value1;value2
|
||||
- Web stream audio and subtitle track selection.
|
||||
- On Windows 10 1903 and later the default code page was changed to UTF-8.
|
||||
- Support of --version command.
|
||||
- File associations and auto-load-folder can be customized with
|
||||
video-file-extensions, audio-file-extensions and image-file-extensions.
|
||||
- Fix menu not showing key '&'.
|
||||
|
||||
|
||||
5.4.8.6 Beta (2020-12-24)
|
||||
=========================
|
||||
|
||||
- Santa hat shown in december. (#216)
|
||||
- Filename not being always shown in title bar. (#214)
|
||||
- Improved OSD message when cycling audio.
|
||||
- DVD audio and subtitle track selection.
|
||||
- Input keylist can be shown on the command-line with --input-keylist
|
||||
- Profiles can be shown on the command-line with --profile=help
|
||||
- Decoders can be shown on the command-line with --ad=help and --vd=help
|
||||
- Decoders can be shown in the menu under: View > Show Decoders
|
||||
- Demuxers can be shown in the menu under: View > Show Demuxers
|
||||
- Audio devices can be shown in the menu under: View > Show Audio Devices
|
||||
- Audio devices can be shown on the command-line with --audio-device=help
|
||||
- Protocols can be shown in the menu under: View > Show Protocols
|
||||
- Allow mpv.net to start from different startup locations
|
||||
without showing the setup dialog. (#218)
|
||||
- libmpv updated to shinshiro 2020-12-20
|
||||
|
||||
|
||||
5.4.8.5 Beta
|
||||
============
|
||||
|
||||
- Load AviSynth DLL from environment variable AviSynthDLL
|
||||
in order to support AviSynth portable mode.
|
||||
- New option global-media-keys (next, previous, play/pause, stop).
|
||||
- Redesigned PowerShell based setup and setup dialog, it was done
|
||||
because of a bug and upcoming chocolately and winget integration.
|
||||
- Redesigned auto update using different file name, using zip instead
|
||||
of 7zip format now, 7zip distribution will shortly get dropped.
|
||||
- Whenever there is a new startup location, the setup dialog is shown.
|
||||
- libmpv updated to shinshiro 2020-12-06
|
||||
- youtube-dl is no longer included, users have to install it
|
||||
on their own (put it in the startup or a PATH folder).
|
||||
|
||||
|
||||
5.4.8.4 Beta
|
||||
============
|
||||
|
||||
- Blu-rays with dozens of titles showed all titles in the menu
|
||||
which was difficult to choose and extremely slow.
|
||||
- Blu-ray folder paths are auto detected when received
|
||||
from drag & drop and command-line.
|
||||
- Cycle audio was not working for Blu-ray.
|
||||
- Message asking if image is BD or DVD in case image is < 10 GB.
|
||||
|
||||
|
||||
5.4.8.3 Beta
|
||||
============
|
||||
|
||||
- Support Wheel_Left and Wheel_Right. (arnesacnussem)
|
||||
- Default screen was changed from primary to OS default to start
|
||||
from the same screen where the File Explorer window is located.
|
||||
- When mpv.net was started maximized and next was invoked then the
|
||||
window state was changed to normal instead of staying maximized.
|
||||
|
||||
|
||||
5.4.8.2 Beta
|
||||
============
|
||||
|
||||
- CLI --shuffle issue fix.
|
||||
- ISO image files can be opened like any other files, files smaller
|
||||
than 10 GB are handled as DVD and larger as BluRay.
|
||||
- Menu support for BluRay title, audio and subtitle selection.
|
||||
- Property input-key-list can be shown with: View > Show Keys
|
||||
- youtube-dl 2020.06.16.1
|
||||
- libmpv 2020-06-21 shinchiro
|
||||
|
||||
|
||||
5.4.8.1 Beta
|
||||
============
|
||||
|
||||
- fix stdin support
|
||||
|
||||
|
||||
5.4.8.0
|
||||
=======
|
||||
@@ -275,7 +657,7 @@ stable release, no changes since the last beta
|
||||
- libmpv was updated to shinchiro 2019-08-04
|
||||
- in case mpv.net was started from a terminal it sets now the mpv property input-terminal to yes,
|
||||
this means mpv.net will now receive and handle input keys from the terminal
|
||||
- certain command line properties didn't work (input-terminal, terminal, input-file,
|
||||
- certain command-line properties didn't work (input-terminal, terminal, input-file,
|
||||
config, config-dir, input-conf, load-scripts, script, scripts, player-operation-mode)
|
||||
- the about dialog shows now the mpv version and build date
|
||||
- the dialog that asks for a config folder has now a cancel option
|
||||
@@ -286,7 +668,7 @@ stable release, no changes since the last beta
|
||||
- the logo/icon had a very small cosmetic change
|
||||
- the help in the context menu was improved,
|
||||
for quick access consider the command palette (F1 key)
|
||||
- config options specific to mpv.net are now available from the command line
|
||||
- config options specific to mpv.net are now available from the command-line
|
||||
- the input editor no longer has known limitations, 'alt gr' and ctrl+alt are working now
|
||||
- the help in the input editor was simplified and the filter logic was improved
|
||||
- fixed issue in file associations causing mpv.net not to appear in OS default apps
|
||||
@@ -302,10 +684,10 @@ stable release, no changes since the last beta
|
||||
- the search field in the config editor was not always remembered
|
||||
- new setting remember-volume added, saves volume and mute on exit
|
||||
and restores it on start.
|
||||
- it's now enforced that mpv properties on the command line and in
|
||||
- it's now enforced that mpv properties on the command-line and in
|
||||
the mpv.conf config file are lowercase, if not a error is shown
|
||||
- gpu-api vulkan was not working if media files were opened via
|
||||
command line (that included Explorer)
|
||||
command-line (that included Explorer)
|
||||
- new setting minimum-aspect-ratio added, minimum aspect ratio for the window,
|
||||
this was previously hard coded to 1.3
|
||||
- new setting auto-load-folder added, for single files automatically load
|
||||
@@ -420,7 +802,7 @@ stable release, no changes since the last beta
|
||||
thanks to 44vince44 for pointing this out!!!
|
||||
- new Python and C# script examples were added to the wiki and the scripting and
|
||||
extension documentation was improved
|
||||
- invalid command line arguments were ignored, now an error message is shown
|
||||
- invalid command-line arguments were ignored, now an error message is shown
|
||||
- a description on how to start mpv.net from Google Chrome was added to the
|
||||
manual, it's useful to play videos from sites like YouTube, find the
|
||||
description [here](https://github.com/stax76/mpv.net/blob/master/Manual.md#chrome-extension)
|
||||
@@ -466,7 +848,7 @@ stable release, no changes since the last beta
|
||||
|
||||
- drag & drop support for subtitles was added
|
||||
- libmpv was updated
|
||||
- command line support for stdin and URLs was added
|
||||
- command-line support for stdin and URLs was added
|
||||
- there was a crash happening when the player is
|
||||
minimized in the taskbar
|
||||
|
||||
@@ -479,7 +861,7 @@ stable release, no changes since the last beta
|
||||
- the info command (i key) shows the audio format
|
||||
- new options osd-font-size, sub-font, sub-font-size
|
||||
- new color options with dedicated GUI support: sub-color, sub-border-color, sub-back-color
|
||||
- the config editor no longer shows the command line switches
|
||||
- the config editor no longer shows the command-line switches
|
||||
- the github start page was greatly improved
|
||||
- the setup.ps1 PowerShell script was greatly improved in regard of error handling and readability
|
||||
- a [manual to mpv.net](Manual.md) was created
|
||||
1580
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
|
||||
BIN
docs/img/CommandPalette.webp
Normal file
|
After Width: | Height: | Size: 672 KiB |
BIN
docs/img/ConfEditor.png
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
docs/img/InputEditor.webp
Normal file
|
After Width: | Height: | Size: 251 KiB |
BIN
docs/img/Main.webp
Normal file
|
After Width: | Height: | Size: 442 KiB |
BIN
docs/img/Menu.jpg
Normal file
|
After Width: | Height: | Size: 536 KiB |
BIN
docs/img/Playlist.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
docs/img/Terminal.png
Normal file
|
After Width: | Height: | Size: 355 KiB |
BIN
docs/img/mpvnet-santa.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
@@ -1,66 +0,0 @@
|
||||
// This extension writes a rating to the filename of rated videos when mpv.net shuts down.
|
||||
|
||||
// The input.conf defaults contain key bindings for this extension to set ratings.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using mpvnet;
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace RatingExtension // the assembly name must end with 'Extension'
|
||||
{
|
||||
[Export(typeof(IExtension))]
|
||||
public class RatingExtension : IExtension
|
||||
{
|
||||
// dictionory to store the filename and the rating
|
||||
Dictionary<string, int> Dic = new Dictionary<string, int>();
|
||||
|
||||
public RatingExtension() // plugin initialization
|
||||
{
|
||||
core.ClientMessage += ClientMessage; //handles keys defined in input.conf
|
||||
core.Shutdown += Shutdown; // handles MPV_EVENT_SHUTDOWN
|
||||
}
|
||||
|
||||
// handles MPV_EVENT_SHUTDOWN
|
||||
void Shutdown()
|
||||
{
|
||||
foreach (var i in Dic)
|
||||
{
|
||||
string filepath = i.Key;
|
||||
int rating = i.Value;
|
||||
if (String.IsNullOrEmpty(filepath) || !File.Exists(filepath))
|
||||
return;
|
||||
string basename = Path.GetFileNameWithoutExtension(filepath);
|
||||
|
||||
for (int x = 0; x < 6; x++)
|
||||
if (basename.Contains(" (" + x + "stars)"))
|
||||
basename = basename.Replace(" (" + x + "stars)", "");
|
||||
|
||||
basename += $" ({rating}stars)";
|
||||
string newPath = Path.Combine(Path.GetDirectoryName(filepath), basename + Path.GetExtension(filepath));
|
||||
if (filepath.ToLower() != newPath.ToLower())
|
||||
File.Move(filepath, newPath);
|
||||
File.SetLastWriteTime(newPath, DateTime.Now);
|
||||
}
|
||||
}
|
||||
|
||||
//handles keys defined in input.conf
|
||||
void ClientMessage(string[] args)
|
||||
{
|
||||
if (args[0] != "rate-file") return;
|
||||
|
||||
if (int.TryParse(args[1], out int rating))
|
||||
{
|
||||
string path = core.get_property_string("path");
|
||||
if (!File.Exists(path)) return;
|
||||
Dic[path] = rating;
|
||||
core.commandv("show-text", $"Rating: {rating}");
|
||||
}
|
||||
else if (args[1] == "about")
|
||||
Msg.Show("Rating Extension", "This extension writes a rating to the filename of rated videos when mpv.net shuts down.\n\nThe input.conf defaults contain key bindings for this extension to set ratings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("RatingExtension")]
|
||||
[assembly: AssemblyDescription("RatingExtension")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Frank Skare (stax76)")]
|
||||
[assembly: AssemblyProduct("RatingExtension")]
|
||||
[assembly: AssemblyCopyright("Copyright (C) 2017-2020 Frank Skare (stax76)")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("55c88710-539d-4402-84c8-31694841c731")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
// This extension implements the C# scripting feature of mpv.net which
|
||||
// is based on CS-Script (https://www.cs-script.net).
|
||||
|
||||
// I also use this extension to code scripts in order to have full
|
||||
// code completion and debugger support, once the script code is
|
||||
// finished I move it from the extension to a standalone script.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using mpvnet;
|
||||
using CSScriptLibrary;
|
||||
using static mpvnet.Core;
|
||||
|
||||
// the file name of extensions must end with 'Extension'
|
||||
namespace ScriptingExtension
|
||||
{
|
||||
[Export(typeof(IExtension))]
|
||||
public class ScriptingExtension : IExtension
|
||||
{
|
||||
//Script Script;
|
||||
|
||||
public ScriptingExtension()
|
||||
{
|
||||
//Script = new Script();
|
||||
List<string> files = new List<string>();
|
||||
|
||||
if (Directory.Exists(core.ConfigFolder + "scripts-cs"))
|
||||
files.AddRange(Directory.GetFiles(core.ConfigFolder + "scripts-cs", "*.cs"));
|
||||
|
||||
if (Directory.Exists(Folder.Startup + "scripts"))
|
||||
foreach (string path in Directory.GetFiles(Folder.Startup + "scripts", "*.cs"))
|
||||
files.AddRange(Directory.GetFiles(Folder.Startup + "scripts", "*.cs"));
|
||||
|
||||
if (files.Count == 0)
|
||||
return;
|
||||
|
||||
CSScriptLibrary.CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom;
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
try
|
||||
{
|
||||
CSScriptLibrary.CSScript.Evaluator.LoadCode(File.ReadAllText(file));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.ShowException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{94255EF2-C823-4D82-9017-0E993CC0F5A1}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ScriptingExtension</RootNamespace>
|
||||
<AssemblyName>ScriptingExtension</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\mpv.net\bin\x86\Extensions\ScriptingExtension\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>..\..\mpv.net\bin\x86\Extensions\ScriptingExtension\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\mpv.net\bin\x64\Extensions\ScriptingExtension\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\..\mpv.net\bin\x64\Extensions\ScriptingExtension\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CSScriptLibrary">
|
||||
<HintPath>.\CSScriptLibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ScriptingExtension.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="script.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\mpv.net\mpv.net.csproj">
|
||||
<Project>{1751f378-8edf-4b62-be6d-304c7c287089}</Project>
|
||||
<Name>mpv.net</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29123.88
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptingExtension", "ScriptingExtension.csproj", "{55C88710-539D-4402-84C8-31694841C731}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.Build.0 = Debug|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.Build.0 = Debug|x86
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.ActiveCfg = Release|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.Build.0 = Release|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.ActiveCfg = Release|x86
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C8A53BF6-B00A-4215-B9D7-801ADB9C8F60}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
using System.IO;
|
||||
|
||||
using mpvnet;
|
||||
using static mpvnet.Core;
|
||||
|
||||
class Script
|
||||
{
|
||||
public Script()
|
||||
{
|
||||
core.Shutdown += Shutdown;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
foreach (string file in Directory.GetFiles(@"C:\Users\frank\Desktop\aaa"))
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
BIN
img/Avatar.png
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 214 KiB |
BIN
img/Main.png
|
Before Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 628 KiB |
BIN
img/Menu.png
|
Before Width: | Height: | Size: 1.3 MiB |
BIN
img/Terminal.png
|
Before Width: | Height: | Size: 2.2 MiB |
51
mpv.net.sln
@@ -1,51 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28729.10
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpv.net", "mpv.net\mpv.net.csproj", "{1751F378-8EDF-4B62-BE6D-304C7C287089}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RatingExtension", "extensions\RatingExtension\RatingExtension.csproj", "{55C88710-539D-4402-84C8-31694841C731}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptingExtension", "extensions\ScriptingExtension\ScriptingExtension.csproj", "{94255EF2-C823-4D82-9017-0E993CC0F5A1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x64.Build.0 = Debug|x64
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Debug|x86.Build.0 = Debug|x86
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x64.ActiveCfg = Release|x64
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x64.Build.0 = Release|x64
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x86.ActiveCfg = Release|x86
|
||||
{1751F378-8EDF-4B62-BE6D-304C7C287089}.Release|x86.Build.0 = Release|x86
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x64.Build.0 = Debug|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Debug|x86.Build.0 = Debug|x86
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.ActiveCfg = Release|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x64.Build.0 = Release|x64
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.ActiveCfg = Release|x86
|
||||
{55C88710-539D-4402-84C8-31694841C731}.Release|x86.Build.0 = Release|x86
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x64.Build.0 = Debug|x64
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Debug|x86.Build.0 = Debug|x86
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x64.ActiveCfg = Release|x64
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x64.Build.0 = Release|x64
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x86.ActiveCfg = Release|x86
|
||||
{94255EF2-C823-4D82-9017-0E993CC0F5A1}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8DE9E796-619E-44B8-9576-F4DE028701BF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,64 +0,0 @@
|
||||
<UserControl x:Name="OptionSettingControl1" x:Class="DynamicGUI.OptionSettingControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:DynamicGUI"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800">
|
||||
|
||||
<Grid Margin="20,0">
|
||||
<StackPanel>
|
||||
<TextBox x:Name="TitleTextBox"
|
||||
FontSize="24"
|
||||
Margin="0,10"
|
||||
BorderThickness="0"
|
||||
IsReadOnly="True"
|
||||
Foreground="{x:Static mpvnet:Theme.Heading}"
|
||||
Background="{x:Static mpvnet:Theme.Background}" />
|
||||
|
||||
<ItemsControl x:Name="ItemsControl">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<WrapPanel Orientation="Vertical">
|
||||
<RadioButton x:Name="RadioButton"
|
||||
VerticalContentAlignment="Center"
|
||||
IsChecked="{Binding Checked}"
|
||||
GroupName="{Binding OptionSetting.Name}"
|
||||
Content="{Binding Text}"
|
||||
FontSize="16"
|
||||
FontWeight="Normal"
|
||||
VerticalAlignment="Top"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"/>
|
||||
|
||||
<TextBox x:Name="ItemHelpTextBox"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
Text="{Binding Help}"
|
||||
Visibility="{Binding Visibility}"
|
||||
Margin="10,0,0,0" BorderThickness="0"
|
||||
IsReadOnly="True" Padding="7,0,0,0"
|
||||
MinHeight="0"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground2}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"/>
|
||||
|
||||
</WrapPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<TextBox x:Name="HelpTextBox"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
BorderThickness="0"
|
||||
IsReadOnly="True"
|
||||
Margin="0,10,0,0"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"/>
|
||||
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
||||
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,58 +0,0 @@
|
||||
<UserControl x:Name="StringSettingControl1" x:Class="DynamicGUI.StringSettingControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:DynamicGUI"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800">
|
||||
|
||||
<Grid Margin="20,0">
|
||||
<StackPanel>
|
||||
<TextBox x:Name="TitleTextBox"
|
||||
FontSize="24"
|
||||
Margin="0,10"
|
||||
BorderThickness="0"
|
||||
IsReadOnly="True"
|
||||
Foreground="{x:Static mpvnet:Theme.Heading}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"/>
|
||||
|
||||
<Grid Margin="0,0,0,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="ValueTextBox"
|
||||
Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="150"
|
||||
Height="20"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
CaretBrush="{x:Static mpvnet:Theme.Foreground}"
|
||||
TextChanged="ValueTextBox_TextChanged"/>
|
||||
|
||||
<Button x:Name="Button"
|
||||
Height="20"
|
||||
Grid.Column="1"
|
||||
Visibility="{Binding Path=Text, ElementName=StringSettingControl1}"
|
||||
Margin="5,0,0,0"
|
||||
Width="20"
|
||||
Click="Button_Click">...</Button>
|
||||
</Grid>
|
||||
|
||||
<TextBox x:Name="HelpTextBox"
|
||||
TextWrapping="WrapWithOverflow"
|
||||
BorderThickness="0"
|
||||
IsReadOnly="True"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"/>
|
||||
|
||||
<TextBlock x:Name="LinkTextBlock" Margin="0,10">
|
||||
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,194 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public static class App
|
||||
{
|
||||
public static string[] VideoTypes { get; } = "264 265 asf avc avi avs flv h264 h265 hevc m2ts m2v m4v mkv mov mp4 mpeg mpg mpv mts ts vob vpy webm wmv y4m".Split(' ');
|
||||
public static string[] AudioTypes { get; } = "mp3 mp2 ac3 ogg opus flac wav w64 m4a dts dtsma dtshr dtshd eac3 thd thd+ac3 mka aac mpa".Split(' ');
|
||||
public static string[] ImageTypes { get; } = {"jpg", "bmp", "gif", "png"};
|
||||
public static string[] SubtitleTypes { get; } = { "srt", "ass", "idx", "sup", "ttxt", "ssa", "smi" };
|
||||
|
||||
public static string RegPath { get; } = @"HKCU\Software\" + Application.ProductName;
|
||||
public static string ConfPath { get => core.ConfigFolder + "mpvnet.conf"; }
|
||||
public static string ProcessInstance { get; set; } = "single";
|
||||
public static string DarkMode { get; set; } = "always";
|
||||
public static string DarkTheme { get; set; } = "dark";
|
||||
public static string LightTheme { get; set; } = "light";
|
||||
public static string StartSize { get; set; } = "previous";
|
||||
|
||||
public static bool RememberPosition { get; set; }
|
||||
public static bool DebugMode { get; set; }
|
||||
public static bool IsStartedFromTerminal { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
|
||||
public static bool RememberVolume { get; set; } = true;
|
||||
public static bool AutoLoadFolder { get; set; } = true;
|
||||
public static bool Queue { get; set; }
|
||||
public static bool UpdateCheck { get; set; }
|
||||
|
||||
public static int StartThreshold { get; set; } = 1500;
|
||||
public static int RecentCount { get; set; } = 15;
|
||||
|
||||
public static float MinimumAspectRatio { get; set; } = 1.2f;
|
||||
|
||||
public static Extension Extension { get; set; }
|
||||
|
||||
public static bool IsDarkMode {
|
||||
get => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
string dummy = core.ConfigFolder;
|
||||
var dummy2 = core.Conf;
|
||||
|
||||
foreach (var i in Conf)
|
||||
ProcessProperty(i.Key, i.Value, true);
|
||||
|
||||
if (App.DebugMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = core.ConfigFolder + "mpvnet-debug.log";
|
||||
|
||||
if (File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
|
||||
Trace.AutoFlush = true;
|
||||
|
||||
//if (App.DebugMode)
|
||||
// Trace.WriteLine("");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Msg.ShowException(e);
|
||||
}
|
||||
}
|
||||
|
||||
string themeContent = null;
|
||||
|
||||
if (File.Exists(core.ConfigFolder + "theme.conf"))
|
||||
themeContent = File.ReadAllText(core.ConfigFolder + "theme.conf");
|
||||
|
||||
Theme.Init(
|
||||
themeContent,
|
||||
Properties.Resources.theme,
|
||||
IsDarkMode ? DarkTheme : LightTheme);
|
||||
|
||||
core.Shutdown += Shutdown;
|
||||
core.Initialized += Initialized;
|
||||
}
|
||||
|
||||
public static void RunAction(Action action)
|
||||
{
|
||||
Task.Run(() => {
|
||||
try
|
||||
{
|
||||
action.Invoke();
|
||||
Debug.WriteLine(Environment.TickCount);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ShowException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void ShowException(object obj)
|
||||
{
|
||||
if (obj is Exception e)
|
||||
{
|
||||
if (App.IsStartedFromTerminal)
|
||||
ConsoleHelp.WriteError(e.ToString());
|
||||
else
|
||||
Msg.ShowException(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (App.IsStartedFromTerminal)
|
||||
ConsoleHelp.WriteError(obj.ToString());
|
||||
else
|
||||
Msg.ShowError(obj.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowError(string title, string msg)
|
||||
{
|
||||
if (App.IsStartedFromTerminal)
|
||||
{
|
||||
ConsoleHelp.WriteError(title);
|
||||
ConsoleHelp.WriteError(msg);
|
||||
}
|
||||
else
|
||||
Msg.ShowError(title, msg);
|
||||
}
|
||||
|
||||
static void Initialized()
|
||||
{
|
||||
if (RememberVolume)
|
||||
{
|
||||
core.set_property_int("volume", RegistryHelp.GetInt(App.RegPath, "Volume", 70));
|
||||
core.set_property_string("mute", RegistryHelp.GetString(App.RegPath, "Mute", "no"));
|
||||
}
|
||||
}
|
||||
|
||||
static void Shutdown()
|
||||
{
|
||||
if (RememberVolume)
|
||||
{
|
||||
RegistryHelp.SetValue(App.RegPath, "Volume", core.get_property_int("volume"));
|
||||
RegistryHelp.SetValue(App.RegPath, "Mute", core.get_property_string("mute"));
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<string, string> _Conf;
|
||||
|
||||
public static Dictionary<string, string> Conf {
|
||||
get {
|
||||
if (_Conf == null)
|
||||
{
|
||||
_Conf = new Dictionary<string, string>();
|
||||
|
||||
if (File.Exists(ConfPath))
|
||||
foreach (string i in File.ReadAllLines(ConfPath))
|
||||
if (i.Contains("=") && !i.StartsWith("#"))
|
||||
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
||||
}
|
||||
return _Conf;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ProcessProperty(string name, string value, bool writeError = false)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "remember-position": RememberPosition = value == "yes"; return true;
|
||||
case "debug-mode": DebugMode = value == "yes"; return true;
|
||||
case "remember-volume": RememberVolume = value == "yes"; return true;
|
||||
case "queue": Queue = value == "yes"; return true;
|
||||
case "auto-load-folder": AutoLoadFolder = value == "yes"; return true;
|
||||
case "update-check": UpdateCheck = value == "yes"; return true;
|
||||
case "start-size": StartSize = value; return true;
|
||||
case "process-instance": ProcessInstance = value; return true;
|
||||
case "dark-mode": DarkMode = value; return true;
|
||||
case "start-threshold": StartThreshold = value.Int(); return true;
|
||||
case "recent-count": RecentCount = value.Int(); return true;
|
||||
case "minimum-aspect-ratio": MinimumAspectRatio = value.Float(); return true;
|
||||
case "dark-theme": DarkTheme = value.Trim('\'', '"'); return true;
|
||||
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
|
||||
default:
|
||||
if (writeError)
|
||||
ConsoleHelp.WriteError($"unknown mpvnet.conf property: {name}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Interop;
|
||||
|
||||
using VB = Microsoft.VisualBasic;
|
||||
|
||||
using static NewLine;
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public class Commands
|
||||
{
|
||||
public static void Execute(string id, string[] args)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case "open-files": OpenFiles(args); break;
|
||||
case "update-check": UpdateCheck.CheckOnline(true); break;
|
||||
case "open-url": OpenURL(); break;
|
||||
case "open-optical-media": Open_DVD_Or_BD_Folder(); break;
|
||||
case "manage-file-associations": // deprecated 2019
|
||||
case "show-setup-dialog": ShowDialog(typeof(SetupWindow)); break;
|
||||
case "cycle-audio": CycleAudio(); break;
|
||||
case "load-audio": LoadAudio(); break;
|
||||
case "load-sub": LoadSubtitle(); break;
|
||||
case "execute-mpv-command": ExecuteMpvCommand(); break;
|
||||
case "show-history": ShowHistory(); break;
|
||||
case "show-media-search": ShowDialog(typeof(EverythingWindow)); break;
|
||||
case "show-command-palette": ShowDialog(typeof(CommandPaletteWindow)); break;
|
||||
case "show-about": ShowDialog(typeof(AboutWindow)); break;
|
||||
case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break;
|
||||
case "show-input-editor": ShowDialog(typeof(InputWindow)); break;
|
||||
case "open-conf-folder": Process.Start(core.ConfigFolder); break;
|
||||
case "shell-execute": Process.Start(args[0]); break;
|
||||
case "show-info": ShowInfo(); break;
|
||||
case "playlist-first": PlaylistFirst(); break;
|
||||
case "playlist-last": PlaylistLast(); break;
|
||||
case "show-profiles": ShowProfiles(); break;
|
||||
case "show-properties": ShowProperties(); break;
|
||||
case "show-commands": ShowCommands(); break;
|
||||
case "add-files-to-playlist": OpenFiles("append"); break; // deprecated 2019
|
||||
default: Msg.ShowError($"No command '{id}' found."); break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void InvokeOnMainThread(Action action) => MainForm.Instance.BeginInvoke(action);
|
||||
|
||||
public static void ShowDialog(Type winType)
|
||||
{
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
Window win = Activator.CreateInstance(winType) as Window;
|
||||
new WindowInteropHelper(win).Owner = MainForm.Instance.Handle;
|
||||
win.ShowDialog();
|
||||
}));
|
||||
}
|
||||
|
||||
public static void OpenFiles(params string[] args)
|
||||
{
|
||||
bool append = Control.ModifierKeys.HasFlag(Keys.Control);
|
||||
bool loadFolder = true;
|
||||
|
||||
foreach (string arg in args)
|
||||
{
|
||||
if (arg == "append") append = true;
|
||||
if (arg == "no-folder") loadFolder = false;
|
||||
}
|
||||
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
using (var d = new OpenFileDialog() { Multiselect = true })
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
core.LoadFiles(d.FileNames, loadFolder, append);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Open_DVD_Or_BD_Folder()
|
||||
{
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
using (var d = new FolderBrowserDialog())
|
||||
{
|
||||
d.Description = "Select a DVD or Blu-ray folder.";
|
||||
d.ShowNewFolderButton = false;
|
||||
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (Directory.Exists(d.SelectedPath + "\\BDMV"))
|
||||
{
|
||||
core.set_property_string("bluray-device", d.SelectedPath);
|
||||
core.LoadFiles(new[] { @"bd://" }, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.set_property_string("dvd-device", d.SelectedPath);
|
||||
core.LoadFiles(new[] { @"dvd://" }, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static void PlaylistFirst()
|
||||
{
|
||||
int pos = core.get_property_int("playlist-pos");
|
||||
|
||||
if (pos != 0)
|
||||
core.set_property_int("playlist-pos", 0);
|
||||
}
|
||||
|
||||
public static void PlaylistLast()
|
||||
{
|
||||
int pos = core.get_property_int("playlist-pos");
|
||||
int count = core.get_property_int("playlist-count");
|
||||
|
||||
if (pos < count - 1)
|
||||
core.set_property_int("playlist-pos", count - 1);
|
||||
}
|
||||
|
||||
public static void ShowHistory()
|
||||
{
|
||||
if (File.Exists(core.ConfigFolder + "history.txt"))
|
||||
Process.Start(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.") == MsgResult.OK)
|
||||
|
||||
File.WriteAllText(core.ConfigFolder + "history.txt", "");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
string performer, title, album, genre, date, duration, text = "";
|
||||
long fileSize = 0;
|
||||
string path = core.get_property_string("path");
|
||||
|
||||
if (path.Contains("://"))
|
||||
path = core.get_property_string("media-title");
|
||||
|
||||
int width = core.get_property_int("video-params/w");
|
||||
int height = core.get_property_int("video-params/h");
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
fileSize = new FileInfo(path).Length;
|
||||
|
||||
if (App.AudioTypes.Contains(path.ShortExt()))
|
||||
{
|
||||
using (MediaInfo mediaInfo = new MediaInfo(path))
|
||||
{
|
||||
performer = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Performer");
|
||||
title = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Title");
|
||||
album = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Album");
|
||||
genre = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Genre");
|
||||
date = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Recorded_Date");
|
||||
duration = mediaInfo.GetInfo(MediaInfoStreamKind.Audio, "Duration/String");
|
||||
|
||||
if (performer != "") text += "Artist: " + performer + "\n";
|
||||
if (title != "") text += "Title: " + title + "\n";
|
||||
if (album != "") text += "Album: " + album + "\n";
|
||||
if (genre != "") text += "Genre: " + genre + "\n";
|
||||
if (date != "") text += "Year: " + date + "\n";
|
||||
if (duration != "") text += "Length: " + duration + "\n";
|
||||
text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n";
|
||||
text += "Type: " + path.ShortExt().ToUpper();
|
||||
|
||||
core.commandv("show-text", text, "5000");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (App.ImageTypes.Contains(path.ShortExt()))
|
||||
{
|
||||
using (MediaInfo mediaInfo = new MediaInfo(path))
|
||||
{
|
||||
text =
|
||||
"Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" +
|
||||
"Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" +
|
||||
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
|
||||
"Type: " + path.ShortExt().ToUpper();
|
||||
|
||||
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();
|
||||
|
||||
text = path.FileName() + "\n" +
|
||||
FormatTime(position.TotalMinutes) + ":" +
|
||||
FormatTime(position.Seconds) + " / " +
|
||||
FormatTime(duration2.TotalMinutes) + ":" +
|
||||
FormatTime(duration2.Seconds) + "\n" +
|
||||
$"{width} x {height}\n";
|
||||
|
||||
if (fileSize > 0)
|
||||
text += Convert.ToInt32(fileSize / 1024.0 / 1024.0) + " MB\n";
|
||||
|
||||
text += $"{videoFormat}\n{audioCodec}";
|
||||
|
||||
core.commandv("show-text", text, "5000");
|
||||
string FormatTime(double value) => ((int)value).ToString("00");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.ShowException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExecuteMpvCommand() // deprecated 2019
|
||||
{
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
string command = VB.Interaction.InputBox("Enter a mpv command to be executed.", "Execute Command", RegistryHelp.GetString(App.RegPath, "RecentExecutedCommand"));
|
||||
|
||||
if (string.IsNullOrEmpty(command))
|
||||
return;
|
||||
|
||||
RegistryHelp.SetValue(App.RegPath, "RecentExecutedCommand", command);
|
||||
core.command(command, false);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void OpenURL()
|
||||
{
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
string clipboard = System.Windows.Forms.Clipboard.GetText();
|
||||
|
||||
if (string.IsNullOrEmpty(clipboard) || (!clipboard.Contains("://") && !File.Exists(clipboard)) || clipboard.Contains("\n"))
|
||||
{
|
||||
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(() => {
|
||||
using (var d = new OpenFileDialog())
|
||||
{
|
||||
string path = core.get_property_string("path");
|
||||
|
||||
if (File.Exists(path))
|
||||
d.InitialDirectory = Path.GetDirectoryName(path);
|
||||
|
||||
d.Multiselect = true;
|
||||
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
foreach (string filename in d.FileNames)
|
||||
core.commandv("sub-add", filename);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static void LoadAudio()
|
||||
{
|
||||
InvokeOnMainThread(new Action(() => {
|
||||
using (var d = new OpenFileDialog())
|
||||
{
|
||||
string path = core.get_property_string("path");
|
||||
if (File.Exists(path))
|
||||
d.InitialDirectory = Path.GetDirectoryName(path);
|
||||
d.Multiselect = true;
|
||||
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
foreach (string i in d.FileNames)
|
||||
core.commandv("audio-add", i);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static void CycleAudio()
|
||||
{
|
||||
string path = core.get_property_string("path");
|
||||
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
using (MediaInfo mi = new MediaInfo(path))
|
||||
{
|
||||
MediaTrack[] audTracks = core.MediaTracks.Where(track => track.Type == "a").ToArray();
|
||||
|
||||
if (audTracks.Length < 2)
|
||||
return;
|
||||
|
||||
int aid = core.get_property_int("aid");
|
||||
aid += 1;
|
||||
|
||||
if (aid > audTracks.Length)
|
||||
aid = 1;
|
||||
|
||||
core.commandv("set", "aid", aid.ToString());
|
||||
core.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000");
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowProfiles()
|
||||
{
|
||||
string code = @"
|
||||
foreach ($item in ($json | ConvertFrom-Json | foreach { $_ } | sort name))
|
||||
{
|
||||
$item.name
|
||||
''
|
||||
|
||||
foreach ($option in $item.options)
|
||||
{
|
||||
' ' + $option.key + ' = ' + $option.value
|
||||
}
|
||||
|
||||
''
|
||||
}";
|
||||
|
||||
string json = core.get_property_string("profile-list");
|
||||
string file = Path.GetTempPath() + @"\mpv profile-list.txt";
|
||||
File.WriteAllText(file, BR + PowerShell.InvokeAndReturnString(code, "json", json));
|
||||
Process.Start(file);
|
||||
}
|
||||
|
||||
static void ShowCommands()
|
||||
{
|
||||
string code = @"
|
||||
foreach ($item in ($json | ConvertFrom-Json | foreach { $_ } | sort name))
|
||||
{
|
||||
''
|
||||
$item.name
|
||||
|
||||
foreach ($arg in $item.args)
|
||||
{
|
||||
$value = $arg.name + ' <' + $arg.type.ToLower() + '>'
|
||||
|
||||
if ($arg.optional -eq $true)
|
||||
{
|
||||
$value = '[' + $value + ']'
|
||||
}
|
||||
|
||||
' ' + $value
|
||||
}
|
||||
}";
|
||||
|
||||
string json = core.get_property_string("command-list");
|
||||
string file = Path.GetTempPath() + @"\mpv command-list.txt";
|
||||
File.WriteAllText(file, PowerShell.InvokeAndReturnString(code, "json", json) + BR);
|
||||
Process.Start(file);
|
||||
}
|
||||
|
||||
static void ShowProperties()
|
||||
{
|
||||
string file = Path.GetTempPath() + @"\mpv property-list.txt";
|
||||
var props = core.get_property_string("property-list").Split(',').OrderBy(prop => prop);
|
||||
File.WriteAllText(file, BR + string.Join(BR, props) + BR);
|
||||
Process.Start(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static string FileName(this string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) return "";
|
||||
int index = path.LastIndexOf('\\');
|
||||
if (index > -1) return path.Substring(index + 1);
|
||||
index = path.LastIndexOf('/');
|
||||
if (index > -1) return path.Substring(index + 1);
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string ShortExt(this string path)
|
||||
{
|
||||
return Path.GetExtension(path).ToLower().TrimStart('.');
|
||||
}
|
||||
|
||||
public static int Int(this string value)
|
||||
{
|
||||
int.TryParse(value, out int result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float Float(this string value)
|
||||
{
|
||||
float.TryParse(value.Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out float result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public static class ConsoleHelp
|
||||
{
|
||||
public static int Padding { get; set; }
|
||||
|
||||
public static void WriteError(object obj, string module = "mpv.net")
|
||||
{
|
||||
Write(obj, module, ConsoleColor.Red, false);
|
||||
}
|
||||
|
||||
public static void Write(object obj, string module = "mpv.net")
|
||||
{
|
||||
Write(obj, module, ConsoleColor.Black, true);
|
||||
}
|
||||
|
||||
public static void Write(object obj, string module, ConsoleColor color)
|
||||
{
|
||||
Write(obj, module, color, false);
|
||||
}
|
||||
|
||||
public static void Write(object obj, string module, ConsoleColor color, bool useDefaultColor)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
|
||||
string value = obj.ToString();
|
||||
|
||||
if (!string.IsNullOrEmpty(module))
|
||||
module = "[" + module + "] ";
|
||||
|
||||
if (useDefaultColor)
|
||||
Console.ResetColor();
|
||||
else
|
||||
Console.ForegroundColor = color;
|
||||
|
||||
value = module + value;
|
||||
|
||||
if (Padding > 0 && value.Length < Padding)
|
||||
value = value.PadRight(Padding);
|
||||
|
||||
Console.WriteLine(value);
|
||||
Console.ResetColor();
|
||||
Trace.WriteLine(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public class CursorHelp
|
||||
{
|
||||
static bool IsVisible = true;
|
||||
|
||||
public static void Show()
|
||||
{
|
||||
if (!IsVisible)
|
||||
{
|
||||
Cursor.Show();
|
||||
IsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Hide()
|
||||
{
|
||||
if (IsVisible)
|
||||
{
|
||||
Cursor.Hide();
|
||||
IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsPosDifferent(Point screenPos)
|
||||
{
|
||||
return
|
||||
Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
|
||||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
|
||||
}
|
||||
}
|
||||
|
||||
public class mpvHelp
|
||||
{
|
||||
public static string WM_APPCOMMAND_to_mpv_key(int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
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
|
||||
case 12: return "PREV"; // MEDIA_PREVIOUSTRACK
|
||||
case 13: return "STOP"; // MEDIA_STOP
|
||||
case 14: return "PLAYPAUSE"; // MEDIA_PLAY_PAUSE
|
||||
case 46: return "PLAY"; // MEDIA_PLAY
|
||||
case 47: return "PAUSE"; // MEDIA_PAUSE
|
||||
case 48: return "RECORD"; // MEDIA_RECORD
|
||||
case 49: return "FORWARD"; // MEDIA_FAST_FORWARD
|
||||
case 50: return "REWIND"; // MEDIA_REWIND
|
||||
case 51: return "CHANNEL_UP"; // MEDIA_CHANNEL_UP
|
||||
case 52: return "CHANNEL_DOWN"; // MEDIA_CHANNEL_DOWN
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public class Sys
|
||||
{
|
||||
public static bool IsDarkTheme {
|
||||
get {
|
||||
object value = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
|
||||
|
||||
if (value is null)
|
||||
value = 1;
|
||||
|
||||
return (int)value == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class StringLogicalComparer : IComparer, IComparer<string>
|
||||
{
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int StrCmpLogical(string x, string y);
|
||||
|
||||
int IComparer_Compare(object x, object y) => StrCmpLogical(x.ToString(), y.ToString());
|
||||
int IComparer.Compare(object x, object y) => IComparer_Compare(x, y);
|
||||
int IComparerOfString_Compare(string x, string y) => StrCmpLogical(x, y);
|
||||
int IComparer<string>.Compare(string x, string y) => IComparerOfString_Compare(x, y);
|
||||
}
|
||||
|
||||
public class FileAssociation
|
||||
{
|
||||
static string ExePath = Application.ExecutablePath;
|
||||
static string ExeFilename = Path.GetFileName(Application.ExecutablePath);
|
||||
static string ExeFilenameNoExt = Path.GetFileNameWithoutExtension(Application.ExecutablePath);
|
||||
static string[] Types;
|
||||
|
||||
public static void Register(string[] types)
|
||||
{
|
||||
Types = types;
|
||||
|
||||
RegistryHelp.SetValue(@"HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename, null, ExePath);
|
||||
RegistryHelp.SetValue(@"HKCR\Applications\" + ExeFilename, "FriendlyAppName", "mpv.net media player");
|
||||
RegistryHelp.SetValue($@"HKCR\Applications\{ExeFilename}\shell\open\command", null, $"\"{ExePath}\" \"%1\"");
|
||||
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationDescription", "mpv.net media player");
|
||||
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities", "ApplicationName", "mpv.net");
|
||||
RegistryHelp.SetValue(@"HKCR\SystemFileAssociations\video\OpenWithList\" + ExeFilename, null, "");
|
||||
RegistryHelp.SetValue(@"HKCR\SystemFileAssociations\audio\OpenWithList\" + ExeFilename, null, "");
|
||||
RegistryHelp.SetValue(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net", @"SOFTWARE\Clients\Media\mpv.net\Capabilities");
|
||||
|
||||
foreach (string ext in Types)
|
||||
{
|
||||
RegistryHelp.SetValue($@"HKCR\Applications\{ExeFilename}\SupportedTypes", "." + ext, "");
|
||||
RegistryHelp.SetValue($@"HKCR\" + "." + ext, null, ExeFilenameNoExt + "." + ext);
|
||||
RegistryHelp.SetValue($@"HKCR\" + "." + ext + @"\OpenWithProgIDs", ExeFilenameNoExt + "." + ext, "");
|
||||
|
||||
if (App.VideoTypes.Contains(ext))
|
||||
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "video");
|
||||
|
||||
if (App.AudioTypes.Contains(ext))
|
||||
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "audio");
|
||||
|
||||
if (App.ImageTypes.Contains(ext))
|
||||
RegistryHelp.SetValue(@"HKCR\" + "." + ext, "PerceivedType", "image");
|
||||
|
||||
RegistryHelp.SetValue($@"HKCR\" + ExeFilenameNoExt + "." + ext + @"\shell\open\command", null, $"\"{ExePath}\" \"%1\"");
|
||||
RegistryHelp.SetValue(@"HKLM\SOFTWARE\Clients\Media\mpv.net\Capabilities\FileAssociations", "." + ext, ExeFilenameNoExt + "." + ext);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister()
|
||||
{
|
||||
RegistryHelp.RemoveKey($@"HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths\" + ExeFilename);
|
||||
RegistryHelp.RemoveKey($@"HKCR\Applications\" + ExeFilename);
|
||||
RegistryHelp.RemoveKey($@"HKLM\SOFTWARE\Clients\Media\mpv.net");
|
||||
RegistryHelp.RemoveKey($@"HKCR\SystemFileAssociations\video\OpenWithList\" + ExeFilename);
|
||||
RegistryHelp.RemoveKey($@"HKCR\SystemFileAssociations\audio\OpenWithList\" + ExeFilename);
|
||||
RegistryHelp.RemoveValue(@"HKLM\SOFTWARE\RegisteredApplications", "mpv.net");
|
||||
|
||||
foreach (string id in Registry.ClassesRoot.GetSubKeyNames())
|
||||
{
|
||||
if (id.StartsWith(ExeFilenameNoExt + "."))
|
||||
Registry.ClassesRoot.DeleteSubKeyTree(id);
|
||||
|
||||
RegistryHelp.RemoveValue($@"HKCR\Software\Classes\{id}\OpenWithProgIDs", ExeFilenameNoExt + id);
|
||||
RegistryHelp.RemoveValue($@"HKLM\Software\Classes\{id}\OpenWithProgIDs", ExeFilenameNoExt + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MediaTrack
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public string Type { get; set; }
|
||||
public int ID { get; set; }
|
||||
}
|
||||
|
||||
public class CommandItem : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public string Path { get; set; } = "";
|
||||
public string Command { get; set; } = "";
|
||||
|
||||
public CommandItem() { }
|
||||
|
||||
public CommandItem(SerializationInfo info, StreamingContext context) { }
|
||||
|
||||
void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
string _Input = "";
|
||||
|
||||
public string Input {
|
||||
get => _Input;
|
||||
set {
|
||||
_Input = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public static ObservableCollection<CommandItem> GetItems(string content)
|
||||
{
|
||||
var items = new ObservableCollection<CommandItem>();
|
||||
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
foreach (string line in content.Split('\r', '\n'))
|
||||
{
|
||||
string val = line.Trim();
|
||||
|
||||
if (val.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
if (!val.Contains(" "))
|
||||
continue;
|
||||
|
||||
CommandItem item = new CommandItem();
|
||||
item.Input = val.Substring(0, val.IndexOf(" "));
|
||||
|
||||
if (item.Input == "_")
|
||||
item.Input = "";
|
||||
|
||||
val = val.Substring(val.IndexOf(" ") + 1);
|
||||
|
||||
if (val.Contains("#menu:"))
|
||||
{
|
||||
item.Path = val.Substring(val.IndexOf("#menu:") + 6).Trim();
|
||||
val = val.Substring(0, val.IndexOf("#menu:"));
|
||||
|
||||
if (item.Path.Contains(";"))
|
||||
item.Path = item.Path.Substring(item.Path.IndexOf(";") + 1).Trim();
|
||||
}
|
||||
|
||||
item.Command = val.Trim();
|
||||
|
||||
if (item.Command == "")
|
||||
continue;
|
||||
|
||||
if (item.Command.ToLower() == "ignore")
|
||||
item.Command = "";
|
||||
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
static ObservableCollection<CommandItem> _Items;
|
||||
|
||||
public static ObservableCollection<CommandItem> Items {
|
||||
get {
|
||||
if (_Items is null)
|
||||
_Items = GetItems(File.ReadAllText(core.InputConfPath));
|
||||
|
||||
return _Items;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Folder
|
||||
{
|
||||
public static string Startup { get; } = Application.StartupPath + @"\";
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
using System;
|
||||
|
||||
public static class NewLine
|
||||
{
|
||||
public static string BR = Environment.NewLine;
|
||||
public static string BR2 = Environment.NewLine + Environment.NewLine;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
|
||||
using System;
|
||||
using Microsoft.Win32;
|
||||
using System.Windows.Forms;
|
||||
|
||||
public class RegistryHelp
|
||||
{
|
||||
public static string ApplicationKey { get; } = @"HKCU\Software\" + Application.ProductName;
|
||||
|
||||
public static void SetValue(string path, string name, object value)
|
||||
{
|
||||
using (RegistryKey regKey = GetRootKey(path).CreateSubKey(path.Substring(5), RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
regKey.SetValue(name, value);
|
||||
}
|
||||
|
||||
public static string GetString(string path, string name, string defaultValue = "")
|
||||
{
|
||||
object value = GetValue(path, name, defaultValue);
|
||||
return !(value is string) ? defaultValue : value.ToString();
|
||||
}
|
||||
|
||||
public static int GetInt(string path, string name, int defaultValue = 0)
|
||||
{
|
||||
object value = GetValue(path, name, defaultValue);
|
||||
return !(value is int) ? defaultValue : (int)value;
|
||||
}
|
||||
|
||||
public static bool GetBool(string path, string name, bool defaultValue = false)
|
||||
{
|
||||
object val = GetValue(path, name, defaultValue);
|
||||
return val is bool ? (bool)val : defaultValue;
|
||||
}
|
||||
|
||||
public static object GetValue(string path, string name, object defaultValue = null)
|
||||
{
|
||||
using (RegistryKey regKey = GetRootKey(path).OpenSubKey(path.Substring(5)))
|
||||
return regKey == null ? null : regKey.GetValue(name, defaultValue);
|
||||
}
|
||||
|
||||
public static void RemoveKey(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
GetRootKey(path).DeleteSubKeyTree(path.Substring(5), false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static void RemoveValue(string path, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (RegistryKey regKey = GetRootKey(path).OpenSubKey(path.Substring(5), true))
|
||||
if (regKey != null)
|
||||
regKey.DeleteValue(name, false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
static RegistryKey GetRootKey(string path)
|
||||
{
|
||||
switch (path.Substring(0, 4))
|
||||
{
|
||||
case "HKLM": return Registry.LocalMachine;
|
||||
case "HKCU": return Registry.CurrentUser;
|
||||
case "HKCR": return Registry.ClassesRoot;
|
||||
default: throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
class UpdateCheck
|
||||
{
|
||||
public static void DailyCheck()
|
||||
{
|
||||
if (App.UpdateCheck && RegistryHelp.GetInt(RegistryHelp.ApplicationKey, "UpdateCheckLast")
|
||||
!= DateTime.Now.DayOfYear)
|
||||
|
||||
CheckOnline();
|
||||
}
|
||||
|
||||
public static async void CheckOnline(bool showUpToDateMessage = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
RegistryHelp.SetValue(RegistryHelp.ApplicationKey, "UpdateCheckLast", DateTime.Now.DayOfYear);
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "mpv.net");
|
||||
var response = await client.GetAsync("https://api.github.com/repos/stax76/mpv.net/releases/latest");
|
||||
response.EnsureSuccessStatusCode();
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
Match match = Regex.Match(content, @"""mpv\.net-portable-x64-([\d\.]+)\.7z""");
|
||||
Version onlineVersion = Version.Parse(match.Groups[1].Value);
|
||||
Version currentVersion = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
if (onlineVersion <= currentVersion)
|
||||
{
|
||||
if (showUpToDateMessage)
|
||||
Msg.Show($"{Application.ProductName} is up to date.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((RegistryHelp.GetString(RegistryHelp.ApplicationKey, "UpdateCheckVersion")
|
||||
!= onlineVersion.ToString() || showUpToDateMessage) && Msg.ShowQuestion(
|
||||
$"New version {onlineVersion} is available, update now?") == MsgResult.OK)
|
||||
{
|
||||
string arch = IntPtr.Size == 8 ? "64" : "86";
|
||||
string url = $"https://github.com/stax76/mpv.net/releases/download/{onlineVersion}/mpv.net-portable-x{arch}-{onlineVersion}.7z";
|
||||
|
||||
using (Process proc = new Process())
|
||||
{
|
||||
proc.StartInfo.UseShellExecute = true;
|
||||
proc.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
proc.StartInfo.FileName = "PowerShell";
|
||||
proc.StartInfo.Arguments = $"-NoLogo -NoExit -File \"{Folder.Startup + "Update.ps1"}\" \"{url}\" \"{Application.StartupPath.TrimEnd('\\')}\"";
|
||||
|
||||
if (Folder.Startup.Contains("Program Files"))
|
||||
proc.StartInfo.Verb = "runas";
|
||||
|
||||
proc.Start();
|
||||
}
|
||||
|
||||
core.command("quit");
|
||||
}
|
||||
|
||||
RegistryHelp.SetValue(RegistryHelp.ApplicationKey, "UpdateCheckVersion", onlineVersion.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (showUpToDateMessage)
|
||||
Msg.ShowException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class WinAPI
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool AttachConsole(int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool FreeConsole();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr LoadLibrary(string path);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int RegisterWindowMessage(string id);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AllowSetForegroundWindow(int dwProcessId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern void ReleaseCapture();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
|
||||
static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
|
||||
static extern IntPtr GetWindowLong64(IntPtr hWnd, int nIndex);
|
||||
|
||||
public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return GetWindowLong64(hWnd, nIndex);
|
||||
else
|
||||
return GetWindowLong32(hWnd, nIndex);
|
||||
}
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
|
||||
public RECT(Rectangle r)
|
||||
{
|
||||
Left = r.Left;
|
||||
Top = r.Top;
|
||||
Right = r.Right;
|
||||
Bottom = r.Bottom;
|
||||
}
|
||||
|
||||
public RECT(int left, int top, int right, int bottom)
|
||||
{
|
||||
Left = left;
|
||||
Top = top;
|
||||
Right = right;
|
||||
Bottom = bottom;
|
||||
}
|
||||
|
||||
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
|
||||
public Size Size => new Size(Right - Left, Bottom - Top);
|
||||
public int Width => Right - Left;
|
||||
public int Height => Bottom - Top;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct COPYDATASTRUCT
|
||||
{
|
||||
public IntPtr dwData;
|
||||
public int cbData;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpData;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public static class NativeHelp
|
||||
{
|
||||
public static int GetResizeBorder(int v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case 1 /* WMSZ_LEFT */ : return 3;
|
||||
case 3 /* WMSZ_TOP */ : return 2;
|
||||
case 2 /* WMSZ_RIGHT */ : return 3;
|
||||
case 6 /* WMSZ_BOTTOM */ : return 2;
|
||||
case 4 /* WMSZ_TOPLEFT */ : return 1;
|
||||
case 5 /* WMSZ_TOPRIGHT */ : return 1;
|
||||
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
|
||||
case 8 /* WMSZ_BOTTOMRIGHT */: return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SubtractWindowBorders(IntPtr hwnd, ref WinAPI.RECT rc)
|
||||
{
|
||||
var b = new WinAPI.RECT(0, 0, 0, 0);
|
||||
AddWindowBorders(hwnd, ref b);
|
||||
rc.Left -= b.Left;
|
||||
rc.Top -= b.Top;
|
||||
rc.Right -= b.Right;
|
||||
rc.Bottom -= b.Bottom;
|
||||
}
|
||||
|
||||
public static void AddWindowBorders(IntPtr hwnd, ref WinAPI.RECT rc)
|
||||
{
|
||||
WinAPI.AdjustWindowRect(ref rc, (uint)WinAPI.GetWindowLong(hwnd, -16 /* GWL_STYLE */), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,662 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
public class Msg
|
||||
{
|
||||
static string ShownMessages;
|
||||
|
||||
public static string SupportURL { get; set; }
|
||||
|
||||
public static void Show(string mainInstruction, string content = null)
|
||||
{
|
||||
Msg.Show(mainInstruction, content, MsgIcon.Info, MsgButtons.Ok, MsgResult.None);
|
||||
}
|
||||
|
||||
public static void ShowError(string mainInstruction, string content = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TaskDialog<string> td = new TaskDialog<string>())
|
||||
{
|
||||
td.AllowCancel = false;
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
{
|
||||
if (mainInstruction.Length < 80)
|
||||
td.MainInstruction = mainInstruction;
|
||||
else
|
||||
td.Content = mainInstruction;
|
||||
}
|
||||
else
|
||||
{
|
||||
td.MainInstruction = mainInstruction;
|
||||
td.Content = content;
|
||||
}
|
||||
|
||||
td.MainIcon = MsgIcon.Error;
|
||||
td.Footer = "[Copy Message](copymsg)";
|
||||
|
||||
if (!string.IsNullOrEmpty(Msg.SupportURL))
|
||||
td.Footer += $" [Contact Support]({SupportURL})";
|
||||
|
||||
td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
|
||||
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowException(Exception exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TaskDialog<string> td = new TaskDialog<string>())
|
||||
{
|
||||
td.MainInstruction = exception.GetType().Name;
|
||||
td.Content = exception.Message;
|
||||
td.MainIcon = MsgIcon.Error;
|
||||
td.ExpandedInformation = exception.StackTrace;
|
||||
td.Footer = "[Copy Message](copymsg)";
|
||||
|
||||
if (!string.IsNullOrEmpty(Msg.SupportURL))
|
||||
td.Footer += $" [Contact Support]({SupportURL})";
|
||||
|
||||
td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show(e.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowWarning(string mainInstruction,
|
||||
string content = null,
|
||||
bool onlyOnce = false)
|
||||
{
|
||||
if (onlyOnce && Msg.ShownMessages != null &&
|
||||
Msg.ShownMessages.Contains(mainInstruction + content))
|
||||
return;
|
||||
|
||||
Msg.Show(mainInstruction, content, MsgIcon.Warning, MsgButtons.Ok, MsgResult.None);
|
||||
if (!onlyOnce) return;
|
||||
Msg.ShownMessages += mainInstruction + content;
|
||||
}
|
||||
|
||||
public static MsgResult ShowQuestion(
|
||||
string mainInstruction, MsgButtons buttons = MsgButtons.OkCancel)
|
||||
{
|
||||
return Msg.Show(mainInstruction, null, MsgIcon.None, buttons, MsgResult.None);
|
||||
}
|
||||
|
||||
public static MsgResult ShowQuestion(
|
||||
string mainInstruction, string content, MsgButtons buttons = MsgButtons.OkCancel)
|
||||
{
|
||||
return Msg.Show(mainInstruction, content, MsgIcon.None, buttons, MsgResult.None);
|
||||
}
|
||||
|
||||
public static MsgResult Show(
|
||||
string mainInstruction,
|
||||
string content,
|
||||
MsgIcon icon,
|
||||
MsgButtons buttons,
|
||||
MsgResult defaultButton = MsgResult.None)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (TaskDialog<MsgResult> td = new TaskDialog<MsgResult>())
|
||||
{
|
||||
td.AllowCancel = false;
|
||||
td.DefaultButton = defaultButton;
|
||||
td.MainIcon = icon;
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
if (mainInstruction.Length < 80)
|
||||
td.MainInstruction = mainInstruction;
|
||||
else
|
||||
td.Content = mainInstruction;
|
||||
}
|
||||
else
|
||||
{
|
||||
td.MainInstruction = mainInstruction;
|
||||
td.Content = content;
|
||||
}
|
||||
if (buttons == MsgButtons.OkCancel)
|
||||
{
|
||||
td.AddButton("OK", MsgResult.OK);
|
||||
td.AddButton("Cancel", MsgResult.Cancel);
|
||||
}
|
||||
else
|
||||
td.CommonButtons = buttons;
|
||||
return td.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return (MsgResult)MessageBox.Show(e.GetType().Name + "\n\n" + e.Message + "\n\n" + e,
|
||||
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TaskDialog<T> : TaskDialogNative, IDisposable
|
||||
{
|
||||
Dictionary<int, T> IdValueDic;
|
||||
Dictionary<int, string> IdTextDic;
|
||||
List<int> CommandLinkShieldList;
|
||||
IntPtr ButtonArray;
|
||||
IntPtr RadioButtonArray;
|
||||
T SelectedValueValue;
|
||||
string SelectedTextValue;
|
||||
int TimeoutValue;
|
||||
int ExitTickCount;
|
||||
bool Disposed;
|
||||
List<TaskDialogNative.TASKDIALOG_BUTTON> Buttons;
|
||||
List<TaskDialogNative.TASKDIALOG_BUTTON> RadioButtons;
|
||||
TaskDialogNative.TASKDIALOGCONFIG Config;
|
||||
|
||||
const int TDE_CONTENT = 0;
|
||||
const int TDE_EXPANDED_INFORMATION = 1;
|
||||
const int TDE_FOOTER = 2;
|
||||
const int TDE_MAIN_INSTRUCTION = 3;
|
||||
const int TDN_CREATED = 0;
|
||||
const int TDN_NAVIGATED = 1;
|
||||
const int TDN_BUTTON_CLICKED = 2;
|
||||
const int TDN_HYPERLINK_CLICKED = 3;
|
||||
const int TDN_TIMER = 4;
|
||||
const int TDN_DESTROYED = 5;
|
||||
const int TDN_RADIO_BUTTON_CLICKED = 6;
|
||||
const int TDN_DIALOG_CONSTRUCTED = 7;
|
||||
const int TDN_VERIFICATION_CLICKED = 8;
|
||||
const int TDN_HELP = 9;
|
||||
const int TDN_EXPANDO_BUTTON_CLICKED = 10;
|
||||
const int TDM_NAVIGATE_PAGE = 1125;
|
||||
const int TDM_CLICK_BUTTON = 1126;
|
||||
const int TDM_SET_MARQUEE_PROGRESS_BAR = 1127;
|
||||
const int TDM_SET_PROGRESS_BAR_STATE = 1128;
|
||||
const int TDM_SET_PROGRESS_BAR_RANGE = 1129;
|
||||
const int TDM_SET_PROGRESS_BAR_POS = 1130;
|
||||
const int TDM_SET_PROGRESS_BAR_MARQUEE = 1131;
|
||||
const int TDM_SET_ELEMENT_TEXT = 1132;
|
||||
const int TDM_CLICK_RADIO_BUTTON = 1134;
|
||||
const int TDM_ENABLE_BUTTON = 1135;
|
||||
const int TDM_ENABLE_RADIO_BUTTON = 1136;
|
||||
const int TDM_CLICK_VERIFICATION = 1137;
|
||||
const int TDM_UPDATE_ELEMENT_TEXT = 1138;
|
||||
const int TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = 1139;
|
||||
const int TDM_UPDATE_ICON = 1140;
|
||||
|
||||
public TaskDialog()
|
||||
{
|
||||
IdValueDic = new Dictionary<int, T>();
|
||||
IdTextDic = new Dictionary<int, string>();
|
||||
CommandLinkShieldList = new List<int>();
|
||||
Buttons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
|
||||
RadioButtons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
|
||||
_SelectedID = -1;
|
||||
Config = new TaskDialogNative.TASKDIALOGCONFIG();
|
||||
Config.cbSize = (uint)Marshal.SizeOf(Config);
|
||||
Config.hwndParent = GetHandle();
|
||||
Config.hInstance = IntPtr.Zero;
|
||||
Config.dwFlags = TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
Config.dwCommonButtons = MsgButtons.None;
|
||||
Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
|
||||
Config.FooterIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
|
||||
Config.cxWidth = 0U;
|
||||
Config.cButtons = 0U;
|
||||
Config.cRadioButtons = 0U;
|
||||
Config.pButtons = IntPtr.Zero;
|
||||
Config.pRadioButtons = IntPtr.Zero;
|
||||
Config.nDefaultButton = 0;
|
||||
Config.nDefaultRadioButton = 0;
|
||||
Config.pszWindowTitle = ((AssemblyProductAttribute)Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0]).Product;
|
||||
Config.pszMainInstruction = "";
|
||||
Config.pszContent = "";
|
||||
Config.pfCallback = new PFTASKDIALOGCALLBACK(this.DialogProc);
|
||||
}
|
||||
|
||||
public IntPtr GetHandle()
|
||||
{
|
||||
StringBuilder lpszFileName = new StringBuilder(260);
|
||||
IntPtr foregroundWindow = TaskDialogNative.GetForegroundWindow();
|
||||
TaskDialogNative.GetWindowModuleFileName(foregroundWindow, lpszFileName, 260U);
|
||||
|
||||
if (Path.GetFileName(lpszFileName.ToString().Replace(".vshost", "")) ==
|
||||
Path.GetFileName(Assembly.GetEntryAssembly().Location))
|
||||
|
||||
return foregroundWindow;
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
public bool AllowCancel {
|
||||
set {
|
||||
if (value)
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
else
|
||||
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
|
||||
}
|
||||
}
|
||||
|
||||
public string MainInstruction {
|
||||
get => Config.pszMainInstruction;
|
||||
set => Config.pszMainInstruction = value;
|
||||
}
|
||||
|
||||
public string Content {
|
||||
get => Config.pszContent;
|
||||
set => Config.pszContent = ExpandMarkdownMarkup(value);
|
||||
}
|
||||
|
||||
public string ExpandedInformation {
|
||||
get => Config.pszExpandedInformation;
|
||||
set => Config.pszExpandedInformation = ExpandMarkdownMarkup(value);
|
||||
}
|
||||
|
||||
public string VerificationText {
|
||||
get => Config.pszVerificationText;
|
||||
set => Config.pszVerificationText = value;
|
||||
}
|
||||
|
||||
public MsgResult DefaultButton {
|
||||
get => (MsgResult)Config.nDefaultButton;
|
||||
set => Config.nDefaultButton = (int)value;
|
||||
}
|
||||
|
||||
public string Footer {
|
||||
get => Config.pszFooter;
|
||||
set => Config.pszFooter = ExpandMarkdownMarkup(value);
|
||||
}
|
||||
|
||||
public MsgIcon MainIcon {
|
||||
set => Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION((int)value);
|
||||
}
|
||||
|
||||
int _SelectedID;
|
||||
|
||||
public int SelectedID {
|
||||
get => _SelectedID;
|
||||
set {
|
||||
foreach (var i in IdValueDic)
|
||||
if (i.Key == value)
|
||||
_SelectedID = value;
|
||||
}
|
||||
}
|
||||
|
||||
public T SelectedValue {
|
||||
get {
|
||||
if (IdValueDic.ContainsKey(SelectedID))
|
||||
return IdValueDic[SelectedID];
|
||||
|
||||
return SelectedValueValue;
|
||||
}
|
||||
set => SelectedValueValue = value;
|
||||
}
|
||||
|
||||
public string SelectedText {
|
||||
get {
|
||||
if (IdTextDic.ContainsKey(SelectedID))
|
||||
return IdTextDic[SelectedID];
|
||||
|
||||
return SelectedTextValue;
|
||||
}
|
||||
set => SelectedTextValue = value;
|
||||
}
|
||||
|
||||
public bool CheckBoxChecked {
|
||||
get => (Config.dwFlags & TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED)
|
||||
== TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
|
||||
set {
|
||||
if (value)
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
|
||||
else
|
||||
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
|
||||
}
|
||||
}
|
||||
|
||||
public MsgButtons CommonButtons {
|
||||
get => Config.dwCommonButtons;
|
||||
set => Config.dwCommonButtons = value;
|
||||
}
|
||||
|
||||
public int Timeout {
|
||||
get => Convert.ToInt32(TimeoutValue / 1000.0);
|
||||
set {
|
||||
TimeoutValue = value * 1000;
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddButton(string text, T value)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
}
|
||||
|
||||
public string ExpandMarkdownMarkup(string value)
|
||||
{
|
||||
if (value.Contains("["))
|
||||
{
|
||||
Regex regex = new Regex(@"\[(.+)\]\((.+)\)");
|
||||
|
||||
if (regex.Match(value).Success)
|
||||
{
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS;
|
||||
value = regex.Replace(value, "<a href=\"$2\">$1</a>");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void AddCommand(string text, T value)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
IdTextDic[n] = text;
|
||||
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
|
||||
}
|
||||
|
||||
public void AddCommand(string text, string description, T value, bool setShield = false)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
|
||||
if (setShield)
|
||||
CommandLinkShieldList.Add(n);
|
||||
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
text += "\n" + description;
|
||||
|
||||
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
|
||||
}
|
||||
|
||||
public void AddRadioButton(string text, T value)
|
||||
{
|
||||
int n = 1000 + IdValueDic.Count + 1;
|
||||
IdValueDic[n] = value;
|
||||
RadioButtons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
|
||||
}
|
||||
|
||||
public T Show()
|
||||
{
|
||||
MarshalDialogControlStructs();
|
||||
TaskDialogNative.TASKDIALOGCONFIG config = Config;
|
||||
int hr = TaskDialogNative.TaskDialogIndirect(
|
||||
config, out int dummy1, out int dummy2, out bool isChecked);
|
||||
|
||||
if (hr < 0)
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
|
||||
CheckBoxChecked = isChecked;
|
||||
|
||||
if (SelectedValue is MsgResult)
|
||||
SelectedValue = (T)(object)SelectedID;
|
||||
|
||||
return SelectedValue;
|
||||
}
|
||||
|
||||
public int DialogProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, IntPtr lpRefData)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case 0: //TDN_CREATED
|
||||
foreach (var i in CommandLinkShieldList)
|
||||
SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, new IntPtr(i), new IntPtr(1));
|
||||
break;
|
||||
case 2: //TDN_BUTTON_CLICKED
|
||||
case 6: //TDN_RADIO_BUTTON_CLICKED
|
||||
if (SelectedValue is MsgResult)
|
||||
_SelectedID = wParam.ToInt32();
|
||||
else
|
||||
SelectedID = wParam.ToInt32();
|
||||
break;
|
||||
case 3: //TDN_HYPERLINK_CLICKED
|
||||
string stringUni = Marshal.PtrToStringUni(lParam);
|
||||
|
||||
if (stringUni.StartsWith("mailto") || stringUni.StartsWith("http"))
|
||||
Process.Start(stringUni);
|
||||
|
||||
if (stringUni == "copymsg")
|
||||
{
|
||||
Thread thread = new Thread((ThreadStart)(() => {
|
||||
Clipboard.SetText(MainInstruction + "\r\n\r\n" + Content + "\r\n\r\n" + ExpandedInformation);
|
||||
MessageBox.Show("Message was copied to clipboard.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}));
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
}
|
||||
break;
|
||||
case 4: //TDN_TIMER
|
||||
if (ExitTickCount == 0) ExitTickCount = Environment.TickCount + Timeout * 1000;
|
||||
if (Environment.TickCount > ExitTickCount)
|
||||
TaskDialogNative.SendMessage(hwnd, 1126, new IntPtr(1), IntPtr.Zero);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void MarshalDialogControlStructs()
|
||||
{
|
||||
if (Buttons != null && Buttons.Count > 0)
|
||||
{
|
||||
ButtonArray = TaskDialog<T>.AllocateAndMarshalButtons(Buttons);
|
||||
Config.pButtons = ButtonArray;
|
||||
Config.cButtons = (uint)Buttons.Count;
|
||||
}
|
||||
|
||||
if (RadioButtons == null || RadioButtons.Count <= 0) return;
|
||||
RadioButtonArray = TaskDialog<T>.AllocateAndMarshalButtons(RadioButtons);
|
||||
Config.pRadioButtons = RadioButtonArray;
|
||||
Config.cRadioButtons = (uint)RadioButtons.Count;
|
||||
}
|
||||
|
||||
public static IntPtr AllocateAndMarshalButtons(List<TaskDialogNative.TASKDIALOG_BUTTON> structs)
|
||||
{
|
||||
var initialPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TASKDIALOG_BUTTON)) * structs.Count);
|
||||
var currentPtr = initialPtr;
|
||||
|
||||
foreach (var button in structs)
|
||||
{
|
||||
Marshal.StructureToPtr(button, currentPtr, false);
|
||||
currentPtr = (IntPtr)(currentPtr.ToInt64() + Marshal.SizeOf(button));
|
||||
}
|
||||
|
||||
return initialPtr;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~TaskDialog()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
return;
|
||||
|
||||
Disposed = true;
|
||||
|
||||
if (ButtonArray != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(ButtonArray);
|
||||
ButtonArray = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (RadioButtonArray != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(RadioButtonArray);
|
||||
RadioButtonArray = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public delegate int PFTASKDIALOGCALLBACK(
|
||||
IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, IntPtr lpRefData);
|
||||
|
||||
public class TaskDialogNative
|
||||
{
|
||||
[DllImport("comctl32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern int TaskDialogIndirect(
|
||||
TaskDialogNative.TASKDIALOGCONFIG pTaskConfig,
|
||||
out int pnButton,
|
||||
out int pnRadioButton,
|
||||
out bool pVerificationFlagChecked);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern uint GetWindowModuleFileName(
|
||||
IntPtr hwnd, StringBuilder lpszFileName, uint cchFileNameMax);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr SendMessage(
|
||||
IntPtr handle, int message, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
|
||||
public class TASKDIALOGCONFIG
|
||||
{
|
||||
public uint cbSize;
|
||||
public IntPtr hwndParent;
|
||||
public IntPtr hInstance;
|
||||
public TaskDialogNative.TASKDIALOG_FLAGS dwFlags;
|
||||
public MsgButtons dwCommonButtons;
|
||||
public string pszWindowTitle;
|
||||
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION MainIcon;
|
||||
public string pszMainInstruction;
|
||||
public string pszContent;
|
||||
public uint cButtons;
|
||||
public IntPtr pButtons;
|
||||
public int nDefaultButton;
|
||||
public uint cRadioButtons;
|
||||
public IntPtr pRadioButtons;
|
||||
public int nDefaultRadioButton;
|
||||
public string pszVerificationText;
|
||||
public string pszExpandedInformation;
|
||||
public string pszExpandedControlText;
|
||||
public string pszCollapsedControlText;
|
||||
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION FooterIcon;
|
||||
public string pszFooter;
|
||||
public PFTASKDIALOGCALLBACK pfCallback;
|
||||
public IntPtr lpCallbackData;
|
||||
public uint cxWidth;
|
||||
}
|
||||
|
||||
public enum TASKDIALOG_FLAGS
|
||||
{
|
||||
NONE = 0,
|
||||
TDF_ENABLE_HYPERLINKS = 1,
|
||||
TDF_USE_HICON_MAIN = 2,
|
||||
TDF_USE_HICON_FOOTER = 4,
|
||||
TDF_ALLOW_DIALOG_CANCELLATION = 8,
|
||||
TDF_USE_COMMAND_LINKS = 16,
|
||||
TDF_USE_COMMAND_LINKS_NO_ICON = 32,
|
||||
TDF_EXPAND_FOOTER_AREA = 64,
|
||||
TDF_EXPANDED_BY_DEFAULT = 128,
|
||||
TDF_VERIFICATION_FLAG_CHECKED = 256,
|
||||
TDF_SHOW_PROGRESS_BAR = 512,
|
||||
TDF_SHOW_MARQUEE_PROGRESS_BAR = 1024,
|
||||
TDF_CALLBACK_TIMER = 2048,
|
||||
TDF_POSITION_RELATIVE_TO_WINDOW = 4096,
|
||||
TDF_RTL_LAYOUT = 8192,
|
||||
TDF_NO_DEFAULT_RADIO_BUTTON = 16384,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
|
||||
public struct TASKDIALOGCONFIG_ICON_UNION
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int hMainIcon;
|
||||
[FieldOffset(0)]
|
||||
public int pszIcon;
|
||||
[FieldOffset(0)]
|
||||
public IntPtr spacer;
|
||||
|
||||
public TASKDIALOGCONFIG_ICON_UNION(int i)
|
||||
{
|
||||
this = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION();
|
||||
spacer = IntPtr.Zero;
|
||||
pszIcon = 0;
|
||||
hMainIcon = i;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
|
||||
public struct TASKDIALOG_BUTTON
|
||||
{
|
||||
public int nButtonID;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string pszButtonText;
|
||||
|
||||
public TASKDIALOG_BUTTON(int n, string txt)
|
||||
{
|
||||
this = new TaskDialogNative.TASKDIALOG_BUTTON();
|
||||
nButtonID = n;
|
||||
pszButtonText = txt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MsgButtons
|
||||
{
|
||||
None = 0,
|
||||
Ok = 1,
|
||||
Yes = 2,
|
||||
No = 4,
|
||||
YesNo = 6,
|
||||
Cancel = 8,
|
||||
OkCancel = 9,
|
||||
YesNoCancel = 14,
|
||||
Retry = 16,
|
||||
RetryCancel = 24,
|
||||
Close = 32,
|
||||
}
|
||||
|
||||
public enum MsgResult
|
||||
{
|
||||
None,
|
||||
OK,
|
||||
Cancel,
|
||||
Abort,
|
||||
Retry,
|
||||
Ignore,
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
public enum MsgIcon
|
||||
{
|
||||
None = 0,
|
||||
SecurityShieldGray = 65527,
|
||||
SecuritySuccess = 65528,
|
||||
SecurityError = 65529,
|
||||
SecurityWarning = 65530,
|
||||
SecurityShieldBlue = 65531,
|
||||
Shield = 65532,
|
||||
Info = 65533,
|
||||
Error = 65534,
|
||||
Warning = 65535,
|
||||
}
|
||||
@@ -1,587 +0,0 @@
|
||||
|
||||
[[settings]]
|
||||
name = "hwdec"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Video"
|
||||
url = "https://mpv.io/manual/master/#options-hwdec"
|
||||
help = "Specify the hardware video decoding API that should be used if possible. Whether hardware decoding is actually done depends on the video codec. If hardware decoding is not possible, mpv will fall back on software decoding.\n\nFor more information visit:"
|
||||
options = [{ name = "no", help = "always use software decoding" },
|
||||
{ name = "auto", help = "enable best hw decoder (see below)" },
|
||||
{ name = "yes", help = "exactly the same as auto" },
|
||||
{ name = "auto-copy", help = "enable best hw decoder with copy-back (see below)" },
|
||||
{ name = "dxva2", help = "requires vo=gpu with gpu-context=d3d11, gpu-context=angle or gpu-context=dxinterop (Windows only)" },
|
||||
{ name = "dxva2-copy", help = "copies video back to system RAM (Windows only)" },
|
||||
{ name = "d3d11va", help = "requires vo=gpu with gpu-context=d3d11 or gpu-context=angle (Windows 8+ only)" },
|
||||
{ name = "d3d11va-copy", help = "copies video back to system RAM (Windows 8+ only)" },
|
||||
{ name = "cuda", help = "requires vo=gpu (Any platform CUDA is available)" },
|
||||
{ name = "cuda-copy", help = "copies video back to system RAM (Any platform CUDA is available)" },
|
||||
{ name = "nvdec", help = "requires vo=gpu (Any platform CUDA is available)" },
|
||||
{ name = "nvdec-copy", help = "copies video back to system RAM (Any platform CUDA is available)" },
|
||||
{ name = "crystalhd", help = "copies video back to system RAM (Any platform supported by hardware)" },
|
||||
{ name = "rkmpp", help = "requires vo=gpu (some RockChip devices only)" }]
|
||||
|
||||
[[settings]]
|
||||
name = "gpu-api"
|
||||
file = "mpv"
|
||||
default = "auto"
|
||||
filter = "Video"
|
||||
help = "Controls which type of graphics APIs will be accepted. Auto uses d3d11, it should only be changed in case of problems, Vulkan is not recommended."
|
||||
options = [{ name = "auto", help = "Use any available API" },
|
||||
{ name = "opengl", help = "Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)" },
|
||||
{ name = "vulkan", help = "Allow only Vulkan (not recommended). " },
|
||||
{ name = "d3d11", help = "Allow only gpu-context=d3d11" }]
|
||||
|
||||
[[settings]]
|
||||
name = "gpu-context"
|
||||
file = "mpv"
|
||||
default = "auto"
|
||||
filter = "Video"
|
||||
options = [{ name = "auto", help = "auto-select" },
|
||||
{ name = "win", help = "Win32/WGL" },
|
||||
{ name = "winvk", help = "VK_KHR_win32_surface" },
|
||||
{ name = "angle", help = "Direct3D11 through the OpenGL ES translation layer ANGLE. This supports almost everything the win backend does (if the ANGLE build is new enough)." },
|
||||
{ name = "dxinterop", help = "(experimental) Win32, using WGL for rendering and Direct3D 9Ex for presentation. Works on Nvidia and AMD. Newer Intel chips with the latest drivers may also work." },
|
||||
{ name = "d3d11", help = "Win32, with native Direct3D 11 rendering." }]
|
||||
|
||||
[[settings]]
|
||||
name = "vo"
|
||||
file = "mpv"
|
||||
default = "gpu"
|
||||
filter = "Video"
|
||||
help = "Video output drivers to be used.\n\nFor more information visit:"
|
||||
url = "https://mpv.io/manual/master/#video-output-drivers-vo"
|
||||
options = [{ name = "gpu", help = "General purpose, customizable, GPU-accelerated video output driver. It supports extended scaling methods, dithering, color management, custom shaders, HDR, and more." },
|
||||
{ name = "direct3d", help = "Video output driver that uses the Direct3D interface" }]
|
||||
|
||||
[[settings]]
|
||||
name = "video-sync"
|
||||
file = "mpv"
|
||||
default = "audio"
|
||||
filter = "Video"
|
||||
help = "How the player synchronizes audio and video.\n\nFor more information visit:"
|
||||
url = "https://mpv.io/manual/master/#options-video-sync"
|
||||
options = [{ name = "audio" },
|
||||
{ name = "display-resample" },
|
||||
{ name = "display-resample-vdrop" },
|
||||
{ name = "display-resample-desync" },
|
||||
{ name = "display-vdrop" },
|
||||
{ name = "display-adrop" },
|
||||
{ name = "display-desync" },
|
||||
{ name = "desync" }]
|
||||
|
||||
[[settings]]
|
||||
name = "scale"
|
||||
file = "mpv"
|
||||
default = "bilinear"
|
||||
filter = "Video"
|
||||
help = "The GPU renderer filter function to use when upscaling video. There are some more filters, but most are not as useful. For a complete list, pass help as value, e.g.: mpv --scale=help"
|
||||
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality)." },
|
||||
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
|
||||
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
|
||||
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
|
||||
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
|
||||
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale)." },
|
||||
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see tscale)." },
|
||||
{ name = "linear", help = "A tscale filter." }]
|
||||
|
||||
[[settings]]
|
||||
name = "cscale"
|
||||
file = "mpv"
|
||||
default = "bilinear"
|
||||
filter = "Video"
|
||||
help = "As scale, but for interpolating chroma information. If the image is not subsampled, this option is ignored entirely."
|
||||
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality)." },
|
||||
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
|
||||
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
|
||||
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
|
||||
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
|
||||
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale)." },
|
||||
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see tscale)." },
|
||||
{ name = "linear", help = "A tscale filter." }]
|
||||
|
||||
[[settings]]
|
||||
name = "dscale"
|
||||
file = "mpv"
|
||||
default = "bilinear"
|
||||
filter = "Video"
|
||||
help = "Like scale, but apply these filters on downscaling instead. If this option is unset, the filter implied by scale will be applied."
|
||||
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality)." },
|
||||
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
|
||||
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
|
||||
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
|
||||
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
|
||||
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with scale-param1 and scale-param2. This filter is very good at downscaling (see dscale)." },
|
||||
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see tscale)." },
|
||||
{ name = "linear", help = "A tscale filter." }]
|
||||
|
||||
[[settings]]
|
||||
name = "dither-depth"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Video"
|
||||
help = "Set dither target depth to N. Note that the depth of the connected video display device cannot be detected. Often, LCD panels will do dithering on their own, which conflicts with this option and leads to ugly output."
|
||||
options = [{ name = "no", help = "Disable any dithering done by mpv." },
|
||||
{ name = "auto", help = "Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed." },
|
||||
{ name = "8", help = "Dither to 8 bit output." }]
|
||||
|
||||
[[settings]]
|
||||
name = "correct-downscaling"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Video"
|
||||
help = "When using convolution based filters, extend the filter size when downscaling. Increases quality, but reduces performance while downscaling.\n\nThis will perform slightly sub-optimally for anamorphic video (but still better than without it) since it will extend the size to match only the milder of the scale factors between the axes."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "sigmoid-upscaling"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Video"
|
||||
help = "When upscaling, use a sigmoidal color transform to avoid emphasizing ringing artifacts. This also implies linear-scaling."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "deband"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Video"
|
||||
help = "Enable the debanding algorithm. This greatly reduces the amount of visible banding, blocking and other quantization artifacts, at the expense of very slightly blurring some of the finest details. In practice, it's virtually always an improvement - the only reason to disable it would be for performance."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "d3d11va-zero-copy"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Video"
|
||||
help = "By default, when using hardware decoding with --gpu-api=d3d11, the video image will be copied (GPU-to-GPU) from the decoder surface to a shader resource. Set this option to avoid that copy by sampling directly from the decoder image. This may increase performance and reduce power usage, but can cause the image to be sampled incorrectly on the bottom and right edges due to padding, and may invoke driver bugs, since Direct3D 11 technically does not allow sampling from a decoder surface (though most drivers support it.)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "hdr-compute-peak"
|
||||
file = "mpv"
|
||||
default = "auto"
|
||||
filter = "Video"
|
||||
help = "Compute the HDR peak and frame average brightness per-frame instead of relying on tagged metadata. These values are averaged over local regions as well as over several frames to prevent the value from jittering around too much. This option basically gives you dynamic, per-scene tone mapping. Requires compute shaders, which is a fairly recent OpenGL feature, and will probably also perform horribly on some drivers, so enable at your own risk. The special value auto (default) will enable HDR peak computation automatically if compute shaders and SSBOs are supported."
|
||||
options = [{ name = "auto" },
|
||||
{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "volume"
|
||||
file = "mpv"
|
||||
filter = "Audio"
|
||||
help = "Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. Negative values can be passed for compatibility, but are treated as 0. Since mpv 0.18.1, this always controls the internal mixer (aka \"softvol\"). Default: 100"
|
||||
|
||||
[[settings]]
|
||||
name = "remember-volume"
|
||||
file = "mpvnet"
|
||||
default = "yes"
|
||||
filter = "Audio"
|
||||
help = "Save volume and mute on exit and restore it on start. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "alang"
|
||||
file = "mpv"
|
||||
filter = "Audio"
|
||||
type = "string"
|
||||
help = "Specify a priority list of audio languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two-letter language codes, Matroska, MPEG-TS and NUT use ISO 639-2 three-letter language codes, while OGM uses a free-form identifier. See also aid.\n\nExamples\n\nmpv dvd://1 alang=hu,en chooses the Hungarian language track on a DVD and falls back on English if Hungarian is not available.\n\nmpv alang=jpn example.mkv plays a Matroska file with Japanese audio."
|
||||
|
||||
[[settings]]
|
||||
name = "audio-file-auto"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Audio"
|
||||
help = "Load additional audio files matching the video filename. The parameter specifies how external audio files are matched."
|
||||
options = [{ name = "no", help = "Don't automatically load external audio files." },
|
||||
{ name = "exact", help = "Load the media filename with audio file extension." },
|
||||
{ name = "fuzzy", help = "Load all audio files containing media filename." },
|
||||
{ name = "all", help = "Load all audio files in the current and audio-file-paths directories." }]
|
||||
|
||||
[[settings]]
|
||||
name = "slang"
|
||||
file = "mpv"
|
||||
filter = "Subtitle"
|
||||
type = "string"
|
||||
help = "Specify a priority list of subtitle languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two letter language codes, Matroska uses ISO 639-2 three letter language codes while OGM uses a free-form identifier. See also sid."
|
||||
|
||||
[[settings]]
|
||||
name = "sub-auto"
|
||||
file = "mpv"
|
||||
default = "exact"
|
||||
filter = "Subtitle"
|
||||
help = "Load additional subtitle files matching the video filename. The parameter specifies how external subtitle files are matched. exact is enabled by default."
|
||||
options = [{ name = "no", help = "Don't automatically load external subtitle files." },
|
||||
{ name = "exact", help = "Load the media filename with subtitle file extension." },
|
||||
{ name = "fuzzy", help = "Load all subs containing media filename." },
|
||||
{ name = "all", help = "Load all subs in the current and sub-file-paths directories." }]
|
||||
|
||||
[[settings]]
|
||||
name = "sub-font"
|
||||
file = "mpv"
|
||||
filter = "Subtitle"
|
||||
type = "string"
|
||||
help = "Specify font to use for subtitles that do not themselves specify a particular font. The default is sans-serif."
|
||||
|
||||
[[settings]]
|
||||
name = "sub-font-size"
|
||||
file = "mpv"
|
||||
filter = "Subtitle"
|
||||
help = "Specify the sub font size. The unit is the size in scaled pixels at a window height of 720. The actual pixel size is scaled with the window height: if the window height is larger or smaller than 720, the actual size of the text increases or decreases as well. Default: 55"
|
||||
|
||||
[[settings]]
|
||||
name = "sub-color"
|
||||
file = "mpv"
|
||||
type = "color"
|
||||
filter = "Subtitle"
|
||||
help = "Specify the color used for unstyled text subtitles.\n\nThe color is specified in the form r/g/b, where each color component is specified as number in the range 0.0 to 1.0. It's also possible to specify the transparency by using r/g/b/a, where the alpha value 0 means fully transparent, and 1.0 means opaque. If the alpha component is not given, the color is 100% opaque.\n\nPassing a single number to the option sets the sub to gray, and the form gray/a lets you specify alpha additionally.\n\nExamples\n\n1.0/0.0/0.0 set sub to opaque red\n1.0/0.0/0.0/0.75 set sub to opaque red with 75% alpha\n0.5/0.75 set sub to 50% gray with 75% alpha\n\nAlternatively, the color can be specified as a RGB hex triplet in the form #RRGGBB, where each 2-digit group expresses a color value in the range 0 (00) to 255 (FF). For example, #FF0000 is red. This is similar to web colors. Alpha is given with #AARRGGBB.\n\nExamples\n\n#FF0000 set sub to opaque red\n#C0808080 set sub to 50% gray with 75% alpha"
|
||||
|
||||
[[settings]]
|
||||
name = "sub-border-color"
|
||||
file = "mpv"
|
||||
type = "color"
|
||||
filter = "Subtitle"
|
||||
help = "See sub-color. Color used for the sub font border. Ignored when sub-back-color is specified (or more exactly: when that option is not set to completely transparent)."
|
||||
|
||||
[[settings]]
|
||||
name = "sub-back-color"
|
||||
file = "mpv"
|
||||
type = "color"
|
||||
filter = "Subtitle"
|
||||
help = "See sub-color. Color used for sub text background. You can use sub-shadow-offset to change its size relative to the text."
|
||||
|
||||
[[settings]]
|
||||
name = "fullscreen"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Screen"
|
||||
help = "Start the player in fullscreen mode."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "border"
|
||||
file = "mpv"
|
||||
default = "yes"
|
||||
filter = "Screen"
|
||||
help = "Show window with decoration (titlebar, border)."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "screen"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "<0-32> In multi-monitor configurations (i.e. a single desktop that spans across multiple displays), this option tells mpv which screen to display the video on."
|
||||
|
||||
[[settings]]
|
||||
name = "osd-playing-msg"
|
||||
file = "mpv"
|
||||
width = 300
|
||||
filter = "Screen"
|
||||
type = "string"
|
||||
help = "Show a message on OSD when playback starts. The string is expanded for properties, e.g. osd-playing-msg='file: ${filename}' will show the message file: followed by a space and the currently played filename. For more information visit:"
|
||||
url = "https://mpv.io/manual/master/#property-expansion"
|
||||
|
||||
[[settings]]
|
||||
name = "osd-font-size"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "Specify the OSD font size. See sub-font-size for details. Default: 55"
|
||||
|
||||
[[settings]]
|
||||
name = "osd-duration"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "Set the duration of the OSD messages in ms. Default: 1000"
|
||||
|
||||
[[settings]]
|
||||
name = "osd-scale-by-window"
|
||||
file = "mpv"
|
||||
default = "yes"
|
||||
filter = "Screen"
|
||||
help = "Whether to scale the OSD with the window size. If this is disabled, osd-font-size and other OSD options that use scaled pixels are always in actual pixels. The effect is that changing the window size won't change the OSD font size."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "autofit"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "<int> Initial window height in percent. Default: 60"
|
||||
|
||||
[[settings]]
|
||||
name = "autofit-smaller"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "<int> Minimum window height in percent. Default: 30"
|
||||
|
||||
[[settings]]
|
||||
name = "autofit-larger"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "<int> Maximum window height in percent. Default: 80"
|
||||
|
||||
[[settings]]
|
||||
name = "start-size"
|
||||
file = "mpvnet"
|
||||
default = "previous"
|
||||
filter = "Screen"
|
||||
help = "Setting to remember the window height. (mpv.net specific setting)"
|
||||
options = [{ name = "video", help = "Window size is set to video resolution" },
|
||||
{ name = "previous", help = "Window size is remembered but only in the current session" },
|
||||
{ name = "always", help = "Window size is always remembered"}]
|
||||
|
||||
[[settings]]
|
||||
name = "start-threshold"
|
||||
file = "mpvnet"
|
||||
filter = "Screen"
|
||||
help = "Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. Default: 1500 (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "minimum-aspect-ratio"
|
||||
file = "mpvnet"
|
||||
filter = "Screen"
|
||||
help = "<float> Minimum aspect ratio, 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-position"
|
||||
file = "mpvnet"
|
||||
default = "no"
|
||||
filter = "Screen"
|
||||
help = "Save the window position on exit. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "window-maximized"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Screen"
|
||||
help = "Start with a maximized window."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-directory"
|
||||
file = "mpv"
|
||||
width = 500
|
||||
type = "folder"
|
||||
filter = "Screen"
|
||||
help = "Store screenshots in this directory. This path is joined with the filename generated by screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot."
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-format"
|
||||
file = "mpv"
|
||||
default = "jpg"
|
||||
filter = "Screen"
|
||||
help = "Set the image file type used for saving screenshots."
|
||||
options = [{ name = "jpg" },
|
||||
{ name = "png" }]
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-tag-colorspace"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Screen"
|
||||
help = "Tag screenshots with the appropriate colorspace. Note that not all formats are supported."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-high-bit-depth"
|
||||
file = "mpv"
|
||||
default = "yes"
|
||||
filter = "Screen"
|
||||
help = "If possible, write screenshots with a bit depth similar to the source video. This is interesting in particular for PNG, as this sometimes triggers writing 16 bit PNGs with huge file sizes. This will also include an unused alpha channel in the resulting files if 16 bit is used."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-jpeg-source-chroma"
|
||||
file = "mpv"
|
||||
default = "yes"
|
||||
filter = "Screen"
|
||||
help = "Write JPEG files with the same chroma subsampling as the video. If disabled, the libjpeg default is used."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-template"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
type = "string"
|
||||
help = "Specify the filename template used to save screenshots. The template specifies the filename without file extension, and can contain format specifiers, which will be substituted when taking a screenshot. By default, the template is mpv-shot%n, which results in filenames like mpv-shot0012.png for example.\n\nFind the full documentation here:"
|
||||
url = "https://mpv.io/manual/master/#options-screenshot-template"
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-jpeg-quality"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "<0-100> Set the JPEG quality level. Higher means better quality. The default is 90."
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-png-compression"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "<0-9> Set the PNG compression level. Higher means better compression. This will affect the file size of the written screenshot file and the time it takes to write a screenshot. Too high compression might occupy enough CPU time to interrupt playback. The default is 7."
|
||||
|
||||
[[settings]]
|
||||
name = "screenshot-png-filter"
|
||||
file = "mpv"
|
||||
filter = "Screen"
|
||||
help = "<0-5> Set the filter applied prior to PNG compression. 0 is none, 1 is 'sub', 2 is 'up', 3 is 'average', 4 is 'Paeth', and 5 is 'mixed'. This affects the level of compression that can be achieved. For most images, 'mixed' achieves the best compression ratio, hence it is the default."
|
||||
|
||||
[[settings]]
|
||||
name = "taskbar-progress"
|
||||
file = "mpv"
|
||||
default = "yes"
|
||||
filter = "Playback"
|
||||
help = "Show progress in taskbar."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "keep-open-pause"
|
||||
file = "mpv"
|
||||
default = "yes"
|
||||
filter = "Playback"
|
||||
help = "If set to no, instead of pausing when keep-open is active, just stop at end of file and continue playing forward when you seek backwards until end where it stops again."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "keep-open"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Playback"
|
||||
help = "Using no, mpv would terminate after the last file but mpv.net never terminates automatically."
|
||||
options = [{ name = "yes", help = "If the current file ends, go to the next file, keep the last file open."},
|
||||
{ name = "no", help = "If the current file ends, go to the next file." },
|
||||
{ name = "always", help = "Playback will never automatically advance to the next file."}]
|
||||
|
||||
[[settings]]
|
||||
name = "loop-file"
|
||||
file = "mpv"
|
||||
filter = "Playback"
|
||||
help = "<N|inf|no> Loop a single file N times. inf means forever, no means normal playback.\n\nThe difference to loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file. loop is an alias for this option."
|
||||
|
||||
[[settings]]
|
||||
name = "save-position-on-quit"
|
||||
file = "mpv"
|
||||
default = "no"
|
||||
filter = "Playback"
|
||||
help = "Always save the current playback position on quit. When this file is played again later, the player will seek to the old playback position on start. This does not happen if playback of a file is stopped in any other way than quitting. For example, going to the next file in the playlist will not save the position, and start playback at beginning the next time the file is played.\n\nThis behavior is disabled by default, but is always available when quitting the player with Shift+Q."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "hr-seek"
|
||||
file = "mpv"
|
||||
default = "absolute"
|
||||
filter = "Playback"
|
||||
help = "Select when to use precise seeks that are not limited to keyframes. Such seeks require decoding video from the previous keyframe up to the target position and so can take some time depending on decoding performance. For some video formats, precise seeks are disabled. This option selects the default choice to use for seeks; it is possible to explicitly override that default in the definition of key bindings and in input commands."
|
||||
options = [{ name = "yes", help = "Use precise seeks whenever possible." },
|
||||
{ name = "no", help = "Never use precise seeks." },
|
||||
{ name = "absolute", help = "Use precise seeks if the seek is to an absolute position in the file, such as a chapter seek, but not for relative seeks like the default behavior of arrow keys." },
|
||||
{ name = "always", help = "Same as yes (for compatibility)." }]
|
||||
|
||||
[[settings]]
|
||||
name = "track-auto-selection"
|
||||
file = "mpv"
|
||||
default = "yes"
|
||||
filter = "Playback"
|
||||
help = "Enable the default track auto-selection. Enabling this will make the player select streams according to aid, alang, and others. If it is disabled, no tracks are selected. In addition, the player will not exit if no tracks are selected, and wait instead (this wait mode is similar to pausing, but the pause option is not set).\n\nThis is useful with lavfi-complex: you can start playback in this mode, and then set select tracks at runtime by setting the filter graph. Note that if lavfi-complex is set before playback is started, the referenced tracks are always selected."
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "loop-playlist"
|
||||
file = "mpv"
|
||||
filter = "Playback"
|
||||
help = "<N|inf|force|no> Loops playback N times. A value of 1 plays it one time (default), 2 two times, etc. inf means forever. no is the same as 1 and disables looping. If several files are specified on command line, the entire playlist is looped. The force mode is like inf, but does not skip playlist entries which have been marked as failing. This means the player might waste CPU time trying to loop a file that doesn't exist. But it might be useful for playing webradios under very bad network conditions."
|
||||
|
||||
[[settings]]
|
||||
name = "auto-load-folder"
|
||||
file = "mpvnet"
|
||||
default = "yes"
|
||||
filter = "Playback"
|
||||
help = "For single files automatically load the entire directory into the playlist. Can be suppressed via shift key. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "input-ar-delay"
|
||||
file = "mpv"
|
||||
filter = "Input"
|
||||
help = "Delay in milliseconds before we start to autorepeat a key (0 to disable)."
|
||||
|
||||
[[settings]]
|
||||
name = "input-ar-rate"
|
||||
file = "mpv"
|
||||
filter = "Input"
|
||||
help = "Number of key presses to generate per second on autorepeat."
|
||||
|
||||
[[settings]]
|
||||
name = "update-check"
|
||||
file = "mpvnet"
|
||||
default = "no"
|
||||
filter = "General"
|
||||
help = "Daily check for new version. (requires PowerShell 5 and curl. mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "process-instance"
|
||||
file = "mpvnet"
|
||||
default = "single"
|
||||
filter = "General"
|
||||
help = "Defines if more then one mpv.net process is allowed. (mpv.net specific setting)\n\nTip: Whenever the control key is pressed when files or URLs are opened, the playlist is not cleared but the files or URLs are appended to the playlist. This not only works on process startup but in all mpv.net features that open files and URLs."
|
||||
options = [{ name = "multi", help = "Create a new process everytime the shell starts mpv.net" },
|
||||
{ name = "single", help = "Force a single process everytime the shell starts mpv.net" },
|
||||
{ name = "queue", help = "Force a single process and add files to playlist" }]
|
||||
|
||||
[[settings]]
|
||||
name = "recent-count"
|
||||
file = "mpvnet"
|
||||
filter = "General"
|
||||
help = "<int> Amount of recent files to be remembered. Default: 15 (mpv.net specific setting)"
|
||||
|
||||
[[settings]]
|
||||
name = "debug-mode"
|
||||
file = "mpvnet"
|
||||
default = "no"
|
||||
filter = "General"
|
||||
help = "Enable this only when a developer asks for it. (mpv.net specific setting)"
|
||||
options = [{ name = "yes" },
|
||||
{ name = "no" }]
|
||||
|
||||
[[settings]]
|
||||
name = "dark-mode"
|
||||
file = "mpvnet"
|
||||
default = "always"
|
||||
filter = "UI"
|
||||
help = "Enables a dark theme. (mpv.net specific setting)"
|
||||
options = [{ name = "always" },
|
||||
{ name = "system" , help = "Available on Windows 10 or higher" },
|
||||
{ name = "never" }]
|
||||
|
||||
[[settings]]
|
||||
name = "dark-theme"
|
||||
file = "mpvnet"
|
||||
filter = "UI"
|
||||
url = "https://github.com/stax76/mpv.net/blob/master/Manual.md#color-theme"
|
||||
help = "Color theme used in dark mode. Default: dark"
|
||||
|
||||
[[settings]]
|
||||
name = "light-theme"
|
||||
file = "mpvnet"
|
||||
filter = "UI"
|
||||
url = "https://github.com/stax76/mpv.net/blob/master/Manual.md#color-theme"
|
||||
help = "Color theme used in light mode. Default: light"
|
||||
@@ -1,206 +0,0 @@
|
||||
|
||||
# This file defines the key and mouse bindings and the context menu of mpv.net.
|
||||
|
||||
# A convenient input and config editor can be found in the context menu of mpv.net
|
||||
# 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 it easier to do a text search, so if you want to know
|
||||
# if 'o' has already a binding you can do a text search on ' o '.
|
||||
|
||||
# input test mode:
|
||||
# mpvnet --input-test
|
||||
|
||||
# input key list:
|
||||
# mpv --input-keylist
|
||||
|
||||
# mpv.net input.conf defaults:
|
||||
# https://github.com/stax76/mpv.net/blob/master/mpv.net/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
|
||||
|
||||
o script-message mpv.net open-files #menu: Open > Open Files...
|
||||
u script-message mpv.net open-url #menu: Open > Open URL or file path from clipboard
|
||||
_ script-message mpv.net open-optical-media #menu: Open > Open DVD/Blu-ray Drive/Folder...
|
||||
_ ignore #menu: Open > -
|
||||
Alt+a script-message mpv.net load-audio #menu: Open > Load external audio files...
|
||||
Alt+s script-message mpv.net load-sub #menu: Open > Load external subtitle files...
|
||||
_ ignore #menu: Open > -
|
||||
_ script-message mpv.net open-files append #menu: Open > Add files to playlist...
|
||||
F3 script-message mpv.net show-media-search #menu: Open > Show media search...
|
||||
_ ignore #menu: Open > -
|
||||
_ ignore #menu: Open > Recent
|
||||
|
||||
_ ignore #menu: -
|
||||
Space cycle pause #menu: Play/Pause
|
||||
s stop #menu: Stop
|
||||
_ ignore #menu: -
|
||||
Enter cycle fullscreen #menu: Toggle Fullscreen
|
||||
|
||||
F11 playlist-prev #menu: Navigate > Previous File
|
||||
F12 playlist-next #menu: Navigate > Next File
|
||||
_ ignore #menu: Navigate > -
|
||||
Home script-message mpv.net playlist-first #menu: Navigate > First File
|
||||
End script-message mpv.net playlist-last #menu: Navigate > Last File
|
||||
_ ignore #menu: Navigate > -
|
||||
PGUP add chapter 1 #menu: Navigate > Next Chapter
|
||||
PGDWN add chapter -1 #menu: Navigate > Previous Chapter
|
||||
_ ignore #menu: Navigate > -
|
||||
. frame-step #menu: Navigate > Jump Next Frame
|
||||
, frame-back-step #menu: Navigate > Jump Previous Frame
|
||||
_ ignore #menu: Navigate > -
|
||||
Right seek 7 #menu: Navigate > Jump 7 sec forward
|
||||
Left seek -7 #menu: Navigate > Jump 7 sec backward
|
||||
_ ignore #menu: Navigate > -
|
||||
Up seek 40 #menu: Navigate > Jump 40 sec forward
|
||||
Down seek -40 #menu: Navigate > Jump 40 sec backward
|
||||
_ ignore #menu: Navigate > -
|
||||
Ctrl+Right seek 300 #menu: Navigate > Jump 5 min forward
|
||||
Ctrl+Left seek -300 #menu: Navigate > Jump 5 min backward
|
||||
_ ignore #menu: Navigate > -
|
||||
_ ignore #menu: Navigate > Chapters
|
||||
|
||||
Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size
|
||||
Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size
|
||||
_ ignore #menu: Pan & Scan > -
|
||||
Ctrl+KP4 add video-pan-x -0.01 #menu: Pan & Scan > Move Left
|
||||
Ctrl+KP6 add video-pan-x 0.01 #menu: Pan & Scan > Move Right
|
||||
_ ignore #menu: Pan & Scan > -
|
||||
Ctrl+KP8 add video-pan-y -0.01 #menu: Pan & Scan > Move Up
|
||||
Ctrl+KP2 add video-pan-y 0.01 #menu: Pan & Scan > Move Down
|
||||
_ ignore #menu: Pan & Scan > -
|
||||
w add panscan -0.1 #menu: Pan & Scan > Decrease Height
|
||||
W add panscan 0.1 #menu: Pan & Scan > Increase Height
|
||||
_ ignore #menu: Pan & Scan > -
|
||||
Ctrl+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0 #menu: Pan & Scan > Reset
|
||||
|
||||
Ctrl+1 add contrast -1 #menu: Video > Decrease Contrast
|
||||
Ctrl+2 add contrast 1 #menu: Video > Increase Contrast
|
||||
_ ignore #menu: Video > -
|
||||
Ctrl+3 add brightness -1 #menu: Video > Decrease Brightness
|
||||
Ctrl+4 add brightness 1 #menu: Video > Increase Brightness
|
||||
_ ignore #menu: Video > -
|
||||
Ctrl+5 add gamma -1 #menu: Video > Decrease Gamma
|
||||
Ctrl+6 add gamma 1 #menu: Video > Increase Gamma
|
||||
_ ignore #menu: Video > -
|
||||
Ctrl+7 add saturation -1 #menu: Video > Decrease Saturation
|
||||
Ctrl+8 add saturation 1 #menu: Video > Increase Saturation
|
||||
_ ignore #menu: Video > -
|
||||
Ctrl+s async screenshot #menu: Video > Take Screenshot
|
||||
d cycle deinterlace #menu: Video > Toggle Deinterlace
|
||||
a cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1" #menu: Video > Cycle Aspect Ratio
|
||||
|
||||
KP7 script-message mpv.net cycle-audio #menu: Audio > Cycle/Next
|
||||
_ ignore #menu: Audio > -
|
||||
KP6 add audio-delay 0.1 #menu: Audio > Delay +0.1
|
||||
KP9 add audio-delay -0.1 #menu: Audio > Delay -0.1
|
||||
|
||||
KP8 cycle sub #menu: Subtitle > Cycle/Next
|
||||
v cycle sub-visibility #menu: Subtitle > Toggle Visibility
|
||||
_ ignore #menu: Subtitle > -
|
||||
z add sub-delay -0.1 #menu: Subtitle > Delay -0.1
|
||||
Z add sub-delay 0.1 #menu: Subtitle > Delay +0.1
|
||||
_ ignore #menu: Subtitle > -
|
||||
r add sub-pos -1 #menu: Subtitle > Move Up
|
||||
R add sub-pos +1 #menu: Subtitle > Move Down
|
||||
_ ignore #menu: Subtitle > -
|
||||
_ add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size
|
||||
_ add sub-scale 0.1 #menu: Subtitle > Increase Subtitle Font Size
|
||||
|
||||
_ ignore #menu: Track
|
||||
|
||||
+ add volume 10 #menu: Volume > Up
|
||||
- add volume -10 #menu: Volume > Down
|
||||
_ ignore #menu: Volume > -
|
||||
m cycle mute #menu: Volume > Mute
|
||||
|
||||
[ multiply speed 1/1.1 #menu: Speed > -10%
|
||||
] multiply speed 1.1 #menu: Speed > +10%
|
||||
_ ignore #menu: Speed > -
|
||||
{ multiply speed 0.5 #menu: Speed > Half
|
||||
} multiply speed 2.0 #menu: Speed > Double
|
||||
_ ignore #menu: Speed > -
|
||||
BS set speed 1 #menu: Speed > Reset
|
||||
|
||||
KP0 script-message rate-file 0 #menu: Extensions > Rating > 0stars
|
||||
KP1 script-message rate-file 1 #menu: Extensions > Rating > 1stars
|
||||
KP2 script-message rate-file 2 #menu: Extensions > Rating > 2stars
|
||||
KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
|
||||
KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
|
||||
KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
|
||||
_ ignore #menu: Extensions > Rating > -
|
||||
_ script-message rate-file about #menu: Extensions > Rating > About
|
||||
|
||||
Ctrl+t set ontop yes #menu: View > On Top > Enable
|
||||
Ctrl+T set ontop no #menu: View > On Top > Disable
|
||||
Alt++ no-osd set window-scale 1.2 #menu: View > Window Size > Enlarge
|
||||
Alt+- no-osd set window-scale 0.8 #menu: View > Window Size > Shrink
|
||||
b cycle border #menu: View > Toggle Border
|
||||
i script-message mpv.net show-info #menu: View > File/Stream Info
|
||||
t script-binding stats/display-stats #menu: View > Show Statistics
|
||||
T script-binding stats/display-stats-toggle #menu: View > Toggle Statistics
|
||||
Del script-binding osc/visibility #menu: View > Toggle OSC Visibility
|
||||
F8 script-binding show-playlist #menu: View > Show Playlist
|
||||
F9 show-text ${track-list} 5000 #menu: View > Show Audio/Video/Subtitle List
|
||||
p show-progress #menu: View > Show Progress
|
||||
Ctrl+p script-message mpv.net show-profiles #menu: View > Show Profiles
|
||||
Shift+p script-message mpv.net show-properties #menu: View > Show Properties
|
||||
Shift+c script-message mpv.net show-commands #menu: View > Show Commands
|
||||
` script-binding console/enable #menu: View > Show Console
|
||||
|
||||
c script-message mpv.net show-conf-editor #menu: Settings > Show Config Editor
|
||||
Ctrl+i script-message mpv.net show-input-editor #menu: Settings > Show Input Editor
|
||||
Ctrl+f script-message mpv.net open-conf-folder #menu: Settings > Open Config Folder
|
||||
|
||||
F1 script-message mpv.net show-command-palette #menu: Tools > Show All Commands
|
||||
h script-message mpv.net show-history #menu: Tools > Show History
|
||||
l ab-loop #menu: Tools > Set/clear A-B loop points
|
||||
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping
|
||||
_ cycle shuffle #menu: Tools > Toggle Shuffle
|
||||
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Toggle Hardware Decoding
|
||||
_ script-message mpv.net show-setup-dialog #menu: Tools > Setup...
|
||||
|
||||
_ script-message mpv.net shell-execute https://mpv.io #menu: Help > Website mpv
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net #menu: Help > Website mpv.net
|
||||
_ ignore #menu: Help > -
|
||||
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Manual mpv
|
||||
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/Manual.md #menu: Help > Manual mpv.net
|
||||
_ ignore #menu: Help > -
|
||||
_ script-message mpv.net update-check #menu: Help > Check for Updates
|
||||
_ script-message mpv.net show-about #menu: Help > About mpv.net
|
||||
|
||||
_ ignore #menu: -
|
||||
Esc quit #menu: Exit
|
||||
Q quit-watch-later #menu: Exit Watch Later
|
||||
|
||||
Power quit
|
||||
Play cycle pause
|
||||
Pause cycle pause
|
||||
PlayPause cycle pause
|
||||
MBTN_Mid cycle pause
|
||||
Stop stop
|
||||
Forward seek 60
|
||||
Rewind seek -60
|
||||
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
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
input-default-bindings = no
|
||||
input-ar-delay = 500
|
||||
input-ar-rate = 20
|
||||
keep-open = yes
|
||||
keep-open-pause = no
|
||||
osd-duration = 2000
|
||||
osd-playing-msg = '${filename}'
|
||||
script-opts = osc-scalewindowed=1.5,osc-hidetimeout=2000,console-scale=1
|
||||
screenshot-directory = '~~desktop/'
|
||||
hwdec = yes
|
||||
|
||||
[protocol.https]
|
||||
osd-playing-msg = '${media-title}'
|
||||
@@ -1,67 +0,0 @@
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if ($args.Length -ne 2) {
|
||||
Write-Host 'Invalid arguments' -ForegroundColor Red
|
||||
exit
|
||||
}
|
||||
|
||||
if (-not (Get-Command curl.exe)) {
|
||||
Write-Host 'Error using curl.exe' -ForegroundColor Red
|
||||
exit
|
||||
}
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -lt 5) {
|
||||
Write-Host 'PowerShell 5.1 not found' -ForegroundColor Red
|
||||
exit
|
||||
}
|
||||
|
||||
Add-Type -AssemblyName Microsoft.VisualBasic
|
||||
|
||||
# Delete directory using recycle bin
|
||||
function Remove-Directory($directory) {
|
||||
if (Test-Path $directory) {
|
||||
[Microsoft.VisualBasic.FileIO.FileSystem]::
|
||||
DeleteDirectory($directory, 'OnlyErrorDialogs', 'SendToRecycleBin')
|
||||
}
|
||||
}
|
||||
|
||||
$currentDir = $args[1];
|
||||
|
||||
$targetDir = (Split-Path $currentDir) + "\new version"
|
||||
Remove-Directory $targetDir
|
||||
$targetFile = $targetDir + '.7z'
|
||||
Remove-Item $targetFile -Force -ErrorAction Ignore
|
||||
|
||||
Write-Host 'Download new version' -ForegroundColor Green
|
||||
curl.exe $args[0] --location --output $targetFile
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
Write-Host 'Unpack new version' -ForegroundColor Green
|
||||
& ($currentDir + '\7z\7za.exe') x -y $targetFile -o"$targetDir"
|
||||
if ($LastExitCode) { throw $LastExitCode }
|
||||
|
||||
Write-Host 'Delete downloaded file' -ForegroundColor Green
|
||||
Remove-Item $targetFile -Force -Recurse
|
||||
|
||||
$portableConfigDir = $currentDir + '\portable_config'
|
||||
$portableConfigTempDir = (Split-Path $currentDir) + '\portable config dir temp'
|
||||
Remove-Item $portableConfigTempDir -Force -ErrorAction Ignore
|
||||
|
||||
if (Test-Path $portableConfigDir) {
|
||||
Write-Host 'Backup portable config' -ForegroundColor Green
|
||||
Copy-Item $portableConfigDir $portableConfigTempDir -Recurse -Force
|
||||
}
|
||||
|
||||
Write-Host 'Delete current version' -ForegroundColor Green
|
||||
Remove-Directory $currentDir
|
||||
|
||||
Write-Host 'Rename directory' -ForegroundColor Green
|
||||
Rename-Item $targetDir (Split-Path $currentDir -Leaf)
|
||||
|
||||
if (Test-Path $portableConfigTempDir) {
|
||||
Write-Host 'Restore portable config' -ForegroundColor Green
|
||||
Move-Item $portableConfigTempDir $portableConfigDir -Force
|
||||
}
|
||||
|
||||
Write-Host 'Update is complete' -ForegroundColor Green
|
||||
@@ -1,28 +0,0 @@
|
||||
<Window x:Class="mpvnet.AboutWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="About mpv.net"
|
||||
Height="230"
|
||||
Width="400"
|
||||
FontSize="16"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ResizeMode="NoResize"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}">
|
||||
|
||||
<Grid>
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock FontSize="48" HorizontalAlignment="Center" Margin="0,0,0,10">mpv.net</TextBlock>
|
||||
<TextBlock HorizontalAlignment="Center">Copyright (C) 2017-2020 Frank Skare (stax76)</TextBlock>
|
||||
<TextBlock Name="Version" HorizontalAlignment="Center" />
|
||||
<TextBlock Name="mpvVersion" HorizontalAlignment="Center" />
|
||||
<TextBlock HorizontalAlignment="Center" Margin="0,0,0,20">MIT License</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public partial class AboutWindow : Window
|
||||
{
|
||||
public AboutWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Version.Text = $"mpv.net Version {System.Windows.Forms.Application.ProductVersion} ({File.GetLastWriteTime(System.Windows.Forms.Application.ExecutablePath).ToShortDateString()})";
|
||||
mpvVersion.Text = $"{core.get_property_string("mpv-version")} ({File.GetLastWriteTime(Folder.Startup + "mpv-1.dll").ToShortDateString()})";
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e) => Close();
|
||||
protected override void OnMouseDown(MouseButtonEventArgs e) => Close();
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<Window x:Class="mpvnet.CommandPaletteWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="Command Palette"
|
||||
Height="295"
|
||||
Width="400"
|
||||
FontSize="13"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Loaded="Window_Loaded">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox Name="FilterTextBox"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
PreviewKeyDown="FilterTextBox_PreviewKeyDown"
|
||||
TextChanged="FilterTextBox_TextChanged"/>
|
||||
|
||||
<ListView Name="ListView"
|
||||
Grid.Row="1"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
MouseUp="ListView_MouseUp">
|
||||
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="{Binding Path}"></TextBlock>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding Input}"
|
||||
HorizontalAlignment="Right"></TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,126 +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.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public partial class CommandPaletteWindow : Window
|
||||
{
|
||||
ICollectionView CollectionView;
|
||||
|
||||
public CommandPaletteWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
CollectionViewSource collectionViewSource = new CollectionViewSource() { Source = CommandItem.Items };
|
||||
CollectionView = collectionViewSource.View;
|
||||
var yourCostumFilter = new Predicate<object>(item => Filter((CommandItem)item));
|
||||
CollectionView.Filter = yourCostumFilter;
|
||||
ListView.ItemsSource = CollectionView;
|
||||
}
|
||||
|
||||
bool Filter(CommandItem item)
|
||||
{
|
||||
if (item.Command == "" || item.Path == "")
|
||||
return false;
|
||||
|
||||
string filter = FilterTextBox.Text.ToLower();
|
||||
|
||||
if (filter == "")
|
||||
return true;
|
||||
|
||||
if (item.Command.ToLower().Contains(filter) ||
|
||||
item.Input.ToLower().Contains(filter) ||
|
||||
item.Path.ToLower().Contains(filter))
|
||||
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
|
||||
source.AddHook(new HwndSourceHook(WndProc));
|
||||
Keyboard.Focus(FilterTextBox);
|
||||
SelectFirst();
|
||||
}
|
||||
|
||||
void SelectFirst()
|
||||
{
|
||||
if (ListView.Items.Count > 0)
|
||||
ListView.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||
{
|
||||
if (msg == 0x200 /*WM_MOUSEMOVE*/ && Mouse.LeftButton != MouseButtonState.Pressed)
|
||||
handled = true;
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
void FilterTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Up:
|
||||
{
|
||||
int index = ListView.SelectedIndex;
|
||||
index -= 1;
|
||||
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
ListView.SelectedIndex = index;
|
||||
ListView.ScrollIntoView(ListView.SelectedItem);
|
||||
}
|
||||
break;
|
||||
case Key.Down:
|
||||
{
|
||||
int index = ListView.SelectedIndex;
|
||||
index += 1;
|
||||
|
||||
if (index > ListView.Items.Count - 1)
|
||||
index = ListView.Items.Count - 1;
|
||||
|
||||
ListView.SelectedIndex = index;
|
||||
ListView.ScrollIntoView(ListView.SelectedItem);
|
||||
}
|
||||
break;
|
||||
case Key.Escape:
|
||||
Close();
|
||||
break;
|
||||
case Key.Enter:
|
||||
Execute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Execute()
|
||||
{
|
||||
if (ListView.SelectedItem != null)
|
||||
{
|
||||
CommandItem item = ListView.SelectedItem as CommandItem;
|
||||
Close();
|
||||
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,66 +0,0 @@
|
||||
<Window xmlns:Controls="clr-namespace:Controls" x:Name="ConfWindow1" x:Class="mpvnet.ConfWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="Config Editor"
|
||||
Height="530"
|
||||
Width="700"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Loaded="ConfWindow1_Loaded">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Controls:SearchTextBoxUserControl
|
||||
x:Name="SearchControl"
|
||||
HintText="Find a setting"
|
||||
Width="250"
|
||||
Margin="0,20,0,0"
|
||||
Grid.ColumnSpan="2"/>
|
||||
|
||||
<ScrollViewer Name="MainScrollViewer"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="0,0,0,10">
|
||||
|
||||
<StackPanel x:Name="MainStackPanel"></StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<StackPanel Margin="20,0,0,0" Grid.Row="1">
|
||||
<ListBox Name="FilterListBox"
|
||||
ItemsSource="{Binding FilterStrings}"
|
||||
BorderThickness="0"
|
||||
SelectionChanged="FilterListBox_SelectionChanged"
|
||||
Foreground="{x:Static mpvnet:Theme.Heading}"
|
||||
Background="{x:Static mpvnet:Theme.Background}">
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" FontSize="16" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<TextBlock Name="OpenSettingsTextBlock" Margin="0,30,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static mpvnet:Theme.Heading}" MouseUp="OpenSettingsTextBlock_MouseUp">Open config folder</TextBlock>
|
||||
<TextBlock Name="PreviewTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static mpvnet:Theme.Heading}" MouseUp="PreviewTextBlock_MouseUp">Preview mpv.conf</TextBlock>
|
||||
<TextBlock Name="ShowManualTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static mpvnet:Theme.Heading}" MouseUp="ShowManualTextBlock_MouseUp">Show mpv manual</TextBlock>
|
||||
<TextBlock Name="SupportTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static mpvnet:Theme.Heading}" MouseUp="SupportTextBlock_MouseUp">Show support forum</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,44 +0,0 @@
|
||||
<Window x:Class="mpvnet.EverythingWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="Media File Search"
|
||||
FontSize="13"
|
||||
Height="300"
|
||||
Width="600"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Loaded="Window_Loaded">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox Name="FilterTextBox"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
PreviewKeyDown="FilterTextBox_PreviewKeyDown"
|
||||
TextChanged="FilterTextBox_TextChanged"/>
|
||||
|
||||
<ListView Name="ListView"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet: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,164 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public partial class EverythingWindow : Window
|
||||
{
|
||||
public EverythingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
const int EVERYTHING_REQUEST_FILE_NAME = 0x00000001;
|
||||
const int EVERYTHING_REQUEST_PATH = 0x00000002;
|
||||
|
||||
[DllImport("Everything.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int Everything_SetSearch(string lpSearchString);
|
||||
|
||||
[DllImport("Everything.dll")]
|
||||
public static extern void Everything_SetRequestFlags(UInt32 dwRequestFlags);
|
||||
|
||||
[DllImport("Everything.dll")]
|
||||
public static extern void Everything_SetSort(UInt32 dwSortType);
|
||||
|
||||
[DllImport("Everything.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern bool Everything_Query(bool bWait);
|
||||
|
||||
[DllImport("Everything.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern void Everything_GetResultFullPathName(UInt32 nIndex, StringBuilder lpString, UInt32 nMaxCount);
|
||||
|
||||
[DllImport("Everything.dll")]
|
||||
public static extern bool Everything_GetResultSize(UInt32 nIndex, out long lpFileSize);
|
||||
|
||||
[DllImport("Everything.dll")]
|
||||
public static extern UInt32 Everything_GetNumResults();
|
||||
|
||||
void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
|
||||
source.AddHook(new HwndSourceHook(WndProc));
|
||||
Keyboard.Focus(FilterTextBox);
|
||||
}
|
||||
|
||||
void SelectFirst()
|
||||
{
|
||||
if (ListView.Items.Count > 0)
|
||||
ListView.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||
{
|
||||
if (msg == 0x200 /*WM_MOUSEMOVE*/ && Mouse.LeftButton != MouseButtonState.Pressed)
|
||||
handled = true;
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
void FilterTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Up:
|
||||
{
|
||||
int index = ListView.SelectedIndex;
|
||||
index -= 1;
|
||||
if (index < 0) index = 0;
|
||||
ListView.SelectedIndex = index;
|
||||
ListView.ScrollIntoView(ListView.SelectedItem);
|
||||
}
|
||||
break;
|
||||
case Key.Down:
|
||||
{
|
||||
int index = ListView.SelectedIndex;
|
||||
index += 1;
|
||||
if (index > ListView.Items.Count - 1) index = ListView.Items.Count - 1;
|
||||
ListView.SelectedIndex = index;
|
||||
ListView.ScrollIntoView(ListView.SelectedItem);
|
||||
}
|
||||
break;
|
||||
case Key.Escape: Close(); break;
|
||||
case Key.Enter: Execute(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void ListView_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Escape)
|
||||
Close();
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
Execute();
|
||||
}
|
||||
|
||||
void Execute()
|
||||
{
|
||||
if (ListView.SelectedItem != null)
|
||||
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;
|
||||
Task.Run(() => Search(searchtext));
|
||||
}
|
||||
|
||||
object LockObject = new object();
|
||||
|
||||
void Search(string searchtext)
|
||||
{
|
||||
lock (LockObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> items = new List<string>();
|
||||
UInt32 i;
|
||||
const int bufsize = 500;
|
||||
StringBuilder buf = new StringBuilder(bufsize);
|
||||
Everything_SetSearch(searchtext);
|
||||
Everything_SetRequestFlags(EVERYTHING_REQUEST_FILE_NAME | EVERYTHING_REQUEST_PATH);
|
||||
Everything_Query(true);
|
||||
|
||||
for (i = 0; i < Everything_GetNumResults(); i++)
|
||||
{
|
||||
Everything_GetResultFullPathName(i, buf, bufsize);
|
||||
string ext = buf.ToString().ShortExt();
|
||||
|
||||
if (App.AudioTypes.Contains(ext) || App.VideoTypes.Contains(ext)
|
||||
|| App.ImageTypes.Contains(ext))
|
||||
|
||||
items.Add(buf.ToString());
|
||||
|
||||
if (items.Count > 100)
|
||||
break;
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => {
|
||||
ListView.ItemsSource = items;
|
||||
SelectFirst();
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Msg.ShowError("Search query failed.",
|
||||
"The search feature depends on [Everything](https://www.voidtools.com) being installed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
<Window xmlns:Controls="clr-namespace:Controls" x:Class="mpvnet.InputWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="Input Editor"
|
||||
Height="500"
|
||||
Width="750"
|
||||
FontSize="13"
|
||||
ShowInTaskbar="False"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
Loaded="Window_Loaded"
|
||||
Closed="Window_Closed">
|
||||
|
||||
<Window.Resources>
|
||||
<Style x:Key="DataGrid_Font_Centering" TargetType="{x:Type DataGridCell}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type DataGridCell}">
|
||||
<Grid Background="{TemplateBinding Background}">
|
||||
<ContentPresenter VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Controls:SearchTextBoxUserControl
|
||||
HintText="Type ? to get help."
|
||||
x:Name="SearchControl"
|
||||
Width="300"
|
||||
Margin="0,20,0,20"
|
||||
Grid.ColumnSpan="2" />
|
||||
|
||||
<DataGrid x:Name="DataGrid"
|
||||
Grid.Row="1"
|
||||
CommandManager.PreviewCanExecute="DataGrid_PreviewCanExecute"
|
||||
AutoGenerateColumns="False"
|
||||
CellStyle="{StaticResource DataGrid_Font_Centering}" >
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Menu" Binding="{Binding Path}"/>
|
||||
|
||||
<DataGridTemplateColumn Header="Input">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button MinHeight="20" Click="ButtonClick">
|
||||
<TextBlock Text="{Binding Input}"></TextBlock>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<DataGridTextColumn Header="Command" Binding="{Binding Command}" MaxWidth="330" />
|
||||
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,49 +0,0 @@
|
||||
<Window x:Class="mpvnet.LearnWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="Learn Input"
|
||||
Height="200"
|
||||
Width="400"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ResizeMode="NoResize"
|
||||
Loaded="Window_Loaded"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
MouseWheel="Window_MouseWheel"
|
||||
MouseUp="Window_MouseUp"
|
||||
MouseDoubleClick="Window_MouseDoubleClick" PreviewKeyDown="Window_PreviewKeyDown">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="40" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock x:Name="MenuTextBlock"
|
||||
Grid.ColumnSpan="2"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="16"></TextBlock>
|
||||
|
||||
<TextBlock x:Name="KeyTextBlock"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="2"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="16" />
|
||||
|
||||
<Button x:Name="ConfirmButton" Grid.Row="2" Click="ConfirmButton_Click">Confirm</Button>
|
||||
<Button x:Name="ClearButton" Grid.Row="2" Click="ClearButton_Click" Grid.Column="1">Clear</Button>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,120 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet">
|
||||
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TextBox}">
|
||||
<Border x:Name="border"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"
|
||||
SnapsToDevicePixels="True">
|
||||
|
||||
<ScrollViewer x:Name="PART_ContentHost"
|
||||
Focusable="false"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Hidden"/>
|
||||
</Border>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsFocused" Value="true">
|
||||
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static mpvnet:Theme.Heading}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style TargetType="RadioButton">
|
||||
<Setter Property="Padding" Value="6 0 0 0" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RadioButton">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="LeftCol" Width="18" />
|
||||
<ColumnDefinition x:Name="RightCol" Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid x:Name="PART_CHECKBOX">
|
||||
<Ellipse
|
||||
x:Name="normal"
|
||||
Width="18"
|
||||
Height="18"
|
||||
Fill="{x:Static mpvnet:Theme.Background}"
|
||||
Stroke="{x:Static mpvnet:Theme.Heading}"
|
||||
StrokeThickness="2" />
|
||||
<Ellipse
|
||||
x:Name="Checked1"
|
||||
Width="8"
|
||||
Height="8"
|
||||
Fill="{TemplateBinding Foreground}"
|
||||
Opacity="0" />
|
||||
<Ellipse
|
||||
x:Name="disabled"
|
||||
Width="18"
|
||||
Height="18"
|
||||
Fill="{DynamicResource SemiTransparentWhiteBrush}"
|
||||
Opacity="0"
|
||||
StrokeThickness="{TemplateBinding BorderThickness}" />
|
||||
</Grid>
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="contentPresenter"
|
||||
Grid.Column="1"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentStringFormat="{TemplateBinding ContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
|
||||
RecognizesAccessKey="True" />
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="contentPresenter"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
To=".55"
|
||||
Duration="0" />
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="disabled"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
To="1"
|
||||
Duration="0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="CheckStates">
|
||||
<VisualState x:Name="Checked">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="Checked1"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
To="1"
|
||||
Duration="0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Unchecked" />
|
||||
<VisualState x:Name="Indeterminate" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,68 +0,0 @@
|
||||
<UserControl x:Class="Controls.SearchTextBoxUserControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800">
|
||||
|
||||
<Grid Name="SearchTextBoxUserControl1"
|
||||
Background="{x:Static mpvnet:Theme.Background}">
|
||||
|
||||
<TextBlock Name="HintTextBlock"
|
||||
Margin="5,2"
|
||||
Text="Find a setting"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground2}"
|
||||
Background="{x:Static mpvnet:Theme.Background}" />
|
||||
|
||||
<TextBox Name="SearchTextBox"
|
||||
Height="25"
|
||||
Padding="1,2,0,0"
|
||||
BorderThickness="2"
|
||||
Background="Transparent"
|
||||
TextChanged="SearchTextBox_TextChanged"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
CaretBrush="{x:Static mpvnet:Theme.Foreground}" />
|
||||
|
||||
<Button Name="SearchClearButton"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right"
|
||||
FontFamily="Marlett"
|
||||
FontSize="10"
|
||||
Width="17"
|
||||
Height="17"
|
||||
Margin="2,0,4,0"
|
||||
Visibility="Hidden"
|
||||
Click="SearchClearButton_Click" >r
|
||||
|
||||
<Button.Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="{x:Static mpvnet:Theme.Background}"/>
|
||||
<Setter Property="Foreground" Value="{x:Static mpvnet:Theme.Foreground2}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border BorderThickness="1"
|
||||
BorderBrush="{TemplateBinding Foreground}"
|
||||
SnapsToDevicePixels="True">
|
||||
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Foreground" Value="{x:Static mpvnet:Theme.Heading}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,33 +0,0 @@
|
||||
<Window x:Class="mpvnet.SetupWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mpvnet="clr-namespace:mpvnet"
|
||||
mc:Ignorable="d"
|
||||
|
||||
Title="mpv.net Setup"
|
||||
FontSize="13"
|
||||
Foreground="{x:Static mpvnet:Theme.Foreground}"
|
||||
Background="{x:Static mpvnet:Theme.Background}"
|
||||
SizeToContent="WidthAndHeight"
|
||||
WindowStartupLocation="CenterOwner" >
|
||||
|
||||
<Window.Resources>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Padding" Value="10"></Setter>
|
||||
<Setter Property="Margin" Value="5"></Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<StackPanel Margin="10">
|
||||
<Button Name="RegisterVideo" Click="RegisterVideo_Click">Register video file extensions (requires admin rights)</Button>
|
||||
<Button Name="RegisterAudio" Click="RegisterAudio_Click">Register audio file extensions (requires admin rights)</Button>
|
||||
<Button Name="RegisterImage" Click="RegisterImage_Click">Register image file extensions (requires admin rights)</Button>
|
||||
<Button Name="UnregisterFileAssociations" Click="UnregisterFileAssociations_Click">Unregister file extensions (requires admin rights)</Button>
|
||||
<Button Name="AddToPathEnvVar" Click="AddToPathEnvVar_Click">Add mpv.net to Path environment variable</Button>
|
||||
<Button Name="RemoveFromPathEnvVar" Click="RemoveFromPathEnvVar_Click">Remove mpv.net from Path environment variable</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,64 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
|
||||
using WinForms = System.Windows.Forms;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public partial class SetupWindow : Window
|
||||
{
|
||||
public SetupWindow() => InitializeComponent();
|
||||
|
||||
void RegisterFileAssociations(string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (Process proc = new Process())
|
||||
{
|
||||
proc.StartInfo.FileName = WinForms.Application.ExecutablePath;
|
||||
proc.StartInfo.Arguments = "--reg-file-assoc " + value;
|
||||
proc.StartInfo.Verb = "runas";
|
||||
proc.Start();
|
||||
}
|
||||
|
||||
Process.Start("ms-settings:defaultapps");
|
||||
} catch {}
|
||||
}
|
||||
|
||||
void RegisterVideo_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("video");
|
||||
void RegisterAudio_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("audio");
|
||||
void RegisterImage_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("image");
|
||||
|
||||
void UnregisterFileAssociations_Click(object sender, RoutedEventArgs e) => RegisterFileAssociations("unreg");
|
||||
|
||||
void AddToPathEnvVar_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string var = WinForms.Application.StartupPath + ";";
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
|
||||
|
||||
if (path.Contains(var))
|
||||
Msg.ShowWarning("Path was already containing mpv.net.");
|
||||
else
|
||||
{
|
||||
Environment.SetEnvironmentVariable("Path", var + path, EnvironmentVariableTarget.User);
|
||||
Msg.Show("mpv.net was successfully added to Path.", (var + path).Replace(";","\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveFromPathEnvVar_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string var = WinForms.Application.StartupPath + ";";
|
||||
string path = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.User);
|
||||
|
||||
if (path.Contains(var))
|
||||
{
|
||||
Environment.SetEnvironmentVariable("Path", path.Replace(var, ""), EnvironmentVariableTarget.User);
|
||||
Msg.Show("mpv.net was successfully removed from Path.");
|
||||
}
|
||||
else
|
||||
Msg.ShowWarning("Path was not containing mpv.net.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,876 +0,0 @@
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using static mpvnet.Core;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
public static MainForm Instance { get; set; }
|
||||
public static IntPtr Hwnd { get; set; }
|
||||
public new ContextMenuStripEx ContextMenu { get; set; }
|
||||
Point LastCursorPosition;
|
||||
int LastCursorChanged;
|
||||
int LastCycleFullscreen;
|
||||
int LastAppCommand;
|
||||
int TaskbarButtonCreatedMessage;
|
||||
int ShownTickCount;
|
||||
|
||||
Taskbar Taskbar;
|
||||
List<string> RecentFiles;
|
||||
bool WasMaximized;
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
try
|
||||
{
|
||||
object recent = RegistryHelp.GetValue(App.RegPath, "Recent");
|
||||
|
||||
if (recent is string[] r)
|
||||
RecentFiles = new List<string>(r);
|
||||
else
|
||||
RecentFiles = new List<string>();
|
||||
|
||||
Instance = this;
|
||||
Hwnd = Handle;
|
||||
ConsoleHelp.Padding = 60;
|
||||
core.Init();
|
||||
|
||||
core.Shutdown += Shutdown;
|
||||
core.VideoSizeChanged += VideoSizeChanged;
|
||||
core.FileLoaded += FileLoaded;
|
||||
core.Idle += Idle;
|
||||
core.Seek += () => UpdateProgressBar();
|
||||
|
||||
core.observe_property("window-maximized", PropChangeWindowMaximized);
|
||||
core.observe_property("window-minimized", PropChangeWindowMinimized);
|
||||
core.observe_property_bool("pause", PropChangePause);
|
||||
core.observe_property_bool("fullscreen", PropChangeFullscreen);
|
||||
core.observe_property_bool("ontop", PropChangeOnTop);
|
||||
core.observe_property_bool("border", PropChangeBorder);
|
||||
|
||||
core.observe_property_string("sid", PropChangeSid);
|
||||
core.observe_property_string("aid", PropChangeAid);
|
||||
core.observe_property_string("vid", PropChangeVid);
|
||||
|
||||
core.observe_property_int("edition", PropChangeEdition);
|
||||
core.observe_property_double("window-scale", PropChangeWindowScale);
|
||||
|
||||
if (core.GPUAPI != "vulkan")
|
||||
core.ProcessCommandLine(false);
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, e) => App.ShowException(e.ExceptionObject);
|
||||
Application.ThreadException += (sender, e) => App.ShowException(e.Exception);
|
||||
Msg.SupportURL = "https://github.com/stax76/mpv.net#support";
|
||||
Text = "mpv.net " + Application.ProductVersion;
|
||||
TaskbarButtonCreatedMessage = WinAPI.RegisterWindowMessage("TaskbarButtonCreated");
|
||||
|
||||
ContextMenu = new ContextMenuStripEx(components);
|
||||
ContextMenu.Opened += ContextMenu_Opened;
|
||||
ContextMenu.Opening += ContextMenu_Opening;
|
||||
|
||||
if (core.Screen == -1)
|
||||
core.Screen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
|
||||
|
||||
int targetIndex = core.Screen;
|
||||
Screen[] screens = Screen.AllScreens;
|
||||
|
||||
if (targetIndex < 0)
|
||||
targetIndex = 0;
|
||||
|
||||
if (targetIndex > screens.Length - 1)
|
||||
targetIndex = screens.Length - 1;
|
||||
|
||||
Screen screen = screens[Array.IndexOf(screens, screens[targetIndex])];
|
||||
Rectangle target = screen.Bounds;
|
||||
Left = target.X + (target.Width - Width) / 2;
|
||||
Top = target.Y + (target.Height - Height) / 2;
|
||||
|
||||
if (!core.Border)
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
|
||||
int posX = RegistryHelp.GetInt(App.RegPath, "PosX");
|
||||
int posY = RegistryHelp.GetInt(App.RegPath, "PosY");
|
||||
|
||||
if (posX != 0 && posY != 0 && App.RememberPosition)
|
||||
{
|
||||
Left = posX - Width / 2;
|
||||
Top = posY - Height / 2;
|
||||
}
|
||||
|
||||
if (core.WindowMaximized)
|
||||
{
|
||||
SetFormPosAndSize(1, true);
|
||||
WindowState = FormWindowState.Maximized;
|
||||
}
|
||||
|
||||
if (core.WindowMinimized)
|
||||
{
|
||||
SetFormPosAndSize(1, true);
|
||||
WindowState = FormWindowState.Minimized;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Msg.ShowException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public MenuItem FindMenuItem(string text) => FindMenuItem(text, ContextMenu.Items);
|
||||
|
||||
void Shutdown() => BeginInvoke(new Action(() => Close()));
|
||||
|
||||
void Idle()
|
||||
{
|
||||
BeginInvoke(new Action(() => Text = "mpv.net " + Application.ProductVersion));
|
||||
}
|
||||
|
||||
bool WasShown() => ShownTickCount != 0 && Environment.TickCount > ShownTickCount + 500;
|
||||
|
||||
void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
|
||||
|
||||
void VideoSizeChanged() => BeginInvoke(new Action(() => SetFormPosAndSize()));
|
||||
|
||||
void PropChangeFullscreen(bool value) => BeginInvoke(new Action(() => CycleFullscreen(value)));
|
||||
|
||||
void ContextMenu_Opened(object sender, EventArgs e) => CursorHelp.Show();
|
||||
|
||||
bool IsFullscreen => WindowState == FormWindowState.Maximized && FormBorderStyle == FormBorderStyle.None;
|
||||
|
||||
bool IsMouseInOSC()
|
||||
{
|
||||
Point pos = PointToClient(Control.MousePosition);
|
||||
float top = 0;
|
||||
|
||||
if (FormBorderStyle == FormBorderStyle.None)
|
||||
top = ClientSize.Height * 0.1f;
|
||||
|
||||
return pos.Y > ClientSize.Height * 0.85 || pos.Y < top;
|
||||
}
|
||||
|
||||
void ContextMenu_Opening(object sender, CancelEventArgs e)
|
||||
{
|
||||
lock (core.MediaTracks)
|
||||
{
|
||||
MenuItem trackMenuItem = FindMenuItem("Track");
|
||||
|
||||
if (trackMenuItem != null)
|
||||
{
|
||||
trackMenuItem.DropDownItems.Clear();
|
||||
|
||||
MediaTrack[] audTracks = core.MediaTracks.Where(track => track.Type == "a").ToArray();
|
||||
MediaTrack[] subTracks = core.MediaTracks.Where(track => track.Type == "s").ToArray();
|
||||
MediaTrack[] vidTracks = core.MediaTracks.Where(track => track.Type == "v").ToArray();
|
||||
MediaTrack[] ediTracks = core.MediaTracks.Where(track => track.Type == "e").ToArray();
|
||||
|
||||
foreach (MediaTrack track in vidTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => core.commandv("set", "vid", track.ID.ToString());
|
||||
mi.Checked = core.Vid == track.ID.ToString();
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
|
||||
if (vidTracks.Length > 0)
|
||||
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
|
||||
|
||||
foreach (MediaTrack track in audTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => core.commandv("set", "aid", track.ID.ToString());
|
||||
mi.Checked = core.Aid == track.ID.ToString();
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
|
||||
if (subTracks.Length > 0)
|
||||
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
|
||||
|
||||
foreach (MediaTrack track in subTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => core.commandv("set", "sid", track.ID.ToString());
|
||||
mi.Checked = core.Sid == track.ID.ToString();
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
|
||||
if (subTracks.Length > 0)
|
||||
{
|
||||
MenuItem mi = new MenuItem("S: No subtitles");
|
||||
mi.Action = () => core.commandv("set", "sid", "no");
|
||||
mi.Checked = core.Sid == "no";
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
|
||||
if (ediTracks.Length > 0)
|
||||
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
|
||||
|
||||
foreach (MediaTrack track in ediTracks)
|
||||
{
|
||||
MenuItem mi = new MenuItem(track.Text);
|
||||
mi.Action = () => core.commandv("set", "edition", track.ID.ToString());
|
||||
mi.Checked = core.Edition == track.ID;
|
||||
trackMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lock (core.Chapters)
|
||||
{
|
||||
MenuItem chaptersMenuItem = FindMenuItem("Chapters");
|
||||
|
||||
if (chaptersMenuItem != null)
|
||||
{
|
||||
chaptersMenuItem.DropDownItems.Clear();
|
||||
|
||||
foreach (var i in core.Chapters)
|
||||
{
|
||||
MenuItem mi = new MenuItem(i.Key);
|
||||
mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " ";
|
||||
mi.Action = () => core.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute");
|
||||
chaptersMenuItem.DropDownItems.Add(mi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem recent = FindMenuItem("Recent");
|
||||
|
||||
if (recent != null)
|
||||
{
|
||||
recent.DropDownItems.Clear();
|
||||
|
||||
foreach (string path in RecentFiles)
|
||||
MenuItem.Add(recent.DropDownItems, path, () => core.LoadFiles(new[] { path }, true, Control.ModifierKeys.HasFlag(Keys.Control)));
|
||||
|
||||
recent.DropDownItems.Add(new ToolStripSeparator());
|
||||
MenuItem mi = new MenuItem("Clear List");
|
||||
mi.Action = () => RecentFiles.Clear();
|
||||
recent.DropDownItems.Add(mi);
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem FindMenuItem(string text, ToolStripItemCollection items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item is MenuItem mi)
|
||||
{
|
||||
if (mi.Text.StartsWith(text) && mi.Text.Trim() == text)
|
||||
return mi;
|
||||
|
||||
if (mi.DropDownItems.Count > 0)
|
||||
{
|
||||
MenuItem val = FindMenuItem(text, mi.DropDownItems);
|
||||
if (val != null) return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void SetFormPosAndSize(double scale = 1, bool force = false)
|
||||
{
|
||||
if (!force)
|
||||
{
|
||||
if (WindowState != FormWindowState.Normal)
|
||||
return;
|
||||
|
||||
if (core.Fullscreen)
|
||||
{
|
||||
CycleFullscreen(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Screen screen = Screen.FromControl(this);
|
||||
int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * core.Autofit);
|
||||
|
||||
if (core.VideoSize.Height == 0 || core.VideoSize.Width == 0 ||
|
||||
core.VideoSize.Width / (float)core.VideoSize.Height < App.MinimumAspectRatio)
|
||||
|
||||
core.VideoSize = new Size((int)(autoFitHeight * (16 / 9f)), autoFitHeight);
|
||||
|
||||
Size videoSize = core.VideoSize;
|
||||
int height = videoSize.Height;
|
||||
|
||||
if (core.WasInitialSizeSet || scale != 1)
|
||||
height = ClientSize.Height;
|
||||
else
|
||||
{
|
||||
int savedHeight = RegistryHelp.GetInt(App.RegPath, "Height");
|
||||
|
||||
if (App.StartSize == "always" && savedHeight != 0)
|
||||
height = savedHeight;
|
||||
else
|
||||
if (App.StartSize != "video")
|
||||
height = autoFitHeight;
|
||||
|
||||
core.WasInitialSizeSet = true;
|
||||
}
|
||||
|
||||
height = Convert.ToInt32(height * scale);
|
||||
int width = height * videoSize.Width / videoSize.Height;
|
||||
int maxHeight = screen.WorkingArea.Height - (Height - ClientSize.Height);
|
||||
int maxWidth = screen.WorkingArea.Width - (Width - ClientSize.Width);
|
||||
|
||||
if (height < maxHeight * core.AutofitSmaller)
|
||||
{
|
||||
height = Convert.ToInt32(maxHeight * core.AutofitSmaller);
|
||||
width = Convert.ToInt32(height * videoSize.Width / videoSize.Height);
|
||||
}
|
||||
|
||||
if (height > maxHeight * core.AutofitLarger)
|
||||
{
|
||||
height = Convert.ToInt32(maxHeight * core.AutofitLarger);
|
||||
width = Convert.ToInt32(height * videoSize.Width / videoSize.Height);
|
||||
}
|
||||
|
||||
if (width > maxWidth)
|
||||
{
|
||||
width = maxWidth;
|
||||
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width);
|
||||
}
|
||||
|
||||
Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
|
||||
var rect = new WinAPI.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
|
||||
NativeHelp.AddWindowBorders(Handle, ref rect);
|
||||
int left = middlePos.X - rect.Width / 2;
|
||||
int top = middlePos.Y - rect.Height / 2;
|
||||
|
||||
Screen[] screens = Screen.AllScreens;
|
||||
int minLeft = screens.Select(val => val.WorkingArea.X).Min();
|
||||
int maxRight = screens.Select(val => val.WorkingArea.Right).Max();
|
||||
int minTop = screens.Select(val => val.WorkingArea.Y).Min();
|
||||
int maxBottom = screens.Select(val => val.WorkingArea.Bottom).Max();
|
||||
|
||||
if (left < minLeft)
|
||||
left = minLeft;
|
||||
|
||||
if (left + rect.Width > maxRight)
|
||||
left = maxRight - rect.Width;
|
||||
|
||||
if (top < minTop)
|
||||
top = minTop;
|
||||
|
||||
if (top + rect.Height > maxBottom)
|
||||
top = maxBottom - rect.Height;
|
||||
|
||||
WinAPI.SetWindowPos(Handle, IntPtr.Zero /* HWND_TOP */,
|
||||
left, top, rect.Width, rect.Height, 4 /* SWP_NOZORDER */);
|
||||
}
|
||||
|
||||
public void CycleFullscreen(bool enabled)
|
||||
{
|
||||
LastCycleFullscreen = Environment.TickCount;
|
||||
core.Fullscreen = enabled;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (WindowState != FormWindowState.Maximized || FormBorderStyle != FormBorderStyle.None)
|
||||
{
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
WindowState = FormWindowState.Maximized;
|
||||
|
||||
if (WasMaximized)
|
||||
{
|
||||
Rectangle b = Screen.FromControl(this).Bounds;
|
||||
uint SWP_SHOWWINDOW = 0x0040;
|
||||
IntPtr HWND_TOP= IntPtr.Zero;
|
||||
WinAPI.SetWindowPos(Handle, HWND_TOP, b.X, b.Y, b.Width, b.Height, SWP_SHOWWINDOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WindowState == FormWindowState.Maximized && FormBorderStyle == FormBorderStyle.None)
|
||||
{
|
||||
if (WasMaximized)
|
||||
WindowState = FormWindowState.Maximized;
|
||||
else
|
||||
WindowState = FormWindowState.Normal;
|
||||
|
||||
if (core.Border)
|
||||
FormBorderStyle = FormBorderStyle.Sizable;
|
||||
else
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
|
||||
SetFormPosAndSize();
|
||||
SaveWindowProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildMenu()
|
||||
{
|
||||
string content = File.ReadAllText(core.InputConfPath);
|
||||
var items = CommandItem.GetItems(content);
|
||||
|
||||
if (!content.Contains("#menu:"))
|
||||
{
|
||||
var defaultItems = CommandItem.GetItems(Properties.Resources.input_conf);
|
||||
|
||||
foreach (CommandItem item in items)
|
||||
foreach (CommandItem defaultItem in defaultItems)
|
||||
if (item.Command == defaultItem.Command)
|
||||
defaultItem.Input = item.Input;
|
||||
|
||||
items = defaultItems;
|
||||
}
|
||||
|
||||
foreach (CommandItem item in items)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item.Path))
|
||||
continue;
|
||||
|
||||
string path = item.Path.Replace("&", "&&");
|
||||
|
||||
MenuItem menuItem = ContextMenu.Add(path, () => {
|
||||
try {
|
||||
core.command(item.Command);
|
||||
} catch (Exception ex) {
|
||||
Msg.ShowException(ex);
|
||||
}
|
||||
});
|
||||
|
||||
if (menuItem != null)
|
||||
menuItem.ShortcutKeyDisplayString = item.Input + " ";
|
||||
}
|
||||
}
|
||||
|
||||
void FileLoaded()
|
||||
{
|
||||
string path = core.get_property_string("path");
|
||||
|
||||
BeginInvoke(new Action(() => {
|
||||
if (path.Contains("://"))
|
||||
Text = core.get_property_string("media-title") + " - mpv.net " + Application.ProductVersion;
|
||||
else if (path.Contains(":\\") || path.StartsWith("\\\\"))
|
||||
Text = path.FileName() + " - mpv.net " + Application.ProductVersion;
|
||||
else
|
||||
Text = "mpv.net " + Application.ProductVersion;
|
||||
|
||||
int interval = (int)(core.Duration.TotalMilliseconds / 100);
|
||||
|
||||
if (interval < 100)
|
||||
interval = 100;
|
||||
|
||||
if (interval > 1000)
|
||||
interval = 1000;
|
||||
|
||||
ProgressTimer.Interval = interval;
|
||||
UpdateProgressBar();
|
||||
}));
|
||||
|
||||
if (RecentFiles.Contains(path))
|
||||
RecentFiles.Remove(path);
|
||||
|
||||
RecentFiles.Insert(0, path);
|
||||
|
||||
while (RecentFiles.Count > App.RecentCount)
|
||||
RecentFiles.RemoveAt(App.RecentCount);
|
||||
}
|
||||
|
||||
void SaveWindowProperties()
|
||||
{
|
||||
if (WindowState == FormWindowState.Normal)
|
||||
{
|
||||
RegistryHelp.SetValue(App.RegPath, "PosX", Left + Width / 2);
|
||||
RegistryHelp.SetValue(App.RegPath, "PosY", Top + Height / 2);
|
||||
RegistryHelp.SetValue(App.RegPath, "Height", ClientSize.Height);
|
||||
}
|
||||
}
|
||||
|
||||
protected override CreateParams CreateParams {
|
||||
get {
|
||||
CreateParams cp = base.CreateParams;
|
||||
cp.Style |= 0x00020000 /* WS_MINIMIZEBOX */;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WndProc(ref Message m)
|
||||
{
|
||||
//Debug.WriteLine(m);
|
||||
|
||||
switch (m.Msg)
|
||||
{
|
||||
case 0x201: // WM_LBUTTONDOWN
|
||||
case 0x202: // WM_LBUTTONUP
|
||||
case 0x207: // WM_MBUTTONDOWN
|
||||
case 0x208: // WM_MBUTTONUP
|
||||
case 0x20b: // WM_XBUTTONDOWN
|
||||
case 0x20c: // WM_XBUTTONUP
|
||||
case 0x20A: // WM_MOUSEWHEEL
|
||||
case 0x100: // WM_KEYDOWN
|
||||
case 0x101: // WM_KEYUP
|
||||
case 0x104: // WM_SYSKEYDOWN
|
||||
case 0x105: // WM_SYSKEYUP
|
||||
{
|
||||
bool skip = m.Msg == 0x100 && LastAppCommand != 0 &&
|
||||
(Environment.TickCount - LastAppCommand) < 1000;
|
||||
|
||||
if (core.WindowHandle != IntPtr.Zero && !skip)
|
||||
m.Result = WinAPI.SendMessage(core.WindowHandle, m.Msg, m.WParam, m.LParam);
|
||||
}
|
||||
break;
|
||||
case 0x319: // WM_APPCOMMAND
|
||||
{
|
||||
string value = mpvHelp.WM_APPCOMMAND_to_mpv_key((int)(m.LParam.ToInt64() >> 16 & ~0xf000));
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
core.command("keypress " + value);
|
||||
m.Result = new IntPtr(1);
|
||||
LastAppCommand = Environment.TickCount;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0200: // WM_MOUSEMOVE
|
||||
if (Environment.TickCount - LastCycleFullscreen > 500)
|
||||
{
|
||||
Point pos = PointToClient(Cursor.Position);
|
||||
core.command($"mouse {pos.X} {pos.Y}");
|
||||
}
|
||||
|
||||
if (CursorHelp.IsPosDifferent(LastCursorPosition))
|
||||
CursorHelp.Show();
|
||||
break;
|
||||
case 0x2a3: // WM_MOUSELEAVE
|
||||
//osc won't auto hide after mouse left window in borderless mode
|
||||
core.command($"mouse {ClientSize.Width / 2} {ClientSize.Height / 3}");
|
||||
break;
|
||||
case 0x203: // WM_LBUTTONDBLCLK
|
||||
{
|
||||
Point pos = PointToClient(Cursor.Position);
|
||||
core.command($"mouse {pos.X} {pos.Y} 0 double");
|
||||
}
|
||||
break;
|
||||
case 0x02E0: // WM_DPICHANGED
|
||||
{
|
||||
if (!WasShown())
|
||||
break;
|
||||
|
||||
WinAPI.RECT rect = Marshal.PtrToStructure<WinAPI.RECT>(m.LParam);
|
||||
WinAPI.SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, 0);
|
||||
}
|
||||
break;
|
||||
case 0x0214: // WM_SIZING
|
||||
{
|
||||
var rc = Marshal.PtrToStructure<WinAPI.RECT>(m.LParam);
|
||||
var r = rc;
|
||||
NativeHelp.SubtractWindowBorders(Handle, ref r);
|
||||
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
|
||||
Size s = core.VideoSize;
|
||||
|
||||
if (s == Size.Empty)
|
||||
s = new Size(16, 9);
|
||||
|
||||
float aspect = s.Width / (float)s.Height;
|
||||
int d_w = (int)(c_h * aspect - c_w);
|
||||
int d_h = (int)(c_w / aspect - c_h);
|
||||
|
||||
Debug.WriteLine(d_w);
|
||||
Debug.WriteLine(d_h);
|
||||
|
||||
int d_w2 = (int)(c_h * aspect - c_w);
|
||||
int d_h2 = (int)(c_w / aspect - c_h);
|
||||
|
||||
Debug.WriteLine(d_w2);
|
||||
Debug.WriteLine(d_h2);
|
||||
|
||||
int[] d_corners = { d_w, d_h, -d_w, -d_h };
|
||||
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
|
||||
int corner = NativeHelp.GetResizeBorder(m.WParam.ToInt32());
|
||||
|
||||
if (corner >= 0)
|
||||
corners[corner] -= d_corners[corner];
|
||||
|
||||
Marshal.StructureToPtr<WinAPI.RECT>(new WinAPI.RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false);
|
||||
m.Result = new IntPtr(1);
|
||||
}
|
||||
return;
|
||||
case 0x004A: // WM_COPYDATA
|
||||
{
|
||||
var copyData = (WinAPI.COPYDATASTRUCT)m.GetLParam(typeof(WinAPI.COPYDATASTRUCT));
|
||||
string[] files = copyData.lpData.Split('\n');
|
||||
string mode = files[0];
|
||||
files = files.Skip(1).ToArray();
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case "single":
|
||||
core.LoadFiles(files, true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
break;
|
||||
case "queue":
|
||||
foreach (string file in files)
|
||||
core.commandv("loadfile", file, "append");
|
||||
break;
|
||||
}
|
||||
|
||||
Activate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.Msg == TaskbarButtonCreatedMessage && core.TaskbarProgress)
|
||||
{
|
||||
Taskbar = new Taskbar(Handle);
|
||||
ProgressTimer.Start();
|
||||
}
|
||||
|
||||
// beep sound when closed using taskbar due to exception
|
||||
if (!IsDisposed)
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
void CursorTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (CursorHelp.IsPosDifferent(LastCursorPosition))
|
||||
{
|
||||
LastCursorPosition = Control.MousePosition;
|
||||
LastCursorChanged = Environment.TickCount;
|
||||
}
|
||||
else if (Environment.TickCount - LastCursorChanged > 1500 &&
|
||||
!IsMouseInOSC() && ClientRectangle.Contains(PointToClient(MousePosition)) &&
|
||||
Form.ActiveForm == this && !ContextMenu.Visible)
|
||||
|
||||
CursorHelp.Hide();
|
||||
}
|
||||
|
||||
void ProgressTimer_Tick(object sender, EventArgs e) => UpdateProgressBar();
|
||||
|
||||
void UpdateProgressBar()
|
||||
{
|
||||
if (core.TaskbarProgress && Taskbar != null)
|
||||
Taskbar.SetValue(core.get_property_number("time-pos"), core.Duration.TotalSeconds);
|
||||
}
|
||||
|
||||
void PropChangeOnTop(bool value) => BeginInvoke(new Action(() => TopMost = value));
|
||||
|
||||
void PropChangeAid(string value) => core.Aid = value;
|
||||
|
||||
void PropChangeSid(string value) => core.Sid = value;
|
||||
|
||||
void PropChangeVid(string value) => core.Vid = value;
|
||||
|
||||
void PropChangeEdition(int value) => core.Edition = value;
|
||||
|
||||
void PropChangeWindowScale(double value)
|
||||
{
|
||||
if (value != 1)
|
||||
{
|
||||
BeginInvoke(new Action(() => SetFormPosAndSize(value)));
|
||||
core.command("no-osd set window-scale 1");
|
||||
}
|
||||
}
|
||||
|
||||
void PropChangeWindowMaximized()
|
||||
{
|
||||
if (!WasShown())
|
||||
return;
|
||||
|
||||
BeginInvoke(new Action(() =>
|
||||
{
|
||||
core.WindowMaximized = core.get_property_bool("window-maximized");
|
||||
|
||||
if (core.WindowMaximized && WindowState != FormWindowState.Maximized)
|
||||
WindowState = FormWindowState.Maximized;
|
||||
else if (!core.WindowMaximized && WindowState == FormWindowState.Maximized)
|
||||
WindowState = FormWindowState.Normal;
|
||||
}));
|
||||
}
|
||||
|
||||
void PropChangeWindowMinimized()
|
||||
{
|
||||
if (!WasShown())
|
||||
return;
|
||||
|
||||
BeginInvoke(new Action(() =>
|
||||
{
|
||||
core.WindowMinimized = core.get_property_bool("window-minimized");
|
||||
|
||||
if (core.WindowMinimized && WindowState != FormWindowState.Minimized)
|
||||
WindowState = FormWindowState.Minimized;
|
||||
else if (!core.WindowMinimized && WindowState == FormWindowState.Minimized)
|
||||
WindowState = FormWindowState.Normal;
|
||||
}));
|
||||
}
|
||||
|
||||
void PropChangeBorder(bool enabled) {
|
||||
core.Border = enabled;
|
||||
|
||||
BeginInvoke(new Action(() => {
|
||||
if (!IsFullscreen)
|
||||
{
|
||||
if (core.Border && FormBorderStyle == FormBorderStyle.None)
|
||||
FormBorderStyle = FormBorderStyle.Sizable;
|
||||
|
||||
if (!core.Border && FormBorderStyle == FormBorderStyle.Sizable)
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void PropChangePause(bool enabled)
|
||||
{
|
||||
if (Taskbar != null && core.TaskbarProgress)
|
||||
{
|
||||
if (enabled)
|
||||
Taskbar.SetState(TaskbarStates.Paused);
|
||||
else
|
||||
Taskbar.SetState(TaskbarStates.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
if (core.GPUAPI != "vulkan")
|
||||
core.VideoSizeAutoResetEvent.WaitOne(App.StartThreshold);
|
||||
|
||||
LastCycleFullscreen = Environment.TickCount;
|
||||
SetFormPosAndSize();
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
|
||||
if (core.GPUAPI == "vulkan")
|
||||
core.ProcessCommandLine(false);
|
||||
|
||||
ToolStripRendererEx.ForegroundColor = Theme.Current.GetWinFormsColor("menu-foreground");
|
||||
ToolStripRendererEx.BackgroundColor = Theme.Current.GetWinFormsColor("menu-background");
|
||||
ToolStripRendererEx.SelectionColor = Theme.Current.GetWinFormsColor("menu-highlight");
|
||||
ToolStripRendererEx.BorderColor = Theme.Current.GetWinFormsColor("menu-border");
|
||||
ToolStripRendererEx.CheckedColor = Theme.Current.GetWinFormsColor("menu-checked");
|
||||
|
||||
BuildMenu();
|
||||
ContextMenuStrip = ContextMenu;
|
||||
WPF.WPF.Init();
|
||||
System.Windows.Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
|
||||
Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
|
||||
UpdateCheck.DailyCheck();
|
||||
core.LoadScripts();
|
||||
Task.Run(() => App.Extension = new Extension());
|
||||
ShownTickCount = Environment.TickCount;
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
base.OnActivated(e);
|
||||
Message m = new Message() { Msg = 0x0202 }; // WM_LBUTTONUP
|
||||
WinAPI.SendMessage(MainForm.Instance.Handle, m.Msg, m.WParam, m.LParam);
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
|
||||
if (core.IsLogoVisible)
|
||||
core.ShowLogo();
|
||||
|
||||
if (FormBorderStyle != FormBorderStyle.None)
|
||||
{
|
||||
if (WindowState == FormWindowState.Maximized)
|
||||
WasMaximized = true;
|
||||
else if (WindowState == FormWindowState.Normal)
|
||||
WasMaximized = false;
|
||||
}
|
||||
|
||||
if (WasShown())
|
||||
{
|
||||
if (WindowState == FormWindowState.Minimized)
|
||||
{
|
||||
core.set_property_string("window-minimized", "yes");
|
||||
}
|
||||
else if (WindowState == FormWindowState.Normal)
|
||||
{
|
||||
core.set_property_string("window-maximized", "no");
|
||||
core.set_property_string("window-minimized", "no");
|
||||
}
|
||||
else if (WindowState == FormWindowState.Maximized)
|
||||
{
|
||||
core.set_property_string("window-maximized", "yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
base.OnFormClosing(e);
|
||||
SaveWindowProperties();
|
||||
RegistryHelp.SetValue(App.RegPath, "Recent", RecentFiles.ToArray());
|
||||
|
||||
if (core.IsQuitNeeded)
|
||||
core.commandv("quit");
|
||||
|
||||
if (!core.ShutdownAutoResetEvent.WaitOne(10000))
|
||||
Msg.ShowError("Shutdown thread failed to complete within 10 seconds.");
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
if (WindowState == FormWindowState.Normal &&
|
||||
e.Button == MouseButtons.Left && !IsMouseInOSC())
|
||||
{
|
||||
var HTCAPTION = new IntPtr(2);
|
||||
WinAPI.ReleaseCapture();
|
||||
WinAPI.PostMessage(Handle, 0xA1 /* WM_NCLBUTTONDOWN */, HTCAPTION, IntPtr.Zero);
|
||||
}
|
||||
|
||||
if (Width - e.Location.X < 10 && e.Location.Y < 10)
|
||||
core.commandv("quit");
|
||||
}
|
||||
|
||||
protected override void OnDragEnter(DragEventArgs e)
|
||||
{
|
||||
base.OnDragEnter(e);
|
||||
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(DataFormats.Text))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
}
|
||||
|
||||
protected override void OnDragDrop(DragEventArgs e)
|
||||
{
|
||||
base.OnDragDrop(e);
|
||||
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
core.LoadFiles(e.Data.GetData(DataFormats.FileDrop) as String[], true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
|
||||
if (e.Data.GetDataPresent(DataFormats.Text))
|
||||
core.LoadFiles(new[] { e.Data.GetData(DataFormats.Text).ToString() }, true, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
}
|
||||
|
||||
protected override void OnLostFocus(EventArgs e)
|
||||
{
|
||||
base.OnLostFocus(e);
|
||||
CursorHelp.Show();
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
// prevent beep using alt key
|
||||
if (Control.ModifierKeys == Keys.Alt)
|
||||
e.SuppressKeyPress = true;
|
||||
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
public class ContextMenuStripEx : ContextMenuStrip
|
||||
{
|
||||
public ContextMenuStripEx()
|
||||
{
|
||||
}
|
||||
|
||||
public ContextMenuStripEx(IContainer container) : base(container)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
Renderer = new ToolStripRendererEx();
|
||||
}
|
||||
|
||||
public MenuItem Add(string path)
|
||||
{
|
||||
return Add(path, null);
|
||||
}
|
||||
|
||||
public MenuItem Add(string path, Action action, bool enabled = true)
|
||||
{
|
||||
MenuItem ret = MenuItem.Add(Items, path, action);
|
||||
if (ret == null) return null;
|
||||
ret.Enabled = enabled;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public class MenuItem : ToolStripMenuItem
|
||||
{
|
||||
public Action Action { get; set; }
|
||||
|
||||
public MenuItem()
|
||||
{
|
||||
}
|
||||
|
||||
public MenuItem(string text) : base(text)
|
||||
{
|
||||
}
|
||||
|
||||
public MenuItem(string text, Action action) : base(text)
|
||||
{
|
||||
Action = action;
|
||||
}
|
||||
|
||||
protected override void OnClick(EventArgs e)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Action?.Invoke();
|
||||
base.OnClick(e);
|
||||
}
|
||||
|
||||
public static MenuItem Add(ToolStripItemCollection items, string path, Action action)
|
||||
{
|
||||
string[] a = path.Split(new[] { " > ", " | " }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var itemsCollection = items;
|
||||
|
||||
for (int x = 0; x < a.Length; x++)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
foreach (var i in itemsCollection.OfType<ToolStripMenuItem>())
|
||||
{
|
||||
if (x < a.Length - 1)
|
||||
{
|
||||
if (i.Text == a[x] + " ")
|
||||
{
|
||||
found = true;
|
||||
itemsCollection = i.DropDownItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (x == a.Length - 1)
|
||||
{
|
||||
if (a[x] == "-")
|
||||
itemsCollection.Add(new ToolStripSeparator());
|
||||
else
|
||||
{
|
||||
MenuItem item = new MenuItem(a[x] + " ", action);
|
||||
itemsCollection.Add(item);
|
||||
itemsCollection = item.DropDownItems;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MenuItem item = new MenuItem();
|
||||
item.Text = a[x] + " ";
|
||||
itemsCollection.Add(item);
|
||||
itemsCollection = item.DropDownItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Size GetPreferredSize(Size constrainingSize)
|
||||
{
|
||||
Size size = base.GetPreferredSize(constrainingSize);
|
||||
size.Height = Convert.ToInt32(Font.Height * 1.4);
|
||||
return size;
|
||||
}
|
||||
|
||||
public void CloseAll(object item)
|
||||
{
|
||||
if (item is ToolStripItem)
|
||||
CloseAll(((ToolStripItem)item).Owner);
|
||||
|
||||
if (item is ToolStripDropDown)
|
||||
{
|
||||
var d = (ToolStripDropDown)item;
|
||||
d.Close();
|
||||
CloseAll(d.OwnerItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ToolStripRendererEx : ToolStripSystemRenderer
|
||||
{
|
||||
public static Color ForegroundColor { get; set; }
|
||||
public static Color BackgroundColor { get; set; }
|
||||
public static Color SelectionColor { get; set; }
|
||||
public static Color CheckedColor { get; set; }
|
||||
public static Color BorderColor { get; set; }
|
||||
|
||||
int TextOffset;
|
||||
|
||||
public static void SetDefaultColors()
|
||||
{
|
||||
ForegroundColor = Color.FromArgb(unchecked((int)0xFF000000));
|
||||
BackgroundColor = Color.FromArgb(unchecked((int)0xFFDFDFDF));
|
||||
SelectionColor = Color.FromArgb(unchecked((int)0xFFBFBFBF));
|
||||
CheckedColor = Color.FromArgb(unchecked((int)0xFFAAAAAA));
|
||||
BorderColor = Color.FromArgb(unchecked((int)0xFF6A6A6A));
|
||||
}
|
||||
|
||||
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
|
||||
{
|
||||
Rectangle r = e.AffectedBounds;
|
||||
r.Inflate(-1, -1);
|
||||
ControlPaint.DrawBorder(e.Graphics, r, BackgroundColor, ButtonBorderStyle.Solid);
|
||||
ControlPaint.DrawBorder(e.Graphics, e.AffectedBounds, BorderColor, ButtonBorderStyle.Solid);
|
||||
}
|
||||
|
||||
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
||||
{
|
||||
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
|
||||
|
||||
if (e.Item is ToolStripMenuItem && !(e.Item.Owner is MenuStrip))
|
||||
{
|
||||
Rectangle rect = e.TextRectangle;
|
||||
var dropDown = e.ToolStrip as ToolStripDropDownMenu;
|
||||
|
||||
if (dropDown == null || dropDown.ShowImageMargin || dropDown.ShowCheckMargin)
|
||||
TextOffset = Convert.ToInt32(e.Item.Height * 1.1);
|
||||
else
|
||||
TextOffset = Convert.ToInt32(e.Item.Height * 0.2);
|
||||
|
||||
e.TextColor = ForegroundColor;
|
||||
e.TextRectangle = new Rectangle(TextOffset, Convert.ToInt32((e.Item.Height - rect.Height) / 2.0), rect.Width, rect.Height);
|
||||
}
|
||||
|
||||
base.OnRenderItemText(e);
|
||||
}
|
||||
|
||||
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
|
||||
{
|
||||
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
|
||||
|
||||
if (!(e.Item.Owner is MenuStrip))
|
||||
e.Graphics.Clear(BackgroundColor);
|
||||
|
||||
if (e.Item.Selected && e.Item.Enabled)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
rect = new Rectangle(rect.X + 2, rect.Y, rect.Width - 4, rect.Height - 1);
|
||||
rect.Inflate(-1, -1);
|
||||
using (SolidBrush b = new SolidBrush(SelectionColor))
|
||||
e.Graphics.FillRectangle(b, rect);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
|
||||
{
|
||||
if (e.Direction == ArrowDirection.Down) throw new NotImplementedException();
|
||||
float x1 = e.Item.Width - e.Item.Height * 0.6f;
|
||||
float y1 = e.Item.Height * 0.25f;
|
||||
float x2 = x1 + e.Item.Height * 0.25f;
|
||||
float y2 = e.Item.Height / 2f;
|
||||
float x3 = x1;
|
||||
float y3 = e.Item.Height * 0.75f;
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
using (Brush b = new SolidBrush(ForegroundColor))
|
||||
{
|
||||
using (Pen p = new Pen(b, Control.DefaultFont.Height / 20f))
|
||||
{
|
||||
e.Graphics.DrawLine(p, x1, y1, x2, y2);
|
||||
e.Graphics.DrawLine(p, x2, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
|
||||
{
|
||||
if (e.Item.GetType() != typeof(MenuItem))
|
||||
return;
|
||||
|
||||
MenuItem item = e.Item as MenuItem;
|
||||
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
if (!item.Checked)
|
||||
return;
|
||||
|
||||
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
|
||||
rect = new Rectangle(rect.X + 2, rect.Y, rect.Height - 1, rect.Height - 1);
|
||||
rect.Inflate(-1, -1);
|
||||
|
||||
using (Brush brush = new SolidBrush(CheckedColor))
|
||||
e.Graphics.FillRectangle(brush, rect);
|
||||
|
||||
float ellipseWidth = rect.Height / 3f;
|
||||
|
||||
RectangleF rectF = new RectangleF(rect.X + rect.Height / 2f - ellipseWidth / 2f,
|
||||
rect.Y + rect.Height / 2f - ellipseWidth / 2f,
|
||||
ellipseWidth,
|
||||
ellipseWidth);
|
||||
|
||||
using (Brush brush = new SolidBrush(ForegroundColor))
|
||||
e.Graphics.FillEllipse(brush, rectF);
|
||||
}
|
||||
|
||||
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
|
||||
{
|
||||
e.Graphics.Clear(BackgroundColor);
|
||||
int top = e.Item.Height / 2;
|
||||
top -= 1;
|
||||
int offset = Convert.ToInt32(e.Item.Font.Height * 0.7);
|
||||
using (Pen p = new Pen(BorderColor))
|
||||
e.Graphics.DrawLine(p,
|
||||
new Point(offset, top),
|
||||
new Point(e.Item.Width - offset, top));
|
||||
}
|
||||
}
|
||||
|
||||
public struct HSLColor
|
||||
{
|
||||
public HSLColor(Color color) : this()
|
||||
{
|
||||
SetRGB(color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
public HSLColor(int h, int s, int l) : this()
|
||||
{
|
||||
Hue = h;
|
||||
Saturation = s;
|
||||
Luminosity = l;
|
||||
}
|
||||
|
||||
double _Hue;
|
||||
|
||||
public int Hue {
|
||||
get => System.Convert.ToInt32(_Hue * 240);
|
||||
set => _Hue = CheckRange(value / 240.0);
|
||||
}
|
||||
|
||||
double _Saturation;
|
||||
|
||||
public int Saturation {
|
||||
get => System.Convert.ToInt32(_Saturation * 240);
|
||||
set => _Saturation = CheckRange(value / 240.0);
|
||||
}
|
||||
|
||||
double _Luminosity;
|
||||
|
||||
public int Luminosity {
|
||||
get => System.Convert.ToInt32(_Luminosity * 240);
|
||||
set => _Luminosity = CheckRange(value / 240.0);
|
||||
}
|
||||
|
||||
double CheckRange(double value)
|
||||
{
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
else if (value > 1)
|
||||
value = 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
public Color ToColorAddLuminosity(int luminosity)
|
||||
{
|
||||
Luminosity += luminosity;
|
||||
return ToColor();
|
||||
}
|
||||
|
||||
public Color ToColorSetLuminosity(int luminosity)
|
||||
{
|
||||
Luminosity = luminosity;
|
||||
return ToColor();
|
||||
}
|
||||
|
||||
public Color ToColor()
|
||||
{
|
||||
double r = 0, g = 0, b = 0;
|
||||
|
||||
if (_Luminosity != 0)
|
||||
{
|
||||
if (_Saturation == 0)
|
||||
{
|
||||
b = _Luminosity;
|
||||
g = _Luminosity;
|
||||
r = _Luminosity;
|
||||
}
|
||||
else
|
||||
{
|
||||
double temp2 = GetTemp2(this);
|
||||
double temp1 = 2.0 * _Luminosity - temp2;
|
||||
r = GetColorComponent(temp1, temp2, _Hue + 1.0 / 3.0);
|
||||
g = GetColorComponent(temp1, temp2, _Hue);
|
||||
b = GetColorComponent(temp1, temp2, _Hue - 1.0 / 3.0);
|
||||
}
|
||||
}
|
||||
|
||||
return Color.FromArgb(
|
||||
System.Convert.ToInt32(255 * r),
|
||||
System.Convert.ToInt32(255 * g),
|
||||
System.Convert.ToInt32(255 * b));
|
||||
}
|
||||
|
||||
static double GetColorComponent(double temp1, double temp2, double temp3)
|
||||
{
|
||||
temp3 = MoveIntoRange(temp3);
|
||||
|
||||
if (temp3 < 1 / 6.0)
|
||||
return temp1 + (temp2 - temp1) * 6.0 * temp3;
|
||||
else if (temp3 < 0.5)
|
||||
return temp2;
|
||||
else if (temp3 < 2 / 3.0)
|
||||
return temp1 + ((temp2 - temp1) * (2 / 3.0 - temp3) * 6);
|
||||
else
|
||||
return temp1;
|
||||
}
|
||||
|
||||
static double MoveIntoRange(double temp3)
|
||||
{
|
||||
if (temp3 < 0)
|
||||
temp3 += 1;
|
||||
else if (temp3 > 1)
|
||||
temp3 -= 1;
|
||||
return temp3;
|
||||
}
|
||||
|
||||
static double GetTemp2(HSLColor hslColor)
|
||||
{
|
||||
double temp2;
|
||||
|
||||
if (hslColor._Luminosity < 0.5)
|
||||
temp2 = hslColor._Luminosity * (1.0 + hslColor._Saturation);
|
||||
else
|
||||
temp2 = hslColor._Luminosity + hslColor._Saturation - (hslColor._Luminosity * hslColor._Saturation);
|
||||
|
||||
return temp2;
|
||||
}
|
||||
|
||||
public static HSLColor Convert(Color c)
|
||||
{
|
||||
HSLColor r = new HSLColor();
|
||||
r._Hue = c.GetHue() / 360.0;
|
||||
r._Luminosity = c.GetBrightness();
|
||||
r._Saturation = c.GetSaturation();
|
||||
return r;
|
||||
}
|
||||
|
||||
public void SetRGB(int red, int green, int blue)
|
||||
{
|
||||
HSLColor hc = HSLColor.Convert(Color.FromArgb(red, green, blue));
|
||||
_Hue = hc._Hue;
|
||||
_Saturation = hc._Saturation;
|
||||
_Luminosity = hc._Luminosity;
|
||||
}
|
||||
}
|
||||
1179
mpv.net/mpv/Core.cs
@@ -1,35 +0,0 @@
|
||||
|
||||
// When seeking displays position and duration like so: 70:00 / 80:00
|
||||
// Which is different from most players which use: 01:10:00 / 01:20:00
|
||||
// In input.conf set the input command prefix no-osd infront of the seek command.
|
||||
|
||||
function add_zero(val)
|
||||
{
|
||||
val = Math.round(val);
|
||||
return val > 9 ? "" + val : "0" + val;
|
||||
}
|
||||
|
||||
function format(val)
|
||||
{
|
||||
var sec = Math.round(val);
|
||||
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
|
||||
pos_min_floor = Math.floor(sec / 60);
|
||||
sec_rest = sec - pos_min_floor * 60;
|
||||
return add_zero(pos_min_floor) + ":" + add_zero(sec_rest);
|
||||
}
|
||||
|
||||
function on_seek(_)
|
||||
{
|
||||
pos = mp.get_property_number("time-pos");
|
||||
dur = mp.get_property_number("duration");
|
||||
|
||||
if (pos > dur)
|
||||
pos = dur;
|
||||
|
||||
mp.commandv("show-text", format(pos) + " / " + format(dur));
|
||||
}
|
||||
|
||||
mp.register_event("seek", on_seek);
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
// This script shows the playlist.
|
||||
|
||||
function showPlaylist()
|
||||
{
|
||||
// set font size
|
||||
mp.set_property_number("osd-font-size", 40);
|
||||
|
||||
// show playlist for 5 seconds
|
||||
mp.command("show-text ${playlist} 5000");
|
||||
|
||||
// restore original font size in 6 seconds
|
||||
setTimeout(resetFontSize, 6000);
|
||||
}
|
||||
|
||||
// restore original font size
|
||||
function resetFontSize()
|
||||
{
|
||||
mp.set_property_number("osd-font-size", size);
|
||||
}
|
||||
|
||||
// save original font size
|
||||
var size = mp.get_property_number("osd-font-size");
|
||||
|
||||
// input.conf: key script-binding show-playlist
|
||||
mp.add_key_binding(null, "show-playlist", showPlaylist);
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
-- https://github.com/mpv-player/mpv/blob/master/TOOLS/lua/pause-when-minimize.lua
|
||||
|
||||
-- This script pauses playback when minimizing the window, and resumes playback
|
||||
-- if it's brought back again. If the player was already paused when minimizing,
|
||||
-- then try not to mess with the pause state.
|
||||
|
||||
local did_minimize = false
|
||||
|
||||
mp.observe_property("window-minimized", "bool", function(name, value)
|
||||
local pause = mp.get_property_native("pause")
|
||||
if value == true then
|
||||
if pause == false then
|
||||
mp.set_property_native("pause", true)
|
||||
did_minimize = true
|
||||
end
|
||||
elseif value == false then
|
||||
if did_minimize and (pause == true) then
|
||||
mp.set_property_native("pause", false)
|
||||
end
|
||||
did_minimize = false
|
||||
end
|
||||
end)
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
# Shows the current file in File Explorer
|
||||
|
||||
# In input.conf add: <key> script-message show-in-file-explorer
|
||||
|
||||
$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') + '"')
|
||||
}
|
||||
}
|
||||
|
||||
$mp.register_event("client-message", $code)
|
||||
48
setup.iss
@@ -1,48 +0,0 @@
|
||||
|
||||
#define MyAppName "mpv.net"
|
||||
#define MyAppExeName "mpvnet.exe"
|
||||
|
||||
#ifndef arch
|
||||
#define arch "x64"
|
||||
#endif
|
||||
|
||||
#if arch == "x64"
|
||||
#define MyAppSourceDir "mpv.net\bin\x64"
|
||||
#define MyAppVersion GetFileVersion("mpv.net\bin\x64\mpvnet.exe")
|
||||
#else
|
||||
#define MyAppSourceDir "mpv.net\bin\x86"
|
||||
#define MyAppVersion GetFileVersion("mpv.net\bin\x86\mpvnet.exe")
|
||||
#endif
|
||||
|
||||
[Setup]
|
||||
AppId={{9AA2B100-BEF3-44D0-B819-D8FC3C4D557D}}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher=Frank Skare (stax76)
|
||||
|
||||
#if arch == "x64"
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
#endif
|
||||
|
||||
Compression=lzma2
|
||||
DefaultDirName={commonpf}\{#MyAppName}
|
||||
OutputBaseFilename=mpv.net-setup-{#arch}-{#MyAppVersion}
|
||||
OutputDir={#GetEnv('USERPROFILE')}\Desktop
|
||||
DefaultGroupName={#MyAppName}
|
||||
SetupIconFile=mpv.net\mpvnet.ico
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
|
||||
[Files]
|
||||
Source: "{#MyAppSourceDir}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#MyAppSourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "Associate video file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc video"
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "Associate audio file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc audio"
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "Associate image file extensions?"; Flags: postinstall unchecked runascurrentuser runhidden nowait; Parameters: "--reg-file-assoc image"
|
||||
|
||||
[UninstallRun]
|
||||
Filename: "{app}\{#MyAppExeName}"; Flags: runascurrentuser runhidden; Parameters: "--reg-file-assoc unreg"
|
||||
22
src/.editorconfig
Normal file
@@ -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
|
||||
@@ -5,4 +5,4 @@
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
</configuration>
|
||||
135
src/Extensions/RatingExtension/RatingExtension.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
|
||||
// This extension writes a rating to the filename of rated videos when mpv.net shuts down.
|
||||
|
||||
// The input.conf setup:
|
||||
|
||||
// KP0 script-message rate-file 0 #menu: Extensions > Rating > 0stars
|
||||
// KP1 script-message rate-file 1 #menu: Extensions > Rating > 1stars
|
||||
// KP2 script-message rate-file 2 #menu: Extensions > Rating > 2stars
|
||||
// KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
|
||||
// KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
|
||||
// KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
|
||||
// _ ignore #menu: Extensions > Rating > -
|
||||
// _ script-message rate-file about #menu: Extensions > Rating > About
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Microsoft.VisualBasic.FileIO;
|
||||
|
||||
using mpvnet;
|
||||
using static mpvnet.Global;
|
||||
|
||||
namespace RatingExtension // the assembly name must end with 'Extension'!
|
||||
{
|
||||
[Export(typeof(IExtension))]
|
||||
public class RatingExtension : IExtension
|
||||
{
|
||||
//Script script = new Script();
|
||||
|
||||
// dictionory to store the filename and the rating
|
||||
Dictionary<string, int> Dic = new Dictionary<string, int>();
|
||||
|
||||
string FileToDelete;
|
||||
DateTime DeleteTime;
|
||||
|
||||
public RatingExtension() // plugin initialization
|
||||
{
|
||||
Core.ClientMessage += ClientMessage; //handles keys defined in input.conf
|
||||
Core.Shutdown += Shutdown; // handles MPV_EVENT_SHUTDOWN
|
||||
}
|
||||
|
||||
// handles MPV_EVENT_SHUTDOWN
|
||||
void Shutdown()
|
||||
{
|
||||
foreach (var i in Dic)
|
||||
{
|
||||
string filepath = i.Key;
|
||||
int rating = i.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(filepath) || !File.Exists(filepath))
|
||||
return;
|
||||
|
||||
string basename = Path.GetFileNameWithoutExtension(filepath);
|
||||
|
||||
for (int x = 0; x < 6; x++)
|
||||
if (basename.Contains(" (" + x + "stars)"))
|
||||
basename = basename.Replace(" (" + x + "stars)", "");
|
||||
|
||||
basename += $" ({rating}stars)";
|
||||
|
||||
string newPath = Path.Combine(Path.GetDirectoryName(filepath),
|
||||
basename + Path.GetExtension(filepath));
|
||||
|
||||
if (filepath.ToLower() != newPath.ToLower())
|
||||
File.Move(filepath, newPath);
|
||||
|
||||
File.SetLastWriteTime(newPath, DateTime.Now);
|
||||
}
|
||||
}
|
||||
|
||||
//handles keys defined in input.conf
|
||||
void ClientMessage(string[] args)
|
||||
{
|
||||
if (args[0] != "rate-file")
|
||||
return;
|
||||
|
||||
if (int.TryParse(args[1], out int rating))
|
||||
{
|
||||
string path = Core.GetPropertyString("path");
|
||||
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
if (rating == 0 || rating == 1)
|
||||
Delete(rating);
|
||||
else
|
||||
{
|
||||
Dic[path] = rating;
|
||||
Core.CommandV("show-text", $"Rating: {rating}");
|
||||
}
|
||||
}
|
||||
else if (args[1] == "about")
|
||||
MessageBox.Show($"This extension writes a rating to the filename of rated videos " +
|
||||
"when mpv.net shuts down." + BR2 +
|
||||
"The input.conf defaults contain key bindings for this extension to set ratings.",
|
||||
"Rating Extension");
|
||||
}
|
||||
|
||||
void Delete(int rating)
|
||||
{
|
||||
if (rating == 0)
|
||||
{
|
||||
FileToDelete = Core.GetPropertyString("path");
|
||||
DeleteTime = DateTime.Now;
|
||||
Core.CommandV("show-text", "Press 1 to delete file", "5000");
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeSpan ts = DateTime.Now - DeleteTime;
|
||||
string path = Core.GetPropertyString("path");
|
||||
|
||||
if (FileToDelete == path && ts.TotalSeconds < 5 && File.Exists(FileToDelete))
|
||||
{
|
||||
Core.Command("playlist-remove current");
|
||||
int pos = Core.GetPropertyInt("playlist-pos");
|
||||
|
||||
if (pos == -1)
|
||||
{
|
||||
int count = Core.GetPropertyInt("playlist-count");
|
||||
|
||||
if (count > 0)
|
||||
Core.SetPropertyInt("playlist-pos", count - 1);
|
||||
}
|
||||
|
||||
Thread.Sleep(2000);
|
||||
FileSystem.DeleteFile(FileToDelete, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,46 +13,33 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\mpv.net\bin\x86\Extensions\RatingExtension\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>..\..\mpv.net\bin\x86\Extensions\RatingExtension\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\..\mpv.net\bin\x64\Extensions\RatingExtension\</OutputPath>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\..\mpv.net\bin\x64\Extensions\RatingExtension\</OutputPath>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualBasic" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -63,9 +50,10 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="RatingExtension.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ScriptDevelopment.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\mpv.net\mpv.net.csproj">
|
||||
<ProjectReference Include="..\..\mpv.net.csproj">
|
||||
<Project>{1751f378-8edf-4b62-be6d-304c7c287089}</Project>
|
||||
<Name>mpv.net</Name>
|
||||
<Private>False</Private>
|
||||
42
src/Extensions/RatingExtension/ScriptDevelopment.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
//// This script adds dynamic menu items for profile switching.
|
||||
|
||||
//// In input.conf add a menu item called 'Profiles'
|
||||
|
||||
//using mpvnet;
|
||||
//using System.ComponentModel;
|
||||
//using System.Linq;
|
||||
|
||||
//class Script
|
||||
//{
|
||||
// MainForm MainForm;
|
||||
// CorePlayer Core;
|
||||
|
||||
// public Script()
|
||||
// {
|
||||
// Core = Global.Core;
|
||||
// MainForm = MainForm.Instance;
|
||||
// MainForm.ContextMenu.Opening += ContextMenu_Opening;
|
||||
// }
|
||||
|
||||
// void ContextMenu_Opening(object sender, CancelEventArgs e)
|
||||
// {
|
||||
// MenuItem menuItem = MainForm.FindMenuItem("My Menu");
|
||||
|
||||
// if (menuItem == null)
|
||||
// {
|
||||
// Terminal.WriteError("Profiles menu item not found.", "switch-profile-context-menu.cs");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// menuItem.DropDownItems.Clear();
|
||||
// var editionTracks = Core.MediaTracks.Where(track => track.Type == "e");
|
||||
|
||||
// foreach (int i in new[] {1, 2, 3})
|
||||
// {
|
||||
// MenuItem mi = new MenuItem(i.ToString());
|
||||
// mi.Action = () => { Core.commandv("show-text", i.ToString()); };
|
||||
// menuItem.DropDownItems.Add(mi);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
294
src/Misc/App.cs
Normal file
@@ -0,0 +1,294 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using static mpvnet.Global;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public static class App
|
||||
{
|
||||
public static List<string> TempFiles { get; } = new List<string>();
|
||||
|
||||
public static string ConfPath { get => Core.ConfigFolder + "mpvnet.conf"; }
|
||||
public static string ProcessInstance { get; set; } = "single";
|
||||
public static string DarkMode { get; set; } = "always";
|
||||
public static string DarkTheme { get; set; } = "dark";
|
||||
public static string LightTheme { get; set; } = "light";
|
||||
public static string StartSize { get; set; } = "height-session";
|
||||
|
||||
public static bool AutoLoadFolder { get; set; } = true;
|
||||
public static bool AutoPlay { get; set; }
|
||||
public static bool DebugMode { get; set; }
|
||||
public static bool Exit { get; set; }
|
||||
public static bool IsTerminalAttached { get; } = Environment.GetEnvironmentVariable("_started_from_console") == "yes";
|
||||
public static bool MediaInfo { get; set; } = true;
|
||||
public static bool Queue { get; set; }
|
||||
public static bool RememberVolume { get; set; } = true;
|
||||
public static bool RememberWindowPosition { get; set; }
|
||||
public static bool ShowLogo { get; set; } = true;
|
||||
public static bool ShowSantaLogo { get; set; } = true;
|
||||
|
||||
public static int StartThreshold { get; set; } = 1500;
|
||||
public static int RecentCount { get; set; } = 15;
|
||||
|
||||
public static float AutofitAudio { get; set; } = 0.7f;
|
||||
public static float AutofitImage { get; set; } = 0.8f;
|
||||
public static float MinimumAspectRatio { get; set; }
|
||||
public static float MinimumAspectRatioAudio { get; set; }
|
||||
public static float QuickBookmark { get; set; }
|
||||
|
||||
public static Extension Extension { get; set; }
|
||||
|
||||
public static bool IsDarkMode => (DarkMode == "system" && Sys.IsDarkTheme) || DarkMode == "always";
|
||||
|
||||
static AppSettings _Settings;
|
||||
|
||||
public static AppSettings Settings {
|
||||
get {
|
||||
if (_Settings == null)
|
||||
_Settings = SettingsManager.Load();
|
||||
|
||||
return _Settings;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
var useless1 = Core.ConfigFolder;
|
||||
var useless2 = Core.Conf;
|
||||
|
||||
foreach (var i in Conf)
|
||||
ProcessProperty(i.Key, i.Value, true);
|
||||
|
||||
if (DebugMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filePath = Core.ConfigFolder + "mpvnet-debug.log";
|
||||
|
||||
if (File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(filePath));
|
||||
Trace.AutoFlush = true;
|
||||
|
||||
//if (App.DebugMode)
|
||||
// Trace.WriteLine("");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Msg.ShowException(e);
|
||||
}
|
||||
}
|
||||
|
||||
InitTheme();
|
||||
|
||||
Core.Shutdown += Core_Shutdown;
|
||||
Core.Initialized += Core_Initialized;
|
||||
}
|
||||
|
||||
public static void InitTheme()
|
||||
{
|
||||
string themeContent = null;
|
||||
|
||||
if (File.Exists(Core.ConfigFolder + "theme.conf"))
|
||||
themeContent = File.ReadAllText(Core.ConfigFolder + "theme.conf");
|
||||
|
||||
Theme.Init(
|
||||
themeContent,
|
||||
Properties.Resources.theme,
|
||||
IsDarkMode ? DarkTheme : LightTheme);
|
||||
}
|
||||
|
||||
public static void UpdateWpfColors()
|
||||
{
|
||||
var dic = System.Windows.Application.Current.Resources;
|
||||
|
||||
dic.Remove("BorderColor");
|
||||
dic.Add("BorderColor", Theme.Current.GetColor("menu-highlight"));
|
||||
|
||||
dic.Remove("RegionColor");
|
||||
dic.Add("RegionColor", Theme.Current.GetColor("menu-background"));
|
||||
|
||||
dic.Remove("SecondaryRegionColor");
|
||||
dic.Add("SecondaryRegionColor", Theme.Current.GetColor("menu-highlight"));
|
||||
|
||||
dic.Remove("PrimaryTextColor");
|
||||
dic.Add("PrimaryTextColor", Theme.Current.GetColor("menu-foreground"));
|
||||
|
||||
dic.Remove("HighlightColor");
|
||||
dic.Add("HighlightColor", Theme.Current.GetColor("highlight"));
|
||||
}
|
||||
|
||||
public static void RunTask(Action action)
|
||||
{
|
||||
Task.Run(() => {
|
||||
try {
|
||||
action.Invoke();
|
||||
}
|
||||
catch (Exception e) {
|
||||
ShowException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static string Version => "Copyright (C) 2000-2022 mpv.net/mpv/mplayer\n" +
|
||||
$"mpv.net {Application.ProductVersion}" + GetLastWriteTime(Application.ExecutablePath) + "\n" +
|
||||
$"{Core.GetPropertyString("mpv-version")}" + GetLastWriteTime(Folder.Startup + "mpv-2.dll") + "\n" +
|
||||
$"ffmpeg {Core.GetPropertyString("ffmpeg-version")}\n" +
|
||||
$"MediaInfo {FileVersionInfo.GetVersionInfo(Path.Combine(Application.StartupPath, "MediaInfo.dll")).FileVersion}" +
|
||||
GetLastWriteTime(Path.Combine(Application.StartupPath , "MediaInfo.dll")) + "\nGPL v2 License";
|
||||
|
||||
static string GetLastWriteTime(string path)
|
||||
{
|
||||
if (IsStoreVrsion)
|
||||
return "";
|
||||
|
||||
return $" ({File.GetLastWriteTime(path).ToShortDateString()})";
|
||||
}
|
||||
|
||||
static bool IsStoreVrsion => Application.StartupPath.Contains("FrankSkare.mpv.net");
|
||||
|
||||
public static void ShowException(object obj)
|
||||
{
|
||||
if (IsTerminalAttached)
|
||||
Terminal.WriteError(obj.ToString());
|
||||
else
|
||||
{
|
||||
if (obj is Exception e)
|
||||
InvokeOnMainThread(() => Msg.ShowException(e));
|
||||
else
|
||||
InvokeOnMainThread(() => Msg.ShowError(obj.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
public static void InvokeOnMainThread(Action action)
|
||||
{
|
||||
if (action == null)
|
||||
return;
|
||||
|
||||
if (MainForm.Instance == null)
|
||||
action.Invoke();
|
||||
else
|
||||
MainForm.Instance.BeginInvoke(action);
|
||||
}
|
||||
|
||||
public static void ShowInfo(string msg)
|
||||
{
|
||||
if (IsTerminalAttached)
|
||||
{
|
||||
if (msg != null)
|
||||
Terminal.Write(msg);
|
||||
}
|
||||
else
|
||||
InvokeOnMainThread(() => Msg.ShowInfo(msg));
|
||||
}
|
||||
|
||||
public static void ShowError(string msg)
|
||||
{
|
||||
if (IsTerminalAttached)
|
||||
{
|
||||
if (msg != null)
|
||||
Terminal.WriteError(msg);
|
||||
}
|
||||
else
|
||||
InvokeOnMainThread(() => Msg.ShowError(msg));
|
||||
}
|
||||
|
||||
static void Core_Initialized()
|
||||
{
|
||||
if (RememberVolume)
|
||||
{
|
||||
Core.SetPropertyInt("volume", Settings.Volume);
|
||||
Core.SetPropertyString("mute", Settings.Mute);
|
||||
}
|
||||
}
|
||||
|
||||
static void Core_Shutdown()
|
||||
{
|
||||
Settings.Volume = Core.GetPropertyInt("volume");
|
||||
Settings.Mute = Core.GetPropertyString("mute");
|
||||
|
||||
SettingsManager.Save(Settings);
|
||||
|
||||
foreach (string file in TempFiles)
|
||||
FileHelp.Delete(file);
|
||||
}
|
||||
|
||||
static Dictionary<string, string> _Conf;
|
||||
|
||||
public static Dictionary<string, string> Conf {
|
||||
get {
|
||||
if (_Conf == null)
|
||||
{
|
||||
_Conf = new Dictionary<string, string>();
|
||||
|
||||
if (File.Exists(ConfPath))
|
||||
foreach (string i in File.ReadAllLines(ConfPath))
|
||||
if (i.Contains("=") && !i.StartsWith("#"))
|
||||
_Conf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
|
||||
}
|
||||
return _Conf;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ProcessProperty(string name, string value, bool writeError = false)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "audio-file-extensions": CorePlayer.AudioTypes = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
|
||||
case "auto-load-folder": AutoLoadFolder = value == "yes"; return true;
|
||||
case "auto-play": AutoPlay = value == "yes"; return true;
|
||||
case "autofit-image": AutofitImage = value.Trim('%').ToInt() / 100f; return true;
|
||||
case "autofit-audio": AutofitAudio = value.Trim('%').ToInt() / 100f; return true;
|
||||
case "dark-mode": DarkMode = value; return true;
|
||||
case "dark-theme": DarkTheme = value.Trim('\'', '"'); return true;
|
||||
case "debug-mode": DebugMode = value == "yes"; return true;
|
||||
case "image-file-extensions": CorePlayer.ImageTypes = value.Split(" ,;".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); return true;
|
||||
case "light-theme": LightTheme = value.Trim('\'', '"'); return true;
|
||||
case "media-info": MediaInfo = value == "yes"; return true;
|
||||
case "minimum-aspect-ratio": MinimumAspectRatio = value.ToFloat(); return true;
|
||||
case "minimum-aspect-ratio-audio": MinimumAspectRatioAudio = 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 "show-logo": ShowLogo = value == "yes"; return true;
|
||||
case "show-santa-logo": ShowSantaLogo = 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");
|
||||
}
|
||||
|
||||
public static (string Title, string Path) GetTitleAndPath(string input)
|
||||
{
|
||||
if (input.Contains("|"))
|
||||
{
|
||||
var a = input.Split('|');
|
||||
return (a[1], a[0]);
|
||||
}
|
||||
|
||||
return (input, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/Misc/CSharpScriptHost.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using Microsoft.CSharp;
|
||||
|
||||
using static mpvnet.Global;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
class CSharpScriptHost
|
||||
{
|
||||
static List<object> References = new List<object>();
|
||||
|
||||
public static void ExecuteScriptsInFolder(string folder)
|
||||
{
|
||||
if (Directory.Exists(folder))
|
||||
foreach (string file in Directory.GetFiles(folder, "*.cs"))
|
||||
App.RunTask(() => Execute(file));
|
||||
}
|
||||
|
||||
static void Execute(string file)
|
||||
{
|
||||
string code = File.ReadAllText(file);
|
||||
string filename = Path.GetFileNameWithoutExtension(file) + " " + StringHelp.GetMD5Hash(code) + "-v6.dll";
|
||||
string outputFile = Path.Combine(Path.GetTempPath(), filename);
|
||||
|
||||
if (!File.Exists(outputFile))
|
||||
Compile(outputFile, file);
|
||||
|
||||
if (File.Exists(outputFile))
|
||||
{
|
||||
object instance = Assembly.LoadFile(outputFile).CreateInstance("Script");
|
||||
|
||||
if (instance != null)
|
||||
References.Add(instance);
|
||||
else
|
||||
Terminal.WriteError("Failed to initialize script.", outputFile.FileName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void Compile(string outputFile, string file)
|
||||
{
|
||||
CSharpCodeProvider provider = new CSharpCodeProvider();
|
||||
CompilerParameters parameters = new CompilerParameters();
|
||||
|
||||
string[] dependencies = {
|
||||
Folder.Startup + "mpvnet.exe",
|
||||
"Microsoft.VisualBasic.dll",
|
||||
"System.Core.dll", "System.Data.dll", "System.dll", "System.Drawing.dll", "System.Web.dll",
|
||||
"System.Windows.Forms.dll", "System.Xaml.dll", "System.Xml.dll", "System.Xml.Linq.dll",
|
||||
"WPF\\PresentationCore.dll", "WPF\\PresentationFramework.dll", "WPF\\WindowsBase.dll"
|
||||
};
|
||||
|
||||
foreach (string i in dependencies)
|
||||
parameters.ReferencedAssemblies.Add(i);
|
||||
|
||||
parameters.OutputAssembly = outputFile;
|
||||
CompilerResults results = provider.CompileAssemblyFromFile(parameters, file);
|
||||
|
||||
var errors = results.Errors.Cast<CompilerError>().Select(i => "Line Number " +
|
||||
i.Line + "\n" + "Error Number: " + i.ErrorNumber + "\n" + i.ErrorText);
|
||||
|
||||
if (errors.Count() > 0)
|
||||
Terminal.WriteError(string.Join(BR2, errors), Path.GetFileName(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
720
src/Misc/Commands.cs
Normal file
@@ -0,0 +1,720 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
|
||||
using WinForms = System.Windows.Forms;
|
||||
|
||||
using static mpvnet.Global;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public class Commands
|
||||
{
|
||||
public static void Execute(string id, string[] args)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case "add-files-to-playlist": OpenFiles("append"); break; // deprecated 2019
|
||||
case "cycle-audio": CycleAudio(); break;
|
||||
case "execute-mpv-command": Msg.ShowError("The command was removed, 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-clipboard": OpenFromClipboard(); 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": OpenFromClipboard(); break; // deprecated 2022
|
||||
case "play-pause": PlayPause(); break;
|
||||
case "playlist-add": PlaylistAdd(Convert.ToInt32(args[0])); break;
|
||||
case "playlist-first": PlaylistFirst(); break;
|
||||
case "playlist-last": PlaylistLast(); break;
|
||||
case "quick-bookmark": QuickBookmark(); break;
|
||||
case "reg-file-assoc": RegisterFileAssociations(args[0]); break;
|
||||
case "scale-window": ScaleWindow(float.Parse(args[0], CultureInfo.InvariantCulture)); break;
|
||||
case "select-profile": SelectProfile(); break;
|
||||
case "shell-execute": ProcessHelp.ShellExecute(args[0]); break;
|
||||
case "show-about": ShowDialog(typeof(AboutWindow)); break;
|
||||
case "show-audio-devices": Msg.ShowInfo(Core.GetPropertyOsdString("audio-device-list")); break;
|
||||
case "show-audio-tracks": ShowAudioTracks(); break;
|
||||
case "show-chapters": ShowChapters(); break;
|
||||
case "show-command-palette": ShowCommandPalette(); break;
|
||||
case "show-commands": ShowCommands(); break;
|
||||
case "show-conf-editor": ShowDialog(typeof(ConfWindow)); break;
|
||||
case "show-decoders": ShowStrings(mpvHelp.GetDecoders().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); break;
|
||||
case "show-demuxers": ShowStrings(mpvHelp.GetDemuxers().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); break;
|
||||
case "show-history": ShowHistory(); break;
|
||||
case "show-info": ShowInfo(); break;
|
||||
case "show-input-editor": ShowDialog(typeof(InputWindow)); break;
|
||||
case "show-keys": ShowStrings(Core.GetPropertyString("input-key-list").Split(',')); break;
|
||||
case "show-media-info": ShowMediaInfo(args); break;
|
||||
case "show-menu": ShowMenu(); break;
|
||||
case "show-playlist": ShowPlaylist(); break;
|
||||
case "show-profiles": Msg.ShowInfo(mpvHelp.GetProfiles()); break;
|
||||
case "show-progress": ShowProgress(); break;
|
||||
case "show-properties": ShowProperties(); break;
|
||||
case "show-protocols": ShowStrings(mpvHelp.GetProtocols().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); break;
|
||||
case "show-recent": ShowRecent(); break;
|
||||
case "show-setup-dialog": ShowSetupDialog(); break; // deprecated 2022
|
||||
case "show-subtitle-tracks": ShowSubtitleTracks(); break;
|
||||
case "show-text": ShowText(args[0], Convert.ToInt32(args[1]), Convert.ToInt32(args[2])); break;
|
||||
case "window-scale": WindowScale(float.Parse(args[0], CultureInfo.InvariantCulture)); break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowTextWithEditor(string name, string text)
|
||||
{
|
||||
string file = Path.Combine(Path.GetTempPath(), name + ".txt");
|
||||
App.TempFiles.Add(file);
|
||||
File.WriteAllText(file, BR + text.Trim() + BR);
|
||||
ProcessHelp.ShellExecute(file);
|
||||
}
|
||||
|
||||
public static void ShowDialog(Type winType) => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
Window win = Activator.CreateInstance(winType) as Window;
|
||||
new WindowInteropHelper(win).Owner = MainForm.Instance.Handle;
|
||||
win.ShowDialog();
|
||||
});
|
||||
|
||||
public static void OpenFiles(params string[] args)
|
||||
{
|
||||
bool append = Control.ModifierKeys.HasFlag(Keys.Control);
|
||||
|
||||
foreach (string arg in args)
|
||||
if (arg == "append")
|
||||
append = true;
|
||||
|
||||
App.InvokeOnMainThread(new Action(() => {
|
||||
using (var d = new OpenFileDialog() { Multiselect = true })
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
Core.LoadFiles(d.FileNames, true, append);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Open_DVD_Or_BD_Folder() => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
var dialog = new FolderBrowser();
|
||||
|
||||
if (dialog.Show())
|
||||
Core.LoadDiskFolder(dialog.SelectedPath);
|
||||
});
|
||||
|
||||
public static void PlaylistFirst()
|
||||
{
|
||||
if (Core.PlaylistPos != 0)
|
||||
Core.SetPropertyInt("playlist-pos", 0);
|
||||
}
|
||||
|
||||
public static void PlaylistLast()
|
||||
{
|
||||
int count = Core.GetPropertyInt("playlist-count");
|
||||
|
||||
if (Core.PlaylistPos < count - 1)
|
||||
Core.SetPropertyInt("playlist-pos", count - 1);
|
||||
}
|
||||
|
||||
public static void PlayPause()
|
||||
{
|
||||
int count = Core.GetPropertyInt("playlist-count");
|
||||
|
||||
if (count > 0)
|
||||
Core.Command("cycle pause");
|
||||
else if (App.Settings.RecentFiles.Count > 0)
|
||||
{
|
||||
foreach (string i in App.Settings.RecentFiles)
|
||||
{
|
||||
if (i.Contains("://") || File.Exists(i))
|
||||
{
|
||||
Core.LoadFiles(new[] { i }, true, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowHistory()
|
||||
{
|
||||
if (File.Exists(Core.ConfigFolder + "history.txt"))
|
||||
ProcessHelp.ShellExecute(Core.ConfigFolder + "history.txt");
|
||||
else
|
||||
{
|
||||
if (Msg.ShowQuestion("Create history.txt file in config folder?" + BR2 +
|
||||
"mpv.net will write the date, time and filename of opened files to it.") == MessageBoxResult.OK)
|
||||
|
||||
File.WriteAllText(Core.ConfigFolder + "history.txt", "");
|
||||
}
|
||||
}
|
||||
|
||||
static int LastShowInfo;
|
||||
|
||||
public static void ShowInfo()
|
||||
{
|
||||
if (Core.PlaylistPos == -1)
|
||||
return;
|
||||
|
||||
if (Environment.TickCount - LastShowInfo < 5000)
|
||||
{
|
||||
Core.Command("script-message-to mpvnet show-media-info osd");
|
||||
LastShowInfo = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
LastShowInfo = Environment.TickCount;
|
||||
|
||||
string text;
|
||||
long fileSize = 0;
|
||||
string path = Core.GetPropertyString("path");
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
fileSize = new FileInfo(path).Length;
|
||||
|
||||
if (CorePlayer.AudioTypes.Contains(path.Ext()))
|
||||
{
|
||||
text = Core.GetPropertyOsdString("filtered-metadata");
|
||||
Core.CommandV("show-text", text, "5000");
|
||||
return;
|
||||
}
|
||||
else if (CorePlayer.ImageTypes.Contains(path.Ext()))
|
||||
{
|
||||
text = "Width: " + Core.GetPropertyInt("width") + "\n" +
|
||||
"Height: " + Core.GetPropertyInt("height") + "\n" +
|
||||
"Size: " + Convert.ToInt32(fileSize / 1024.0) + " KB\n" +
|
||||
"Type: " + path.Ext().ToUpper();
|
||||
|
||||
Core.CommandV("show-text", text, "5000");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (path.Contains("://")) path = Core.GetPropertyString("media-title");
|
||||
string videoFormat = Core.GetPropertyString("video-format").ToUpper();
|
||||
string audioCodec = Core.GetPropertyString("audio-codec-name").ToUpper();
|
||||
int width = Core.GetPropertyInt("video-params/w");
|
||||
int height = Core.GetPropertyInt("video-params/h");
|
||||
TimeSpan len = TimeSpan.FromSeconds(Core.GetPropertyDouble("duration"));
|
||||
text = path.FileName() + "\n";
|
||||
text += FormatTime(len.TotalMinutes) + ":" + FormatTime(len.Seconds) + "\n";
|
||||
if (fileSize > 0) text += Convert.ToInt32(fileSize / 1024.0 / 1024.0) + " MB\n";
|
||||
text += $"{width} x {height}\n";
|
||||
text += $"{videoFormat}\n{audioCodec}";
|
||||
Core.CommandV("show-text", text, "5000");
|
||||
}
|
||||
|
||||
static string FormatTime(double value) => ((int)value).ToString("00");
|
||||
|
||||
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) + " " +
|
||||
DateTime.Now.ToString("H:mm dddd d MMMM", CultureInfo.InvariantCulture);
|
||||
|
||||
Core.CommandV("show-text", text, "5000");
|
||||
}
|
||||
|
||||
public static void OpenFromClipboard() => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
if (WinForms.Clipboard.ContainsFileDropList())
|
||||
{
|
||||
string[] files = WinForms.Clipboard.GetFileDropList().Cast<string>().ToArray();
|
||||
Core.LoadFiles(files, false, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
}
|
||||
else
|
||||
{
|
||||
string clipboard = WinForms.Clipboard.GetText();
|
||||
List<string> files = new List<string>();
|
||||
|
||||
foreach (string i in clipboard.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
|
||||
if (i.Contains("://") || File.Exists(i))
|
||||
files.Add(i);
|
||||
|
||||
if (files.Count == 0)
|
||||
{
|
||||
App.ShowError("The clipboard does not contain a valid URL or file.");
|
||||
return;
|
||||
}
|
||||
|
||||
Core.LoadFiles(files.ToArray(), false, Control.ModifierKeys.HasFlag(Keys.Control));
|
||||
}
|
||||
});
|
||||
|
||||
public static void LoadSubtitle() => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
using (var d = new OpenFileDialog())
|
||||
{
|
||||
string path = Core.GetPropertyString("path");
|
||||
|
||||
if (File.Exists(path))
|
||||
d.InitialDirectory = Path.GetDirectoryName(path);
|
||||
|
||||
d.Multiselect = true;
|
||||
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
foreach (string filename in d.FileNames)
|
||||
Core.CommandV("sub-add", filename);
|
||||
}
|
||||
});
|
||||
|
||||
public static void LoadAudio() => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
using (var d = new OpenFileDialog())
|
||||
{
|
||||
string path = Core.GetPropertyString("path");
|
||||
|
||||
if (File.Exists(path))
|
||||
d.InitialDirectory = Path.GetDirectoryName(path);
|
||||
|
||||
d.Multiselect = true;
|
||||
|
||||
if (d.ShowDialog() == DialogResult.OK)
|
||||
foreach (string i in d.FileNames)
|
||||
Core.CommandV("audio-add", i);
|
||||
}
|
||||
});
|
||||
|
||||
public static void CycleAudio()
|
||||
{
|
||||
Core.UpdateExternalTracks();
|
||||
|
||||
lock (Core.MediaTracksLock)
|
||||
{
|
||||
MediaTrack[] tracks = Core.MediaTracks.Where(track => track.Type == "a").ToArray();
|
||||
|
||||
if (tracks.Length < 1)
|
||||
{
|
||||
Core.CommandV("show-text", "No audio tracks");
|
||||
return;
|
||||
}
|
||||
|
||||
int aid = Core.GetPropertyInt("aid");
|
||||
|
||||
if (tracks.Length > 1)
|
||||
{
|
||||
if (++aid > tracks.Length)
|
||||
aid = 1;
|
||||
|
||||
Core.CommandV("set", "aid", aid.ToString());
|
||||
}
|
||||
|
||||
Core.CommandV("show-text", aid + "/" + tracks.Length + ": " + tracks[aid - 1].Text.Substring(3), "5000");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowCommands()
|
||||
{
|
||||
string jsonString = Core.GetPropertyString("command-list");
|
||||
var jsonObject = jsonString.FromJson<List<Dictionary<string, object>>>().OrderBy(i => i["name"]);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (Dictionary<string, object> dic in jsonObject)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(dic["name"].ToString());
|
||||
|
||||
foreach (Dictionary<string, object> i2 in dic["args"] as List<object>)
|
||||
{
|
||||
string value = i2["name"].ToString() + " <" + i2["type"].ToString().ToLower() + ">";
|
||||
|
||||
if ((bool)i2["optional"] == true)
|
||||
value = "[" + value + "]";
|
||||
|
||||
sb.AppendLine(" " + value);
|
||||
}
|
||||
}
|
||||
|
||||
ShowTextWithEditor("command-list", sb.ToString());
|
||||
}
|
||||
|
||||
public static void ScaleWindow(float factor) => Core.RaiseScaleWindow(factor);
|
||||
|
||||
public static void WindowScale(float value) => Core.RaiseWindowScaleNET(value);
|
||||
|
||||
public static void ShowText(string text, int duration = 0, int fontSize = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return;
|
||||
|
||||
if (duration == 0)
|
||||
duration = Core.GetPropertyInt("osd-duration");
|
||||
|
||||
if (fontSize == 0)
|
||||
fontSize = Core.GetPropertyInt("osd-font-size");
|
||||
|
||||
Core.Command("show-text \"${osd-ass-cc/0}{\\\\fs" + fontSize +
|
||||
"}${osd-ass-cc/1}" + text + "\" " + duration);
|
||||
}
|
||||
|
||||
public static void ShowMediaInfo(string[] args) => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
{
|
||||
(string Name, string Value)[] pairs = {
|
||||
("Show text box", "script-message-to mpvnet show-media-info default"),
|
||||
("Show text editor", "script-message-to mpvnet show-media-info editor"),
|
||||
("Show on screen", "script-message-to mpvnet show-media-info osd"),
|
||||
("Show full", "script-message-to mpvnet show-media-info editor full"),
|
||||
("Show raw", "script-message-to mpvnet show-media-info editor full raw") };
|
||||
|
||||
var list = pairs.Select(i => new CommandPaletteItem(i.Name, () => Core.Command(i.Value)));
|
||||
CommandPalette.Instance.SetItems(list);
|
||||
MainForm.Instance.ShowCommandPalette();
|
||||
CommandPalette.Instance.SelectFirst();
|
||||
return;
|
||||
}
|
||||
|
||||
string path = Core.GetPropertyString("path");
|
||||
string text = "";
|
||||
|
||||
bool full = args.Contains("full");
|
||||
bool raw = args.Contains("raw");
|
||||
bool editor = args.Contains("editor");
|
||||
bool osd = args.Contains("osd");
|
||||
|
||||
if (App.MediaInfo && !osd && File.Exists(path) && !path.Contains(@"\\.\pipe\"))
|
||||
using (MediaInfo mediaInfo = new MediaInfo(path))
|
||||
text = Regex.Replace(mediaInfo.GetSummary(full, raw), "Unique ID.+", "");
|
||||
else
|
||||
{
|
||||
Core.UpdateExternalTracks();
|
||||
lock (Core.MediaTracksLock)
|
||||
foreach (MediaTrack track in Core.MediaTracks)
|
||||
text += track.Text + BR;
|
||||
}
|
||||
|
||||
text = text.TrimEx();
|
||||
|
||||
if (editor)
|
||||
ShowTextWithEditor("media-info", text);
|
||||
else if (osd)
|
||||
ShowText(text.Replace("\r", ""), 5000, 17);
|
||||
else
|
||||
{
|
||||
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(() =>
|
||||
{
|
||||
Core.UpdateExternalTracks();
|
||||
|
||||
lock (Core.MediaTracksLock)
|
||||
{
|
||||
MediaTrack[] tracks = Core.MediaTracks.Where(track => track.Type == "a").ToArray();
|
||||
|
||||
if (tracks.Length < 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 + "/" + tracks.Length + ": " +
|
||||
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(() =>
|
||||
{
|
||||
Core.UpdateExternalTracks();
|
||||
|
||||
lock (Core.MediaTracksLock)
|
||||
{
|
||||
MediaTrack[] tracks = Core.MediaTracks.Where(track => track.Type == "s").ToArray();
|
||||
|
||||
if (tracks.Length < 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 + "/" + tracks.Length + ": " +
|
||||
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)
|
||||
};
|
||||
|
||||
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 + "\n\n" + 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 path in App.Settings.RecentFiles)
|
||||
{
|
||||
var file = App.GetTitleAndPath(path);
|
||||
|
||||
CommandPaletteItem item = new CommandPaletteItem()
|
||||
{
|
||||
Text = file.Title.ShortPath(60),
|
||||
Action = () => Core.LoadFiles(new[] { file.Path }, 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 Name, string Value)[] pairs = {
|
||||
("Register video file associations", "script-message-to mpvnet reg-file-assoc video"),
|
||||
("Register audio file associations", "script-message-to mpvnet reg-file-assoc audio"),
|
||||
("Register image file associations", "script-message-to mpvnet reg-file-assoc image"),
|
||||
("Unregister file associations", "script-message-to mpvnet reg-file-assoc unreg") };
|
||||
|
||||
var list = pairs.Select(i => new CommandPaletteItem(i.Name, () => Core.Command(i.Value)));
|
||||
CommandPalette.Instance.SetItems(list);
|
||||
MainForm.Instance.ShowCommandPalette();
|
||||
CommandPalette.Instance.SelectFirst();
|
||||
});
|
||||
|
||||
public static void SelectProfile() => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
var items = Core.ProfileNames.Where(i => !i.StartsWith("extension."))
|
||||
.Select(i => new CommandPaletteItem(i, () => {
|
||||
Core.CommandV("show-text", i);
|
||||
Core.CommandV("apply-profile", i);
|
||||
}));
|
||||
|
||||
CommandPalette.Instance.SetItems(items);
|
||||
MainForm.Instance.ShowCommandPalette();
|
||||
CommandPalette.Instance.SelectFirst();
|
||||
});
|
||||
|
||||
public static void ShowChapters() => App.InvokeOnMainThread(() =>
|
||||
{
|
||||
var items = Core.GetChapters().Select(i => new CommandPaletteItem(i.Title, i.TimeDisplay, () =>
|
||||
Core.CommandV("seek", i.Time.ToString(CultureInfo.InvariantCulture), "absolute")));
|
||||
|
||||
CommandPalette.Instance.SetItems(items);
|
||||
MainForm.Instance.ShowCommandPalette();
|
||||
CommandPalette.Instance.SelectFirst();
|
||||
});
|
||||
|
||||
public static void ShowMenu() => Core.RaiseShowMenu();
|
||||
|
||||
public static void PlaylistAdd(int value)
|
||||
{
|
||||
int pos = Core.PlaylistPos;
|
||||
int count = Core.GetPropertyInt("playlist-count");
|
||||
|
||||
if (count < 2)
|
||||
return;
|
||||
|
||||
pos = pos + value;
|
||||
|
||||
if (pos < 0)
|
||||
pos = count - 1;
|
||||
|
||||
if (pos > count - 1)
|
||||
pos = 0;
|
||||
|
||||
Core.SetPropertyInt("playlist-pos", pos);
|
||||
}
|
||||
|
||||
public static void QuickBookmark()
|
||||
{
|
||||
if (App.QuickBookmark == 0)
|
||||
{
|
||||
App.QuickBookmark = (float)Core.GetPropertyDouble("time-pos");
|
||||
|
||||
if (App.QuickBookmark != 0)
|
||||
Core.Command("show-text 'Bookmark Saved'");
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.SetPropertyDouble("time-pos", App.QuickBookmark);
|
||||
App.QuickBookmark = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Navigation;
|
||||
|
||||
using Tommy;
|
||||
|
||||
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,46 +47,53 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConfItem
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string Value { get; set; } = "";
|
||||
public string Comment { get; set; } = "";
|
||||
public string LineComment { get; set; } = "";
|
||||
public string Section { get; set; } = "";
|
||||
public string File { get; set; } = "";
|
||||
public string LineComment { get; set; } = "";
|
||||
public string Name { get; set; } = "";
|
||||
public string Section { get; set; } = "";
|
||||
public string Value { get; set; } = "";
|
||||
|
||||
public bool IsSectionItem { get; set; }
|
||||
public SettingBase SettingBase { get; set; }
|
||||
}
|
||||
|
||||
public abstract class SettingBase
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string File { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string Help { get; set; }
|
||||
public string Default { get; set; }
|
||||
public string URL { get; set; }
|
||||
public string File { get; set; }
|
||||
public string Filter { get; set; }
|
||||
public string Help { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string StartValue { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string URL { get; set; }
|
||||
public string Value { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
public ConfItem ConfItem { get; set; }
|
||||
}
|
||||
@@ -147,16 +147,18 @@ namespace DynamicGUI
|
||||
{
|
||||
void HyperLinkEx_RequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
Process.Start(e.Uri.AbsoluteUri);
|
||||
ProcessHelp.ShellExecute(e.Uri.AbsoluteUri);
|
||||
}
|
||||
|
||||
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,9 +4,8 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using static mpvnet.Core;
|
||||
using static mpvnet.Global;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
@@ -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
|
||||
ConsoleHelp.WriteError("Failed to load extension:\n\n" + extDir +
|
||||
"\n\nOnly extensions that ship with mpv.net are allowed in <startup>\\extensions" +
|
||||
"\n\nUser extensions have to use <config folder>\\extensions" +
|
||||
"\n\nNever copy or install a new mpv.net version over a old mpv.net version.");
|
||||
}
|
||||
}
|
||||
|
||||
dir = core.ConfigFolder + "extensions";
|
||||
string dir = Core.ConfigFolder + "extensions";
|
||||
|
||||
if (Directory.Exists(dir))
|
||||
foreach (string extDir in Directory.GetDirectories(dir))
|
||||
132
src/Misc/ExtensionMethods.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public static class TestStringExtension
|
||||
{
|
||||
public static bool ContainsEx(this string instance, string value)
|
||||
{
|
||||
if (instance != null && value != null)
|
||||
return instance.Contains(value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool StartsWithEx(this string instance, string value)
|
||||
{
|
||||
if (instance != null && value != null)
|
||||
return instance.StartsWith(value);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConvertToStringExtension
|
||||
{
|
||||
public static string ToUpperEx(this string instance)
|
||||
{
|
||||
if (instance != null)
|
||||
return instance.ToUpperInvariant();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string ToLowerEx(this string instance)
|
||||
{
|
||||
if (instance != null)
|
||||
return instance.ToLowerInvariant();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string TrimEx(this string instance)
|
||||
{
|
||||
if (instance == null)
|
||||
return "";
|
||||
|
||||
return instance.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConvertStringExtension
|
||||
{
|
||||
public static int ToInt(this string instance)
|
||||
{
|
||||
int.TryParse(instance, out int result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float ToFloat(this string instance)
|
||||
{
|
||||
float.TryParse(instance.Replace(",", "."), NumberStyles.Float,
|
||||
CultureInfo.InvariantCulture, out float result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PathStringExtension
|
||||
{
|
||||
public static string Ext(this string filepath) => Ext(filepath, false);
|
||||
|
||||
public static string Ext(this string filepath, bool includeDot)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filepath))
|
||||
return "";
|
||||
|
||||
char[] chars = filepath.ToCharArray();
|
||||
|
||||
for (int x = filepath.Length - 1; x >= 0; x--)
|
||||
{
|
||||
if (chars[x] == Path.DirectorySeparatorChar)
|
||||
return "";
|
||||
|
||||
if (chars[x] == '.')
|
||||
return filepath.Substring(x + (includeDot ? 0 : 1)).ToLowerInvariant();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string FileName(this string instance)
|
||||
{
|
||||
if (string.IsNullOrEmpty(instance))
|
||||
return "";
|
||||
|
||||
int index = instance.LastIndexOf('\\');
|
||||
|
||||
if (index > -1)
|
||||
return instance.Substring(index + 1);
|
||||
|
||||
index = instance.LastIndexOf('/');
|
||||
|
||||
if (index > -1)
|
||||
return instance.Substring(index + 1);
|
||||
|
||||
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)
|
||||
{
|
||||
if (string.IsNullOrEmpty(instance))
|
||||
return "";
|
||||
|
||||
if (!instance.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
instance = instance + Path.DirectorySeparatorChar;
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/Misc/Global.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
public class Global
|
||||
{
|
||||
public static string BR = Environment.NewLine;
|
||||
public static string BR2 = Environment.NewLine + Environment.NewLine;
|
||||
|
||||
public static CorePlayer Core { get; } = new CorePlayer();
|
||||
}
|
||||
}
|
||||
188
src/Misc/GlobalHotkey.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static mpvnet.Global;
|
||||
|
||||
namespace mpvnet
|
||||
{
|
||||
class GlobalHotkey
|
||||
{
|
||||
public static Dictionary<int, string> Commands { get; set; }
|
||||
static int ID;
|
||||
static IntPtr HWND;
|
||||
|
||||
public static void RegisterGlobalHotkeys(IntPtr hwnd)
|
||||
{
|
||||
HWND = hwnd;
|
||||
string path = Core.ConfigFolder + "global-input.conf";
|
||||
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
foreach (string i in File.ReadAllLines(path))
|
||||
{
|
||||
string line = i.Trim();
|
||||
|
||||
if (line.StartsWith("#") || !line.Contains(" "))
|
||||
continue;
|
||||
|
||||
ProcessGlobalHotkeyLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessGlobalHotkeyLine(string line)
|
||||
{
|
||||
string key = line.Substring(0, line.IndexOf(" "));
|
||||
string command = line.Substring(line.IndexOf(" ") + 1);
|
||||
string[] parts = key.Split('+');
|
||||
KeyModifiers mod = KeyModifiers.None;
|
||||
int vk;
|
||||
|
||||
for (int i = 0; i < parts.Length - 1; i++)
|
||||
{
|
||||
string umod = parts[i].ToUpper();
|
||||
|
||||
if (umod == "ALT") mod |= KeyModifiers.Alt;
|
||||
if (umod == "CTRL") mod |= KeyModifiers.Ctrl;
|
||||
if (umod == "SHIFT") mod |= KeyModifiers.Shift;
|
||||
if (umod == "WIN") mod |= KeyModifiers.Win;
|
||||
}
|
||||
|
||||
key = parts[parts.Length - 1];
|
||||
|
||||
if (key.Length == 1)
|
||||
{
|
||||
short result = VkKeyScanEx(key[0], GetKeyboardLayout(0));
|
||||
|
||||
int hi = result >> 8;
|
||||
int lo = result & 0xFF;
|
||||
|
||||
vk = lo;
|
||||
|
||||
if ((hi & 1) == 1) mod |= KeyModifiers.Shift;
|
||||
if ((hi & 2) == 2) mod |= KeyModifiers.Ctrl;
|
||||
if ((hi & 4) == 4) mod |= KeyModifiers.Alt;
|
||||
}
|
||||
else
|
||||
vk = mpv_to_VK(key);
|
||||
|
||||
if (Commands == null)
|
||||
Commands = new Dictionary<int, string>();
|
||||
|
||||
if (vk > 0)
|
||||
{
|
||||
Commands[ID] = command.Trim();
|
||||
bool success = RegisterHotKey(HWND, ID++, mod, vk);
|
||||
|
||||
if (!success)
|
||||
Terminal.WriteError(line + ": " + new Win32Exception().Message + "\n", "global-input.conf");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Execute(int id)
|
||||
{
|
||||
if (Commands.ContainsKey(id))
|
||||
Core.Command(Commands[id]);
|
||||
}
|
||||
|
||||
static int mpv_to_VK(string value)
|
||||
{
|
||||
switch (value.ToUpperEx())
|
||||
{
|
||||
case "NEXT" : return 0xB0; // VK_MEDIA_NEXT_TRACK
|
||||
case "PREV" : return 0xB1; // VK_MEDIA_PREV_TRACK
|
||||
case "STOP" : return 0xB2; // VK_MEDIA_STOP
|
||||
case "PLAYPAUSE" : return 0xB3; // VK_MEDIA_PLAY_PAUSE
|
||||
case "SLEEP" : return 0x5F; // VK_SLEEP
|
||||
case "RIGHT" : return 0x27; // VK_RIGHT
|
||||
case "UP" : return 0x26; // VK_UP
|
||||
case "LEFT" : return 0x25; // VK_LEFT
|
||||
case "DOWN" : return 0x28; // VK_DOWN
|
||||
case "PGUP" : return 0x21; // VK_PRIOR
|
||||
case "PGDWN" : return 0x22; // VK_NEXT
|
||||
case "PAUSE" : return 0x13; // VK_PAUSE
|
||||
case "PRINT" : return 0x2A; // VK_PRINT
|
||||
case "HOME" : return 0x24; // VK_HOME
|
||||
case "INS" : return 0x2D; // VK_INSERT
|
||||
case "KP_INS" : return 0x2D; // VK_INSERT
|
||||
case "DEL" : return 0x2E; // VK_DELETE
|
||||
case "KP_DEL" : return 0x2E; // VK_DELETE
|
||||
case "END" : return 0x23; // VK_END
|
||||
case "F1" : return 0x70; // VK_F1
|
||||
case "F2" : return 0x71; // VK_F2
|
||||
case "F3" : return 0x72; // VK_F3
|
||||
case "F4" : return 0x73; // VK_F4
|
||||
case "F5" : return 0x74; // VK_F5
|
||||
case "F6" : return 0x75; // VK_F6
|
||||
case "F7" : return 0x76; // VK_F7
|
||||
case "F8" : return 0x77; // VK_F8
|
||||
case "F9" : return 0x78; // VK_F9
|
||||
case "F10" : return 0x79; // VK_F10
|
||||
case "F11" : return 0x7A; // VK_F11
|
||||
case "F12" : return 0x7B; // VK_F12
|
||||
case "F13" : return 0x7C; // VK_F13
|
||||
case "F14" : return 0x7D; // VK_F14
|
||||
case "F15" : return 0x7E; // VK_F15
|
||||
case "F16" : return 0x7F; // VK_F16
|
||||
case "F17" : return 0x80; // VK_F17
|
||||
case "F18" : return 0x81; // VK_F18
|
||||
case "F19" : return 0x82; // VK_F19
|
||||
case "F20" : return 0x83; // VK_F20
|
||||
case "F21" : return 0x84; // VK_F21
|
||||
case "F22" : return 0x85; // VK_F22
|
||||
case "F23" : return 0x86; // VK_F23
|
||||
case "F24" : return 0x87; // VK_F24
|
||||
case "ENTER" : return 0x0D; // VK_RETURN
|
||||
case "KP_ENTER" : return 0x0D; // VK_RETURN
|
||||
case "TAB" : return 0x09; // VK_TAB
|
||||
case "MENU" : return 0x5D; // VK_APPS
|
||||
case "CANCEL" : return 0x03; // VK_CANCEL
|
||||
case "BS" : return 0x08; // VK_BACK
|
||||
case "KP_DEC" : return 0x6E; // VK_DECIMAL
|
||||
case "ESC" : return 0x1B; // VK_ESCAPE
|
||||
case "KP0" : return 0x60; // VK_NUMPAD0
|
||||
case "KP1" : return 0x61; // VK_NUMPAD1
|
||||
case "KP2" : return 0x62; // VK_NUMPAD2
|
||||
case "KP3" : return 0x63; // VK_NUMPAD3
|
||||
case "KP4" : return 0x64; // VK_NUMPAD4
|
||||
case "KP5" : return 0x65; // VK_NUMPAD5
|
||||
case "KP6" : return 0x66; // VK_NUMPAD6
|
||||
case "KP7" : return 0x67; // VK_NUMPAD7
|
||||
case "KP8" : return 0x68; // VK_NUMPAD8
|
||||
case "KP9" : return 0x69; // VK_NUMPAD9
|
||||
case "FAVORITES" : return 0xAB; // VK_BROWSER_FAVORITES
|
||||
case "SEARCH" : return 0xAA; // VK_BROWSER_SEARCH
|
||||
case "MAIL" : return 0xB4; // VK_LAUNCH_MAIL
|
||||
case "VOLUME_UP" : return 0xAF; // VK_VOLUME_UP
|
||||
case "VOLUME_DOWN": return 0xAE; // VK_VOLUME_DOWN
|
||||
case "MUTE" : return 0xAD; // VK_VOLUME_MUTE
|
||||
case "SPACE" : return 0x20; // VK_SPACE
|
||||
case "IDEOGRAPHIC_SPACE": return 0x20; // VK_SPACE
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
static extern short VkKeyScanEx(char ch, IntPtr dwhkl);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern IntPtr GetKeyboardLayout(uint idThread);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, int vk);
|
||||
|
||||
[Flags]
|
||||
enum KeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Alt = 1,
|
||||
Ctrl = 2,
|
||||
Shift = 4,
|
||||
Win = 8
|
||||
}
|
||||
}
|
||||
}
|
||||
217
src/Misc/Help.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
using (Process proc = new Process())
|
||||
{
|
||||
proc.StartInfo.FileName = file;
|
||||
proc.StartInfo.Arguments = arguments;
|
||||
proc.StartInfo.UseShellExecute = false;
|
||||
proc.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShellExecute(string file, string arguments = null)
|
||||
{
|
||||
using (Process proc = new Process())
|
||||
{
|
||||
proc.StartInfo.FileName = file;
|
||||
proc.StartInfo.Arguments = arguments;
|
||||
proc.StartInfo.UseShellExecute = true;
|
||||
proc.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CursorHelp
|
||||
{
|
||||
static bool IsVisible = true;
|
||||
|
||||
public static void Show()
|
||||
{
|
||||
if (!IsVisible)
|
||||
{
|
||||
Cursor.Show();
|
||||
IsVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Hide()
|
||||
{
|
||||
if (IsVisible)
|
||||
{
|
||||
Cursor.Hide();
|
||||
IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsPosDifferent(Point screenPos)
|
||||
{
|
||||
return Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
|
||||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
|
||||
}
|
||||
}
|
||||
|
||||
public class mpvHelp
|
||||
{
|
||||
public static string GetProfiles()
|
||||
{
|
||||
string json = Core.GetPropertyString("profile-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.Append(i["name"].ToString() + BR2);
|
||||
|
||||
foreach (Dictionary<string, object> i2 in i["options"] as List<object>)
|
||||
sb.AppendLine(" " + i2["key"] + " = " + i2["value"]);
|
||||
|
||||
sb.Append(BR);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GetDecoders()
|
||||
{
|
||||
string json = Core.GetPropertyString("decoder-list");
|
||||
var o = json.FromJson<List<Dictionary<string, object>>>().OrderBy(i => i["codec"]);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (Dictionary<string, object> i in o)
|
||||
sb.AppendLine(i["codec"] + " - " + i["description"]);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string GetProtocols()
|
||||
{
|
||||
string list = Core.GetPropertyString("protocol-list");
|
||||
return string.Join(BR, list.Split(',').OrderBy(a => a));
|
||||
}
|
||||
|
||||
public static string GetDemuxers()
|
||||
{
|
||||
string list = Core.GetPropertyString("demuxer-lavf-list");
|
||||
return string.Join(BR, list.Split(',').OrderBy(a => a));
|
||||
}
|
||||
}
|
||||
|
||||
public class RegistryHelp
|
||||
{
|
||||
public static string ApplicationKey { get; } = @"HKCU\Software\" + Application.ProductName;
|
||||
|
||||
public static void SetInt(string name, object value)
|
||||
{
|
||||
SetValue(ApplicationKey, name, value);
|
||||
}
|
||||
|
||||
public static void SetString(string name, string value)
|
||||
{
|
||||
SetValue(ApplicationKey, name, value);
|
||||
}
|
||||
|
||||
public static void SetValue(string name, object value)
|
||||
{
|
||||
using (RegistryKey regKey = GetRootKey(ApplicationKey).CreateSubKey(ApplicationKey.Substring(5), RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
regKey.SetValue(name, value);
|
||||
}
|
||||
|
||||
public static void SetValue(string path, string name, object value)
|
||||
{
|
||||
using (RegistryKey regKey = GetRootKey(path).CreateSubKey(path.Substring(5), RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
regKey.SetValue(name, value);
|
||||
}
|
||||
|
||||
public static string GetString(string name, string defaultValue = "")
|
||||
{
|
||||
object value = GetValue(ApplicationKey, name, defaultValue);
|
||||
return !(value is string) ? defaultValue : value.ToString();
|
||||
}
|
||||
|
||||
public static int GetInt(string name, int defaultValue = 0)
|
||||
{
|
||||
object value = GetValue(ApplicationKey, name, defaultValue);
|
||||
return !(value is int) ? defaultValue : (int)value;
|
||||
}
|
||||
|
||||
public static object GetValue(string name) => GetValue(ApplicationKey, name, null);
|
||||
|
||||
public static object GetValue(string path, string name, object defaultValue = null)
|
||||
{
|
||||
using (RegistryKey regKey = GetRootKey(path).OpenSubKey(path.Substring(5)))
|
||||
return regKey == null ? null : regKey.GetValue(name, defaultValue);
|
||||
}
|
||||
|
||||
public static void RemoveKey(string path)
|
||||
{
|
||||
try {
|
||||
GetRootKey(path).DeleteSubKeyTree(path.Substring(5), false);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
public static void RemoveValue(string path, string name)
|
||||
{
|
||||
try {
|
||||
using (RegistryKey regKey = GetRootKey(path).OpenSubKey(path.Substring(5), true))
|
||||
if (regKey != null)
|
||||
regKey.DeleteValue(name, false);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
static RegistryKey GetRootKey(string path)
|
||||
{
|
||||
switch (path.Substring(0, 4))
|
||||
{
|
||||
case "HKLM": return Registry.LocalMachine;
|
||||
case "HKCU": return Registry.CurrentUser;
|
||||
case "HKCR": return Registry.ClassesRoot;
|
||||
default: throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||