Projektdateien hinzufügen.

This commit is contained in:
Kevin Krüger
2023-07-24 12:00:34 +02:00
parent 656751e10b
commit 0d00a90942
210 changed files with 45049 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
namespace VideoBrowser.Helpers
{
using System.Windows;
/// <summary>
/// Defines the <see cref="BindingProxy" />.
/// </summary>
public class BindingProxy : Freezable
{
#region Fields
/// <summary>
/// The binding data context property.
/// </summary>
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register(nameof(DataContext), typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
#endregion Fields
#region Properties
/// <summary>
/// Gets or sets the DataContext.
/// </summary>
public object DataContext
{
get { return GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
#endregion Properties
#region Methods
/// <summary>
/// The CreateInstanceCore.
/// </summary>
/// <returns>The <see cref="Freezable"/>.</returns>
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion Methods
}
}

View File

@@ -0,0 +1,27 @@
namespace VideoBrowser.Helpers
{
/// <summary>
/// Defines the <see cref="DebugHelper" />.
/// </summary>
public class DebugHelper
{
#region Properties
/// <summary>
/// Gets a value indicating whether IsDebug.
/// </summary>
internal static bool IsDebug
{
get
{
#if DEBUG
return true;
#else
return false;
#endif
}
}
#endregion Properties
}
}

View File

@@ -0,0 +1,104 @@
namespace VideoBrowser.Helpers
{
using System;
using System.Windows.Forms;
/// <summary>
/// Defines the <see cref="DelayCall" />.
/// </summary>
public class DelayCall
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="DelayCall"/> class.
/// </summary>
/// <param name="action">The action<see cref="Action"/>.</param>
/// <param name="milliSecondDelay">The milliSecondDelay<see cref="int"/>.</param>
/// <param name="callInUIThread">The callInUIThread<see cref="bool"/>.</param>
public DelayCall(Action action, int milliSecondDelay, bool callInUIThread = false)
{
this.Action = action ?? throw new ArgumentNullException(nameof(action));
this.MilliSecondDelay = milliSecondDelay;
this.IsCallInUIThread = callInUIThread;
this.Timer = new Timer();
this.Timer.Tick += this.OnTimer_Tick;
this.Timer.Interval = this.MilliSecondDelay;
this.Timer.Stop();
}
#endregion Constructors
#region Properties
/// <summary>
/// Gets the Action.
/// </summary>
public Action Action { get; }
/// <summary>
/// Gets a value indicating whether IsCallInUIThread.
/// </summary>
public bool IsCallInUIThread { get; }
/// <summary>
/// Gets or sets the MilliSecondDelay.
/// </summary>
public int MilliSecondDelay { get; set; }
/// <summary>
/// Gets the Timer.
/// </summary>
public Timer Timer { get; }
#endregion Properties
#region Methods
/// <summary>
/// The Call.
/// </summary>
public void Call()
{
this.Restart();
}
/// <summary>
/// The OnThick.
/// </summary>
/// <param name="state">The state<see cref="object"/>.</param>
private void OnThick(object state)
{
this.Timer.Stop();
if (this.IsCallInUIThread)
{
UIThreadHelper.Invoke(this.Action);
}
else
{
this.Action();
}
}
/// <summary>
/// The OnTimer_Tick.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="EventArgs"/>.</param>
private void OnTimer_Tick(object sender, EventArgs e)
{
throw new NotImplementedException();
}
/// <summary>
/// The Restart.
/// </summary>
private void Restart()
{
this.Timer.Stop();
this.Timer.Start();
}
#endregion Methods
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
namespace VideoBrowser.Helpers
{
#region Enums
/// <summary>
/// Defines the FFMpegFileType
/// </summary>
public enum FFMpegFileType
{
/// <summary>
/// Defines the Audio
/// </summary>
Audio,
/// <summary>
/// Defines the Error
/// </summary>
Error,
/// <summary>
/// Defines the Video
/// </summary>
Video
}
#endregion Enums
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
namespace VideoBrowser.Helpers
{
using System.Collections.Generic;
/// <summary>
/// Defines the <see cref="FFMpegResult{T}" />
/// </summary>
/// <typeparam name="T"></typeparam>
public class FFMpegResult<T>
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="FFMpegResult{T}"/> class.
/// </summary>
/// <param name="exitCode">The exitCode<see cref="int"/></param>
/// <param name="errors">The errors<see cref="IEnumerable{string}"/></param>
public FFMpegResult(int exitCode, IEnumerable<string> errors)
{
this.Value = default(T);
this.ExitCode = exitCode;
this.Errors = new List<string>(errors);
}
/// <summary>
/// Initializes a new instance of the <see cref="FFMpegResult{T}"/> class.
/// </summary>
/// <param name="result">The result<see cref="T"/></param>
public FFMpegResult(T result)
{
this.Value = result;
this.ExitCode = 0;
this.Errors = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="FFMpegResult{T}"/> class.
/// </summary>
/// <param name="value">The value<see cref="T"/></param>
/// <param name="exitCode">The exitCode<see cref="int"/></param>
/// <param name="errors">The errors<see cref="IEnumerable{string}"/></param>
public FFMpegResult(T value, int exitCode, IEnumerable<string> errors)
{
this.Value = value;
this.ExitCode = exitCode;
this.Errors = new List<string>(errors);
}
#endregion Constructors
#region Properties
/// <summary>
/// Gets the Errors
/// Gets a list of errors from running FFmpeg. Returns null if there wasn't any errors.
/// </summary>
public List<string> Errors { get; private set; }
/// <summary>
/// Gets or sets the ExitCode
/// Gets the FFmpeg exit code.
/// </summary>
public int ExitCode { get; set; }
/// <summary>
/// Gets the result value.
/// </summary>
public T Value { get; private set; }
#endregion Properties
}
}

View File

@@ -0,0 +1,139 @@
namespace VideoBrowser.Helpers
{
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
/// <summary>
/// Defines the <see cref="FileHelper" />
/// </summary>
public static class FileHelper
{
#region Methods
/// <summary>
/// Returns valid file name.
/// </summary>
/// <param name="filename">The filename to validate.</param>
public static string GetValidFilename(string filename)
{
var illegalChars = Path.GetInvalidFileNameChars();
// Check if filename contains illegal characters
// Returning true for some reason: valid = filename.Any(x => illegalChars.Contains(x));
var valid = filename.IndexOfAny(illegalChars) <= -1;
if (!valid)
{
string new_filename = YoutubeHelper.FormatTitle(filename);
filename = new_filename;
}
return filename;
}
/// <summary>
/// Attempts to delete given file(s), ignoring exceptions for 10 tries, with 2 second delay between each try.
/// </summary>
/// <param name="files">The files to delete.</param>
public static void DeleteFiles(params string[] files)
{
new Thread(delegate ()
{
var dict = new Dictionary<string, int>();
var keys = new List<string>();
foreach (string file in files)
{
dict.Add(file, 0);
keys.Add(file);
}
while (dict.Count > 0)
{
foreach (string key in keys)
{
try
{
if (File.Exists(key))
{
File.Delete(key);
}
// Remove file from dictionary since it either got deleted
// or it doesn't exist anymore.
dict.Remove(key);
}
catch
{
if (dict[key] == 10)
{
dict.Remove(key);
}
else
{
dict[key]++;
}
}
}
Thread.Sleep(2000);
}
}).Start();
}
/// <summary>
/// The GetDirectorySize
/// </summary>
/// <param name="directory">The directory<see cref="string"/></param>
/// <returns>The <see cref="long"/></returns>
public static long GetDirectorySize(string directory)
{
return Directory
.GetFiles(directory, "*.*", SearchOption.AllDirectories)
.Sum(f => new FileInfo(f).Length);
}
/// <summary>
/// The GetDirectorySizeFormatted
/// </summary>
/// <param name="directory">The directory<see cref="string"/></param>
/// <returns>The <see cref="string"/></returns>
public static string GetDirectorySizeFormatted(string directory) => FormatString.FormatFileSize(GetDirectorySize(directory));
/// <summary>
/// Calculates the ETA (estimated time of accomplishment).
/// </summary>
/// <param name="speed">The speed as bytes. (Bytes per second?)</param>
/// <param name="totalBytes">The total amount of bytes.</param>
/// <param name="downloadedBytes">The amount of downloaded bytes.</param>
/// <returns>The <see cref="long"/></returns>
public static long GetETA(int speed, long totalBytes, long downloadedBytes)
{
if (speed == 0)
{
return 0;
}
var remainBytes = totalBytes - downloadedBytes;
return remainBytes / speed;
}
/// <summary>
/// Returns a long of the file size from given file in bytes.
/// </summary>
/// <param name="file">The file to get file size from.</param>
/// <returns>The <see cref="long"/></returns>
public static long GetFileSize(string file) => !File.Exists(file) ? 0 : new FileInfo(file).Length;
/// <summary>
/// Returns an formatted string of the given file's size.
/// </summary>
/// <param name="file">The file<see cref="string"/></param>
/// <returns>The <see cref="string"/></returns>
public static string GetFileSizeFormatted(string file) => FormatString.FormatFileSize(GetFileSize(file));
#endregion Methods
}
}

View File

@@ -0,0 +1,90 @@
namespace VideoBrowser.Helpers
{
using System;
using VideoBrowser.Common;
/// <summary>
/// Defines the <see cref="FormatString" />.
/// </summary>
public static class FormatString
{
#region Fields
private static readonly string[] TimeUnitsNames = { "Milli", "Sec", "Min", "Hour", "Day", "Month", "Year", "Decade", "Century" };
private static int[] TimeUnitsValue = { 1000, 60, 60, 24, 30, 12, 10, 10 };// Reference unit is milli
#endregion Fields
#region Methods
/// <summary>
/// Returns a formatted string of the given file size.
/// </summary>
/// <param name="size">The file size as long to format.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string FormatFileSize(this long size)
{
return string.Format(new ByteFormatProvider(), "{0:fs}", size);
}
/// <summary>
/// The FormatLeftTime.
/// </summary>
/// <param name="milliseconds">The milliseconds<see cref="long"/>.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string FormatLeftTime(this long milliseconds)
{
var format = "";
for (var i = 0; i < TimeUnitsValue.Length; i++)
{
var y = milliseconds % TimeUnitsValue[i];
milliseconds = milliseconds / TimeUnitsValue[i];
if (y == 0)
{
continue;
}
format = y + " " + TimeUnitsNames[i] + " , " + format;
}
format = format.Trim(',', ' ');
return format == "" ? "0 Sec" : format;
}
/// <summary>
/// Returns a formatted string of the video length.
/// </summary>
/// <param name="duration">The video duration as long.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string FormatVideoLength(this long duration)
{
return FormatVideoLength(TimeSpan.FromSeconds(duration));
}
/// <summary>
/// Returns a formatted string of the video length.
/// </summary>
/// <param name="duration">The video duration as TimeSpan.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string FormatVideoLength(this TimeSpan duration)
{
return duration.Hours > 0
? string.Format("{0}:{1:00}:{2:00}", duration.Hours, duration.Minutes, duration.Seconds)
: string.Format("{0}:{1:00}", duration.Minutes, duration.Seconds);
}
/// <summary>
/// The GetDirectorySizeFormatted.
/// </summary>
/// <param name="directory">The directory<see cref="string"/>.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string GetDirectorySizeFormatted(this string directory)
{
return FormatFileSize(FileHelper.GetDirectorySize(directory));
}
#endregion Methods
}
}

View File

@@ -0,0 +1,33 @@
namespace VideoBrowser.Helpers
{
using System.Drawing;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
/// <summary>
/// Defines the <see cref="ImageHelper" />.
/// </summary>
public static class ImageHelper
{
#region Methods
/// <summary>
/// The ToImageSource.
/// </summary>
/// <param name="icon">The icon<see cref="Icon"/>.</param>
/// <returns>The <see cref="ImageSource"/>.</returns>
public static ImageSource ToImageSource(this Icon icon)
{
var imageSource = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}
#endregion Methods
}
}

View File

@@ -0,0 +1,82 @@
namespace VideoBrowser.Helpers
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using VideoBrowser.Common;
/// <summary>
/// Defines the <see cref="ProcessHelper" />
/// </summary>
public static class ProcessHelper
{
#region Methods
/// <summary>
/// Creates a Process with the given arguments, then returns it.
/// </summary>
/// <param name="fileName">The fileName<see cref="string"/></param>
/// <param name="arguments">The arguments<see cref="string"/></param>
/// <param name="output">The output<see cref="Action{Process, string}"/></param>
/// <param name="error">The error<see cref="Action{Process, string}"/></param>
/// <param name="environmentVariables">The environmentVariables<see cref="Dictionary{string, string}"/></param>
/// <returns>The <see cref="Process"/></returns>
public static Process StartProcess(string fileName,
string arguments,
Action<Process, string> output,
Action<Process, string> error,
Dictionary<string, string> environmentVariables)
{
var psi = new ProcessStartInfo(fileName, arguments)
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = AppEnvironment.GetLogsDirectory()
};
if (environmentVariables != null)
{
foreach (KeyValuePair<string, string> pair in environmentVariables)
psi.EnvironmentVariables.Add(pair.Key, pair.Value);
}
var process = new Process()
{
EnableRaisingEvents = true,
StartInfo = psi
};
process.OutputDataReceived += delegate (object sender, DataReceivedEventArgs e)
{
if (string.IsNullOrEmpty(e.Data))
{
return;
}
Logger.Info(e.Data);
output?.Invoke(process, e.Data);
};
process.ErrorDataReceived += delegate (object sender, DataReceivedEventArgs e)
{
if (string.IsNullOrEmpty(e.Data))
{
return;
}
Logger.Info(e.Data);
error?.Invoke(process, e.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
return process;
}
#endregion Methods
}
}

View File

@@ -0,0 +1,112 @@
namespace VideoBrowser.Helpers
{
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
/// <summary>
/// Defines the <see cref="UIThreadHelper" />.
/// </summary>
public static class UIThreadHelper
{
#region Methods
/// <summary>
/// The DelayedInvokeAsync.
/// </summary>
/// <param name="action">The action<see cref="Action"/>.</param>
/// <param name="milliSecondsDelay">The milliSecondsDelay<see cref="int"/>.</param>
public static void DelayedInvokeAsync(Action action, int milliSecondsDelay)
{
Task.Run(async () =>
{
await Task.Delay(milliSecondsDelay);
InvokeAsync(action);
});
}
/// <summary>
/// The Invoke.
/// </summary>
/// <param name="action">The action<see cref="Action"/>.</param>
public static void Invoke(Action action)
{
if (Application.Current == null)
{
return;
}
var dispatcher = Application.Current.Dispatcher;
if (dispatcher.CheckAccess())
{
action?.Invoke();
}
else
{
dispatcher.Invoke(() => action?.Invoke());
}
}
/// <summary>
/// The Invoke.
/// </summary>
/// <param name="dispatcherObject">The dispatcherObject<see cref="DispatcherObject"/>.</param>
/// <param name="action">The action<see cref="Action"/>.</param>
public static void Invoke(this DispatcherObject dispatcherObject, Action action)
{
var dispatcher = dispatcherObject.Dispatcher;
if (dispatcher.CheckAccess())
{
action?.Invoke();
}
else
{
dispatcher.Invoke(() => action?.Invoke());
}
}
/// <summary>
/// The InvokeAsync.
/// </summary>
/// <param name="action">The action<see cref="Action"/>.</param>
public static void InvokeAsync(Action action)
{
if (Application.Current == null)
{
return;
}
Application.Current.Dispatcher.InvokeAsync(action);
}
/// <summary>
/// The InvokeAsync.
/// </summary>
/// <param name="dispatcher">The dispatcher<see cref="Dispatcher"/>.</param>
/// <param name="action">The action<see cref="Action"/>.</param>
public static void InvokeAsync(this Dispatcher dispatcher, Action action)
{
if (dispatcher.CheckAccess())
{
action?.Invoke();
}
else
{
dispatcher.InvokeAsync(() => action?.Invoke());
}
}
/// <summary>
/// The InvokeAsync.
/// </summary>
/// <param name="dispatcherObject">The dispatcherObject<see cref="DispatcherObject"/>.</param>
/// <param name="action">The action<see cref="Action"/>.</param>
public static void InvokeAsync(this DispatcherObject dispatcherObject, Action action)
{
dispatcherObject.Dispatcher.InvokeAsync(action);
}
#endregion Methods
}
}

View File

@@ -0,0 +1,53 @@
namespace VideoBrowser.Helpers
{
using System;
using System.Web;
/// <summary>
/// Defines the <see cref="UrlHelper" />.
/// </summary>
internal static class UrlHelper
{
#region Methods
/// <summary>
/// The GetValidUrl.
/// </summary>
/// <param name="url">The url<see cref="string"/>.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string GetValidUrl(string url)
{
if (!IsValidUrl(url))
{
var encodedUrl = HttpUtility.UrlEncode(url);
url = $"https://www.youtube.com/results?search_query={encodedUrl}";
}
return url;
}
/// <summary>
/// The IsValidUrl.
/// </summary>
/// <param name="url">The url<see cref="string"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool IsValidUrl(string url)
{
if (!url.Contains("."))
{
return false;
}
if (!url.Contains("http"))
{
url = $"http://{url}";
}
var result = Uri.TryCreate(url, UriKind.Absolute, out Uri uriResult)
&& (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
return result;
}
#endregion Methods
}
}

View File

@@ -0,0 +1,140 @@
namespace VideoBrowser.Helpers
{
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using VideoBrowser.Core;
/// <summary>
/// Defines the <see cref="YoutubeHelper" />.
/// </summary>
public static class YoutubeHelper
{
#region Methods
/// <summary>
/// Returns a fixed URL, stripped of unnecessary invalid information.
/// </summary>
/// <param name="url">The URL to fix.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string FixUrl(string url)
{
// Remove "Watch Later" information, causes error
url = url.Replace("&index=6&list=WL", "");
return url;
}
/// <summary>
/// Returns a formatted string of the given title, stripping illegal characters and replacing HTML entities with their actual character. (e.g. &quot; -> ').
/// </summary>
/// <param name="title">The title to format.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string FormatTitle(string title)
{
var illegalCharacters = new string[] { "/", @"\", "*", "?", "\"", "<", ">" };
var replace = new Dictionary<string, string>()
{
{"|", "-"},
{"&#39;", "'"},
{"&quot;", "'"},
{"&lt;", "("},
{"&gt;", ")"},
{"+", " "},
{":", "-"},
{"amp;", "&"}
};
var sb = new System.Text.StringBuilder(title);
foreach (string s in illegalCharacters)
{
sb.Replace(s, string.Empty);
}
foreach (KeyValuePair<string, string> s in replace)
{
sb.Replace(s.Key, s.Value);
}
return sb.ToString().Trim();
}
/// <summary>
/// Returns the highest quality audio format from the given VideoFormat.
/// </summary>
/// <param name="format">The format to get audio format from.</param>
/// <returns>The <see cref="VideoFormat"/>.</returns>
public static VideoFormat GetAudioFormat(VideoFormat format)
{
var audio = new List<VideoFormat>();
// Add all audio only formats
audio.AddRange(format.VideoInfo.Formats.FindAll(f => f.AudioOnly == true && f.Extension != "webm"));
// Return null if no audio is found
if (audio.Count == 0)
{
return null;
}
// Return either the one with the highest audio bit rate, or the last found one
return audio.OrderBy(a => a.AudioBitRate).Last();
}
/// <summary>
/// Returns the playlist id from given url.
/// </summary>
/// <param name="url">The url to get playlist id from.</param>
/// <returns>The <see cref="string"/>.</returns>
public static string GetPlaylistId(string url)
{
var regex = new Regex(@"^(?:https?://)?(?:www.)?youtube.com/.*list=([0-9a-zA-Z\-_]*).*$");
return regex.Match(url).Groups[1].Value;
}
/// <summary>
/// Returns true if the given url is a playlist YouTube url.
/// </summary>
/// <param name="url">The url to check.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool IsPlaylist(string url)
{
var regex = new Regex(@"^(?:https?://)?(?:www.)?youtube.com/.*list=([0-9a-zA-Z\-_]*).*$");
return regex.IsMatch(url);
}
/// <summary>
/// Returns true if the given url is a valid YouTube url.
/// </summary>
/// <param name="url">The url to check.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool IsValidYouTubeUrl(string url)
{
if (!url.ToLower().Contains("www.youtube.com/watch?"))
{
return false;
}
var pattern = @"^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?$";
var regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
return regex.IsMatch(url);
}
/// <summary>
/// The CheckFormats.
/// </summary>
/// <param name="list">The list<see cref="IList{VideoFormat}"/>.</param>
/// <returns>The <see cref="VideoFormat[]"/>.</returns>
internal static VideoFormat[] CheckFormats(IList<VideoFormat> list)
{
var formats = new List<VideoFormat>(list.Distinct());
formats.RemoveAll(f => f.Extension.Contains("webm") ||
f.HasAudioAndVideo ||
f.FormatID == "meta");
return formats.ToArray();
}
#endregion Methods
}
}