using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json.Linq; using System.Reflection; using System.Security.Cryptography; using Newtonsoft.Json; using System.IO; using System.Threading; namespace JellyfinRPC { class JellyfinAPI { public static async Task Jellyfin() { while (true) { try { var playingInfo = await GetCurrentlyPlaying(); if (playingInfo != null) { JToken nowPlaying = playingInfo.NowPlayingItem; string largeImageKey = playingInfo.IsMusic ? GetAlbumCover(nowPlaying) : await GetJellyfinLogo(); string largeImageText = playingInfo.IsMusic ? nowPlaying["Album"]?.ToString() ?? "Unknown Album" : "Jellyfin"; string details = playingInfo.IsMusic ? $"{playingInfo.Title}" : nowPlaying["SeriesName"] != null ? $"Watching {nowPlaying["SeriesName"]} - {playingInfo.Title}" : $"Watching {playingInfo.Title}"; string state = playingInfo.IsMusic ? $"{playingInfo.Artist}" : nowPlaying["SeriesName"] != null ? $"Season {playingInfo.Season}, Episode {playingInfo.Episode}" : ""; DateTime duration = playingInfo.Duration; DateTime progress = playingInfo.Progress; return $"{largeImageKey}|{largeImageText}|{details}|{state}|{duration}|{progress}"; } } catch (Exception ex) { ConsoleManager.WriteToConsole($"Error fetching Jellyfin data: {ex.Message}"); } } } public static string AssemblyVersion { get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } private static async Task GetJellyfinLogo() { using var httpClient = new HttpClient(); try { if (ConfigManager.GetEntry("JellyfinToken") == "") { var response = await httpClient.GetAsync($"{ConfigManager.GetEntry("ServerURL")}/System/Info?api_key={ConfigManager.GetEntry("APIKey")}"); response.EnsureSuccessStatusCode(); var jsonResponse = await response.Content.ReadAsStringAsync(); var json = JArray.Parse(jsonResponse); var logoUrl = json["LogoUrl"]?.ToString(); return logoUrl ?? "jellyfin_logo"; } else { return "jellyfin_logo"; } } catch (Exception ex) { ConsoleManager.WriteToConsole($"Error fetching Jellyfin logo: {ex.Message}"); return "jellyfin_logo"; } } private static async Task GetCurrentlyPlaying() { using var httpClient = new HttpClient(); try { if (ConfigManager.GetEntry("JellyfinToken") == "") { var response = await httpClient.GetAsync($"{ConfigManager.GetEntry("ServerURL")}/Sessions?api_key={ConfigManager.GetEntry("APIKey")}"); response.EnsureSuccessStatusCode(); var jsonResponse = await response.Content.ReadAsStringAsync(); var sessions = JArray.Parse(jsonResponse); foreach (var session in sessions) { if (session["UserId"]?.ToString() == ConfigManager.GetEntry("UserID") && session["NowPlayingItem"] != null) { var nowPlaying = session["NowPlayingItem"]; var mediaType = nowPlaying["Type"]?.ToString(); bool isMusic = mediaType?.ToLower() == "audio"; string albumCover = ""; string artist = "Unknown Artist"; if (isMusic) { albumCover = GetAlbumCover(nowPlaying); var artists = nowPlaying["Artists"]?.ToObject(); if (artists != null && artists.Count > 0) { artist = artists[0].ToString(); } else { artist = "Unknown Artist"; } } return new PlayingInfo { Title = nowPlaying["Name"]?.ToString(), Artist = artist, AlbumCover = albumCover, Season = nowPlaying["ParentIndexNumber"]?.ToString() ?? "N/A", Episode = nowPlaying["IndexNumber"]?.ToString() ?? "N/A", Progress = new DateTime((long)session["PlayState"]["PositionTicks"]), //Progress = TimeSpan.FromTicks((long)session["PlayState"]["PositionTicks"]), Duration = new DateTime((long)nowPlaying["RunTimeTicks"]), //Duration = TimeSpan.FromTicks((long)nowPlaying["RunTimeTicks"]), IsMusic = isMusic, NowPlayingItem = nowPlaying }; } } } } catch (Exception ex) { ConsoleManager.WriteToConsole($"Error fetching Jellyfin data: {ex.Message}"); } return null; } private static string GetAlbumCover(JToken nowPlaying) { var mediaStreams = nowPlaying["MediaStreams"]?.ToObject(); if (mediaStreams != null) { foreach (var stream in mediaStreams) { var imageTag = stream["ImageTag"]?.ToString(); if (!string.IsNullOrEmpty(imageTag)) { return imageTag; } } } return "album_cover"; } public static string quickConnectToken; static bool authSuccess; public static bool formClosed; public static async Task AuthWithQuickConnect() { using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Authorization", $"MediaBrowser Client=\"JellyfinRPC {AssemblyVersion}, \", Device=\"{System.Net.Dns.GetHostName()}\", DeviceId=\"{ConfigManager.GetEntry("DeviceID")}\", Version=\"running on {Environment.OSVersion}\""); if (ConfigManager.GetEntry("ServerURL") != "") { var quickConnectInitResponse = await httpClient.GetAsync($"{ConfigManager.GetEntry("ServerURL")}/QuickConnect/Initiate"); authSuccess = false; if (quickConnectInitResponse.StatusCode is (System.Net.HttpStatusCode)401) { System.Windows.Forms.MessageBox.Show("This server does not have Quick Connect enabled.", "Quick Connect Unavailable.", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error, System.Windows.Forms.MessageBoxDefaultButton.Button1); } else { try { quickConnectInitResponse.EnsureSuccessStatusCode(); var jsonResponse = await quickConnectInitResponse.Content.ReadAsStringAsync(); var jsonObject = JObject.Parse(jsonResponse); if (!jsonObject.HasValues) { } else { string quickConnectCode = jsonObject.Value("Code"); if (jsonObject.Value("Secret") != null && jsonObject.Value("Secret") != "") { quickConnectToken = jsonObject.Value("Secret"); } else { quickConnectToken = null; } (System.Windows.Forms.Application.OpenForms["ConfigForm"] as ConfigForm).label9.Text = quickConnectCode; while (authSuccess == false) { var getThings = await CheckQuickConnectStatus(); if (formClosed == true) { break; } else if (getThings == null) { await CheckQuickConnectStatus(); } else if (getThings == "this isn't gonna work") { System.Windows.Forms.MessageBox.Show("Quick Connect doesn't seem to be working. Check your Internet connection and try again later.", "Quick Connect Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error); break; } else { authSuccess = true; } } } } catch (Exception ex) { #if DEBUG System.Windows.Forms.MessageBox.Show(ex.ToString()); #endif } } } else { System.Windows.Forms.MessageBox.Show("No Server URL is set.", "Quick Connect Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Exclamation); } } public static string DeviceID() { using RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); byte[] randomNumber = new byte[4]; rng.GetBytes(randomNumber); int value = BitConverter.ToInt32(randomNumber, 0); byte[] valueBytes = System.Text.Encoding.UTF8.GetBytes(value.ToString()); return System.Convert.ToBase64String(valueBytes); } public static async Task GetTokenFromUsernameAndPassword(string Username, string Password) { using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Authorization", $"MediaBrowser Client=\"JellyfinRPC {AssemblyVersion}, \", Device=\"{System.Net.Dns.GetHostName()}\", DeviceId=\"{ConfigManager.GetEntry("DeviceID")}\", Version=\"running on {Environment.OSVersion}\""); if (ConfigManager.GetEntry("ServerURL") != "") { string username = Username; string password = Password; var loginRequest = new Login() { username = username, pw = password }; var loginJson = JsonConvert.SerializeObject(loginRequest); HttpResponseMessage loginWithUsernameandPassResponse = await httpClient.PostAsync($"{ConfigManager.GetEntry("ServerURL")}/Users/AuthenticateByName", new StringContent(loginJson, Encoding.UTF8, "application/json")); if (loginWithUsernameandPassResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized) { System.Windows.Forms.MessageBox.Show("The Username or Password is incorrect.", "Authentication Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error, System.Windows.Forms.MessageBoxDefaultButton.Button1); } else { loginWithUsernameandPassResponse.EnsureSuccessStatusCode(); var jsonResponse = await loginWithUsernameandPassResponse.Content.ReadAsStringAsync(); var jsonShit = JObject.Parse(jsonResponse); string thatToken = jsonShit.Value("AccessToken"); if (thatToken != null && thatToken != " ") { ConfigManager.SetEntry("JellyfinToken", thatToken); } } } } public static async Task CheckQuickConnectStatus() { using var httpClient = new HttpClient(); if (quickConnectToken != null && quickConnectToken != "") { TaskEx.Delay(1000); string secret = quickConnectToken.Replace('"', ' ').Trim(); HttpResponseMessage QuickConnectStatusResponse = await httpClient.GetAsync($"{ConfigManager.GetEntry("ServerURL")}/QuickConnect/Connect?Secret={quickConnectToken}"); QuickConnectStatusResponse.EnsureSuccessStatusCode(); var responseAsString = await QuickConnectStatusResponse.Content.ReadAsStringAsync(); var responseJson = JObject.Parse(responseAsString); if (responseJson.ContainsKey("AccessToken")) { return responseJson.Value("AccessToken"); } else { return null; } } else { return "this isn't gonna work"; } } } public class Login { #pragma warning disable IDE1006 // Naming Styles public string username { get; set; } public string pw { get; set; } #pragma warning restore IDE1006 // Naming Styles } }