diff --git a/Contents/Code/__init__.py b/Contents/Code/__init__.py index c216b53..66f95ad 100644 --- a/Contents/Code/__init__.py +++ b/Contents/Code/__init__.py @@ -1,57 +1,112 @@ ROOT_MENU = 'http://opml.radiotime.com/Browse.ashx?formats=mp3,aac' +ART = 'art-default.jpg' +ICON = 'icon-default.jpg' + +# STATION_URL = 'http://tunein.com/radio/-%s/' +USER_URL = 'http://opml.radiotime.com/Browse.ashx?c=presets&partnerId=RadioTime&username=%s' +MY_STATIONS = 'tunein://mystations' +CUSTOM_URL_PREFIX = 'tunein://play?' + #################################################################################################### def Start(): ObjectContainer.title1 = 'TuneIn' HTTP.CacheTime = 300 + ObjectContainer.art = R(ART) + DirectoryObject.art = R(ART) + DirectoryObject.thumb = R(ICON) + +#################################################################################################### +def ValidatePrefs(): + + return True #################################################################################################### @handler('/music/tunein', 'TuneIn') @route('/music/tunein/menu') -def Menu(url=ROOT_MENU, title='', outline_text=''): +def Menu(url=ROOT_MENU, title='', xml = None): oc = ObjectContainer(title2=title) - root = XML.ElementFromURL(url).xpath('//body')[0] - if len(root.xpath('./outline[@URL and not(@type="audio")]')) > 0: - for item in root.xpath('./outline[@URL]'): + if url == ROOT_MENU and not xml: + my_stations = L('My Stations') + oc.add(DirectoryObject( + key = Callback(Menu, url=MY_STATIONS, title=my_stations), + title = my_stations + )) + oc.add(PrefsObject( + title = L('Preferences...'), + ) + ) - oc.add(DirectoryObject( - key = Callback(Menu, url=item.get('URL'), title=item.get('text')), - title = item.get('text'), - thumb = Resource.ContentsOfURLWithFallback('') - )) + if url == MY_STATIONS: + username = Prefs['username'] - if len(root.xpath('./outline[@text and not(@URL) and not(@key="related")]')) > 0 and outline_text == '': - for item in root.xpath('./outline[@text and not(@URL) and not(@key="related")]'): + if not username: + oc.message = L('Please specify user name in the TuneIn preferences') + return oc - if item.get('text') == 'This program is not available': - continue + url = USER_URL % username - oc.add(DirectoryObject( - key = Callback(Menu, url=url, title=item.get('text'), outline_text=item.get('text')), - title = item.get('text'), - thumb = Resource.ContentsOfURLWithFallback('') - )) + if xml: + subitems = XML.ElementFromString(xml) + else: + subitems = XML.ElementFromURL(url).xpath('//body')[0] + + # Log.Debug('Subitems: '+str(subitems)) + Log.Debug('Subitems count: '+str(len(subitems))) - if outline_text != '': - for item in root.xpath('./outline[@text="%s"]/outline' % outline_text): + for item in subitems: + typ = item.get('type') + local_url = item.get('URL') + text = item.get('text') + image = item.get('image') + key = item.get('key') + subtext = item.get('subtext') + # station_id = item.get('guide_id') + itemAttr = item.get('item') - if item.get('type') == 'link': - oc.add(DirectoryObject( - key = Callback(Menu, url=item.get('URL'), title=item.get('text')), - title = item.get('text'), - thumb = Resource.ContentsOfURLWithFallback(item.get('image')) - )) + if key in ['unavailable', 'related']: + continue - elif item.get('type') == 'audio': + if itemAttr == 'url': + data = { + 'url' : local_url, + 'title': text, + 'summary': subtext, + 'image': image + } - oc.add(TrackObject( - url = item.get('URL'), - title = item.get('text'), - thumb = Resource.ContentsOfURLWithFallback(item.get('image')) - )) + oc.add(TrackObject( + url = CUSTOM_URL_PREFIX+String.Encode(JSON.StringFromObject(data)), + title = text, + summary = subtext, + source_title = 'TuneIn', + thumb = Resource.ContentsOfURLWithFallback(image) + )) + elif typ == 'audio': + oc.add(TrackObject( + url = local_url, + # url = STATION_URL % station_id, + title = text, + summary = subtext, + source_title = 'TuneIn', + thumb = Resource.ContentsOfURLWithFallback(image) + )) + elif typ == 'link': + oc.add(DirectoryObject( + key = Callback(Menu, url=local_url, title=text), + title = text, + thumb = Resource.ContentsOfURLWithFallback('') + )) + else: + # Log.Debug('Current item: '+str(item)) + oc.add(DirectoryObject( + key = Callback(Menu, title=text, xml = XML.StringFromElement(item)), + title = text, + thumb = Resource.ContentsOfURLWithFallback('') + )) return oc diff --git a/Contents/DefaultPrefs.json b/Contents/DefaultPrefs.json new file mode 100644 index 0000000..c4cc262 --- /dev/null +++ b/Contents/DefaultPrefs.json @@ -0,0 +1,8 @@ +[ + { + "id": "username", + "type": "text", + "label": "TuneIn username", + "default": "" + } +] diff --git a/Contents/Resources/art-default.jpg b/Contents/Resources/art-default.jpg new file mode 100644 index 0000000..e9232c9 Binary files /dev/null and b/Contents/Resources/art-default.jpg differ diff --git a/Contents/Resources/icon-default.jpg b/Contents/Resources/icon-default.jpg new file mode 100644 index 0000000..440ddb5 Binary files /dev/null and b/Contents/Resources/icon-default.jpg differ diff --git a/Contents/Services/ServiceInfo.plist b/Contents/Services/ServiceInfo.plist index 63173f2..1f34175 100644 --- a/Contents/Services/ServiceInfo.plist +++ b/Contents/Services/ServiceInfo.plist @@ -9,6 +9,8 @@ URLPatterns ^http://opml\.radiotime\.com/Tune\.ashx + ^http://tunein\.com/radio/.*-(s|p)\d+/$ + ^tunein:// diff --git a/Contents/Services/URL/TuneIn/ServiceCode.pys b/Contents/Services/URL/TuneIn/ServiceCode.pys index a49c841..ac03c92 100644 --- a/Contents/Services/URL/TuneIn/ServiceCode.pys +++ b/Contents/Services/URL/TuneIn/ServiceCode.pys @@ -1,82 +1,166 @@ -DETAILS_URL = 'http://opml.radiotime.com/Describe.ashx?id=%s' -STATION_DETAILS_URL = 'http://opml.radiotime.com/Describe.ashx?c=nowplaying&id=%s' +URL_STATION = 'http://tunein.com/radio/-%s/' -RE_ID = Regex('id=(?P(s|p)\d+)') -RE_ENTRIES = Regex('NumberOfEntries=(?P\d+)') -RE_STREAM = Regex('File%s=(?P.*)$') +RE_IDS = [ + Regex('-(?P(s|p)\d+)/'), + Regex('id=(?P(s|p)\d+)') + ] + +CUSTOM_URL_PREFIX = 'tunein://play?' #################################################################################################### def MetadataObjectForURL(url): - station_id = RE_ID.search(url).group('id') - station_details_page = XML.ElementFromURL(STATION_DETAILS_URL % station_id) - - station = station_details_page.xpath("//outline[@key='station']/text()")[0] - - show_id = station_details_page.xpath("//outline[@key='show']/@guide_id")[0] - show_detail_page = XML.ElementFromURL(DETAILS_URL % show_id) + Log.Debug("Requesting metadata for url: %s", url) - try: title = show_detail_page.xpath("//show/title/text()")[0] - except: title = None + customStream = ParseCustomUrl(url) - try: hosts = show_detail_page.xpath("//show/hosts/text()")[0] - except: hosts = None + if customStream: + title = customStream['title'] + summary = customStream['summary'] + playing = summary + image_url = customStream['image'] + else: + station = TuneInStation(url) - try: thumb = show_detail_page.xpath("//show/logo/text()")[0] - except: thumb = '' - - try: genre = show_detail_page.xpath("//show/genre_id/text()")[0] - except: genre = None + title = station.title + summary = station.title + playing = station.playing + image_url = station.image_url return TrackObject( - artist = station, - album = title, - title = hosts, - thumb = Resource.ContentsOfURLWithFallback(thumb) + artist = title, + album = playing, + title = summary, + summary = playing, + source_title = 'TuneIn', + thumb = Resource.ContentsOfURLWithFallback(image_url) ) #################################################################################################### def MediaObjectsForURL(url): - return [ - MediaObject( - parts = [ - PartObject(key = Callback(PlayTrack, url=url)) - ] - ) - ] + return [MediaObject( + # container = container, + # audio_codec = audio_codec, + # bitrate = bitrate, + # audio_channels = 2, + parts = [PartObject(key = Callback(PlayTrack, url=url))] + )] #################################################################################################### def PlayTrack(url): - details = XML.ElementFromURL(url + '&c=ebrowse') - Log(XML.StringFromElement(details)) + customStream = ParseCustomUrl(url) + + if customStream: + return Redirect(customStream['url']) + + station = TuneInStation(url) - stream_url = details.xpath("//outline[@type='audio']/@URL")[0] - Log(stream_url) + best_reliability = -1 + for stream in station.loadStreams(): + reliability = int(stream['Reliability']) + if reliability > best_reliability: + best_reliability = reliability + stream_url = stream['Url'] - Log(HTTP.Request(stream_url).content.strip()) - return Redirect(HTTP.Request(stream_url).content.strip()) + # stream_url = HTTP.Request(m3u8).content.strip() + + # Log("m3u8 url: %s, audio stream: %s" %(m3u8, stream_url)) + + return Redirect(stream_url) #################################################################################################### -def parse_m3u(content): +def GetStationId(url): - streams = [] + for re in RE_IDS: + m = re.search(url) + if m: + return m.group('id') - for item in content.split('\n'): + return None - if item.startswith('#') == False: - streams.append(item.strip()) +#################################################################################################### +def UrlRequest(url): - return streams + return HTTP.Request( + url, + headers={ + 'x-requested-with': 'XMLHttpRequest', + 'Accept' : 'application/json, text/javascript, */*; q=0.01'} + ).content #################################################################################################### -def parse_pls(content): +def ParseCustomUrl(url): + + if not url.startswith(CUSTOM_URL_PREFIX): + return None + + param = url[len(CUSTOM_URL_PREFIX):] + + # Log.Debug("Url: %s, param encoded: %s", url, param) + + s = String.Decode(param) + # Log.Debug("param decoded: %s", s) + + return JSON.ObjectFromString(s) + +#################################################################################################### +class TuneInStation: + + def __init__(self, url='', id=''): + if not id: + id = GetStationId(url) + + text = UrlRequest(URL_STATION % id) + + # Log.Debug("Requested url: %s, response: %s", url, text) + + payload = JSON.ObjectFromString(text)['payload'] + + if 'Station' in payload: + self.js = payload['Station'] + else: + self.js = payload['Program'] + + self.broadcast = self.js['broadcast'] + self.echo = self.broadcast['EchoData'] + + # Log.Debug('Station id: %s, json: %s' % (id, self.js)) + # print('Station id: %s, json: %s' % (id, self.js)) + + @property + def id(self): + return self.echo['targetGuideId'] + + @property + def title(self): + return self.broadcast['Title'] + + @property + def description(self): + return self.js['description'] + + @property + def image_url(self): + return self.broadcast['Logo'] + + @property + def summary(self): + return self.echo['subtitle'] + + @property + def playing(self): + return self.broadcast['SongPlayingTitle'] - streams = [] - entries = RE_ENTRIES.search(content).group('entries') + @property + def stream_url(self): + url = self.broadcast['StreamUrl'] + if url.startswith('//'): + url = 'http:'+url; + return url - for i in range(1, entries+1): - streams.append(RE_STREAM.search(content).group('stream')) + def loadStreams(self): + text = UrlRequest(self.stream_url)[2:-2] + return JSON.ObjectFromString(text)['Streams'] - return streams diff --git a/README.md b/README.md index 2b0bdba..2e8c241 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,22 @@ License ------- -If the software submitted to this repository accesses or calls any software provided by Plex (“Interfacing Software”), then as a condition for receiving services from Plex in response to such accesses or calls, you agree to grant and do hereby grant to Plex and its affiliates worldwide a worldwide, nonexclusive, and royalty-free right and license to use (including testing, hosting and linking to), copy, publicly perform, publicly display, reproduce in copies for distribution, and distribute the copies of any Interfacing Software made by you or with your assistance; provided, however, that you may notify Plex at legal@plex.tv if you do not wish for Plex to use, distribute, copy, publicly perform, publicly display, reproduce in copies for distribution, or distribute copies of an Interfacing Software that was created by you, and Plex will reasonable efforts to comply with such a request within a reasonable time. \ No newline at end of file +If the software submitted to this repository accesses or calls any software provided by Plex (“Interfacing Software”), then as a condition for receiving services from Plex in response to such accesses or calls, you agree to grant and do hereby grant to Plex and its affiliates worldwide a worldwide, nonexclusive, and royalty-free right and license to use (including testing, hosting and linking to), copy, publicly perform, publicly display, reproduce in copies for distribution, and distribute the copies of any Interfacing Software made by you or with your assistance; provided, however, that you may notify Plex at legal@plex.tv if you do not wish for Plex to use, distribute, copy, publicly perform, publicly display, reproduce in copies for distribution, or distribute copies of an Interfacing Software that was created by you, and Plex will reasonable efforts to comply with such a request within a reasonable time. + +# Installation + +Follow the Manual Installation Instructions from [here](https://support.plex.tv/hc/en-us/articles/201187656-How-do-I-manually-install-a-channel-). + +# Listing of a user following stations + +'My Stations' sections shows radio stations following by a user. You need to specify username in preferences to use this feature. Such username can be found if you open a web page of a tunein user, for [this](http://tunein.com/user/adamchuk2168/) example the username is `adamchuk2168`. + +# Information for developer +* Requesting for a json with all station for a user: `curl 'http://tunein.com/profile/follows/?identifier=u159012873/follows/stations&type=&offset=20' -H 'x-requested-with: XMLHttpRequest'` +* [Example of a user profile page](http://tunein.com/user/adamchuk2168/) +* [Setting header to HTTP Request](http://thingsinjars.com/post/297/writing-a-plex-plugin-part-i/) +* [Persisting channel information](http://forums.plex.tv/discussion/88179/storing-user-data-in-dict) +* [RadioTime API documentation](https://github.com/brianhornsby/plugin.audio.tuneinradio/wiki/RadioTime-API-Methods:-Browse) +* [Stations for a user in xml format](http://opml.radiotime.com/Browse.ashx?c=presets&partnerId=RadioTime&username=adamchuk2168) +* Requestign detailed station info in json format: `curl 'http://tunein.com/radio/-s23428/' -H 'Accept: application/json, text/javascript, */*; q=0.01' -H 'X-Requested-With: XMLHttpRequest'` +* Requesting stations stream info: `curl 'http://stream.radiotime.com/listen.stream?streamIds=9652698&rti=dihyG20zOk1VUx9xRB5fWFslWUwQWxt5UhFLXVhIJlsWThRxYFsIDFcHJnwQRgQzWQcUWAIRRDxFTAl3Tx0KFlIXDHRqGAVABUUFU1pWZwI%3d%7e%7e%7e' -H 'Accept: application/json, text/javascript, */*; q=0.01' -H 'X-Requested-With: XMLHttpRequest'` diff --git a/tools/files/station.json b/tools/files/station.json new file mode 100644 index 0000000..88df1df --- /dev/null +++ b/tools/files/station.json @@ -0,0 +1,212 @@ +{ + "markup": "\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n\r\n
\r\n
\r\n
    \r\n
  • \r\n \r\n Follow\r\n Following\r\n \r\n
  • \r\n
  • \r\n Share\r\n
  • \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n

