1
+ """Trakt user collections integration for Mediarr."""
2
+ import logging
3
+ from datetime import datetime, timedelta
4
+ from ..common.sensor import MediarrSensor
5
+
6
+ _LOGGER = logging.getLogger(__name__)
7
+
8
+ TRAKT_USER_ENDPOINTS = {
9
+ 'collection': ['collection/movies', 'collection/shows'],
10
+ 'watched': ['watched/movies', 'watched/shows'],
11
+ 'watchlist': ['watchlist/movies', 'watchlist/shows'],
12
+ 'recommendations': ['recommendations/movies', 'recommendations/shows'],
13
+ 'recently_watched': ['history/movies', 'history/shows'],
14
+ 'upcoming': ['calendar/movies', 'calendar/my/shows']
15
+ }
16
+
17
+ class TraktUserMediarrSensor(MediarrSensor):
18
+ """Representation of a Trakt user collection sensor."""
19
+
20
+ def __init__(self, session, username, client_id, client_secret, endpoint, max_items, tmdb_api_key=None):
21
+ """Initialize the sensor."""
22
+ super().__init__()
23
+ self._session = session
24
+ self._username = username
25
+ self._client_id = client_id
26
+ self._client_secret = client_secret
27
+ self._endpoint = endpoint
28
+ self._max_items = max_items
29
+ self._tmdb_api_key = tmdb_api_key
30
+ self._name = f"Trakt User Mediarr {endpoint.replace('_', ' ').title()}"
31
+ self._access_token = None
32
+ self._headers = {
33
+ 'Content-Type': 'application/json',
34
+ 'trakt-api-version': '2',
35
+ 'trakt-api-key': client_id
36
+ }
37
+
38
+ @property
39
+ def name(self):
40
+ """Return the name of the sensor."""
41
+ return self._name
42
+
43
+ @property
44
+ def unique_id(self):
45
+ """Return the unique ID of the sensor."""
46
+ return f"trakt_user_mediarr_{self._endpoint}"
47
+
48
+ async def async_update(self):
49
+ """Update sensor state."""
50
+ try:
51
+ results = []
52
+ endpoints = TRAKT_USER_ENDPOINTS.get(self._endpoint, [])
53
+
54
+ for endpoint in endpoints:
55
+ params = {}
56
+ if self._endpoint == 'upcoming':
57
+ start_date = datetime.now().strftime('%Y-%m-%d')
58
+ end_date = (datetime.now() + timedelta(days=30)).strftime('%Y-%m-%d')
59
+ params = {'start_date': start_date, 'end_date': end_date}
60
+ elif self._endpoint == 'recently_watched':
61
+ params = {'limit': self._max_items}
62
+
63
+ async with self._session.get(
64
+ f"https://api.trakt.tv/users/{self._username}/{endpoint}",
65
+ headers=self._headers,
66
+ params=params
67
+ ) as response:
68
+ if response.status == 200:
69
+ data = await response.json()
70
+
71
+ for item in data:
72
+ if 'movie' in item:
73
+ media_item = item['movie']
74
+ media_type = 'movie'
75
+ elif 'show' in item:
76
+ media_item = item['show']
77
+ media_type = 'show'
78
+ else:
79
+ continue
80
+
81
+ result = {
82
+ 'title': media_item.get('title'),
83
+ 'year': media_item.get('year'),
84
+ 'type': media_type,
85
+ 'collected_at': item.get('collected_at'),
86
+ 'last_watched_at': item.get('last_watched_at'),
87
+ 'updated_at': item.get('updated_at'),
88
+ 'ids': media_item.get('ids', {}),
89
+ 'tmdb_id': media_item.get('ids', {}).get('tmdb'),
90
+ 'imdb_id': media_item.get('ids', {}).get('imdb'),
91
+ 'trakt_id': media_item.get('ids', {}).get('trakt')
92
+ }
93
+
94
+ if self._tmdb_api_key and result['tmdb_id']:
95
+ tmdb_data = await self._fetch_tmdb_data(
96
+ result['tmdb_id'],
97
+ 'movie' if media_type == 'movie' else 'tv'
98
+ )
99
+ result.update(tmdb_data)
100
+
101
+ results.append(result)
102
+
103
+ self._state = len(results)
104
+ self._attributes = {'data': results[:self._max_items]}
105
+ self._available = True
106
+
107
+ except Exception as err:
108
+ _LOGGER.error("Error updating Trakt user sensor: %s", err)
109
+ self._state = None
110
+ self._attributes = {'data': []}
111
+ self._available = False
112
+
113
+ async def _fetch_tmdb_data(self, tmdb_id, media_type):
114
+ """Fetch additional metadata from TMDB."""
115
+ try:
116
+ headers = {
117
+ 'Authorization': f'Bearer {self._tmdb_api_key}',
118
+ 'accept': 'application/json'
119
+ }
120
+
121
+ async with self._session.get(
122
+ f"https://api.themoviedb.org/3/{media_type}/{tmdb_id}",
123
+ headers=headers
124
+ ) as response:
125
+ if response.status == 200:
126
+ data = await response.json()
127
+ return {
128
+ 'poster': f"https://image.tmdb.org/t/p/w500{data.get('poster_path')}" if data.get('poster_path') else None,
129
+ 'backdrop': f"https://image.tmdb.org/t/p/original{data.get('backdrop_path')}" if data.get('backdrop_path') else None,
130
+ 'overview': data.get('overview'),
131
+ 'vote_average': data.get('vote_average'),
132
+ 'popularity': data.get('popularity')
133
+ }
134
+ return {}
135
+ except Exception as err:
136
+ _LOGGER.error("Error fetching TMDB data: %s", err)
137
+ return {}
0 commit comments