commit
9728aa8b0a
@ -1,152 +0,0 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Diagnostics;
|
||||
|
||||
namespace Emby.Server.Implementations.Diagnostics
|
||||
{
|
||||
public class CommonProcess : IProcess
|
||||
{
|
||||
private readonly Process _process;
|
||||
|
||||
private bool _disposed = false;
|
||||
private bool _hasExited;
|
||||
|
||||
public CommonProcess(ProcessOptions options)
|
||||
{
|
||||
StartInfo = options;
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
Arguments = options.Arguments,
|
||||
FileName = options.FileName,
|
||||
WorkingDirectory = options.WorkingDirectory,
|
||||
UseShellExecute = options.UseShellExecute,
|
||||
CreateNoWindow = options.CreateNoWindow,
|
||||
RedirectStandardError = options.RedirectStandardError,
|
||||
RedirectStandardInput = options.RedirectStandardInput,
|
||||
RedirectStandardOutput = options.RedirectStandardOutput,
|
||||
ErrorDialog = options.ErrorDialog
|
||||
};
|
||||
|
||||
|
||||
if (options.IsHidden)
|
||||
{
|
||||
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
}
|
||||
|
||||
_process = new Process
|
||||
{
|
||||
StartInfo = startInfo
|
||||
};
|
||||
|
||||
if (options.EnableRaisingEvents)
|
||||
{
|
||||
_process.EnableRaisingEvents = true;
|
||||
_process.Exited += OnProcessExited;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler Exited;
|
||||
|
||||
public ProcessOptions StartInfo { get; }
|
||||
|
||||
public StreamWriter StandardInput => _process.StandardInput;
|
||||
|
||||
public StreamReader StandardError => _process.StandardError;
|
||||
|
||||
public StreamReader StandardOutput => _process.StandardOutput;
|
||||
|
||||
public int ExitCode => _process.ExitCode;
|
||||
|
||||
private bool HasExited
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_hasExited)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_hasExited = _process.HasExited;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
_hasExited = true;
|
||||
}
|
||||
|
||||
return _hasExited;
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_process.Start();
|
||||
}
|
||||
|
||||
public void Kill()
|
||||
{
|
||||
_process.Kill();
|
||||
}
|
||||
|
||||
public bool WaitForExit(int timeMs)
|
||||
{
|
||||
return _process.WaitForExit(timeMs);
|
||||
}
|
||||
|
||||
public Task<bool> WaitForExitAsync(int timeMs)
|
||||
{
|
||||
// Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true.
|
||||
|
||||
if (HasExited)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
timeMs = Math.Max(0, timeMs);
|
||||
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
|
||||
var cancellationToken = new CancellationTokenSource(timeMs).Token;
|
||||
|
||||
_process.Exited += (sender, args) => tcs.TrySetResult(true);
|
||||
|
||||
cancellationToken.Register(() => tcs.TrySetResult(HasExited));
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_process?.Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private void OnProcessExited(object sender, EventArgs e)
|
||||
{
|
||||
_hasExited = true;
|
||||
Exited?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using MediaBrowser.Model.Diagnostics;
|
||||
|
||||
namespace Emby.Server.Implementations.Diagnostics
|
||||
{
|
||||
public class ProcessFactory : IProcessFactory
|
||||
{
|
||||
public IProcess Create(ProcessOptions options)
|
||||
{
|
||||
return new CommonProcess(options);
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1,117 @@
|
||||
{}
|
||||
{
|
||||
"HeaderFavoriteAlbums": "پسندیدہ البمز",
|
||||
"HeaderNextUp": "اگلا",
|
||||
"HeaderFavoriteArtists": "پسندیدہ فنکار",
|
||||
"HeaderAlbumArtists": "البم کے فنکار",
|
||||
"Movies": "فلمیں",
|
||||
"HeaderFavoriteEpisodes": "پسندیدہ اقساط",
|
||||
"Collections": "مجموعہ",
|
||||
"Folders": "فولڈرز",
|
||||
"HeaderLiveTV": "براہ راست ٹی وی",
|
||||
"Channels": "چینل",
|
||||
"HeaderContinueWatching": "دیکھنا جاری رکھیں",
|
||||
"Playlists": "پلے لسٹس",
|
||||
"ValueSpecialEpisodeName": "خاص - {0}",
|
||||
"Shows": "شوز",
|
||||
"Genres": "انواع",
|
||||
"Artists": "فنکار",
|
||||
"Sync": "مطابقت",
|
||||
"Photos": "تصوریں",
|
||||
"Albums": "البم",
|
||||
"Favorites": "پسندیدہ",
|
||||
"Songs": "گانے",
|
||||
"Books": "کتابیں",
|
||||
"HeaderFavoriteSongs": "پسندیدہ گانے",
|
||||
"HeaderFavoriteShows": "پسندیدہ شوز",
|
||||
"TaskDownloadMissingSubtitlesDescription": "میٹا ڈیٹا کی تشکیل پر مبنی ذیلی عنوانات کے غائب عنوانات انٹرنیٹ پے تلاش کرتا ہے۔",
|
||||
"TaskDownloadMissingSubtitles": "غائب سب ٹائٹلز ڈاؤن لوڈ کریں",
|
||||
"TaskRefreshChannelsDescription": "انٹرنیٹ چینل کی معلومات کو تازہ دم کرتا ہے۔",
|
||||
"TaskRefreshChannels": "چینلز ریفریش کریں",
|
||||
"TaskCleanTranscodeDescription": "ایک دن سے زیادہ پرانی ٹرانسکوڈ فائلوں کو حذف کرتا ہے۔",
|
||||
"TaskCleanTranscode": "ٹرانس کوڈ ڈائرکٹری صاف کریں",
|
||||
"TaskUpdatePluginsDescription": "پلگ انز کے لئے اپ ڈیٹس ڈاؤن لوڈ اور انسٹال کرتے ہیں جو خود بخود اپ ڈیٹ کرنے کیلئے تشکیل شدہ ہیں۔",
|
||||
"TaskUpdatePlugins": "پلگ انز کو اپ ڈیٹ کریں",
|
||||
"TaskRefreshPeopleDescription": "آپ کی میڈیا لائبریری میں اداکاروں اور ہدایت کاروں کے لئے میٹا ڈیٹا کی تازہ کاری۔",
|
||||
"TaskRefreshPeople": "لوگوں کو تروتازہ کریں",
|
||||
"TaskCleanLogsDescription": "لاگ فائلوں کو حذف کریں جو {0} دن سے زیادہ پرانی ہیں۔",
|
||||
"TaskCleanLogs": "لاگ ڈائرکٹری کو صاف کریں",
|
||||
"TaskRefreshLibraryDescription": "میڈیا لائبریری کو اسکین کرتا ھے ہر میٹا دیٹا کہ تازہ دم کرتا ھے.",
|
||||
"TaskRefreshLibrary": "اسکین میڈیا لائبریری",
|
||||
"TaskRefreshChapterImagesDescription": "بابوں والی ویڈیوز کے لئے تمبنیل بنایں۔",
|
||||
"TaskRefreshChapterImages": "باب کی تصاویر نکالیں",
|
||||
"TaskCleanCacheDescription": "فائلوں کو حذف کریں جنکی ضرورت نھیں ھے۔",
|
||||
"TaskCleanCache": "کیش ڈائرکٹری کلیر کریں",
|
||||
"TasksChannelsCategory": "انٹرنیٹ چینلز",
|
||||
"TasksApplicationCategory": "پروگرام",
|
||||
"TasksLibraryCategory": "لآیبریری",
|
||||
"TasksMaintenanceCategory": "مرمت",
|
||||
"VersionNumber": "ورژن {0}",
|
||||
"ValueHasBeenAddedToLibrary": "{0} آپ کی میڈیا لائبریری میں شامل کر دیا گیا ہے",
|
||||
"UserStoppedPlayingItemWithValues": "{0} نے {1} چلانا ختم کر دیا ھے {2} پے",
|
||||
"UserStartedPlayingItemWithValues": "{0} چلا رہا ہے {1} {2} پے",
|
||||
"UserPolicyUpdatedWithName": "صارف {0} کی پالیسی کیلئے تازہ کاری کی گئی ہے",
|
||||
"UserPasswordChangedWithName": "صارف {0} کے لئے پاس ورڈ تبدیل کر دیا گیا ہے",
|
||||
"UserOnlineFromDevice": "{0} آن لائن ہے {1} سے",
|
||||
"UserOfflineFromDevice": "{0} سے منقطع ہوگیا ہے {1}",
|
||||
"UserLockedOutWithName": "صارف {0} کو لاک آؤٹ کردیا گیا ہے",
|
||||
"UserDownloadingItemWithValues": "{0} ڈاؤن لوڈ کر رھا ھے {1}",
|
||||
"UserDeletedWithName": "صارف {0} کو ہٹا دیا گیا ہے",
|
||||
"UserCreatedWithName": "صارف {0} تشکیل دیا گیا ہے",
|
||||
"User": "صارف",
|
||||
"TvShows": "ٹی وی کے پروگرام",
|
||||
"System": "نظام",
|
||||
"SubtitleDownloadFailureFromForItem": "ذیلی عنوانات {0} سے ڈاؤن لوڈ کرنے میں ناکام {1} کے لیے",
|
||||
"StartupEmbyServerIsLoading": "جیلیفن سرور لوڈ ہورہا ہے۔ براہ کرم جلد ہی دوبارہ کوشش کریں۔",
|
||||
"ServerNameNeedsToBeRestarted": "{0} دوبارہ چلانے کرنے کی ضرورت ہے",
|
||||
"ScheduledTaskStartedWithName": "{0} شروع",
|
||||
"ScheduledTaskFailedWithName": "{0} ناکام",
|
||||
"ProviderValue": "فراہم کرنے والا: {0}",
|
||||
"PluginUpdatedWithName": "{0} تازہ کاری کی گئی تھی",
|
||||
"PluginUninstalledWithName": "[0} ہٹا دیا گیا تھا",
|
||||
"PluginInstalledWithName": "{0} انسٹال کیا گیا تھا",
|
||||
"Plugin": "پلگن",
|
||||
"NotificationOptionVideoPlaybackStopped": "ویڈیو پلے بیک رک گیا",
|
||||
"NotificationOptionVideoPlayback": "ویڈیو پلے بیک شروع ہوا",
|
||||
"NotificationOptionUserLockedOut": "صارف کو لاک آؤٹ کیا گیا",
|
||||
"NotificationOptionTaskFailed": "طے شدہ کام کی ناکامی",
|
||||
"NotificationOptionServerRestartRequired": "سرور دوبارہ چلانے کرنے کی ضرورت ہے",
|
||||
"NotificationOptionPluginUpdateInstalled": "پلگ ان اپ ڈیٹ انسٹال",
|
||||
"NotificationOptionPluginUninstalled": "پلگ ان ہٹا دیا گیا",
|
||||
"NotificationOptionPluginInstalled": "پلگ ان انسٹال ہوا",
|
||||
"NotificationOptionPluginError": "پلگ ان کی ناکامی",
|
||||
"NotificationOptionNewLibraryContent": "نیا مواد شامل کیا گیا",
|
||||
"NotificationOptionInstallationFailed": "تنصیب کی ناکامی",
|
||||
"NotificationOptionCameraImageUploaded": "کیمرے کی تصویر اپ لوڈ ہوگئی",
|
||||
"NotificationOptionAudioPlaybackStopped": "آڈیو پلے بیک رک گیا",
|
||||
"NotificationOptionAudioPlayback": "آڈیو پلے بیک شروع ہوا",
|
||||
"NotificationOptionApplicationUpdateInstalled": "پروگرام اپ ڈیٹ انسٹال ہوچکا ھے",
|
||||
"NotificationOptionApplicationUpdateAvailable": "پروگرام کی تازہ کاری دستیاب ہے",
|
||||
"NewVersionIsAvailable": "جیلیفن سرور کا ایک نیا ورژن ڈاؤن لوڈ کے لئے دستیاب ہے۔",
|
||||
"NameSeasonUnknown": "نامعلوم باب",
|
||||
"NameSeasonNumber": "باب {0}",
|
||||
"NameInstallFailed": "{0} تنصیب ناکام ہوگئی",
|
||||
"MusicVideos": "موسیقی ویڈیو",
|
||||
"Music": "موسیقی",
|
||||
"MixedContent": "مخلوط مواد",
|
||||
"MessageServerConfigurationUpdated": "سرور کو اپ ڈیٹ کر دیا گیا ہے",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "سرور ضمن {0} کو ترتیب دے دیا گیا ھے",
|
||||
"MessageApplicationUpdatedTo": "جیلیفن سرور کو اپ ڈیٹ کیا ہے {0}",
|
||||
"MessageApplicationUpdated": "جیلیفن سرور کو اپ ڈیٹ کر دیا گیا ہے",
|
||||
"Latest": "تازہ ترین",
|
||||
"LabelRunningTimeValue": "چلانے کی مدت",
|
||||
"LabelIpAddressValue": "ای پی پتے {0}",
|
||||
"ItemRemovedWithName": "لائبریری سے ہٹا دیا گیا ھے",
|
||||
"ItemAddedWithName": "[0} لائبریری میں شامل کیا گیا ھے",
|
||||
"Inherit": "وراثت میں",
|
||||
"HomeVideos": "ہوم ویڈیو",
|
||||
"HeaderRecordingGroups": "ریکارڈنگ گروپس",
|
||||
"HeaderCameraUploads": "کیمرہ اپلوڈز",
|
||||
"FailedLoginAttemptWithUserName": "لاگن کئ کوشش ناکام {0}",
|
||||
"DeviceOnlineWithName": "{0} متصل ھو چکا ھے",
|
||||
"DeviceOfflineWithName": "{0} منقطع ھو چکا ھے",
|
||||
"ChapterNameValue": "باب",
|
||||
"AuthenticationSucceededWithUserName": "{0} کامیابی کے ساتھ تصدیق ھوچکی ھے",
|
||||
"CameraImageUploadedFrom": "ایک نئی کیمرہ تصویر اپ لوڈ کی گئی ہے {0}",
|
||||
"Application": "پروگرام",
|
||||
"AppDeviceValues": "پروگرام:{0}, آلہ:{1}"
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="Process"/>.
|
||||
/// </summary>
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously wait for the process to exit.
|
||||
/// </summary>
|
||||
/// <param name="process">The process to wait for.</param>
|
||||
/// <param name="timeout">The duration to wait before cancelling waiting for the task.</param>
|
||||
/// <returns>True if the task exited normally, false if the timeout elapsed before the process exited.</returns>
|
||||
/// <exception cref="InvalidOperationException">If <see cref="Process.EnableRaisingEvents"/> is not set to true for the process.</exception>
|
||||
public static async Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
|
||||
{
|
||||
using (var cancelTokenSource = new CancellationTokenSource(timeout))
|
||||
{
|
||||
return await WaitForExitAsync(process, cancelTokenSource.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously wait for the process to exit.
|
||||
/// </summary>
|
||||
/// <param name="process">The process to wait for.</param>
|
||||
/// <param name="cancelToken">A <see cref="CancellationToken"/> to observe while waiting for the process to exit.</param>
|
||||
/// <returns>True if the task exited normally, false if cancelled before the process exited.</returns>
|
||||
public static async Task<bool> WaitForExitAsync(this Process process, CancellationToken cancelToken)
|
||||
{
|
||||
if (!process.EnableRaisingEvents)
|
||||
{
|
||||
throw new InvalidOperationException("EnableRisingEvents must be enabled to async wait for a task to exit.");
|
||||
}
|
||||
|
||||
// Add an event handler for the process exit event
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
process.Exited += (sender, args) => tcs.TrySetResult(true);
|
||||
|
||||
// Return immediately if the process has already exited
|
||||
if (process.HasExitedSafe())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Register with the cancellation token then await
|
||||
using (var cancelRegistration = cancelToken.Register(() => tcs.TrySetResult(process.HasExitedSafe())))
|
||||
{
|
||||
return await tcs.Task.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the associated process has been terminated using
|
||||
/// <see cref="Process.HasExited"/>. This is safe to call even if there is no operating system process
|
||||
/// associated with the <see cref="Process"/>.
|
||||
/// </summary>
|
||||
/// <param name="process">The process to check the exit status for.</param>
|
||||
/// <returns>
|
||||
/// True if the operating system process referenced by the <see cref="Process"/> component has
|
||||
/// terminated, or if there is no associated operating system process; otherwise, false.
|
||||
/// </returns>
|
||||
private static bool HasExitedSafe(this Process process)
|
||||
{
|
||||
try
|
||||
{
|
||||
return process.HasExited;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Model.Diagnostics
|
||||
{
|
||||
public interface IProcess : IDisposable
|
||||
{
|
||||
event EventHandler Exited;
|
||||
|
||||
void Kill();
|
||||
bool WaitForExit(int timeMs);
|
||||
Task<bool> WaitForExitAsync(int timeMs);
|
||||
int ExitCode { get; }
|
||||
void Start();
|
||||
StreamWriter StandardInput { get; }
|
||||
StreamReader StandardError { get; }
|
||||
StreamReader StandardOutput { get; }
|
||||
ProcessOptions StartInfo { get; }
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Model.Diagnostics
|
||||
{
|
||||
public interface IProcessFactory
|
||||
{
|
||||
IProcess Create(ProcessOptions options);
|
||||
}
|
||||
|
||||
public class ProcessOptions
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public string Arguments { get; set; }
|
||||
public string WorkingDirectory { get; set; }
|
||||
public bool CreateNoWindow { get; set; }
|
||||
public bool UseShellExecute { get; set; }
|
||||
public bool EnableRaisingEvents { get; set; }
|
||||
public bool ErrorDialog { get; set; }
|
||||
public bool RedirectStandardError { get; set; }
|
||||
public bool RedirectStandardInput { get; set; }
|
||||
public bool RedirectStandardOutput { get; set; }
|
||||
public bool IsHidden { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
Loading…
Reference in new issue