summaryrefslogtreecommitdiff
path: root/plugin.image.daily_dilbert/addon.py
diff options
context:
space:
mode:
authorKolja Lampe <razzeee@gmail.com>2017-04-10 22:09:00 +0200
committerKolja Lampe <razzeee@gmail.com>2017-04-16 10:16:43 +0200
commitaf15e29fad7d298a26dfa1ca9be3dc058f714a01 (patch)
treed85cb85826f57140c4dd678fe0c6f427ef43f00d /plugin.image.daily_dilbert/addon.py
parenta01c8144cc8f6742565a8725e5ec40ebbce81120 (diff)
[plugin.image.daily_dilbert] 1.1.2
Diffstat (limited to 'plugin.image.daily_dilbert/addon.py')
-rw-r--r--plugin.image.daily_dilbert/addon.py320
1 files changed, 320 insertions, 0 deletions
diff --git a/plugin.image.daily_dilbert/addon.py b/plugin.image.daily_dilbert/addon.py
new file mode 100644
index 0000000..4726d9e
--- /dev/null
+++ b/plugin.image.daily_dilbert/addon.py
@@ -0,0 +1,320 @@
+####
+# This plugin was inspired by the original Dilbert plugin and the Garfield plugin.
+# I used those as basis and rewrote a lot of parts. Some code snippets still are re-used though.
+# Thanks to the coders of the two above named plugins!
+#
+# The intention was to get familiar with Python as I had no clue of it prior. The coding is for sure not
+# perfect and most likely not a good style. Helping comments are welcome - check the repo on github
+# https://github.com/bigcookie/plugin.image.daily_dilbert/
+# Desires: I would like to add images to the directories including thumbnails to allow right/left key browsing, but performance was too low. Any ideas to improve are welcome.
+#
+
+import urllib,urllib2,os,re,sys,datetime,xbmc,xbmcgui,xbmcaddon,xbmcplugin
+import pickle
+from calendar import monthrange
+from urlparse import parse_qs
+from random import randint, randrange
+
+### Global variables ###
+# I dont like global variables, but in this case it is easier/faster for me.
+# global variables including used Kodi arguments, which are not supposed to be changed or altered
+g_AddonHandle = int(sys.argv[1])
+g_AddonPath = xbmcaddon.Addon().getAddonInfo('path')
+g_AddonName = xbmcaddon.Addon().getAddonInfo('name')
+g_Args = parse_qs(sys.argv[2][1:])
+g_Args_Mode = g_Args.get('mode', None)
+g_Args_Year = g_Args['year'][0] if 'year' in g_Args else "";
+g_Args_Month= g_Args['month'][0] if 'month' in g_Args else "";
+g_Args_Day = g_Args['day'][0] if 'day' in g_Args else "";
+g_Args_Page = g_Args['page'][0] if 'page' in g_Args else "";
+g_Args_URL = sys.argv[0]
+g_CacheDir = os.path.join(g_AddonPath, "cache/") # Where to we store cached scraped Dilbert URLs
+g_Now = datetime.date.today() # Today
+
+### Dilbert Settings ###
+g_UseCache = True # Use the cache function
+g_PageItems = 7 # the page_number items will be pre-fetched and cached, so the higher the number, the longer it takes.
+g_PageItemsRandom = 7 # items to be loaded/pre-scraped in random menu
+### Dilbert Scraper Configuration
+g_BaseUrl = "http://www.dilbert.com/strip/" # Base URL, date will be added in form .../strip/yyy-mm-dd to get according Dilbert webpage
+g_Pattern = re.compile('"(http://assets.amuniversal.com/[a-z0-9]+)"') # Pattern to search on Dilberts webpage
+g_FirstDilbert = datetime.date(1989,4,16) # 1. Dilbert online available on 16.4.1989, required for date checks
+g_cachemodefile='lastmode.cache'
+g_cacherandomdates='randomdates.cache'
+### Dilbert icons and fanart
+g_Icons={}
+g_Icons['today'] = os.path.join(g_AddonPath, "resources/media/dil_today.png")
+g_Icons['recent'] = os.path.join(g_AddonPath, "resources/media/dil_recent.png")
+g_Icons['random'] = os.path.join(g_AddonPath, "resources/media/dil_random.png")
+g_Icons['date'] = os.path.join(g_AddonPath, "resources/media/dil_bydate.png")
+g_Icons['browse'] = os.path.join(g_AddonPath, "resources/media/dil_browse.png")
+g_Icons['next'] = os.path.join(g_AddonPath, "resources/media/dil_next.png")
+g_Icons['click'] = os.path.join(g_AddonPath, "resources/media/dil_click2show.png") # For necessary click action to show strip as no preview is available
+g_FanartImage=["","","","","",""]
+g_FanartImage[0]= os.path.join(g_AddonPath, "resources/media/fanart1.jpg") # Unused for now
+g_FanartImage[1]= os.path.join(g_AddonPath, "resources/media/fanart2.jpg") # For "Today"
+g_FanartImage[2]= os.path.join(g_AddonPath, "resources/media/fanart3.jpg") # For "Random"
+g_FanartImage[3]= os.path.join(g_AddonPath, "resources/media/fanart4.jpg") # For "Recent"
+g_FanartImage[4]= os.path.join(g_AddonPath, "resources/media/fanart5.jpg") # For "Browse"
+g_FanartImage[5]= os.path.join(g_AddonPath, "resources/media/fanart6.jpg") # For "By Date"
+
+
+### SubRoutines ###
+def build_url(query):
+ return g_Args_URL + '?' + urllib.urlencode(query)
+
+def add_directory(mode=None,year='',month='',day='', page='',name='',icon='',fanart=''):
+ url = build_url({'mode': mode, 'foldername': name, 'page': page, 'year': year, 'month': month, 'day': day})
+ li = xbmcgui.ListItem(name)
+ li.setArt({'icon':icon,'fanart':fanart})
+ xbmcplugin.addDirectoryItem(handle=g_AddonHandle, url=url, listitem=li, isFolder=True)
+
+def read_cache(date):
+ # Reads a cached scraped URL if existent
+ filename=date.strftime('%Y-%m-%d') + '.link'
+ return get_cacheddata(filename)
+
+def write_cache(date,url):
+ # Writes a scraped URL to the cache directory
+ filename=date.strftime('%Y-%m-%d') + '.link'
+ return set_cacheddata(url,filename)
+
+def get_cacheddata(filename):
+ # Reads a cached data from file if existent
+ # filename: lastmode/lastpage
+ cache_file=os.path.join(g_CacheDir, filename)
+ if os.path.isfile(cache_file):
+ try:
+ with open(cache_file, "r") as file:
+ data=file.read()
+ return data
+ except:
+ return ""
+ else:
+ return ""
+
+def set_cacheddata(param,filename):
+ # Writes a data to the cache directory
+ # filename: lastmode(lastpage)
+ cache_file=os.path.join(g_CacheDir, filename)
+ try:
+ with open(cache_file, "w") as file:
+ file.write(param)
+ return True
+ except:
+ return False
+
+def delete_cachefile(filename):
+ file=os.path.join(g_CacheDir, filename)
+ if os.path.isfile(file):
+ try:
+ os.remove(file)
+ return True
+ except:
+ return False
+ else:
+ return False
+
+def get_image_url(date):
+ # Scrapes Dilbert website for URL to get according Dilbert comic strip from given date.
+ # Can be used with or without caching function (controlled by g_UseCache).
+ url = read_cache(date) if g_UseCache else "";
+ if url:
+ return url
+ else:
+ req=urllib2.Request(g_BaseUrl+date.strftime("%Y-%m-%d")+'/')
+ req.add_header('User-Agent', ' Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3')
+ try:
+ response=urllib2.urlopen(req)
+ page=response.read()
+ response.close()
+ del response
+ except:
+ msg=[g_AddonName + ''': Couldn't scrape Dilbert webpage for the date '''+str(date.year)+'/'+str(date.month)+'/'+str(date.day)+'''. Please check your internet connection.''','''To be sure try http://www.dilbert.com/strip/1989-04-16 if the webpage is still alive.''']
+ xbmcaddon.Addon().log(msg, xbmc.LOGERROR)
+ xbmcgui.Dialog().ok('Error: ' + g_AddonName, str(msg[0]))
+ sys.exit(1)
+ match=g_Pattern.search(page)
+ if match:
+ if g_UseCache:
+ write_cache(date,match.group(1))
+ return match.group(1)
+ else:
+ return ""
+
+def create_random_date(starting_date, ending_date):
+ # Creates a random date between a starting and an end date
+ date_delta = ending_date - starting_date
+ random_days = randrange(date_delta.days)
+ return starting_date + datetime.timedelta(days=random_days)
+
+def create_mainmenu():
+ # Main menu of the plugin
+ add_directory(mode='today', name='Today\'s Dilbert',icon=g_Icons['today'], fanart=g_FanartImage[1])
+ add_directory(mode='last_week',page='1',name='Recent Dilberts',icon=g_Icons['recent'], fanart=g_FanartImage[2])
+ add_directory(mode='random',page='1',name='Random Dilberts',icon=g_Icons['random'], fanart=g_FanartImage[3])
+ add_directory(mode='browse',page='1',name='Browse Dates',icon=g_Icons['browse'], fanart=g_FanartImage[4])
+ add_directory(mode='enter',name='Open a specific date',icon=g_Icons['date'], fanart=g_FanartImage[5])
+ xbmcplugin.endOfDirectory(g_AddonHandle)
+
+def check_cachedirectory():
+ # Checks if cache directory exists. If not, try to create. If creation failed, return False
+ if g_UseCache == False:
+ return False
+ elif not os.path.exists(g_CacheDir):
+ try:
+ os.makedirs(g_CacheDir)
+ except:
+ msg=[g_AddonName + ': Cache directory \"' + g_CacheDir + '\" could not be created. No cache will be used even though it is enabled...']
+ xbmcaddon.Addon().log(msg, xbmc.LOGERROR)
+ return False
+ return True
+
+def select_lastweek(date,fanart_image):
+ # This function builds folder structure for recent Dilbert comic strips and allows to go page by page further into the past.
+ # g_PageItems configures the strips shown per page
+ # Due to performance, we dont pre-scrape and show thumbnails. Strip is shown on click - though no browsing with the arrow keys possible.
+ if g_Args_Year and g_Args_Month and g_Args_Day:
+ date=datetime.date(int(g_Args_Year),int(g_Args_Month),int(g_Args_Day))
+ show_image(date)
+ return
+
+ days_offset = g_PageItems * (int(g_Args_Page)-1)
+ date = date - datetime.timedelta(days=(days_offset))
+ for i in range(g_PageItems):
+ date=date-datetime.timedelta(days=1)
+ if date >= g_FirstDilbert:
+ add_directory(mode='last_week',year=date.year,month=date.month,day=date.day,name='%04d-%02d-%02d'%(date.year,date.month,date.day),icon=g_Icons['click'], fanart=fanart_image)
+ else:
+ break
+ title='Next ' + str(g_PageItems) + ' comic strips... >>'
+ add_directory(mode='last_week',page='%s'%(int(g_Args_Page)+1),name=title,icon=g_Icons['next'], fanart=fanart_image)
+ xbmcplugin.endOfDirectory(g_AddonHandle,cacheToDisc=False)
+
+def select_random(date,fanart_image):
+ # This function builds the menu for displaying random Dilbert comic strips.
+ # g_PageItemsRandom controls the items shown per page.
+
+ # If date was selected, show strip
+ if g_Args_Year and g_Args_Month and g_Args_Day:
+ date=datetime.date(int(g_Args_Year),int(g_Args_Month),int(g_Args_Day))
+ show_image(date)
+ return
+
+ # Handle a cache, as otherwise after showing a strip and coming back the list would be refreshed.
+ datelist=[]
+ if get_cacheddata(g_cachemodefile)=='random':
+ datelist=pickle.load(open(g_CacheDir+g_cacherandomdates,"r"))
+ else:
+ datelist=create_randomdatelist(g_PageItemsRandom)
+ pickle.dump(datelist,open(g_CacheDir+g_cacherandomdates,"wb"))
+
+ # create directory items for random dates
+ for i in range(0,len(datelist)):
+ random_date = datelist[i]
+ title='%04d-%02d-%02d'%(random_date.year,random_date.month,random_date.day)
+ add_directory(mode='random',year=random_date.year,month=random_date.month, day=random_date.day,name=title,icon=g_Icons['click'], fanart=fanart_image)
+ xbmcplugin.endOfDirectory(g_AddonHandle)
+
+def create_randomdatelist(number):
+ datelist=[]
+ for i in range(number):
+ random_date = create_random_date(g_FirstDilbert, g_Now)
+ datelist.append(random_date)
+ return datelist
+
+def select_browse(fanart_image):
+ # This function builds the folder structure for browsing by date.
+ # Due to time needed for scraping, the comic strip URL is scraped on selection and no thumbnails are shown. This prevents unfortunately browsing with the arrow keys...
+ if g_Args_Day:
+ date=datetime.date(int(g_Args_Year),int(g_Args_Month),int(g_Args_Day))
+ show_image(date)
+ return
+
+ elif g_Args_Month:
+ day_range_end = g_Now.day+1 if (int(g_Args_Year) == g_Now.year and int(g_Args_Month) == g_Now.month) else monthrange(int(g_Args_Year),int(g_Args_Month))[1]+1
+ day_range_start = 16 if (int(g_Args_Year) == 1989 and int(g_Args_Month) == 4) else 1
+ for i in range(day_range_start,day_range_end,1):
+ if (int(g_Args_Year) == g_Now.year and int(g_Args_Month) == g_Now.month and int(i) == g_Now.day):
+ title_addon = ' (Today)'
+ elif (int(g_Args_Year) == g_FirstDilbert.year and int(g_Args_Month) == g_FirstDilbert.month and i == g_FirstDilbert.day):
+ title_addon = ' (First Dilbert online available)'
+ else:
+ title_addon = ""
+ title='%s'%i + title_addon
+ add_directory(mode='browse',year=g_Args_Year,month=g_Args_Month, day=i,name=title,icon=g_Icons['click'], fanart=fanart_image)
+ xbmcplugin.endOfDirectory(g_AddonHandle)
+ elif g_Args_Year:
+ month_range_end = g_Now.month+1 if (int(g_Args_Year) == g_Now.year) else 12+1
+ month_range_start = 4 if (int(g_Args_Year) == 1989) else 1
+ for i in range(month_range_start,month_range_end,1):
+ title= datetime.date(int(g_Args_Year),int(i),1)
+ title=title.strftime("%B") #+ ' %s'%i
+ add_directory(mode='browse',year=g_Args_Year,month=i,name=title,icon=g_Icons['next'], fanart=fanart_image)
+ xbmcplugin.endOfDirectory(g_AddonHandle)
+ else:
+ for i in range(g_Now.year,g_FirstDilbert.year-1,-1):
+ add_directory(mode='browse',year='%4d'%i,name='%s'%i,icon=g_Icons['next'], fanart=fanart_image)
+ xbmcplugin.endOfDirectory(g_AddonHandle)
+
+def select_date(date):
+ # Shows Dilbert comic strip per entered date.
+ # Checks entered date as well for format and if in range from first Dilbert to today
+ keyboard = xbmc.Keyboard('', 'Enter date(yyyy/mm/dd)', False)
+ keyboard.doModal()
+ if keyboard.isConfirmed():
+ input = keyboard.getText()
+ try:
+ year,month,day = input.split('/')
+ entered_date = datetime.date(int(year),int(month),int(day))
+ if entered_date > date:
+ msg=['You hit the future.\nYour entered date '+year+'/'+month+'/'+day+' is out of range!!!']
+ xbmcgui.Dialog().ok('Error: '+g_AddonName, str(msg[0]))
+ elif entered_date < g_FirstDilbert:
+ msg=['Too far back in time. Your entered date '+year+'/'+month+'/'+day+' is out of range!\nThe first electronically avialbale Dilbert is from '+str(g_FirstDilbert.year)+'/'+str(g_FirstDilbert.month)+'/'+str(g_FirstDilbert.day)+' !']
+ xbmcgui.Dialog().ok('Error: '+g_AddonName, str(msg[0]))
+ else:
+ image_url = get_image_url(entered_date)
+ xbmc.executebuiltin("ShowPicture(%s)"%image_url)
+ except (TypeError,ValueError):
+ msg=['Please enter the date in the correct format \"yyyy/mm/dd\" !']
+ xbmcgui.Dialog().ok('Error: '+g_AddonName, str(msg[0]))
+ sys.exit(1)
+ else:
+ return
+
+def show_image(date):
+ # This function displays a comic strip by date.
+ image_url=get_image_url(date)
+ if image_url:
+ xbmc.executebuiltin("ShowPicture(%s)"%image_url)
+ else:
+ return False
+
+def cache_mode():
+ # Cache last mode for handling the datelist cache of the random function
+ if g_Args_Mode:
+ set_cacheddata(g_Args_Mode[0],g_cachemodefile)
+ else:
+ delete_cachefile(g_cachemodefile)
+ return True
+
+### Main program start ###
+
+# Check for Cache
+g_UseCache=check_cachedirectory()
+# Show menus
+if g_Args_Mode is None:
+ create_mainmenu()
+elif g_Args_Mode[0]=='today':
+ show_image(g_Now)
+elif g_Args_Mode[0]=='last_week':
+ select_lastweek(g_Now,g_FanartImage[2])
+elif g_Args_Mode[0]=='random':
+ select_random(g_Now,g_FanartImage[3])
+elif g_Args_Mode[0]=='browse':
+ select_browse(g_FanartImage[4])
+elif g_Args_Mode[0]=='enter':
+ select_date(g_Now)
+
+cache_mode() \ No newline at end of file