mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-25 12:44:46 +01:00
Minor cross-platform improvements
git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@407 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
parent
b3a52e9dba
commit
ceb00b5960
@ -539,7 +539,9 @@ namespace Nikse.SubtitleEdit.Controls
|
||||
_pictureBoxPlay.BringToFront();
|
||||
|
||||
_panelcontrols.BackColor = _backgroundColor;
|
||||
|
||||
_pictureBoxPlay.BringToFront();
|
||||
_pictureBoxPlayDown.BringToFront();
|
||||
_pictureBoxPlayOver.BringToFront();
|
||||
_labelTimeCode.BringToFront();
|
||||
return _panelcontrols;
|
||||
}
|
||||
|
@ -36,10 +36,15 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
buttonRipWave.Enabled = false;
|
||||
_cancel = false;
|
||||
|
||||
SourceVideoFileName = labelVideoFileName.Text;
|
||||
string targetFile = Path.GetTempFileName() + ".wav";
|
||||
string parameters = "-I dummy -vvv \"" + SourceVideoFileName + "\" --sout=#transcode{vcodec=none,acodec=s16l}:file{dst=\"" + targetFile + "\"} vlc://quit";
|
||||
|
||||
string vlcPath;
|
||||
if (Utilities.IsRunningOnLinux() || Utilities.IsRunningOnMac())
|
||||
{
|
||||
vlcPath = "vlc";
|
||||
vlcPath = "cvlc";
|
||||
parameters = "-vvv --no-sout-video --sout '#transcode{acodec=s16l}:std{mux=wav,access=file,dst=" + targetFile +"}' \"" + SourceVideoFileName + "\" vlc://quit";
|
||||
}
|
||||
else // windows
|
||||
{
|
||||
@ -59,11 +64,6 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
}
|
||||
|
||||
labelPleaseWait.Visible = true;
|
||||
SourceVideoFileName = labelVideoFileName.Text;
|
||||
string targetFile = Path.GetTempFileName() + ".wav";
|
||||
string parameters = "-I dummy -vvv \"" + SourceVideoFileName + "\" --sout=#transcode{vcodec=none,acodec=s16l}:file{dst=\"" + targetFile + "\"} vlc://quit";
|
||||
//string parameters = "-I dummy -vvv \"" + _wavFileName + "\" --sout=#transcode{vcodec=none,acodec=s24l}:file{dst=\"" + _targetFile + "\"} vlc://quit";
|
||||
//string parameters = "-I dummy -vvv \"" + _wavFileName + "\" --sout=#transcode{vcodec=none,acodec=s32l}:file{dst=\"" + _targetFile + "\"} vlc://quit";
|
||||
|
||||
Process process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo(vlcPath, parameters);
|
||||
|
@ -4617,6 +4617,11 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
Configuration.Settings.RecentFiles.Add(_fileName, FirstVisibleIndex, FirstSelectedIndex, _videoFileName, _subtitleAlternateFileName);
|
||||
Configuration.Settings.Save();
|
||||
|
||||
if (mediaPlayer.VideoPlayer != null)
|
||||
{
|
||||
mediaPlayer.VideoPlayer.DisposeVideoPlayer();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1251,7 +1251,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
process.StartInfo.Arguments = "\"" + tempTiffFileName + "\" \"" + tempTextFileName + "\" -l " + language;
|
||||
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
|
||||
if (Utilities.IsRunningOnLinux())
|
||||
if (Utilities.IsRunningOnLinux() || Utilities.IsRunningOnMac())
|
||||
{
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
|
@ -38,7 +38,7 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Utilities.IsRunningOnLinux())
|
||||
if (Utilities.IsRunningOnLinux() || Utilities.IsRunningOnMac())
|
||||
return "/usr/share/tesseract-ocr/tessdata";
|
||||
else
|
||||
return TesseractFolder + "tessdata";
|
||||
|
@ -1150,7 +1150,10 @@ namespace Nikse.SubtitleEdit.Logic
|
||||
{
|
||||
GeneralSettings gs = Configuration.Settings.General;
|
||||
|
||||
return new MPlayer();
|
||||
if (Utilities.IsRunningOnLinux())
|
||||
return new MPlayer();
|
||||
if (Utilities.IsRunningOnMac())
|
||||
return new LibVlcMono();
|
||||
|
||||
if (gs.VideoPlayer == "VLC" && LibVlc11xDynamic.IsInstalled)
|
||||
return new LibVlc11xDynamic();
|
||||
|
@ -401,7 +401,7 @@ namespace Nikse.SubtitleEdit.Logic.VideoPlayers
|
||||
|
||||
public static string GetVlcPath(string fileName)
|
||||
{
|
||||
if (Utilities.IsRunningOnLinux())
|
||||
if (Utilities.IsRunningOnLinux() || Utilities.IsRunningOnMac())
|
||||
return null;
|
||||
|
||||
string path;
|
||||
|
354
src/Logic/VideoPlayers/LibVlcMono.cs
Normal file
354
src/Logic/VideoPlayers/LibVlcMono.cs
Normal file
@ -0,0 +1,354 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Logic.VideoPlayers
|
||||
{
|
||||
class LibVlcMono : VideoPlayer
|
||||
{
|
||||
private System.Windows.Forms.Timer _videoLoadedTimer;
|
||||
private System.Windows.Forms.Timer _videoEndTimer;
|
||||
|
||||
private IntPtr _libVlcDLL;
|
||||
private IntPtr _libVlc;
|
||||
private IntPtr _mediaPlayer;
|
||||
private System.Windows.Forms.Control _ownerControl;
|
||||
private System.Windows.Forms.Form _parentForm;
|
||||
|
||||
// LibVLC Core - http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__core.html
|
||||
[DllImport("libvlc")]
|
||||
private static extern IntPtr libvlc_new(int argc, [MarshalAs(UnmanagedType.LPArray)] string[] argv);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern IntPtr libvlc_get_version();
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_release(IntPtr libVlc);
|
||||
|
||||
// LibVLC Media - http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__media.html
|
||||
[DllImport("libvlc")]
|
||||
private static extern IntPtr libvlc_media_new_path(IntPtr instance, byte[] input);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern IntPtr libvlc_media_player_new_from_media(IntPtr media);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_media_release(IntPtr media);
|
||||
|
||||
|
||||
// LibVLC Video Controls - http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__video.html#g8f55326b8b51aecb59d8b8a446c3f118
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_video_get_size(IntPtr mediaPlayer, UInt32 number, out UInt32 x, out UInt32 y);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern int libvlc_audio_get_track_count(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern int libvlc_audio_get_track(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern int libvlc_audio_set_track(IntPtr mediaPlayer, int trackNumber);
|
||||
|
||||
// LibVLC Audio Controls - http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__audio.html
|
||||
[DllImport("libvlc")]
|
||||
private static extern int libvlc_audio_get_volume(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_audio_set_volume(IntPtr mediaPlayer, int volume);
|
||||
|
||||
|
||||
// LibVLC Media Player - http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__media__player.html
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_media_player_play(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_media_player_stop(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_media_player_pause(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_media_player_set_hwnd(IntPtr mediaPlayer, IntPtr windowsHandle);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern int libvlc_media_player_is_playing(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern Int64 libvlc_media_player_get_time(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_media_player_set_time(IntPtr mediaPlayer, Int64 position);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern float libvlc_media_player_get_fps(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern byte libvlc_media_player_get_state(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern Int64 libvlc_media_player_get_length(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern void libvlc_media_list_player_release(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern float libvlc_media_player_get_rate(IntPtr mediaPlayer);
|
||||
|
||||
[DllImport("libvlc")]
|
||||
private static extern int libvlc_media_player_set_rate(IntPtr mediaPlayer, float rate);
|
||||
|
||||
private static byte[] StringToCharPointer(string s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(s + "\0");
|
||||
}
|
||||
|
||||
public override string PlayerName
|
||||
{
|
||||
get { return "VLC Lib Mono"; }
|
||||
}
|
||||
|
||||
public override int Volume
|
||||
{
|
||||
get
|
||||
{
|
||||
return libvlc_audio_get_volume(_mediaPlayer);
|
||||
}
|
||||
set
|
||||
{
|
||||
libvlc_audio_set_volume(_mediaPlayer, value);
|
||||
}
|
||||
}
|
||||
|
||||
public override double Duration
|
||||
{
|
||||
get
|
||||
{
|
||||
return libvlc_media_player_get_length(_mediaPlayer) / 1000.0;
|
||||
}
|
||||
}
|
||||
|
||||
public override double CurrentPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return libvlc_media_player_get_time(_mediaPlayer) / 1000.0;
|
||||
}
|
||||
set
|
||||
{
|
||||
libvlc_media_player_set_time(_mediaPlayer, (long)(value * 1000.0));
|
||||
}
|
||||
}
|
||||
|
||||
public override double PlayRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return libvlc_media_player_get_rate(_mediaPlayer);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value >= 0 && value <= 2.0)
|
||||
libvlc_media_player_set_rate(_mediaPlayer, (float)value);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Play()
|
||||
{
|
||||
libvlc_media_player_play(_mediaPlayer);
|
||||
}
|
||||
|
||||
public override void Pause()
|
||||
{
|
||||
if (!IsPaused)
|
||||
libvlc_media_player_pause(_mediaPlayer);
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
libvlc_media_player_stop(_mediaPlayer);
|
||||
}
|
||||
|
||||
public override bool IsPaused
|
||||
{
|
||||
get
|
||||
{
|
||||
const int Paused = 4;
|
||||
int state = libvlc_media_player_get_state(_mediaPlayer);
|
||||
return state == Paused;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsPlaying
|
||||
{
|
||||
get
|
||||
{
|
||||
const int Playing = 3;
|
||||
int state = libvlc_media_player_get_state(_mediaPlayer);
|
||||
return state == Playing;
|
||||
}
|
||||
}
|
||||
|
||||
public int AudioTrackCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return libvlc_audio_get_track_count(_mediaPlayer) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int AudioTrackNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return libvlc_audio_get_track(_mediaPlayer) - 1;
|
||||
}
|
||||
set
|
||||
{
|
||||
libvlc_audio_set_track(_mediaPlayer, value + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public LibVlcMono MakeSecondMediaPlayer(System.Windows.Forms.Control ownerControl, string videoFileName, EventHandler onVideoLoaded, EventHandler onVideoEnded)
|
||||
{
|
||||
LibVlcMono newVlc = new LibVlcMono();
|
||||
newVlc._libVlc = this._libVlc;
|
||||
newVlc._libVlcDLL = this._libVlcDLL;
|
||||
newVlc._ownerControl = ownerControl;
|
||||
if (ownerControl != null)
|
||||
newVlc._parentForm = ownerControl.FindForm();
|
||||
|
||||
newVlc.OnVideoLoaded = onVideoLoaded;
|
||||
newVlc.OnVideoEnded = onVideoEnded;
|
||||
|
||||
if (!string.IsNullOrEmpty(videoFileName))
|
||||
{
|
||||
IntPtr media = libvlc_media_new_path(_libVlc, Encoding.UTF8.GetBytes(videoFileName + "\0"));
|
||||
newVlc._mediaPlayer = libvlc_media_player_new_from_media(media);
|
||||
libvlc_media_release(media);
|
||||
|
||||
// Linux: libvlc_media_player_set_xdrawable (_mediaPlayer, xdrawable);
|
||||
// Mac: libvlc_media_player_set_nsobject (_mediaPlayer, view);
|
||||
libvlc_media_player_set_hwnd(newVlc._mediaPlayer, ownerControl.Handle); // windows
|
||||
|
||||
if (onVideoEnded != null)
|
||||
{
|
||||
newVlc._videoEndTimer = new System.Windows.Forms.Timer { Interval = 500 };
|
||||
newVlc._videoEndTimer.Tick += VideoEndTimerTick;
|
||||
newVlc._videoEndTimer.Start();
|
||||
}
|
||||
|
||||
libvlc_media_player_play(newVlc._mediaPlayer);
|
||||
newVlc._videoLoadedTimer = new System.Windows.Forms.Timer { Interval = 500 };
|
||||
newVlc._videoLoadedTimer.Tick += new EventHandler(newVlc.VideoLoadedTimer_Tick);
|
||||
newVlc._videoLoadedTimer.Start();
|
||||
}
|
||||
return newVlc;
|
||||
}
|
||||
|
||||
void VideoLoadedTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
int i = 0;
|
||||
while (!IsPlaying && i < 50)
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
i++;
|
||||
}
|
||||
libvlc_media_player_pause(_mediaPlayer);
|
||||
_videoLoadedTimer.Stop();
|
||||
|
||||
if (OnVideoLoaded != null)
|
||||
OnVideoLoaded.Invoke(_mediaPlayer, new EventArgs());
|
||||
}
|
||||
|
||||
|
||||
public override void Initialize(System.Windows.Forms.Control ownerControl, string videoFileName, EventHandler onVideoLoaded, EventHandler onVideoEnded)
|
||||
{
|
||||
_ownerControl = ownerControl;
|
||||
if (ownerControl != null)
|
||||
_parentForm = ownerControl.FindForm();
|
||||
|
||||
OnVideoLoaded = onVideoLoaded;
|
||||
OnVideoEnded = onVideoEnded;
|
||||
|
||||
if (!string.IsNullOrEmpty(videoFileName))
|
||||
{
|
||||
string[] initParameters = new string[] { "--no-sub-autodetect-file" }; //, "--no-video-title-show" }; //TODO: Put in options/config file
|
||||
_libVlc = libvlc_new(initParameters.Length, initParameters);
|
||||
IntPtr media = libvlc_media_new_path(_libVlc, Encoding.UTF8.GetBytes(videoFileName + "\0"));
|
||||
_mediaPlayer = libvlc_media_player_new_from_media(media);
|
||||
libvlc_media_release(media);
|
||||
|
||||
// Linux: libvlc_media_player_set_xdrawable (_mediaPlayer, xdrawable);
|
||||
// Mac: libvlc_media_player_set_nsobject (_mediaPlayer, view);
|
||||
libvlc_media_player_set_hwnd(_mediaPlayer, ownerControl.Handle); // windows
|
||||
|
||||
if (onVideoEnded != null)
|
||||
{
|
||||
_videoEndTimer = new System.Windows.Forms.Timer { Interval = 500 };
|
||||
_videoEndTimer.Tick += VideoEndTimerTick;
|
||||
_videoEndTimer.Start();
|
||||
}
|
||||
|
||||
libvlc_media_player_play(_mediaPlayer);
|
||||
_videoLoadedTimer = new System.Windows.Forms.Timer { Interval = 500 };
|
||||
_videoLoadedTimer.Tick += new EventHandler(VideoLoadedTimer_Tick);
|
||||
_videoLoadedTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VideoEndTimerTick(object sender, EventArgs e)
|
||||
{
|
||||
const int Ended = 6;
|
||||
int state = libvlc_media_player_get_state(_mediaPlayer);
|
||||
if (state == Ended)
|
||||
{
|
||||
// hack to make sure VLC is in ready state
|
||||
Stop();
|
||||
Play();
|
||||
Pause();
|
||||
OnVideoEnded.Invoke(_mediaPlayer, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisposeVideoPlayer()
|
||||
{
|
||||
if (_videoLoadedTimer != null)
|
||||
_videoLoadedTimer.Stop();
|
||||
|
||||
if (_videoEndTimer != null)
|
||||
_videoEndTimer.Stop();
|
||||
|
||||
ThreadPool.QueueUserWorkItem(DisposeVLC, this);
|
||||
}
|
||||
|
||||
private void DisposeVLC(object player)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_mediaPlayer != IntPtr.Zero)
|
||||
{
|
||||
libvlc_media_player_stop(_mediaPlayer);
|
||||
libvlc_media_list_player_release(_mediaPlayer);
|
||||
}
|
||||
|
||||
if (_libVlc != IntPtr.Zero)
|
||||
libvlc_release(_libVlc);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public override event EventHandler OnVideoLoaded;
|
||||
|
||||
public override event EventHandler OnVideoEnded;
|
||||
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ namespace Nikse.SubtitleEdit.Logic.VideoPlayers
|
||||
private Process _mplayer;
|
||||
private System.Windows.Forms.Timer timer;
|
||||
private TimeSpan _lengthInSeconds;
|
||||
private TimeSpan _lastLengthInSeconds = TimeSpan.FromDays(0);
|
||||
private bool _paused;
|
||||
private bool _loaded = false;
|
||||
private bool _ended = false;
|
||||
@ -64,22 +65,26 @@ namespace Nikse.SubtitleEdit.Logic.VideoPlayers
|
||||
|
||||
public override void Play()
|
||||
{
|
||||
SetProperty("pause", "1", false);
|
||||
// SetProperty("pause", "1", false);
|
||||
_mplayer.StandardInput.WriteLine("pause");
|
||||
_mplayer.StandardInput.Flush();
|
||||
_paused = false;
|
||||
}
|
||||
|
||||
public override void Pause()
|
||||
{
|
||||
_mplayer.StandardInput.WriteLine("pausing set_property pause 1");
|
||||
//_mplayer.StandardInput.WriteLine("pausing set_property pause 1");
|
||||
_mplayer.StandardInput.WriteLine("pause");
|
||||
_mplayer.StandardInput.Flush();
|
||||
_paused = true;
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
_mplayer.StandardInput.WriteLine("pausing set_property time_pos 0");
|
||||
_mplayer.StandardInput.WriteLine("stop");
|
||||
_mplayer.StandardInput.Flush();
|
||||
_paused = true;
|
||||
_lastLengthInSeconds = _lengthInSeconds;
|
||||
}
|
||||
|
||||
public override bool IsPaused
|
||||
@ -127,7 +132,7 @@ namespace Nikse.SubtitleEdit.Logic.VideoPlayers
|
||||
|
||||
// start timer to collect variable properties
|
||||
timer = new System.Windows.Forms.Timer();
|
||||
timer.Interval = 500;
|
||||
timer.Interval = 1000;
|
||||
timer.Tick += new EventHandler(timer_Tick);
|
||||
timer.Start();
|
||||
|
||||
@ -155,9 +160,16 @@ namespace Nikse.SubtitleEdit.Logic.VideoPlayers
|
||||
|
||||
if (OnVideoLoaded != null && _loaded == true)
|
||||
{
|
||||
timer.Stop();
|
||||
_loaded = false;
|
||||
OnVideoLoaded.Invoke(this, null);
|
||||
timer.Interval = 200;
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
if (_lengthInSeconds != _lastLengthInSeconds)
|
||||
_paused = false;
|
||||
_lastLengthInSeconds = _lengthInSeconds;
|
||||
}
|
||||
|
||||
void MPlayerOutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
@ -282,6 +294,7 @@ namespace Nikse.SubtitleEdit.Logic.VideoPlayers
|
||||
|
||||
public override void DisposeVideoPlayer()
|
||||
{
|
||||
timer.Stop();
|
||||
if (_mplayer != null)
|
||||
{
|
||||
_mplayer.OutputDataReceived -= MPlayerOutputDataReceived;
|
||||
|
@ -585,6 +585,7 @@
|
||||
<Compile Include="Logic\VideoFormats\RiffParser.cs" />
|
||||
<Compile Include="Logic\VideoFormats\VideoInfo.cs" />
|
||||
<Compile Include="Logic\VideoPlayers\LibVlcDynamic.cs" />
|
||||
<Compile Include="Logic\VideoPlayers\LibVlcMono.cs" />
|
||||
<Compile Include="Logic\VideoPlayers\ManagedDirectXPlayer.cs" />
|
||||
<Compile Include="Logic\VideoPlayers\MPlayer.cs" />
|
||||
<Compile Include="Logic\VideoPlayers\QuartsPlayer.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user