Compare commits

..

63 Commits

Author SHA1 Message Date
stax76
7f680829ef update changelog 2022-07-30 13:05:30 +02:00
stax76
603f956261 update changelog 2022-07-30 12:55:32 +02:00
stax76
6d06df9004 6.0.3.1 2022-07-30 12:52:19 +02:00
stax76
5ea086d05b Support --audio-file and --sub-file aliases 2022-07-30 11:45:07 +02:00
stax76
1ad819fa9d Fix external audio tracks not shown correctly in tracks context menu 2022-07-30 11:26:45 +02:00
stax76
f2dd6205b5 Merge branch 'master' of https://github.com/stax76/mpv.net 2022-07-27 09:42:02 +02:00
stax76
b2a3c231ff command line syntax is supported in mpv.conf 2022-07-27 09:42:00 +02:00
stax76
f6c223a411 Update issue templates 2022-07-25 09:51:28 +02:00
stax76
e7a2ba6805 Update issue templates 2022-07-25 09:43:58 +02:00
stax76
5a08d9ccd6 Shift key enables process-instance=multi 2022-07-23 08:50:07 +02:00
stax76
5714a5e62a Merge branch 'master' of https://github.com/stax76/mpv.net 2022-07-17 08:04:43 +02:00
stax76
def7e5ac5a misc 2022-07-17 08:04:32 +02:00
stax76
601bb20492 Update FUNDING.yml 2022-07-14 04:31:20 +02:00
stax76
59600df977 update manual 2022-07-13 09:02:51 +02:00
stax76
e1b9730e9b use mpv.net to cycle subtitles 2022-07-12 05:49:05 +02:00
stax76
e378551938 misc 2022-07-11 13:14:26 +02:00
stax76
a82b2ef571 disable unused mpv events 2022-07-11 07:05:50 +02:00
stax76
6157a01701 disable unused mpv events 2022-07-11 06:57:10 +02:00
stax76
ec17ae8ce9 support shortcuts with media file target 2022-07-11 06:14:01 +02:00
stax76
f719528017 fix #293 2022-07-10 10:30:01 +02:00
stax76
966b45eb65 shorten annoying media info titles 2022-07-10 00:49:56 +02:00
stax76
eeae6994a2 remove basic view and enhance advanced view of show-info command 2022-07-09 17:26:49 +02:00
stax76
07809d882f use mpvnet instead of mpv to create playlist from folder 2022-07-08 12:20:36 +02:00
stax76
e970f0b4e4 libmpv shinchiro 2022-07-02 2022-07-08 05:51:06 +02:00
stax76
a36b6a3fdf misc 2022-07-04 08:45:37 +02:00
stax76
4febca257f properly fix OSC hide behavior 2022-07-04 08:32:53 +02:00
stax76
9d493b4d08 store package update 2022-07-03 10:49:13 +02:00
stax76
9a6bf5a481 v6.0.3.0 update changelog 2022-07-03 10:35:39 +02:00
stax76
40565e8b3d fix possible race condition 2022-07-02 15:10:22 +02:00
stax76
fb294c441d 6.0.2.0 2022-07-02 10:19:19 +02:00
stax76
03b775370b window title fix 2022-07-02 09:35:15 +02:00
stax76
1015f87533 changelog fix 2022-06-30 15:19:42 +02:00
stax76
cadc5d65cf 6.0.1.0 2022-06-30 15:00:07 +02:00
stax76
3e2f104aa7 fix #449 2022-06-28 15:17:35 +02:00
stax76
c87ce3b66f fix #449 2022-06-28 07:53:48 +02:00
stax76
3093dd43a4 add smart-volume script to changelog 2022-06-27 15:03:26 +02:00
stax76
061bb39b60 improve changlog 2022-06-25 16:22:05 +02:00
stax76
d994c79d5d fix #372 2022-06-25 16:18:16 +02:00
stax76
9ca66db07b Merge pull request #448 from soredake/patch-1
Add two new keybinds for controlling volume
2022-06-25 16:02:22 +02:00
stax76
4a382d4e29 border issue 2022-06-25 13:56:45 +02:00
stax76
69a5ba4470 Fix #445 chapters that are script created after the media file is loaded 2022-06-25 13:07:17 +02:00
soredake
4a890a4da7 Add two new keybinds for controlling volume
This keybinds is used in mpv, - + are intuitive for controlling volume, but i have compact keyboard without numpad, and pressing + in number row requires me to press it with shift, which i want to avoid.
2022-06-23 21:23:29 +03:00
stax76
023c1db417 recent list path normalization 2022-06-20 19:29:39 +02:00
stax76
7ef1f9315e Width of command palette slightly increased 2022-06-20 19:24:24 +02:00
stax76
a148c88435 new option minimum-aspect-ratio-audio 2022-06-19 18:06:08 +02:00
stax76
f6ad169f9d show Default only when track count is > 1 2022-06-19 08:21:31 +02:00
stax76
e69a5559e8 Fix start-size=session not working 2022-06-19 07:51:30 +02:00
stax76
500fe9abc4 #442 show chapters in the command palette 2022-06-19 05:23:10 +02:00
stax76
55f4a340af setting env var MPVNET_VERSION 2022-06-14 15:09:56 +02:00
stax76
b17ed3675e #334 New support of the mpv option snap-window 2022-06-11 09:32:02 +02:00
stax76
34031fa15d Fix borderless window not resizable with mouse 2022-06-09 21:48:35 +02:00
stax76
d6d31d8ae9 Fix compatibility with mpv-osc-tethys 2022-06-09 19:37:42 +02:00
stax76
0bfee26418 logo change 2022-06-09 10:25:06 +02:00
stax76
71d6b96c10 Fix logo overlap using mordenx.lua 2022-06-09 08:27:45 +02:00
stax76
d1b7250a7a changelog update 2022-06-08 21:39:36 +02:00
stax76
39b81d0664 manual update 2022-06-08 21:05:42 +02:00
stax76
6337818dbc New options autofit-image and autofit-audio 2022-06-08 10:16:40 +02:00
stax76
2257af6294 change minimum-aspect-ratio default value to 0 2022-06-07 23:00:10 +02:00
stax76
572257b645 change minimum-aspect-ratio default value to 1 2022-06-07 22:51:52 +02:00
stax76
6eb82b6b7e Merge pull request #437 from hooke007/doc
bump Manual_chs v6.0.0.0
2022-06-06 19:30:56 +02:00
hooke007
7ef703da42 bump Manual_chs v6.0.0.0 2022-06-06 17:12:09 +01:00
stax76
f7f8aa550a use filtered-metadata option for music osd 2022-06-05 18:55:08 +02:00
stax76
8d693b5e01 fix minor conf editor issue 2022-06-05 17:26:44 +02:00
27 changed files with 971 additions and 384 deletions

1
.github/FUNDING.yml vendored
View File

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

View File

