/// <summary> /// Starts the web media server /// </summary> public static void StartWebMediaServer() { //Stop the server if it's already running if (WebMediaServer != null) { if (WebMediaServer.IsTCPOnline) { WebMediaServer.Stop(); } } //Create webserver ConLog.Log("WebMedia Link", "Starting WebMedia link server", LogType.Info); WebMediaServer = ConnectionFactory.CreateServerConnectionContainer(/*WebMediaIp,*/ WebMediaPort, false); WebMediaServer.AllowUDPConnections = false; //Create connection established and lost handlers WebMediaServer.ConnectionEstablished += async(connection, type) => await WebMediaConnected(connection, type); WebMediaServer.ConnectionLost += async(connection, type, reason) => await WebMediaDisconnected(connection, type, reason); //Start webserver WebMediaServer.Start(); ConLog.Log("WebMedia Link", "WebMedia link server started", LogType.Ok); }
/// <summary> /// Attempts to start the HTTP server /// </summary> /// <returns>True if it started successfully, false if not</returns> public bool StartServer() { ConLog.Log("HTTP Server", "Starting HTTP server", LogType.Info); bool hasStarted = false; try { Server = new HttpListener(); //Add server prefixes Server.Prefixes.Add("http://*:" + Port + "/"); Server.Start(); //Register the cancellation token to stop the server CancelToken.Register(() => Server.Stop()); //Start get context loop _ = Task.Run(() => MainLoop()); ConLog.Log("HTTP Server", "HTTP Server started", LogType.Ok); hasStarted = true; } catch (HttpListenerException e) { ConLog.Log("HTTP Server", "Error while starting HTTP server: " + e.Message, LogType.Error); hasStarted = false; } return(hasStarted); }
/// <summary> /// Called when a media server connects. Adds the connection to the appropriate dictionaries /// </summary> /// <param name="connection">The connection that connected</param> /// <param name="type">The type of connection. Should be TCP</param> /// <returns>A Task representing the operation</returns> private static async Task WebMediaConnected(Connection connection, Network.Enums.ConnectionType type) { //Check that it's TCP if (type != Network.Enums.ConnectionType.TCP) { return; } ConLog.Log("WebMedia Link", "Media server " + connection.IPRemoteEndPoint.ToString() + " connected", LogType.Info); //Check that SignalR is connected - if not, disconnect them if (SignalRConnectionState != HubConnectionState.Connected) { ConLog.Log("WebMedia Link", "Disconnecting media server " + connection.IPRemoteEndPoint.ToString() + " because the server is not done setting up", LogType.Info); connection.Close(Network.Enums.CloseReason.ClientClosed); return; } //Create a new media server with the given name MediaServer newServer = new MediaServer((TcpConnection)connection); //Initiate await newServer.Init(); //Add to dictionaries UuidToMediaServer.Add(newServer.UUID, newServer); ConnectionToUuid.Add(newServer.Connection, newServer.UUID); //Update SignalR await UpdateAllSignalRClients(); ConLog.Log("WebMedia Link", "Added media server with name " + newServer.Name + " and address " + newServer.Connection.IPRemoteEndPoint.ToString(), LogType.Ok); }
/// <summary> /// Load a configuration from a YAML file /// </summary> /// <typeparam name="T">The class to deserialize the YAML file into</typeparam> /// <param name="fileLocation">The location of the config file</param> /// <returns>An object of type T containing the data loaded from the config file</returns> public static T LoadConfig <T>(string fileLocation) where T : new() { ConLog.Log("Configuration", "Loading configuration from " + Path.GetFullPath(fileLocation), LogType.Info); Deserializer convert = new Deserializer(); T returnObj = new T(); //Check that the file exists if (!File.Exists(fileLocation)) { SaveConfig(fileLocation, returnObj); ConLog.Log("Configuration", "The configuration file was not found, so one was generated. Please review the configuration before re-launching the program", LogType.Fatal); } //Try to deserialise it try { using StreamReader reader = new StreamReader(fileLocation); returnObj = convert.Deserialize <T>(reader); } catch (YamlDotNet.Core.YamlException e) { ConLog.Log("Configuration", "An error occurred when reading from the configuration file. To regenerate the config file, delete it and re-launch the program\nException:\n" + e.Message, LogType.Fatal); } ConLog.Log("Configuration", "Configuration loaded", LogType.Ok); return(returnObj); }
/// <summary> /// Starts the web server with the provided arguments, IP and port /// </summary> /// <param name="args">The arguments to pass to the builder</param> /// <returns>A Task that ends when the web server stops</returns> public static async Task <Task> StartWebInterface(string[] args) { ConLog.Log("WebMedia Link", "Starting web interface", LogType.Info); Task webTask = Task.Run(async() => await Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup <Startup>(); webBuilder.UseUrls("http://" + WebServerIp + ":" + WebServerPort + "/"); }).Build().RunAsync()); ConLog.Log("WebMedia Link", "Starting SignalR", LogType.Info); //Start SignalR SignalRConnection = new HubConnectionBuilder() .WithAutomaticReconnect() .WithUrl("http://" + WebServerIp + ":" + WebServerPort + "/serverlistHub") .Build(); //Create event handlers HubConnectionExtensions.On <string>(SignalRConnection, "ClientConnected", SignalRClientConnected); await SignalRConnection.StartAsync(); ConLog.Log("WebMedia Link", "Web interface started", LogType.Ok); return(webTask); }
/// <summary> /// Save a configuration to a YAML file /// </summary> /// <param name="fileLocation">The location of the config file</param> /// <param name="configToSave">The data to save into the config file</param> public static void SaveConfig(string fileLocation, object configToSave) { ConLog.Log("Configuration", "Saving configuration to " + Path.GetFullPath(fileLocation), LogType.Info); Serializer convert = new Serializer(); using StreamWriter writer = new StreamWriter(fileLocation); convert.Serialize(writer, configToSave); ConLog.Log("Configuration", "Configuration saved", LogType.Ok); }
/// <summary> /// Creates a new webmedia client with the given IP, Port, and HTTP server /// </summary> /// <param name="ip">The IP of the webmedia link server</param> /// <param name="port">The port of the webmedia link server</param> /// <param name="httpIp">The IP to host the HTTP server from</param> /// <param name="httpPort">The port to host the HTTP server on</param> /// <param name="name">The name of the media server</param> /// <param name="password">The password of the media server</param> /// <param name="pathToMediaFiles">The location of the folder containing the media files</param> /// <param name="pathToDownloadFiles">The location of the folder containing the download files</param> /// <param name="pathToSubtitleFiles">The location of the folder containing the subtitle files</param> public WebMediaClient(string ip, ushort port, string httpIp, ushort httpPort, string name, string password, string pathToMediaFiles, string pathToDownloadFiles, string pathToSubtitleFiles) { WebserverIp = ip; WebserverPort = port; MediaserverIp = httpIp; MediaserverPort = httpPort; Name = name; Password = password; MediaFilesPath = pathToMediaFiles; DownloadFilesPath = pathToDownloadFiles; SubtitleFilesPath = pathToSubtitleFiles; //Use the .exe if windows, use the . nothing otherwise if (Environment.OSVersion.Platform == PlatformID.Win32NT) { Downloader = new YoutubeDL(Helpful.GetExecutingDirectory() + "\\youtubedl.exe", CancelToken); } else { Downloader = new YoutubeDL(Helpful.GetExecutingDirectory() + "\\youtubedl", CancelToken); } //Create the media server MediaServer = new HttpServer(httpIp, httpPort, pathToMediaFiles, pathToDownloadFiles, pathToSubtitleFiles, CancelTokenSource.Token); //Populate the media server's list of available files RescanForFiles(); //Try to start media server. If it fails, stop the program if (!MediaServer.StartServer()) { CancelTokenSource.Cancel(); ConLog.Log("HTTP Server", "Failed to start HTTP server. Try running as an administrator, and check that your firewall or antivirus isn't preventing this program from starting the HTTP server", LogType.Fatal); } //Register file system watchers FileSystemWatcher mediaWatcher = new FileSystemWatcher(pathToMediaFiles, "*.*"); mediaWatcher.EnableRaisingEvents = true; mediaWatcher.IncludeSubdirectories = false; mediaWatcher.Changed += (sender, e) => UpdateAvailableFiles(); mediaWatcher.Created += (sender, e) => UpdateAvailableFiles(); mediaWatcher.Deleted += (sender, e) => UpdateAvailableFiles(); mediaWatcher.Renamed += (sender, e) => UpdateAvailableFiles(); FileSystemWatcher downloadWatcher = new FileSystemWatcher(pathToDownloadFiles, "*.*"); downloadWatcher.EnableRaisingEvents = true; downloadWatcher.IncludeSubdirectories = false; downloadWatcher.Changed += (sender, e) => UpdateAvailableFiles(); downloadWatcher.Created += (sender, e) => UpdateAvailableFiles(); downloadWatcher.Deleted += (sender, e) => UpdateAvailableFiles(); downloadWatcher.Renamed += (sender, e) => UpdateAvailableFiles(); }
static void Main(string[] args) { #if DEBUG Task.Delay(6000).Wait(); #endif const string CONFIG_FILE_LOCATION = "config.yaml"; //Load the config Configuration config = ConfigParser.LoadConfig <Configuration>(CONFIG_FILE_LOCATION); //Validate config if (!Directory.Exists(config.PathToMedia)) { ConLog.Log("Configuration", "The path to the media files folder doesn't exist", LogType.Fatal); } if (config.Name == "Untitled") { ConLog.Log("Configuration", "Please change the name of the media server from its default value", LogType.Fatal); } if (string.IsNullOrWhiteSpace(config.Name)) { ConLog.Log("Configuration", "The name must not be left blank", LogType.Fatal); } if (string.IsNullOrWhiteSpace(config.Password)) { config.Password = ""; } //Delete and create the downloads folder if (Directory.Exists(config.PathToDownload)) { Directory.Delete(config.PathToDownload, true); } Directory.CreateDirectory(config.PathToDownload); Directory.CreateDirectory(config.PathToDownload + "\\incomplete"); //Delete and create the subtitles folder if (Directory.Exists(config.PathToSubtitle)) { Directory.Delete(config.PathToSubtitle, true); } Directory.CreateDirectory(config.PathToSubtitle); //Connect to webserver WebMediaClient serverLink = new WebMediaClient(config.WebserverIp, config.WebserverPort, config.HttpHostIp, config.HttpHostPort, config.Name, config.Password, config.PathToMedia, config.PathToDownload, config.PathToSubtitle); serverLink.ConnectToWebserver().Wait(); Task.Delay(-1, serverLink.CancelToken).Wait(); ConLog.Log("Program", "End of program", LogType.Info); Environment.Exit(0); }
/// <summary> /// Handle a download request /// </summary> /// <param name="rawData">The raw data sent</param> /// <param name="connection">The connection that sent the request</param> /// <returns>A Task representing the download</returns> private async Task DownloadFromRequest(Network.Packets.RawData rawData, Connection connection) { string url = Encoding.Unicode.GetString(rawData.Data); ConLog.Log("WebMedia Link", "Received request to download " + url, LogType.Info); if (!await DownloadUrl(url)) { ConLog.Log("WebMedia Link", url + " failed", LogType.Warning); } else { ConLog.Log("WebMedia Link", url + " completed", LogType.Info); } }
public async Task Init() { ConLog.Log("YouTubeDL", "Initiating YouTubeDL", LogType.Info); //Check that the file exists - if it doesn't, download it if (!File.Exists(PathToExecutable)) { ConLog.Log("YouTubeDL", "YouTubeDL executable not found! Downloading...", LogType.Warning); using (WebClient client = new WebClient()) { await client.DownloadFileTaskAsync(new Uri("https://yt-dl.org/downloads/latest/youtube-dl.exe"), PathToExecutable); } } ConLog.Log("YouTubeDL", "Initiated YouTubeDL", LogType.Ok); }
/// <summary> /// Connects to the webserver /// </summary> /// <returns>A Task representing the process</returns> public async Task ConnectToWebserver() { //If the connection is alive, close it if (WebServer != null) { if (WebServer.IsAlive) { WebServer.Close(Network.Enums.CloseReason.ServerClosed, false); } } //Initiate youtubedl await Downloader.Init(); //Connect to webserver ConLog.Log("WebMedia Link", "Connecting to WebMediaLink server", LogType.Info); Tuple <TcpConnection, ConnectionResult> result = await ConnectionFactory.CreateTcpConnectionAsync(WebserverIp, WebserverPort); //Check if connection worked if (result.Item2 != ConnectionResult.Connected) { ConLog.Log("WebMedia Link", "Failed to connect to WebMediaLink server", LogType.Error); await Disconnected(Network.Enums.CloseReason.Timeout, result.Item1); } WebServer = result.Item1; ConLog.Log("WebMedia Link", "Connected to WebMediaLink server", LogType.Ok); //Register cancel token triggered CancelToken.Register(() => { if (WebServer != null) { if (WebServer.IsAlive) { WebServer.Close(Network.Enums.CloseReason.ServerClosed, false); } } }); //Register connection lost handler WebServer.ConnectionClosed += async(reason, connection) => await Disconnected(reason, connection); //Register packet handlers WebServer.RegisterPacketHandler <GetInfoRequest>(GetInfoRequestReceived, this); WebServer.RegisterRawDataHandler("Download", async(rawData, connection) => await DownloadFromRequest(rawData, connection)); }
/// <summary> /// Downloads a file from a URL /// </summary> /// <param name="url">The URL to download from</param> /// <param name="pathToDownloadInto">The path of the file when it is downloaded</param> /// <returns>True if it was successful, false if not</returns> public async Task <bool> DownloadFileFromUrl(string url, string pathToDownloadInto) { ConLog.Log("YouTubeDL", "Downloading " + url, LogType.Info); string output = await RunProcessAndGetOutput("--no-playlist --quiet -f \"bestvideo+bestaudio/best/bestaudio/bestvideo\" --merge-output-format \"mp4\" -o \"" + pathToDownloadInto + "\" \"" + url + "\""); //Check for error if (output == null) { ConLog.Log("YouTubeDL", "Failed to download " + url, LogType.Warning); return(false); } else { ConLog.Log("YouTubeDL", "Downloaded " + url, LogType.Ok); return(true); } }
/// <summary> /// Downloads the information from a URL /// </summary> /// <param name="url">The URL to get the information of</param> /// <returns>The information downloaded. Null if the download failed</returns> public async Task <DownloadInfo> GetDownloadInfoFromUrl(string url) { ConLog.Log("YouTubeDL", "Downloading info from " + url, LogType.Info); string output = await RunProcessAndGetOutput("--no-playlist --quiet --dump-json -f \"bestvideo+bestaudio/best/bestaudio/bestvideo\" --merge-output-format \"mp4\" \"" + url + "\""); //Check for error if (output == null) { ConLog.Log("YouTubeDL", "Failed to download info from " + url, LogType.Warning); return(null); } //Get json DownloadInfo result = JsonConvert.DeserializeObject <DownloadInfo>(output); ConLog.Log("YouTubeDL", "Downloaded info from " + url, LogType.Ok); return(result); }
/// <summary> /// Creates a new http server, hosting it on the provided ip and port, and offering the media files found in the provided folder /// </summary> /// <param name="ip">The IP to host from</param> /// <param name="port">The port to host on</param> /// <param name="pathToMediaFiles">The location of the folder containing the media files</param> /// <param name="pathToDownloadFiles">The location of the folder containing the download files</param> /// <param name="pathToSubtitleFiles">The location of the folder containing the subtitle files</param> /// <param name="cancel">The cancellation token that halts the server</param> public HttpServer(string ip, ushort port, string pathToMediaFiles, string pathToDownloadFiles, string pathToSubtitleFiles, CancellationToken cancel) { Ip = ip; Port = port; MediaFilesPath = pathToMediaFiles; DownloadFilesPath = pathToDownloadFiles; SubtitleFilesPath = pathToSubtitleFiles; CancelToken = cancel; //Check if we have an image if (File.Exists("server-image.png")) { HasImage = true; ConLog.Log("WebMedia Link", "server-image.png found. Using that as the server's image", LogType.Ok); } else { ConLog.Log("WebMedia Link", "server-image.png not found. This server will not have an image in the server list", LogType.Warning); } }
/// <summary> /// Called when a media server disconnects. Removes the connection from the appropriate dictionaries /// </summary> /// <param name="connection">The connection that disconnected</param> /// <param name="type">The type of connection. Should be TCP</param> /// <param name="reason">The reason for disconnecting</param> /// <returns>A Task representing the operation</returns> private static async Task WebMediaDisconnected(Connection connection, Network.Enums.ConnectionType type, Network.Enums.CloseReason reason) { //Check that it's TCP if (type != Network.Enums.ConnectionType.TCP) { return; } //Check that it exists if (ConnectionToUuid.ContainsKey((TcpConnection)connection)) { //Get the UUID MediaServer deadServer = UuidToMediaServer[ConnectionToUuid[(TcpConnection)connection]]; ConLog.Log("WebMedia Link", "Media server with name " + deadServer.Name + " and address " + connection.IPRemoteEndPoint.ToString() + " disconnected", LogType.Info); //Remove the packet handlers connection.UnRegisterRawDataHandler("AvailableFilesUpdated"); //Close it await deadServer.Close(false); //Remove from dictionaries UuidToMediaServer.Remove(deadServer.UUID); ConnectionToUuid.Remove((TcpConnection)connection); //Update SignalR await UpdateAllSignalRClients(); ConLog.Log("WebMedia Link", "Removed media server with name " + deadServer.Name, LogType.Ok); } else { ConLog.Log("WebMedia Link", "Media server with address " + connection.IPRemoteEndPoint.ToString() + " disconnected", LogType.Info); } }
/// <summary> /// Sends a file over a context /// </summary> /// <param name="context">The HTTP context to send it over</param> /// <param name="filePath">The file to send</param> /// <returns>A Task representing the process</returns> private async Task SendFile(HttpListenerContext context, string filePath) { HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; Stream fileStream = null; byte[] buffer = new byte[BUFFER_SIZE]; long bytesLeft; try { fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); bytesLeft = fileStream.Length; response.AddHeader("Accept-Ranges", "bytes"); response.AddHeader("Access-Control-Allow-Origin", "*"); //Check for a provided range if (!string.IsNullOrEmpty(request.Headers["Range"])) { string[] range = request.Headers["Range"].Split(new char[] { '=', '-' }); long startPos; long endPos; //Validate if (range[1] == "") { startPos = 0; } else { startPos = Convert.ToInt32(range[1]); } if (range[2] == "") { endPos = bytesLeft - 1; } else { endPos = Convert.ToInt32(range[2]); } response.StatusCode = 206; //Add header response.AddHeader("Content-Range", "bytes " + startPos + "-" + endPos + "/" + bytesLeft); //Move the start position fileStream.Seek(startPos, SeekOrigin.Begin); //Change the bytes left bytesLeft = (endPos + 1) - startPos; } //Send the data while (bytesLeft > 0) { //Read the data into the buffer int bytesRead = await fileStream.ReadAsync(buffer, 0, BUFFER_SIZE); if (CancelToken.IsCancellationRequested) { return; } //Write the data to the response output stream await response.OutputStream.WriteAsync(buffer, 0, bytesRead); if (CancelToken.IsCancellationRequested) { return; } //Reduce the bytes left, and clear the buffer buffer = new byte[BUFFER_SIZE]; bytesLeft -= bytesRead; //Flush the stream to send it await response.OutputStream.FlushAsync(); if (CancelToken.IsCancellationRequested) { return; } } } catch (Exception e) { response.StatusCode = 500; if (e.Message != "The specified network name is no longer available.") { ConLog.Log("HTTP Server", "500 internal error: " + e.Message, LogType.Error); } } //Close the file streamd if it's not null if (fileStream != null) { fileStream.Close(); } //Send the response off response.Close(); }
/// <summary> /// Serve a particular context /// </summary> /// <param name="context">The context to server</param> /// <returns>A Task representing the operation</returns> private async Task HandleContext(HttpListenerContext context) { HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; string filePath; string fileName; string[] arrayToSearchIn; //Check whether it's media or download or subtitle or server image if (request.Url.LocalPath.StartsWith("/media/")) { fileName = request.Url.LocalPath.Substring(7); filePath = Path.Combine(MediaFilesPath, fileName); arrayToSearchIn = AvailableMediaFiles; } else if (request.Url.LocalPath.StartsWith("/download/")) { fileName = request.Url.LocalPath.Substring(10); filePath = Path.Combine(DownloadFilesPath, fileName); arrayToSearchIn = AvailableDownloadFiles; } else if (request.Url.LocalPath.StartsWith("/subtitle/")) { fileName = request.Url.LocalPath.Substring(10); filePath = Path.Combine(SubtitleFilesPath, fileName); arrayToSearchIn = AvailableSubtitleFiles; } else if (request.Url.LocalPath == "/server-image.png") { fileName = "server-image.png"; filePath = Path.GetFullPath("server-image.png"); arrayToSearchIn = new string[] { "server-image.png" }; } else { //File not found response.StatusCode = 404; ConLog.Log("HTTP Server", "404 not found", LogType.Warning); response.Close(); return; } //Check if the file doesn't exist if (!File.Exists(filePath)) { //File not found response.StatusCode = 404; ConLog.Log("HTTP Server", "404 not found", LogType.Warning); response.Close(); return; } //Check if the file exists, but we don't have access to it else if (!arrayToSearchIn.Contains(fileName)) { //File forbidden response.StatusCode = 403; ConLog.Log("HTTP Server", "403 forbidden", LogType.Warning); response.Close(); return; } //Alright, we're good to go await SendFile(context, filePath); }
/// <summary> /// Rescans the media file directory and updates the files available for download /// </summary> private bool RescanForFiles() { ConLog.Log("HTTP Server", "Rescanning media and download folders for available files", LogType.Info); bool hasAnythingChanged = false; string[] filesFound = Directory.GetFiles(MediaFilesPath, "*.*", SearchOption.TopDirectoryOnly); //Repopulate playable file array List <PlayableFile> newMediaFiles = new List <PlayableFile>(); //Add back in all the downloads that are still there foreach (PlayableFile file in Files) { if (file.Type == FileType.Downloaded) { if (File.Exists(DownloadFilesPath + "\\" + Path.GetFileName(file.VideoUrl)) || File.Exists(DownloadFilesPath + "\\" + Path.GetFileName(file.AudioUrl))) { newMediaFiles.Add(new PlayableFile(file.VideoUrl, file.AudioUrl, file.Title, file.Sha1, file.Subtitles, file.Duration, true, FileType.Downloaded)); if (!file.IsAvailable) { hasAnythingChanged = true; file.IsAvailable = true; } } else if (!file.IsAvailable) { newMediaFiles.Add(file); } else { hasAnythingChanged = true; ConLog.Log("HTTP Server", "Download titled " + file.Title + " was removed because the file was deleted", LogType.Warning); } } } //Add the media foreach (string file in filesFound) { //Check if it's audio or video MediaInfoWrapper wrapper = new MediaInfoWrapper(file); //Check that we have media if (wrapper.AudioStreams.Count == 0 && wrapper.VideoStreams.Count == 0) { continue; } string fileName = Path.GetFileName(file); //We have media. Check if it's audio or video if (wrapper.HasVideo) { newMediaFiles.Add(new PlayableFile("http://" + MediaserverIp + ":" + MediaserverPort + "/media/" + fileName, "", fileName, null, new SubtitleInfo[0], wrapper.Duration / 1000.0, true, FileType.Offline)); } else { newMediaFiles.Add(new PlayableFile("", "http://" + MediaserverIp + ":" + MediaserverPort + "/media/" + fileName, fileName, null, new SubtitleInfo[0], wrapper.Duration / 1000.0, true, FileType.Offline)); } } //Check if this differs from the old one foreach (PlayableFile file in newMediaFiles) { PlayableFile matchFound = null; foreach (PlayableFile possibleMatch in Files) { if (file.VideoUrl == possibleMatch.VideoUrl && file.AudioUrl == possibleMatch.AudioUrl && file.Title == possibleMatch.Title && file.Duration == possibleMatch.Duration && file.IsAvailable == possibleMatch.IsAvailable) { matchFound = possibleMatch; } } //If we didn't find a match, something has changed if (matchFound == null) { hasAnythingChanged = true; //If it's not a download, generate a sha1 hash if (file.Type == FileType.Offline) { //Get the file path string fileName; if (!string.IsNullOrEmpty(file.VideoUrl)) { fileName = Path.GetFileName(file.VideoUrl); } else { fileName = Path.GetFileName(file.AudioUrl); } string filePath = MediaFilesPath + "/" + fileName; file.Sha1 = GenerateSha1OfFile(filePath); } } //If we did find a match, copy the sha1 hash else { file.Sha1 = matchFound.Sha1; } } if (newMediaFiles.Count != Files.Count) { hasAnythingChanged = true; } Files = newMediaFiles; //Set the HTTP server's arrays SetHttpServerFiles(); if (hasAnythingChanged) { ConLog.Log("HTTP Server", "Scan complete and the available files has changed. Extracting subtitles and fonts from all media files", LogType.Ok); ExtractAllSubtitlesAndFontsForAllMediaFiles(); ConLog.Log("HTTP Server", "Subtitles and fonts extracted", LogType.Ok); } else { ConLog.Log("HTTP Server", "Scan complete and the available files has not changed", LogType.Ok); } return(hasAnythingChanged); }
private async Task Disconnected(Network.Enums.CloseReason reason, Connection connection) { //Stop program CancelTokenSource.Cancel(); ConLog.Log("WebMedia Link", "Disconnected from WebMediaLink server", LogType.Fatal); }