Skip to content

Commit e86ee52

Browse files
committed
Added support for deep_links, episode_num, and season_num in sensor attributes
1 parent 83d0be9 commit e86ee52

File tree

3 files changed

+42
-56
lines changed

3 files changed

+42
-56
lines changed

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@ Home Assistant component to feed [Upcoming Media Card](https://github.com/custom
44
Plex's recently added media.</br>
55
This component does not require, nor conflict with, the default Plex components.</br></br>
66

7+
### New!
8+
* Added support for Plex 'deep_links' in sensor attributes (Direct URLs to each TV Episode & Movie on Plex Web).
9+
* Added support for 'season_num' & 'episode_num' in sensor attributes for TV Episodes.
10+
711
### Issues
812
Read through these two resources before posting issues to GitHub or the forums.
913
* [troubleshooting guide](https://github.com/custom-cards/upcoming-media-card/blob/master/troubleshooting.md)
1014
* [@thomasloven's lovelace guide](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins).
1115

12-
## Supporting Development
13-
- :coffee:&nbsp;&nbsp;[Buy me a coffee](https://www.buymeacoffee.com/FgwNR2l)
14-
- :1st_place_medal:&nbsp;&nbsp;[Tip some Crypto](https://github.com/sponsors/maykar)
15-
- :heart:&nbsp;&nbsp;[Sponsor me on GitHub](https://github.com/sponsors/maykar)
16-
<br><br>
17-
1816
## Installation:
1917
1. Install this component by copying [these files](https://github.com/custom-components/sensor.plex_recently_added/tree/master/custom_components/plex_recently_added) to `custom_components/plex_recently_added/`.
2018
2. Install the card: [Upcoming Media Card](https://github.com/custom-cards/upcoming-media-card)

custom_components/plex_recently_added/sensor.py

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ async def fetch(session, url, self, ssl, content):
3535
return await response.content.read()
3636
else:
3737
return await response.text()
38-
except:
39-
pass
38+
except (aiohttp.ClientError, asyncio.TimeoutError) as e:
39+
_LOGGER.error(f"Error fetching data: {e}")
4040

4141

4242
async def request(url, self, content=False, ssl=False):
@@ -109,10 +109,9 @@ def __init__(self, hass, conf, name):
109109
_LOGGER.warning(
110110
"Plex Recently Added: The server_name option has been removed. Use host and port options instead.")
111111
return
112-
else:
113-
self.server_ip = conf.get(CONF_HOST)
114-
self.local_ip = conf.get(CONF_HOST)
115-
self.port = conf.get(CONF_PORT)
112+
self.server_ip = conf.get(CONF_HOST)
113+
self.local_ip = conf.get(CONF_HOST)
114+
self.port = conf.get(CONF_PORT)
116115
self.url_elements = [self.ssl, self.server_ip, self.local_ip,
117116
self.port, self.token, self.cert, self.dl_images]
118117
self.change_detected = False
@@ -156,85 +155,79 @@ def extra_state_attributes(self):
156155
else:
157156
continue
158157
if 'addedAt' in media:
159-
card_item['airdate'] = datetime.utcfromtimestamp(
160-
media['addedAt']).strftime('%Y-%m-%dT%H:%M:%SZ')
158+
card_item['airdate'] = datetime.utcfromtimestamp(media['addedAt']).strftime('%Y-%m-%dT%H:%M:%SZ')
161159
else:
162160
continue
163-
if 'originallyAvailableAt' in media:
164-
card_item['aired'] = media.get('originallyAvailableAt', '')
165-
else:
166-
card_item['aired'] = ''
161+
card_item['aired'] = media.get('originallyAvailableAt', '')
167162
if days_since(media['addedAt'], self._tz) <= 7:
168163
card_item['release'] = '$day, $date $time'
169164
else:
170165
card_item['release'] = '$day, $date $time'
171-
if 'viewCount' in media:
172-
card_item['flag'] = False
173-
else:
174-
card_item['flag'] = True
166+
card_item['flag'] = 'viewCount' not in media
175167
if media['type'] == 'movie':
176168
card_item['title'] = media.get('title', '')
177169
card_item['episode'] = ''
170+
card_item['number'] = ''
178171
elif media['type'] == 'episode':
179172
card_item['title'] = media.get('grandparentTitle', '')
180173
card_item['episode'] = media.get('title', '')
181-
card_item['number'] = ('S{:02d}E{:02d}').format(
182-
media.get('parentIndex', 0), media.get('index', 0))
174+
season_num, episode_num = media.get('parentIndex', 0), media.get('index', 0)
175+
card_item['season_num'] = season_num
176+
card_item['episode_num'] = episode_num
177+
card_item['number'] = f'S{season_num:02d}E{episode_num:02d}'
183178
else:
184179
continue
185180
if media.get('duration', 0) > 0:
186-
card_item['runtime'] = math.floor(
187-
media['duration'] / 60000)
188-
if 'studio' in media:
189-
card_item['studio'] = media.get('studio', '')
190-
if 'Genre' in media:
191-
card_item['genres'] = ', '.join(
192-
[genre['tag'] for genre in media['Genre']][:3])
193-
if media.get('rating', 0) > 0:
194-
card_item['rating'] = ('\N{BLACK STAR} ' +
195-
str(media['rating']))
196-
else:
197-
card_item['rating'] = ''
181+
card_item['runtime'] = math.floor(media['duration'] / 60000)
182+
card_item['studio'] = media.get('studio', '')
183+
card_item['genres'] = ', '.join([genre['tag'] for genre in media.get('Genre', [])][:3])
184+
card_item['rating'] = ('\N{BLACK STAR} ' + str(media['rating'])) if media.get('rating', 0) > 0 else ''
185+
key = media['key'].split('/')[-1]
198186
if media['type'] == 'movie':
199187
poster = media.get('thumb', '')
200188
fanart = media.get('art', '')
201189
elif media['type'] == 'episode':
202190
poster = media.get('grandparentThumb', '')
203191
fanart = media.get('grandparentArt', '')
204-
else:
205-
continue
206192
if self.dl_images:
207193
if os.path.isfile(self.img.format('www', 'p', key)):
208-
card_item['poster'] = self.img_url.format('/local',
209-
'p', key)
210-
else:
211-
continue
194+
card_item['poster'] = self.img_url.format('/local', 'p', key)
212195
if os.path.isfile(self.img.format('www', 'f', key)):
213-
card_item['fanart'] = self.img_url.format('/local',
214-
'f', key)
215-
else:
216-
card_item['fanart'] = ''
196+
card_item['fanart'] = self.img_url.format('/local', 'f', key)
217197
else:
218-
card_item['poster'] = image_url(self,
219-
False, poster, self.resolution)
220-
card_item['fanart'] = image_url(self,
221-
False, fanart, self.resolution)
198+
card_item['poster'] = image_url(self, False, poster, self.resolution)
199+
card_item['fanart'] = image_url(self, False, fanart, self.resolution)
222200
should_add = True
223201
if self.excludes:
224202
for exclude in self.excludes:
225203
if exclude.lower() in card_item['title'].lower():
226204
should_add = False
227205
if should_add:
206+
if self.server_identifier:
207+
card_item['deep_link'] = f'http://{self.server_ip}:{self.port}/web/index.html#!/server/{self.server_identifier}/details?key=%2Flibrary%2Fmetadata%2F{key}'
208+
else:
209+
card_item['deep_link'] = None
228210
self.card_json.append(card_item)
229-
self.change_detected = False
211+
self.change_detected = False
230212
attributes['data'] = self.card_json
231213
return attributes
232214

233215
async def async_update(self):
234216
import os
235217
import re
218+
import json
236219
if self.server_name:
237220
return
221+
222+
server_info_url = f'http://{self.server_ip}:{self.port}/?X-Plex-Token={self.token}'
223+
try:
224+
server_info_response = await request(server_info_url, self)
225+
server_info_data = json.loads(server_info_response)
226+
self.server_identifier = server_info_data.get('MediaContainer', {}).get('machineIdentifier')
227+
except Exception as e:
228+
_LOGGER.error(f"Error retrieving Plex server information: {e}")
229+
self.server_identifier = None
230+
238231
url_base = 'http{0}://{1}:{2}/library/sections'.format(self.ssl,
239232
self.server_ip,
240233
self.port)

info.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
11
This component feeds [Upcoming Media Card](./146783593) with Plex's recently added media.
2-
3-
## Supporting Development
4-
- :coffee: [Buy me a coffee](https://www.buymeacoffee.com/FgwNR2l)
5-
- :red_circle: [Tip some Crypto](https://github.com/sponsors/maykar)
6-
- :heart: [Sponsor me on GitHub](https://github.com/sponsors/maykar)

0 commit comments

Comments
 (0)