Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
|
72d8131747 | ||
|
6621e56127 | ||
3752368156 | |||
b1cbe1988d | |||
52ab4c6398 | |||
63a94836e6 | |||
|
a673d042e7 | ||
|
1ef38ec268 | ||
|
39fa1db557 | ||
0775ab2a43 | |||
3a164c5599 |
41 changed files with 257 additions and 230 deletions
4
.editorconfig
Normal file
4
.editorconfig
Normal file
|
@ -0,0 +1,4 @@
|
|||
[*.cs]
|
||||
|
||||
# Default severity for all analyzer diagnostics
|
||||
dotnet_analyzer_diagnostic.severity = silent
|
BIN
.vs/JellyfinDiscordRPC/DesignTimeBuild/.dtbcache.v2
Normal file
BIN
.vs/JellyfinDiscordRPC/DesignTimeBuild/.dtbcache.v2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.vs/JellyfinDiscordRPC/v17/.futdcache.v2
Normal file
BIN
.vs/JellyfinDiscordRPC/v17/.futdcache.v2
Normal file
Binary file not shown.
37
.vs/JellyfinDiscordRPC/v17/DocumentLayout.backup.json
Normal file
37
.vs/JellyfinDiscordRPC/v17/DocumentLayout.backup.json
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}|JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj|c:\\users\\joshua\\documents\\github\\jellyfin-discord-rpc\\jellyfindiscordrpc\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}|JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj|solutionrelative:jellyfindiscordrpc\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": 0,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\Program.cs",
|
||||
"RelativeDocumentMoniker": "JellyfinDiscordRPC\\Program.cs",
|
||||
"ToolTip": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\Program.cs",
|
||||
"RelativeToolTip": "JellyfinDiscordRPC\\Program.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAgAAAANAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2024-11-30T05:30:39.706Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
37
.vs/JellyfinDiscordRPC/v17/DocumentLayout.json
Normal file
37
.vs/JellyfinDiscordRPC/v17/DocumentLayout.json
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}|JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj|c:\\users\\joshua\\documents\\github\\jellyfin-discord-rpc\\jellyfindiscordrpc\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}|JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj|solutionrelative:jellyfindiscordrpc\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": 0,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\Program.cs",
|
||||
"RelativeDocumentMoniker": "JellyfinDiscordRPC\\Program.cs",
|
||||
"ToolTip": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\Program.cs",
|
||||
"RelativeToolTip": "JellyfinDiscordRPC\\Program.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAgAAAANAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2024-11-30T05:30:39.706Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
BIN
.vs/ProjectEvaluation/jellyfindiscordrpc.metadata.v9.bin
Normal file
BIN
.vs/ProjectEvaluation/jellyfindiscordrpc.metadata.v9.bin
Normal file
Binary file not shown.
BIN
.vs/ProjectEvaluation/jellyfindiscordrpc.projects.v9.bin
Normal file
BIN
.vs/ProjectEvaluation/jellyfindiscordrpc.projects.v9.bin
Normal file
Binary file not shown.
BIN
.vs/ProjectEvaluation/jellyfindiscordrpc.strings.v9.bin
Normal file
BIN
.vs/ProjectEvaluation/jellyfindiscordrpc.strings.v9.bin
Normal file
Binary file not shown.
|
@ -1,20 +1,37 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.12.35514.174 d17.12
|
||||
VisualStudioVersion = 17.12.35514.174
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JellyfinDiscordRPC", "JellyfinDiscordRPC\JellyfinDiscordRPC.csproj", "{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B615520C-ED8E-4BBE-A88B-96812A61C61F}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Debug|x64.Build.0 = Debug|x64
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Debug|x86.Build.0 = Debug|x86
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Release|x64.ActiveCfg = Release|x64
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Release|x64.Build.0 = Release|x64
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Release|x86.ActiveCfg = Release|x64
|
||||
{06FF6B5D-B070-4DB7-9A87-9B6E280A794D}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -5,10 +5,19 @@
|
|||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x64;x86</Platforms>
|
||||
<PackageIcon>jellyfin.png</PackageIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="assets\jellyfin.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -12,23 +12,55 @@ class Program
|
|||
private static DiscordRpcClient _discordClient;
|
||||
private static Config _config;
|
||||
|
||||
// Hard-code the Discord Client ID here
|
||||
private const string DiscordClientId = "1312264302601834578"; // Replace with your actual Discord client ID
|
||||
// Hard-coded the Discord Client ID
|
||||
private const string DiscordClientId = "1312264302601834578";
|
||||
|
||||
static bool presenceUpdated = false; // Flag to track initial rich presence update
|
||||
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Starting Jellyfin Discord Rich Presence...");
|
||||
// Load or create configuration first
|
||||
LoadOrCreateConfig(); // Initialize _config first
|
||||
|
||||
// Load or create configuration
|
||||
LoadOrCreateConfig();
|
||||
// Now we can safely access _config for the console title
|
||||
Console.WriteLine("Starting Jellyfin Discord Rich Presence...");
|
||||
Console.Title = $"Jellyfin Discord RPC - {_config.JellyfinBaseUrl}";
|
||||
|
||||
// Initialize Discord Rich Presence
|
||||
_discordClient = new DiscordRpcClient(DiscordClientId);
|
||||
_discordClient.OnReady += (sender, e) => Console.WriteLine("Connected to Discord RPC!");
|
||||
_discordClient.OnPresenceUpdate += (sender, e) => Console.WriteLine("Rich Presence updated!");
|
||||
_discordClient.OnReady += (sender, e) =>
|
||||
{
|
||||
Console.WriteLine("Connected to Discord RPC!");
|
||||
|
||||
// Log message when connection to Discord is established
|
||||
if (!presenceUpdated)
|
||||
{
|
||||
Console.WriteLine("Rich Presence updated!"); // This will only show once
|
||||
presenceUpdated = true; // Set the flag to true to avoid logging it again
|
||||
}
|
||||
};
|
||||
|
||||
// Handle presence updates only once at the start
|
||||
_discordClient.OnPresenceUpdate += (sender, e) =>
|
||||
{
|
||||
if (!presenceUpdated)
|
||||
{
|
||||
Console.WriteLine("Rich Presence updated!");
|
||||
presenceUpdated = true; // Set the flag to true so it doesn't display again
|
||||
}
|
||||
};
|
||||
|
||||
_discordClient.Initialize();
|
||||
|
||||
// Poll Jellyfin API for currently playing media
|
||||
var updateTask = UpdateRichPresence(); // Start the rich presence update task
|
||||
|
||||
await updateTask; // Wait for the rich presence update task to finish
|
||||
}
|
||||
|
||||
|
||||
private static async Task UpdateRichPresence()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
|
@ -36,48 +68,57 @@ 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
|
||||
: nowPlaying["SeriesName"] != null
|
||||
? $"Watching: {nowPlaying["SeriesName"]} - {playingInfo.Title}" // Show series and episode name
|
||||
: $"Watching: {playingInfo.Title}"; // For movies, show only the title
|
||||
|
||||
string state = playingInfo.IsMusic
|
||||
? $"{playingInfo.Artist}" // Show artist name
|
||||
: nowPlaying["SeriesName"] != null
|
||||
? $"Season {playingInfo.Season}, Episode {playingInfo.Episode}" // Show season and episode for series
|
||||
: ""; // Leave state empty for movies
|
||||
|
||||
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 = string.IsNullOrWhiteSpace(state) ? null : state, // Avoid sending empty state to Discord
|
||||
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 +134,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,40 +148,22 @@ 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.");
|
||||
Console.WriteLine("Configuration saved to config.json.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,35 +180,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 +213,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 +228,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; }
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
<PublishDir>bin\Release\net9.0\publish\win-x64\</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>false</SelfContained>
|
||||
<PublishSingleFile>false</PublishSingleFile>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
</PropertyGroup>
|
||||
</Project>
|
BIN
JellyfinDiscordRPC/assets/jellyfin.png
Normal file
BIN
JellyfinDiscordRPC/assets/jellyfin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
@ -1,106 +0,0 @@
|
|||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v9.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v9.0": {
|
||||
"JellyfinDiscordRPC/1.0.0": {
|
||||
"dependencies": {
|
||||
"DiscordRichPresence": "1.2.1.24"
|
||||
},
|
||||
"runtime": {
|
||||
"JellyfinDiscordRPC.dll": {}
|
||||
}
|
||||
},
|
||||
"DiscordRichPresence/1.2.1.24": {
|
||||
"dependencies": {
|
||||
"Microsoft.Win32.Registry": "4.5.0",
|
||||
"Newtonsoft.Json": "13.0.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/DiscordRPC.dll": {
|
||||
"assemblyVersion": "1.2.1.24",
|
||||
"fileVersion": "1.2.1.24"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/2.0.0": {},
|
||||
"Microsoft.Win32.Registry/4.5.0": {
|
||||
"dependencies": {
|
||||
"System.Security.AccessControl": "4.5.0",
|
||||
"System.Security.Principal.Windows": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||
"assemblyVersion": "13.0.0.0",
|
||||
"fileVersion": "13.0.1.25517"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Security.AccessControl/4.5.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0",
|
||||
"System.Security.Principal.Windows": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Security.Principal.Windows/4.5.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"JellyfinDiscordRPC/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"DiscordRichPresence/1.2.1.24": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-DVmmlFQ/oQmidNRmZhPzYjC7ryaT4beWcKaMKPVw6fhOzM/HOoY6NOL4KMOYEnD4M7SNsODjleYimvUNIZcbiA==",
|
||||
"path": "discordrichpresence/1.2.1.24",
|
||||
"hashPath": "discordrichpresence.1.2.1.24.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/2.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==",
|
||||
"path": "microsoft.netcore.platforms/2.0.0",
|
||||
"hashPath": "microsoft.netcore.platforms.2.0.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Win32.Registry/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-+FWlwd//+Tt56316p00hVePBCouXyEzT86Jb3+AuRotTND0IYn0OO3obs1gnQEs/txEnt+rF2JBGLItTG+Be6A==",
|
||||
"path": "microsoft.win32.registry/4.5.0",
|
||||
"hashPath": "microsoft.win32.registry.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||
"path": "newtonsoft.json/13.0.1",
|
||||
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Security.AccessControl/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==",
|
||||
"path": "system.security.accesscontrol/4.5.0",
|
||||
"hashPath": "system.security.accesscontrol.4.5.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Principal.Windows/4.5.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==",
|
||||
"path": "system.security.principal.windows/4.5.0",
|
||||
"hashPath": "system.security.principal.windows.4.5.0.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net9.0",
|
||||
"framework": {
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "9.0.0"
|
||||
},
|
||||
"configProperties": {
|
||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"JellyfinBaseUrl": "https://jellyfin.diamondcreeper.org",
|
||||
"JellyfinApiKey": "9b868f61663140d09406b50538c91b8a",
|
||||
"JellyfinUserId": "b4f8289c703c48f6aa827655ca209681"
|
||||
}
|
|
@ -14,7 +14,7 @@ using System.Reflection;
|
|||
[assembly: System.Reflection.AssemblyCompanyAttribute("JellyfinDiscordRPC")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9330106c24c49cbac14fbc441fd4dfeb17b5e6b7")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("JellyfinDiscordRPC")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("JellyfinDiscordRPC")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
|
|
@ -1 +1 @@
|
|||
2e189d0dffba66b81eb9b145504dcd231f91e1098305af08ba9c25f348b380fa
|
||||
2850d7fb1b219d71ca36ce27f283a88484554fa270adaed893963d07cc96c066
|
||||
|
|
|
@ -8,7 +8,7 @@ build_property.PlatformNeutralAssembly =
|
|||
build_property.EnforceExtendedAnalyzerRules =
|
||||
build_property._SupportedPlatformList = Linux,macOS,Windows
|
||||
build_property.RootNamespace = JellyfinDiscordRPC
|
||||
build_property.ProjectDir = C:\Users\joshua\source\repos\JellyfinDiscordRPC\JellyfinDiscordRPC\
|
||||
build_property.ProjectDir = C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\
|
||||
build_property.EnableComHosting =
|
||||
build_property.EnableGeneratedComInterfaceComImportInterop =
|
||||
build_property.EffectiveAnalysisLevelStyle = 9.0
|
||||
|
|
Binary file not shown.
|
@ -16,3 +16,21 @@ C:\Users\joshua\source\repos\JellyfinDiscordRPC\JellyfinDiscordRPC\obj\Debug\net
|
|||
C:\Users\joshua\source\repos\JellyfinDiscordRPC\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.pdb
|
||||
C:\Users\joshua\source\repos\JellyfinDiscordRPC\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.genruntimeconfig.cache
|
||||
C:\Users\joshua\source\repos\JellyfinDiscordRPC\JellyfinDiscordRPC\obj\Debug\net9.0\ref\JellyfinDiscordRPC.dll
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\bin\Debug\net9.0\JellyfinDiscordRPC.exe
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\bin\Debug\net9.0\JellyfinDiscordRPC.deps.json
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\bin\Debug\net9.0\JellyfinDiscordRPC.runtimeconfig.json
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\bin\Debug\net9.0\JellyfinDiscordRPC.dll
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\bin\Debug\net9.0\JellyfinDiscordRPC.pdb
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\bin\Debug\net9.0\DiscordRPC.dll
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\bin\Debug\net9.0\Newtonsoft.Json.dll
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.csproj.AssemblyReference.cache
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.GeneratedMSBuildEditorConfig.editorconfig
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.AssemblyInfoInputs.cache
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.AssemblyInfo.cs
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.csproj.CoreCompileInputs.cache
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\Jellyfin.FC5C5640.Up2Date
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.dll
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\refint\JellyfinDiscordRPC.dll
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.pdb
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\JellyfinDiscordRPC.genruntimeconfig.cache
|
||||
C:\Users\joshua\Documents\GitHub\jellyfin-discord-rpc\JellyfinDiscordRPC\obj\Debug\net9.0\ref\JellyfinDiscordRPC.dll
|
||||
|
|
Binary file not shown.
|
@ -1 +1 @@
|
|||
230f9294a7604eecab82305c77c4c9089de4c82cb2749e33c24c53a44ff224ba
|
||||
593d3e37ea484aac9177fb6433f49c519e46953c7db165fd924c9f5746fc869a
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"format": 1,
|
||||
"restore": {
|
||||
"C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj": {}
|
||||
"C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj": {}
|
||||
},
|
||||
"projects": {
|
||||
"C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj": {
|
||||
"C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"projectUniqueName": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"projectName": "JellyfinDiscordRPC",
|
||||
"projectPath": "C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"projectPath": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"packagesPath": "C:\\Users\\joshua\\.nuget\\packages\\",
|
||||
"outputPath": "C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\obj\\",
|
||||
"outputPath": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"fallbackFolders": [
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||
|
|
|
@ -313,11 +313,11 @@
|
|||
"project": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"projectUniqueName": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"projectName": "JellyfinDiscordRPC",
|
||||
"projectPath": "C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"projectPath": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"packagesPath": "C:\\Users\\joshua\\.nuget\\packages\\",
|
||||
"outputPath": "C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\obj\\",
|
||||
"outputPath": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"fallbackFolders": [
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"version": 2,
|
||||
"dgSpecHash": "1MP9+VdKfz0=",
|
||||
"dgSpecHash": "83oYIM0kfME=",
|
||||
"success": true,
|
||||
"projectFilePath": "C:\\Users\\joshua\\source\\repos\\JellyfinDiscordRPC\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"projectFilePath": "C:\\Users\\joshua\\Documents\\GitHub\\jellyfin-discord-rpc\\JellyfinDiscordRPC\\JellyfinDiscordRPC.csproj",
|
||||
"expectedPackageFiles": [
|
||||
"C:\\Users\\joshua\\.nuget\\packages\\discordrichpresence\\1.2.1.24\\discordrichpresence.1.2.1.24.nupkg.sha512",
|
||||
"C:\\Users\\joshua\\.nuget\\packages\\microsoft.netcore.platforms\\2.0.0\\microsoft.netcore.platforms.2.0.0.nupkg.sha512",
|
||||
|
|
17
README.md
Normal file
17
README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
## Jellyfin Discord RPC
|
||||
|
||||
Jellyfin Discord RPC is an integration that updates your Discord status to reflect the media you're currently enjoying on Jellyfin. Whether you're watching movies, binging TV shows, or listening to music, this tool enhances your Discord profile with dynamic, real-time information, including media titles, progress, and even album covers.
|
||||
|
||||
Key Features:
|
||||
|
||||
- Displays what you're watching or listening to on Jellyfin in your Discord status.
|
||||
- Automatically updates with details like movie/show titles, song names, artist info, and runtime progress.
|
||||
- Configurable and lightweight—works out of the box with minimal setup.
|
||||
|
||||
Requirements:
|
||||
|
||||
- A running Jellyfin server.
|
||||
- A Discord application with Rich Presence enabled.
|
||||
- .NET environment to run the app.
|
||||
|
||||
This is great for Jellyfin users who want to share their viewing or listening experience with friends on Discord.
|
Loading…
Add table
Reference in a new issue