Skip to content
This repository has been archived by the owner on Feb 20, 2019. It is now read-only.

Commit

Permalink
Merge branch 'release/1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Kévin Darcel committed May 7, 2017
2 parents dc103be + bff21d6 commit 469a03b
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 89 deletions.
100 changes: 12 additions & 88 deletions Contents/Code/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import re

TITLE = 'MYTF1'
ART = 'art-default.jpg'
ICON = 'icon-default.png'
Expand All @@ -9,8 +7,6 @@
PROGRAMS = '%s/programmes-tv' % BASE_URL
VIDEOS = '%s%s/videos'

RE_MEDIA_ID = Regex("c_idwat = '(?P<media_id>[^']+)'")

####################################################################################################
def Start():

Expand Down Expand Up @@ -107,98 +103,26 @@ def Videos(video_cat, prog_url):
else:
img = video.xpath('./div/a/div/picture/source/@srcset')[0]

url = video.xpath('./div/div/a/@href')[0]
url = BASE_URL + video.xpath('./div/div/a/@href')[0]
title = video.xpath('./div/div/a/div/p[contains(@class, "title")]/text()')[0]
summary = video.xpath('./div/div/a/div/p[contains(@class, "stitle")]/text()')[0]
thumb = 'http:' + img.split(',')[-1].split(' ')[0]
duration = video.xpath('./div/div/a/div/p[contains(@class, "uptitle")]/span/text()')[0]
originally_available_at = video.xpath('./div/div/a/div/p[contains(@class, "uptitle")]/span/text()')[2]
try:
duration = int(video.xpath('./div/div/a/div/p[contains(@class, "uptitle")]/span/text()')[0]) * 1000
except:
duration = None
try:
oaa = Datetime.ParseDate(video.xpath('./div/div/a/div/p[contains(@class, "uptitle")]/span/text()')[2])
except:
oaa = None

oc.add(VideoClipObject(
key=Callback(VideoDetails, title=title, summary=summary, thumb=thumb, duration=duration, originally_available_at=originally_available_at, rating_key=title, url=url),
url=url,
title=title,
summary=summary,
thumb=thumb,
rating_key=title
duration=duration,
originally_available_at=oaa
))

return oc


@route(PREFIX + '/video/details')
def VideoDetails(title, summary, thumb, duration, originally_available_at, rating_key, url):

oc = ObjectContainer()

oc.add(VideoClipObject(
key=Callback(VideoDetails, title=title, summary=summary, thumb=thumb, duration=duration, originally_available_at=originally_available_at, rating_key=title, url=url),
title=title,
summary=summary,
thumb=thumb,
duration=int(duration) * 1000,
originally_available_at=Datetime.ParseDate(originally_available_at).date(),
rating_key=rating_key,
items=[
MediaObject(
protocol=Protocol.HLS,
#bitrate=bitrate,
audio_channels=2,
audio_codec=AudioCodec.AAC,
video_codec=VideoCodec.H264,
video_resolution=video_resolution,
#container=Container.MP4,
container=Container.MPEGTS,
video_frame_rate=25,
optimized_for_streaming=True,
parts=[
PartObject(
key=HTTPLiveStreamURL(Callback(PlayVideo, url=url))
)
]
) for video_resolution, bitrate in [(720, 2719), (540, 1977), (360, 1340), (360, 704), (270, 492), (234, 280)]
]
))

return oc

####################################################################################################
@indirect
@route(PREFIX + '/video/play.m3u8')
def PlayVideo(url):

playlist_url = GetVideoPlaylistURL(url)

return IndirectResponse(VideoClipObject, key=playlist_url)


####################################################################################################
def GetVideoPlaylistURL(prog_url):

page = HTTP.Request(BASE_URL + prog_url).content
media_id = RE_MEDIA_ID.search(page).group('media_id')

def GetAuthKey(app_name, media_id):

secret = String.Decode('VzNtMCMxbUZJ')
timestamp = HTTP.Request('http://www.wat.tv/servertime2', cacheTime=60).content

string = '%s-%s-%s-%s-%s' % (media_id, secret, app_name, secret, timestamp)

auth_key = Hash.MD5(string) + '/' + timestamp
return auth_key

user_agent = 'MyTF1/16090602 CFNetwork/808.1.4 Darwin/16.1.0'
app_name = 'sdk/Iphone/1.0'
method = 'getUrl'
auth_key = GetAuthKey(app_name, media_id)
version = '1.8.14'
hosting_application_name = 'com.tf1.applitf1'
hosting_application_version = '6.3'

data = ('appName=%s&method=%s&mediaId=%s&authKey=%s&version=%s&hostingApplicationName=%s&hostingApplicationVersion=%s') % (app_name, method, media_id, auth_key, version, hosting_application_name, hosting_application_version)
payload = JSON.ObjectFromString(HTTP.Request('http://api.wat.tv/services/Delivery', headers={'User-Agent': user_agent}, cacheTime=60, data=data).content)

