astrXbian/.install/.kodi/addons/plugin.video.filmsforaction/resources/lib/ffa_api.py

225 lines
10 KiB
Python

# _*_ coding: utf-8 _*_
'''
Films For Action API lib: library functions for Films For Action add-on.
Copyright (C) 2014 José Antonio Montes (jamontes)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Description:
These funtions are called from the main plugin module, aimed to ease
and simplify the add-on development process.
Release 0.1.6
'''
import lutil as l
root_url = 'https://www.filmsforaction.org'
def set_debug(debug_flag, func_log=l.local_log):
"""This function is a wrapper to setup the debug flag into the lutil module"""
l.set_debug_mode(debug_flag, func_log)
def get_categories():
"""This function gets the categories list from the FFA website."""
category_pattern = "'topic', '([0-9]+)'[^>]+?>([^<]+?)</a>"
category_url = 'https://www.filmsforaction.org/library/?category=all+videos&topic=%s'
buffer_url = l.carga_web(root_url)
category_list = []
topic_list = []
for topic, category_name in l.find_multiple(buffer_url, category_pattern):
if topic not in topic_list:
url = category_url % topic
category_list.append((url, category_name))
topic_list.append(topic)
return category_list
def get_videolist(url, cat_menu=""):
"""This function gets the video list from the FFA website and returns them in a pretty data format."""
video_entry_sep = 'content-view'
video_url_pattern = '["\'](/watch/[^/]*?/)'
video_thumb_pattern = '["\'](/img/[^"\']*?)["\']'
video_title_pattern = '<a href=["\']/watch/[^/]*?/["\'][ ]*?>([^<]+?)</a>'
video_plot_pattern = '<span class="content-description">([^<]*?)</span>'
video_duration_pattern = '([0-9]+[ ]+[Mm]in)'
video_rating_pattern = '([0-9.]+[ ]+[Ss]tars)'
video_views_pattern = '([0-9,]+[ ]+[Vv]iews)'
page_num_pattern = 'href=["\']/library/([0-9]+)/'
page_num_url_pattern = 'href=["\'](/library/%d/[^"\']*?)["\']'
page_num_cur_pattern = '/library/([0-9]+)/'
buffer_url = l.carga_web(url)
video_list = []
reset_cache = False
current_page_num = int(l.find_first(url, page_num_cur_pattern) or '1')
last_page_num = int(max(l.find_multiple(buffer_url, page_num_pattern) or ('1',), key=int))
if current_page_num != 1:
prev_page_num = current_page_num - 1
previous_page_url = root_url + l.find_first(buffer_url, page_num_url_pattern % prev_page_num)
video_entry = { 'url': previous_page_url, 'title': '<< %s (%d)' % (cat_menu, prev_page_num), 'IsPlayable': False }
video_list.append(video_entry)
reset_cache = True
category = "Video" # The category is no longer included in the latest website change.
for video_section in buffer_url.split(video_entry_sep)[1:]:
url = l.find_first(video_section, video_url_pattern)
if not url:
continue # Sometimes in the search menu can appear articles and other sort of entries rather than videos.
thumb = l.find_first(video_section, video_thumb_pattern)
title = l.find_first(video_section, video_title_pattern)
plot = l.find_first(video_section, video_plot_pattern)
duration = l.find_first(video_section, video_duration_pattern)
rating = l.find_first(video_section, video_rating_pattern)
views = l.find_first(video_section, video_views_pattern)
l.log('Video info. url: "%s" thumb: "%s" title: "%s"' % (url, thumb, title))
l.log('Video tags. duration: "%s" rating: "%s" views: "%s"' % (duration, rating, views))
video_entry = {
'url' : root_url + url,
'title' : title.strip() or '.',
'thumbnail' : root_url + thumb,
'plot' : "%s\n%s - %s - %s" % (
plot.strip(),
duration,
views,
rating,
),
'duration' : int(duration.split()[0]) * 60 if duration else 0,
'rating' : rating.split()[0] if rating else '',
'genre' : category,
'IsPlayable' : True
}
video_list.append(video_entry)
if current_page_num < last_page_num:
next_page_num = current_page_num + 1
next_page_url = root_url + l.find_first(buffer_url, page_num_url_pattern % next_page_num)
video_entry = { 'url': next_page_url, 'title': '>> %s (%d/%d)' % (cat_menu, next_page_num, last_page_num), 'IsPlayable': False }
video_list.append(video_entry)
return { 'video_list': video_list, 'reset_cache': reset_cache }
def get_search_url(search_string):
"""This function returns the search encoded URL to find the videos from the input search string"""
return 'https://www.filmsforaction.org/library/?search=' + l.get_url_encoded(search_string)
def get_playable_url(url):
"""This function returns a playable URL parsing the different video sources available from the iframe link"""
video_patterns = (
('vimeo1', 'vimeo.com/video/([0-9]+)', 'vimeo'),
('vimeo2', 'vimeo.com%2Fvideo%2F([0-9]+)', 'vimeo'),
('youtube1', 'videoId: "([0-9A-Za-z_-]{11})', 'youtube'),
('youtube2', 'youtube.com%2Fwatch%3Fv%3D([0-9A-Za-z_-]{11})', 'youtube'),
('youtube3', 'youtube.com%2Fembed%2F([0-9A-Za-z_-]{11})', 'youtube'),
('youtube4', 'youtube.com/embed/([0-9A-Za-z_-]{11})', 'youtube'),
('dailymotion1', ' src="[htp:]*?//www.dailymotion.com/embed/video/([0-9a-zA-Z]+)', 'dailymotion'),
('dailymotion2', 'www.dailymotion.com%2Fembed%2Fvideo%2F(.*?)%', 'dailymotion'),
('archiveorg1', ' src="(https://archive.org/embed/[^"]*?)"', 'archiveorg'),
('kickstarter1', ' src="(https://www.kickstarter.com/[^"]*?)"', 'kickstarter'),
('tagtele1', ' src="(http://www.tagtele.com/embed/[^"]*?)"', 'tagtele'),
)
buffer_url = l.carga_web(url)
for pattern_name, pattern, source in video_patterns:
video_id = l.find_first(buffer_url, pattern)
if video_id:
l.log('We have found this video_id "%s" using the pattern: "%s"' % (video_id, pattern_name))
try:
playable_url = eval("get_playable_%s_url(video_id)" % source)
break
except:
l.log("There was a problem using the pattern '%s' on this video link: '%s'\n" % (pattern_name, url))
return ''
else:
l.log("Sorry, but we cannot support the type of video for this link yet:\n'%s'" % url)
playable_url = ''
return playable_url
def get_playable_vimeo_url(video_id):
"""This function returns the playable URL for the Vimeo embedded video from the video_id retrieved."""
video_quality_pattern = '"profile":[0-9]+,"width":([0-9]+),.*?,"url":"([^"]*?)"'
quality_list = ('640', '720', '480', '320', '960', '1280', '1920')
video_info_url = 'https://player.vimeo.com/video/' + video_id
buffer_link = l.carga_web(video_info_url)
video_options = dict((quality, video) for quality, video in l.find_multiple(buffer_link, video_quality_pattern))
if len(video_options):
l.log("List of video options: "+repr(video_options))
for quality in quality_list:
if quality in video_options:
return video_options.get(quality)
# This quality isn't normalized as it doesn't appear into the quality_list.
return video_options.get(video_options.keys()[0])
return ""
def get_playable_youtube_url(video_id):
"""This function returns the URL path to call the Youtube add-on with the video_id retrieved."""
return 'plugin://plugin.video.youtube/play/?video_id=' + video_id
def get_playable_dailymotion_url(video_id):
"""This function returns the playable URL for the Dalymotion embedded video from the video_id retrieved."""
daily_video_pattern = '"([0-9]+)":\[[^]]*?{"type":"video\\\/mp4","url":"([^"]+?)"'
daily_video_qualities = ('480', '720', '380', '240')
daily_url = 'http://www.dailymotion.com/embed/video/' + video_id
buffer_link = l.carga_web(daily_url)
video_options = dict((quality, video) for quality, video in l.find_multiple(buffer_link, daily_video_pattern))
l.log("List of video options: "+repr(video_options))
for quality_option in daily_video_qualities:
if quality_option in video_options:
video_url = video_options.get(quality_option).replace('\\','')
return video_url
return ""
def get_playable_archiveorg_url(archive_url):
"""This function returns the playable URL for the Archive.org embedded video from the video link retrieved."""
pattern_archive_video = '<meta property="og:video" content="(.+?)"'
buffer_link = l.carga_web(archive_url)
return l.find_first(buffer_link, pattern_archive_video)
def get_playable_kickstarter_url(kickstarter_url):
"""This function returns the playable URL for the Kickstarter embedded video from the video link retrieved."""
pattern_kickstarter_video = ' data-video-url="(.+?)"'
buffer_link = l.carga_web(kickstarter_url)
return l.find_first(buffer_link, pattern_kickstarter_video)
def get_playable_tagtele_url(tagtele_url):
"""This function returns the playable URL for the Tagtele embedded video from the video link retrieved."""
pattern_tagtele_video = " file: '(.+?)'"
buffer_link = l.carga_web(tagtele_url)
return l.find_first(buffer_link, pattern_tagtele_video)