Compare commits

...

34 Commits

Author SHA1 Message Date
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
16 changed files with 574 additions and 261 deletions

View File

@@ -1,4 +1,38 @@
# 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

@@ -282,6 +282,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 +298,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.
@@ -381,6 +387,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 +437,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
@@ -532,7 +546,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
--------------
@@ -598,64 +612,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 +642,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 +662,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 +771,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 +780,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).

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

@@ -46,6 +46,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;
@@ -170,81 +171,33 @@ namespace mpvnet
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();
}
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");
@@ -255,7 +208,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");
}
@@ -718,6 +670,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)

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; }
@@ -130,7 +129,6 @@ namespace mpvnet
{
SetPropertyString("terminal", "yes");
SetPropertyString("input-terminal", "yes");
SetPropertyString("msg-level", "osd/libass=fatal");
}
SetPropertyInt("osd-duration", 2000);
@@ -149,6 +147,8 @@ namespace mpvnet
ProcessCommandLine(true);
Environment.SetEnvironmentVariable("MPVNET_VERSION", Application.ProductVersion);
mpv_error err = mpv_initialize(Handle);
if (err < 0)
@@ -171,6 +171,7 @@ namespace mpvnet
SetPropertyString("idle", "yes");
ObservePropertyDouble("window-scale", value => WindowScaleMpv(value));
ObservePropertyString("path", value => Path = value);
ObservePropertyBool("pause", value => {
Paused = value;
@@ -249,27 +250,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 +339,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))
{
@@ -436,7 +444,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)
@@ -1186,6 +1194,9 @@ namespace mpvnet
{
string file = files[i];
if (file.Contains("|"))
file = file.Substring(0, file.IndexOf("|"));
if (file.Ext() == "avs")
LoadAviSynth();
@@ -1193,7 +1204,7 @@ namespace mpvnet
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")))
else if (file.Ext().Length != 3 && File.Exists(System.IO.Path.Combine(file, "BDMV\\index.bdmv")))
{
Command("stop");
Thread.Sleep(500);
@@ -1282,7 +1293,7 @@ namespace mpvnet
path = path.Replace("/", "\\");
if (path.Contains("\\"))
dir = Path.GetDirectoryName(path);
dir = System.IO.Path.GetDirectoryName(path);
List<string> files = Directory.GetFiles(dir).ToList();
@@ -1386,6 +1397,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))
@@ -1417,7 +1432,7 @@ namespace mpvnet
}
public void RaiseScaleWindow(float value) => ScaleWindow(value);
public void RaiseWindowScaleNET(float value) => WindowScaleNET(value);
public void RaiseShowMenu() => ShowMenu();
@@ -1437,23 +1452,26 @@ 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()
@@ -1598,7 +1616,7 @@ namespace mpvnet
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";
@@ -1618,7 +1636,7 @@ namespace mpvnet
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, (audioCount > 1 && mi.GetAudio(i, "Default") == "Yes") ? "Default" : "");
Add(track, mi.GetAudio(i, "Title"));
track.Text = "A: " + track.Text.Trim(' ', ',');
track.Type = "a";
@@ -1643,7 +1661,7 @@ namespace mpvnet
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, (subCount > 1 && mi.GetText(i, "Default") == "Yes") ? "Default" : "");
Add(track, mi.GetText(i, "Title"));
track.Text = "S: " + track.Text.Trim(' ', ',');
track.Type = "s";

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

@@ -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.2.0")]
[assembly: AssemblyFileVersion("6.0.2.0")]

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

@@ -94,6 +94,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,6 +120,7 @@ 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
@@ -170,7 +173,6 @@ 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
@@ -211,4 +213,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()
{
@@ -824,7 +866,7 @@ namespace mpvnet
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 +881,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);
@@ -862,7 +904,7 @@ namespace mpvnet
Core.Command($"mouse {pos.X} {pos.Y} 0 double");
}
break;
case 0x02E0: // WM_DPICHANGED
case 0x2E0: // WM_DPICHANGED
{
if (!Core.Shown)
break;
@@ -871,7 +913,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 +941,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 +965,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 +1347,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

@@ -93,6 +93,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 +187,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 +212,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>