m3u8_url = re.sub(r'&?bw(?:max|min)=\d+', '', payload['message'])
Log.Debug('Playing: ' + m3u8_url)

return m3u8_url
2 changes: 1 addition & 1 deletion Contents/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<key>CFBundleIdentifier</key>
<string>com.plexapp.plugins.mytf1</string>
<key>CFBundleVersion</key>
<string>1.0.2</string>
<string>1.1.0</string>
<key>PlexFrameworkVersion</key>
<string>2</string>
<key>PlexClientPlatforms</key>
Expand Down
22 changes: 22 additions & 0 deletions Contents/Services/ServiceInfo.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>URL</key>
<dict>
<key>TF1</key>
<dict>
<key>Identifier</key>
<string>com.plexapp.plugins.mytf1</string>
<key>URLPatterns</key>
<array>
<string>^http://www\.tf1\.fr/.+</string>
</array>
<key>TestURLs</key>
<array>
<string>http://www.tf1.fr/tmc/quotidien-avec-yann-barthes/videos/miss-france-2017-premier-talk-show-d-alicia-aylies.html</string>
</array>
</dict>
</dict>
</dict>
</plist>
96 changes: 96 additions & 0 deletions Contents/Services/URL/TF1/ServiceCode.pys
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import re

RE_MEDIA_ID = Regex("c_idwat = '(?P<media_id>[^']+)'")

####################################################################################################
def MetadataObjectForURL(url):

html = HTML.ElementFromURL(url)

container = html.xpath('//div[contains(@id, "contentPlayer")]/div/div/div/div[contains(@class, "container")]')[0]

title = container.xpath('./div[contains(@class, "content")]/h1[contains(@class, "title")]/text()')[0]
summary = container.xpath('./div[contains(@class, "content")]/div[contains(@class, "description")]/p/text()')[0]
thumb = 'http:' + container.xpath('./div[contains(@class, "iframe")]/meta[contains(@itemprop, "thumbnailUrl")]/@content')[0]
try:
duration = int(container.xpath('./div[contains(@class, "iframe")]/meta[contains(@itemprop, "duration")]/@content')[0]) * 1000
except:
duration = None
try:
oaa = Datetime.ParseDate(container.xpath('./div[contains(@class, "iframe")]/meta[contains(@itemprop, "uploadDate")]/@content')[0])
except:
oaa = None

return VideoClipObject(
title=title,
summary=summary,
thumb=thumb,
duration=duration,
originally_available_at=oaa
)


####################################################################################################
@deferred
def MediaObjectsForURL(url):

return [
MediaObject(
protocol=Protocol.HLS,
#bitrate=bitrate,
audio_channels=2,
audio_codec=AudioCodec.AAC,
video_codec=VideoCodec.H264,
video_resolution=video_resolution,
#container=Container.MP4,
container=Container.MPEGTS,
video_frame_rate=25,
optimized_for_streaming=True,
parts=[
PartObject(
key=HTTPLiveStreamURL(Callback(PlayVideo, url=url))
)
]
) for video_resolution, bitrate in [(720, 2719), (540, 1977), (360, 1340), (360, 704), (270, 492), (234, 280)]
]

####################################################################################################
@indirect
def PlayVideo(url):

playlist_url = GetVideoPlaylistURL(url)

return IndirectResponse(VideoClipObject, key=playlist_url)


####################################################################################################
def GetVideoPlaylistURL(prog_url):

page = HTTP.Request(prog_url).content

media_id = RE_MEDIA_ID.search(page).group('media_id')

def GetAuthKey(app_name, media_id):

secret = String.Decode('VzNtMCMxbUZJ')
timestamp = HTTP.Request('http://www.wat.tv/servertime2', cacheTime=60).content

string = '%s-%s-%s-%s-%s' % (media_id, secret, app_name, secret, timestamp)

auth_key = Hash.MD5(string) + '/' + timestamp
return auth_key

user_agent = 'MyTF1/16090602 CFNetwork/808.1.4 Darwin/16.1.0'
app_name = 'sdk/Iphone/1.0'
method = 'getUrl'
auth_key = GetAuthKey(app_name, media_id)
version = '1.8.14'
hosting_application_name = 'com.tf1.applitf1'
hosting_application_version = '6.3'

data = ('appName=%s&method=%s&mediaId=%s&authKey=%s&version=%s&hostingApplicationName=%s&hostingApplicationVersion=%s') % (app_name, method, media_id, auth_key, version, hosting_application_name, hosting_application_version)
payload = JSON.ObjectFromString(HTTP.Request('http://api.wat.tv/services/Delivery', headers={'User-Agent': user_agent}, cacheTime=60, data=data).content)

m3u8_url = re.sub(r'&?bw(?:max|min)=\d+', '', payload['message'])

return m3u8_url

0 comments on commit 469a03b

Please sign in to comment.