@@ -8,3 +8,33 @@ assignees: stax76
---
This template is meant for usage questions of mpv.net.
Some type of questions like questions about a problem require filling out an issue template:
**Describe the problem**
A clear and concise description of what the problem is.
**To Reproduce**
To reproduce, try the last beta version using the CLI option `--config=no`.
In case of an audio or video problem, try to reproduce the problem using mpv instead of mpv.net.
If it can be reproduced with mpv, use the [mpv issue tracker](https://github.com/mpv-player/mpv/issues).
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
1. mpv.net version
2. Windows version
3. GPU name
4. Media info

View File

@@ -11,6 +11,11 @@ assignees: stax76
A clear and concise description of what the bug is.
**To Reproduce**
To reproduce, try the last beta version using the CLI option `--config=no`.
In case of an audio or video issue, try to reproduce the issue using mpv instead of mpv.net.
If it can be reproduced with mpv, use the [mpv issue tracker](https://github.com/mpv-player/mpv/issues).
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
@@ -25,3 +30,7 @@ If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
1. mpv.net version
2. Windows version
3. GPU name
4. Media info

View File

@@ -16,10 +16,6 @@ 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
Modern GUI with customizable color themes.

View File

@@ -1,4 +1,69 @@
# 6.0.3.1 (2022-07-30)
- Creating a playlist from a folder uses absolute normalized paths, non-media files are ignored.
- The show-info command shows directly an advanced view, which was enhanced with a General section and the filename.
- Media info titles are shortened if they contain duplicated or obvious information.
- Support of shortcuts (.lnk files) with media file target.
- Support --audio-file and --sub-file aliases.
- playlist-random command jumps to a random playlist entry, default key binding is F9.
- Fix OSC hide behavior on mouse move.
- Fix external audio tracks not shown correctly in tracks context menu.
- New binding (e key) to show the current file in File Explorer.
- Shift key enables `process-instance=multi`.
- Command line syntax (preceding double hyphen) is supported in mpv.conf for options implemented by mpv.net.
- MediaInfo v22.06
- libmpv shinchiro 2022-07-30
input.conf changes:
New:
```
e run powershell -command "explorer.exe '/select,' ( \"${path}\" -replace '/', '\\' )" #menu: Tools > Show current file in File Explorer
F9 script-message-to mpvnet playlist-random #menu: Navigate > Random File
```
# 6.0.3.0 (2022-07-03)
- Fix the rare occasion of duplicated playlist entries produced by the auto-load-folder feature.
# 6.0.2.0 (2022-07-02)
- Fix main window shown collapsed when the player was started with full screen.
# 6.0.1.0 (2022-06-30)
- 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

View File

@@ -42,9 +42,7 @@ 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.
Like mpv, mpv.net is designed for power users.
Download
@@ -90,12 +88,21 @@ the files are opened in mpv.net in random order, this works with maximum 15 file
Support
-------
Before making a support request, please try the newest version first.
Before making a support request, please try the newest [beta version](../../../releases) first.
Bugs and feature requests can be made on the github [issue tracker](../../../issues),
feel free to use for anything mpv.net related, usage questions are welcome.
Support can be requested here:
Or use the [support thread](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows) in the VideoHelp forum.
Beginner questions:
https://www.reddit.com/r/mpv
mpv.net bug reports, feature requests and advanced questions:
https://github.com/stax76/mpv.net/issues
Advanced mpv questions:
https://github.com/mpv-player/mpv/issues
Settings
@@ -270,6 +277,9 @@ already the first entry, nothing happens.
Jumps to the last playlist entry, if the loaded file is
already the last entry, nothing happens.
### playlist-random
Jumps to a random playlist entry.
### quick-bookmark
On the first press a bookmark is saved, on the second
@@ -282,6 +292,9 @@ Registers the file associations.
### scale-window \<factor\>
Decreases or increases the Window size.
### select-profile
Shows the command palette to select a profile.
### shell-execute \<file|URL\>
Shell executes a single file or URL.
@@ -295,6 +308,9 @@ Shows available audio devices in a message box.
Shows available audio tracks in the command palette
and allows to load the selected audio track.
### show-chapters
Shows chapters in the command palette.
### show-command-palette
Shows the command palette.
@@ -314,9 +330,6 @@ Shows available demuxers.
Shows the history file when existing.
### show-info
Shows media info on screen, a second key press shows more detailed media info.
### show-input-editor
Shows the input editor.
@@ -381,6 +394,12 @@ mpv.net specific options can be found in the conf editor searching for 'mpv.net'
The options are saved in the mpvnet.conf file.
#### --autofit-audio \<integer\>
Initial window height in percent for audio files. Default: 70
#### --autofit-image \<integer\>
Initial window height in percent for image files. Default: 80
#### --queue \<files\>
Adds files to the playlist, requires [--process-instance=single](#--process-instancevalue).
@@ -425,22 +444,24 @@ Window size is remembered in the current session.
**always**
Window size is always remembered.
#### --start-threshold=\<milliseconds\>
Threshold in milliseconds to wait for libmpv returning the video
resolution before the window is shown, otherwise default dimensions
are used as defined by autofit and start-size. Default: 1500
#### --minimum-aspect-ratio=\<float\>
Minimum aspect ratio, if the AR is smaller than the defined value then
the window AR is set to 16/9. This avoids a square window for Music
with cover art. Default: 1.2
Minimum aspect ratio of the window. Useful to force
a wider window and therefore a larger OSC.
#### --minimum-aspect-ratio-audio=\<float\>
Same as minimum-aspect-ratio but used for audio files.
#### --remember-window-position=\<yes|no\>
Save the window position on exit. Default: no
#### --start-threshold=\<milliseconds\>
Threshold in milliseconds to wait for libmpv returning the video
resolution before the window is shown, otherwise default dimensions
are used as defined by autofit and start-size. Default: 1500
### Playback
@@ -461,10 +482,12 @@ playback automatically resumes.
Defines if more then one mpv.net process is allowed.
Tip: Whenever the CTRL key is pressed when files or URLs are opened,
Whenever the CTRL key is pressed when files or URLs are opened,
the playlist is not cleared but the files or URLs are appended to the playlist.
This not only works on process startup but in all mpv.net features that open files and URLs.
Multi can alternatively be enabled by pressing the SHIFT key.
**multi**
Create a new process everytime the shell starts mpv.net.
@@ -532,7 +555,7 @@ Draws the blue mpv.net logo ontop of the native OSC logo. Default: yes
#### --show-santa-logo=\<yes|no\>
Draws the blue mpv.net logo with a santa hat in december,
the option is called green and grumpy in mpv. Default: yes
the option is called greenandgrumpy in mpv. Default: yes
External Tools
--------------
@@ -558,31 +581,6 @@ Alternatively the Chrome/Firefox extension [Open With](../../../issues/119) can
[Open with++](https://github.com/stax76/OpenWithPlusPlus) can be used to extend the File Explorer context menu to get menu items for [Play with mpv.net](https://github.com/stax76/OpenWithPlusPlus#play-with-mpvnet) and [Add to mpv.net playlist](https://github.com/stax76/OpenWithPlusPlus#add-to-mpvnet-playlist).
### Universal Remote Android app
Universal Remote is Android remote control app which costs 5 €.
https://www.unifiedremote.com
https://play.google.com/store/apps/details?id=com.Relmtech.Remote
https://play.google.com/store/apps/details?id=com.Relmtech.RemotePaid
https://www.unifiedremote.com/tutorials/how-to-create-a-custom-keyboard-shortcuts-remote
https://www.unifiedremote.com/tutorials/how-to-install-a-custom-remote
[My config](./Universal%20Remote)
Very useful is the Universal Remote File Browser feature.
### One For All Contour URC1210 and FLIRC USB
My primary remote control solution however is a One For All Contour URC1210
using Philips code 0556 together with FLIRC USB (gen2).
### External Application Button
Videos can be streamed or downloaded easily with the Chrome extension
@@ -598,64 +596,28 @@ Scripting
#### Lua
File Type: `lua`
A very large collection of Lua user scripts can be found in the mpv wiki [here](https://github.com/mpv-player/mpv/wiki/User-Scripts).
Location: `<config folder>\scripts`
The Lua script host is built into libmpv.
Error and debug messages are printed on the terminal.
Lua scripts are loaded before the first media file loads.
[mpv Lua documentation](https://mpv.io/manual/master/#lua-scripting)
[mpv user scripts in the wiki](https://github.com/mpv-player/mpv/wiki/User-Scripts)
[mpv user scripts on GitHub](https://github.com/topics/mpv-script)
[mpv user scripts found by Google](https://www.google.com/search?q=mpv+script)
Lua scripting is documented in the mpv.net wiki [here](https://github.com/stax76/mpv.net/wiki/Extending-mpv-and-mpv.net-via-Lua-scripting).
#### JavaScript
File Type: `js`
Location: `<config folder>\scripts`
The JavaScript script host is built into libmpv.
Error and debug messages are printed on the terminal.
JavaScript scripts are loaded before the first media file loads.
[mpv JavaScript documentation](https://mpv.io/manual/master/#javascript)
[mpv user scripts](https://github.com/mpv-player/mpv/wiki/User-Scripts)
#### PowerShell
File Type: `ps1`
Location: `<config folder>\scripts-ps`
The PowerShell scripting host is like extensions not
initialized before media files are loaded.
mpv.net does not define scripting interfaces but instead exposed
its complete internals, there are no compatibility guaranties.
The PowerShell scripting host is not initialized before media files are loaded.
[Example Scripts](../../../tree/master/src/Scripts)
#### C#
File Type: `cs`
Location: `<config folder>\scripts-cs`
mpv.net does not define scripting interfaces but instead exposed
its complete internals, there are no compatibility guaranties.
There are no compatibility guaranties.
Script code can be written within a C# [extension](../../../tree/master/src/Extensions),
that way full code completion and debugger support is available.
@@ -664,6 +626,10 @@ from the extension to a lightweight standalone script.
The script host uses an old C# version, modern features
like string interpolation are not available.
There are synchronous and asynchronous events, prefer asynchronous events
and don't block synchronous events and observed properties, as it would
block the main event loop.
The C# scripting host is like [extensions](../../../tree/master/src/Extensions)
not initialized before media files are loaded.
@@ -680,9 +646,9 @@ and the filename must have the same name as the directory:
<config folder>\extensions\ExampleExtension\ExampleExtension.dll
```
mpv.net does not define extension interfaces but instead exposed
its complete internals, there are no compatibility guaranties.
There are synchronous and asynchronous events, prefer asynchronous events
and don't block synchronous events and observed properties, as it would
block the main event loop.
### Walkthrough creating an extension
@@ -789,6 +755,7 @@ https://mpv.io/manual/master/#window
- [keepaspect-window](https://mpv.io/manual/master/#options-keepaspect-window)
- [ontop](https://mpv.io/manual/master/#options-ontop)
- [screen](https://mpv.io/manual/master/#options-screen)
- [snap-window](https://mpv.io/manual/master/#options-snap-window)
- [title](https://mpv.io/manual/master/#options-title)
- [window-maximized](https://mpv.io/manual/master/#options-window-maximized)
- [window-minimized](https://mpv.io/manual/master/#options-window-minimized)
@@ -797,9 +764,12 @@ https://mpv.io/manual/master/#window
**Partly implemented are:**
- [autofit-larger](https://mpv.io/manual/master/#options-autofit-larger)
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller)
- [autofit](https://mpv.io/manual/master/#options-autofit)
- [autofit-larger](https://mpv.io/manual/master/#options-autofit-larger)
Supported is a single integer value in the range 0-100.
- [autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller)
Supported is a single integer value in the range 0-100.
- [autofit](https://mpv.io/manual/master/#options-autofit)
Supported is a single integer value in the range 0-100.
mpv.net specific window features are documented in the [screen section](#screen).
@@ -1255,7 +1225,7 @@ Adds a negative audio delay using the following command:
Shows the next subtitle track using the following command:
`cycle sub`
`script-message-to mpvnet cycle-subtitles`
[cycle command](https://mpv.io/manual/master/#command-interface-cycle-%3Cname%3E-[%3Cvalue%3E])

View File

@@ -2,7 +2,7 @@
mpv.net手册
==============
适配版本 [v5.9.0.0-beta](https://github.com/stax76/mpv.net/releases/tag/v5.9.0.0-beta)
适配版本 [v6.0.0.0-beta](https://github.com/stax76/mpv.net/releases/tag/v6.0.0.0-beta)
**[ENGLISH](Manual.md)** | **简体中文**
@@ -62,8 +62,10 @@ mpv专注命令行与终端的使用而mpv.net保留了这些并加入了现
mpv.net需要.NET Framework 4.8运行库和高于win7版本的系统以及一张不太旧的显卡。
对于来自YouTube和类似网站的网络流必须将yt-dlp复制到mpv.net的文件夹中
或编辑用户环境变量PATH使其包括yt-dlp的文件夹。
互联网流媒体需要:
- 下载[yt-dlp](https://github.com/yt-dlp/yt-dlp)并将其添加到[用户环境变量PATH](https://www.google.com/search?q=user+environment+variable+PATH)
- 在使用代理服务器的情况下,需要[手动配置](https://github.com/stax76/mpv.net/issues/401)。
#### 文件关联
@@ -215,7 +217,7 @@ mpv有一些基于非属性的开关在mpv.net中一般不受支持。
mpv.net的专属命令
-------------------------
`script-message mpv.net <command> <arguments>`
`script-message-to mpvnet <command> <arguments>`
mpv.net命令可在mpv命令不存在或缺乏某种功能时使用。
@@ -232,14 +234,11 @@ mpv.net命令可在mpv命令不存在或缺乏某种功能时使用。
用Windows资源管理器打开配置文件夹。
### open-files [\<flags\>]
**no-folder**
对于单个文件,防止将文件夹内的全部文件加载到播放列表中。
**append**
追加文件到播放列表中。
打开一个资源管理器的对话框,以便选择要打开的文件。资源管理器的对话框支持多选以
一次性加载多个文件。按住CTRL键可以将这些文件追加到播放列表中。
打开一个资源管理器的对话框,以便选择要打开的文件。资源管理器的对话框
支持多选以一次性加载多个文件。按住CTRL键可以将这些文件追加到播放列表中。
### open-optical-media
显示一个资源管理器的对话框来打开一个DVD或BD文件夹。ISO镜像不需要被挂载
@@ -260,6 +259,10 @@ mpv.net命令可在mpv命令不存在或缺乏某种功能时使用。
### playlist-last
跳转到播放列表的最后一个条目,如果加载的文件已经是最后一个条目,则无动作。
### quick-bookmark
第一次触发时,书签被保存,第二次触发时,它被恢复并移除。当加载新文件时,
书签也会被移除。
### reg-file-assoc \<audio|video|image\>
注册文件关联。
@@ -297,7 +300,7 @@ Shell执行单个文件或URL。
显示已有的历史文件。
### show-info
显示一个简易的文件信息。
在屏幕上显示mediainfo第二次触发可显示更详细的媒体信息。
### show-input-editor
显示器快捷键编辑器。
@@ -312,6 +315,9 @@ Shell执行单个文件或URL。
**editor**
在一个文本编辑器中显示mediainfo
**osd**
OSD上显示mediainfo
**full**
显示mediainfo的完整细节
@@ -328,7 +334,7 @@ Shell执行单个文件或URL。
用一个信息框显示可用的profile
### show-progress
显示一个简易的OSD进度条信息。
显示一个简易的OSD进度条信息,附带时间和日期
### show-properties
在命令面板中显示可用的属性,并允许显示所选属性的值。
@@ -363,8 +369,8 @@ mpv.net的专属选项
#### --command=\<input command\>
通过命令行向正在运行的mpv.net实例发送输入命令例如使用 AutoHotkey 创建全局热键,
必须设置 [process-instance=single](#--process-instancevalue) 。
通过命令行向正在运行的mpv.net实例发送输入命令例如使用 AutoHotkey 创建
全局热键,必须设置 [process-instance=single](#--process-instancevalue) 。
### Audio
@@ -430,12 +436,6 @@ mpv.net的专属选项
如果在播放器暂停时,加载另一个文件,会自动恢复播放。
#### --keep-open-exit
如果设置为yes并且keep-open设置为nompv.net将在播完最后一个文件后退出。
在mpv中可以使用idle属性但对mpv.net来说不可能实现它。
### General
#### --process-instance=\<value\>
@@ -460,6 +460,11 @@ mpv.net的专属选项
最近文件的记录数量。默认15
#### --media-info=\<yes|no\>
使用MediaInfo而不是mpv来访问媒体信息。默认yes
#### --video-file-extensions=\<string\>
用于创建文件关联的视频文件扩展名,由自动加载文件夹的功能使用。
@@ -512,7 +517,12 @@ mpv.net的专属选项
#### --show-logo=\<yes|no\>
在原始OSC标志的基础上绘制蓝色的mpvnet图标。更改将在应用程序重新启动后生效。默认yes
在原始OSC标志的基础上绘制蓝色的mpvnet图标。默认yes
#### --show-santa-logo=\<yes|no\>
在12月绘制蓝色的mpvnet图标时使用圣诞彩蛋。默认yes
外部工具
@@ -642,9 +652,10 @@ mpv.net没有定义脚本接口而是公开了它的完整内部没有兼
mpv.net没有定义脚本接口而是公开了它的完整内部没有兼容性保证。
脚本代码可以在C#[扩展](../../../tree/master/src/Extensions)中编写,这样就可以获得
完整的代码和调试器支持。一旦代码被调试和开发完成,就可以将其从扩展转移到轻量级的独立脚本。
脚本host使用的是旧的C#版本,像字符串插值这样的现代功能是不存在的。
脚本代码可以在C#[扩展](../../../tree/master/src/Extensions)中编写,这样
就可以获得完整的代码和调试器支持。一旦代码被调试和开发完成,就可以将其
从扩展转移到轻量级的独立脚本。脚本host使用的是旧的C#版本,像字符串插值
这样的现代功能是不存在的。
C#脚本的host类似于[扩展](../../../tree/master/src/Extensions),在打开媒体文件前尚未初始化。
@@ -789,6 +800,13 @@ mpv.net支持基于属性的mpv命令行选项这意味着它支持mpv几乎
--version
### 其它限制
mpv的属性 [idle](https://mpv.io/manual/master/#options-idle) 在mpv.net中
也会相应的发挥作用但是LUA脚本获取到的值始终是 `yes` 因为mpv.net必须
设置它才能正常工作这是一个难以攻克的来自libmpv的限制。
### mpv.net的专属选项
在config editor中输入 `mpv.net` 检索这些选项,在[此处](#mpvnet的专属选项)的手册中有对应说明。
@@ -1481,8 +1499,8 @@ input.conf 文件内涵mpv的键鼠绑定
### Tools > Show History
显示包含历史记录的文本文件。如果文件不存在,则会询问是否在设置文件夹中创建该文件。
一旦文件存在,则写入历史记录(包括时间和文件名)
显示包含历史记录的文本文件。如果文件不存在,则会询问是否在设置文件夹中
创建该文件。一旦文件存在,则写入历史记录(包括时间和文件名)
屏蔽部分路径的参数:

View File

@@ -36,7 +36,10 @@ namespace mpvnet
public static int StartThreshold { get; set; } = 1500;
public static int RecentCount { get; set; } = 15;
public static float MinimumAspectRatio { get; set; } = 1.2f;
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; }
@@ -241,6 +244,8 @@ namespace mpvnet
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;
@@ -248,6 +253,7 @@ namespace mpvnet
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;

View File

@@ -24,20 +24,19 @@ namespace mpvnet
{
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 "cycle-subtitles": CycleSubtitles(); break;
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 "playlist-random": PlaylistRandom(); 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;
@@ -46,6 +45,7 @@ namespace mpvnet
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;
@@ -63,10 +63,20 @@ namespace mpvnet
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;
// deprecated 2019
case "add-files-to-playlist": OpenFiles("append"); break;
// deprecated 2020
case "execute-mpv-command": Msg.ShowError("command was removed, reset input.conf by deleting it, in the new menu use the on screen console."); break;
case "key-binding": if (args[0] == "show-playlist") ShowPlaylist(); break;
// deprecated 2022
case "show-setup-dialog": ShowSetupDialog(); break;
case "open-url": OpenFromClipboard(); break;
}
}
@@ -154,97 +164,42 @@ namespace mpvnet
}
}
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 performer, title, album, genre, date, duration, text = "";
string text;
long fileSize = 0;
string path = Core.GetPropertyString("path");
if (path.Contains("://"))
path = Core.GetPropertyString("media-title");
if (File.Exists(path))
{
fileSize = new FileInfo(path).Length;
if (CorePlayer.AudioTypes.Contains(path.Ext()))
{
if (App.MediaInfo)
{
using (MediaInfo mediaInfo = new MediaInfo(path))
{
performer = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Performer");
title = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Title");
album = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Album");
genre = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Genre");
date = mediaInfo.GetInfo(MediaInfoStreamKind.General, "Recorded_Date");
duration = mediaInfo.GetInfo(MediaInfoStreamKind.Audio, "Duration/String");
if (performer != "") text += "Artist: " + performer + "\n";
if (title != "") text += "Title: " + title + "\n";
if (album != "") text += "Album: " + album + "\n";
if (genre != "") text += "Genre: " + genre + "\n";
if (date != "") text += "Year: " + date + "\n";
if (duration != "") text += "Length: " + duration + "\n";
text += "Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n";
text += "Type: " + path.Ext().ToUpper();
}
}
else
{
text = "File: " + path.FileName() + "\n";
duration = TimeSpan.FromSeconds((int)Core.GetPropertyDouble("duration")).ToString();
if (duration != "") text += "Length: " + duration + "\n";
if (fileSize > 0) text += "Size: " + Convert.ToInt32(fileSize / 1024.0 / 1024.0) + " MB\n";
text += "Type: " + path.Ext().ToUpper();
}
text = Core.GetPropertyOsdString("filtered-metadata");
Core.CommandV("show-text", text, "5000");
return;
}
else if (CorePlayer.ImageTypes.Contains(path.Ext()))
{
if (App.MediaInfo)
{
using (MediaInfo mediaInfo = new MediaInfo(path))
{
text = "Width: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Width") + "\n" +
"Height: " + mediaInfo.GetInfo(MediaInfoStreamKind.Image, "Height") + "\n" +
"Size: " + mediaInfo.GetInfo(MediaInfoStreamKind.General, "FileSize/String") + "\n" +
"Type: " + path.Ext().ToUpper();
}
}
else
{
text = "Width: " + Core.GetPropertyInt("width") + "\n" +
"Height: " + Core.GetPropertyInt("height") + "\n" +
"Size: " + Convert.ToInt32(fileSize / 1024.0) + " KB\n" +
"Type: " + path.Ext().ToUpper();
}
fileSize = new FileInfo(path).Length;
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;
}
else
{
Core.Command("script-message-to mpvnet show-media-info osd");
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");
@@ -255,7 +210,6 @@ namespace mpvnet
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");
}
@@ -356,13 +310,44 @@ namespace mpvnet
if (++aid > tracks.Length)
aid = 1;
Core.CommandV("set", "aid", aid.ToString());
Core.SetPropertyInt("aid", aid);
}
Core.CommandV("show-text", aid + "/" + tracks.Length + ": " + tracks[aid - 1].Text.Substring(3), "5000");
}
}
public static void CycleSubtitles()
{
Core.UpdateExternalTracks();
lock (Core.MediaTracksLock)
{
MediaTrack[] tracks = Core.MediaTracks.Where(track => track.Type == "s").ToArray();
if (tracks.Length < 1)
{
Core.CommandV("show-text", "No subtitles");
return;
}
int sid = Core.GetPropertyInt("sid");
if (tracks.Length > 1)
{
if (++sid > tracks.Length)
sid = 0;
Core.SetPropertyInt("sid", sid);
}
if (sid == 0)
Core.CommandV("show-text", "No subtitle");
else
Core.CommandV("show-text", sid + "/" + tracks.Length + ": " + tracks[sid - 1].Text.Substring(3), "5000");
}
}
public static void ShowCommands()
{
string jsonString = Core.GetPropertyString("command-list");
@@ -439,6 +424,7 @@ namespace mpvnet
else
{
Core.UpdateExternalTracks();
text = "N: " + Core.GetPropertyString("filename") + BR;
lock (Core.MediaTracksLock)
foreach (MediaTrack track in Core.MediaTracks)
text += track.Text + BR;
@@ -566,6 +552,9 @@ namespace mpvnet
Action = () => Core.SetPropertyInt("playlist-pos", index)
};
if (string.IsNullOrEmpty(item.Text))
item.Text = file;
items.Add(item);
if (currentPath.ToLowerEx() == file.ToLowerEx())
@@ -718,6 +707,16 @@ namespace mpvnet
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)
@@ -739,6 +738,12 @@ namespace mpvnet
Core.SetPropertyInt("playlist-pos", pos);
}
public static void PlaylistRandom()
{
int count = Core.GetPropertyInt("playlist-count");
Core.SetPropertyInt("playlist-pos", new Random().Next(count));
}
public static void QuickBookmark()
{
if (App.QuickBookmark == 0)

View File

@@ -7,7 +7,7 @@ public static class TestStringExtension
{
public static bool ContainsEx(this string instance, string value)
{
if (instance != null && value != null)
if (!string.IsNullOrEmpty(instance) && !string.IsNullOrEmpty(value))
return instance.Contains(value);
return false;
@@ -47,6 +47,8 @@ public static class ConvertToStringExtension
return instance.Trim();
}
public static string ToStringEx(this object instance) => instance?.ToString() ?? "";
}
public static class ConvertStringExtension

View File

@@ -146,7 +146,19 @@ namespace mpvnet
public string Path { get; set; } = "";
public string Command { get; set; } = "";
public string Display { get { return string.IsNullOrEmpty(Path) ? Command : Path; } }
public string Display {
get {
if (string.IsNullOrEmpty(Path))
{
if (Command.Length > 47)
return Command.Substring(0, 47) + "...";
return Command;
}
else
return Path;
}
}
public CommandItem() { }
@@ -249,6 +261,13 @@ namespace mpvnet
Action = action;
}
public CommandPaletteItem(string text, string secondaryText, Action action)
{
Text = text;
Action = action;
SecondaryText = secondaryText;
}
public string Text { get; set; } = "";
public string SecondaryText { get; set; } = "";
public Action Action { get; set; }
@@ -271,4 +290,26 @@ namespace mpvnet
});
}
}
public class Chapter
{
public string Title { get; set; }
public double Time { get; set; }
string _TimeDisplay;
public string TimeDisplay {
get {
if (_TimeDisplay == null)
{
_TimeDisplay = TimeSpan.FromSeconds(Time).ToString();
if (_TimeDisplay.ContainsEx("."))
_TimeDisplay = _TimeDisplay.Substring(0, _TimeDisplay.LastIndexOf("."));
}
return _TimeDisplay;
}
}
}
}

View File

@@ -21,8 +21,8 @@ namespace mpvnet
public class CorePlayer
{
public static string[] VideoTypes { get; set; } = "264 265 asf avc avi avs dav flv h264 h265 hevc m2t m2ts m2v m4v mkv mov mp4 mpeg mpg mpv mts ts vob vpy webm wmv y4m".Split(' ');
public static string[] AudioTypes { get; set; } = "aac ac3 dts dtshd dtshr dtsma eac3 flac m4a mka mp2 mp3 mpa mpc ogg opus thd thd+ac3 w64 wav".Split(' ');
public static string[] ImageTypes { get; set; } = { "jpg", "bmp", "png", "gif" };
public static string[] AudioTypes { get; set; } = "aac ac3 dts dtshd dtshr dtsma eac3 flac m4a mka mp2 mp3 mpa mpc ogg opus thd w64 wav".Split(' ');
public static string[] ImageTypes { get; set; } = { "jpg", "bmp", "png", "gif", "webp" };
public static string[] SubtitleTypes { get; } = { "srt", "ass", "idx", "sub", "sup", "ttxt", "txt", "ssa", "smi", "mks" };
public event Action<mpv_log_level, string> LogMessageAsync; // log-message MPV_EVENT_LOG_MESSAGE
@@ -56,9 +56,9 @@ namespace mpvnet
public event Action InitializedAsync;
public event Action Pause;
public event Action ShowMenu;
public event Action<double> WindowScaleMpv;
public event Action<float> ScaleWindow;
public event Action<float> WindowScaleNET;
public event Action<double> WindowScaleMpv;
public event Action<int> PlaylistPosChanged;
public event Action<int> PlaylistPosChangedAsync;
public event Action<Size> VideoSizeChanged;
@@ -69,24 +69,22 @@ namespace mpvnet
public Dictionary<string, List<Action<bool>>> BoolPropChangeActions { get; set; } = new Dictionary<string, List<Action<bool>>>();
public Dictionary<string, List<Action<double>>> DoublePropChangeActions { get; set; } = new Dictionary<string, List<Action<double>>>();
public Dictionary<string, List<Action<string>>> StringPropChangeActions { get; set; } = new Dictionary<string, List<Action<string>>>();
public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public object MediaTracksLock { get; } = new object();
public List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>();
public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>();
public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false);
public AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false);
public IntPtr Handle { get; set; }
public IntPtr NamedHandle { get; set; }
public List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public List<TimeSpan> BluRayTitles { get; } = new List<TimeSpan>();
public object MediaTracksLock { get; } = new object();
public Size VideoSize { get; set; }
public TimeSpan Duration;
public AutoResetEvent ShutdownAutoResetEvent { get; } = new AutoResetEvent(false);
public AutoResetEvent VideoSizeAutoResetEvent { get; } = new AutoResetEvent(false);
public string ConfPath { get => ConfigFolder + "mpv.conf"; }
public string GPUAPI { get; set; } = "auto";
public string VO { get; set; } = "gpu";
public string InputConfPath => ConfigFolder + "input.conf";
public string Path { get; set; } = "";
public string VO { get; set; } = "gpu";
public string VID { get; set; } = "";
public string AID { get; set; } = "";
@@ -99,6 +97,7 @@ namespace mpvnet
public bool KeepaspectWindow { get; set; }
public bool Paused { get; set; }
public bool Shown { get; set; }
public bool SnapWindow { get; set; }
public bool TaskbarProgress { get; set; } = true;
public bool WasInitialSizeSet;
public bool WindowMaximized { get; set; }
@@ -119,6 +118,11 @@ namespace mpvnet
Handle = mpv_create();
var events = Enum.GetValues(typeof(mpv_event_id)).Cast<mpv_event_id>();
foreach (mpv_event_id i in events)
mpv_request_event(Handle, i, 0);
mpv_request_log_messages(Handle, "no");
App.RunTask(() => MainEventLoop());
@@ -130,7 +134,6 @@ namespace mpvnet
{
SetPropertyString("terminal", "yes");
SetPropertyString("input-terminal", "yes");
SetPropertyString("msg-level", "osd/libass=fatal");
}
SetPropertyInt("osd-duration", 2000);
@@ -149,6 +152,8 @@ namespace mpvnet
ProcessCommandLine(true);
Environment.SetEnvironmentVariable("MPVNET_VERSION", Application.ProductVersion);
mpv_error err = mpv_initialize(Handle);
if (err < 0)
@@ -171,6 +176,7 @@ namespace mpvnet
SetPropertyString("idle", "yes");
ObservePropertyDouble("window-scale", value => WindowScaleMpv(value));
ObservePropertyString("path", value => Path = value);
ObservePropertyBool("pause", value => {
Paused = value;
@@ -249,27 +255,34 @@ namespace mpvnet
switch (name)
{
case "autofit":
if (int.TryParse(value.Trim('%'), out int result))
Autofit = result / 100f;
{
if (int.TryParse(value.Trim('%'), out int result))
Autofit = result / 100f;
}
break;
case "autofit-smaller":
if (int.TryParse(value.Trim('%'), out int result2))
AutofitSmaller = result2 / 100f;
{
if (int.TryParse(value.Trim('%'), out int result))
AutofitSmaller = result / 100f;
}
break;
case "autofit-larger":
if (int.TryParse(value.Trim('%'), out int result3))
AutofitLarger = result3 / 100f;
{
if (int.TryParse(value.Trim('%'), out int result))
AutofitLarger = result / 100f;
}
break;
case "border": Border = value == "yes"; break;
case "fs":
case "fullscreen": Fullscreen = value == "yes"; break;
case "border": Border = value == "yes"; break;
case "gpu-api": GPUAPI = value; break;
case "keepaspect-window": KeepaspectWindow = value == "yes"; break;
case "screen": Screen = Convert.ToInt32(value); break;
case "snap-window": SnapWindow = value == "yes"; break;
case "taskbar-progress": TaskbarProgress = value == "yes"; break;
case "vo": VO = value; break;
case "window-maximized": WindowMaximized = value == "yes"; break;
case "window-minimized": WindowMinimized = value == "yes"; break;
case "taskbar-progress": TaskbarProgress = value == "yes"; break;
case "screen": Screen = Convert.ToInt32(value); break;
case "gpu-api": GPUAPI = value; break;
case "vo": VO = value; break;
}
if (AutofitLarger > 1)
@@ -331,7 +344,7 @@ namespace mpvnet
{
File.WriteAllText(_ConfigFolder + "input.conf", Properties.Resources.input_conf);
string scriptOptsPath = _ConfigFolder + "script-opts" + Path.DirectorySeparatorChar;
string scriptOptsPath = _ConfigFolder + "script-opts" + System.IO.Path.DirectorySeparatorChar;
if (!Directory.Exists(scriptOptsPath))
{
@@ -365,6 +378,9 @@ namespace mpvnet
string key = i.Substring(0, i.IndexOf("=")).Trim();
string value = i.Substring(i.IndexOf("=") + 1).Trim();
if (key.StartsWith("-"))
key = key.TrimStart('-');
if (value.Contains("#") && !value.StartsWith("#") &&
!value.StartsWith("'#") && !value.StartsWith("\"#"))
@@ -436,7 +452,7 @@ namespace mpvnet
ps.Scripts.Add(eventCode);
ps.Scripts.Add(propertyChangedCode);
ps.Scripts.Add(File.ReadAllText(file));
ps.Module = Path.GetFileName(file);
ps.Module = System.IO.Path.GetFileName(file);
ps.Print = true;
lock (PowerShell.References)
@@ -1116,11 +1132,13 @@ namespace mpvnet
string left = arg.Substring(2, arg.IndexOf("=") - 2);
string right = arg.Substring(left.Length + 3);
if (left == "script")
left = "scripts";
if (left == "external-file")
left = "external-files";
switch (left)
{
case "script": left = "scripts"; break;
case "audio-file": left = "audio-files"; break;
case "sub-file": left = "sub-files"; break;
case "external-file": left = "external-files"; break;
}
if (preInit && preInitProperties.Contains(left))
{
@@ -1186,19 +1204,39 @@ namespace mpvnet
{
string file = files[i];
if (file.Ext() == "avs")
LoadAviSynth();
if (string.IsNullOrEmpty(file))
continue;
if (file.Ext() == "iso")
LoadISO(file);
else if(SubtitleTypes.Contains(file.Ext()))
CommandV("sub-add", file);
else if (file.Ext().Length != 3 && File.Exists(Path.Combine(file, "BDMV\\index.bdmv")))
if (file.Contains("|"))
file = file.Substring(0, file.IndexOf("|"));
string ext = file.Ext();
switch (ext)
{
Command("stop");
Thread.Sleep(500);
SetPropertyString("bluray-device", file);
CommandV("loadfile", @"bd://");
case "avs": LoadAviSynth(); break;
case "lnk": file = GetShortcutTarget(file); break;
}
if (ext == "iso")
LoadISO(file);
else if(SubtitleTypes.Contains(ext))
CommandV("sub-add", file);
else if (ext == "" && !file.Contains("://") && Directory.Exists(file))
{
if (File.Exists(System.IO.Path.Combine(file, "BDMV\\index.bdmv")))
{
Command("stop");
Thread.Sleep(500);
SetPropertyString("bluray-device", file);
CommandV("loadfile", @"bd://");
}
else
{
files = GetMediaFiles(Directory.GetFiles(file, "*.*", SearchOption.AllDirectories)).ToArray();
LoadFiles(files, loadFolder, append);
return;
}
}
else
{
@@ -1265,41 +1303,48 @@ namespace mpvnet
}
}
static object LoadFolderLockObject = new object();
public void LoadFolder()
{
if (!App.AutoLoadFolder || Control.ModifierKeys.HasFlag(Keys.Shift))
return;
Thread.Sleep(1000);
string path = GetPropertyString("path");
if (!File.Exists(path) || GetPropertyInt("playlist-count") != 1)
return;
lock (LoadFolderLockObject)
{
string path = GetPropertyString("path");
string dir = Environment.CurrentDirectory;
if (!File.Exists(path) || GetPropertyInt("playlist-count") != 1)
return;
if (path.Contains(":/") && !path.Contains("://"))
path = path.Replace("/", "\\");
string dir = Environment.CurrentDirectory;
if (path.Contains("\\"))
dir = Path.GetDirectoryName(path);
if (path.Contains(":/") && !path.Contains("://"))
path = path.Replace("/", "\\");
List<string> files = Directory.GetFiles(dir).ToList();
if (path.Contains("\\"))
dir = System.IO.Path.GetDirectoryName(path);
files = files.Where(file =>
VideoTypes.Contains(file.Ext()) ||
AudioTypes.Contains(file.Ext()) ||
ImageTypes.Contains(file.Ext())).ToList();
List<string> files = GetMediaFiles(Directory.GetFiles(dir)).ToList();
files.Sort(new StringLogicalComparer());
int index = files.IndexOf(path);
files.Remove(path);
files.Sort(new StringLogicalComparer());
int index = files.IndexOf(path);
files.Remove(path);
foreach (string i in files)
CommandV("loadfile", i, "append");
foreach (string i in files)
CommandV("loadfile", i, "append");
if (index > 0)
CommandV("playlist-move", "0", (index + 1).ToString());
}
}
if (index > 0)
CommandV("playlist-move", "0", (index + 1).ToString());
IEnumerable<string> GetMediaFiles(IEnumerable<string> files)
{
return files.Where(i => VideoTypes.Contains(i.Ext()) ||
AudioTypes.Contains(i.Ext()) ||
ImageTypes.Contains(i.Ext()));
}
bool WasAviSynthLoaded;
@@ -1386,6 +1431,10 @@ namespace mpvnet
void HideLogo() => Command("overlay-remove 0");
public bool IsImage => ImageTypes.Contains(Path.Ext());
public bool IsAudio => AudioTypes.Contains(Path.Ext());
string GetLanguage(string id)
{
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.NeutralCultures))
@@ -1416,8 +1465,24 @@ namespace mpvnet
}
}
public void RaiseScaleWindow(float value) => ScaleWindow(value);
string GetNativeLanguage(string name)
{
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.NeutralCultures))
if (ci.EnglishName == name)
return ci.NativeName;
return name;
}
public static string GetShortcutTarget(string path)
{
Type t = Type.GetTypeFromProgID("WScript.Shell");
dynamic sh = Activator.CreateInstance(t);
return sh.CreateShortcut(path).TargetPath;
}
public void RaiseScaleWindow(float value) => ScaleWindow(value);
public void RaiseWindowScaleNET(float value) => WindowScaleNET(value);
public void RaiseShowMenu() => ShowMenu();
@@ -1437,33 +1502,37 @@ namespace mpvnet
else
MediaTracks = GetTracks();
}
}
lock (Chapters)
public List<Chapter> GetChapters() {
List<Chapter> chapters = new List<Chapter>();
int count = GetPropertyInt("chapter-list/count");
for (int x = 0; x < count; x++)
{
Chapters.Clear();
int count = GetPropertyInt("chapter-list/count");
string title = GetPropertyString($"chapter-list/{x}/title");
double time = GetPropertyDouble($"chapter-list/{x}/time");
for (int x = 0; x < count; x++)
{
string text = GetPropertyString($"chapter-list/{x}/title");
double time = GetPropertyDouble($"chapter-list/{x}/time");
if (string.IsNullOrEmpty(title) ||
(title.Length == 12 && title.Contains(":") && title.Contains(".")))
if (string.IsNullOrEmpty(text))
text = "Chapter " + (x + 1);
title = "Chapter " + (x + 1);
Chapters.Add(new KeyValuePair<string, double>(text, time));
}
chapters.Add(new Chapter() { Title = title, Time = time });
}
return chapters;
}
public void UpdateExternalTracks()
{
int trackCount = GetPropertyInt("track-list/count");
int trackListTrackCount = GetPropertyInt("track-list/count");
int editionCount = GetPropertyInt("edition-list/count");
int count = MediaTracks.Where(i => i.Type != "g").Count();
lock (MediaTracksLock)
{
if (MediaTracks.Count != (trackCount + editionCount))
if (count != (trackListTrackCount + editionCount))
{
MediaTracks = MediaTracks.Where(i => !i.External).ToList();
MediaTracks.AddRange(GetTracks(false));
@@ -1581,6 +1650,15 @@ namespace mpvnet
using (MediaInfo mi = new MediaInfo(path))
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetGeneral("Format"));
Add(track, mi.GetGeneral("FileSize/String"));
Add(track, mi.GetGeneral("Duration/String"));
Add(track, mi.GetGeneral("OverallBitRate/String"));
track.Text = "G: " + track.Text.Trim(' ', ',');
track.Type = "g";
tracks.Add(track);
int videoCount = mi.GetCount(MediaInfoStreamKind.Video);
for (int i = 0; i < videoCount; i++)
@@ -1590,15 +1668,13 @@ namespace mpvnet
if (float.TryParse(fps, NumberStyles.Float, CultureInfo.InvariantCulture, out float result))
fps = result.ToString(CultureInfo.InvariantCulture);
MediaTrack track = new MediaTrack();
track = new MediaTrack();
Add(track, mi.GetVideo(i, "Format"));
Add(track, mi.GetVideo(i, "Format_Profile"));
Add(track, mi.GetVideo(i, "Width") + "x" + mi.GetVideo(i, "Height"));
Add(track, mi.GetVideo(i, "BitRate/String"));
Add(track, fps + " FPS");
Add(track, mi.GetVideo(i, "Language/String"));
Add(track, mi.GetVideo(i, "Forced") == "Yes" ? "Forced" : "");
Add(track, mi.GetVideo(i, "Default") == "Yes" ? "Default" : "");
Add(track, (videoCount > 1 && mi.GetVideo(i, "Default") == "Yes") ? "Default" : "");
Add(track, mi.GetVideo(i, "Title"));
track.Text = "V: " + track.Text.Trim(' ', ',');
track.Type = "v";
@@ -1610,16 +1686,80 @@ namespace mpvnet
for (int i = 0; i < audioCount; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetAudio(i, "Language/String"));
Add(track, mi.GetAudio(i, "Format"));
string lang = mi.GetAudio(i, "Language/String");
string nativeLang = GetNativeLanguage(lang);
string title = mi.GetAudio(i, "Title");
string format = mi.GetAudio(i, "Format");
if (!string.IsNullOrEmpty(title))
{
if (title.ContainsEx("DTS-HD MA"))
format = "DTS-MA";
if (title.ContainsEx("DTS-HD MA"))
title = title.Replace("DTS-HD MA", "");
if (title.ContainsEx("Blu-ray"))
title = title.Replace("Blu-ray", "");
if (title.ContainsEx("UHD "))
title = title.Replace("UHD ", "");
if (title.ContainsEx("EAC"))
title = title.Replace("EAC", "E-AC");
if (title.ContainsEx("AC3"))
title = title.Replace("AC3", "AC-3");
if (title.ContainsEx(lang))
title = title.Replace(lang, "").Trim();
if (title.ContainsEx(nativeLang))
title = title.Replace(nativeLang, "").Trim();
if (title.ContainsEx("Surround"))
title = title.Replace("Surround", "");
if (title.ContainsEx("Dolby Digital"))
title = title.Replace("Dolby Digital", "");
if (title.ContainsEx("Stereo"))
title = title.Replace("Stereo", "");
if (title.StartsWith(format + " "))
title = title.Replace(format + " ", "");
foreach (string i2 in new [] { "2.0", "5.1", "6.1", "7.1" })
if (title.ContainsEx(i2))
title = title.Replace(i2, "");
if (title.ContainsEx("()"))
title = title.Replace("()", "");
if (title.ContainsEx("[]"))
title = title.Replace("[]", "");
if (title.TrimEx() == format)
title = null;
}
track = new MediaTrack();
Add(track, lang);
Add(track, format);
Add(track, mi.GetAudio(i, "Format_Profile"));
Add(track, mi.GetAudio(i, "BitRate/String"));
Add(track, mi.GetAudio(i, "Channel(s)") + " ch");
Add(track, mi.GetAudio(i, "SamplingRate/String"));
Add(track, mi.GetAudio(i, "Forced") == "Yes" ? "Forced" : "");
Add(track, mi.GetAudio(i, "Default") == "Yes" ? "Default" : "");
Add(track, mi.GetAudio(i, "Title"));
Add(track, (audioCount > 1 && mi.GetAudio(i, "Default") == "Yes") ? "Default" : "");
Add(track, title);
if (track.Text.Contains("MPEG Audio, Layer 2"))
track.Text = track.Text.Replace("MPEG Audio, Layer 2", "MP2");
if (track.Text.Contains("MPEG Audio, Layer 3"))
track.Text = track.Text.Replace("MPEG Audio, Layer 2", "MP3");
track.Text = "A: " + track.Text.Trim(' ', ',');
track.Type = "a";
track.ID = i + 1;
@@ -1631,6 +1771,7 @@ namespace mpvnet
for (int i = 0; i < subCount; i++)
{
string codec = mi.GetText(i, "Format").ToUpperEx();
if (codec == "UTF-8")
codec = "SRT";
else if (codec == "WEBVTT")
@@ -1638,13 +1779,57 @@ namespace mpvnet
else if (codec == "VOBSUB")
codec = "VOB";
MediaTrack track = new MediaTrack();
Add(track, mi.GetText(i, "Language/String"));
string lang = mi.GetText(i, "Language/String");
string nativeLang = GetNativeLanguage(lang);
string title = mi.GetText(i, "Title");
bool forced = mi.GetText(i, "Forced") == "Yes";
if (!string.IsNullOrEmpty(title))
{
if (title.ContainsEx("VobSub"))
title = title.Replace("VobSub", "VOB");
if (title.ContainsEx(codec))
title = title.Replace(codec, "");
if (title.ContainsEx(lang.ToLowerEx()))
title = title.Replace(lang.ToLowerEx(), lang);
if (title.ContainsEx(nativeLang.ToLowerEx()))
title = title.Replace(nativeLang.ToLowerEx(), nativeLang).Trim();
if (title.ContainsEx(lang))
title = title.Replace(lang, "");
if (title.ContainsEx(nativeLang))
title = title.Replace(nativeLang, "").Trim();
if (title.ContainsEx("full"))
title = title.Replace("full", "").Trim();
if (title.ContainsEx("Full"))
title = title.Replace("Full", "").Trim();
if (title.ContainsEx("forced"))
title = title.Replace("forced", "Forced").Trim();
if (forced && title.ContainsEx("Forced"))
title = title.Replace("Forced", "").Trim();
if (title.ContainsEx("()"))
title = title.Replace("()", "");
if (title.ContainsEx("[]"))
title = title.Replace("[]", "");
}
track = new MediaTrack();
Add(track, lang);
Add(track, codec);
Add(track, mi.GetText(i, "Format_Profile"));
Add(track, mi.GetText(i, "Forced") == "Yes" ? "Forced" : "");
Add(track, mi.GetText(i, "Default") == "Yes" ? "Default" : "");
Add(track, mi.GetText(i, "Title"));
Add(track, forced ? "Forced" : "");
Add(track, (subCount > 1 && mi.GetText(i, "Default") == "Yes") ? "Default" : "");
Add(track, title);
track.Text = "S: " + track.Text.Trim(' ', ',');
track.Type = "s";
track.ID = i + 1;
@@ -1671,8 +1856,10 @@ namespace mpvnet
void Add(MediaTrack track, object value)
{
if (value != null && !(track.Text != null && track.Text.Contains(value.ToString())))
track.Text += " " + value + ",";
string str = value.ToStringEx().Trim();
if (str != "" && !(track.Text != null && track.Text.Contains(str)))
track.Text += " " + str + ",";
}
private string[] _ProfileNames;

View File

@@ -32,6 +32,9 @@ namespace mpvnet
App.Init();
Mutex mutex = new Mutex(true, StringHelp.GetMD5Hash(App.ConfPath), out bool isFirst);
if (Control.ModifierKeys.HasFlag(Keys.Shift))
App.ProcessInstance = "multi";
if ((App.ProcessInstance == "single" || App.ProcessInstance == "queue") && !isFirst)
{
List<string> args2 = new List<string>();

View File

@@ -23,7 +23,6 @@ namespace mpvnet
public Size WindowSize;
public string ConfigEditorSearch = "Video:";
public string Mute = "no";
public string UpdateCheckVersion = "";
}
class SettingsManager

View File

@@ -23,6 +23,12 @@ public class MediaInfo : IDisposable
public int GetCount(MediaInfoStreamKind kind) => MediaInfo_Count_Get(Handle, kind, -1);
public string GetGeneral(string parameter)
{
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.General,
0, parameter, MediaInfoKind.Text, MediaInfoKind.Name));
}
public string GetVideo(int stream, string parameter)
{
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Video,

View File

@@ -21,6 +21,9 @@ namespace mpvnet
[DllImport("user32.dll")]
public static extern uint ActivateKeyboardLayout(IntPtr hkl, uint flags);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(
IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
@@ -88,6 +91,37 @@ namespace mpvnet
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(
IntPtr hwnd, uint dwAttribute, out RECT pvAttribute, uint cbAttribute);
public static bool GetDwmWindowRect(IntPtr handle, out RECT rect)
{
const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9;
return 0 == DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS, out rect, (uint)Marshal.SizeOf<RECT>());
}
public static Rectangle GetWorkingArea(IntPtr handle, Rectangle workingArea)
{
if (handle != IntPtr.Zero && GetDwmWindowRect(handle, out RECT dwmRect) &&
GetWindowRect(handle, out RECT rect))
{
int left = workingArea.Left;
int top = workingArea.Top;
int right = workingArea.Right;
int bottom = workingArea.Bottom;
left += rect.Left - dwmRect.Left;
top -= rect.Top - dwmRect.Top;
right -= dwmRect.Right - rect.Right;
bottom -= dwmRect.Bottom - rect.Bottom;
return new Rectangle(left, top, right - left, bottom - top);
}
return workingArea;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
@@ -116,6 +150,16 @@ namespace mpvnet
public Size Size => new Size(Right - Left, Bottom - Top);
public int Width => Right - Left;
public int Height => Bottom - Top;
public static RECT FromRectangle(Rectangle rect)
{
return new RECT(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
}
public override string ToString()
{
return "{Left=" + Left + ",Top=" + Top + ",Right=" + Right + ",Bottom=" + Bottom + "}";
}
}
[StructLayout(LayoutKind.Sequential)]

View File

@@ -65,6 +65,9 @@ public class libmpv
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mpv_wait_event(IntPtr mpvHandle, double timeout);
[DllImport("mpv-2.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern mpv_error mpv_request_event(IntPtr mpvHandle, mpv_event_id id, int enable);
public enum mpv_error
{
MPV_ERROR_SUCCESS = 0,

View File

@@ -11,7 +11,7 @@
<Identity
Name="5664FrankSkare.mpv.net"
Publisher="CN=6A1A1E69-736C-4C77-B310-7B6D38E32617"
Version="5.7.0.0" />
Version="6.0.3.0" />
<Properties>
<DisplayName>mpv.net</DisplayName>

View File

@@ -27,7 +27,7 @@
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>neutral</AppxBundlePlatforms>
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
</PropertyGroup>

View File

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("6.0.0.0")]
[assembly: AssemblyFileVersion("6.0.0.0")]
[assembly: AssemblyVersion("6.0.3.1")]
[assembly: AssemblyFileVersion("6.0.3.1")]

View File

@@ -21,7 +21,7 @@ name = media-info
file = mpvnet
default = yes
filter = General
help = Usage of the media info library instead of mpv to access media information. Default: no (mpv.net specific option)
help = Usage of the media info library instead of mpv to access media information. (mpv.net specific option)
option = yes
option = no
@@ -410,6 +410,18 @@ file = mpv
filter = Screen
help = <int> Initial window height in percent. Default: 60
[setting]
name = autofit-image
file = mpvnet
filter = Screen
help = <int> Initial window height in percent for image files. Default: 80
[setting]
name = autofit-audio
file = mpvnet
filter = Screen
help = <int> Initial window height in percent for audio files. Default: 70
[setting]
name = autofit-smaller
file = mpv
@@ -447,17 +459,17 @@ help = keepaspect-window will lock the window size to the video aspect. Default:
option = yes
option = no
[setting]
name = start-threshold
file = mpvnet
filter = Screen
help = Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. Default: 1500 (mpv.net specific option)
[setting]
name = minimum-aspect-ratio
file = mpvnet
filter = Screen
help = <float> Minimum aspect ratio, if the AR is smaller than the defined value then the window AR is set to 16/9. This avoids a square window for Music with cover art. Default: 1.2 (mpv.net specific option)
help = <float> Minimum aspect ratio of the window. Useful to force a wider window and therefore a larger OSC. (mpv.net specific option)
[setting]
name = minimum-aspect-ratio-audio
file = mpvnet
filter = Screen
help = Same as minimum-aspect-ratio but used for audio files.
[setting]
name = remember-window-position
@@ -469,6 +481,16 @@ help = Save the window position on exit. (mpv.net specific option)
option = yes
option = no
[setting]
name = snap-window
file = mpv
default = no
filter = Screen
help = Snap the player window to screen edges.
option = yes
option = no
[setting]
name = window-maximized
file = mpv
@@ -479,6 +501,12 @@ help = Start with a maximized window.
option = yes
option = no
[setting]
name = start-threshold
file = mpvnet
filter = Screen
help = Threshold in milliseconds to wait for libmpv returning the video resolution before the window is shown, otherwise default dimensions are used as defined by autofit and start-size. Default: 1500 (mpv.net specific option)
[setting]
name = taskbar-progress
file = mpv
@@ -643,7 +671,7 @@ name = show-santa-logo
file = mpvnet
default = yes
filter = UI
help = Draws the blue mpv.net logo with a santa hat in december, the option is called green and grumpy in mpv.
help = Draws the blue mpv.net logo with a santa hat in december, the option is called greenandgrumpy in mpv.
option = yes
option = no

View File

@@ -24,6 +24,8 @@ _ ignore #menu: Navigate > -
Home script-message-to mpvnet playlist-first #menu: Navigate > First File
End script-message-to mpvnet playlist-last #menu: Navigate > Last File
_ ignore #menu: Navigate > -
F9 script-message-to mpvnet playlist-random #menu: Navigate > Random File
_ ignore #menu: Navigate > -
PGUP add chapter 1 #menu: Navigate > Next Chapter
PGDWN add chapter -1 #menu: Navigate > Previous Chapter
_ ignore #menu: Navigate > -
@@ -78,7 +80,7 @@ _ ignore #menu: Audio > -
Ctrl+d add audio-delay 0.1 #menu: Audio > Delay +0.1
Ctrl+D add audio-delay -0.1 #menu: Audio > Delay -0.1
KP8 cycle sub #menu: Subtitle > Cycle/Next
KP8 script-message-to mpvnet cycle-subtitles #menu: Subtitle > Cycle/Next #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
@@ -94,6 +96,8 @@ _ ignore #menu: Track
+ add volume 2 #menu: Volume > Up
- add volume -2 #menu: Volume > Down
0 add volume 2 #menu: Volume > Up
9 add volume -2 #menu: Volume > Down
_ ignore #menu: Volume > -
m cycle mute #menu: Volume > Mute
@@ -118,14 +122,14 @@ Ctrl+p script-message-to mpvnet select-profile #menu: View > Show Profile
Ctrl+P script-message-to mpvnet show-profiles #menu: View > Show Profiles
Ctrl+7 script-message-to mpvnet show-audio-tracks #menu: View > Show Audio Tracks
Ctrl+8 script-message-to mpvnet show-subtitle-tracks #menu: View > Show Subtitle Tracks
Ctrl+c script-message-to mpvnet show-chapters #menu: View > Show Chapters
b cycle border #menu: View > Toggle Border
Ctrl+t cycle ontop #menu: View > Toggle On Top
t script-binding stats/display-stats-toggle #menu: View > Toggle Statistics
Del script-binding osc/visibility #menu: View > Toggle OSC Visibility
i script-message-to mpvnet show-info #menu: View > Show File/Stream Info
i script-message-to mpvnet show-info #menu: View > Show Media Info
Ctrl+m script-message-to mpvnet show-media-info #menu: View > Show Media Info Advanced
p show-progress #menu: View > Show Progress
F9 script-message-to mpvnet show-media-info osd #menu: View > Show Tracks
Ctrl+m script-message-to mpvnet show-media-info #menu: View > Show Media Info
Alt+r script-message-to mpvnet show-recent #menu: View > Show Recent
` script-binding console/enable #menu: View > Advanced > Show Console
@@ -154,6 +158,7 @@ L cycle-values loop-file inf no #menu: Tools > Toggle infi
_ playlist-shuffle #menu: Tools > Shuffle Playlist
Ctrl+h cycle-values hwdec auto no #menu: Tools > Toggle Hardware Decoding
Q quit-watch-later #menu: Tools > Exit Watch Later
e run powershell -command "explorer.exe '/select,' ( \"${path}\" -replace '/', '\\' )" #menu: Tools > Show current file in File Explorer
_ script-message-to mpvnet shell-execute https://mpv.io #menu: Help > Website mpv
_ script-message-to mpvnet shell-execute https://github.com/stax76/mpv.net #menu: Help > Website mpv.net
@@ -170,15 +175,14 @@ Esc quit #menu: Exit
MBTN_Right script-message-to mpvnet show-menu
6 script-message-to mpvnet show-progress
KP6 script-message-to mpvnet show-progress
9 ab-loop
KP9 ab-loop
7 script-message-to mpvnet cycle-audio
Sharp script-message-to mpvnet cycle-audio
Ctrl+F11 script-message-to mpvnet playlist-add -10
Ctrl+F12 script-message-to mpvnet playlist-add 10
Alt+q script-message-to mpvnet quick-bookmark
8 cycle sub
j cycle sub
8 script-message-to mpvnet cycle-subtitles
j script-message-to mpvnet cycle-subtitles
q quit
Power quit
Play cycle pause
@@ -211,4 +215,4 @@ Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek
Ctrl+Shift+Left no-osd sub-seek -1 # seek to the previous subtitle
Ctrl+Shift+Right no-osd sub-seek 1 # seek to the next subtitle
Ctrl+Wheel_Up no-osd seek 7
Ctrl+Wheel_Down no-osd seek -7
Ctrl+Wheel_Down no-osd seek -7

View File

@@ -50,7 +50,7 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(348, 0);
this.ClientSize = new System.Drawing.Size(857, 444);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);

View File

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

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
@@ -20,9 +21,11 @@ namespace mpvnet
{
public partial class MainForm : Form
{
public SnapManager SnapManager = new SnapManager();
public ElementHost CommandPaletteHost { get; set; }
public IntPtr mpvWindowHandle { get; set; }
public static MainForm Instance { get; set; }
public Dictionary<string, WpfControls.MenuItem> MenuItemDuplicate = new Dictionary<string, WpfControls.MenuItem>();
new WpfControls.ContextMenu ContextMenu { get; set; }
AutoResetEvent MenuAutoResetEvent { get; } = new AutoResetEvent(false);
@@ -45,7 +48,7 @@ namespace mpvnet
Core.FileLoaded += Core_FileLoaded;
Core.Pause += Core_Pause;
Core.PlaylistPosChanged += (value) => SetTitle();
Core.PlaylistPosChanged += Core_PlaylistPosChanged;
Core.ScaleWindow += Core_ScaleWindow;
Core.Seek += () => UpdateProgressBar();
Core.ShowMenu += Core_ShowMenu;
@@ -115,6 +118,12 @@ namespace mpvnet
}
}
private void Core_PlaylistPosChanged(int pos)
{
if (pos == -1)
SetTitle();
}
void Init()
{
Core.Init(Handle);
@@ -220,7 +229,7 @@ namespace mpvnet
if (FormBorderStyle == FormBorderStyle.None)
top = ClientSize.Height * 0.1f;
return pos.Y > ClientSize.Height * 0.85 || pos.Y < top;
return pos.Y > ClientSize.Height * 0.78 || pos.Y < top;
}
void UpdateMenu()
@@ -291,26 +300,18 @@ namespace mpvnet
}
}
lock (Core.Chapters)
var chaptersMenuItem = FindMenuItem("Chapters");
if (chaptersMenuItem != null)
{
var chaptersMenuItem = FindMenuItem("Chapters");
chaptersMenuItem.Items.Clear();
if (chaptersMenuItem != null)
foreach (Chapter chapter in Core.GetChapters())
{
chaptersMenuItem.Items.Clear();
foreach (var pair in Core.Chapters)
{
string caption = TimeSpan.FromSeconds(pair.Value).ToString();
if (caption.ContainsEx("."))
caption = caption.Substring(0, caption.LastIndexOf("."));
var chapterMenuItem = new WpfControls.MenuItem() { Header = pair.Key };
chapterMenuItem.InputGestureText = caption;
chapterMenuItem.Click += (sender, args) => Core.CommandV("seek", pair.Value.ToString(CultureInfo.InvariantCulture), "absolute");
chaptersMenuItem.Items.Add(chapterMenuItem);
}
var chapterMenuItem = new WpfControls.MenuItem() { Header = chapter.Title };
chapterMenuItem.InputGestureText = chapter.TimeDisplay;
chapterMenuItem.Click += (sender, args) => Core.CommandV("seek", chapter.Time.ToString(CultureInfo.InvariantCulture), "absolute");
chaptersMenuItem.Items.Add(chapterMenuItem);
}
}
@@ -431,13 +432,23 @@ namespace mpvnet
}
Screen screen = Screen.FromControl(this);
int autoFitHeight = Convert.ToInt32(screen.WorkingArea.Height * Core.Autofit);
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
int autoFitHeight = Convert.ToInt32(workingArea.Height * Core.Autofit);
if (Core.VideoSize.Height == 0 || Core.VideoSize.Width == 0 ||
Core.VideoSize.Width / (float)Core.VideoSize.Height < App.MinimumAspectRatio)
if (App.AutofitAudio > 1) App.AutofitAudio = 1;
if (App.AutofitImage > 1) App.AutofitImage = 1;
if (Core.IsAudio) autoFitHeight = Convert.ToInt32(workingArea.Height * App.AutofitAudio);
if (Core.IsImage) autoFitHeight = Convert.ToInt32(workingArea.Height * App.AutofitImage);
if (Core.VideoSize.Height == 0 || Core.VideoSize.Width == 0)
Core.VideoSize = new Size((int)(autoFitHeight * (16 / 9f)), autoFitHeight);
float minAspectRatio = Core.IsAudio ? App.MinimumAspectRatioAudio : App.MinimumAspectRatio;
if (minAspectRatio != 0 && Core.VideoSize.Width / (float)Core.VideoSize.Height < minAspectRatio)
Core.VideoSize = new Size((int)(autoFitHeight * minAspectRatio), autoFitHeight);
Size videoSize = Core.VideoSize;
int height = videoSize.Height;
@@ -473,7 +484,7 @@ namespace mpvnet
height = windowSize.Height;
width = height * videoSize.Width / videoSize.Height;
}
else if (App.StartSize == "height-session")
else if (App.StartSize == "height-session" || App.StartSize == "session")
{
height = autoFitHeight;
width = height * videoSize.Width / videoSize.Height;
@@ -488,7 +499,7 @@ namespace mpvnet
width = autoFitHeight / 9 * 16;
height = (int)Math.Ceiling(width * videoSize.Height / (double)videoSize.Width);
}
else if (KeepSize() && windowSize.Height != 0)
else if (App.StartSize == "always" && windowSize.Height != 0)
{
height = windowSize.Height;
width = windowSize.Width;
@@ -502,8 +513,10 @@ namespace mpvnet
void SetSize(int width, int height, Screen screen, bool checkAutofit = true)
{
int maxHeight = screen.WorkingArea.Height - (Height - ClientSize.Height) - 2;
int maxWidth = screen.WorkingArea.Width - (Width - ClientSize.Width);
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
int maxHeight = workingArea.Height - (Height - ClientSize.Height) - 2;
int maxWidth = workingArea.Width - (Width - ClientSize.Width);
int startWidth = width;
int startHeight = height;
@@ -558,10 +571,10 @@ namespace mpvnet
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();
int minLeft = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).X).Min();
int maxRight = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Right).Max();
int minTop = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Y).Min();
int maxBottom = screens.Select(val => GetWorkingArea(Handle, val.WorkingArea).Bottom).Max();
if (left < minLeft)
left = minLeft;
@@ -607,7 +620,12 @@ namespace mpvnet
if (WasMaximized)
WindowState = FormWindowState.Maximized;
else
{
WindowState = FormWindowState.Normal;
if (!Core.WasInitialSizeSet)
SetFormPosAndSize();
}
if (Core.Border)
FormBorderStyle = FormBorderStyle.Sizable;
@@ -622,7 +640,7 @@ namespace mpvnet
public int GetHorizontalLocation(Screen screen)
{
Rectangle workingArea = screen.WorkingArea;
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
if (workingArea.Width / (float)Width < 1.1)
@@ -639,7 +657,7 @@ namespace mpvnet
public int GetVerticalLocation(Screen screen)
{
Rectangle workingArea = screen.WorkingArea;
Rectangle workingArea = GetWorkingArea(Handle, screen.WorkingArea);
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
if (workingArea.Height / (float)Height < 1.1)
@@ -672,31 +690,40 @@ namespace mpvnet
foreach (CommandItem item in items)
{
var tempItem = item;
CommandItem tempItem = item;
if (string.IsNullOrEmpty(tempItem.Path))
continue;
var menuItem = MenuHelp.Add(ContextMenu.Items, tempItem.Path);
if (menuItem != null)
if (MenuItemDuplicate.ContainsKey(tempItem.Path))
{
menuItem.Click += (sender, args) => {
try {
App.RunTask(() => {
MenuAutoResetEvent.WaitOne();
System.Windows.Application.Current.Dispatcher.Invoke(
DispatcherPriority.Background, new Action(delegate { }));
if (!string.IsNullOrEmpty(tempItem.Command))
Core.Command(tempItem.Command);
});
}
catch (Exception ex) {
Msg.ShowException(ex);
}
};
var mi = MenuItemDuplicate[tempItem.Path];
mi.InputGestureText = mi.InputGestureText + ", " + tempItem.Input;
}
else
{
var menuItem = MenuHelp.Add(ContextMenu.Items, tempItem.Path);
menuItem.InputGestureText = tempItem.Input;
if (menuItem != null)
{
MenuItemDuplicate[tempItem.Path] = menuItem;
menuItem.Click += (sender, args) => {
try {
App.RunTask(() => {
MenuAutoResetEvent.WaitOne();
System.Windows.Application.Current.Dispatcher.Invoke(
DispatcherPriority.Background, new Action(delegate { }));
if (!string.IsNullOrEmpty(tempItem.Command))
Core.Command(tempItem.Command);
});
}
catch (Exception ex) {
Msg.ShowException(ex);
}
};
menuItem.InputGestureText = tempItem.Input;
}
}
}
}
@@ -704,7 +731,7 @@ namespace mpvnet
void Core_FileLoaded()
{
BeginInvoke(new Action(() => {
Text = Core.Expand(Title);
SetTitleInternal();
int interval = (int)(Core.Duration.TotalMilliseconds / 100);
@@ -720,7 +747,7 @@ namespace mpvnet
string path = Core.GetPropertyString("path");
if (path.Contains(":/") && !path.Contains("://"))
if ((path.Contains(":/") && !path.Contains("://")) || (path.Contains(":\\") && path.Contains("/")))
path = path.Replace("/", "\\");
if (path.Contains("://"))
@@ -743,7 +770,22 @@ namespace mpvnet
}
}
void SetTitle() => BeginInvoke(new Action(() => Text = Core.Expand(Title)));
void SetTitle() => BeginInvoke(new Action(() => SetTitleInternal()));
void SetTitleInternal()
{
string title = Title;
if (title == "${filename}" && Core.Path.ContainsEx("://"))
title = "${media-title}";
string text = Core.Expand(title);
if (text == "(unavailable)")
text = "mpv.net";
Text = text;
}
public void Voodoo()
{
@@ -818,13 +860,14 @@ namespace mpvnet
case 0x20b: // WM_XBUTTONDOWN
case 0x20c: // WM_XBUTTONUP
case 0x20e: // WM_MOUSEHWHEEL
case 0x2a3: // WM_MOUSELEAVE
if (mpvWindowHandle == IntPtr.Zero)
mpvWindowHandle = FindWindowEx(Handle, IntPtr.Zero, "mpv", null);
if (mpvWindowHandle != IntPtr.Zero)
m.Result = SendMessage(mpvWindowHandle, m.Msg, m.WParam, m.LParam);
break;
case 0x051: // WM_INPUTLANGCHANGE
case 0x51: // WM_INPUTLANGCHANGE
ActivateKeyboardLayout(m.LParam, 0x00000100u /*KLF_SETFORPROCESS*/);
break;
case 0x319: // WM_APPCOMMAND
@@ -839,10 +882,10 @@ namespace mpvnet
}
}
break;
case 0x0312: // WM_HOTKEY
case 0x312: // WM_HOTKEY
GlobalHotkey.Execute(m.WParam.ToInt32());
break;
case 0x0200: // WM_MOUSEMOVE
case 0x200: // WM_MOUSEMOVE
if (Environment.TickCount - LastCycleFullscreen > 500)
{
Point pos = PointToClient(Cursor.Position);
@@ -852,17 +895,13 @@ namespace mpvnet
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
case 0x2E0: // WM_DPICHANGED
{
if (!Core.Shown)
break;
@@ -871,7 +910,7 @@ namespace mpvnet
SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, 0);
}
break;
case 0x0214: // WM_SIZING
case 0x214: // WM_SIZING
if (Core.KeepaspectWindow)
{
RECT rc = Marshal.PtrToStructure<RECT>(m.LParam);
@@ -899,7 +938,7 @@ namespace mpvnet
m.Result = new IntPtr(1);
}
return;
case 0x004A: // WM_COPYDATA
case 0x4A: // WM_COPYDATA
{
var copyData = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));
string[] args = copyData.lpData.Split('\n');
@@ -923,6 +962,56 @@ namespace mpvnet
Activate();
}
return;
case 0x84: // WM_NCHITTEST
// resize borderless window
if (!Core.Border && !Core.Fullscreen) {
const int HTCLIENT = 1;
const int HTLEFT = 10;
const int HTRIGHT = 11;
const int HTTOP = 12;
const int HTTOPLEFT = 13;
const int HTTOPRIGHT = 14;
const int HTBOTTOM = 15;
const int HTBOTTOMLEFT = 16;
const int HTBOTTOMRIGHT = 17;
int x = (short)(m.LParam.ToInt32() & 0xFFFF); // LoWord
int y = (short)(m.LParam.ToInt32() >> 16); // HiWord
Point pt = PointToClient(new Point(x, y));
Size cs = ClientSize;
m.Result = new IntPtr(HTCLIENT);
int distance = FontHeight / 3;
if (pt.X >= cs.Width - distance && pt.Y >= cs.Height - distance && cs.Height >= distance)
m.Result = (IntPtr)HTBOTTOMRIGHT;
else if (pt.X <= distance && pt.Y >= cs.Height - distance && cs.Height >= distance)
m.Result = (IntPtr)HTBOTTOMLEFT;
else if (pt.X <= distance && pt.Y <= distance && cs.Height >= distance)
m.Result = (IntPtr)HTTOPLEFT;
else if (pt.X >= cs.Width - distance && pt.Y <= distance && cs.Height >= distance)
m.Result = (IntPtr)HTTOPRIGHT;
else if (pt.Y <= distance && cs.Height >= distance)
m.Result = (IntPtr)HTTOP;
else if (pt.Y >= cs.Height - distance && cs.Height >= distance)
m.Result = (IntPtr)HTBOTTOM;
else if (pt.X <= distance && cs.Height >= distance)
m.Result = (IntPtr)HTLEFT;
else if (pt.X >= cs.Width - distance && cs.Height >= distance)
m.Result = (IntPtr)HTRIGHT;
return;
}
break;
case 0x231: // WM_ENTERSIZEMOVE
case 0x005: // WM_SIZE
if (Core.SnapWindow)
SnapManager.OnSizeAndEnterSizeMove(this);
break;
case 0x216: // WM_MOVING
if (Core.SnapWindow)
SnapManager.OnMoving(ref m);
break;
}
if (m.Msg == TaskbarButtonCreatedMessage && Core.TaskbarProgress)
@@ -1255,7 +1344,7 @@ namespace mpvnet
if (CommandPaletteHost == null)
return;
CommandPaletteHost.Width = FontHeight * 25;
CommandPaletteHost.Width = FontHeight * 26;
if (CommandPaletteHost.Width > ClientSize.Width)
CommandPaletteHost.Width = ClientSize.Width;

View File

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

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using static mpvnet.Native;
namespace mpvnet
{
public class SnapManager
{
int DragOffsetX { get; set; }
int DragOffsetY { get; set; }
IntPtr Handle;
[Flags]
public enum SnapLocation
{
None = 0,
Left = 1 << 0,
Top = 1 << 1,
Right = 1 << 2,
Bottom = 1 << 3,
All = Left | Top | Right | Bottom
}
public int AnchorDistance { get; set; }
public int SnapDistance { get; set; }
bool InSnapRange(int a, int b) => Math.Abs(a - b) < SnapDistance;
void FindSnap(ref Rectangle effectiveBounds)
{
Screen currentScreen = Screen.FromPoint(effectiveBounds.Location);
Rectangle workingArea = GetWorkingArea(Handle, currentScreen.WorkingArea);
if (InSnapRange(effectiveBounds.Left, workingArea.Left + AnchorDistance))
effectiveBounds.X = workingArea.Left + AnchorDistance;
else if (InSnapRange(effectiveBounds.Right, workingArea.Right - AnchorDistance))
effectiveBounds.X = workingArea.Right - AnchorDistance - effectiveBounds.Width;
if (InSnapRange(effectiveBounds.Top, workingArea.Top + AnchorDistance))
effectiveBounds.Y = workingArea.Top + AnchorDistance;
else if (InSnapRange(effectiveBounds.Bottom, workingArea.Bottom - AnchorDistance))
effectiveBounds.Y = workingArea.Bottom - AnchorDistance - effectiveBounds.Height;
}
public void OnMoving(ref Message m)
{
if (Handle == IntPtr.Zero)
return;
RECT boundsLtrb = Marshal.PtrToStructure<RECT>(m.LParam);
Rectangle bounds = boundsLtrb.ToRectangle();
// This is where the window _would_ be located if snapping
// had not occurred. This prevents the cursor from sliding
// off the title bar if the snap distance is too large.
Rectangle effectiveBounds = new Rectangle(
Cursor.Position.X - DragOffsetX,
Cursor.Position.Y - DragOffsetY,
bounds.Width,
bounds.Height);
FindSnap(ref effectiveBounds);
RECT newLtrb = RECT.FromRectangle(effectiveBounds);
Marshal.StructureToPtr(newLtrb, m.LParam, false);
m.Result = new IntPtr(1);
}
public void OnSizeAndEnterSizeMove(Form form)
{
Handle = form.Handle;
SnapDistance = form.Font.Height;
// Need to handle window size changed as well when
// un-maximizing the form by dragging the title bar.
DragOffsetX = Cursor.Position.X - form.Left;
DragOffsetY = Cursor.Position.Y - form.Top;
}
}
}

View File

@@ -69,6 +69,7 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
@@ -93,6 +94,7 @@
<Compile Include="Misc\Common.cs" />
<Compile Include="Misc\FolderBrowser.cs" />
<Compile Include="Misc\JSONParser.cs" />
<Compile Include="WinForms\SnapManager.cs" />
<Compile Include="WPF\HandyControl\Controls\Attach\BorderElement.cs" />
<Compile Include="WPF\HandyControl\Controls\Attach\MenuTopLineAttach.cs" />
<Compile Include="WPF\HandyControl\Tools\Converter\BorderCircularConverter.cs" />
@@ -186,10 +188,10 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Native\libmpv.cs" />
<Compile Include="Misc\MainForm.cs">
<Compile Include="WinForms\MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Misc\MainForm.Designer.cs">
<Compile Include="WinForms\MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Misc\Misc.cs" />
@@ -211,7 +213,7 @@
<DependentUpon>InputWindow.xaml</DependentUpon>
</Compile>
<Compile Include="WPF\WPF.cs" />
<EmbeddedResource Include="Misc\MainForm.resx">
<EmbeddedResource Include="WinForms\MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>