Compare commits

...

10 Commits
2.9 ... 3.1

Author SHA1 Message Date
Frank Skare
2415e2ed43 - 2019-04-21 00:18:42 +02:00
Frank Skare
d5d26784e8 - 2019-04-21 00:04:39 +02:00
Frank Skare
6c1bad15f2 - 2019-04-21 00:00:48 +02:00
Frank Skare
5137e43aad - 2019-04-20 23:59:31 +02:00
Frank Skare
6fc0ebf9d5 - 2019-04-20 23:49:05 +02:00
Frank Skare
a0e30ff982 - 2019-04-20 23:27:14 +02:00
Frank Skare
c2a0d95851 - 2019-04-20 23:07:04 +02:00
Frank Skare
34d5d2fff5 - 2019-04-20 20:56:54 +02:00
Frank Skare
baa669fe1e - 2019-04-20 20:51:05 +02:00
Frank Skare
67ecebbf6b - 2019-04-20 04:34:44 +02:00
13 changed files with 376 additions and 279 deletions

View File

@@ -11,7 +11,7 @@ Public Class CSScriptAddon
Implements IAddon
Sub New()
Dim scriptDir = mp.mpvConfFolderPath + "scripts"
Dim scriptDir = mp.MpvConfFolderPath + "scripts"
If Not Directory.Exists(scriptDir) Then Return
Dim csFiles = Directory.GetFiles(scriptDir, "*.cs").ToList
csFiles.AddRange(Directory.GetFiles(Application.StartupPath + "\\Scripts", "*.cs"))

View File

