using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BoneLib.BoneMenu; using BoneLib.Notifications; using HarmonyLib; using LabFusion.Network; using LabFusion.Network.Serialization; using LabFusion.Player; using LabFusion.SDK.Metadata; using LabFusion.SDK.Modules; using LabFusion.Safety; using MediaDrop; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(MediaDropMod), "MediaDrop", "1.3.1", "ChappieStudios", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("MediaDrop")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MediaDrop")] [assembly: AssemblyTitle("MediaDrop")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MediaDrop { public sealed class MediaDropMod : MelonMod { private static readonly HashSet VideoExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { ".mp4", ".m4v", ".mov", ".webm", ".avi", ".wmv", ".mkv" }; private static readonly HashSet AudioExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { ".mp3", ".wav", ".ogg", ".m4a", ".aac", ".flac" }; private static readonly HttpClient HttpClient = new HttpClient { Timeout = TimeSpan.FromMinutes(10.0) }; private const int PreferredPort = 28472; private const int MaxMenuNameLength = 52; private const float FusionPresenceUpdateSeconds = 5f; private const string FusionPresenceKey = "MediaDropMod"; private const string FusionPresenceValue = "1.3.1"; private const string CloudflaredDownloadUrl = "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe"; private readonly object _lock = new object(); private readonly Queue _mainThreadActions = new Queue(); private readonly Dictionary _fusionLinks = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly HashSet _allowedTunnelHosts = new HashSet(StringComparer.OrdinalIgnoreCase); private MelonPreferences_Category _preferences; private MelonPreferences_Entry _autoCopyPreference; private MelonPreferences_Entry _shareToFusionPreference; private Page _menuPage; private Page _peopleWithoutModPage; private string _mediaFolder; private string _cloudflaredPath; private bool _autoCopyNewFiles = true; private bool _shareToFusion = true; private TcpListener _listener; private Thread _serverThread; private volatile bool _serverRunning; private int _port; private Process _tunnelProcess; private string _publicBaseUrl; private bool _tunnelStarting; private FileSystemWatcher _watcher; private string _pendingAutoCopyPath; private float _nextFusionPresenceUpdateTime; private float _nextMissingModMenuRefreshTime; internal static MediaDropMod Instance { get; private set; } public override void OnInitializeMelon() { Instance = this; SetupPreferences(); RegisterFusionNetworking(); ((MelonBase)this).HarmonyInstance.PatchAll(typeof(MediaDropMod).Assembly); _mediaFolder = Path.Combine(MelonEnvironment.UserDataDirectory, "MediaDrop"); _cloudflaredPath = Path.Combine(_mediaFolder, "cloudflared.exe"); Directory.CreateDirectory(_mediaFolder); StartServer(); StartWatcher(); BuildMenu(); RestartPublicTunnel(); ((MelonBase)this).LoggerInstance.Msg("MediaDrop loaded. Folder: " + _mediaFolder); } public override void OnDeinitializeMelon() { StopWatcher(); StopTunnel(); StopServer(); Instance = null; } public override void OnUpdate() { float time = Time.time; UpdateFusionPresence(time); RefreshPeopleWithoutModPage(time); while (true) { Action action = null; lock (_lock) { if (_mainThreadActions.Count > 0) { action = _mainThreadActions.Dequeue(); } } if (action != null) { try { action(); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("MediaDrop main-thread action failed: " + ex.Message); } continue; } break; } } private void SetupPreferences() { _preferences = MelonPreferences.CreateCategory("MediaDrop"); _autoCopyPreference = _preferences.CreateEntry("AutoCopyNewFiles", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _shareToFusionPreference = _preferences.CreateEntry("ShareToFusion", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _autoCopyNewFiles = _autoCopyPreference.Value; _shareToFusion = _shareToFusionPreference.Value; } private void RegisterFusionNetworking() { try { ModuleMessageManager.RegisterHandler(); ((MelonBase)this).LoggerInstance.Msg("MediaDrop Fusion networking registered."); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("MediaDrop Fusion networking registration skipped: " + ex.Message); } } private void BuildMenu() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) if (_menuPage == null) { _menuPage = Page.Root.CreatePage("MediaDrop", Color.cyan, 0, true); } else { _menuPage.RemoveAll(); } List mediaFiles = GetMediaFiles(); string text = ((!string.IsNullOrWhiteSpace(_publicBaseUrl)) ? "Tunnel Ready" : (_tunnelStarting ? "Tunnel Starting" : "No Public Tunnel")); _menuPage.CreateBool("Auto Copy New Files", Color.yellow, _autoCopyNewFiles, (Action)SetAutoCopy); _menuPage.CreateBool("Share To Fusion", Color.cyan, _shareToFusion, (Action)SetShareToFusion); _menuPage.CreateFunction(text, string.IsNullOrWhiteSpace(_publicBaseUrl) ? Color.red : Color.green, (Action)CopyTunnelBaseUrl); _menuPage.CreateFunction("Restart Public Tunnel", Color.yellow, (Action)RestartPublicTunnel); _menuPage.CreateFunction($"Refresh Files ({mediaFiles.Count})", Color.yellow, (Action)BuildMenu); _menuPage.CreateFunction("Open Media Folder", Color.green, (Action)OpenMediaFolder); _menuPage.CreateFunction("Copy Latest Public Link", Color.white, (Action)CopyLatestPublicLink); AddFilePage("Videos", Color.red, mediaFiles.Where(IsVideoFile).ToList()); AddFilePage("Audio", Color.magenta, mediaFiles.Where(IsAudioFile).ToList()); AddFilePage("All Files", Color.white, mediaFiles); AddFusionLinksPage(); _peopleWithoutModPage = _menuPage.CreatePage("People Without Mod", Color.cyan, 0, true); BuildPeopleWithoutModPage(); } private void AddFilePage(string name, Color color, List files) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) Page val = _menuPage.CreatePage($"{name} ({files.Count})", color, 0, true); if (files.Count == 0) { val.CreateFunction("No Files Found", Color.gray, (Action)delegate { }); return; } foreach (string item in files.OrderBy(Path.GetFileName)) { string capturedFile = item; val.CreateFunction(TrimMenuName(Path.GetFileName(capturedFile)), Color.white, (Action)delegate { CopyOrQueuePublicUrl(capturedFile); }); } } private void SetAutoCopy(bool value) { _autoCopyNewFiles = value; _autoCopyPreference.Value = value; _preferences.SaveToFile(false); } private void SetShareToFusion(bool value) { _shareToFusion = value; _shareToFusionPreference.Value = value; _preferences.SaveToFile(false); } private void AddFusionLinksPage() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) Page val = _menuPage.CreatePage($"Fusion Links ({_fusionLinks.Count})", Color.cyan, 0, true); if (_fusionLinks.Count == 0) { val.CreateFunction("No Links Received", Color.gray, (Action)delegate { }); return; } foreach (KeyValuePair item in _fusionLinks.OrderBy((KeyValuePair pair) => pair.Key)) { string name = item.Key; string url = item.Value; val.CreateFunction(TrimMenuName(name), Color.white, (Action)delegate { CopyReceivedFusionUrl(name, url); }); } } private void UpdateFusionPresence(float now) { if (now < _nextFusionPresenceUpdateTime) { return; } _nextFusionPresenceUpdateTime = now + 5f; try { if (NetworkInfo.HasServer && PlayerIDManager.LocalID != null && PlayerIDManager.LocalID.IsValid && PlayerIDManager.LocalID.Metadata.Metadata.GetMetadata("MediaDropMod") != "1.3.1") { PlayerIDManager.LocalID.Metadata.Metadata.TrySetMetadata("MediaDropMod", "1.3.1"); } } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("MediaDrop Fusion mod check failed: " + ex.Message); } } private void RefreshPeopleWithoutModPage(float now) { if (!(now < _nextMissingModMenuRefreshTime)) { _nextMissingModMenuRefreshTime = now + 5f; BuildPeopleWithoutModPage(); } } private void BuildPeopleWithoutModPage() { //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) if (_peopleWithoutModPage == null) { return; } _peopleWithoutModPage.RemoveAll(); _peopleWithoutModPage.CreateFunction("Refresh", Color.yellow, (Action)BuildPeopleWithoutModPage); try { if (!NetworkInfo.HasServer) { _peopleWithoutModPage.CreateFunction("Not In Fusion Lobby", Color.gray, (Action)delegate { }); return; } List list = new List(PlayerIDManager.PlayerIDs); list.Sort((PlayerID left, PlayerID right) => string.Compare(GetFusionPlayerName(left), GetFusionPlayerName(right), StringComparison.OrdinalIgnoreCase)); int num = 0; foreach (PlayerID item in list) { if (item != null && item.IsValid && !item.IsMe && string.IsNullOrWhiteSpace(item.Metadata.Metadata.GetMetadata("MediaDropMod"))) { num++; string fusionPlayerName = GetFusionPlayerName(item); _peopleWithoutModPage.CreateFunction(TrimMenuName(fusionPlayerName), Color.red, (Action)delegate { }); } } if (num == 0) { _peopleWithoutModPage.CreateFunction("Everyone Has Mod", Color.green, (Action)delegate { }); } } catch (Exception ex) { _peopleWithoutModPage.CreateFunction("Could Not Read Lobby", Color.red, (Action)delegate { }); ((MelonBase)this).LoggerInstance.Warning("MediaDrop people-without-mod menu failed: " + ex.Message); } } private static string GetFusionPlayerName(PlayerID player) { if (player == null) { return "Unknown Player"; } PlayerMetadata metadata = player.Metadata; object obj; if (metadata == null) { obj = null; } else { MetadataVariable nickname = metadata.Nickname; obj = ((nickname != null) ? nickname.GetValueOrEmpty() : null); } string text = (string)obj; if (!string.IsNullOrWhiteSpace(text)) { return text; } PlayerMetadata metadata2 = player.Metadata; object obj2; if (metadata2 == null) { obj2 = null; } else { MetadataVariable username = metadata2.Username; obj2 = ((username != null) ? username.GetValueOrEmpty() : null); } string text2 = (string)obj2; if (!string.IsNullOrWhiteSpace(text2)) { return text2; } return $"Player {player.SmallID}"; } private void OpenMediaFolder() { try { Process.Start(new ProcessStartInfo { FileName = _mediaFolder, UseShellExecute = true }); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("Could not open MediaDrop folder: " + ex.Message); } } private void CopyTunnelBaseUrl() { if (string.IsNullOrWhiteSpace(_publicBaseUrl)) { Notify("MediaDrop", "Public tunnel is not ready yet."); return; } GUIUtility.systemCopyBuffer = _publicBaseUrl; Notify("MediaDrop", "Copied public tunnel link."); } private void CopyLatestPublicLink() { string text = GetMediaFiles().OrderByDescending(File.GetLastWriteTimeUtc).FirstOrDefault(); if (string.IsNullOrWhiteSpace(text)) { Notify("MediaDrop", "No media files found."); } else { CopyOrQueuePublicUrl(text); } } private void CopyOrQueuePublicUrl(string path) { if (!File.Exists(path)) { return; } if (string.IsNullOrWhiteSpace(_publicBaseUrl)) { _pendingAutoCopyPath = path; Notify("MediaDrop", "Waiting for public tunnel, then link will copy."); if (!_tunnelStarting) { RestartPublicTunnel(); } } else { string publicUrlForFile = GetPublicUrlForFile(path); AllowTunnelUrl(publicUrlForFile); GUIUtility.systemCopyBuffer = publicUrlForFile; Notify("MediaDrop", "Copied public link: " + Path.GetFileName(path)); ((MelonBase)this).LoggerInstance.Msg("Copied public MediaDrop link: " + publicUrlForFile); SharePublicUrlWithFusion(Path.GetFileName(path), publicUrlForFile); } } private string GetPublicUrlForFile(string path) { string text = Uri.EscapeDataString(Path.GetFileName(path)); return _publicBaseUrl.TrimEnd('/') + "/media/" + text; } private void StartWatcher() { _watcher = new FileSystemWatcher(_mediaFolder); _watcher.IncludeSubdirectories = false; _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; _watcher.Created += OnMediaFolderChanged; _watcher.Renamed += OnMediaFolderRenamed; _watcher.Deleted += OnMediaFolderChanged; _watcher.EnableRaisingEvents = true; } private void StopWatcher() { if (_watcher != null) { _watcher.EnableRaisingEvents = false; _watcher.Dispose(); _watcher = null; } } private void OnMediaFolderChanged(object sender, FileSystemEventArgs args) { QueueMainThread(BuildMenu); if (_autoCopyNewFiles && File.Exists(args.FullPath) && IsMediaFile(args.FullPath)) { QueueMainThread(delegate { CopyOrQueuePublicUrl(args.FullPath); }); } } private void OnMediaFolderRenamed(object sender, RenamedEventArgs args) { QueueMainThread(BuildMenu); if (_autoCopyNewFiles && File.Exists(args.FullPath) && IsMediaFile(args.FullPath)) { QueueMainThread(delegate { CopyOrQueuePublicUrl(args.FullPath); }); } } private void StartServer() { try { _listener = new TcpListener(IPAddress.Loopback, 28472); _listener.Start(); } catch { _listener = new TcpListener(IPAddress.Loopback, 0); _listener.Start(); } _port = ((IPEndPoint)_listener.LocalEndpoint).Port; _serverRunning = true; _serverThread = new Thread(ServerLoop) { IsBackground = true, Name = "MediaDrop HTTP Server" }; _serverThread.Start(); } private void StopServer() { _serverRunning = false; try { _listener?.Stop(); } catch { } _listener = null; } private void RestartPublicTunnel() { if (_tunnelStarting) { Notify("MediaDrop", "Public tunnel is already starting."); return; } StopTunnel(); _publicBaseUrl = null; _tunnelStarting = true; BuildMenu(); Notify("MediaDrop", "Starting public tunnel."); Task.Run((Func)StartTunnelWorker); } private async Task StartTunnelWorker() { try { await EnsureCloudflared(); ProcessStartInfo startInfo = new ProcessStartInfo { FileName = _cloudflaredPath, Arguments = $"tunnel --no-autoupdate --url http://127.0.0.1:{_port}", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true }; Process process = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; process.OutputDataReceived += OnTunnelOutput; process.ErrorDataReceived += OnTunnelOutput; process.Exited += OnTunnelExited; lock (_lock) { _tunnelProcess = process; } process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); } catch (Exception ex2) { Exception ex = ex2; ((MelonBase)this).LoggerInstance.Warning("Could not start MediaDrop public tunnel: " + ex.Message); QueueMainThread(delegate { _tunnelStarting = false; Notify("MediaDrop Tunnel Failed", ex.Message); BuildMenu(); }); } } private async Task EnsureCloudflared() { if (!File.Exists(_cloudflaredPath)) { QueueMainThread(delegate { Notify("MediaDrop", "Downloading public tunnel helper."); }); byte[] bytes = await HttpClient.GetByteArrayAsync("https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe"); File.WriteAllBytes(_cloudflaredPath, bytes); } } private void OnTunnelOutput(object sender, DataReceivedEventArgs args) { if (string.IsNullOrWhiteSpace(args.Data)) { return; } Match match = Regex.Match(args.Data, "https://[-a-zA-Z0-9.]+\\.trycloudflare\\.com"); if (!match.Success) { return; } string url = match.Value; QueueMainThread(delegate { _publicBaseUrl = url; AllowTunnelUrl(url); _tunnelStarting = false; Notify("MediaDrop", "Public tunnel ready."); BuildMenu(); if (!string.IsNullOrWhiteSpace(_pendingAutoCopyPath) && File.Exists(_pendingAutoCopyPath)) { string pendingAutoCopyPath = _pendingAutoCopyPath; _pendingAutoCopyPath = null; CopyOrQueuePublicUrl(pendingAutoCopyPath); } }); } private void OnTunnelExited(object sender, EventArgs args) { QueueMainThread(delegate { ((MelonBase)this).LoggerInstance.Warning("MediaDrop public tunnel stopped."); _publicBaseUrl = null; _tunnelStarting = false; BuildMenu(); }); } private void SharePublicUrlWithFusion(string fileName, string url) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!_shareToFusion || !NetworkInfo.HasServer) { return; } try { MessageRelay.RelayModule(new MediaDropLinkData { FileName = fileName, Url = url }, CommonMessageRoutes.ReliableToOtherClients); Notify("MediaDrop Fusion", "Sent link to Fusion players."); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("Could not share MediaDrop link through Fusion: " + ex.Message); } } internal void ReceiveFusionLink(string fileName, string url) { if (!string.IsNullOrWhiteSpace(url)) { if (string.IsNullOrWhiteSpace(fileName)) { fileName = "MediaDrop Link"; } AllowTunnelUrl(url); _fusionLinks[fileName] = url; GUIUtility.systemCopyBuffer = url; Notify("MediaDrop Fusion", "Received link: " + fileName); BuildMenu(); } } private void CopyReceivedFusionUrl(string name, string url) { if (!string.IsNullOrWhiteSpace(url)) { AllowTunnelUrl(url); GUIUtility.systemCopyBuffer = url; Notify("MediaDrop Fusion", "Copied link: " + name); } } private void AllowTunnelUrl(string url) { if (Uri.TryCreate(url, UriKind.Absolute, out Uri result)) { _allowedTunnelHosts.Add(result.Host); } } internal static bool IsAllowedMediaDropUrl(string url) { if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result)) { return false; } if (result.Scheme != Uri.UriSchemeHttp && result.Scheme != Uri.UriSchemeHttps) { return false; } if (!result.AbsolutePath.StartsWith("/media/", StringComparison.OrdinalIgnoreCase)) { return false; } MediaDropMod instance = Instance; if (instance != null && instance._allowedTunnelHosts.Contains(result.Host)) { return true; } return result.Host.EndsWith(".trycloudflare.com", StringComparison.OrdinalIgnoreCase); } private void StopTunnel() { Process process = null; lock (_lock) { process = _tunnelProcess; _tunnelProcess = null; } if (process == null) { return; } try { if (!process.HasExited) { process.Kill(); } } catch { } } private void ServerLoop() { while (_serverRunning) { try { TcpClient client = _listener.AcceptTcpClient(); ThreadPool.QueueUserWorkItem(delegate { HandleClient(client); }); } catch { if (_serverRunning) { Thread.Sleep(50); } } } } private void HandleClient(TcpClient client) { using (client) { using NetworkStream stream = client.GetStream(); try { string text = ReadRequestHeader(stream); if (string.IsNullOrWhiteSpace(text)) { return; } string[] array = text.Split(new string[1] { "\r\n" }, StringSplitOptions.None); string[] array2 = array[0].Split(' '); if (array2.Length < 2) { WriteStatus(stream, "400 Bad Request", "Bad request."); return; } string text2 = array2[0]; string text3 = array2[1]; if (text2 != "GET" && text2 != "HEAD") { WriteStatus(stream, "405 Method Not Allowed", "Only GET and HEAD are supported."); return; } if (!text3.StartsWith("/media/", StringComparison.OrdinalIgnoreCase)) { WriteStatus(stream, "404 Not Found", "Media file not found."); return; } string path = Uri.UnescapeDataString(text3.Substring("/media/".Length).Split('?')[0]); path = Path.GetFileName(path); string text4 = Path.Combine(_mediaFolder, path); if (!File.Exists(text4) || !IsMediaFile(text4)) { WriteStatus(stream, "404 Not Found", "Media file not found."); } else { ServeFile(stream, text4, array, text2 == "HEAD"); } } catch { } } } private static string ReadRequestHeader(NetworkStream stream) { List list = new List(); byte[] array = new byte[1]; while (list.Count < 16384 && stream.Read(array, 0, 1) > 0) { list.Add(array[0]); int count = list.Count; if (count >= 4 && list[count - 4] == 13 && list[count - 3] == 10 && list[count - 2] == 13 && list[count - 1] == 10) { break; } } return Encoding.ASCII.GetString(list.ToArray()); } private static void ServeFile(NetworkStream stream, string filePath, string[] requestLines, bool headOnly) { long length = new FileInfo(filePath).Length; long num = 0L; long num2 = length - 1; bool flag = false; string text = requestLines.FirstOrDefault((string line) => line.StartsWith("Range:", StringComparison.OrdinalIgnoreCase)); if (!string.IsNullOrWhiteSpace(text)) { string text2 = text.Substring("Range:".Length).Trim(); if (text2.StartsWith("bytes=", StringComparison.OrdinalIgnoreCase)) { string[] array = text2.Substring("bytes=".Length).Split('-'); if (array.Length == 2) { if (long.TryParse(array[0], out var result)) { num = Math.Max(0L, result); } if (long.TryParse(array[1], out var result2)) { num2 = Math.Min(length - 1, result2); } if (num <= num2) { flag = true; } } } } long num3 = num2 - num + 1; string value = (flag ? "206 Partial Content" : "200 OK"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("HTTP/1.1 ").Append(value).Append("\r\n"); stringBuilder.Append("Content-Type: ").Append(GetContentType(filePath)).Append("\r\n"); stringBuilder.Append("Accept-Ranges: bytes\r\n"); stringBuilder.Append("Content-Length: ").Append(num3).Append("\r\n"); if (flag) { stringBuilder.Append("Content-Range: bytes ").Append(num).Append("-") .Append(num2) .Append("/") .Append(length) .Append("\r\n"); } stringBuilder.Append("Connection: close\r\n\r\n"); byte[] bytes = Encoding.ASCII.GetBytes(stringBuilder.ToString()); stream.Write(bytes, 0, bytes.Length); if (headOnly) { return; } byte[] array2 = new byte[81920]; using FileStream fileStream = File.OpenRead(filePath); fileStream.Position = num; long num4 = num3; while (num4 > 0) { int num5 = fileStream.Read(array2, 0, (int)Math.Min(array2.Length, num4)); if (num5 <= 0) { break; } stream.Write(array2, 0, num5); num4 -= num5; } } private static void WriteStatus(NetworkStream stream, string status, string message) { byte[] bytes = Encoding.UTF8.GetBytes(message); string s = $"HTTP/1.1 {status}\r\nContent-Type: text/plain\r\nContent-Length: {bytes.Length}\r\nConnection: close\r\n\r\n"; byte[] bytes2 = Encoding.ASCII.GetBytes(s); stream.Write(bytes2, 0, bytes2.Length); stream.Write(bytes, 0, bytes.Length); } private List GetMediaFiles() { if (!Directory.Exists(_mediaFolder)) { return new List(); } return Directory.EnumerateFiles(_mediaFolder, "*", SearchOption.TopDirectoryOnly).Where(IsMediaFile).OrderBy(Path.GetFileName) .ToList(); } private static bool IsMediaFile(string path) { if (!IsVideoFile(path)) { return IsAudioFile(path); } return true; } private static bool IsVideoFile(string path) { return VideoExtensions.Contains(Path.GetExtension(path)); } private static bool IsAudioFile(string path) { return AudioExtensions.Contains(Path.GetExtension(path)); } private static string GetContentType(string path) { switch (Path.GetExtension(path).ToLowerInvariant()) { case ".m4v": case ".mp4": return "video/mp4"; case ".mov": return "video/quicktime"; case ".webm": return "video/webm"; case ".avi": return "video/x-msvideo"; case ".wmv": return "video/x-ms-wmv"; case ".mkv": return "video/x-matroska"; case ".mp3": return "audio/mpeg"; case ".wav": return "audio/wav"; case ".ogg": return "audio/ogg"; case ".m4a": return "audio/mp4"; case ".aac": return "audio/aac"; case ".flac": return "audio/flac"; default: return "application/octet-stream"; } } private static string TrimMenuName(string value) { if (string.IsNullOrWhiteSpace(value)) { return "Unnamed File"; } if (value.Length > 52) { return value.Substring(0, 49) + "..."; } return value; } private void QueueMainThread(Action action) { lock (_lock) { _mainThreadActions.Enqueue(action); } } private void Notify(string title, string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown try { Notifier.Send(new Notification { Title = new NotificationText(title), Message = new NotificationText(message), ShowTitleOnPopup = true, PopupLength = 5f, Type = (NotificationType)0 }); } catch { } } } public sealed class MediaDropLinkData : INetSerializable { public string FileName; public string Url; public int? GetSize() { return SizeExtensions.GetSize(FileName) + SizeExtensions.GetSize(Url); } public void Serialize(INetSerializer serializer) { serializer.SerializeValue(ref FileName); serializer.SerializeValue(ref Url); } } public sealed class MediaDropLinkMessage : ModuleMessageHandler { protected override void OnHandleMessage(ReceivedMessage received) { MediaDropLinkData mediaDropLinkData = ((ReceivedMessage)(ref received)).ReadData(); MediaDropMod.Instance?.ReceiveFusionLink(mediaDropLinkData.FileName, mediaDropLinkData.Url); } } [HarmonyPatch(typeof(URLWhitelistManager), "IsURLWhitelisted")] internal static class FusionUrlWhitelistPatch { private static void Postfix(string url, ref bool __result) { if (!__result && MediaDropMod.IsAllowedMediaDropUrl(url)) { __result = true; } } } }