diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..025ccfc
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,20 @@
+language: python
+matrix:
+ include:
+ - python: "2.6"
+ - python: "2.7"
+ - python: "2.7.10"
+ - python: "2.7.11"
+ allow_failures:
+ - python: "3.2"
+ - python: "3.3"
+ - python: "3.4"
+ - python: "3.5"
+ - python: "nightly"
+
+# command to install dependencies
+install:
+ - pip install python-dateutil pytest
+# command to run tests
+script: py.test -v
+
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 11ac83f..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2021 Henry Richard J
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2d3c05c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# Kodi Voot Addon
+ This Kodi addon allows you to watch Movies and TV Shows from Voot OTT platform without Voot Account.
+
+ # My Kodi Repo
+Vist Here to get more information about my kodi repo https://henry-richard.ml/Kodi/
+
+# Screenshots
+
+
+ # My Youtube Channel
+[![](https://img.shields.io/badge/Subscribe-red?style=for-the-badge&logo=YouTube)](https://www.youtube.com/channel/UCVGasc5jr45eZUpZNHvbtWQ)
+
+
+# My Telegram Channel
+[![](https://img.shields.io/badge/Telegram-Join%20Now-blue?style=for-the-badge&logo=Telegram)](https://t.me/cracked4free)
+
+## Donations
+If you like my projects then consider making a small donation by clicking below button ^_^
+
+[![](https://img.shields.io/badge/Donate-Paypal-blue?style=for-the-badge&logo=paypal)](https://www.paypal.com/paypalme/henryrics)
+
+# Copyrights © [Henry Richard J](https://github.com/henry-richard7)
+#### Star the Repo in case you liked it :)
diff --git a/Screenshots/Voot 1.png b/Screenshots/Voot 1.png
new file mode 100644
index 0000000..e688fb4
Binary files /dev/null and b/Screenshots/Voot 1.png differ
diff --git a/Screenshots/Voot 2.png b/Screenshots/Voot 2.png
new file mode 100644
index 0000000..aa6b1aa
Binary files /dev/null and b/Screenshots/Voot 2.png differ
diff --git a/Screenshots/Voot 3.png b/Screenshots/Voot 3.png
new file mode 100644
index 0000000..049484e
Binary files /dev/null and b/Screenshots/Voot 3.png differ
diff --git a/addon.xml b/addon.xml
new file mode 100644
index 0000000..31da1e4
--- /dev/null
+++ b/addon.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+ video
+
+
+ Watch Voot without login.
+
+
+ all
+ MIT
+
+ henry-richard.ml
+
+
+
+
+
+ resources/icon.png
+ resources/fanart.jpg
+
+
+
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..c36565f
--- /dev/null
+++ b/main.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+from resources.lib import plugin
+if __name__ == "__main__":
+ plugin.run()
\ No newline at end of file
diff --git a/resources/__init__.py b/resources/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/resources/fanart.jpg b/resources/fanart.jpg
new file mode 100644
index 0000000..8cb2025
Binary files /dev/null and b/resources/fanart.jpg differ
diff --git a/resources/icon.png b/resources/icon.png
new file mode 100644
index 0000000..de25dc6
Binary files /dev/null and b/resources/icon.png differ
diff --git a/resources/language/README.md b/resources/language/README.md
new file mode 100644
index 0000000..b4f8390
--- /dev/null
+++ b/resources/language/README.md
@@ -0,0 +1 @@
+This folder will be the home of your translations
\ No newline at end of file
diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po
new file mode 100644
index 0000000..65c16c5
--- /dev/null
+++ b/resources/language/resource.language.en_gb/strings.po
@@ -0,0 +1,27 @@
+# Kodi Media Center language file
+# Addon Name: Voot Streamer
+# Addon id: plugin.henry.vootstreamer
+# Addon Provider: Henry Richard
+msgid ""
+msgstr ""
+"Project-Id-Version: XBMC Addons\n"
+"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
+"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Kodi Translation Team\n"
+"Language-Team: English (http://www.transifex.com/projects/p/xbmc-addons/language/en/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: en\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#This is a comment
+
+msgctxt "#32000"
+msgid "Example"
+msgstr ""
+
+msgctxt "#32001"
+msgid "Debug"
+msgstr ""
\ No newline at end of file
diff --git a/resources/lib/__init__.py b/resources/lib/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/resources/lib/kodilogging.py b/resources/lib/kodilogging.py
new file mode 100644
index 0000000..5f42ab7
--- /dev/null
+++ b/resources/lib/kodilogging.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals
+from resources.lib.kodiutils import get_setting_as_bool
+
+import logging
+import xbmc
+import xbmcaddon
+
+
+class KodiLogHandler(logging.StreamHandler):
+
+ def __init__(self):
+ logging.StreamHandler.__init__(self)
+ addon_id = xbmcaddon.Addon().getAddonInfo('id')
+ prefix = b"[%s] " % addon_id
+ formatter = logging.Formatter(prefix + b'%(name)s: %(message)s')
+ self.setFormatter(formatter)
+
+ def emit(self, record):
+ levels = {
+ logging.CRITICAL: xbmc.LOGFATAL,
+ logging.ERROR: xbmc.LOGERROR,
+ logging.WARNING: xbmc.LOGWARNING,
+ logging.INFO: xbmc.LOGINFO,
+ logging.DEBUG: xbmc.LOGDEBUG,
+ logging.NOTSET: xbmc.LOGNONE,
+ }
+ if get_setting_as_bool('debug'):
+ try:
+ xbmc.log(self.format(record), levels[record.levelno])
+ except UnicodeEncodeError:
+ xbmc.log(self.format(record).encode(
+ 'utf-8', 'ignore'), levels[record.levelno])
+
+ def flush(self):
+ pass
+
+
+def config():
+ logger = logging.getLogger()
+ logger.addHandler(KodiLogHandler())
+ logger.setLevel(logging.DEBUG)
diff --git a/resources/lib/kodiutils.py b/resources/lib/kodiutils.py
new file mode 100644
index 0000000..bbcec90
--- /dev/null
+++ b/resources/lib/kodiutils.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+
+import xbmc
+import xbmcaddon
+import xbmcgui
+import sys
+import logging
+import json as json
+
+
+# read settings
+ADDON = xbmcaddon.Addon()
+
+logger = logging.getLogger(__name__)
+
+
+def notification(header, message, time=5000, icon=ADDON.getAddonInfo('icon'), sound=True):
+ xbmcgui.Dialog().notification(header, message, icon, time, sound)
+
+
+def show_settings():
+ ADDON.openSettings()
+
+
+def get_setting(setting):
+ return ADDON.getSetting(setting).strip().decode('utf-8')
+
+
+def set_setting(setting, value):
+ ADDON.setSetting(setting, str(value))
+
+
+def get_setting_as_bool(setting):
+ return get_setting(setting).lower() == "true"
+
+
+def get_setting_as_float(setting):
+ try:
+ return float(get_setting(setting))
+ except ValueError:
+ return 0
+
+
+def get_setting_as_int(setting):
+ try:
+ return int(get_setting_as_float(setting))
+ except ValueError:
+ return 0
+
+
+def get_string(string_id):
+ return ADDON.getLocalizedString(string_id).encode('utf-8', 'ignore')
+
+
+def kodi_json_request(params):
+ data = json.dumps(params)
+ request = xbmc.executeJSONRPC(data)
+
+ try:
+ response = json.loads(request)
+ except UnicodeDecodeError:
+ response = json.loads(request.decode('utf-8', 'ignore'))
+
+ try:
+ if 'result' in response:
+ return response['result']
+ return None
+ except KeyError:
+ logger.warn("[%s] %s" %
+ (params['method'], response['error']['message']))
+ return None
diff --git a/resources/lib/plugin.py b/resources/lib/plugin.py
new file mode 100644
index 0000000..9ce7cf8
--- /dev/null
+++ b/resources/lib/plugin.py
@@ -0,0 +1,158 @@
+from __future__ import unicode_literals
+
+# noinspection PyUnresolvedReferences
+from codequick import Route, Resolver, Listitem, run
+from codequick.utils import urljoin_partial, bold
+import requests
+import xbmcgui
+import re
+import urllib
+import inputstreamhelper
+
+apiUrl = 'https://psapi.voot.com/media/voot/v1/'
+headers = {
+
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36",
+ "accept": "application/json, text/plain, */*",
+ "accept-encoding": "gzip, deflate, br",
+ "content-type": "application/json; charset=utf-8",
+ "referer": "https://www.voot.com/",
+ "usertype": "svod",
+ "Content-Version": "V4",
+ "origin": "https://www.voot.com"
+}
+
+languages = ['Hindi', 'Marathi', 'Tamil', 'English', 'Telugu',
+ 'Kannada', 'Bengali', 'Gujarati', 'Tulu']
+
+
+def direct_link(movie_id):
+ response = requests.get(
+ f"https://wapi.voot.com/ws/ott/getMediaInfo.json?platform=Web&pId=2&mediaId={movie_id}").json()
+ return response["assets"]["Files"][3]["URL"]
+
+
+@Route.register
+def root(plugin, content_type="segment"):
+ Movies_Languages_item = {
+ "label": "Voot Movies",
+ "callback": voot_movies_languages
+ }
+
+ Shows_Languages_item = {
+ "label": "Voot Shows",
+ "callback": voot_shows_languages
+ }
+
+ yield Listitem.from_dict(**Movies_Languages_item)
+ yield Listitem.from_dict(**Shows_Languages_item)
+
+
+@Route.register
+def voot_movies_languages(plugin):
+ for language in languages:
+ item = Listitem()
+ item.label = language
+ item.info["plot"] = f"Watch Voot {language} Movies for free!"
+ item.set_callback(list_voot_movies, lang=language, page_no="1")
+ yield item
+
+
+@Route.register
+def voot_shows_languages(plugin):
+ for language in languages:
+ item = Listitem()
+ item.label = language
+ item.info["plot"] = f"Watch Voot {language} Shows for free!"
+ item.set_callback(list_voot_shows, lang=language, page_no="1")
+ yield item
+
+
+@Route.register
+def list_voot_movies(plugin, lang, page_no):
+ url = '%svoot-web/content/generic/movies-by-language?language=include:%s&sort=mostpopular:desc&&page=%s&responseType=common' % (
+ apiUrl, lang, page_no)
+ movies = requests.get(url, headers=headers).json()
+
+ next_page = int(movies["page"]) + 1
+ for movie in movies["result"]:
+ item = Listitem()
+ item.label = movie["fullTitle"]
+ item.art["thumb"] = f'http://v3img.voot.com/{movie["imageUri"]}'
+ item.art["fanart"] = f'http://v3img.voot.com/{movie["imageUri"]}'
+ item.info["plot"] = movie["fullSynopsis"]
+ item.set_callback(play_video, video_id=movie["id"])
+
+ yield item
+ yield Listitem.next_page(page_no=next_page, lang=lang, callback=list_voot_movies)
+
+
+@Route.register
+def list_voot_shows(plugin, lang, page_no):
+ url = f"https://psapi.voot.com/jio/voot/v1/voot-web/content/generic/filtered-shows?sort=mostpopular:desc&language=include:{lang}&page={page_no}&responseType=common"
+ jd = requests.get(url, headers=headers).json()
+ shows = jd['result']
+ next_page = int(jd["page"]) + 1
+ for show in shows:
+ item = Listitem()
+ item.label = show["fullTitle"]
+ item.art["thumb"] = f'http://v3img.voot.com/{show["imageUri"]}'
+ item.art["fanart"] = f'http://v3img.voot.com/{show["imageUri"]}'
+ item.info["plot"] = show["fullSynopsis"]
+ item.set_callback(list_seasons, show_id=show["id"], Page_No="1")
+
+ yield item
+ yield Listitem.next_page(page_no=next_page, lang=lang, callback=list_voot_shows)
+
+
+@Route.register
+def list_seasons(plugin, show_id, Page_No):
+ url = '%svoot-web/content/generic/season-by-show?sort=season:desc&id=%s&page=%s&responseType=common' % (
+ apiUrl, show_id, Page_No)
+
+ jd = requests.get(url, headers=headers).json()
+ next_page = int(jd["page"]) + 1
+ seasons = jd["result"]
+
+ for season in seasons:
+ item = Listitem()
+ item.label = season["fullTitle"]
+ item.art["thumb"] = f'http://v3img.voot.com/{season["imageUri"]}'
+ item.art["fanart"] = f'http://v3img.voot.com/{season["imageUri"]}'
+ item.info["plot"] = season["fullSynopsis"]
+ item.set_callback(list_episodes, season_id=season["id"], Page_No="1")
+ yield item
+ yield Listitem.next_page(Page_No=next_page, show_id=show_id, callback=list_seasons)
+
+
+@Route.register
+def list_episodes(plugin, season_id, Page_No):
+ url = '%svoot-web/content/generic/series-wise-episode?sort=episode:desc&id=%s&&page=%s&responseType=common' % (
+ apiUrl, season_id, Page_No)
+
+ jd = requests.get(url, headers=headers).json()
+ next_page = int(jd["page"]) + 1
+
+ episodes = jd["result"]
+ for episode in episodes:
+ item = Listitem()
+ item.label = episode["fullTitle"]
+ item.art["thumb"] = f'http://v3img.voot.com/{episode["imageUri"]}'
+ item.art["fanart"] = f'http://v3img.voot.com/{episode["imageUri"]}'
+ item.info["plot"] = episode["fullSynopsis"]
+ item.set_callback(play_video, video_id=episode["id"])
+ yield item
+ yield Listitem.next_page(Page_No=next_page, season_id=season_id, callback=list_episodes)
+
+
+@Resolver.register
+def play_video(plugin, video_id):
+ return Listitem().from_dict(**{
+ "label": "Playing",
+ "callback": direct_link(video_id),
+ "properties": {
+ "inputstream.adaptive.manifest_type": "hls",
+ "inputstream": "inputstream.adaptive"
+
+ }
+ })
diff --git a/resources/settings.xml b/resources/settings.xml
new file mode 100644
index 0000000..96f7359
--- /dev/null
+++ b/resources/settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..ad2917c
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,2 @@
+# Tests
+This folder should be the home for your unit tests
\ No newline at end of file