@@ -23,7 +23,7 @@ Table of contents
- Searchable options dialog with modern UI as mpv compatible standalone application
- Searchable input (key/mouse) binding editor with modern UI as mpv compatible standalone application
- Modern UI using the OS theme color and dark mode
- Rich addon API for .NET languages, over 700 available mpv properties
- Rich addon/extension API for .NET languages, over 700 available mpv properties
- Rich scripting API for Python, C#, Lua, JavaScript and PowerShell
- mpv's OSC (on screen controller (play control bar)), IPC, conf files
@@ -61,18 +61,28 @@ if it's missing mpv.net generates it with the following defaults:
Scripting is supported via Python, C#, Lua, JavaScript and PowerShell
https://github.com/stax76/mpv.net/wiki/Scripting-(CSharp,-Python,-JavaScript,-Lua,-PowerShell)
[Scripting wiki page](https://github.com/stax76/mpv.net/wiki/Scripting-(CSharp,-Python,-JavaScript,-Lua,-PowerShell))
### Support
<https://forum.doom9.org/showthread.php?t=174841>
[Support thread in Doom9 forum](https://forum.doom9.org/showthread.php?t=174841)
<https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows>
[Support thread in VideoHelp forum](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows)
<https://github.com/stax76/mpv.net/issues>
[Issue tracker to report bugs and request features](https://github.com/stax76/mpv.net/issues)
### Changelog
### 3.0 (2019-04-20)
- the history feature logs now only files that were opened longer than 90 seconds
- the default input command for cycling the audio tracks was replaced with an
mpv.net command that shows detailed track info and has no 'no audio' track. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L89).
- new website at <https://mpv-net.github.io/mpv.net-web-site/>
- the Tracks menu supports now MKV edition selection. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L106).
- the Navigate menu supports now chapter selection. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L57).
- opening the context menu was crashing if the default binding for Tracks was missing
### 2.9 (2019-04-16)
- clicking the right top corner in full screen mode
@@ -96,6 +106,4 @@ https://github.com/stax76/mpv.net/wiki/Scripting-(CSharp,-Python,-JavaScript,-Lu
- the context menu has a new track menu where the active track
can be seen and selected, it shows video, audio and subtitle
tracks with various metadata. [Menu default definition](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt#L104).
The screenshots were updated showing the [new track menu](https://github.com/stax76/mpv.net#screenshots).
[go to download page](https://github.com/stax76/mpv.net/releases)
The screenshots were updated showing the [new track menu](https://github.com/stax76/mpv.net#screenshots).

View File

@@ -10,7 +10,7 @@ namespace RatingAddon
[Export(typeof(IAddon))]
public class RatingAddon : IAddon
{
private Dictionary<string, int> Dic = new Dictionary<string, int>();
Dictionary<string, int> Dic = new Dictionary<string, int>();
public RatingAddon()
{
@@ -18,7 +18,7 @@ namespace RatingAddon
mp.Shutdown += mpv_Shutdown;
}
private void mpv_Shutdown()
void mpv_Shutdown()
{
foreach (var i in Dic)
{
@@ -44,7 +44,7 @@ namespace RatingAddon
}
}
private void mpv_ClientMessage(string[] args)
void mpv_ClientMessage(string[] args)
{
int rating;

View File

@@ -58,7 +58,7 @@ Public Class Msg
End Try
End Sub
Private Shared ShownMessages As String
Shared ShownMessages As String
Public Shared Sub ShowWarning(mainInstruction As String,
Optional content As String = Nothing,
@@ -421,11 +421,11 @@ Public Class TaskDialog(Of T)
Private ExitTickCount As Integer
Private Function DialogProc(hwnd As IntPtr,
msg As UInteger,
wParam As IntPtr,
lParam As IntPtr,
lpRefData As IntPtr) As Integer
Function DialogProc(hwnd As IntPtr,
msg As UInteger,
wParam As IntPtr,
lParam As IntPtr,
lpRefData As IntPtr) As Integer
Select Case msg
Case TDN_BUTTON_CLICKED, TDN_RADIO_BUTTON_CLICKED
If TypeOf SelectedValue Is MsgResult Then
@@ -464,7 +464,7 @@ Public Class TaskDialog(Of T)
End Select
End Function
Private Sub MarshalDialogControlStructs()
Sub MarshalDialogControlStructs()
If Not Buttons Is Nothing AndAlso Buttons.Count > 0 Then
ButtonArray = AllocateAndMarshalButtons(Buttons)
Config.pButtons = ButtonArray
@@ -478,7 +478,7 @@ Public Class TaskDialog(Of T)
End If
End Sub
Private Shared Function AllocateAndMarshalButtons(structs As List(Of TASKDIALOG_BUTTON)) As IntPtr
Shared Function AllocateAndMarshalButtons(structs As List(Of TASKDIALOG_BUTTON)) As IntPtr
Dim initialPtr = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(TASKDIALOG_BUTTON)) * structs.Count)
Dim currentPtr = initialPtr

View File

@@ -14,7 +14,7 @@ namespace mpvnet
[ImportMany]
public IEnumerable<IAddon> Addons = null;
private readonly CompositionContainer CompositionContainer;
readonly CompositionContainer CompositionContainer;
public Addon()
{
@@ -28,7 +28,7 @@ namespace mpvnet
foreach (string i in Directory.GetDirectories(dir))
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Addon.dll"));
dir = mp.mpvConfFolderPath + "\\Addons";
dir = mp.MpvConfFolderPath + "\\Addons";
if (Directory.Exists(dir))
foreach (string i in Directory.GetDirectories(dir))

View File

@@ -2,8 +2,8 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
using VBNET;
@@ -15,7 +15,7 @@ namespace mpvnet
public string Name { get; set; }
public Action<string[]> Action { get; set; }
private static List<Command> commands;
static List<Command> commands;
public static List<Command> Commands
{
@@ -58,7 +58,7 @@ namespace mpvnet
public static void open_conf_folder(string[] args)
{
Process.Start(mp.mpvConfFolderPath);
Process.Start(mp.MpvConfFolderPath);
}
public static void show_input_editor(string[] args)
@@ -73,7 +73,7 @@ namespace mpvnet
public static void show_history(string[] args)
{
var fp = mp.mpvConfFolderPath + "history.txt";
var fp = mp.MpvConfFolderPath + "history.txt";
if (File.Exists(fp))
Process.Start(fp);
@@ -197,5 +197,22 @@ namespace mpvnet
}
}));
}
public static void cycle_audio(string[] args)
{
string filePath = mp.get_property_string("path", false);
if (!File.Exists(filePath)) return;
using (MediaInfo mi = new MediaInfo(filePath))
{
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
if (audTracks.Length < 2) return;
int aid = mp.get_property_int("aid");
aid += 1;
if (aid > audTracks.Length) aid = 1;
mp.commandv("set", "aid", aid.ToString());
mp.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000");
}
}
}
}

View File

@@ -6,32 +6,35 @@ using System.Threading;
using System.Windows.Forms;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using VBNET;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Globalization;
namespace mpvnet
{
public partial class MainForm : Form
{
public static MainForm Instance { get; set; }
public static IntPtr Hwnd;
public static IntPtr Hwnd { get; set; }
private Point LastCursorPosChanged;
private int LastCursorChangedTickCount;
private bool IgnoreDpiChanged = true;
private MenuItemEx TracksMenu;
private List<MediaTrack> MediaTracks = new List<MediaTrack>();
public new ContextMenuStripEx ContextMenu;
private float MpvAutofit = 0.50f;
private bool MpvFullscreen;
private int MpvScreen = -1;
private string MpvNetDarkMode = "system";
private string MpvSid = "";
private string MpvAid = "";
private string MpvVid = "";
MenuItemEx TracksMenu;
MenuItemEx ChaptersMenu;
Point LastCursorPosChanged;
int LastCursorChangedTickCount;
bool IgnoreDpiChanged = true;
float MpvAutofit = 0.50f;
bool MpvFullscreen;
int MpvScreen = -1;
string MpvNetDarkMode = "system";
string MpvSid = "";
string MpvAid = "";
string MpvVid = "";
int MpvEdition;
public MainForm()
{
@@ -67,19 +70,21 @@ namespace mpvnet
}
}
private void ContextMenu_Opening(object sender, CancelEventArgs e)
void ContextMenu_Opening(object sender, CancelEventArgs e)
{
lock (MediaTracks)
lock (mp.MediaTracks)
{
TracksMenu.DropDownItems.Clear();
if (TracksMenu != null)
TracksMenu.DropDownItems.Clear();
MediaTrack[] audTracks = MediaTracks.Where(track => track.Type == "a").ToArray();
MediaTrack[] subTracks = MediaTracks.Where(track => track.Type == "s").ToArray();
MediaTrack[] vidTracks = MediaTracks.Where(track => track.Type == "v").ToArray();
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
MediaTrack[] subTracks = mp.MediaTracks.Where(track => track.Type == "s").ToArray();
MediaTrack[] vidTracks = mp.MediaTracks.Where(track => track.Type == "v").ToArray();
MediaTrack[] ediTracks = mp.MediaTracks.Where(track => track.Type == "e").ToArray();
foreach (MediaTrack track in vidTracks)
{
var mi = ContextMenu.Add("Track > " + track.Text);
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
mi.Action = () => { mp.commandv("set", "vid", track.ID.ToString()); };
mi.Checked = MpvVid == track.ID.ToString();
}
@@ -89,7 +94,7 @@ namespace mpvnet
foreach (MediaTrack track in audTracks)
{
var mi = ContextMenu.Add("Track > " + track.Text);
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
mi.Action = () => { mp.commandv("set", "aid", track.ID.ToString()); };
mi.Checked = MpvAid == track.ID.ToString();
}
@@ -99,17 +104,40 @@ namespace mpvnet
foreach (MediaTrack track in subTracks)
{
var mi = ContextMenu.Add("Track > " + track.Text);
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
mi.Action = () => { mp.commandv("set", "sid", track.ID.ToString()); };
mi.Checked = MpvSid == track.ID.ToString();
}
if (subTracks.Length > 0)
{
var mi = ContextMenu.Add("Track > S: No subtitles");
MenuItemEx mi = ContextMenu.Add("Track > S: No subtitles");
mi.Action = () => { mp.commandv("set", "sid", "no"); };
mi.Checked = MpvSid == "no";
}
if (ediTracks.Length > 0)
ContextMenu.Add("Track > -");
foreach (MediaTrack track in ediTracks)
{
MenuItemEx mi = ContextMenu.Add("Track > " + track.Text);
mi.Action = () => { mp.commandv("set", "edition", track.ID.ToString()); };
mi.Checked = MpvEdition == track.ID;
}
}
lock (mp.Chapters)
{
if (ChaptersMenu != null)
ChaptersMenu.DropDownItems.Clear();
foreach (var i in mp.Chapters)
{
MenuItemEx mi = ContextMenu.Add("Navigate > Chapters > " + i.Key);
mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " ";
mi.Action = () => { mp.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute"); };
}
}
}
@@ -280,131 +308,39 @@ namespace mpvnet
menuItem.Text.Trim() == "Track")
TracksMenu = menuItem;
if (ChaptersMenu == null && menuItem.Text.StartsWith("Chapters ") &&
menuItem.Text.Trim() == "Chapters")
ChaptersMenu = menuItem;
}
}
}
private void ContextMenu_Opened(object sender, EventArgs e) => CursorHelp.Show();
void ContextMenu_Opened(object sender, EventArgs e) => CursorHelp.Show();
private string LastHistory;
void mp_PlaybackRestart() => BeginInvoke(new Action(() => { Text = Path.GetFileName(mp.get_property_string("path")) + " - mpv.net " + Application.ProductVersion; }));
private void mp_PlaybackRestart()
{
string filePath = mp.get_property_string("path");
BeginInvoke(new Action(() => { Text = Path.GetFileName(filePath) + " - mpv.net " + Application.ProductVersion; }));
void Mp_Idle() => BeginInvoke(new Action(() => { Text = "mpv.net " + Application.ProductVersion; }));
Task.Run(new Action(() => {
string historyFilepath = mp.mpvConfFolderPath + "history.txt";
void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
if (LastHistory != filePath && File.Exists(historyFilepath))
{
File.AppendAllText(historyFilepath, DateTime.Now.ToString() + " " +
Path.GetFileNameWithoutExtension(filePath) + "\r\n");
LastHistory = filePath;
}
lock (MediaTracks)
{
MediaTracks.Clear();
using (MediaInfo mi = new MediaInfo(filePath))
{
int count = mi.GetCount(MediaInfoStreamKind.Video);
for (int i = 0; i < count; i++)
{
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, "FrameRate") + " 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, mi.GetVideo(i, "Title"));
track.Text = "V: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "v";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = mi.GetCount(MediaInfoStreamKind.Audio);
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetAudio(i, "Language/String"));
Add(track, mi.GetAudio(i, "Format"));
Add(track, mi.GetAudio(i, "Format_Profile"));
Add(track, mi.GetAudio(i, "BitRate/String"));
Add(track, mi.GetAudio(i, "Channel(s)/String"));
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"));
track.Text = "A: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "a";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = mi.GetCount(MediaInfoStreamKind.Text);
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetText(i, "Language/String"));
Add(track, mi.GetText(i, "Format"));
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"));
track.Text = "S: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "s";
track.ID = i + 1;
MediaTracks.Add(track);
}
void Add(MediaTrack track, string val)
{
if (!string.IsNullOrEmpty(val) && !(track.Text != null && track.Text.Contains(val)))
track.Text += " " + val + ",";
}
}
}
}));
}
class MediaTrack
{
public string Text { get; set; }
public string Type { get; set; }
public int ID { get; set; }
}
private void Mp_Idle()
{
BeginInvoke(new Action(() => { Text = "mpv.net " + Application.ProductVersion; }));
}
private void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
Msg.ShowException(e.Exception);
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Msg.ShowError(e.ExceptionObject.ToString());
}
private void mp_VideoSizeChanged()
void mp_VideoSizeChanged()
{
BeginInvoke(new Action(() => SetFormPositionAndSizeKeepHeight()));
}
private void mp_Shutdown()
void mp_Shutdown()
{
BeginInvoke(new Action(() => Close()));
}
@@ -531,12 +467,9 @@ namespace mpvnet
CursorHelp.Show();
}
bool IsMouseInOSC()
{
return PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
}
bool IsMouseInOSC() => PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
private void Timer_Tick(object sender, EventArgs e)
void Timer_Tick(object sender, EventArgs e)
{
if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
{
@@ -568,6 +501,7 @@ namespace mpvnet
mp.observe_property_string("sid", mpPropChangeSid);
mp.observe_property_string("aid", mpPropChangeAid);
mp.observe_property_string("vid", mpPropChangeVid);
mp.observe_property_int("edition", mpPropChangeEdition);
mp.Shutdown += mp_Shutdown;
mp.VideoSizeChanged += mp_VideoSizeChanged;
mp.PlaybackRestart += mp_PlaybackRestart;
@@ -582,6 +516,8 @@ namespace mpvnet
void mpPropChangeVid(string value) => MpvVid = value;
void mpPropChangeEdition(int value) => MpvEdition = value;
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
@@ -600,7 +536,7 @@ namespace mpvnet
{
base.OnFormClosed(e);
mp.commandv("quit");
mp.AutoResetEvent.WaitOne(3000);
mp.AutoResetEvent.WaitOne(3000);
}
protected override void OnLostFocus(EventArgs e)
@@ -615,14 +551,14 @@ namespace mpvnet
CheckYouTube();
}
private string LastURL;
void CheckYouTube()
{
string clipboard = Clipboard.GetText();
if (clipboard.StartsWith("https://www.youtube.com/watch?") && LastURL != clipboard && Visible)
if (clipboard.StartsWith("https://www.youtube.com/watch?") && RegistryHelp.GetValue("HKCU\\Software\\" + Application.ProductName, "LastYouTubeURL") != clipboard && Visible)
{
LastURL = clipboard;
RegistryHelp.SetValue("HKCU\\Software\\" + Application.ProductName, "LastYouTubeURL", clipboard);
if (Msg.ShowQuestion("Play YouTube URL?") == MsgResult.OK)
mp.LoadURL(clipboard);
}

View File

@@ -3,8 +3,8 @@ using System.Runtime.InteropServices;
public class MediaInfo : IDisposable
{
private IntPtr Handle;
private static bool Loaded;
IntPtr Handle;
static bool Loaded;
public MediaInfo(string sourcepath)
{
@@ -42,7 +42,7 @@ public class MediaInfo : IDisposable
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Text, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
}
private bool Disposed;
bool Disposed;
public void Dispose()
{
@@ -57,32 +57,32 @@ public class MediaInfo : IDisposable
~MediaInfo() { Dispose(); }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string path);
static extern IntPtr LoadLibrary(string path);
[DllImport("MediaInfo.dll")]
private static extern IntPtr MediaInfo_New();
static extern IntPtr MediaInfo_New();
[DllImport("MediaInfo.dll")]
private static extern void MediaInfo_Delete(IntPtr handle);
static extern void MediaInfo_Delete(IntPtr handle);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
private static extern int MediaInfo_Open(IntPtr handle, string fileName);
static extern int MediaInfo_Open(IntPtr handle, string fileName);
[DllImport("MediaInfo.dll")]
private static extern int MediaInfo_Close(IntPtr handle);
static extern int MediaInfo_Close(IntPtr handle);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr MediaInfo_Get(IntPtr handle,
MediaInfoStreamKind streamKind,
int streamNumber,
string parameter,
MediaInfoInfoKind kindOfInfo,
MediaInfoInfoKind kindOfSearch);
static extern IntPtr MediaInfo_Get(IntPtr handle,
MediaInfoStreamKind streamKind,
int streamNumber,
string parameter,
MediaInfoInfoKind kindOfInfo,
MediaInfoInfoKind kindOfSearch);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
private static extern int MediaInfo_Count_Get(IntPtr handle,
MediaInfoStreamKind streamKind,
int streamNumber);
static extern int MediaInfo_Count_Get(IntPtr handle,
MediaInfoStreamKind streamKind,
int streamNumber);
}
public enum MediaInfoStreamKind

View File

@@ -149,7 +149,7 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
public static Color ColorToolStrip3 { get; set; }
public static Color ColorToolStrip4 { get; set; }
private int TextOffset;
int TextOffset;
public ToolStripRendererEx()
{
@@ -321,28 +321,28 @@ public struct HSLColor
Luminosity = l;
}
private double hue;
double _Hue;
public int Hue {
get => System.Convert.ToInt32(hue * 240);
set => hue = CheckRange(value / 240.0);
get => System.Convert.ToInt32(_Hue * 240);
set => _Hue = CheckRange(value / 240.0);
}
private double saturation;
double _Saturation;
public int Saturation {
get => System.Convert.ToInt32(saturation * 240);
set => saturation = CheckRange(value / 240.0);
get => System.Convert.ToInt32(_Saturation * 240);
set => _Saturation = CheckRange(value / 240.0);
}
private double luminosity;
double _Luminosity;
public int Luminosity {
get => System.Convert.ToInt32(luminosity * 240);
set => luminosity = CheckRange(value / 240.0);
get => System.Convert.ToInt32(_Luminosity * 240);
set => _Luminosity = CheckRange(value / 240.0);
}
private double CheckRange(double value)
double CheckRange(double value)
{
if (value < 0)
value = 0;
@@ -367,21 +367,21 @@ public struct HSLColor
{
double r = 0, g = 0, b = 0;
if (luminosity != 0)
if (_Luminosity != 0)
{
if (saturation == 0)
if (_Saturation == 0)
{
b = luminosity;
g = luminosity;
r = luminosity;
b = _Luminosity;
g = _Luminosity;
r = _Luminosity;
}
else
{
double temp2 = GetTemp2(this);
double temp1 = 2.0 * luminosity - temp2;
r = GetColorComponent(temp1, temp2, hue + 1.0 / 3.0);
g = GetColorComponent(temp1, temp2, hue);
b = GetColorComponent(temp1, temp2, hue - 1.0 / 3.0);
double temp1 = 2.0 * _Luminosity - temp2;
r = GetColorComponent(temp1, temp2, _Hue + 1.0 / 3.0);
g = GetColorComponent(temp1, temp2, _Hue);
b = GetColorComponent(temp1, temp2, _Hue - 1.0 / 3.0);
}
}
@@ -391,7 +391,7 @@ public struct HSLColor
System.Convert.ToInt32(255 * b));
}
private static double GetColorComponent(double temp1, double temp2, double temp3)
static double GetColorComponent(double temp1, double temp2, double temp3)
{
temp3 = MoveIntoRange(temp3);
@@ -405,7 +405,7 @@ public struct HSLColor
return temp1;
}
private static double MoveIntoRange(double temp3)
static double MoveIntoRange(double temp3)
{
if (temp3 < 0)
temp3 += 1;
@@ -414,14 +414,14 @@ public struct HSLColor
return temp3;
}
private static double GetTemp2(HSLColor hslColor)
static double GetTemp2(HSLColor hslColor)
{
double temp2;
if (hslColor.luminosity < 0.5)
temp2 = hslColor.luminosity * (1.0 + hslColor.saturation);
if (hslColor._Luminosity < 0.5)
temp2 = hslColor._Luminosity * (1.0 + hslColor._Saturation);
else
temp2 = hslColor.luminosity + hslColor.saturation - (hslColor.luminosity * hslColor.saturation);
temp2 = hslColor._Luminosity + hslColor._Saturation - (hslColor._Luminosity * hslColor._Saturation);
return temp2;
}
@@ -429,17 +429,17 @@ public struct HSLColor
public static HSLColor Convert(Color c)
{
HSLColor r = new HSLColor();
r.hue = c.GetHue() / 360.0;
r.luminosity = c.GetBrightness();
r.saturation = c.GetSaturation();
r._Hue = c.GetHue() / 360.0;
r._Luminosity = c.GetBrightness();
r._Saturation = c.GetSaturation();
return r;
}
public void SetRGB(int red, int green, int blue)
{
HSLColor hc = HSLColor.Convert(Color.FromArgb(red, green, blue));
hue = hc.hue;
saturation = hc.saturation;
luminosity = hc.luminosity;
_Hue = hc._Hue;
_Saturation = hc._Saturation;
_Luminosity = hc._Luminosity;
}
}

View File

@@ -99,6 +99,15 @@ namespace mpvnet
rk.SetValue(name, value);
}
public static string GetValue(string path, string name)
{
using (RegistryKey rk = GetRootKey(path).OpenSubKey(path.Substring(5)))
if (rk != null)
return rk.GetValue(name, "").ToString();
else
return "";
}
public static void RemoveKey(string path)
{
GetRootKey(path).DeleteSubKeyTree(path.Substring(5), false);
@@ -122,4 +131,11 @@ namespace mpvnet
}
}
}
public class MediaTrack
{
public string Text { get; set; }
public string Type { get; set; }
public int ID { get; set; }
}
}

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("2.9.0.0")]
[assembly: AssemblyFileVersion("2.9.0.0")]
[assembly: AssemblyVersion("3.0.0.0")]
[assembly: AssemblyFileVersion("3.0.0.0")]

