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; 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 async Task SendQuickConnectRequest() { using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Authorization", $"MediaBrowser Client=\"JellyfinRPC\", Device=\"Windows, Probably\", DeviceId=\"{ConfigManager.GetEntry("JellyfinDeviceID")}\", Version=\"{AssemblyVersion}\""); if (ConfigManager.GetEntry("ServerURL") != "") { var response = await httpClient.PostAsync($"{ConfigManager.GetEntry("ServerURL")}/QuickConnect/Initiate", null); if (response.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); return "Error: Server does not have Quick Connect Enabled."; } else { try { response.EnsureSuccessStatusCode(); var jsonResponse = await response.Content.ReadAsStringAsync(); var contents = JArray.Parse(jsonResponse); if (!contents.Any()) { return "Error: Server did not respond."; } foreach (var content in contents) { if (content["Code"]?.ToString() != "") { return content["Code"]?.ToString(); } else { return "Error: Server did not return code."; } } return "Error: All values returned are null."; } catch (Exception ex) { return $"{ex.Message.Trim()}"; } } } else { return "Error: No Server URL Set."; } } 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); } } } }