Radio RMF Swieta

\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
    \r\n
  • \r\n
    1
    \r\n
    Broadcast
    \r\n
  • \r\n
  • \r\n
    4.1K
    \r\n
    Followers
    \r\n
  • \r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n
\r\n\r\n\r\n
\r\n
\r\n

Stations

\r\n
\r\n
    \r\n \r\n\r\n
  • \r\n
    \r\n
    \r\n
    \r\n
    \r\n

    Slade - Merry Xmas Everybody

    \r\n

    Radio RMF Swieta

    \r\n
    \r\n
    \r\n
  • \r\n
\r\n \r\n
\r\n
\r\n\r\n
\r\n\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n\r\n
\r\n

Daily Schedule

\r\n
\r\n

\r\n TuneIn does not have lineup information for this date.\r\n Try visiting the station's website for more information.\r\n

\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n

STATION INFORMATION

\r\n
\r\n
\r\n \r\n
\r\n
\r\n

Listen to Radio RMF Swieta on your phone!

\r\n \r\n \r\n
\r\n
\r\n\r\n\r\n
\r\n
\r\n
\r\n

More information

\r\n \r\n RMFon.pl to platforma muzyczna, prezentująca kilkadziesiąt stacji radiowych online, dedykowanych różnym gatunkom, dekadom i artystom oraz radia RMF FM, RMF Maxxx i RMF Classic. Ponadto RMFon to muzyczne newsy, biografie, dyskografie, galerie, kalendarium, filmy wideo i konkursy.\r\n \r\n
\r\n\r\n
\r\n\r\n
\r\n
\r\n", + "testGroup": { + "tests": [], + "testIds": [] + }, + "payload": { + "Station": { + "stationId": 119801, + "description": "Radio RMF Swieta", + "broadcast": { + "GuideId": "s119801", + "FollowGuideId": "s119801", + "IsFollowing": false, + "ShareData": { + "title": "Radio RMF Swieta", + "subtitle": "Wybierz radio internetowe i znajdź muzykę dla siebie!", + "image": "http://cdn-radiotime-logos.tunein.com/s119801q.png", + "url": "http://tun.in/seOgl", + "shareText": "Listen to Radio RMF Swieta on TuneIn", + "guideId": "s119801", + "tuneType": "Station", + "playGuideId": "s119801", + "canEmbed": true, + "isDomainRestricted": false + }, + "EchoData": { + "sourceGuideId": null, + "targetGuideId": "s119801", + "scope": "s119801", + "imageUrl": "http://cdn-radiotime-logos.tunein.com/s119801q.png", + "title": "Radio RMF Swieta", + "subtitle": "Wybierz radio internetowe i znajdź muzykę dla siebie!" + }, + "SubscriptionRequired": false, + "StationId": 119801, + "ProgramId": 0, + "TopicId": 0, + "StartTime": null, + "TuneType": "Station", + "IsProgram": false, + "HasTopics": false, + "TopicDuration": 0, + "BuildVersion": "201601121211", + "DisplaySubtitle": null, + "SongPlayingTitle": "Merry Xmas Everybody - Slade", + "AudioClipId": 0, + "AudioClipOwnerId": null, + "ContentDuration": 0, + "IsEvent": false, + "StreamId": 0, + "HasUpcomingProgram": false, + "IsAutoTune": false, + "GeoRestricted": false, + "StreamUrl": "http://stream.radiotime.com/listen.stream?streamIds=9652698&rti=dihyG20zOk1VUx9xRB5fWFslWUwQWxt5UhFLXVhIJlsWThRxYFsIDFcHJnwQRgQzWQcUWAIRRDxFTAl3Tx0KFlIXDHRqGAVABUUFU1pWZwI%3d%7e%7e%7e", + "DirectStreams": [], + "Streams": [], + "Url": "http://tun.in/seOgl", + "Title": "Radio RMF Swieta", + "Logo": "http://cdn-radiotime-logos.tunein.com/s119801q.png", + "ShareLogo": "http://cdn-radiotime-logos.tunein.com/s119801q.png", + "DeepLinkUrl": "/tune/s119801", + "PartnerId": null, + "NavUrl": "/radio/Radio-RMF-Swieta-s119801/", + "Location": "Krakow, Poland", + "PlayableLater": false, + "BroadcasterRestricted": false, + "AllowCommercialAds": true, + "AllowAudioBanners": false + }, + "isInPremiumUpsellRegion": false + }, + "GuideItemGroups": { + "groups": [ + { + "moreBaseUrl": "/profile/contentItems/?identifier=", + "hasMore": false, + "count": 1, + "guideItems": [ + { + "GuideId": "s119801", + "Token": "BAUGAAAAAAAAAQVIUgAAAAAAAA%3d%3d", + "FollowGuideId": "s119801", + "Url": "/radio/Radio-RMF-Swieta-s119801/", + "CanPlay": true, + "CanPlayInline": true, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio RMF Swieta", + "Subtitle": "Slade - Merry Xmas Everybody", + "Image": "http://cdn-radiotime-logos.tunein.com/s119801q.png", + "PlayGuideId": "s119801", + "ShareText": "Listen to Radio RMF Swieta on TuneIn", + "ShareUrl": "http://tun.in/seOgl", + "SourceItemId": null, + "TargetItemId": "s119801", + "Scope": "s119801", + "SubscriptionRequired": false, + "Presentation": "PlayTile", + "Type": "Station" + } + ], + "limit": 20 + } + ] + }, + "ShowsPlaylist": { + "stationId": 119801, + "pageSize": 5, + "items": [] + }, + "HeroRibbon": { + "guideId": "s119801", + "contentsUrl": "/station/contents?stationId=119801", + "selectedTabIndex": 0, + "shareData": { + "title": "Radio RMF Swieta", + "subtitle": "Wybierz radio internetowe i znajdź muzykę dla siebie!", + "image": "http://cdn-radiotime-logos.tunein.com/s119801q.png", + "url": "http://tun.in/seOgl", + "shareText": "Listen to Radio RMF Swieta on TuneIn", + "guideId": "s119801", + "tuneType": "Station", + "playGuideId": "s119801", + "canEmbed": true, + "isDomainRestricted": false + } + } + }, + "adSettings": { + "tuneInEnabled": true, + "rotationEnabled": true, + "rotationPeriod": 300, + "baseUrl": "http://ads.tunein.com", + "trackingId": "e79a3393-e3a1-4cc4-91df-dcd92e137f3d", + "listingId": "s119801", + "partnerKey": "RadioTime", + "supplementalProgramId": null, + "displaySlots": [ + { + "id": "GoogleAd1", + "height": 250, + "width": 300, + "dimensions": [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ], + "extId": "15480783/ca-pub-1542925551861702/Station", + "slotName": "station_side", + "adType": "Display", + "tuneInEnabled": true, + "audioBannerEnabled": true, + "googleAdsEnabled": true + }, + { + "id": "div-gpt-ad-1346198113942-0", + "height": 90, + "width": 728, + "dimensions": [ + [ + 728, + 90 + ], + [ + 970, + 66 + ] + ], + "extId": "15480783/ca-pub-1542925551861702/StationLeader", + "slotName": "station_top", + "adType": "Display", + "tuneInEnabled": true, + "audioBannerEnabled": false, + "googleAdsEnabled": true + } + ], + "audioSlots": [ + { + "slotName": "station_preroll", + "adType": "Audio", + "durationSeconds": 15, + "tune": { + "stationId": 119801, + "programId": 0, + "topicId": 0, + "tuneType": "Station" + } + } + ], + "videoSlots": [], + "locale": "en-US", + "serverUtcTime": 130974046112805589, + "targeting": { + "env": "prod", + "gn": "157", + "class": "music", + "ListingId": "s119801" + }, + "vendriPLID": "web01", + "openXHeader": "ox-d.tunein.servedbyopenx.com/w/1.0/jstag?nc=15480783-Tunein" + }, + "pageTitle": "Radio RMF Swieta - Krakow - Listen Online", + "userAnonymous": true, + "metaTagContent": " \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n\r\n" +} diff --git a/tools/files/stations.json b/tools/files/stations.json new file mode 100644 index 0000000..6e60fb5 --- /dev/null +++ b/tools/files/stations.json @@ -0,0 +1,71 @@ +[ + { + "GuideId": "s23005", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s23005", + "Url": "/radio/Z1067-Jackson-s23005/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Z106.7 Jackson", + "Subtitle": "John Boy & Billy Classic Rock", + "Image": "http://cdn-radiotime-logos.tunein.com/s0q.png", + "PlayGuideId": "s23005", + "ShareText": "Listen to Z106.7 Jackson on TuneIn", + "ShareUrl": "http://tun.in/seo47", + "SourceItemId": null, + "TargetItemId": "s23005", + "Scope": "s23005", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s23428", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s23428", + "Url": "/radio/WUSJ-963-s23428/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "WUSJ", + "Subtitle": "Eric Church - Like a Wrecking Ball", + "Image": "http://cdn-radiotime-logos.tunein.com/s23428q.png", + "PlayGuideId": "s23428", + "ShareText": "Listen to Scott & Traci In The Morning on WUSJ on TuneIn", + "ShareUrl": "http://tun.in/sepbW", + "SourceItemId": null, + "TargetItemId": "s23428", + "Scope": "s23428", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s119801", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s119801", + "Url": "/radio/Radio-RMF-Swieta-s119801/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio RMF Swieta", + "Subtitle": "Wybierz radio internetowe i znajdź muzykę dla siebie!", + "Image": "http://cdn-radiotime-logos.tunein.com/s119801q.png", + "PlayGuideId": "s119801", + "ShareText": "Listen to Radio RMF Swieta on TuneIn", + "ShareUrl": "http://tun.in/seOgl", + "SourceItemId": null, + "TargetItemId": "s119801", + "Scope": "s119801", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + } + ] diff --git a/tools/files/stream.json b/tools/files/stream.json new file mode 100644 index 0000000..240445a --- /dev/null +++ b/tools/files/stream.json @@ -0,0 +1,121 @@ +{ + "Streams":[ + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://31.192.216.4:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://217.74.72.3:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://195.150.20.4:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://185.69.192.87:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://195.150.20.243:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://195.150.20.5:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://217.74.72.11:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://217.74.72.4:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://195.150.20.242:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://217.74.72.10:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://31.192.216.5:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://195.150.20.244:8000/rmf_swieta", + "Type":"Live" + }, + { + "StreamId":9652698, + "Reliability":95, + "Bandwidth":128, + "HasPlaylist":false, + "MediaType":"MP3", + "Url":"http://195.150.20.245:8000/rmf_swieta", + "Type":"Live" + } + ] +} diff --git a/tools/files/user.json b/tools/files/user.json new file mode 100644 index 0000000..6ceda0e --- /dev/null +++ b/tools/files/user.json @@ -0,0 +1,641 @@ +{ + "markup": "\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n\r\n
\r\n
\r\n
    \r\n
  • \r\n \r\n Follow\r\n Following\r\n \r\n
  • \r\n
  • \r\n Share\r\n
  • \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n

