Skip to content

Commit

Permalink
Merge branch 'devel'
Browse files Browse the repository at this point in the history
- Add icons with bundle
- Refactor to use PF datetime function
- Add RutubeEmbed URL service and fix Rutube video
  • Loading branch information
KOL committed Apr 12, 2015
2 parents f2bc4a6 + fb63eef commit 77b2be8
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 21 deletions.
28 changes: 9 additions & 19 deletions Contents/Code/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from urllib import urlencode
from datetime import date

PREFIX_V = '/video/vkontakte'
PREFIX_M = '/music/vkontakte'
PREFIX_P = '/photos/vkontakte'

ART = 'art-default.jpg'
ICON = 'icon-default.png'
ICON_V = 'icon-video.png'
ICON_M = 'icon-music.png'
ICON_P = 'icon-photo.png'
TITLE = u'%s' % L('Title')

VK_APP_ID = 4510304
Expand Down Expand Up @@ -75,7 +77,7 @@ def ValidateAuth():
# Video
###############################################################################

@handler(PREFIX_V, u'%s' % L('VideoTitle'), R(ART), R(ICON))
@handler(PREFIX_V, u'%s' % L('VideoTitle'), thumb=ICON_V)
def VideoMainMenu():
if not Dict['token']:
return BadAuthMessage()
Expand Down Expand Up @@ -179,7 +181,7 @@ def VideoPlay(uid, vid):
})

if not res or not res['count']:
return NoContents()
raise Ex.MediaNotAvailable

item = res['items'][0]

Expand Down Expand Up @@ -252,7 +254,7 @@ def AddVideoAlbums(oc, uid, offset=0):
def GetVideoObject(item):
if 'external' in item['files']:
return URLService.MetadataObjectForURL(
NormalizeExternalUrl(item['files']['external'])
item['files']['external']
)

return VideoClipObject(
Expand All @@ -267,7 +269,7 @@ def GetVideoObject(item):
summary=item['description'],
thumb=item['photo_320'],
source_icon=R(ICON),
originally_available_at=date.fromtimestamp(item['date']),
originally_available_at=Datetime.FromTimestamp(item['date']),
duration=(item['duration']*1000),
items=[
MediaObject(
Expand All @@ -288,7 +290,7 @@ def GetVideoObject(item):
# Music
###############################################################################

@handler(PREFIX_M, u'%s' % L('MusicTitle'), R(ART), R(ICON))
@handler(PREFIX_M, u'%s' % L('MusicTitle'), thumb=ICON_M)
def MusicMainMenu():
if not Dict['token']:
return BadAuthMessage()
Expand Down Expand Up @@ -468,7 +470,7 @@ def GetTrackObject(item):
# Photos
###############################################################################

@handler(PREFIX_P, u'%s' % L('PhotosTitle'), R(ART), R(ICON))
@handler(PREFIX_P, u'%s' % L('PhotosTitle'), thumb=ICON_P)
def PhotoMainMenu():
if not Dict['token']:
return BadAuthMessage()
Expand Down Expand Up @@ -684,18 +686,6 @@ def NoContents():
)


def NormalizeExternalUrl(url):
# Rutube service crutch
if Regex('//rutube.ru/[^/]+/embed/[0-9]+').search(url):
url = HTML.ElementFromURL(url, cacheTime=CACHE_1WEEK).xpath(
'//link[contains(@rel, "canonical")]'
)
if url:
return url[0].get('href')

return url


def GetGroups(callback_action, callback_page, uid, offset):
'''Get groups container with custom callback'''
oc = ObjectContainer(
Expand Down
4 changes: 2 additions & 2 deletions Contents/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<key>CFBundleSignature</key>
<string>hook</string>
<key>CFBundleVersion</key>
<string>2.4</string>
<string>2.6</string>

<key>PlexClientPlatforms</key>
<string>*</string>
Expand All @@ -37,4 +37,4 @@
<key>PlexPluginDevMode</key>
<string>0</string>
</dict>
</plist>
</plist>
Binary file added Contents/Resources/icon-music.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Contents/Resources/icon-photo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Contents/Resources/icon-video.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions Contents/Services/ServiceInfo.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>URL</key>
<dict>
<key>RutubeEmbed</key>
<dict>
<key>URLPatterns</key>
<array>
<string>http:\/\/rutube\.ru\/play\/embed/\d+</string>
</array>
</dict>
</dict>
</dict>
</plist>
132 changes: 132 additions & 0 deletions Contents/Services/URL/RutubeEmbed/ServiceCode.pys
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2014, KOL
# All rights reserved.

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the <organization> nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


def GetVideoData(url):
try:
html = HTML.ElementFromURL(url)
except Ex.HTTPError, e:
if e.code == 404:
raise Ex.MediaNotAvailable

try:
ret = {}
for key in ('trackinfo', 'options'):
ret[key] = JSON.ObjectFromString(
html.xpath('//div[@id="'+key+'"]')[0].get('data-value')
)

return ret
except:
pass
return False


def GetVideoUrls(url):
item = GetVideoData(url)
if not item:
raise Ex.MediaNotAvailable

try:
res = HTTP.Request(
item['options']['video_balancer']['m3u8']
).content.splitlines()
except:
raise Ex.MediaNotAvailable

ret = {}
for url in res:
if url and url[:1] != '#':
key = Regex('.+(i=\d+x(\d+)_\d+)').search(url)
resolution = int(key.group(2))
key = key.group(1)

ret[key] = {
'resolution': 240,
'url': url,
}

if resolution >= 700:
ret[key]['resolution'] = 720
elif resolution >= 400:
ret[key]['resolution'] = 480
elif resolution >= 280:
ret[key]['resolution'] = 360

if not len(ret):
raise Ex.MediaNotAvailable

return ret


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

item = GetVideoData(url)
if not item:
raise Ex.MediaNotAvailable

return VideoClipObject(
title=u'%s' % item['trackinfo']['title'],
thumb=u'%s' % item['options']['thumbnail_url'],
duration=int(item['trackinfo']['duration'])*1000
)


############################################################################
def MediaObjectsForURL(url):

info = GetVideoUrls(url)

return [
MediaObject(
parts=[
PartObject(key=Callback(
PlayVideo, url=item['url']
))
],
video_resolution=item['resolution'],
audio_channels=2,
container='mpegts',
video_codec=VideoCodec.H264,
audio_codec=AudioCodec.AAC,
optimized_for_streaming=True
) for item in sorted(
info.values(),
key=lambda k: k['resolution'],
reverse=True
)
]


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

Log.Debug('Play %s' % url)

return IndirectResponse(VideoClipObject, key=HTTPLiveStreamURL(url))

0 comments on commit 77b2be8

Please sign in to comment.