Skip to content
This repository has been archived by the owner on Jul 6, 2021. It is now read-only.

Adds cache timeout for playlist && Adds hook callback for playlist updates #15

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions sxm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@ class SiriusXM:
REST_FORMAT = 'https://player.siriusxm.com/rest/v2/experience/modules/{}'
LIVE_PRIMARY_HLS = 'https://siriusxm-priprodlive.akamaized.net'

def __init__(self, username, password):
def __init__(self, username, password, update_handler=None):
self.session = requests.Session()
self.session.headers.update({'User-Agent': self.USER_AGENT})
self.username = username
self.password = password
self.playlists = {}
self.channels = None

# vars to manage session cache
self.last_renew = None
self.update_interval = 30

# hook function to call whenever the playlist updates
self.update_handler = update_handler

@staticmethod
def log(x):
print('{} <SiriusXM>: {}'.format(datetime.datetime.now().strftime('%d.%b %Y %H:%M:%S'), x))
Expand Down Expand Up @@ -147,8 +154,14 @@ def get_gup_id(self):
return None

def get_playlist_url(self, guid, channel_id, use_cache=True, max_attempts=5):
now = time.time()

if use_cache and channel_id in self.playlists:
return self.playlists[channel_id]
if self.last_renew is None or \
(now - self.last_renew) > self.update_interval:
del self.playlists[channel_id]
else:
return self.playlists[channel_id]

params = {
'assetGUID': guid,
Expand All @@ -166,7 +179,9 @@ def get_playlist_url(self, guid, channel_id, use_cache=True, max_attempts=5):

# get status
try:
status = data['ModuleListResponse']['status']
self.update_interval = int(
data['ModuleListResponse']['moduleList']['modules'][0]['updateFrequency']
)
message = data['ModuleListResponse']['messages'][0]['message']
message_code = data['ModuleListResponse']['messages'][0]['code']
except (KeyError, IndexError):
Expand Down Expand Up @@ -200,6 +215,10 @@ def get_playlist_url(self, guid, channel_id, use_cache=True, max_attempts=5):
if playlist_info['size'] == 'LARGE':
playlist_url = playlist_info['url'].replace('%Live_Primary_HLS%', self.LIVE_PRIMARY_HLS)
self.playlists[channel_id] = self.get_playlist_variant_url(playlist_url)
self.last_renew = time.time()

if self.update_handler is not None:
self.update_handler(data)
return self.playlists[channel_id]

return None
Expand All @@ -215,12 +234,12 @@ def get_playlist_variant_url(self, url):
if res.status_code != 200:
self.log('Received status code {} on playlist variant retrieval'.format(res.status_code))
return None

for x in res.text.split('\n'):
if x.rstrip().endswith('.m3u8'):
# first variant should be 256k one
return '{}/{}'.format(url.rsplit('/', 1)[0], x.rstrip())

return None

def get_playlist(self, name, use_cache=True):
Expand Down Expand Up @@ -277,7 +296,7 @@ def get_segment(self, path, max_attempts=5):
return None

return res.content

def get_channels(self):
# download channel list if necessary
if not self.channels:
Expand Down Expand Up @@ -356,11 +375,11 @@ def do_GET(self):
parser.add_argument('-l', '--list', required=False, action='store_true', default=False)
parser.add_argument('-p', '--port', required=False, default=9999, type=int)
args = vars(parser.parse_args())

sxm = SiriusXM(args['username'], args['password'])
if args['list']:
channels = list(sorted(sxm.get_channels(), key=lambda x: (not x.get('isFavorite', False), int(x.get('siriusChannelNumber', 9999)))))

l1 = max(len(x.get('channelId', '')) for x in channels)
l2 = max(len(str(x.get('siriusChannelNumber', 0))) for x in channels)
l3 = max(len(x.get('name', '')) for x in channels)
Expand Down