Sergi Adamchuk

\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
    \r\n
  • \r\n
    27
    \r\n
    Following
    \r\n
  • \r\n
  • \r\n
    1
    \r\n
    Follower
    \r\n
  • \r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n\r\n
\r\n\r\n
\r\n

Stations

\r\n
\r\n \r\n \r\n Load More\r\n
\r\n

Users

\r\n \r\n
\r\n\r\n\r\n
\r\n\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n", + "testGroup": { + "tests": [], + "testIds": [] + }, + "payload": { + "HeroRibbon": { + "guideId": "u159012873", + "contentsUrl": "/userprofile/contents?username=adamchuk2168", + "selectedTabIndex": 0, + "shareData": { + "title": "Sergi Adamchuk", + "subtitle": "adamchuk2168", + "image": "https://graph.facebook.com/v2.0/679631021/picture?width=300&height=300", + "url": "http://tun.in/ukZvBP", + "shareText": "Check out Sergi Adamchuk on TuneIn", + "guideId": "u159012873", + "tuneType": "User", + "playGuideId": "", + "canEmbed": false, + "isDomainRestricted": false + } + }, + "GuideItemGroups": { + "groups": [ + { + "moreBaseUrl": "/profile/follows/?identifier=u159012873/follows/stations", + "hasMore": true, + "count": 20, + "guideItems": [ + { + "GuideId": "s23174", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s23174", + "Url": "/radio/TK99-995-s23174/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "TK99", + "Subtitle": "Grateful Dead - Touch of Grey", + "Image": "http://cdn-radiotime-logos.tunein.com/s23174q.png", + "PlayGuideId": "s23174", + "ShareText": "Listen to TK99 on TuneIn", + "ShareUrl": "http://tun.in/seo7Q", + "SourceItemId": null, + "TargetItemId": "s23174", + "Scope": "s23174", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s76596", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s76596", + "Url": "/radio/Radio-RMF-80s-s76596/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio RMF 80s", + "Subtitle": "Double - The Captain of Her Heart", + "Image": "http://cdn-radiotime-logos.tunein.com/s76596q.png", + "PlayGuideId": "s76596", + "ShareText": "Listen to Radio RMF 80s on TuneIn", + "ShareUrl": "http://tun.in/seC1u", + "SourceItemId": null, + "TargetItemId": "s76596", + "Scope": "s76596", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s1217", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s1217", + "Url": "/radio/Radio-RMF-FM-960-s1217/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio RMF FM", + "Subtitle": "Thomas Jack - Rivers", + "Image": "http://cdn-radiotime-logos.tunein.com/s1217q.png", + "PlayGuideId": "s1217", + "ShareText": "Listen to Better half of the day on Radio RMF FM on TuneIn", + "ShareUrl": "http://tun.in/sejpH", + "SourceItemId": null, + "TargetItemId": "s1217", + "Scope": "s1217", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s240742", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s240742", + "Url": "/radio/Radio-ROKS-Okean-Elzy-s240742/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio ROKS Okean Elzy", + "Subtitle": "Only Okean Elzy!", + "Image": "http://cdn-radiotime-logos.tunein.com/s240742q.png", + "PlayGuideId": "s240742", + "ShareText": "Listen to Radio ROKS Океан Ельзи on TuneIn", + "ShareUrl": "http://tun.in/sfjI0", + "SourceItemId": null, + "TargetItemId": "s240742", + "Scope": "s240742", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s246410", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s246410", + "Url": "/radio/Hit-FM-Okean-Elzy-s246410/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Hit FM Okean Elzy", + "Subtitle": "Only Okean Elzy!", + "Image": "http://cdn-radiotime-logos.tunein.com/s246410q.png", + "PlayGuideId": "s246410", + "ShareText": "Listen to Хіт FM Океан Ельзи on TuneIn", + "ShareUrl": "http://tun.in/sflcq", + "SourceItemId": null, + "TargetItemId": "s246410", + "Scope": "s246410", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s29195", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s29195", + "Url": "/radio/WGVM-1260-s29195/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "WGVM", + "Subtitle": "The DELTA'S Classic Rock Station!", + "Image": "http://cdn-radiotime-logos.tunein.com/s29195q.png", + "PlayGuideId": "s29195", + "ShareText": "Listen to WGVM on TuneIn", + "ShareUrl": "http://tun.in/seqGX", + "SourceItemId": null, + "TargetItemId": "s29195", + "Scope": "s29195", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s27360", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s27360", + "Url": "/radio/River-101-1013-s27360/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "River 101", + "Subtitle": "Vicksburg's Home For Country", + "Image": "http://cdn-radiotime-logos.tunein.com/s27360q.png", + "PlayGuideId": "s27360", + "ShareText": "Listen to River 101 on TuneIn", + "ShareUrl": "http://tun.in/seqdm", + "SourceItemId": null, + "TargetItemId": "s27360", + "Scope": "s27360", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s214828", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s214828", + "Url": "/radio/Radio-Lux-Lviv-1047-s214828/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio Lux Lviv", + "Subtitle": "Все будет люкс!", + "Image": "http://cdn-radiotime-logos.tunein.com/s214828q.png", + "PlayGuideId": "s214828", + "ShareText": "Listen to Люкс FM Львів on TuneIn", + "ShareUrl": "http://tun.in/sfcY2", + "SourceItemId": null, + "TargetItemId": "s214828", + "Scope": "s214828", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s131659", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s131659", + "Url": "/radio/Radio-Relax-1015-s131659/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio Relax", + "Subtitle": "Perry Como - Killing Me Softly", + "Image": "http://cdn-radiotime-logos.tunein.com/s131659q.png", + "PlayGuideId": "s131659", + "ShareText": "Listen to Радио Релакс on TuneIn", + "ShareUrl": "http://tun.in/seRlB", + "SourceItemId": null, + "TargetItemId": "s131659", + "Scope": "s131659", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s131601", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s131601", + "Url": "/radio/Radio-Business-938-s131601/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio Business", + "Subtitle": "Kiev", + "Image": "http://cdn-radiotime-logos.tunein.com/s131601q.png", + "PlayGuideId": "s131601", + "ShareText": "Listen to Радiо Бiзнес on TuneIn", + "ShareUrl": "http://tun.in/seRkF", + "SourceItemId": null, + "TargetItemId": "s131601", + "Scope": "s131601", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s25931", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s25931", + "Url": "/radio/Radio-EC-1000-s25931/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio EC", + "Subtitle": "Kiev", + "Image": "http://cdn-radiotime-logos.tunein.com/s25931q.png", + "PlayGuideId": "s25931", + "ShareText": "Listen to Radio EC on TuneIn", + "ShareUrl": "http://tun.in/sepQj", + "SourceItemId": null, + "TargetItemId": "s25931", + "Scope": "s25931", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s131665", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s131665", + "Url": "/radio/LoungeFM-994-s131665/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "LoungeFM", + "Subtitle": "Norah Jones - Thinking About You", + "Image": "http://cdn-radiotime-logos.tunein.com/s131665q.png", + "PlayGuideId": "s131665", + "ShareText": "Listen to LoungeFM on TuneIn", + "ShareUrl": "http://tun.in/seRlH", + "SourceItemId": null, + "TargetItemId": "s131665", + "Scope": "s131665", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s6122", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s6122", + "Url": "/radio/Hit-FM-964-s6122/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Hit FM", + "Subtitle": "Mylène Farmer - California", + "Image": "http://cdn-radiotime-logos.tunein.com/s6122q.png", + "PlayGuideId": "s6122", + "ShareText": "Listen to Хіт FM on TuneIn", + "ShareUrl": "http://tun.in/sekGO", + "SourceItemId": null, + "TargetItemId": "s6122", + "Scope": "s6122", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s55142", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s55142", + "Url": "/radio/Lux-FM-1031-s55142/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Lux FM", + "Subtitle": "Kiev", + "Image": "http://cdn-radiotime-logos.tunein.com/s55142q.png", + "PlayGuideId": "s55142", + "ShareText": "Listen to Люкс FM on TuneIn", + "ShareUrl": "http://tun.in/sexrs", + "SourceItemId": null, + "TargetItemId": "s55142", + "Scope": "s55142", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s137395", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s137395", + "Url": "/radio/Halychyna-FM-897-s137395/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Halychyna FM", + "Subtitle": "Файне радіо!", + "Image": "http://cdn-radiotime-logos.tunein.com/s137395q.png", + "PlayGuideId": "s137395", + "ShareText": "Listen to Галичина FM on TuneIn", + "ShareUrl": "http://tun.in/seSP7", + "SourceItemId": null, + "TargetItemId": "s137395", + "Scope": "s137395", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s77664", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s77664", + "Url": "/radio/Radio-Centrum-982-FM-Lublin-s77664/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio Centrum, 98.2 FM, Lublin", + "Subtitle": "Blizej muzyki!", + "Image": "http://cdn-radiotime-logos.tunein.com/s77664q.png", + "PlayGuideId": "s77664", + "ShareText": "Listen to Radio Centrum, 98.2 FM, Lublin on TuneIn", + "ShareUrl": "http://tun.in/seDiI", + "SourceItemId": null, + "TargetItemId": "s77664", + "Scope": "s77664", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s184909", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s184909", + "Url": "/radio/Radio-Domivka-s184909/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio Domivka", + "Subtitle": "100% Ukrainian radio!", + "Image": "http://cdn-radiotime-logos.tunein.com/s184909q.png", + "PlayGuideId": "s184909", + "ShareText": "Listen to Radio Domivka on TuneIn", + "ShareUrl": "http://tun.in/se5ct", + "SourceItemId": null, + "TargetItemId": "s184909", + "Scope": "s184909", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s246411", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s246411", + "Url": "/radio/Hit-FM-Ukrainian-Hits-s246411/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Hit FM Ukrainian Hits", + "Subtitle": "Антитіла - Шаленими Вітрами", + "Image": "http://cdn-radiotime-logos.tunein.com/s246411q.png", + "PlayGuideId": "s246411", + "ShareText": "Listen to Хіт FM Українські хіти on TuneIn", + "ShareUrl": "http://tun.in/sflcr", + "SourceItemId": null, + "TargetItemId": "s246411", + "Scope": "s246411", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s233173", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s233173", + "Url": "/radio/Radio-ROKS-Ukrainian-Rock-s233173/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "Radio ROKS Ukrainian Rock", + "Subtitle": "Alter Apes - Liar", + "Image": "http://cdn-radiotime-logos.tunein.com/s233173q.png", + "PlayGuideId": "s233173", + "ShareText": "Listen to Radio ROKS Український рок on TuneIn", + "ShareUrl": "http://tun.in/sfhKV", + "SourceItemId": null, + "TargetItemId": "s233173", + "Scope": "s233173", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + }, + { + "GuideId": "s190810", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "s190810", + "Url": "/radio/myRadioua-Ukrainian-Rock-s190810/", + "CanPlay": true, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": true, + "CanEmbed": true, + "Title": "myRadio.ua Ukrainian Rock", + "Subtitle": "Радіо української рок-музики українською мовою!", + "Image": "http://cdn-radiotime-logos.tunein.com/s190810q.png", + "PlayGuideId": "s190810", + "ShareText": "Listen to myRadio.ua Ukrainian Rock on TuneIn", + "ShareUrl": "http://tun.in/se6JE", + "SourceItemId": null, + "TargetItemId": "s190810", + "Scope": "s190810", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "Station" + } + ], + "limit": 20 + }, + { + "moreBaseUrl": "/profile/follows/?identifier=", + "hasMore": false, + "count": 3, + "guideItems": [ + { + "GuideId": "u124409363", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "u124409363", + "Url": "/user/naridna/", + "CanPlay": false, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": false, + "CanEmbed": false, + "Title": "Natalya Adamchuk", + "Subtitle": "naridna", + "Image": "https://graph.facebook.com/1785227319/picture?width=300&height=300", + "PlayGuideId": "", + "ShareText": "Check out Natalya Adamchuk on TuneIn", + "ShareUrl": "http://tun.in/uiEjEH", + "SourceItemId": "", + "TargetItemId": "", + "Scope": "", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "User" + }, + { + "GuideId": "u123021859", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "u123021859", + "Url": "/user/denngubsky/", + "CanPlay": false, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": false, + "CanEmbed": false, + "Title": "????? ???????", + "Subtitle": "denngubsky", + "Image": "https://cdn-cms.tunein.com/service/FM/user-logo_d.png", + "PlayGuideId": "", + "ShareText": "Check out ????? ??????? on TuneIn", + "ShareUrl": "http://tun.in/uiyuHB", + "SourceItemId": "", + "TargetItemId": "", + "Scope": "", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "User" + }, + { + "GuideId": "u122035229", + "Token": "BAUGAAAAAAAAAEhSAAAAAAAA", + "FollowGuideId": "u122035229", + "Url": "/user/oostrovetsky/", + "CanPlay": false, + "CanPlayInline": false, + "CanViewProfile": false, + "ForcePlay": false, + "CanEmbed": false, + "Title": "???? ???????????", + "Subtitle": "oostrovetsky", + "Image": "https://cdn-cms.tunein.com/service/FM/user-logo_d.png", + "PlayGuideId": "", + "ShareText": "Check out ???? ??????????? on TuneIn", + "ShareUrl": "http://tun.in/uiul2d", + "SourceItemId": "", + "TargetItemId": "", + "Scope": "", + "SubscriptionRequired": false, + "Presentation": "Default", + "Type": "User" + } + ], + "limit": 20 + } + ] + } + }, + "adSettings": { + "tuneInEnabled": true, + "rotationEnabled": true, + "rotationPeriod": 300, + "baseUrl": "http://ads.tunein.com", + "trackingId": "3909852c-d46d-4990-8df9-33a8b5908960", + "listingId": "", + "partnerKey": "RadioTime", + "supplementalProgramId": null, + "displaySlots": [ + { + "id": "div-gpt-ad-1398278077765-0", + "height": 250, + "width": 300, + "dimensions": [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ], + "extId": "15480783/ca-pub-1542925551861702/web_profile_unit", + "slotName": "user_side", + "adType": "Display", + "tuneInEnabled": true, + "audioBannerEnabled": true, + "googleAdsEnabled": true + }, + { + "id": "div-gpt-ad-1398279154193-0", + "height": 90, + "width": 728, + "dimensions": [ + [ + 728, + 90 + ], + [ + 970, + 66 + ] + ], + "extId": "15480783/ca-pub-1542925551861702/web_profile_top", + "slotName": "user_top", + "adType": "Display", + "tuneInEnabled": true, + "audioBannerEnabled": false, + "googleAdsEnabled": true + } + ], + "audioSlots": [], + "videoSlots": [], + "locale": "en-US", + "serverUtcTime": 130973480834744741, + "targeting": { + "env": "prod" + }, + "vendriPLID": "web01", + "openXHeader": "ox-d.tunein.servedbyopenx.com/w/1.0/jstag?nc=15480783-Tunein" + }, + "pageTitle": "Sergi Adamchuk", + "userAnonymous": true, + "metaTagContent": " \r\n \r\n \r\n \r\n \r\n \r\n\r\n\r\n" +} \ No newline at end of file diff --git a/tools/parse_json.py b/tools/parse_json.py new file mode 100644 index 0000000..da414d1 --- /dev/null +++ b/tools/parse_json.py @@ -0,0 +1,66 @@ +import urllib2, json +from pprint import pprint + +URL_STATION = 'http://tunein.com/radio/-%s/' + +#################################################################################################### +def GetJson(url): + + print ("Requesting "+url) + request = urllib2.Request( + url = url, + headers={ + 'x-requested-with': 'XMLHttpRequest', + 'Accept: application/json': 'text/javascript, */*; q=0.01'} + ) + response = urllib2.urlopen(request) + text = response.read() + + # print ("The response: "+text) + + return json.loads(text) + +#################################################################################################### +class TuneInStation: + + def __init__(self, id='', url=''): + if not id: + id = GetStationId(url) + + self.js = GetJson(URL_STATION % id)['payload']['Station'] + self.broadcast = self.js['broadcast'] + self.echo = self.broadcast['EchoData'] + + # Log.Debug('Station id: %s, json: %s' % (id, self.__js)) + # print('Station id: %s, json: %s' % (id, self.js)) + + @property + def id(self): + return self.echo['targetGuideId'] + + @property + def title(self): + return self.broadcast['Title'] + + @property + def description(self): + return self.js['description'] + + @property + def image_url(self): + return self.broadcast['Logo'] + + @property + def summary(self): + return self.echo['subtitle'] + + @property + def playing(self): + return self.broadcast['SongPlayingTitle'] + + @property + def stream_url(self): + return self.broadcast['StreamUrl'] + +station = TuneInStation('s119801') +print (station.stream_url)