1+ using Fetcharr . Cache . Core ;
2+ using Fetcharr . Models . Configuration ;
3+ using Fetcharr . Provider . Plex . Models ;
4+ using Fetcharr . Shared . GraphQL ;
5+
6+ using GraphQL ;
7+ using GraphQL . Client . Http ;
8+ using GraphQL . Client . Serializer . SystemTextJson ;
9+
10+ using Microsoft . Extensions . DependencyInjection ;
11+ using Microsoft . Extensions . Options ;
12+
13+ namespace Fetcharr . Provider . Plex . Clients
14+ {
15+ /// <summary>
16+ /// Client for interacting with Plex' GraphQL API.
17+ /// </summary>
18+ public class PlexGraphQLClient (
19+ IOptions < FetcharrConfiguration > configuration ,
20+ [ FromKeyedServices ( "plex-graphql" ) ] ICachingProvider cachingProvider )
21+ {
22+ /// <summary>
23+ /// Gets the GraphQL endpoint for Plex.
24+ /// </summary>
25+ public const string GraphQLEndpoint = "https://community.plex.tv/api" ;
26+
27+ private readonly GraphQLHttpClient _client =
28+ new GraphQLHttpClient ( PlexGraphQLClient . GraphQLEndpoint , new SystemTextJsonSerializer ( ) )
29+ . WithAutomaticPersistedQueries ( _ => true )
30+ . WithHeader ( "X-Plex-Token" , configuration . Value . Plex . ApiToken )
31+ . WithHeader ( "X-Plex-Client-Identifier" , "fetcharr" ) ;
32+
33+ /// <summary>
34+ /// Gets the watchlist of a Plex account, who's a friend of the current plex account.
35+ /// </summary>
36+ public async Task < IEnumerable < WatchlistMetadataItem > > GetFriendWatchlistAsync (
37+ string userId ,
38+ int count = 100 ,
39+ string ? cursor = null )
40+ {
41+ string cacheKey = $ "friend-watchlist-{ userId } ";
42+
43+ CacheValue < IEnumerable < WatchlistMetadataItem > > cachedResponse = await cachingProvider
44+ . GetAsync < IEnumerable < WatchlistMetadataItem > > ( cacheKey ) ;
45+
46+ if ( cachedResponse . HasValue )
47+ {
48+ return cachedResponse . Value ;
49+ }
50+
51+ GraphQLRequest request = new ( )
52+ {
53+ Query = """
54+ query GetFriendWatchlist($uuid: ID = "", $first: PaginationInt!, $after: String) {
55+ user(id: $uuid) {
56+ watchlist(first: $first, after: $after) {
57+ nodes {
58+ ... on MetadataItem {
59+ title
60+ ratingKey: id
61+ year
62+ type
63+ }
64+ }
65+ pageInfo {
66+ hasNextPage
67+ endCursor
68+ }
69+ }
70+ }
71+ }
72+ """ ,
73+ OperationName = "GetFriendWatchlist" ,
74+ Variables = new
75+ {
76+ uuid = userId ,
77+ first = count ,
78+ after = cursor ?? string . Empty
79+ }
80+ } ;
81+
82+ GraphQLResponse < PlexUserWatchlistResponseType > response = await this . _client
83+ . SendQueryAsync < PlexUserWatchlistResponseType > ( request ) ;
84+
85+ response . ThrowIfErrors ( message : "Failed to fetch friend's watchlist from Plex" ) ;
86+
87+ IEnumerable < WatchlistMetadataItem > watchlistItems = response . Data . User . Watchlist . Nodes ;
88+
89+ await cachingProvider . SetAsync ( cacheKey , watchlistItems , expiration : TimeSpan . FromHours ( 4 ) ) ;
90+ return watchlistItems ;
91+ }
92+
93+ /// <summary>
94+ /// Gets all the friends of the current Plex account and returns them.
95+ /// </summary>
96+ public async Task < IEnumerable < PlexFriendUser > > GetAllFriendsAsync ( )
97+ {
98+ CacheValue < IEnumerable < PlexFriendUser > > cachedResponse = await cachingProvider
99+ . GetAsync < IEnumerable < PlexFriendUser > > ( "friends-list" ) ;
100+
101+ if ( cachedResponse . HasValue )
102+ {
103+ return cachedResponse . Value ;
104+ }
105+
106+ GraphQLRequest request = new ( )
107+ {
108+ Query = """
109+ query {
110+ allFriendsV2 {
111+ user {
112+ id
113+ username
114+ }
115+ }
116+ }
117+ """
118+ } ;
119+
120+ GraphQLResponse < PlexFriendListResponseType > response = await this . _client
121+ . SendQueryAsync < PlexFriendListResponseType > ( request ) ;
122+
123+ response . ThrowIfErrors ( message : "Failed to fetch friends list from Plex" ) ;
124+
125+ IEnumerable < PlexFriendUser > friends = response . Data . Friends . Select ( v => v . User ) ;
126+
127+ await cachingProvider . SetAsync ( "friends-list" , friends , expiration : TimeSpan . FromHours ( 4 ) ) ;
128+ return friends ;
129+ }
130+ }
131+ }
0 commit comments