Compare commits
No commits in common. "master" and "v0.1" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
*.pyo
|
|
102
addon.py
102
addon.py
@ -5,14 +5,12 @@ import xbmcvfs
|
|||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
|
import urllib
|
||||||
import tmdb
|
|
||||||
|
|
||||||
ADDON = xbmcaddon.Addon()
|
ADDON = xbmcaddon.Addon()
|
||||||
CWD = ADDON.getAddonInfo('path').decode('utf-8')
|
CWD = ADDON.getAddonInfo('path').decode('utf-8')
|
||||||
#CWD = ADDON.getAddonInfo('path') # for kodi 19
|
#CWD = ADDON.getAddonInfo('path') # for kodi 19
|
||||||
|
|
||||||
# reads program names from JSON files and returns a dict
|
|
||||||
def list_programs(cinematic_path):
|
def list_programs(cinematic_path):
|
||||||
dirs, files = xbmcvfs.listdir(cinematic_path)
|
dirs, files = xbmcvfs.listdir(cinematic_path)
|
||||||
programs = {}
|
programs = {}
|
||||||
@ -25,7 +23,6 @@ def list_programs(cinematic_path):
|
|||||||
programs[program_data['name']] = filename
|
programs[program_data['name']] = filename
|
||||||
return programs
|
return programs
|
||||||
|
|
||||||
# shows the selection dialog with program names, returns JSON filename
|
|
||||||
def show_dialog(programs):
|
def show_dialog(programs):
|
||||||
entries = programs.keys()
|
entries = programs.keys()
|
||||||
dialog = xbmcgui.Dialog()
|
dialog = xbmcgui.Dialog()
|
||||||
@ -33,7 +30,6 @@ def show_dialog(programs):
|
|||||||
del dialog
|
del dialog
|
||||||
return programs[entries[ret]]
|
return programs[entries[ret]]
|
||||||
|
|
||||||
# get a number of random files from a directory
|
|
||||||
def files_from_dir(count, location):
|
def files_from_dir(count, location):
|
||||||
dirs, files = xbmcvfs.listdir(location)
|
dirs, files = xbmcvfs.listdir(location)
|
||||||
files = random.sample(files, count)
|
files = random.sample(files, count)
|
||||||
@ -41,7 +37,50 @@ def files_from_dir(count, location):
|
|||||||
files[i] = location + files[i]
|
files[i] = location + files[i]
|
||||||
return files
|
return files
|
||||||
|
|
||||||
# reads the JSON file and conducts a pre-program for the feature movie
|
def get_recommendations(apikey, movieid, language, choice):
|
||||||
|
print("getting %s for %d" % (choice, movieid))
|
||||||
|
baseurl = 'https://api.themoviedb.org/3/'
|
||||||
|
url = baseurl + 'movie/%d/%s?api_key=%s&language=%s'
|
||||||
|
url = url % (movieid, choice, apikey, language)
|
||||||
|
json_url = urllib.urlopen(url)
|
||||||
|
data = json.loads(json_url.read())
|
||||||
|
results = []
|
||||||
|
for result in data['results']:
|
||||||
|
results.append({'title': result['title'], 'movieid': result['id']})
|
||||||
|
return results
|
||||||
|
|
||||||
|
def get_movie_trailers(apikey, movieid, language):
|
||||||
|
print("getting trailers for %d" % movieid)
|
||||||
|
baseurl = 'https://api.themoviedb.org/3/'
|
||||||
|
url = baseurl + 'movie/%d?api_key=%s&language=%s&append_to_response=videos'
|
||||||
|
url = url % (movieid, apikey, language)
|
||||||
|
json_url = urllib.urlopen(url)
|
||||||
|
data = json.loads(json_url.read())
|
||||||
|
results = []
|
||||||
|
for result in data['videos']['results']:
|
||||||
|
if result['site'] == 'YouTube':
|
||||||
|
location = 'plugin://plugin.video.youtube/play/?video_id=%s' % result['key']
|
||||||
|
else:
|
||||||
|
next
|
||||||
|
results.append({'title': result['name'], 'type': result['type'], 'location': location})
|
||||||
|
return results
|
||||||
|
|
||||||
|
def get_trailers(apikey, recommendations, language, cliptype, count):
|
||||||
|
results = []
|
||||||
|
for recommendation in recommendations[:10]:
|
||||||
|
all_trailers = get_movie_trailers(apikey, recommendation['movieid'], language)
|
||||||
|
trailers = []
|
||||||
|
for trailer in all_trailers:
|
||||||
|
if trailer['type'] == cliptype:
|
||||||
|
trailers.append(trailer)
|
||||||
|
if len(trailers) > 0:
|
||||||
|
random.shuffle(trailers)
|
||||||
|
trailer = trailers[0]
|
||||||
|
results.append(trailer)
|
||||||
|
if len(results) == count:
|
||||||
|
break
|
||||||
|
return results
|
||||||
|
|
||||||
def conduct_program(program_file, feature):
|
def conduct_program(program_file, feature):
|
||||||
filehandle = xbmcvfs.File(program_file)
|
filehandle = xbmcvfs.File(program_file)
|
||||||
program_json = filehandle.read()
|
program_json = filehandle.read()
|
||||||
@ -58,18 +97,16 @@ def conduct_program(program_file, feature):
|
|||||||
entry = {'type': 'video', 'data': location}
|
entry = {'type': 'video', 'data': location}
|
||||||
program.append(entry)
|
program.append(entry)
|
||||||
elif settings['source'] == 'tmdbtrailer':
|
elif settings['source'] == 'tmdbtrailer':
|
||||||
TMDB = tmdb.Tmdb(apikey = settings['apikey'], language = settings['language'])
|
apikey = settings['apikey']
|
||||||
tmdbid = int(feature['tmdbid'])
|
tmdbid = int(feature['tmdbid'])
|
||||||
imdbid = feature['imdbid']
|
language = settings['language']
|
||||||
choice = settings['choice']
|
choice = settings['choice']
|
||||||
trailertype = settings['type']
|
trailertype = settings['type']
|
||||||
count = settings['count']
|
count = settings['count']
|
||||||
if not tmdbid:
|
|
||||||
tmdbid = TMDB.get_tmdbid(imdbid)
|
|
||||||
if tmdbid:
|
if tmdbid:
|
||||||
movies = TMDB.get_recommendations(tmdbid, choice)
|
movies = get_recommendations(apikey, tmdbid, language, choice)
|
||||||
random.shuffle(movies)
|
random.shuffle(movies)
|
||||||
trailers = TMDB.get_trailers(movies, trailertype, count)
|
trailers = get_trailers(apikey, movies, language, trailertype, count)
|
||||||
else:
|
else:
|
||||||
print("TODO: this feature has no tmdb id, find someting else to play")
|
print("TODO: this feature has no tmdb id, find someting else to play")
|
||||||
trailers = []
|
trailers = []
|
||||||
@ -95,70 +132,51 @@ def conduct_program(program_file, feature):
|
|||||||
program.append(entry)
|
program.append(entry)
|
||||||
return program
|
return program
|
||||||
|
|
||||||
# fetches information on the feature movie
|
|
||||||
def get_feature(movieid):
|
def get_feature(movieid):
|
||||||
query = '{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovieDetails", "params": {"movieid": %s, "properties": ["file", "mpaa", "uniqueid"]}, "id": "1"}' % movieid
|
query = '{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovieDetails", "params": {"movieid": %s, "properties": ["file", "mpaa", "uniqueid"]}, "id": "1"}' % movieid
|
||||||
json_response = xbmc.executeJSONRPC(query)
|
json_response = xbmc.executeJSONRPC(query)
|
||||||
response = json.loads(json_response)
|
response = json.loads(json_response)
|
||||||
if not 'tmdb' in response['result']['moviedetails']['uniqueid']:
|
if not 'tmdb' in response['result']['moviedetails']['uniqueid']:
|
||||||
response['result']['moviedetails']['uniqueid']['tmdb'] = 0
|
response['result']['moviedetails']['uniqueid']['tmdb'] = 0
|
||||||
if not 'imdb' in response['result']['moviedetails']['uniqueid']:
|
|
||||||
response['result']['moviedetails']['uniqueid']['tmdb'] = ''
|
|
||||||
feature = {
|
feature = {
|
||||||
'label': response['result']['moviedetails']['label'],
|
'label': response['result']['moviedetails']['label'],
|
||||||
'file': response['result']['moviedetails']['file'],
|
'file': response['result']['moviedetails']['file'],
|
||||||
'mpaa': response['result']['moviedetails']['mpaa'],
|
'mpaa': response['result']['moviedetails']['mpaa'],
|
||||||
'tmdbid': response['result']['moviedetails']['uniqueid']['tmdb'],
|
'tmdbid': response['result']['moviedetails']['uniqueid']['tmdb']
|
||||||
'imdbid': response['result']['moviedetails']['uniqueid']['imdb']
|
|
||||||
}
|
}
|
||||||
return feature
|
return feature
|
||||||
|
|
||||||
# entry point
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
for arg in sys.argv[1:]:
|
||||||
|
(name, value) = arg.split('=')
|
||||||
|
if name == 'dbid':
|
||||||
|
movieid = int(value)
|
||||||
|
|
||||||
cinematic_path = ADDON.getSettingString('cinematic_path')
|
cinematic_path = ADDON.getSettingString('cinematic_path')
|
||||||
# collect info about the selected feature movie
|
|
||||||
movieid = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8')
|
|
||||||
feature = get_feature(movieid)
|
feature = get_feature(movieid)
|
||||||
print(feature)
|
print(feature)
|
||||||
|
|
||||||
# let user select one of the JSON programs
|
|
||||||
programs = list_programs(cinematic_path)
|
programs = list_programs(cinematic_path)
|
||||||
program_file = cinematic_path + show_dialog(programs)
|
program_file = cinematic_path + show_dialog(programs)
|
||||||
|
|
||||||
# conduct and show playlist
|
|
||||||
program = conduct_program(program_file, feature)
|
program = conduct_program(program_file, feature)
|
||||||
|
|
||||||
print('=== playlist')
|
print('=== playlist')
|
||||||
for entry in program:
|
for entry in program:
|
||||||
print(" * [%s] -- %s" % (entry['type'], entry['data'].encode('utf-8')))
|
print(" * [%s] -- %s" % (entry['type'], entry['data']))
|
||||||
|
|
||||||
# close modal movie information window
|
|
||||||
if xbmc.getCondVisibility('Window.IsVisible(MovieInformation)'):
|
if xbmc.getCondVisibility('Window.IsVisible(MovieInformation)'):
|
||||||
xbmc.executebuiltin('Dialog.Close(MovieInformation)')
|
xbmc.executebuiltin('Dialog.Close(MovieInformation)')
|
||||||
|
|
||||||
"""
|
print('=== playing')
|
||||||
TODO: this is not the intended way of playing back the conducted playlist.
|
|
||||||
hints for a better implementation are welcome.
|
|
||||||
the plan is to play each video file in the list separately, so the addon is
|
|
||||||
able to perform further tasks in between, like controlling home automation
|
|
||||||
systems. unfortunately, research has to be done in order to find out how
|
|
||||||
that should be implemented.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# build kodi style playlist
|
|
||||||
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||||
playlist.clear()
|
playlist.clear()
|
||||||
for entry in program:
|
for entry in program:
|
||||||
|
print(" * [%s] -- %s" % (entry['type'], entry['data']))
|
||||||
if entry['type'] == 'video':
|
if entry['type'] == 'video':
|
||||||
playlist.add(entry['data'])
|
playlist.add(entry['data'])
|
||||||
else:
|
else:
|
||||||
# it is planned to implement features other than video playback
|
|
||||||
# e. g. call scripts in home automation to dim the lights
|
|
||||||
print(" unable to handle %s yet" % entry['type'])
|
print(" unable to handle %s yet" % entry['type'])
|
||||||
|
|
||||||
# start playback
|
|
||||||
xbmc.Player().play(playlist)
|
xbmc.Player().play(playlist)
|
||||||
xbmc.sleep(500)
|
xbmc.sleep(500)
|
||||||
|
|
||||||
# wait until program is finished
|
|
||||||
while xbmc.getCondVisibility('Player.HasMedia'):
|
while xbmc.getCondVisibility('Player.HasMedia'):
|
||||||
xbmc.sleep(100)
|
xbmc.sleep(100)
|
||||||
|
print('=== done playing')
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="script.cinemavision" name="Cinematic" version="0.3" provider-name="Cinematic">
|
<addon id="script.cinemavision" name="Cinematic" version="0.1" provider-name="Cinematic">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.25.0"/>
|
<import addon="xbmc.python" version="2.25.0"/>
|
||||||
<import addon="plugin.video.youtube" version="6.8.10"/>
|
|
||||||
</requires>
|
</requires>
|
||||||
<extension point="xbmc.python.script" library="addon.py">
|
<extension point="xbmc.python.script" library="addon.py">
|
||||||
<provides>executable</provides>
|
<provides>executable</provides>
|
||||||
|
93
tmdb.py
93
tmdb.py
@ -1,93 +0,0 @@
|
|||||||
# this is a small and single-purpose wrapper around the TMDB API
|
|
||||||
|
|
||||||
import json
|
|
||||||
import random
|
|
||||||
import urllib
|
|
||||||
|
|
||||||
class Tmdb:
|
|
||||||
def __init__(self, apikey, language):
|
|
||||||
self.baseurl = 'https://api.themoviedb.org/3/'
|
|
||||||
self.apikey = apikey
|
|
||||||
self.language = language
|
|
||||||
|
|
||||||
# fetches data from TMDB API
|
|
||||||
def fetch_from_tmdb(self, path, parameters):
|
|
||||||
apikey = "?api_key=%s" % self.apikey
|
|
||||||
url = self.baseurl + path + apikey + parameters
|
|
||||||
json_url = urllib.urlopen(url)
|
|
||||||
data = json.loads(json_url.read())
|
|
||||||
return data
|
|
||||||
|
|
||||||
# finds TMDB-id for a known IMDB-id, return 0 if nothing is found
|
|
||||||
def get_tmdbid(self, imdbid):
|
|
||||||
print("getting tmdbid for imdbid %s" % imdbid)
|
|
||||||
data = self.fetch_from_tmdb(
|
|
||||||
path = 'find/%s' % imdbid,
|
|
||||||
parameters = '&external_source=imdb_id'
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
tmdbid = data['movie_results'][0]['id']
|
|
||||||
print("tmdbid is %d" % tmdbid)
|
|
||||||
except:
|
|
||||||
tmdbid = 0
|
|
||||||
print("tmdbid could not be found")
|
|
||||||
return tmdbid
|
|
||||||
|
|
||||||
# get recommendations for a movie id
|
|
||||||
# choice is either "recommendations" or "similar"
|
|
||||||
def get_recommendations(self, movieid, choice):
|
|
||||||
print("getting %s for %d" % (choice, movieid))
|
|
||||||
data = self.fetch_from_tmdb(
|
|
||||||
path = 'movie/%d/%s' % (movieid, choice),
|
|
||||||
parameters = '&language=%s' % self.language
|
|
||||||
)
|
|
||||||
results = []
|
|
||||||
for result in data['results']:
|
|
||||||
results.append({
|
|
||||||
'title': result['title'],
|
|
||||||
'movieid': result['id']
|
|
||||||
})
|
|
||||||
return results
|
|
||||||
|
|
||||||
# get trailers, teasers, clips... for a movie id
|
|
||||||
def get_movie_trailers(self, movieid):
|
|
||||||
print("getting trailers for %d" % movieid)
|
|
||||||
data = self.fetch_from_tmdb(
|
|
||||||
path = 'movie/%d' % movieid,
|
|
||||||
parameters = '&language=%s&append_to_response=videos' % self.language
|
|
||||||
)
|
|
||||||
results = []
|
|
||||||
for result in data['videos']['results']:
|
|
||||||
if result['site'] == 'YouTube':
|
|
||||||
location = 'plugin://plugin.video.youtube/play/?video_id=%s' % result['key']
|
|
||||||
else:
|
|
||||||
# skip other sites
|
|
||||||
next
|
|
||||||
results.append({
|
|
||||||
'title': result['name'],
|
|
||||||
'type': result['type'],
|
|
||||||
'location': location
|
|
||||||
})
|
|
||||||
return results
|
|
||||||
|
|
||||||
# get a number of trailers of a certain kind for a list of recommended movies
|
|
||||||
def get_trailers(self, recommendations, cliptype, count):
|
|
||||||
results = []
|
|
||||||
# loop over ten out of the list of recommendations
|
|
||||||
random.shuffle(recommendations)
|
|
||||||
for recommendation in recommendations[:10]:
|
|
||||||
all_trailers = self.get_movie_trailers(recommendation['movieid'])
|
|
||||||
# filter to get only a certain kind of trailer
|
|
||||||
trailers = []
|
|
||||||
for trailer in all_trailers:
|
|
||||||
if trailer['type'] == cliptype:
|
|
||||||
trailers.append(trailer)
|
|
||||||
# get a random clip for this recommendation
|
|
||||||
if len(trailers) > 0:
|
|
||||||
random.shuffle(trailers)
|
|
||||||
trailer = trailers[0]
|
|
||||||
results.append(trailer)
|
|
||||||
# quit if enough clips have been collected
|
|
||||||
if len(results) == count:
|
|
||||||
break
|
|
||||||
return results
|
|
Loading…
x
Reference in New Issue
Block a user