#!/usr/bin/python
# encoding=utf8
"""
Copyright (C) 2018 MuadDib
----------------------------------------------------------------------------
"THE BEER-WARE LICENSE" (Revision 42):
@tantrumdev wrote this file. As long as you retain this notice you can do
whatever you want with this stuff. Just Ask first when not released through
the tools and parser GIT. If we meet some day, and you think this stuff is
worth it, you can buy him a beer in return. - Muad'Dib
----------------------------------------------------------------------------
Changelog:
2019.4.16:
- Updated website url change
2018.7.2:
- Added Clear Cache function
- Minor update on fetch cache returns
2018.6.20:
- Added caching to primary menus (Cache time is 3 hours)
Usage Examples:
50 Latest Releasestopfifty/last-50-recent-releaseMost Popular Seriesmain/sidebar-titles/0Latest Series Addedmain/recent-release-main/1Dubbed Animecategory/dubbed-anime-listSubbed Animecategory/subbed-anime-listCartoonscategory/cartoon-listMoviescategory/movie-listOva Seriescategory/ova-listSearch SitewcsearchEverything 101 Dalmatianswcsearch/101 dalmatiansAction Genrewcgenre/14
"""
import __builtin__
import base64,time
import json,re,requests,os,traceback,urlparse
import koding
import xbmc,xbmcaddon,xbmcgui
from koding import route
from resources.lib.plugin import Plugin
from resources.lib.util import dom_parser
from resources.lib.util.context import get_context_items
from resources.lib.util.xml import JenItem, JenList, display_list
from unidecode import unidecode
CACHE_TIME = 10800 # change to wanted cache time in seconds
addon_fanart = xbmcaddon.Addon().getAddonInfo('fanart')
addon_icon = xbmcaddon.Addon().getAddonInfo('icon')
User_Agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
class WatchCartoon(Plugin):
name = "wctoon"
def process_item(self, item_xml):
if "" in item_xml:
item = JenItem(item_xml)
if "wcepisode/" in item.get("wctoon", ""):
result_item = {
'label': item["title"],
'icon': item.get("thumbnail", addon_icon),
'fanart': item.get("fanart", addon_fanart),
'mode': "WCEpisodes",
'url': item.get("wctoon", ""),
'folder': True,
'imdb': "0",
'content': "files",
'season': "0",
'episode': "0",
'info': {},
'year': "0",
'context': get_context_items(item),
"summary": item.get("summary", None)
}
elif "wcsearch" in item.get("wctoon", ""):
result_item = {
'label': item["title"],
'icon': item.get("thumbnail", addon_icon),
'fanart': item.get("fanart", addon_fanart),
'mode': "WCSearch",
'url': item.get("wctoon", ""),
'folder': True,
'imdb': "0",
'content': "files",
'season': "0",
'episode': "0",
'info': {},
'year': "0",
'context': get_context_items(item),
"summary": item.get("summary", None)
}
elif "wcgenre" in item.get("wctoon", ""):
result_item = {
'label': item["title"],
'icon': item.get("thumbnail", addon_icon),
'fanart': item.get("fanart", addon_fanart),
'mode': "WCGenre",
'url': item.get("wctoon", ""),
'folder': True,
'imdb': "0",
'content': "files",
'season': "0",
'episode': "0",
'info': {},
'year': "0",
'context': get_context_items(item),
"summary": item.get("summary", None)
}
elif "direct/" in item.get("wctoon", ""):
result_item = {
'label': item["title"],
'icon': item.get("thumbnail", addon_icon),
'fanart': item.get("fanart", addon_fanart),
'mode': "WCPlayVideo",
'url': item.get("wctoon", ""),
'folder': False,
'imdb': "0",
'content': "files",
'season': "0",
'episode': "0",
'info': {},
'year': "0",
'context': get_context_items(item),
"summary": item.get("summary", None)
}
elif "topfifty/" in item.get("wctoon", ""):
result_item = {
'label': item["title"],
'icon': item.get("thumbnail", addon_icon),
'fanart': item.get("fanart", addon_fanart),
'mode': "TopFifty",
'url': item.get("wctoon", ""),
'folder': True,
'imdb': "0",
'content': "files",
'season': "0",
'episode': "0",
'info': {},
'year': "0",
'context': get_context_items(item),
"summary": item.get("summary", None)
}
elif "main/" in item.get("wctoon", ""):
result_item = {
'label': item["title"],
'icon': item.get("thumbnail", addon_icon),
'fanart': item.get("fanart", addon_fanart),
'mode': "WCMain",
'url': item.get("wctoon", ""),
'folder': True,
'imdb': "0",
'content': "files",
'season': "0",
'episode': "0",
'info': {},
'year': "0",
'context': get_context_items(item),
"summary": item.get("summary", None)
}
elif "category/" in item.get("wctoon", ""):
result_item = {
'label': item["title"],
'icon': item.get("thumbnail", addon_icon),
'fanart': item.get("fanart", addon_fanart),
'mode': "WatchCartoon",
'url': item.get("wctoon", ""),
'folder': True,
'imdb': "0",
'content': "files",
'season': "0",
'episode': "0",
'info': {},
'year': "0",
'context': get_context_items(item),
"summary": item.get("summary", None)
}
result_item["properties"] = {
'fanart_image': result_item["fanart"]
}
result_item['fanart_small'] = result_item["fanart"]
return result_item
def clear_cache(self):
skip_prompt = xbmcaddon.Addon().getSetting("quiet_cache")
dialog = xbmcgui.Dialog()
if skip_prompt == 'false':
if dialog.yesno(xbmcaddon.Addon().getAddonInfo('name'), "Clear WatchCartoon.com Plugin Cache?"):
koding.Remove_Table("wctoon_com_plugin")
else:
koding.Remove_Table("wctoon_com_plugin")
@route(mode='WatchCartoon', args=["url"])
def get_wcstream(url):
url = url.replace('category/', '') # Strip our category tag off.
url = urlparse.urljoin('https://www.thewatchcartoononline.tv/', url)
#url = urlparse.urljoin('https://www.watchcartoononline.com', url)
pins = ""
xml = fetch_from_db(url)
if not xml:
xml = ""
try:
html = requests.get(url).content
ddmcc = dom_parser.parseDOM(html, 'div', attrs={'class':'ddmcc'})[0]
# pull root List, as all the minor lists are contained within it
lists = dom_parser.parseDOM(ddmcc, 'li')
for entry in lists:
try:
movie_style = 0
try:
# if this fails, means it is a movie/ova series entry as they use different html for those categories
show_url, title = re.compile('(.+?)',re.DOTALL).findall(entry)[0]
except:
show_url, title = re.compile('(.+?)',re.DOTALL).findall(entry)[0]
movie_style = 1
title = refreshtitle(title)
title = remove_non_ascii(title)
if movie_style == 1:
xml += ""\
" %s"\
" direct/%s"\
" %s"\
" %s"\
"" % (title,show_url,addon_icon,title)
else:
xml += ""\
" %s"\
" wcepisode/%s"\
" %s"\
" %s"\
"" % (title,show_url,addon_icon,title)
except:
continue
save_to_db(xml, url)
except:
pass
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
@route(mode='TopFifty', args=["url"])
def get_wctopfiftystream(url):
url = url.replace('topfifty/', '') # Strip our category tag off.
url = urlparse.urljoin('https://www.watchcartoononline.io', url)
pins = ""
xml = fetch_from_db(url)
if not xml:
xml = ""
try:
html = requests.get(url).content
thediv = dom_parser.parseDOM(html, 'div', attrs={'class':'menulaststyle'})[0]
lists = dom_parser.parseDOM(thediv, 'li')
for entry in lists:
try:
show_url, title = re.compile('(.+?)',re.DOTALL).findall(entry)[0]
title = refreshtitle(title)
title = remove_non_ascii(title)
xml += ""\
" %s"\
" direct/%s"\
" %s"\
" %s"\
"" % (title,show_url,addon_icon,title)
except:
continue
save_to_db(xml, url)
except:
pass
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
@route(mode='WCMain', args=["url"])
def get_wcmainstream(subid):
xml = ""
subid = subid.replace('main/', '', 1) # Strip our category tag off.
subid = subid.split('/')
pins = ""
try:
html = requests.get('https://www.watchcartoononline.com').content
thedivs = dom_parser.parseDOM(html, 'div', attrs={'class':subid[0]})[int(subid[1])]
list_items = dom_parser.parseDOM(thedivs, 'li')
for content in list_items:
try:
if subid[0] == 'sidebar-titles':
show_url, title = re.compile('(.+?)',re.DOTALL).findall(content)[0]
title = refreshtitle(title).replace('Episode ', 'EP:')
title = remove_non_ascii(title)
xml += ""\
" %s"\
" wcepisode/%s"\
" %s"\
" %s"\
"" % (title,show_url,addon_icon,title)
elif subid[0] == 'recent-release-main':
show_url, title = re.compile('(.+?)',re.DOTALL).findall(content)[1]
title = refreshtitle(title).replace('Episode ', 'EP:')
title = remove_non_ascii(title)
show_icon = re.compile('src="(.+?)"',re.DOTALL).findall(content)[0]
xml += ""\
" %s"\
" wcepisode/%s"\
" %s"\
" %s"\
"" % (title,show_url,show_icon,title)
else:
continue
except:
continue
except:
pass
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
@route(mode='WCEpisodes', args=["url"])
def get_wcepisodes(url):
url = url.replace('wcepisode/', '') # Strip our episode tag off.
url = urlparse.urljoin('https://www.watchcartoononline.com', url)
pins = ""
xml = fetch_from_db(url)
if not xml:
xml = ""
try:
html = requests.get(url).content
thediv = dom_parser.parseDOM(html, 'div', attrs={'id':'sidebar_right3'})[0]
lists = dom_parser.parseDOM(thediv, 'div', attrs={'class':'cat-eps'})
for entry in lists:
show_url, title = re.compile('(.+?)',re.DOTALL).findall(entry)[0]
title = refreshtitle(title).replace('Episode ', 'EP:')
title = remove_non_ascii(title)
show_icon = dom_parser.parseDOM(html, 'meta', attrs={'property':'og:image'}, ret='content')[0]
xml += ""\
" %s"\
" direct/%s"\
" %s"\
" %s"\
"" % (title,show_url,show_icon,title)
save_to_db(xml, url)
except:
pass
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
@route(mode='WCGenre', args=["url"])
def get_wcgenre(url):
pins = ""
if 'all' in url:
get_wcgenrelist()
return
else:
url = url.replace('wcgenre/', '') # Strip our genre tag off.
url = urlparse.urljoin('https://www.watchcartoononline.com/search-by-genre/', url)
xml = fetch_from_db(url)
if not xml:
xml = ""
try:
html = requests.get(url).content
ddmcc = dom_parser.parseDOM(html, 'div', attrs={'class':'ddmcc'})[0]
# pull root List, as all the minor lists are contained within it
lists = dom_parser.parseDOM(ddmcc, 'li')
for entry in lists:
show_url, title = re.compile('href="(.+?)">(.+?)',re.DOTALL).findall(entry)[0]
title = refreshtitle(title)
title = remove_non_ascii(title)
xml += ""\
" %s"\
" wcepisode/%s"\
" %s"\
" %s"\
"" % (title,show_url,addon_icon,title)
save_to_db(xml, url)
except:
pass
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
def get_wcgenrelist():
url = 'https://www.watchcartoononline.com/search-by-genre/'
pins = ""
xml = fetch_from_db(url)
if not xml:
xml = ""
try:
html = requests.get(url).content
ddmcc = dom_parser.parseDOM(html, 'div', attrs={'class':'ddmcc'})[0]
# pull root List, as all the minor lists are contained within it
lists = dom_parser.parseDOM(ddmcc, 'li')
for entry in lists:
show_url, title = re.compile('href="(.+?)">(.+?)',re.DOTALL).findall(entry)[0]
# convert show_url to get last tag in the url for the xml creation
show_url = show_url.split('/')[-1]
title = refreshtitle(title)
title = remove_non_ascii(title)
xml += ""\
" %s"\
" wcgenre/%s"\
" %s"\
" %s"\
"" % (title,show_url,addon_icon,title)
save_to_db(xml, url)
except:
pass
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
@route(mode='WCSearch', args=["url"])
def get_wcsearch(url):
pins = ""
xml = ""
url = url.replace('wcsearch/', '') # Strip our search tag off when used with keywords in the xml
url = url.replace('wcsearch', '') # Catch plain case, for when overall search is used.
if url != None and url != "":
search = url
else:
keyboard = xbmc.Keyboard('', 'Search for')
keyboard.doModal()
if keyboard.isConfirmed() != None and keyboard.isConfirmed() != "":
search = keyboard.getText()
else:
return
if search == None or search == "":
xml += ""\
" Search Cancelled"\
" plugin://plugin.video.squadcontrol/?mode=section_item"\
" %s"\
"" % (addon_icon)
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
return
total = 0
try:
search_url = 'https://www.watchcartoononline.com/wp-json/wp/v2/posts?per_page=100&search=%s' % search.replace(' ', '%20')
html = requests.get(search_url).content
results = re.compile('"post","link":"(.+?)","title".+?"rendered":"(.+?)"',re.DOTALL).findall(html)
if len(results) == 0:
dialog = xbmcgui.Dialog()
dialog.ok('Search Results', 'Search Results are empty')
return
for link,name in results:
link = link.replace('\\','')
name = refreshtitle(name).replace('Episode ', 'EP:')
name = remove_non_ascii(name)
if search.lower() in name.lower() or search.lower() in link.lower():
xml += ""\
" %s"\
" direct/%s"\
" %s"\
"" % (name,link,addon_icon)
total += 1
except:
pass
if total > 0:
jenlist = JenList(xml)
display_list(jenlist.get_list(), jenlist.get_content_type(), pins)
@route(mode='WCPlayVideo', args=["url"])
def get_wcplayvideo(url):
url = url.replace('direct/', '') # Strip our episode tag off.
html = requests.get(url)
url = ''
try:
match = re.findall('''var\s*[a-zA-Z]{3}\s*\=\s*\[([^\]]+)''', html.text)[0]
spread = re.findall('''-\s*(\d+)\)\;\s*\}''', html.text)[0]
match = re.findall('''['"]([^'"]+)['"]''', match)
for i in match:
i = base64.b64decode(i)
i = re.findall(r'(\d+)',i)[0]
i = chr(int(i) - int(spread))
url += i
url = re.findall(r'src="(.*?)"', url)[0]
url = urlparse.urljoin('https://www.watchcartoononline.com', url)
url = requests.get(url)
oldurl = url
url = re.findall(r'''file:\s*['\"]([^'\"]+)['\"](?:\,\s*label:\s*|)(?:['\"]|)([\d]+|)''', url.text)
if len(url) == 0:
url = re.findall(r'''src:\s*['\"]([^'\"]+)['\"](?:\,\s*src:\s*|)(?:['\"]|)([\d]+|)''', oldurl.text)
url = [(i[0],'0' if i[1] == '' else i[1]) for i in url]
url = sorted(url, key=lambda x: int(x[1]),reverse=True)
xbmc.executebuiltin("PlayMedia(%s)" % (url[0][0]))
quit()
return
except:
pass
def save_to_db(item, url):
if not item or not url:
return False
try:
koding.reset_db()
koding.Remove_From_Table(
"wctoon_com_plugin",
{
"url": url
})
koding.Add_To_Table("wctoon_com_plugin",
{
"url": url,
"item": base64.b64encode(item),
"created": time.time()
})
except:
return False
def fetch_from_db(url):
koding.reset_db()
wctoon_plugin_spec = {
"columns": {
"url": "TEXT",
"item": "TEXT",
"created": "TEXT"
},
"constraints": {
"unique": "url"
}
}
koding.Create_Table("wctoon_com_plugin", wctoon_plugin_spec)
match = koding.Get_From_Table(
"wctoon_com_plugin", {"url": url})
if match:
match = match[0]
if not match["item"]:
return None
created_time = match["created"]
if created_time and float(created_time) + CACHE_TIME >= time.time():
match_item = match["item"]
try:
result = base64.b64decode(match_item)
except:
return None
return result
else:
return None
else:
return None
def refreshtitle(title):
title = replaceEscapeCodes(title)
title = replaceHTMLCodes(title).replace('English Dubbed','[COLOR yellow](English Dubbed)[/COLOR]').replace('English Subbed','[COLOR orange](English Subbed)[/COLOR]')
return title
def replaceHTMLCodes(txt):
txt = re.sub("([0-9]+)([^;^0-9]+)", "\\1;\\2", txt)
try:
import html.parser as html_parser
except:
import HTMLParser as html_parser
txt = html_parser.HTMLParser().unescape(txt)
txt = html_parser.HTMLParser().unescape(txt)
txt = txt.replace(""", "\"")
txt = txt.replace("&", "&")
txt = txt.strip()
return txt
def replaceEscapeCodes(txt):
try:
import html.parser as html_parser
except:
import HTMLParser as html_parser
txt = html_parser.HTMLParser().unescape(txt)
return txt
def remove_non_ascii(text):
try:
text = text.decode('utf-8').replace(u'\xc2', u'A').replace(u'\xc3', u'A').replace(u'\xc4', u'A')
except:
pass
return unidecode(text)