View File

@@ -53,6 +53,8 @@
_ ignore #menu: Navigate > -
Ctrl+Right no-osd seek 300 #menu: Navigate > Jump 5 min forward
Ctrl+Left no-osd seek -300 #menu: Navigate > Jump 5 min backward
_ ignore #menu: Navigate > -
_ ignore #menu: Navigate > Chapters
Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size
Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size
@@ -84,7 +86,7 @@
d cycle deinterlace #menu: Video > Toggle Deinterlace
a cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1" #menu: Video > Cycle Aspect Ratio
KP7 cycle audio #menu: Audio > Cycle/Next
KP7 script-message mpv.net cycle-audio #menu: Audio > Cycle/Next
_ ignore #menu: Audio > -
KP6 add audio-delay 0.100 #menu: Audio > Delay +0.1
KP9 add audio-delay -0.100 #menu: Audio > Delay -0.1
@@ -116,12 +118,12 @@
_ ignore #menu: Speed > -
BS set speed 1 #menu: Speed > Reset
KP0 script-message rate-file 0 #menu: Addons > Rating > 0stars
KP1 script-message rate-file 1 #menu: Addons > Rating > 1stars
KP2 script-message rate-file 2 #menu: Addons > Rating > 2stars
KP3 script-message rate-file 3 #menu: Addons > Rating > 3stars
KP4 script-message rate-file 4 #menu: Addons > Rating > 4stars
KP5 script-message rate-file 5 #menu: Addons > Rating > 5stars
KP0 script-message rate-file 0 #menu: Extensions > Rating > 0stars
KP1 script-message rate-file 1 #menu: Extensions > Rating > 1stars
KP2 script-message rate-file 2 #menu: Extensions > Rating > 2stars
KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
Ctrl+t set ontop yes #menu: View > On Top > Enable
Ctrl+T set ontop no #menu: View > On Top > Disable
@@ -150,6 +152,7 @@
_ ignore #menu: -
Esc quit #menu: Exit
Q quit-watch-later #menu: Exit Watch Later
> playlist-next
< playlist-prev
Power quit

View File

@@ -53,20 +53,23 @@ namespace mpvnet
public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW
public static event Action Hook; // MPV_EVENT_HOOK
public static IntPtr MpvHandle;
public static IntPtr MpvWindowHandle;
public static Addon Addon;
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions = new List<KeyValuePair<string, Action<bool>>>();
public static List<KeyValuePair<string, Action<string>>> StringPropChangeActions = new List<KeyValuePair<string, Action<string>>>();
public static Size VideoSize = new Size(1920, 1080);
public static string mpvConfFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
public static string InputConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf";
public static string mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
public static string mpvNetConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpvnet.conf";
public static List<PythonScript> PythonScripts => new List<PythonScript>();
public static AutoResetEvent AutoResetEvent = new AutoResetEvent(false);
public static IntPtr MpvHandle { get; set; }
public static IntPtr MpvWindowHandle { get; set; }
public static Addon Addon { get; set; }
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<bool>>>();
public static List<KeyValuePair<string, Action<int>>> IntPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<int>>>();
public static List<KeyValuePair<string, Action<string>>> StringPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<string>>>();
public static Size VideoSize { get; set; } = new Size(1920, 1080);
public static string MpvConfFolderPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
public static string InputConfPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf";
public static string MpvConfPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
public static string MpvNetConfPath { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpvnet.conf";
public static List<PythonScript> PythonScripts { get; set; } = new List<PythonScript>();
public static AutoResetEvent AutoResetEvent { get; set; } = new AutoResetEvent(false);
public static List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public static List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>();
private static Dictionary<string, string> _mpvConf;
static Dictionary<string, string> _mpvConf;
public static Dictionary<string, string> mpvConf {
get {
@@ -74,8 +77,8 @@ namespace mpvnet
{
_mpvConf = new Dictionary<string, string>();
if (File.Exists(mpvConfPath))
foreach (var i in File.ReadAllLines(mpvConfPath))
if (File.Exists(MpvConfPath))
foreach (var i in File.ReadAllLines(MpvConfPath))
if (i.Contains("=") && ! i.StartsWith("#"))
_mpvConf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
@@ -83,7 +86,7 @@ namespace mpvnet
}
}
private static Dictionary<string, string> _mpvNetConf;
static Dictionary<string, string> _mpvNetConf;
public static Dictionary<string, string> mpvNetConf {
get {
@@ -91,8 +94,8 @@ namespace mpvnet
{
_mpvNetConf = new Dictionary<string, string>();
if (File.Exists(mpvNetConfPath))
foreach (string i in File.ReadAllLines(mpvNetConfPath))
if (File.Exists(MpvNetConfPath))
foreach (string i in File.ReadAllLines(MpvNetConfPath))
if (i.Contains("=") && !i.StartsWith("#"))
_mpvNetConf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
@@ -102,11 +105,11 @@ namespace mpvnet
public static void Init()
{
if (!Directory.Exists(mp.mpvConfFolderPath))
Directory.CreateDirectory(mp.mpvConfFolderPath);
if (!Directory.Exists(mp.MpvConfFolderPath))
Directory.CreateDirectory(mp.MpvConfFolderPath);
if (!File.Exists(mp.mpvConfPath))
File.WriteAllText(mp.mpvConfPath, Properties.Resources.mpv_conf);
if (!File.Exists(mp.MpvConfPath))
File.WriteAllText(mp.MpvConfPath, Properties.Resources.mpv_conf);
if (!File.Exists(mp.InputConfPath))
File.WriteAllText(mp.InputConfPath, Properties.Resources.input_conf);
@@ -143,7 +146,7 @@ namespace mpvnet
if (Path.GetExtension(scriptPath) == ".ps1")
PowerShellScript.Init(scriptPath);
foreach (var scriptPath in Directory.GetFiles(mp.mpvConfFolderPath + "Scripts"))
foreach (var scriptPath in Directory.GetFiles(mp.MpvConfFolderPath + "Scripts"))
if (Path.GetExtension(scriptPath) == ".py")
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
else if (Path.GetExtension(scriptPath) == ".ps1")
@@ -168,6 +171,7 @@ namespace mpvnet
{
case mpv_event_id.MPV_EVENT_SHUTDOWN:
Shutdown?.Invoke();
WriteHistory(null);
AutoResetEvent.Set();
return;
case mpv_event_id.MPV_EVENT_LOG_MESSAGE:
@@ -266,6 +270,11 @@ namespace mpvnet
foreach (var i in StringPropChangeActions)
if (i.Key == propData.name)
i.Value.Invoke(StringFromNativeUtf8(Marshal.PtrToStructure<IntPtr>(propData.data)));
if (propData.format == mpv_format.MPV_FORMAT_INT64)
foreach (var i in IntPropChangeActions)
if (i.Key == propData.name)
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data));
break;
case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART:
PlaybackRestart?.Invoke();
@@ -275,7 +284,12 @@ namespace mpvnet
{
VideoSize = s;
VideoSizeChanged?.Invoke();
}
}
Task.Run(new Action(() => {
WriteHistory(mp.get_property_string("path"));
ReadMetaData();
}));
break;
case mpv_event_id.MPV_EVENT_CHAPTER_CHANGE:
ChapterChange?.Invoke();
@@ -295,7 +309,7 @@ namespace mpvnet
}
}
private static List<PythonEventObject> PythonEventObjects = new List<PythonEventObject>();
static List<PythonEventObject> PythonEventObjects = new List<PythonEventObject>();
public static void register_event(string name, PyRT.PythonFunction pyFunc)
{
@@ -437,6 +451,16 @@ namespace mpvnet
throw new Exception($"{name}: {(mpv_error)err}");
}
public static void observe_property_int(string name, Action<int> action)
{
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_INT64);
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
else
IntPropChangeActions.Add(new KeyValuePair<string, Action<int>>(name, action));
}
public static void observe_property_bool(string name, Action<bool> action)
{
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_FLAG);
@@ -447,18 +471,6 @@ namespace mpvnet
BoolPropChangeActions.Add(new KeyValuePair<string, Action<bool>>(name, action));
}
public static void unobserve_property_bool(string name, Action<bool> action)
{
foreach (var i in BoolPropChangeActions.ToArray())
if (i.Value == action)
BoolPropChangeActions.Remove(i);
int err = mpv_unobserve_property(MpvHandle, (ulong)action.GetHashCode());
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
}
public static void observe_property_string(string name, Action<string> action)
{
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_STRING);
@@ -469,18 +481,6 @@ namespace mpvnet
StringPropChangeActions.Add(new KeyValuePair<string, Action<string>>(name, action));
}
public static void unobserve_property_string(string name, Action<string> action)
{
foreach (var i in StringPropChangeActions.ToArray())
if (i.Value == action)
StringPropChangeActions.Remove(i);
int err = mpv_unobserve_property(MpvHandle, (ulong)action.GetHashCode());
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
}
protected static void ProcessCommandLine()
{
var args = Environment.GetCommandLineArgs().Skip(1);
@@ -533,9 +533,9 @@ namespace mpvnet
mp.LoadFolder();
}
private static bool WasFolderLoaded;
static bool WasFolderLoaded;
public static void LoadFolder()
static void LoadFolder()
{
if (WasFolderLoaded)
return;
@@ -561,7 +561,7 @@ namespace mpvnet
WasFolderLoaded = true;
}
public static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
{
int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel)
byteArrayPointers = new IntPtr[numberOfStrings];
@@ -579,7 +579,7 @@ namespace mpvnet
return rootPointer;
}
public static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, int StringCount)
static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, int StringCount)
{
IntPtr[] pIntPtrArray = new IntPtr[StringCount];
string[] ManagedStringArray = new string[StringCount];
@@ -591,7 +591,7 @@ namespace mpvnet
return ManagedStringArray;
}
public static string StringFromNativeUtf8(IntPtr nativeUtf8)
static string StringFromNativeUtf8(IntPtr nativeUtf8)
{
int len = 0;
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
@@ -600,7 +600,124 @@ namespace mpvnet
return Encoding.UTF8.GetString(buffer);
}
public static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
static string LastHistoryPath;
static DateTime LastHistoryStartDateTime;
static void WriteHistory(string filePath)
{
int totalMinutes = Convert.ToInt32((DateTime.Now - LastHistoryStartDateTime).TotalMinutes);
if (File.Exists(LastHistoryPath) && totalMinutes > 1)
{
string historyFilepath = mp.MpvConfFolderPath + "history.txt";
File.AppendAllText(historyFilepath, DateTime.Now.ToString().Substring(0, 16) +
" " + totalMinutes.ToString().PadLeft(3) + " " +
Path.GetFileNameWithoutExtension(LastHistoryPath) + "\r\n");
}
LastHistoryPath = filePath;
LastHistoryStartDateTime = DateTime.Now;
}
static void ReadMetaData()
{
lock (MediaTracks)
{
MediaTracks.Clear();
using (MediaInfo mi = new MediaInfo(mp.get_property_string("path")))
{
int count = mi.GetCount(MediaInfoStreamKind.Video);
for (int i = 0; i < count; i++)
{
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, "FrameRate") + " 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, mi.GetVideo(i, "Title"));
track.Text = "V: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "v";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = mi.GetCount(MediaInfoStreamKind.Audio);
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetAudio(i, "Language/String"));
Add(track, mi.GetAudio(i, "Format"));
Add(track, mi.GetAudio(i, "Format_Profile"));
Add(track, mi.GetAudio(i, "BitRate/String"));
Add(track, mi.GetAudio(i, "Channel(s)/String"));
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"));
track.Text = "A: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "a";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = mi.GetCount(MediaInfoStreamKind.Text);
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetText(i, "Language/String"));
Add(track, mi.GetText(i, "Format"));
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"));
track.Text = "S: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "s";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = get_property_int("edition-list/count");
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
track.Text = "E: " + get_property_string($"edition-list/{i}/title");
track.Type = "e";
track.ID = i;
MediaTracks.Add(track);
}
void Add(MediaTrack track, string val)
{
if (!string.IsNullOrEmpty(val) && !(track.Text != null && track.Text.Contains(val)))
track.Text += " " + val + ",";
}
}
}
lock (Chapters)
{
Chapters.Clear();
int count = get_property_int("chapter-list/count");
for (int x = 0; x < count; x++)
{
string text = get_property_string($"chapter-list/{x}/title");
double time = get_property_number($"chapter-list/{x}/time");
Chapters.Add(new KeyValuePair<string, double>(text, time));
}
}
}
}
public enum EndFileEventMode