Added stuff

- Attempted to fix the status for when screensharing
- Added the application icon
This commit is contained in:
Diamond Creeper 2024-11-30 21:56:13 +13:00
parent 9330106c24
commit 3a164c5599
38 changed files with 260 additions and 222 deletions

View file

@ -11,6 +11,7 @@ class Program
private const string ConfigFilePath = "config.json";
private static DiscordRpcClient _discordClient;
private static Config _config;
private static bool isScreenSharing = false; // Track screen sharing status
// Hard-code the Discord Client ID here
private const string DiscordClientId = "1312264302601834578"; // Replace with your actual Discord client ID
@ -29,6 +30,62 @@ class Program
_discordClient.Initialize();
// Poll Jellyfin API for currently playing media
var updateTask = UpdateRichPresence(); // Start the rich presence update task
// Command loop for toggling screen sharing
while (true)
{
var command = Console.ReadLine()?.ToLower();
if (command == "toggle")
{
ToggleScreenSharing();
}
else if (command == "exit")
{
break; // Exit the loop and end the program
}
else
{
Console.WriteLine("Invalid command. Type 'toggle' to toggle screen sharing or 'exit' to quit.");
}
}
await updateTask; // Wait for the rich presence update task to finish
}
private static void ToggleScreenSharing()
{
isScreenSharing = !isScreenSharing; // Toggle the screen sharing state
Console.WriteLine(isScreenSharing ? "Screen sharing enabled." : "Screen sharing disabled.");
UpdateDiscordPresence(); // Manually update Discord presence when toggling screen sharing
}
private static void UpdateDiscordPresence()
{
// Log the current status of screen sharing
Console.WriteLine($"Updating Discord Presence. Screen Sharing: {isScreenSharing}");
// Ensure we immediately update the Discord presence when toggling screen sharing
_discordClient.SetPresence(new RichPresence
{
Details = isScreenSharing ? "Sharing screen" : "Watching media",
State = isScreenSharing ? "Screen sharing is active" : "Not sharing screen",
Timestamps = new Timestamps
{
Start = DateTime.UtcNow
},
Assets = new Assets
{
LargeImageKey = isScreenSharing ? "screen_sharing" : "media_playing",
LargeImageText = isScreenSharing ? "Screen sharing on Discord" : "Watching media on Jellyfin"
}
});
Console.WriteLine("Presence updated successfully.");
}
private static async Task UpdateRichPresence()
{
while (true)
{
try
@ -36,48 +93,53 @@ class Program
var playingInfo = await GetCurrentlyPlaying().ConfigureAwait(false);
if (playingInfo != null)
{
// Get the raw JToken from nowPlaying (instead of passing PlayingInfo)
JToken nowPlaying = playingInfo.NowPlayingItem;
// Check if album art exists and pre-fetch it
string largeImageKey = playingInfo.IsMusic
? await GetAlbumCover(nowPlaying).ConfigureAwait(false) // Pass the JToken nowPlaying here
? await GetAlbumCover(nowPlaying).ConfigureAwait(false)
: await GetJellyfinLogo().ConfigureAwait(false);
string largeImageText = playingInfo.IsMusic
? nowPlaying["Album"]?.ToString() ?? "Unknown Album" // Extract album name or fallback to "Unknown Album"
? nowPlaying["Album"]?.ToString() ?? "Unknown Album"
: "Jellyfin Media Player";
// Update Discord Rich Presence for music or video
string details = playingInfo.IsMusic
? $"{playingInfo.Title}" // Show song name
: $"Watching: {playingInfo.Title}"; // Show video title
string state = isScreenSharing ? "Sharing screen" : playingInfo.IsMusic
? $"{playingInfo.Artist}" // Show artist name
: $"Season {playingInfo.Season}, Episode {playingInfo.Episode}";
Console.WriteLine($"Updating presence with details: {details}, state: {state}");
_discordClient.SetPresence(new RichPresence
{
Details = playingInfo.IsMusic
? $"{playingInfo.Title}" // Show song name
: $"Watching: {playingInfo.Title}", // Show video title
State = playingInfo.IsMusic
? $"{playingInfo.Artist}" // Show artist only (no album name)
: $"Season {playingInfo.Season}, Episode {playingInfo.Episode}",
Details = details,
State = state, // Dynamic state based on screen sharing or media
Timestamps = new Timestamps
{
Start = DateTime.UtcNow - playingInfo.Progress, // Start time based on current progress
End = DateTime.UtcNow + (playingInfo.Duration - playingInfo.Progress) // End time based on total duration
Start = DateTime.UtcNow - playingInfo.Progress,
End = DateTime.UtcNow + (playingInfo.Duration - playingInfo.Progress)
},
Assets = new Assets
{
LargeImageKey = largeImageKey, // Dynamically set image based on media type
LargeImageText = largeImageText // Use album name or fallback text
LargeImageKey = largeImageKey,
LargeImageText = largeImageText
}
});
}
else
{
_discordClient.ClearPresence();
Console.WriteLine("No media playing, clearing presence.");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine($"Error fetching Jellyfin data: {ex.Message}");
}
// Wait for a few seconds before polling again
// Wait before polling again
await Task.Delay(5000).ConfigureAwait(false);
}
}
@ -93,16 +155,13 @@ class Program
var jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var json = JObject.Parse(jsonResponse);
// Attempt to get the logo URL
var logoUrl = json["LogoUrl"]?.ToString();
// Fallback to a default logo if no logo URL is found
return logoUrl ?? "jellyfin_logo";
}
catch (Exception ex)
{
Console.WriteLine($"Error fetching Jellyfin logo: {ex.Message}");
return "jellyfin_logo"; // Default fallback in case of error
return "jellyfin_logo"; // Default fallback
}
}
@ -110,39 +169,21 @@ class Program
{
if (File.Exists(ConfigFilePath))
{
// Load configuration from file
var configJson = File.ReadAllText(ConfigFilePath);
_config = JsonSerializer.Deserialize<Config>(configJson);
}
else
{
// Prompt user for configuration on first startup (without Discord Client ID)
_config = new Config();
Console.Write("Enter Jellyfin Server URL: ");
_config.JellyfinBaseUrl = Console.ReadLine();
Console.Write("Enter Jellyfin API Key: ");
_config.JellyfinApiKey = Console.ReadLine();
Console.Write("Enter Jellyfin User ID: ");
_config.JellyfinUserId = Console.ReadLine();
do
{
Console.Write("Enter Jellyfin Server URL (e.g., http://your-jellyfin-server:8096): ");
_config.JellyfinBaseUrl = Console.ReadLine();
} while (string.IsNullOrWhiteSpace(_config.JellyfinBaseUrl));
do
{
Console.Write("Enter Jellyfin API Key: ");
_config.JellyfinApiKey = Console.ReadLine();
} while (string.IsNullOrWhiteSpace(_config.JellyfinApiKey));
Console.WriteLine("Go to the following URL and find your Jellyfin User ID:");
Console.WriteLine(" http://<your-jellyfin-server>:PORTNUMBER/Users?api_key=<your-api-key>");
do
{
Console.Write("Enter Jellyfin User ID: ");
_config.JellyfinUserId = Console.ReadLine();
} while (string.IsNullOrWhiteSpace(_config.JellyfinUserId));
// Save configuration to file (without Discord Client ID)
var configJson = JsonSerializer.Serialize(_config, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(ConfigFilePath, configJson);
Console.WriteLine("Configuration saved to config.json.");
}
}
@ -160,35 +201,29 @@ class Program
foreach (var session in sessions)
{
if (session["UserId"]?.ToString() == _config.JellyfinUserId &&
session["NowPlayingItem"] != null)
if (session["UserId"]?.ToString() == _config.JellyfinUserId && session["NowPlayingItem"] != null)
{
var nowPlaying = session["NowPlayingItem"]; // This is the raw JToken we need
// Extract media type
var nowPlaying = session["NowPlayingItem"];
var mediaType = nowPlaying["Type"]?.ToString();
bool isMusic = mediaType?.ToLower() == "audio";
string albumCover = ""; // Default value for album cover
string artist = "Unknown Artist"; // Default value for artist
string albumCover = "";
string artist = "Unknown Artist";
// If it's music, extract the album art and artist name
if (isMusic)
{
albumCover = await GetAlbumCover(nowPlaying).ConfigureAwait(false); // Pass JToken (not PlayingInfo)
albumCover = await GetAlbumCover(nowPlaying).ConfigureAwait(false);
var artists = nowPlaying["Artists"]?.ToObject<JArray>();
if (artists != null && artists.Count > 0)
{
artist = artists[0].ToString(); // Get the first artist from the array
artist = artists[0].ToString();
}
}
else
{
// If it's video, set artist to Unknown Artist
artist = "Unknown Artist";
}
// Return the extracted data wrapped in the PlayingInfo object
return new PlayingInfo
{
Title = nowPlaying["Name"]?.ToString(),
@ -199,7 +234,7 @@ class Program
Progress = TimeSpan.FromTicks((long)session["PlayState"]["PositionTicks"]),
Duration = TimeSpan.FromTicks((long)nowPlaying["RunTimeTicks"]),
IsMusic = isMusic,
NowPlayingItem = nowPlaying // Add the raw NowPlayingItem JToken here
NowPlayingItem = nowPlaying
};
}
}
@ -214,44 +249,23 @@ class Program
private static async Task<string> GetAlbumCover(JToken nowPlaying)
{
// Try to get the album cover from the "MediaStreams" (audio specific)
var mediaStreams = nowPlaying["MediaStreams"]?.ToObject<JArray>();
if (mediaStreams != null)
{
// Look for the stream that indicates an image (usually "mjpeg" codec)
foreach (var stream in mediaStreams)
{
if (stream["Codec"]?.ToString() == "mjpeg" && stream["Type"]?.ToString() == "EmbeddedImage")
var imageTag = stream["ImageTag"]?.ToString();
if (!string.IsNullOrEmpty(imageTag))
{
// Check for the image tag and try to form the image URL
string imageTag = nowPlaying["ParentLogoImageTag"]?.ToString();
if (!string.IsNullOrWhiteSpace(imageTag))
{
string itemId = nowPlaying["Id"]?.ToString();
if (!string.IsNullOrWhiteSpace(itemId))
{
// Construct the URL for the album cover
return $"{_config.JellyfinBaseUrl}/emby/Items/{itemId}/Images/Primary?tag={imageTag}&api_key={_config.JellyfinApiKey}";
}
}
return imageTag; // Return the album cover image tag
}
}
}
// Fallback: Check if there is an explicit album cover URL in the item
string albumArtUrl = nowPlaying["ImageTags"]?["Primary"]?.ToString();
if (!string.IsNullOrWhiteSpace(albumArtUrl))
{
return $"{_config.JellyfinBaseUrl}/emby/Items/{nowPlaying["Id"]}/Images/Primary?tag={albumArtUrl}&api_key={_config.JellyfinApiKey}";
}
// Fallback to a default cover if no album art is found
return "default_cover";
return "album_cover";
}
}
class Config
class Config
{
public string JellyfinBaseUrl { get; set; }
public string JellyfinApiKey { get; set; }