summaryrefslogtreecommitdiff
path: root/addon.py
diff options
context:
space:
mode:
Diffstat (limited to 'addon.py')
-rw-r--r--addon.py161
1 files changed, 102 insertions, 59 deletions
diff --git a/addon.py b/addon.py
index 0226599..94692a2 100644
--- a/addon.py
+++ b/addon.py
@@ -50,9 +50,9 @@ def get_url(**kwargs):
return "{}?{}".format(URL, urlencode(kwargs))
-def list_genres():
+def list_top_level():
"""
- Create the list of movie genres in the Kodi interface.
+ Create the list of entrypoints in the Kodi interface.
"""
xbmcplugin.setPluginCategory(HANDLE, "Newgrounds")
xbmcplugin.setContent(HANDLE, "movies")
@@ -70,7 +70,6 @@ def list_genres():
for name in genres:
list_item = xbmcgui.ListItem(label=name)
- # list_item.setArt({'icon': genre_info['icon'], 'fanart': genre_info['fanart']})
info_tag = list_item.getVideoInfoTag()
info_tag.setMediaType("video")
@@ -92,7 +91,7 @@ def list_categories(genre="Featured"):
xbmcplugin.setPluginCategory(HANDLE, "Newgrounds")
xbmcplugin.setContent(HANDLE, "movies")
- CATEGORIES = {
+ categories = {
"All": 0,
"Action": 45,
"Comedy - Original": 60,
@@ -105,18 +104,14 @@ def list_categories(genre="Featured"):
"Spam": 55,
}
- for name in CATEGORIES.keys():
+ for name in categories.keys():
list_item = xbmcgui.ListItem(label=name)
- # list_item.setArt({'icon': genre_info['icon'], 'fanart': genre_info['fanart']})
-
info_tag = list_item.getVideoInfoTag()
info_tag.setMediaType("video")
info_tag.setTitle(name)
info_tag.setGenres([name])
-
- url = get_url(action="listing", genre=genre, category=CATEGORIES[name])
+ url = get_url(action="listing", genre=genre, category=categories[name])
is_folder = True
-
xbmcplugin.addDirectoryItem(HANDLE, url, list_item, is_folder)
xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE)
xbmcplugin.endOfDirectory(HANDLE)
@@ -124,7 +119,11 @@ def list_categories(genre="Featured"):
def get_video_url(url):
"""
- TODO
+ Return the location of the stream for a movie.
+
+ :param url: URL of Newgrounds movie page
+ :return: stream URL
+ :rtype: str
"""
html = requests.get(url).text
soup = BeautifulSoup(html, "html.parser")
@@ -150,6 +149,10 @@ def get_video_url(url):
def get_addon_video_info(url):
"""
Scrape metadata from `url`.
+
+ :param url: URL of Newgrounds movie page
+ :return: dictionary of video metadata
+ :rtype: dict
"""
html = requests.get(url).text
soup = BeautifulSoup(html, "html.parser")
@@ -158,7 +161,7 @@ def get_addon_video_info(url):
thumbnail = soup.find("meta", property="og:image")
if thumbnail is not None:
thumbnail = thumbnail["content"]
- sidestats_popularity = soup.find_all('dl', 'sidestats')[0].find_all('dd')
+ sidestats_popularity = soup.find_all("dl", "sidestats")[0].find_all("dd")
views = sidestats_popularity[0].string
faves = sidestats_popularity[1].a
if faves is not None:
@@ -172,7 +175,7 @@ def get_addon_video_info(url):
score = sidestats_popularity[3].span.string
except IndexError:
score = 0
- sidestats_date_and_genre = soup.find_all('dl', 'sidestats')[1].find_all('dd')
+ sidestats_date_and_genre = soup.find_all("dl", "sidestats")[1].find_all("dd")
upload_date = sidestats_date_and_genre[0].string
upload_time = sidestats_date_and_genre[1].string
try:
@@ -180,22 +183,28 @@ def get_addon_video_info(url):
except IndexError as e:
genre = "Unknown"
try:
- tags = [tag.string for tag in soup.find('dd', 'tags').find_all('a')]
+ tags = [tag.string for tag in soup.find("dd", "tags").find_all("a")]
except AttributeError as e:
tags = []
- author_comments = ''.join([s for s in soup.find('div', id='author_comments').strings]).strip()
+ author_comments = "".join(
+ [s for s in soup.find("div", id="author_comments").strings]
+ ).strip()
try:
- authors = [author.string for author in soup.find('ul', 'authorlinks').find_all('a') if author.get("class") is None]
+ authors = [
+ author.string
+ for author in soup.find("ul", "authorlinks").find_all("a")
+ if author.get("class") is None
+ ]
except AttributeError:
authors = []
- if len(soup.find_all('h2', 'rated-a')) != 0:
- rating = 'a'
- elif len(soup.find_all('h2', 'rated-m')) != 0:
- rating = 'm'
- elif len(soup.find_all('h2', 'rated-t')) != 0:
- rating = 't'
+ if len(soup.find_all("h2", "rated-a")) != 0:
+ rating = "a"
+ elif len(soup.find_all("h2", "rated-m")) != 0:
+ rating = "m"
+ elif len(soup.find_all("h2", "rated-t")) != 0:
+ rating = "t"
else:
- rating = 'e'
+ rating = "e"
return {
"title": title,
@@ -215,9 +224,20 @@ def get_addon_video_info(url):
}
-def get_video_urls(
- genre="Featured", interval="today", sort="date", category=0, offset=0
+def get_frontpage_video_urls(
+ grouping="Featured", interval="today", sort_by="date", category=0, offset=0
):
+ """
+ Return a list of movies from the Newgrounds frontpage.
+
+ :param grouping: one of "Featured", "Latest", or "Popular"
+ :param interval: one of "today", "yesterday", "week", "month", "year", "all"
+ :param sort_by: one of "date", score", "views"
+ :param category: numeric identifier for video category
+ :param offset: pagination offset
+ :return: list of video URLs
+ :rtype: list
+ """
URLS = {
"Featured": "https://www.newgrounds.com/movies/featured",
"Latest": "https://www.newgrounds.com/movies/browse",
@@ -225,15 +245,16 @@ def get_video_urls(
}
assert interval in ["today", "yesterday", "week", "month", "year", "all"]
- assert sort in ["date"]
- assert isinstance(genre, int)
+ assert sort_by in ["date", "score", "views"]
+ assert isinstance(category, int)
+ assert isinstance(offset, int)
- url = URLS[genre]
+ url = URLS[grouping]
response = requests.get(
url,
params={
"interval": interval,
- "sort": sort,
+ "sort": sort_by,
"genre": category,
"isAjaxRequest": True,
"offset": offset,
@@ -248,11 +269,33 @@ def get_video_urls(
return [tag["href"] for tag in soup.find_all("a", "inline-card-portalsubmission")]
-def search(term, offset=0):
+def search(term, sort_by="relevance", offset=1):
+ """
+ Return a list of movies matching a given search term.
+
+ :param term: Term to search for
+ :param sort_by: one of "relevance", "date-asc", "date-desc", "score-asc", "score-desc", "views-asc", "views-desc"
+ :param offset: pagination offset
+ :return: list of video URLs
+ :rtype: list
+ """
+ assert isinstance(term, str)
+ assert sort_by in [
+ "relevance",
+ "date-asc",
+ "date-desc",
+ "score-asc",
+ "score-desc",
+ "views-asc",
+ "views-desc",
+ ]
+ assert isinstance(offset, int)
+
response = requests.get(
"https://www.newgrounds.com/search/conduct/movies",
params={
"suitabilities": "etm",
+ "sort": sort_by,
"terms": term,
"page": offset,
"inner": 1,
@@ -276,16 +319,16 @@ def list_videos(video_urls, title=None, next_page=None):
"""
videos = []
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
- # Start the load operations and mark each future with its URL
- future_to_url = {executor.submit(get_addon_video_info, url): url for url in video_urls}
- for future in concurrent.futures.as_completed(future_to_url):
- url = future_to_url[future]
- videos.append(future.result())
+ # Start the load operations and mark each future with its URL
+ future_to_url = {
+ executor.submit(get_addon_video_info, url): url for url in video_urls
+ }
+ for future in concurrent.futures.as_completed(future_to_url):
+ url = future_to_url[future]
+ videos.append(future.result())
xbmcplugin.setPluginCategory(HANDLE, title)
xbmcplugin.setContent(HANDLE, "movies")
- # Get the list of videos in the category.
- # videos = genre_info['movies']
- # Iterate through videos.
+
for video in videos:
list_item = xbmcgui.ListItem(label=video["title"])
if video["thumbnail"] is not None:
@@ -294,14 +337,15 @@ def list_videos(video_urls, title=None, next_page=None):
info_tag = list_item.getVideoInfoTag()
info_tag.setMediaType("movie")
info_tag.setTitle(video["title"])
-
info_tag.setYear(int(video["upload_date"][-4:]))
- info_tag.setRating(float(video["score"]), int(video["votes"].replace(',', '')))
- info_tag.setPlaycount(int(video["views"].replace(',', '')))
+ info_tag.setRating(float(video["score"]), int(video["votes"].replace(",", "")))
+ info_tag.setPlaycount(int(video["views"].replace(",", "")))
info_tag.setPlot(video["description"])
info_tag.setGenres([video["genre"]])
info_tag.setDirectors(video["authors"])
- info_tag.setPremiered(dateutil.parser.parse(video["upload_date"]).strftime("%Y-%m-%d"))
+ info_tag.setPremiered(
+ dateutil.parser.parse(video["upload_date"]).strftime("%Y-%m-%d")
+ )
info_tag.setTags(video["tags"])
if video["rating"] == "a":
@@ -313,9 +357,6 @@ def list_videos(video_urls, title=None, next_page=None):
else:
info_tag.setMpaa("PG")
- # info_tag.setGenres([genre_info['genre']])
- # info_tag.setPlot(video['plot'])
- # info_tag.setYear(video['year'])
list_item.setProperty("IsPlayable", "true")
url = get_url(action="play", video=video["url"])
@@ -323,7 +364,7 @@ def list_videos(video_urls, title=None, next_page=None):
xbmcplugin.addDirectoryItem(HANDLE, url, list_item, is_folder)
# Add a "continue" folder.
- if next_page is not None:
+ if next_page is not None and len(video_urls) > 0:
list_item = xbmcgui.ListItem(label="Next Page")
info_tag = list_item.getVideoInfoTag()
info_tag.setMediaType("video")
@@ -352,16 +393,22 @@ def router(paramstring):
"""
params = dict(parse_qsl(paramstring))
if not params:
- list_genres()
+ list_top_level()
elif params["action"] == "listing" and "category" in params:
offset = int(params.get("offset", 0))
- video_urls = get_video_urls(category=params["category"], interval="all", offset=offset)
- next_page = get_url(action="listing", genre=params["genre"], category=params["category"], offset=offset + 20)
- list_videos(
- video_urls,
- params["genre"],
- next_page
+ video_urls = get_frontpage_video_urls(
+ grouping=params["genre"],
+ interval="all",
+ category=params["category"],
+ offset=offset,
+ )
+ next_page = get_url(
+ action="listing",
+ genre=params["genre"],
+ category=params["category"],
+ offset=offset + 20,
)
+ list_videos(video_urls, params["genre"], next_page)
elif params["action"] == "listing":
list_categories(params["genre"])
elif params["action"] == "searchprompt":
@@ -371,14 +418,10 @@ def router(paramstring):
xbmc.executebuiltin("Container.Update(%s)" % url)
elif params["action"] == "search":
term = params["term"]
- offset = int(params.get("offset", 0))
+ offset = int(params.get("offset", 1))
video_urls = search(term, offset=offset)
next_page = get_url(action="search", term=term, offset=offset + 1)
- list_videos(
- video_urls,
- "Search Results: {}".format(term),
- next_page
- )
+ list_videos(video_urls, "Search Results: {}".format(term), next_page)
elif params["action"] == "play":
play_video(params["video"])
else: