Repository: mov-cli/mov-cli (language: python)

Issue:
Features.. without updating? (Trojan horse?)
For the not-that-technologically savvy bunch of you or the ones needing a TLDR: this codebase is a potential [trojan horse](https://en.wikipedia.org/wiki/Trojan_horse_(computing)).

**Question**
Where do I thank the developer for adding means to add features without the user ever updating the code?

We're [evaluating a file, with 0 restrictions](https://github.com/mov-cli/mov-cli/blob/8b99fd/mov_cli/utils/lang.py#L9). The target file seems similar to what a JSON file could potentially be, but obviously [line 5](https://github.com/mov-cli/mov-cli/blob/8b99fd/mov_cli/utils/lang.py#L5) already imports a JSON parsing library and it isn't used. So a reasonable conclusion can be made that there's an underlying intent of adding a "feature", malicious or not being totally out of the question, to the codebase without any "update" necessary on the client's end.

This is known as [Remote Code Execution](https://en.wikipedia.org/wiki/RCE_-_Remote_Code_Execution). In this instance, it isn't even conditionally executed. It is executed on **each and every run** of this project. There's no defending it, unless of course this is intentional.

This breaks any trust that a potential or an existing user could have from your project. Kindly remove such instances, and maybe be a little competent over future commits.

I'd very much advise to also get rid of the file that is being "executed". Obviously, the damage is irreparable. Any user before [this commit](https://github.com/mov-cli/mov-cli/tree/8b99fd/) has a potential risk of an attack on their device.


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 11072580..dca977f2 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@
   </a>
 
   <p align="center">
- A cli tool to browse and watch Movies/Shows/TV/Sports. 
+    A cli tool to browse and watch Movies/Shows/TV/Sports. 
     <br />
     <br />
     <a href="https://github.com/mov-cli/mov-cli/issues">Report Bug</a>
@@ -72,14 +72,12 @@
 <!-- ABOUT THE PROJECT -->
 ## About The Project
 
+The new and improved mov-cli is here.
+
 mov-cli is a Commandline Tool to watch and download shows and movies.
 
-Shows and Movies are scraped from Streaming Sites.
+Shows and Movies are sourced from Streaming Sites.
 
-mov-cli currently scrapes 15 Providers:
-```
-Actvid · SFlix · Solar · DopeBox · WLEXT · KinoX · StreamBlasters · TamilYogi · Einthusan · ViewAsian · Watchasian · GogoAnime · Eja · KimCartoon · Turkish123
-```
 <p align="right">(<a href="#readme-top">back to top</a>)</p
 
 <!-- GETTING STARTED -->
diff --git a/mov_cli/__init__.py b/mov_cli/__init__.py
index 29c0be85..c07e9455 100644
--- a/mov_cli/__init__.py
+++ b/mov_cli/__init__.py
@@ -1,7 +1,17 @@
 import argparse
+from .utils.props import home
 
 args_parser = argparse.ArgumentParser()
-args_parser.add_argument("--flatpak-mpv", action = argparse.BooleanOptionalAction)
-
+args_parser.add_argument("--flatpak-mpv", action="store_true")
+args_parser.add_argument("--vlc", action="store_true")
+args_parser.add_argument("--pupdate", action="store_true")
+args_parser.add_argument("--debug", action="store_true", required=False)
+args_parser.add_argument("-p", required=False, help="Select Provider from Terminal")
+args_parser.add_argument("-s", required=False, help="Search from the Terminal")
 CMD_ARGS = args_parser.parse_args()
-"""Arguments parsed from the command line via argparse."""
\ No newline at end of file
+
+if CMD_ARGS.pupdate:
+    from .utils.select import updateProvider
+    updateProvider()
+
+"""Arguments parsed from the command line via argparse."""
diff --git a/mov_cli/__main__.py b/mov_cli/__main__.py
index d7388530..5a8abaea 100644
--- a/mov_cli/__main__.py
+++ b/mov_cli/__main__.py
@@ -1,65 +1,27 @@
 import os
 import platform
-from .utils.provider import ask
+from .utils.select import ask
 from .utils.scraper import WebScraper
-
-from .websites.eja import eja
-
-# from .websites.kimcartoon import kimcartoon
-from .websites.actvid import actvid
-from .websites.dopebox import dopebox
-from .websites.sflix import sflix
-from .websites.solar import solar
-from .websites.viewasian import viewasian
-from .websites.gogoanime import gogoanime
-from .websites.watchasian import watchasian
-from .websites.wlext import wlext
-from .websites.streamblasters import streamblasters
-from .websites.tamilyogi import tamilyogi
-from .websites.einthusan import einthusan
-from .websites.turkish123 import turkish123
-from .websites.animefox import animefox
-from .websites.scdn import scdn
-from .websites.openloadmov import openloadmov
-from .websites.remotestream import remotestream
-from .websites.kisscartoon import kisscartoon
-from .websites.yoturkish import yoturkish
-
-calls = {
-    "eja": [eja, "https://eja.tv"],
-    # "kimcartoon": [kimcartoon, "https://kimcartoon.li"],
-    "actvid": [actvid, "https://www.actvid.com"],
-    "sflix": [sflix, "https://sflix.se"],
-    "solar": [solar, "https://solarmovie.pe"],
-    "dopebox": [dopebox, "https://dopebox.to"],
-    "viewasian": [viewasian, "https://viewasian.co"],
-    "gogoanime": [gogoanime, "https://gogoanimehd.to"],
-    "watchasian": [watchasian, "https://watchasian.mx"],
-    "wlext": [wlext, "https://wlext.is"],
-    "streamblasters": [streamblasters, "https://streamblasters.pro"],
-    "tamilyogi": [tamilyogi, "https://tamilyogi.news"],
-    "einthusan": [einthusan, "https://einthusan.tv"],
-    "turkish123": [turkish123, "https://turkish123.ac"],
-    "animefox": [animefox, "https://animefox.to"],
-    "scdn": [scdn, ""],
-    "openloadmov": [openloadmov, "https://openloadmov.com"],
-    "remotestream": [remotestream, "https://remotestre.am"],
-    "kisscartoon": [kisscartoon, "https://thekisscartoon.com"],
-    "yoturkish": [yoturkish, "https://www1.yoturkish.com"],
-}
+from . import CMD_ARGS
 
 if platform.system() == "Windows":
     os.system("color FF")  # Fixes colour in Windows 10 CMD terminal
 
-def movcli():  # TODO add regex
-    try:
-        provider = ask()
-        provider_data = calls.get(provider, calls["actvid"])
-        provider: WebScraper = provider_data[0](provider_data[1])
-        # provider.redo(query) if query is not None else provider.redo()
-        provider.redo()  # if result else provider.redo(query)
-    except UnicodeDecodeError:
-        print("[!] The Current Key is not correct, please wait.")
+
+def movcli(): # TODO add regex
+    if CMD_ARGS.debug:
+        cl, url = ask(CMD_ARGS.p)
+        provider: WebScraper = cl.Provider(url)
+        provider.redo(CMD_ARGS.s)
+    else:
+        try:
+            cl, url = ask(CMD_ARGS.p)
+            provider: WebScraper = cl.Provider(url)
+            provider.redo(CMD_ARGS.s)
+        except UnicodeDecodeError:
+            print("[!] The Current Key is not correct, please wait.")
+        except Exception as e:
+            print(f"[!] An Exception has occurred | {e}")
 
 
 if __name__ == "__main__":
diff --git a/mov_cli/extractors/doodstream.py b/mov_cli/extractors/doodstream.py
index 1afa73fd..fdcad3ca 100644
--- a/mov_cli/extractors/doodstream.py
+++ b/mov_cli/extractors/doodstream.py
@@ -1,5 +1,6 @@
 import re
 import httpx
+from ..utils.props import SelectedNotAvailable
 
 
 def dood(url):
@@ -13,8 +14,10 @@ def dood(url):
         f"https://dood.to/e/{video_id}", headers=headers, follow_redirects=True
     )
     webpage_html = webpage_html.text
-    print(webpage_html)
-    pass_md5 = re.search(r"/pass_md5/[^']*", webpage_html).group()
+    try:
+        pass_md5 = re.search(r"/pass_md5/[^']*", webpage_html).group()
+    except:
+        raise SelectedNotAvailable
     urlh = f"https://dood.to{pass_md5}"
     headers = {
         "User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0",
diff --git a/mov_cli/extractors/tukipasti.py b/mov_cli/extractors/tukipasti.py
new file mode 100644
index 00000000..ba93edac
--- /dev/null
+++ b/mov_cli/extractors/tukipasti.py
@@ -0,0 +1,10 @@
+import httpx
+import re
+
+
+def tukipasti(html):
+    regex = r'''var copyTexti= \['<iframe width="100%" height="100%" src="https:\/\/tukipasti\.com(.*?)"'''
+    s = re.findall(regex, html)[0]
+    req = httpx.get(f"https://tukipasti.com{s}").text
+    url = re.findall("var urlPlay = '(.*?)'", req)[0]
+    return url, f"https://tukipasti.com{s}"
diff --git a/mov_cli/players/player.py b/mov_cli/players/player.py
index 45a1488a..0f60dd9e 100644
--- a/mov_cli/players/player.py
+++ b/mov_cli/players/player.py
@@ -28,11 +28,13 @@ def play(self, url: str, referrer: str, media_title: str) -> subprocess.Popen:
                     f"{url}",
                 ]
             )
-    
+
         elif self.os == "iOS":
             print("[!] Detected your using iOS. \r\n")
-            
-            print(f'\033]8;;outplayer://{url}\033\\-------------------------\n- Tap to open Outplayer -\n-------------------------\033]8;;\033\\\n')
+
+            print(
+                f"\033]8;;outplayer://{url}\033\\-------------------------\n- Tap to open Outplayer -\n-------------------------\033]8;;\033\\\n"
+            )
 
             sys.exit(1)
 
@@ -46,15 +48,27 @@ def play(self, url: str, referrer: str, media_title: str) -> subprocess.Popen:
                         "--no-terminal",
                     ]
 
-                    if CMD_ARGS.flatpak_mpv and self.os == "Linux": # Support for MPV on Flatpak.
+                    if (
+                        CMD_ARGS.flatpak_mpv and self.os == "Linux"
+                    ):  # Support for MPV on Flatpak.
                         print("Using flatpak installation of MPV.")
                         return subprocess.Popen(
                             ["flatpak", "run", "io.mpv.Mpv"] + mpv_args
                         )
 
-                    return subprocess.Popen(
-                        ["mpv"] + mpv_args
-                    )
+                    if CMD_ARGS.vlc:
+                        vlc_args = [
+                            "vlc",
+                            f'--http-referrer="{referrer}"',
+                            f'"{url}"',
+                            f'--meta-title="mov-cli:{media_title}"',
+                            "--no-terminal",
+                        ]
+                        try:
+                            return subprocess.Popen(vlc_args)
+                        except:
+                            raise PlayerNotFound(self)
+                    return subprocess.Popen(["mpv"] + mpv_args)
 
                 elif self.os == "Darwin":
                     return subprocess.Popen(
@@ -69,8 +83,9 @@ def play(self, url: str, referrer: str, media_title: str) -> subprocess.Popen:
                     )
 
                 else:
-                    print("[!] Could not determine what Player to use on your OS")
-                    sys.exit(1)
+                    raise Exception(
+                        "[!] Could not determine what Player to use on your OS"
+                    )
 
             except ModuleNotFoundError:
                 raise PlayerNotFound(self)
diff --git a/mov_cli/utils/dbs.py b/mov_cli/utils/dbs.py
deleted file mode 100644
index 42dba4cb..00000000
--- a/mov_cli/utils/dbs.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import re
-
-import httpx
-from bs4 import BeautifulSoup as BS
-
-
-def get_imdb_id(query: str) -> str:
-    query = query.replace(" ", "_")
-    req = httpx.get(
-        f"https://v2.sg.media-imdb.com/suggestion/{query[0].lower()}/{query}.json"
-    ).json()["d"]
-    print(req)
-    return req[0]["id"]
-
-
-def get_imdb_title(query: str) -> str:
-    query = query.replace(" ", "-")
-    req = httpx.get(
-        f"https://v2.sg.media-imdb.com/suggestion/{query[0].lower()}/{query}.json"
-    ).json()["d"][0]["l"]
-    return req
-
-
-def get_imdb_title_and_img(query: str) -> str:
-    query = query.replace(" ", "-")
-    req = httpx.get(
-        f"https://v2.sg.media-imdb.com/suggestion/{query[0].lower()}/{query}.json"
-    ).json()
-    title = req["d"][0]["l"]
-    img = req["d"][0]["i"]["imageUrl"]
-    return title, img
-
-
-def get_season_seasons(tmdb_id: str, name: str) -> int:
-    req = httpx.get(
-        f"https://www.themoviedb.org/tv/{tmdb_id}-{parse(name)}/seasons"
-    ).text
-    rem = BS(req, self.scraper)
-    seasons = [i.text for i in rem.select(".flex > div.season_wrapper")]
-    return len(seasons)
-
-
-def get_season_episodes(tmdb_id: str, name: str, season_number: str) -> int:
-    req = httpx.get(
-        f"https://www.themoviedb.org/tv/{tmdb_id}-{parse(name)}/season/{season_number}"
-    ).text
-    episodes = int(BS(req, self.scraper).select_one(".episode_sort.space > span").text)
-    return episodes
-
-
-def parse(text: str) -> str:
-    return re.sub(r"\W+", "-", text.lower())
diff --git a/mov_cli/utils/httpclient.py b/mov_cli/utils/httpclient.py
index 81f6b061..8cbfe9bd 100644
--- a/mov_cli/utils/httpclient.py
+++ b/mov_cli/utils/httpclient.py
@@ -2,7 +2,7 @@
 
 import httpx
 
-default_header: dict = {
+DEFAULT_HEADERS: dict = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
     "Chrome/80.0.3987.163 "
     "Safari/537.36",
@@ -13,7 +13,7 @@
 class HttpClient:
     def __init__(self, headers: dict = None, cookies: dict = None):
         if headers is None:
-            headers = default_header
+            headers = DEFAULT_HEADERS
         self.session = httpx.Client(timeout=10.0, headers=headers, cookies=cookies)
 
     def get(self, page: str, redirects: bool = False) -> httpx.Response:
@@ -21,9 +21,9 @@ def get(self, page: str, redirects: bool = False) -> httpx.Response:
         try:
             req = self.session.get(page, follow_redirects=redirects)
             self.session.headers["Referer"] = page
-        except Exception as e:
+        except httpx.TimeoutException:
             print(
-                f"Error: {e}",
+                f"Error: Timeout",
                 "\n Please open an issue if this is not due to your internet connection",
             )
             sys.exit(-1)
@@ -35,9 +35,9 @@ def post(self, page: str, data: dict = None, json=None) -> httpx.Response:
             try:
                 req = self.session.post(page, data=data)
                 self.session.headers["Referer"] = page
-            except Exception as e:
+            except httpx.TimeoutException:
                 print(
-                    f"Error: {e}",
+                    f"Error: Timeout",
                     "\n Please open an issue if this is not due to your internet connection",
                 )
                 sys.exit(-1)
@@ -46,22 +46,22 @@ def post(self, page: str, data: dict = None, json=None) -> httpx.Response:
             try:
                 req = self.session.post(page, json=json)
                 self.session.headers["Referer"] = page
-            except Exception as e:
+            except httpx.TimeoutException:
                 print(
-                    f"Error: {e}",
+                    f"Error: Timeout",
                     "\n Please open an issue if this is not due to your internet connection",
                 )
                 sys.exit(-1)
             return req
 
-    def head(self, page: str, redirects: False) -> httpx.Response:
+    def head(self, page: str, redirects: bool = False) -> httpx.Response:
         print(page)
         try:
             req = self.session.head(page, follow_redirects=redirects)
             self.session.headers["Referer"] = page
-        except Exception as e:
+        except httpx.TimeoutException:
             print(
-                f"Error: {e}",
+                f"Error: Timeout",
                 "\n Please open an issue if this is not due to your internet connection",
             )
             sys.exit(-1)
diff --git a/mov_cli/utils/jsunpack.py b/mov_cli/utils/jsunpack.py
deleted file mode 100644
index 186b5a49..00000000
--- a/mov_cli/utils/jsunpack.py
+++ /dev/null
@@ -1,184 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    ResolveUrl Kodi Addon
-    Copyright (C) 2013 Bstrdsmkr
-    Additional fixes by mortael, jairoxyz
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-    Adapted for use in xbmc from:
-    https://github.com/beautify-web/js-beautify/blob/master/python/jsbeautifier/unpackers/packer.py
-    Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
-    by Einar Lielmanis <einar@jsbeautifier.org>
-        written by Stefano Sanfilippo <a.little.coder@gmail.com>
-    usage:
-    if detect(some_string):
-        unpacked = unpack(some_string)
-    Unpacker for Dean Edward's p.a.c.k.e.r
-"""
-
-import re
-import binascii
-from six import PY2
-
-
-def detect(source):
-    """Detects whether `source` is P.A.C.K.E.R. coded."""
-    mystr = re.search(
-        r"eval[ ]*\([ ]*function[ ]*\([ ]*p[ ]*,[ ]*a[ ]*,[ ]*c["
-        r" ]*,[ ]*k[ ]*,[ ]*e[ ]*,[ ]*",
-        source,
-    )
-    return mystr is not None
-
-
-def unpack(source):
-    """Unpacks P.A.C.K.E.R. packed js code."""
-    payload, symtab, radix, count = _filterargs(source)
-
-    if count != len(symtab):
-        raise UnpackingError("Malformed p.a.c.k.e.r. symtab.")
-
-    try:
-        unbase = Unbaser(radix)
-    except TypeError:
-        raise UnpackingError("Unknown p.a.c.k.e.r. encoding.")
-
-    def lookup(match):
-        """Look up symbols in the synthetic symtab."""
-        word = match.group(0)
-        return symtab[int(word)] if radix == 1 else symtab[unbase(word)] or word
-
-    def getstring(c, a=radix):
-        foo = chr(c % a + 161)
-        if c < a:
-            return foo
-        else:
-            return getstring(int(c / a), a) + foo
-
-    payload = payload.replace("\\\\", "\\").replace("\\'", "'")
-    p = re.search(r"eval\(function\(p,a,c,k,e.+?String\.fromCharCode\(([^)]+)", source)
-    if p:
-        pnew = (
-            re.findall(r"String\.fromCharCode\(([^)]+)", source)[0].split("+")[1]
-            == "161"
-        )
-    else:
-        pnew = False
-
-    if pnew:
-        for i in range(count - 1, -1, -1):
-            payload = payload.replace(
-                getstring(i).decode("latin-1") if PY2 else getstring(i), symtab[i]
-            )
-        return _replacejsstrings((_replacestrings(payload)))
-    else:
-        source = (
-            re.sub(r"\b\w+\b", lookup, payload)
-            if PY2
-            else re.sub(r"\b\w+\b", lookup, payload, flags=re.ASCII)
-        )
-        return _replacestrings(source)
-
-
-def _filterargs(source):
-    """Juice from a source file the four args needed by decoder."""
-    argsregex = r"}\s*\('(.*)',\s*(.*?),\s*(\d+),\s*'(.*?)'\.split\('\|'\)"
-    args = re.search(argsregex, source, re.DOTALL).groups()
-
-    try:
-        payload, radix, count, symtab = args
-        radix = 36 if not radix.isdigit() else int(radix)
-        return payload, symtab.split("|"), radix, int(count)
-    except ValueError:
-        raise UnpackingError("Corrupted p.a.c.k.e.r. data.")
-
-
-def _replacestrings(source):
-    """Strip string lookup table (list) and replace values in source."""
-    match = re.search(r'var *(_\w+)=\["(.*?)"];', source, re.DOTALL)
-
-    if match:
-        varname, strings = match.groups()
-        startpoint = len(match.group(0))
-        lookup = strings.split('","')
-        variable = "%s[%%d]" % varname
-        for index, value in enumerate(lookup):
-            if "\\x" in value:
-                value = value.replace("\\x", "")
-                value = binascii.unhexlify(value).decode("ascii")
-            source = source.replace(variable % index, '"%s"' % value)
-        return source[startpoint:]
-    return source
-
-
-def _replacejsstrings(source):
-    """Strip JS string encodings and replace values in source."""
-    match = re.findall(r"\\x([0-7][0-9A-F])", source)
-
-    if match:
-        match = set(match)
-        for value in match:
-            source = source.replace(
-                "\\x{0}".format(value), binascii.unhexlify(value).decode("ascii")
-            )
-
-    return source
-
-
-class Unbaser(object):
-    """Functor for a given base. Will efficiently convert
-    strings to natural numbers."""
-
-    ALPHABET = {
-        62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
-        95: (
-            r' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-            r"[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
-        ),
-    }
-
-    def __init__(self, base):
-        self.base = base
-
-        # If base can be handled by int() builtin, let it do it for us
-        if 2 <= base <= 36:
-            self.unbase = lambda string: int(string, base)
-        else:
-            if base < 62:
-                self.ALPHABET[base] = self.ALPHABET[62][0:base]
-            elif 62 < base < 95:
-                self.ALPHABET[base] = self.ALPHABET[95][0:base]
-            # Build conversion dictionary cache
-            try:
-                self.dictionary = dict(
-                    (cipher, index) for index, cipher in enumerate(self.ALPHABET[base])
-                )
-            except KeyError:
-                raise TypeError("Unsupported base encoding.")
-
-            self.unbase = self._dictunbaser
-
-    def __call__(self, string):
-        return self.unbase(string)
-
-    def _dictunbaser(self, string):
-        """Decodes a  value to an integer."""
-        ret = 0
-        for index, cipher in enumerate(string[::-1]):
-            ret += (self.base**index) * self.dictionary[cipher]
-        return ret
-
-
-class UnpackingError(Exception):
-    """Badly packed source or general error. Argument is a
-    meaningful description."""
-
-    pass
diff --git a/mov_cli/utils/lang.py b/mov_cli/utils/lang.py
index ed82e132..fba3a015 100644
--- a/mov_cli/utils/lang.py
+++ b/mov_cli/utils/lang.py
@@ -1,28 +1,38 @@
 import httpx
-import platform as pf
-import os
-from os import environ
-import json
 from fzf import fzf_prompt
+from .props import home
+import mov_cli.__main__ as mc
+from json import loads
+from .props import RestartNeeded, LanguageNotAOption
+from pkgutil import get_data
 
-sel = eval(
-    httpx.get("https://raw.githubusercontent.com/mov-cli/translations/main/langs").text
-)
+langsfile = get_data(__name__, "lang/langs")
 
+sel = eval(langsfile)
 
-def homepath() -> str:
-    plt = pf.system()
-    if plt == "Windows":
-        username = environ["username"]
-        return f"C:/Users/{username}/"
-    elif (plt == "Linux") or (plt == "Darwin"):
-        return f"/home/{os.getlogin()}/"
+def existing(language: str, g=False):
+    js = loads(langsfile)
 
+    exist = False
+
+    if g is False:
+        for _, value in js.items():
+            if value == language:
+                exist = True
+        if not exist:
+            raise LanguageNotAOption(language)
+    else:
+        for _, value in js.items():
+            if value == language:
+                exist = True
+        return exist
 
 def getlang():
     try:
-        with open(homepath() + "lang.json", "r") as f:
-            t = json.load(f)
+        with open(home() + "lang.mov-cli", "r") as f:
+            lang = f.read()
+        existing(lang)
+        t = loads(get_data(__name__, f"lang/{lang}.json"))
         ask = t["ASK"]
         ex = t["EXIT"]
         searcha = t["SEARCHA"]
@@ -36,42 +46,19 @@ def getlang():
         t = [ask, ex, searcha, download, spro, dshow, dseason, season, episode, change]
         return t
     except FileNotFoundError:
-        t = httpx.get(
-            "https://raw.githubusercontent.com/mov-cli/translations/main/languages/en.json"
-        ).json()
-        ask = t["ASK"]
-        ex = t["EXIT"]
-        searcha = t["SEARCHA"]
-        download = t["DOWNLOAD"]
-        spro = t["SPROVIDER"]
-        dshow = t["DSHOW"]
-        dseason = t["DSEASON"]
-        season = t["SEASON"]
-        episode = t["EPISODE"]
-        change = t["CHANGE"]
-        t = [ask, ex, searcha, download, spro, dshow, dseason, season, episode, change]
-        return t
-    except json.decoder.JSONDecodeError:
-        plt = pf.system()
-        if plt == "Windows":
-            username = environ["username"]
-            print(
-                rf"Please delete the lang.json in this directory: C:\Users\{username}"
-            )
-            exit(0)
-        elif (plt == "Linux") or (plt == "Darwin"):
-            print(
-                f"Please delete the lang.json in this directory: /home/{os.getlogin()}/"
-            )
-            exit(0)
+        import locale
 
+        localLang = locale.getdefaultlocale()[0][:2]
+        check = existing(localLang, True)
+        if check is True:
+            lang = localLang
+        else:
+            lang = "en"
+        open(home() + "lang.mov-cli", "w").write(lang)
+        print(f"[?] Your Language was set to {lang}")
+        raise RestartNeeded
 
 def setlang():
     s = fzf_prompt(sel)
     selection = sel.get(s)
-    print(selection)
-    txt = httpx.get(
-        f"https://raw.githubusercontent.com/mov-cli/translations/main/languages/{selection}.json"
-    ).text
-    with open(homepath() + "lang.json", "w") as f:
-        f.write(txt)
+    open(home() + "lang.mov-cli", "w").write(selection)
diff --git a/mov_cli/utils/lang/ar.json b/mov_cli/utils/lang/ar.json
new file mode 100644
index 00000000..f6118f89
--- /dev/null
+++ b/mov_cli/utils/lang/ar.json
@@ -0,0 +1,12 @@
+{
+  "ASK": "ماذا تريد ان تشاهد: ",
+  "EXIT": "خروج",
+  "SEARCHA": "بحث مرة اخري",
+  "DOWNLOAD": "تنزيل",
+  "SPROVIDER": "تغيير المزود",
+  "DSHOW": "تنزيل المسلسل",
+  "DSEASON": "تحميل الموسم",
+  "SEASON": "الموسم",
+  "EPISODE": "الحلقه",
+  "CHANGE": "تغيير اللغه"
+}
diff --git a/mov_cli/utils/lang/de.json b/mov_cli/utils/lang/de.json
new file mode 100644
index 00000000..c5288c5c
--- /dev/null
+++ b/mov_cli/utils/lang/de.json
@@ -0,0 +1,12 @@
+{
+    "ASK": "Was möchtest du gerne schauen: ",
+    "EXIT": "Beenden",
+    "SEARCHA": "Noch mal suchen",
+    "DOWNLOAD": "Herunterladen",
+    "SPROVIDER": "Anbieter wechseln",
+    "DSHOW": "Die Ganze Serie herunterladen",
+    "DSEASON": "Eine Staffel herunterladen",
+    "SEASON": "Staffel",
+    "EPISODE": "Episode",
+    "CHANGE": "Ändere die Sprache"
+}
\ No newline at end of file
diff --git a/mov_cli/utils/lang/en.json b/mov_cli/utils/lang/en.json
new file mode 100644
index 00000000..27c7d2c4
--- /dev/null
+++ b/mov_cli/utils/lang/en.json
@@ -0,0 +1,12 @@
+{
+    "ASK": "What would you like to watch: ",
+    "EXIT": "Exit",
+    "SEARCHA": "Search Again",
+    "DOWNLOAD": "Download",
+    "SPROVIDER": "Switch Provider",
+    "DSHOW": "Download Show",
+    "DSEASON": "Download Season",
+    "SEASON": "Season",
+    "EPISODE": "Episode",
+    "CHANGE": "Change Language"
+}
\ No newline at end of file
diff --git a/mov_cli/utils/lang/fr.json b/mov_cli/utils/lang/fr.json
new file mode 100644
index 00000000..a40d942b
--- /dev/null
+++ b/mov_cli/utils/lang/fr.json
@@ -0,0 +1,12 @@
+{
+    "ASK": "Qu'aimeriez-vous regarder: ",
+    "EXIT": "Sortir",
+    "SEARCHA": "Chercher à nouveau",
+    "DOWNLOAD": "Télécharger",
+    "SPROVIDER": "Changer de fournisseur",
+    "DSHOW": "Télécharger la série",
+    "DSEASON": "Télécharger la saison",
+    "SEASON": "Saison",
+    "EPISODE": "Episode",
+    "CHANGE": "Changer de langue"
+}
diff --git a/mov_cli/utils/lang/ko.json b/mov_cli/utils/lang/ko.json
new file mode 100644
index 00000000..6083e8f0
--- /dev/null
+++ b/mov_cli/utils/lang/ko.json
@@ -0,0 +1,12 @@
+{
+    "ASK": "무엇을 보고 싶으세요: ",
+    "EXIT": "종료",
+    "SEARCHA": "다시 검색",
+    "DOWNLOAD": "다운로드",
+    "SPROVIDER": "제공업체 변경",
+    "DSHOW": "방송 다운로드",
+    "DSEASON": "시즌 다운로드",
+    "SEASON": "시즌",
+    "EPISODE": "에피소드",
+    "CHANGE": "언어 바꾸기"
+}
diff --git a/mov_cli/utils/lang/langs b/mov_cli/utils/lang/langs
new file mode 100644
index 00000000..3bae9be7
--- /dev/null
+++ b/mov_cli/utils/lang/langs
@@ -0,0 +1,11 @@
+{
+  "Arabic": "ar",
+  "Deutsch": "de",
+  "English": "en",
+  "Français": "fr",
+  "한국어": "ko",
+  "Русский": "ru",
+  "Português": "pt",
+  "Polski": "pl",
+  "தமிழ்": "ta"
+}
diff --git a/mov_cli/utils/lang/pl.json b/mov_cli/utils/lang/pl.json
new file mode 100644
index 00000000..70f7a138
--- /dev/null
+++ b/mov_cli/utils/lang/pl.json
@@ -0,0 +1,12 @@
+{
+    "ASK": "Co chciałbyś obejrzeć: ",
+    "EXIT": "Wyjdź",
+    "SEARCHA": "Wyszukaj ponownie",
+    "DOWNLOAD": "Pobierz",
+    "SPROVIDER": "Zmień dostawcę",
+    "DSHOW": "Pobierz serial",
+    "DSEASON": "Pobierz sezon",
+    "SEASON": "Sezon",
+    "EPISODE": "Odcinek",
+    "CHANGE": "Zmień język"
+}
\ No newline at end of file
diff --git a/mov_cli/utils/lang/pt.json b/mov_cli/utils/lang/pt.json
new file mode 100644
index 00000000..723b75d8
--- /dev/null
+++ b/mov_cli/utils/lang/pt.json
@@ -0,0 +1,12 @@
+{
+	"ASK": "Oque voce gostaria de assistir: ",
+	"EXIT": "Sair",
+	"SEARCHA": "Pesquisar Novamente",
+	"DOWNLOAD": "Baixar",
+	"SPROVIDER": "Trocar Provedor",
+	"DSHOW": "Baixar serie",
+	"DSEASON": "Baixar Temporada",
+	"SEASON": "Temporada",
+	"EPISODE": "Episodio",
+	"CHANGE": "Trocar Idioma"
+}
diff --git a/mov_cli/utils/lang/ru.json b/mov_cli/utils/lang/ru.json
new file mode 100644
index 00000000..fbb0b9c1
--- /dev/null
+++ b/mov_cli/utils/lang/ru.json
@@ -0,0 +1,12 @@
+{
+    "ASK": "Что бы вы хотели посмотреть: ",
+    "EXIT": "Выход",
+    "SEARCHA": "Cнова скать",
+    "DOWNLOAD": "Скачать",
+    "SPROVIDER": "Переменять nровайдер",
+    "DSHOW": "Скачать шоу",
+    "DSEASON": "Скачать сезон",
+    "SEASON": "сезон",
+    "EPISODE": "Эпизод",
+    "CHANGE": "Переменять языка"
+}
diff --git a/mov_cli/utils/lang/ta.json b/mov_cli/utils/lang/ta.json
new file mode 100644
index 00000000..82e92370
--- /dev/null
+++ b/mov_cli/utils/lang/ta.json
@@ -0,0 +1,12 @@
+{
+    "ASK": "நீங்கள் பார்க்க விரும்புவது என்ன: ",
+    "EXIT": "வெளியேறு",
+    "SEARCHA": "மீண்டும் தேடவும்",
+    "DOWNLOAD": "பதிவிறக்கம்",
+    "SPROVIDER": "வழங்குநரை மாற்று",
+    "DSHOW": "நிகழ்ச்சியைப் பதிவிறக்கவும்",
+    "DSEASON": "பருவத்தைப் பதிவிறக்கவும்",
+    "SEASON": "பருவம்",
+    "EPISODE": "அத்தியாயம்",
+    "CHANGE": "மொழியை மாற்று"
+}
diff --git a/mov_cli/utils/player.py b/mov_cli/utils/player.py
index f929bce0..b64a6865 100644
--- a/mov_cli/utils/player.py
+++ b/mov_cli/utils/player.py
@@ -29,9 +29,9 @@ def display_name(self) -> str:
     @property
     def os(self) -> str:
         """
-        Returns the operating system we're currently running on. (Adds android detection.)
+        Returns the operating system we're currently running on.
 
-        E.g. Windows, Linux, Android, Darwin
+        E.g. Windows, Linux, Android, Darwin, iOS
         """
         if self.__os == "Linux":
             if hasattr(sys, "getandroidapilevel"):
diff --git a/mov_cli/utils/props.py b/mov_cli/utils/props.py
new file mode 100644
index 00000000..704352e6
--- /dev/null
+++ b/mov_cli/utils/props.py
@@ -0,0 +1,42 @@
+from platform import system as pf
+from os import environ
+from getpass import getuser
+
+
+def home():
+    plt = pf()
+    if plt == "Windows":
+        username = environ["username"]
+        return f"C:/Users/{username}/"
+    elif (plt == "Linux") or (plt == "Darwin"):
+        return f"/home/{getuser()}/"
+
+
+class RestartNeeded(Exception):
+    """Raise when mov-cli is needed to restart."""
+
+    def __init__(self) -> None:
+        super().__init__(f"Please restart mov-cli.")
+
+
+class LanguageNotAOption(Exception):
+    """Raise when Language is not a Option."""
+
+    def __init__(self, lang) -> None:
+        super().__init__(
+            f"This language '{lang}' is not available Option in the Language's tab. \r\nPlease delete provider.mov-cli in your home directory."
+        )
+
+
+class SelectedNotAvailable(Exception):
+    """Raise when the selected item is not Available or was removed."""
+
+    def __init__(self) -> None:
+        super().__init__("Not available or it was removed")
+
+
+class NoSupportedProvider(Exception):
+    """Raise when no supported provider was found."""
+
+    def __init__(self) -> None:
+        super().__init__("No supported provider was found")
diff --git a/mov_cli/utils/provider.py b/mov_cli/utils/provider.py
deleted file mode 100644
index 8ac8d082..00000000
--- a/mov_cli/utils/provider.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from fzf import fzf_prompt
-
-english = ["actvid", "sflix", "solar", "dopebox", "openloadmov", "remotestream"]
-
-# german = ["kinox"] kinox was removed, as it didn't function really.
-
-indian = [
-    "streamblasters",
-    "tamilyogi",
-    "einthusan",
-]
-
-asian = [
-    "viewasian",
-    "watchasian",
-]
-
-anime = ["gogoanime", "animefox"]
-
-tv = ["eja"]
-
-cartoons = ["kisscartoon"]
-
-turkish = ["turkish123", "yoturkish"]
-
-sports = ["scdn"]
-
-update = ["pip install mov-cli -U"]
-
-inter = [
-    "wlext",
-]
-
-preselction = {
-    "English Providers": [english],
-    "Indian Providers": [indian],
-    "Asian Providers": [asian],
-    "LIVE TV Providers": [tv],
-    "Cartoons Providers": [cartoons],
-    "Turkish Providers": [turkish],
-    "Anime Providers": [anime],
-    "Sports Providers": [sports],
-    "International Providers": [inter],
-}
-
-
-def ask():
-    init = fzf_prompt(preselction)
-    get = preselction.get(init)[0]
-    choice = fzf_prompt(get)
-    return choice
diff --git a/mov_cli/utils/scraper.py b/mov_cli/utils/scraper.py
index d50346e2..09745025 100644
--- a/mov_cli/utils/scraper.py
+++ b/mov_cli/utils/scraper.py
@@ -1,10 +1,6 @@
-import logging
-import os
-
-# import platform
+from platform import system as pf
 import re
 import subprocess
-import sys
 
 import mov_cli.__main__ as movcli
 from fzf import fzf_prompt
@@ -14,21 +10,11 @@
 from .player import PlayerNotFound
 from ..players.player import ply
 from ..extractors.doodstream import dood
+from ..extractors.tukipasti import tukipasti
 
 # import shlex
 # required for development
 
-# Not needed
-# def determine_path() -> str:
-#    plt = platform.system()
-#    if plt == "Windows":
-#        return f"C://Users//{os.getenv('username')}//Downloads"
-#    elif (plt == "Linux") or (plt == "Darwin"):
-#        return f"/home/{os.getlogin()}/Downloads"
-#    else:
-#        print("Please open an issue for your os")
-#        sys.exit(-2)
-
 
 class WebScraper:
     def __init__(self, base_url: str) -> None:
@@ -49,6 +35,8 @@ def __init__(self, base_url: str) -> None:
             self.change,
         ) = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
         self.scraper = self.parser()
+        self.dseasonp = False
+        self.dshowp = False
         pass
 
     def parser(self):
@@ -73,7 +61,7 @@ def dl(
         referrer: str = None,
     ):
         name = self.parse(name)
-        fixname = re.sub(r"-+", " ", name)
+        fixname = re.sub(r"-+ +", " ", name)
         if episode:
             fixname = f"{fixname} S{season}E{episode}"
 
@@ -97,12 +85,10 @@ def dl(
         ]
 
         if subtitle:
-            # args.extend(f'-vf subtitle="{subtitle}" {self.parse(name)}.mp4')
             args.extend(["-vf", f"subtitle={subtitle}", f"{fixname}.mp4"])
         ffmpeg_process = subprocess.Popen(args)
         ffmpeg_process.wait()
-
-        return print(f"Downloaded at {os.getcwd()}")
+        return
 
     def play(self, url: str, name: str, referrer=None):
         if referrer is None:
@@ -111,10 +97,10 @@ def play(self, url: str, name: str, referrer=None):
             ply_process = ply(self).play(url, referrer, name)
             ply_process.wait()
         except PlayerNotFound as e:
-            txt = f"{self.red('[!]')} Could not play {name}: Correct Player for your OS was not found| {e}"
+            txt = f"[!] Could not play: Correct Player for your OS was not found | {e}"
             # logging.log(logging.ERROR, txt)
             print(txt)  # TODO implement logging to a file
-            sys.exit(1)
+            exit(1)
 
     def search(self, q: str = None) -> str:
         pass
@@ -124,10 +110,10 @@ def results(self, data: str) -> list:
         pass
         # return NotImplementedError()
 
-    def TV_PandDP(self, t: list, state: str = "d" or "p"):
+    def TV_PandDP(self, t: list, state: str):
         pass
 
-    def MOV_PandDP(self, m: list, state: str = "d" or "p"):
+    def MOV_PandDP(self, m: list, state: str):
         pass
 
     def SandR(self, q: str = None):
@@ -144,18 +130,19 @@ def display(self, q: str = None, result_no: int = None):
                 f"[s] {self.translated[self.searcha]}",
                 f"[d] {self.translated[self.download]}",
                 f"[p] {self.translated[self.sprovider]}",
-                f"[sd] {self.translated[self.dshow]}",
-                f"[ds] {self.translated[self.dseason]}",
                 f"[c] {self.translated[self.change]}",
             ]
         )
         r = r[::-1]
         choice = ""
         while choice not in range(len(result) + 1):
-            pre = fzf_prompt(r)
-            choice = re.findall(r"\[(.*?)\]", pre)[0] if not result_no else result_no
+            choice = (
+                re.findall(r"\[(.*?)\]", fzf_prompt(r))[0]
+                if not result_no
+                else result_no
+            )
             if choice == "q":
-                sys.exit()
+                exit()
             elif choice == "s":
                 return self.redo()
             elif choice == "p":
@@ -165,75 +152,49 @@ def display(self, q: str = None, result_no: int = None):
                 return movcli.movcli()
             elif choice == "d":
                 try:
-                    pre = fzf_prompt(r)
-                    choice = (
-                        re.findall(r"\[(.*?)\]", pre)[0] if not result_no else result_no
-                    )
-                    mov_or_tv = result[int(choice) - 1]
-                    if mov_or_tv[self.mv_tv] == "TV":
-                        self.TV_PandDP(mov_or_tv, "d")
+                    modes = [f"[d] {self.translated[self.download]}"]
+                    if self.dshowp and self.dseasonp:
+                        modes.extend(
+                            [
+                                f"[s] {self.translated[self.dshow]}",
+                                f"[e] {self.translated[self.dseason]}",
+                            ]
+                        )
+                    elif self.dseasonp is True:
+                        modes.append(f"[e] {self.translated[self.dseason]}")
+                    elif self.dshowp is True:
+                        modes.append(f"[s] {self.translated[self.dshow]}")
                     else:
-                        self.MOV_PandDP(mov_or_tv, "d")
-                except ValueError as e:
-                    print(
-                        "[!]  Invalid Choice Entered! | ",
-                        str(e),
-                    )
-                    sys.exit(1)
-                except IndexError as e:
-                    print(
-                        "[!]  This Episode is coming soon! | ",
-                        str(e),
-                    )
-                    sys.exit(2)
-            elif choice == "sd":
-                try:
-                    pre = fzf_prompt(r)
+                        pass
+                    modes = modes[::-1]
+                    mode = fzf_prompt(modes, header="Select a mode:")[1]
                     choice = (
-                        re.findall(r"\[(.*?)\]", pre)[0] if not result_no else result_no
+                        re.findall(r"\[(.*?)\]", fzf_prompt(r))[0]
+                        if not result_no
+                        else result_no
                     )
                     mov_or_tv = result[int(choice) - 1]
                     if mov_or_tv[self.mv_tv] == "TV":
-                        self.TV_PandDP(mov_or_tv, "sd")
+                        self.TV_PandDP(mov_or_tv, mode)
                     else:
-                        print("You selected a Movie")
-                        exit(0)
+                        if mode == "e" or mode == "s":
+                            print(
+                                "Those options are not unavailable for movies. Using d."
+                            )
+                            mode = "d"
+                        self.MOV_PandDP(mov_or_tv, mode)
                 except ValueError as e:
                     print(
                         "[!]  Invalid Choice Entered! | ",
                         str(e),
                     )
-                    sys.exit(1)
+                    exit(1)
                 except IndexError as e:
                     print(
                         "[!]  This Episode is coming soon! | ",
                         str(e),
                     )
-                    sys.exit(2)
-            elif choice == "ds":
-                try:
-                    pre = fzf_prompt(r)
-                    choice = (
-                        re.findall(r"\[(.*?)\]", pre)[0] if not result_no else result_no
-                    )
-                    mov_or_tv = result[int(choice) - 1]
-                    if mov_or_tv[self.mv_tv] == "TV":
-                        self.TV_PandDP(mov_or_tv, "ds")
-                    else:
-                        print("You selected a Movie")
-                        exit(0)
-                except ValueError as e:
-                    print(
-                        "[!]  Invalid Choice Entered! | ",
-                        str(e),
-                    )
-                    sys.exit(1)
-                except IndexError as e:
-                    print(
-                        "[!]  This Episode is coming soon! | ",
-                        str(e),
-                    )
-                    sys.exit(2)
+                    exit(2)
             else:
                 mov_or_tv = result[int(choice) - 1]
                 if mov_or_tv[self.mv_tv] == "TV":
@@ -241,11 +202,13 @@ def display(self, q: str = None, result_no: int = None):
                 else:
                     self.MOV_PandDP(mov_or_tv, "p")
 
+    def tuki(self, html: str):
+        return tukipasti(html)
+
     def doodstream(self, url: str):
         return dood(url)
 
     def redo(self, search: str = None, result: int = None):
-        print(result)
         return self.display(search, result)
 
     def askseason(self, seasons: int):
diff --git a/mov_cli/utils/select.py b/mov_cli/utils/select.py
new file mode 100644
index 00000000..02346cb7
--- /dev/null
+++ b/mov_cli/utils/select.py
@@ -0,0 +1,157 @@
+from fzf import fzf_prompt
+from importlib import import_module
+from .props import home, RestartNeeded
+from httpx import get
+import json
+
+base = {"eja": "https://eja.tv", "actvid": "https://actvid.rs", "sflix": "https://sflix.se", "solar": "https://solarmovie.pe", "dopebox": "https://dopebox.to", "viewasian": "https://viewasian.co", "gogoanime": "https://gogoanimehd.to/", "watchasian": "https://watchasian.mx", "wlext": "https://wlext.is", "streamblasters": "https://streamblasters.pro", "tamilyogi": "https://tamilyogi.email", "einthusan": "https://einthusan.tv", "turkish123": "https://turkish123.ac", "scdn": "", "remotestream": "https://remotestre.am", "kisscartoon": "https://thekisscartoon.com", "yoturkish": "https://www1.yoturkish.com"}
+
+english = ["actvid", "sflix", "solar", "dopebox", "remotestream"]
+
+indian = [
+    "tamilyogi",
+    "einthusan",
+    "streamblasters",
+]
+
+asian = [
+    "viewasian",
+    "watchasian",
+]
+
+anime = ["gogoanime"]
+
+tv = ["eja"]
+
+cartoons = ["kisscartoon"]
+
+turkish = ["turkish123", "yoturkish"]
+
+
+sports = ["scdn"]
+
+inter = [
+    "wlext",
+]
+
+ph = []
+
+ep = {
+    "english": english,
+    "indian": indian,
+    "asian": asian,
+    "anime": anime,
+    "livetv": tv,
+    "cartoons": cartoons,
+    "turkish": turkish,
+    "sports": sports,
+    "international": inter,
+    "porn": ph,
+}
+
+
+preselction = {
+    "English Providers": english,
+    "Indian Providers": indian,
+    "Asian Providers": asian,
+    "LIVETV Providers": tv,
+    "Cartoons Providers": cartoons,
+    "Turkish Providers": turkish,
+    "Anime Providers": anime,
+    "Sports Providers": sports,
+    "International Providers": inter,
+}
+
+
+def export(provider: str, typ: str, version: str = "mov_cli"):
+    module = f"{version}.websites.{typ}.{provider}"
+    return import_module(module)
+
+
+def p():
+    try:
+        js = open(f"{home()}/provider.mov-cli")
+        calls = json.load(js)
+    except FileNotFoundError:
+        open(f"{home()}/provider.mov-cli", "w").write(json.dumps(base))
+        raise RestartNeeded
+
+    from porn_cli.__main__ import websites
+    if ph != []:
+        return dict(calls)
+    for main, sub in websites.items():
+        calls[main] = sub
+        ph.append(str(main))
+        preselction["Porn Providers"] = ph
+    return dict(calls)
+
+
+
+def ask(provider: str = None):
+    calls = p()
+    if provider:
+        provider = provider.replace(" ", "")
+        get = calls.get(provider)
+        print(get)
+        if get is None:
+            raise Exception("-p: No such provider was found")
+        else:
+            typ = ""
+            for main, sub in ep.items():
+                try:
+                    sub.index(provider)
+                    typ = main
+                    break
+                except ValueError:
+                    continue
+            if typ.__contains__("porn"):
+                version = "porn_cli"
+            else:
+                version = "mov_cli"
+            cl = export(provider, typ, version)
+            return cl, get
+    else:
+        init = fzf_prompt(preselction, header="Select:")
+        if init is None: exit(1)
+        get = preselction.get(init)
+        choice = fzf_prompt(get, header="Select:")
+        typ = init.split(" ")[0].lower()
+        if typ.__contains__("porn"):
+            version = "porn_cli"
+        else:
+            version = "mov_cli"
+        cl = export(choice, typ, version)
+        return cl, calls.get(choice)
+
+
+def updateProvider():
+    import tldextract
+    DEFAULT_HEADERS: dict = {
+        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
+        "Chrome/80.0.3987.163 "
+        "Safari/537.36",
+        "Accept-Language": "en-GB,en;q=0.5",
+    }
+
+    calls = json.loads(open(f"{home()}/provider.mov-cli").read())
+    for main, sub in dict(calls).items():
+        if sub == "":
+            continue
+        try:
+            check = get(sub, follow_redirects=True, headers=DEFAULT_HEADERS, timeout=10)
+        except:
+            continue
+        checkext = tldextract.extract(str(check.url))
+        subext = tldextract.extract(sub)
+        if checkext.registered_domain == subext.registered_domain:
+            print(f"Checked: {main}")
+        else:
+            if checkext.subdomain:
+                updatedurl = "https://" + checkext.subdomain + "." + checkext.registered_domain
+            else:
+                updatedurl = "https://" +  checkext.registered_domain
+            calls[main] = updatedurl
+            print(f"Updated: {main} from {sub} to {updatedurl}")
+    open(f"{home()}/provider.mov-cli", "w").write(json.dumps(calls))
+    print("Provider Check: Done")
+    exit(0)
\ No newline at end of file
diff --git a/mov_cli/websites/anime/__init__.py b/mov_cli/websites/anime/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/gogoanime.py b/mov_cli/websites/anime/gogoanime.py
similarity index 88%
rename from mov_cli/websites/gogoanime.py
rename to mov_cli/websites/anime/gogoanime.py
index 2c78ad77..04230fd6 100644
--- a/mov_cli/websites/gogoanime.py
+++ b/mov_cli/websites/anime/gogoanime.py
@@ -1,9 +1,9 @@
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 from bs4 import BeautifulSoup as BS
 import re
 
 
-class gogoanime(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
@@ -16,15 +16,20 @@ def results(self, data: str) -> list:
         results = []
         page = 1
         while True:
-            req = self.client.get(f"{self.base_url}/search.html?keyword={data}&page={page}")
+            req = self.client.get(
+                f"{self.base_url}/search.html?keyword={data}&page={page}"
+            )
             soup = BS(req, self.scraper)
             items = soup.find("ul", {"class": "items"}).findAll("li")
-            if len(items) == 0: break
+            if len(items) == 0:
+                break
             urls = [items[i].find("a")["href"] for i in range(len(items))]
             title = [items[i].find("a")["title"] for i in range(len(items))]
             ids = [items[i].find("a")["title"] for i in range(len(items))]
             mov_or_tv = ["TV" for i in range(len(items))]
-            results.extend([list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)])
+            results.extend(
+                [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
+            )
             page += 1
         return results
 
diff --git a/mov_cli/websites/animefox.py b/mov_cli/websites/animefox.py
deleted file mode 100644
index 359fd74e..00000000
--- a/mov_cli/websites/animefox.py
+++ /dev/null
@@ -1,108 +0,0 @@
-from ..utils.scraper import WebScraper
-from bs4 import BeautifulSoup as BS
-import re
-
-
-class animefox(WebScraper):
-    def __init__(self, base_url):
-        super().__init__(base_url)
-        self.base_url = base_url
-
-    def search(self, q: str = None) -> str:
-        q = input(f"[!] {self.translated[self.task]}") if q is None else q
-        return q.replace(" ", "+")
-
-    def results(self, data: str) -> list:
-        req = self.client.get(f"https://animefox.to/search?keyword={data}")
-        soup = BS(req, self.scraper)
-        items = soup.findAll("a", {"class": "film-poster-ahref"})
-        urls = [items[i]["href"] for i in range(len(items))]
-        title = [items[i]["title"] for i in range(len(items))]
-        ids = [i for i in range(len(items))]
-        mov_or_tv = [
-            "MOVIE" if items[i].__contains__("Movie") else "TV"
-            for i in range(len(items))
-        ]
-        return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
-
-    def ask(self, url):
-        a = self.client.get(f"{self.base_url}{url}")
-        soup = BS(a, self.scraper)
-        url = soup.find("div", {"class": "film-buttons"}).find("a")["href"]
-        req = self.client.get(self.base_url + url)
-        soup = BS(req, self.scraper)
-        episodes = len(soup.find("div", {"id": "episodes-page-1"}).findAll("a"))
-        episode = self.askepisode(episodes)
-        return self.base_url + url[:-1] + episode, episode
-
-    def mov(self, url):
-        a = self.client.get(f"{self.base_url}{url}")
-        soup = BS(a, self.scraper)
-        url = soup.find("div", {"class": "film-buttons"}).find("a")["href"]
-        return self.base_url + url
-
-    def cdn_url(self, url):
-        req = self.client.get(url)
-        soup = BS(req, self.scraper)
-        goload = soup.find("select", {"id": "select-iframe-to-display"}).findAll(
-            "option"
-        )[-1]["value"]
-        url = f"https://{goload}".split("-")[0]
-        a = self.client.head(url, redirects=False).headers["location"]
-        a = self.client.get(a)
-        soup = BS(a, self.scraper)
-        server = []
-        servers = soup.findAll("li", {"class": "linkserver"})
-        for video in servers:
-            if "dood.wf" in str(video["data-video"]):
-                server.append(video["data-video"])
-        return self.doodstream(server[0])
-
-    def doodstream(self, url):
-        domain = re.findall("""([^"']*)\/e""", url)[0]
-        req = self.client.get(url).text
-        pass_md = re.findall(r"/pass_md5/[^']*", req)[0]
-        token = pass_md.split("/")[-1]
-        self.client.set_headers(
-            {
-                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
-                "Referer": f"{url}",
-                "Accept-Language": "en-GB,en;q=0.5",
-            }
-        )
-        drylink = self.client.get(f"{domain}{pass_md}").text
-        streamlink = f"{drylink}zUEJeL3mUN?token={token}"
-        print(streamlink)
-        return streamlink
-
-    def download(self, t):
-        a = self.client.get(f"{self.base_url}{t[self.url]}")
-        soup = BS(a, self.scraper)
-        url = soup.find("div", {"class": "film-buttons"}).find("a")["href"]
-        req = self.client.get(self.base_url + url)
-        soup = BS(req, self.scraper)
-        episodes = len(soup.find("div", {"id": "episodes-page-1"}).findAll("a"))
-        for e in range(episodes):
-            url = self.cdn_url(self.base_url + url[:-1] + e + 1)
-            self.dl(url, name=t[self.title], episode=e + 1)
-
-    def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd"):
-        if state == "sd":
-            self.download(t)
-            return
-        name = t[self.title]
-        link, episode = self.ask(t[self.url])
-        url = self.cdn_url(link)
-        if state == "d":
-            self.dl(url, name, season=".", episode=episode)
-            return
-        self.play(url, name)
-
-    def MOV_PandDP(self, t: list, state: str = "d" or "p"):
-        name = t[self.title]
-        link = self.mov(t[self.url])
-        url = self.cdn_url(link)
-        if state == "d":
-            self.dl(url, name)
-            return
-        self.play(url, name)
diff --git a/mov_cli/websites/asian/__init__.py b/mov_cli/websites/asian/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/viewasian.py b/mov_cli/websites/asian/viewasian.py
similarity index 81%
rename from mov_cli/websites/viewasian.py
rename to mov_cli/websites/asian/viewasian.py
index 29d9e1f5..42cbab86 100644
--- a/mov_cli/websites/viewasian.py
+++ b/mov_cli/websites/asian/viewasian.py
@@ -1,9 +1,9 @@
 from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 import re
 
 
-class viewasian(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
@@ -55,23 +55,6 @@ def streamtape(self, url):
             return li
         raise Exception("Video not found or removed")
 
-    #    def doodstream(self, url):
-    #        domain = re.findall("""([^"']*)\/e""", url)[0]
-    #        req = self.client.get(url).text
-    #        pass_md = re.findall(r"/pass_md5/[^']*", req)[0]
-    #        token = pass_md.split("/")[-1]
-    #        self.client.set_headers(
-    #            {
-    #                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0",
-    #                "Referer": f"{url}",
-    #                "Accept-Language": "en-GB,en;q=0.5",
-    #            }
-    #        )
-    #        drylink = self.client.get(f"{domain}{pass_md}").text
-    #        streamlink = f"{drylink}zUEJeL3mUN?token={token}"
-    #        print(streamlink)
-    #        return streamlink
-
     def download(self, t):
         request = self.client.get(f"{self.base_url}{t[self.url]}")
         soup = BS(request, self.scraper)
diff --git a/mov_cli/websites/watchasian.py b/mov_cli/websites/asian/watchasian.py
similarity index 97%
rename from mov_cli/websites/watchasian.py
rename to mov_cli/websites/asian/watchasian.py
index be6f7a90..ddaad8d0 100644
--- a/mov_cli/websites/watchasian.py
+++ b/mov_cli/websites/asian/watchasian.py
@@ -1,9 +1,9 @@
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 from bs4 import BeautifulSoup as BS
 import re
 
 
-class watchasian(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
diff --git a/mov_cli/websites/cartoons/__init__.py b/mov_cli/websites/cartoons/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/kisscartoon.py b/mov_cli/websites/cartoons/kisscartoon.py
similarity index 98%
rename from mov_cli/websites/kisscartoon.py
rename to mov_cli/websites/cartoons/kisscartoon.py
index e146e5c7..7f6e9a11 100644
--- a/mov_cli/websites/kisscartoon.py
+++ b/mov_cli/websites/cartoons/kisscartoon.py
@@ -1,12 +1,12 @@
 from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 import re
 import httpx
 
 cdn_url_re = r"/\\\/cdn\\\/hls\\\/([a-fA-F\d]{32})\\\/master\.txt/gm"
 
 
-class kisscartoon(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
diff --git a/mov_cli/websites/english/__init__.py b/mov_cli/websites/english/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/actvid.py b/mov_cli/websites/english/actvid.py
similarity index 60%
rename from mov_cli/websites/actvid.py
rename to mov_cli/websites/english/actvid.py
index 09ab23ad..a1d7d9fa 100644
--- a/mov_cli/websites/actvid.py
+++ b/mov_cli/websites/english/actvid.py
@@ -6,7 +6,7 @@
 # import chardet
 from Crypto.Cipher import AES
 from urllib import parse as p
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 from bs4 import BeautifulSoup as BS
 import json
 
@@ -17,63 +17,15 @@ def x(d):
     return base64.b64encode(d.encode()).decode().replace("\n", "").replace("=", ".")
 
 
-class actvid(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url) -> None:
         super().__init__(base_url)
-        self.userinput = None
         self.base_url = base_url
-        self.rep_key = (
-            "6LfV6aAaAAAAAC-irCKNuIS5Nf5ocl5r0K3Q0cdz"  # Google Recaptcha key
-        )
-        self.rab_domain = x("https://rabbitstream.net:443")
-        # encoding and then decoding the url
-        # self.redo()
-        # IMP: self.client.get/post always returns a response object
-        # self.client.post/get -> httpx.response
-
-    """def key_num(self, iframe_link: str) -> tuple:
-        self.client.add_elem(
-            {"Referer": self.base_url}
-        )  # adding referer to the headers
-        # self.client.headers['Referer'] = self.base_url
-        req = self.client.get(iframe_link).text
-        soup = BS(req, self.scraper)
-        k = list([i.text for i in soup.find_all("script")][-3].replace("var", ""))
-        key, num = "".join(k[21:61]), k[-3]
-        return key, num  # returns a tuple
-
-    def auth_token(self, key: str) -> str:
-        self.client.add_elem({"Referer": self.base_url})
-        self.client.add_elem({"cacheTime": "0"})  # adding referer to the headers
-        r = self.client.get(
-            f"https://www.google.com/recaptcha/api.js?render={self.rep_key}"
-        )
-        s = r.text.replace("/* PLEASE DO NOT COPY AND PASTE THIS CODE. */", "")
-        s = s.split(";")
-        v_token = s[10].replace("po.src=", "").split("/")[-2]
-        r = self.client.get(
-            f"https://www.google.com/recaptcha/api2/anchor?ar=1&hl=en&size=invisible&cb=xxmovclix&k={key}&co={self.rab_domain}&v={v_token}"
-        ).text
-        soup = BS(r, self.scraper)
-        recap_token = [i["value"] for i in soup.select("#recaptcha-token")][0]
-        data = {
-            "v": v_token,
-            "k": self.rep_key,
-            "c": recap_token,
-            "co": self.rab_domain,
-            "sa": "",
-            "reason": "q",
-        }
-        self.client.add_elem({"cacheTime": "0"})
-        return json.loads(
-            self.client.post(
-                f"https://www.google.com/recaptcha/api2/reload?k={key}", data=data
-            ).text.replace(")]}'", "")
-        )"""
+        self.dseasonp = True
+        self.dshowp = True
 
     def search(self, q: str = None) -> str:
         q = input(f"[!] {self.translated[self.task]}") if q is None else q
-        self.userinput = q
         return self.client.get(f"{self.base_url}/search/{self.parse(q)}").text
 
     def results(self, html: str) -> list:
@@ -83,29 +35,22 @@ def results(self, html: str) -> list:
             "MOVIE" if i["href"].__contains__("/movie/") else "TV"
             for i in soup.select(".film-poster-ahref")
         ]
-        title = [
-            re.sub(
-                pattern="full|/tv/|/movie/|hd|watch|[0-9]{2,}",
-                repl="",
-                string=" ".join(i.split("-")),
-            )
-            for i in urls
-        ]
+        title = [i.text for i in soup.select(".film-name > a")]
         ids = [i.split("-")[-1] for i in urls]
         return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
 
     def ask(self, series_id: str) -> tuple:
-        r = self.client.get(f"{self.base_url}/ajax/v2/tv/seasons/{series_id}")
+        r = self.client.get(f"{self.base_url}/ajax/season/list/{series_id}") # self.ajax_season
         season_ids = [
             i["data-id"] for i in BS(r, self.scraper).select(".dropdown-item")
         ]
         season = self.askseason(len(season_ids))
-        z = f"{self.base_url}/ajax/v2/season/episodes/{season_ids[int(season) - 1]}"
+        z = f"{self.base_url}/ajax/season/episodes/{season_ids[int(season) - 1]}"
         rf = self.client.get(z)
         episodes = [i["data-id"] for i in BS(rf, self.scraper).select(".nav-item > a")]
         episode = episodes[int(self.askepisode(len(episodes))) - 1]
         ep = self.getep(
-            url=f"{self.base_url}/ajax/v2/season/episodes/{season_ids[int(season) - 1]}",
+            url=f"{self.base_url}/ajax/season/episodes/{season_ids[int(season) - 1]}",
             data_id=f"{episode}",
         )
         return episode, season, ep
@@ -122,61 +67,26 @@ def getep(self, url, data_id):
 
         return formated
 
-    """    def websocket(self, iframe_id):
-        # Thanks to Twilight for fixing it.
-        '''
-        will return decryption key, sources and tracks
-        '''
-        ws = create_connection("wss://wsx.dokicloud.one/socket.io/?EIO=4&transport=websocket")
-        p = ws.recv()
-        code = re.findall(self.CODE_REGEX, p)[0]
-
-        # dirty impleamentation
-        if code == "0":
-            ws.send("40")
-            p = ws.recv()
-
-            code = re.findall(self.CODE_REGEX, p)[0]
-
-            if code == "40":
-                key = re.findall(self.SID_REGEX, p)[0]
-
-                ws.send(
-                    '42["getSources",{"id":"' + iframe_id + '"}]'
-                )
-                p = ws.recv()
-                x = json.loads(re.findall(self.SOURCE_REGEX, p)[0])
-
-        return key, x["sources"], x["tracks"]
-
-    def cdn_url(self, rabb_id: str) -> str:
-        key, source, track = self.websocket(rabb_id)
-        predata = self.decrypt(source, bytes(key, "utf-8"))
-        data = json.loads(predata)
-        print(predata)
-        return data[0]['file']"""
-
     def cdn_url(self, final_link: str, rabb_id: str) -> str:
         self.client.set_headers({"X-Requested-With": "XMLHttpRequest"})
         data = self.client.get(f"{final_link}getSources?id={rabb_id}").json()
         n = json.loads(self.decrypt(data["sources"], self.gh_key()))
         return n[0]["file"]
-        
 
     def server_id(self, mov_id: str) -> str:
-        req = self.client.get(f"{self.base_url}/ajax/movie/episodes/{mov_id}")
+        req = self.client.get(f"{self.base_url}/ajax/episode/list/{mov_id}")
         soup = BS(req, self.scraper)
         return [i["data-linkid"] for i in soup.select(".nav-item > a")][0]
 
     def ep_server_id(self, ep_id: str) -> str:
         req = self.client.get(
-            f"{self.base_url}/ajax/v2/episode/servers/{ep_id}/#servers-list"
+            f"{self.base_url}/ajax/episode/servers/{ep_id}"
         )
         soup = BS(req, self.scraper)
         return [i["data-id"] for i in soup.select(".nav-item > a")][0]
 
     def get_link(self, thing_id: str) -> tuple:
-        req = self.client.get(f"{self.base_url}/ajax/get_link/{thing_id}").json()[
+        req = self.client.get(f"{self.base_url}/ajax/episode/sources/{thing_id}").json()[
             "link"
         ]
         print(req)
@@ -191,15 +101,6 @@ def rabbit_id(self, url: str) -> tuple:
             parts[-1],
         )
 
-    ## decryption
-    ## Thanks to Twilight
-
-    # def determine_char_enc(self, value):
-    #    result = chardet.detect(value)['encoding']
-    #    return result
-
-    # websocket simulation
-
     def gh_key(self):
         u = self.client.get(
             "https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt"
@@ -225,7 +126,7 @@ def decrypt(self, data, key):
         dec_key = k[:32]
         iv = k[32:]
         p = AES.new(dec_key, AES.MODE_CBC, iv=iv).decrypt(base64.b64decode(data)[16:])
-        return self.unpad(p).decode()
+        return self.unpad(p).decode()   
 
     def ds(self, series_id: str, name):
         r = self.client.get(f"{self.base_url}/ajax/v2/tv/seasons/{series_id}")
@@ -265,10 +166,10 @@ def sd(self, series_id: str, name):
 
     def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd" or "ds"):
         name = t[self.title]
-        if state == "sd":
+        if state == "s":
             self.sd(t[self.aid], name)
             return
-        if state == "ds":
+        if state == "e":
             self.ds(t[self.aid], name)
             return
         episode, season, ep = self.ask(t[self.aid])
@@ -290,9 +191,6 @@ def MOV_PandDP(self, m: list, state: str = "d" or "p" or "sd"):
         if state == "d":
             self.dl(url, name)
             return
-        if state == "sd":
-            print("You can download only Shows with 'sd'")
-            return
         self.play(url, name)
 
     def SandR(self, q: str = None):
diff --git a/mov_cli/websites/dopebox.py b/mov_cli/websites/english/dopebox.py
similarity index 83%
rename from mov_cli/websites/dopebox.py
rename to mov_cli/websites/english/dopebox.py
index 3ab25bfc..7ee37dcc 100644
--- a/mov_cli/websites/dopebox.py
+++ b/mov_cli/websites/english/dopebox.py
@@ -1,25 +1,13 @@
-from .actvid import actvid
+from .actvid import Provider as pv
 from bs4 import BeautifulSoup as BS
 
 
-class dopebox(actvid):
+class Provider(pv):
     def __init__(self, base_url) -> None:
         super().__init__(base_url)
         self.base_url = base_url
-        self.rep_key = "6LeWLCYeAAAAAL1caYzkrIY-M59Vu41vIblXQZ48"
-        # self.redo()
-
-    """def cdn_url(self, rabbid, rose, num):
-        self.client.set_headers({"X-Requested-With": "XMLHttpRequest"})
-        # data = json.loads(self.client.get(
-        #    f"https://rabbitstream.net/ajax/embed-4/getSources?id={rabbid}&_token={rose}&_number={num}"))['sources'][0][
-        #    'file']
-        data = json.loads(
-            self.client.get(
-                f"https://rabbitstream.net/ajax/embed-4/getSources?id={rabbid}&_token={rose}&_number={num}"
-            ).text
-        )["sources"][0]["file"]
-        return data"""
+        self.dseasonp = True
+        self.dshowp = True
 
     def ask(self, series_id):
         r = self.client.get(f"{self.base_url}/ajax/v2/tv/seasons/{series_id}")
@@ -58,6 +46,13 @@ def server_id(self, mov_id):
         soup = BS(rem, self.scraper)
         return [i["data-id"] for i in soup.select(".link-item")][0]
 
+    def get_link(self, thing_id: str) -> tuple:
+        req = self.client.get(f"{self.base_url}/ajax/sources/{thing_id}").json()[
+            "link"
+        ]
+        print(req)
+        return req, self.rabbit_id(req)
+
     def ep_server_id(self, ep_id):
         rem = self.client.get(
             f"{self.base_url}/ajax/v2/episode/servers/{ep_id}/#servers-list"
diff --git a/mov_cli/websites/sflix.py b/mov_cli/websites/english/sflix.py
similarity index 78%
rename from mov_cli/websites/sflix.py
rename to mov_cli/websites/english/sflix.py
index 9e5b0a63..6b9e4766 100644
--- a/mov_cli/websites/sflix.py
+++ b/mov_cli/websites/english/sflix.py
@@ -1,25 +1,13 @@
-from .actvid import actvid
+from .actvid import Provider as pv
 from bs4 import BeautifulSoup as BS
 
 
-class sflix(actvid):
+class Provider(pv):
     def __init__(self, base_url) -> None:
         super().__init__(base_url)
         self.base_url = base_url
-        self.rep_key = "6LeWLCYeAAAAAL1caYzkrIY-M59Vu41vIblXQZ48"
-        # self.redo()
-
-    """def cdn_url(self, rabbid, rose, num):
-        self.client.set_headers({"X-Requested-With": "XMLHttpRequest"})
-        # data = json.loads(self.client.get(
-        #    f"https://rabbitstream.net/ajax/embed-4/getSources?id={rabbid}&_token={rose}&_number={num}"))['sources'][0][
-        #    'file']
-        data = json.loads(
-            self.client.get(
-                f"https://rabbitstream.net/ajax/embed-4/getSources?id={rabbid}&_token={rose}&_number={num}"
-            ).text
-        )["sources"][0]["file"]
-        return data"""
+        self.dseasonp = True
+        self.dshowp = True
 
     def ask(self, series_id):
         r = self.client.get(f"{self.base_url}/ajax/v2/tv/seasons/{series_id}")
@@ -31,13 +19,18 @@ def ask(self, series_id):
             f"{self.base_url}/ajax/v2/season/episodes/{season_ids[int(season) - 1]}"
         )
         episodes = [i["data-id"] for i in BS(rf, self.scraper).select(".episode-item")]
-        episode = episodes[int(self.askepisode(len(episodes))) - 1]
-        ep = self.getep(
-            f"{self.base_url}/ajax/v2/season/episodes/{season_ids[int(season) - 1]}",
-            data_id=episode,
-        )
+        ep = self.askepisode(len(episodes))
+        episode = episodes[int(ep) - 1]
         return episode, season, ep
 
+    def get_link(self, thing_id: str) -> tuple:
+        req = self.client.get(f"{self.base_url}/ajax/sources/{thing_id}").json()[
+            "link"
+        ]
+        print(req)
+        return req, self.rabbit_id(req)
+
+
     def getep(self, url, data_id):
         source = self.client.get(f"{url}").text
         soup = BS(source, self.scraper)
diff --git a/mov_cli/websites/solar.py b/mov_cli/websites/english/solar.py
similarity index 82%
rename from mov_cli/websites/solar.py
rename to mov_cli/websites/english/solar.py
index b9f1baa5..5a9558aa 100644
--- a/mov_cli/websites/solar.py
+++ b/mov_cli/websites/english/solar.py
@@ -1,13 +1,13 @@
-from .actvid import actvid
+from .actvid import Provider as pv
 from bs4 import BeautifulSoup as BS
 
 
-class solar(actvid):
+class Provider(pv):
     def __init__(self, base_url) -> None:
         super().__init__(base_url)
         self.base_url = base_url
-        self.rep_key = "6LeWLCYeAAAAAL1caYzkrIY-M59Vu41vIblXQZ48"
-        self.redo()
+        self.dseasonp = True
+        self.dshowp = True
 
     def ask(self, series_id):
         r = self.client.get(f"{self.base_url}/ajax/v2/tv/seasons/{series_id}")
@@ -26,6 +26,14 @@ def ask(self, series_id):
         )
         return episode, season, ep
 
+    def get_link(self, thing_id: str) -> tuple:
+        req = self.client.get(f"{self.base_url}/ajax/sources/{thing_id}").json()[
+            "link"
+        ]
+        print(req)
+        return req, self.rabbit_id(req)
+
+
     def getep(self, url, data_id):
         source = self.client.get(f"{url}").text
 
diff --git a/mov_cli/websites/indian/__init__.py b/mov_cli/websites/indian/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/einthusan.py b/mov_cli/websites/indian/einthusan.py
similarity index 96%
rename from mov_cli/websites/einthusan.py
rename to mov_cli/websites/indian/einthusan.py
index 48a2abf4..9ba530d5 100644
--- a/mov_cli/websites/einthusan.py
+++ b/mov_cli/websites/indian/einthusan.py
@@ -1,10 +1,10 @@
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 from bs4 import BeautifulSoup as BS
 import re
 from fzf import fzf_prompt
 
 
-class einthusan(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
diff --git a/mov_cli/websites/streamblasters.py b/mov_cli/websites/indian/streamblasters.py
similarity index 92%
rename from mov_cli/websites/streamblasters.py
rename to mov_cli/websites/indian/streamblasters.py
index a56f4ff1..bc7676f5 100644
--- a/mov_cli/websites/streamblasters.py
+++ b/mov_cli/websites/indian/streamblasters.py
@@ -1,9 +1,11 @@
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
+from ...utils.props import NoSupportedProvider
+
 from bs4 import BeautifulSoup as BS
 import re
 
 
-class streamblasters(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
@@ -41,7 +43,7 @@ def doodext(self, url):
         try:
             src = re.findall('''"https:(.*?)"''', post)[0].replace("\/", "/")
         except:
-            raise Exception("No URL was found")
+            raise NoSupportedProvider
         if "\\" in src:
             src = src.replace("\\", "")
         src = f"https:{src}"
diff --git a/mov_cli/websites/tamilyogi.py b/mov_cli/websites/indian/tamilyogi.py
similarity index 94%
rename from mov_cli/websites/tamilyogi.py
rename to mov_cli/websites/indian/tamilyogi.py
index 8bcd8e4b..aaf14c11 100644
--- a/mov_cli/websites/tamilyogi.py
+++ b/mov_cli/websites/indian/tamilyogi.py
@@ -1,9 +1,9 @@
 from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 import re
 
 
-class tamilyogi(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
diff --git a/mov_cli/websites/international/__init__.py b/mov_cli/websites/international/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/wlext.py b/mov_cli/websites/international/wlext.py
similarity index 92%
rename from mov_cli/websites/wlext.py
rename to mov_cli/websites/international/wlext.py
index e8f6da67..ed20a84c 100644
--- a/mov_cli/websites/wlext.py
+++ b/mov_cli/websites/international/wlext.py
@@ -1,9 +1,10 @@
 from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
+from ...utils.props import NoSupportedProvider, SelectedNotAvailable
 import re
 
 
-class wlext(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url) -> None:
         super().__init__(base_url)
         self.base_url = base_url
@@ -42,7 +43,7 @@ def ask(self, url):
         try:
             episodes = len(t.findAll("option"))
         except:
-            return print("Episode unavailable")
+            raise SelectedNotAvailable
         episode = int(self.askepisode(episodes))
         req = self.client.get(f"{url}?server=cajitatop&episode={episode}").text
         soup = BS(req, self.scraper)
@@ -50,7 +51,7 @@ def ask(self, url):
             t = soup.find("iframe", {"loading": "lazy"})["src"]
             print(t)
         except:
-            return print("Couldn't find cajita.to provider.")
+            raise NoSupportedProvider
         return t, episode
 
     def cdn_url(self, url):
@@ -62,8 +63,7 @@ def cdn_url(self, url):
         ).json()
         file = request["data"]
         if file == "Video not found or has been removed":
-            print("Video not found or has been removed")
-            exit(1)
+            raise SelectedNotAvailable
         else:
             file = request["data"][-1]["file"]
         return file
@@ -82,7 +82,7 @@ def download(self, t):
             try:
                 t = soup.find("iframe", {"loading": "lazy"})["src"]
             except:
-                return print("Couldn't find cajita.to provider.")
+                raise SelectedNotAvailable
             url = str(self.cdn_url(t))
             self.dl(url, t[self.title], episode=e + 1)
 
diff --git a/mov_cli/websites/livetv/__init__.py b/mov_cli/websites/livetv/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/eja.py b/mov_cli/websites/livetv/eja.py
similarity index 77%
rename from mov_cli/websites/eja.py
rename to mov_cli/websites/livetv/eja.py
index f925eb0b..89dc313d 100644
--- a/mov_cli/websites/eja.py
+++ b/mov_cli/websites/livetv/eja.py
@@ -1,9 +1,9 @@
-import httpx
 from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
+from re import findall
 
 
-class eja(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
@@ -28,13 +28,9 @@ def results(self, q: str) -> list:
         return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
 
     def get_hls(self, url):
-        link = str(httpx.get(f"https://eja.tv/?{url}", follow_redirects=True).url)
-        print(link)
-        link = "".join(link)
-        link = link.split("?")[1]
-        link = link.split("#")[0]
-        print(link)
-        return link
+        link = self.client.get(f"https://eja.tv/?{url}", redirects=True)
+        link = link.url
+        return findall("\?(.*)#", link)[0]
 
     def MOV_PandDP(self, m: list, state: str = "d" or "p"):
         name = m[self.title]
@@ -43,6 +39,3 @@ def MOV_PandDP(self, m: list, state: str = "d" or "p"):
             self.dl(url, name)
             return
         self.play(url, name)
-
-    def SandR(self, q: str = None):
-        return self.results(self.search(q))
diff --git a/mov_cli/websites/openloadmov.py b/mov_cli/websites/openloadmov.py
deleted file mode 100644
index 46034ded..00000000
--- a/mov_cli/websites/openloadmov.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
-
-
-class openloadmov(WebScraper):
-    def __init__(self, base_url):
-        super().__init__(base_url)
-        self.base_url = base_url
-        self.getvid = "https://hlspanel.xyz/player/index.php?data={}&do=getVideo"
-
-    def search(self, q: str):
-        q = input(f"[!] {self.translated[self.task]}") if q is None else q
-        return q.replace(" ", "+")
-
-    def results(self, data: str) -> list:
-        req = self.client.get(f"{self.base_url}/?s={data}")
-        soup = BS(req, self.scraper)
-        items = soup.findAll("div", {"class": "result-item"})
-        title = [items[i].find("img")["alt"] for i in range(len(items))]
-        urls = [items[i].find("a")["href"] for i in range(len(items))]
-        ids = [i for i in range(len(items))]
-        mov_or_tv = [
-            "MOVIE" if items[i].find("span").text.__contains__("Movie") else "TV"
-            for i in range(len(items))
-        ]
-        return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
-
-    def ask(self, url):
-        req = self.client.get(url)
-        soup = BS(req, self.scraper)
-        seasons = soup.findAll("div", {"class": "se-c"})
-        season = int(self.askseason(len(seasons)))
-        se_c = seasons[season - 1]
-        episodes = se_c.find("ul").findAll("li")
-        episode = int(self.askepisode(len(episodes)))
-        ep = episodes[episode - 1].find("a")["href"]
-        return ep, episode, season
-
-    def cdn_url(self, url):
-        req = self.client.get(url)
-        soup = BS(req, self.scraper)
-        iframe = soup.find("iframe")["src"]
-        vidhash = iframe.split("/")[-1]
-        self.client.set_headers({"x-requested-with": "XMLHttpRequest"})
-        awd = self.client.post(
-            self.getvid.format(vidhash),
-            data={"hash": vidhash, "r": self.base_url + "/"},
-        ).json()["securedLink"]
-        print(awd)
-        return awd
-
-    def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd"):
-        name = t[self.title]
-        url, episode, season = self.ask(t[self.url])
-        url = self.cdn_url(url)
-        if state == "d":
-            self.dl(url, name, season=season, episode=episode)
-            return
-        self.play(url, name)
-
-    def MOV_PandDP(self, m: list, state: str = "d" or "p" or "sd"):
-        name = m[self.title]
-        url = self.cdn_url(m[self.url])
-        if state == "d":
-            self.dl(url, name)
-            return
-        self.play(url, name)
diff --git a/mov_cli/websites/redundant_kimcartoon.py b/mov_cli/websites/redundant_kimcartoon.py
deleted file mode 100644
index c8ecf07e..00000000
--- a/mov_cli/websites/redundant_kimcartoon.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
-import re
-
-
-class kimcartoon(WebScraper):
-    def __init__(self, base_url):
-        super().__init__(base_url)
-        self.base_url = base_url
-
-    def search(self, q: str = None) -> str:
-        q = input(f"[!] {self.translated[self.task]}") if q is None else q
-        return q
-
-    def results(self, q):
-        res = self.client.post(f"{self.base_url}/Search/Cartoon", data={"keyword": q})
-        soup = BS(res.text, self.scraper)
-        div = soup.find("div", {"class": "list-cartoon"})
-        cartoons = div.findAll("div", {"class": "item"})
-        title = [cartoons[i].find("span").text for i in range(len(cartoons))]
-        urls = [cartoons[i].find("a")["href"] for i in range(len(cartoons))]
-        ids = [i for i in range(len(cartoons))]
-        mov_or_tv = ["TV" for i in range(len(cartoons))]
-        return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
-
-    def ask(self, url):
-        res = self.client.get(self.base_url + url)
-        soup = BS(res, self.scraper)
-        table = soup.find("table", {"class": "listing"})
-        episodes = table.findAll("a", {"rel": "noreferrer noopener"})
-        episode = int(self.askepisode(len(episodes)))
-        url = episodes[len(episodes) - episode]["href"]
-        return url, episode
-
-    def download(self, t: list):
-        res = self.client.get(self.base_url + t[self.url])
-        soup = BS(res, self.scraper)
-        table = soup.find("table", {"class": "listing"})
-        episodes = table.findAll("a", {"rel": "noreferrer noopener"})
-        for e in range(len(episodes)):
-            epi = e + 1
-            link = episodes[len(episodes) - epi]["href"]
-            url = self.cdn_url(link)
-            self.dl(url, t[self.title], episode=e + 1)
-
-    def cdn_url(self, url):
-        res = self.client.get(self.base_url + url + "&s=sb").text
-        iframe_id = re.findall('''src="https:\/\/www.luxubu.review\/v\/(.*?)\"''', res)[
-            0
-        ]
-        r = self.client.post(
-            f"https://www.luxubu.review/api/source/{iframe_id}", data=None
-        ).json()["data"]
-        return r[-1]["file"]
-
-    def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd"):
-        if state == "sd":
-            self.download(t)
-            return
-        name = t[self.title]
-        link, episode = self.ask(t[self.url])
-        url = self.cdn_url(link)
-        if state == "d":
-            self.dl(url, name, season=".", episode=episode)
-            return
-        self.play(url, name)
diff --git a/mov_cli/websites/sports/__init__.py b/mov_cli/websites/sports/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/scdn.py b/mov_cli/websites/sports/scdn.py
similarity index 95%
rename from mov_cli/websites/scdn.py
rename to mov_cli/websites/sports/scdn.py
index 9284e2df..a283b4c7 100644
--- a/mov_cli/websites/scdn.py
+++ b/mov_cli/websites/sports/scdn.py
@@ -5,15 +5,16 @@
 from datetime import datetime
 from urllib.parse import urlparse
 from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 
 """
 Original Code from https://github.com/edl2/sportsapi
 Rewritten for mov-cli
+Needs a rework
 """
 
 
-class scdn(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
@@ -118,7 +119,7 @@ def cdn_url(self, id):
                 f"..extractors.scdn.{extracted_url}.get_link"
             )
         except ImportError:
-            from ..extractors.scdn.ripple import get_link
+            from ...extractors.scdn.ripple import get_link
 
         m3u8 = get_link(url)
         return m3u8, A
@@ -127,6 +128,6 @@ def MOV_PandDP(self, m: list, state: str = "d" or "p"):
         name = m[self.title]
         url, domain = self.cdn_url(m[self.aid])
         if state == "d":
-            self.dl(url, name)
+            self.dl(url, name, referrer=f"https://{domain}/")
             return
         self.play(url, name, referrer=f"https://{domain}/")
diff --git a/mov_cli/websites/turkish/__init__.py b/mov_cli/websites/turkish/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mov_cli/websites/turkish123.py b/mov_cli/websites/turkish/turkish123.py
similarity index 71%
rename from mov_cli/websites/turkish123.py
rename to mov_cli/websites/turkish/turkish123.py
index edcfaf2d..61dce2b3 100644
--- a/mov_cli/websites/turkish123.py
+++ b/mov_cli/websites/turkish/turkish123.py
@@ -1,9 +1,9 @@
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 from bs4 import BeautifulSoup as BS
 import re
 
 
-class turkish123(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
@@ -34,12 +34,8 @@ def ask(self, url):
         episodes = soup.findAll("a", {"class": "episodi"})
         episode = int(self.askepisode(len(episodes)))
         req = self.client.get(episodes[episode - 1]["href"]).text
-        regex = r'''var copyTexti= \['<iframe width="100%" height="100%" src="https:\/\/tukipasti\.com(.*?)"'''
-        s = re.findall(regex, req)[0]
-        req = self.client.get(f"https://tukipasti.com{s}").text
-        url = re.findall("var urlPlay = '(.*?)'", req)[0]
-        print(url)
-        return url, episode, f"https://tukipasti.com{s}"
+        url, tukibase = self.tuki(req)
+        return url, episode, tukibase
 
     def download(self, t):
         req = self.client.get(t[self.url]).text
@@ -47,20 +43,17 @@ def download(self, t):
         episodes = soup.findAll("a", {"class": "episodi"})
         for e in range(len(episodes)):
             req = self.client.get(episodes[e]["href"]).text
-            regex = r'''var copyTexti= \['<iframe width="100%" height="100%" src="https:\/\/tukipasti\.com(.*?)"'''
-            s = re.findall(regex, req)[0]
-            req = self.client.get(f"https://tukipasti.com{s}").text
-            url = re.findall("var urlPlay = '(.*?)'", req)[0]
+            url, tukibase = self.tuki(req)
             print(url)
             self.dl(
                 url,
                 t[self.title],
                 season="",
                 episode=e + 1,
-                referrer=f"https://tukipasti.com{s}",
+                referrer=tukibase,
             )
 
-    def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd" or "ds"):
+    def TV_PandDP(self, t: list, state: str):
         if state == "sd":
             self.download(t)
             return
diff --git a/mov_cli/websites/yoturkish.py b/mov_cli/websites/turkish/yoturkish.py
similarity index 77%
rename from mov_cli/websites/yoturkish.py
rename to mov_cli/websites/turkish/yoturkish.py
index 30ce9920..d417511e 100644
--- a/mov_cli/websites/yoturkish.py
+++ b/mov_cli/websites/turkish/yoturkish.py
@@ -1,83 +1,76 @@
-from ..utils.scraper import WebScraper
-from bs4 import BeautifulSoup as BS
-import re
-
-
-class yoturkish(WebScraper):
-    def __init__(self, base_url):
-        super().__init__(base_url)
-        self.base_url = base_url
-
-    def search(self, q: str):
-        q = input(f"[!] {self.translated[self.task]}") if q is None else q
-        return q.replace(" ", "+")
-
-    def results(self, data: str) -> list:
-        req = self.client.get(f"{self.base_url}/?s={data}").text
-        soup = BS(req, self.scraper)
-        items = []
-        mlitem = soup.findAll("div", {"class": "item"})
-        for i in range(len(mlitem)):
-            if str(mlitem[i]).__contains__("episode"):
-                pass
-            else:
-                items.append(mlitem[i])
-        if soup.find_all("ul", {"class": "pagination"}):
-            pagination = soup.find("ul", {"class": "pagination"}).findAll("li")[1:]
-            for page in pagination:
-                req = self.client.get(page.find("a")["href"]).text
-                soup = BS(req, self.scraper)
-                pageitem = soup.findAll("div", {"class": "item"})
-                for i in range(len(pageitem)):
-                    if str(pageitem[i]).__contains__("episode"):
-                        pass
-                    else:
-                        items.append(pageitem[i])
-        urls = [items[i].find("a")["href"] for i in range(len(items))]
-        title = [items[i].find("a")["title"] for i in range(len(items))]
-        ids = [items[i]["class"] for i in range(len(items))]
-        mov_or_tv = ["TV" for i in range(len(items))]
-        return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
-
-    def ask(self, url):
-        req = self.client.get(url, True).text
-        soup = BS(req, self.scraper)
-        episodes = soup.findAll("a", {"class": "episod"})
-        episode = int(self.askepisode(len(episodes)))
-        req = self.client.get(episodes[episode - 1]["href"], True).text
-        regex = r'''<iframe width="100%" height="100%" src="https:\/\/tukipasti\.com(.*?)"'''
-        s = re.findall(regex, req)[0]
-        req = self.client.get(f"https://tukipasti.com{s}").text
-        url = re.findall("var urlPlay = '(.*?)'", req)[0]
-        print(url)
-        return url, episode, f"https://tukipasti.com{s}"
-
-    def download(self, t):
-        req = self.client.get(t[self.url]).text
-        soup = BS(req, self.scraper)
-        episodes = soup.findAll("a", {"class": "episod"})
-        for e in range(len(episodes)):
-            req = self.client.get(episodes[e]["href"]).text
-            regex = r'''<iframe width="100%" height="100%" src="https:\/\/tukipasti\.com(.*?)"'''
-            s = re.findall(regex, req)[0]
-            req = self.client.get(f"https://tukipasti.com{s}").text
-            url = re.findall("var urlPlay = '(.*?)'", req)[0]
-            print(url)
-            self.dl(
-                url,
-                t[self.title],
-                season="",
-                episode=e + 1,
-                referrer=f"https://tukipasti.com{s}",
-            )
-
-    def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd" or "ds"):
-        if state == "sd":
-            self.download(t)
-            return
-        name = t[self.title]
-        url, episode, ref = self.ask(t[self.url])
-        if state == "d":
-            self.dl(url, name, season=".", episode=episode)
-            return
-        self.play(url, name, referrer=ref)
+from ...utils.scraper import WebScraper
+from bs4 import BeautifulSoup as BS
+import re
+
+
+class Provider(WebScraper):
+    def __init__(self, base_url):
+        super().__init__(base_url)
+        self.base_url = base_url
+
+    def search(self, q: str):
+        q = input(f"[!] {self.translated[self.task]}") if q is None else q
+        return q.replace(" ", "+")
+
+    def results(self, data: str) -> list:
+        req = self.client.get(f"{self.base_url}/?s={data}").text
+        soup = BS(req, self.scraper)
+        items = []
+        mlitem = soup.findAll("div", {"class": "item"})
+        for i in range(len(mlitem)):
+            if str(mlitem[i]).__contains__("episode"):
+                pass
+            else:
+                items.append(mlitem[i])
+        if soup.find_all("ul", {"class": "pagination"}):
+            pagination = soup.find("ul", {"class": "pagination"}).findAll("li")[1:]
+            for page in pagination:
+                req = self.client.get(page.find("a")["href"]).text
+                soup = BS(req, self.scraper)
+                pageitem = soup.findAll("div", {"class": "item"})
+                for i in range(len(pageitem)):
+                    if str(pageitem[i]).__contains__("episode"):
+                        pass
+                    else:
+                        items.append(pageitem[i])
+        urls = [items[i].find("a")["href"] for i in range(len(items))]
+        title = [items[i].find("a")["title"] for i in range(len(items))]
+        ids = [items[i]["class"] for i in range(len(items))]
+        mov_or_tv = ["TV" for i in range(len(items))]
+        return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
+
+    def ask(self, url):
+        req = self.client.get(url, True).text
+        soup = BS(req, self.scraper)
+        episodes = soup.findAll("a", {"class": "episod"})
+        episode = int(self.askepisode(len(episodes)))
+        req = self.client.get(episodes[episode - 1]["href"], True).text
+        url, tukibase = self.tuki(req)
+        return url, episode, tukibase
+
+    def download(self, t):
+        req = self.client.get(t[self.url]).text
+        soup = BS(req, self.scraper)
+        episodes = soup.findAll("a", {"class": "episod"})
+        for e in range(len(episodes)):
+            req = self.client.get(episodes[e]["href"]).text
+            url, tukibase = self.tuki(req)
+            print(url)
+            self.dl(
+                url,
+                t[self.title],
+                season="",
+                episode=e + 1,
+                referrer=tukibase,
+            )
+
+    def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd" or "ds"):
+        if state == "sd":
+            self.download(t)
+            return
+        name = t[self.title]
+        url, episode, ref = self.ask(t[self.url])
+        if state == "d":
+            self.dl(url, name, season=".", episode=episode)
+            return
+        self.play(url, name, referrer=ref)
diff --git a/pyproject.toml b/pyproject.toml
index b472aeef..77f58e62 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -26,4 +26,4 @@ build-backend = "poetry.core.masonry.api"
 mov-cli = "mov_cli.__main__:movcli"
 
 [tool.poetry.urls]
-"Bug Tracker" = "https://github.com/mov-cli/mov-cli/issues"
+"Bug Tracker" = "https://github.com/mov-cli/mov-cli/issues"
\ No newline at end of file
diff --git a/runner.py b/runner.py
index 6916075a..7107ad19 100644
--- a/runner.py
+++ b/runner.py
@@ -2,3 +2,4 @@
 
 if __name__ == "__main__":
     movcli()
+


Test patch:
diff --git a/mov_cli/websites/remotestream.py b/mov_cli/websites/english/remotestream.py
similarity index 65%
rename from mov_cli/websites/remotestream.py
rename to mov_cli/websites/english/remotestream.py
index 54e16e3a..c307d482 100644
--- a/mov_cli/websites/remotestream.py
+++ b/mov_cli/websites/english/remotestream.py
@@ -1,13 +1,16 @@
 from bs4 import BeautifulSoup as BS
-from ..utils.scraper import WebScraper
+from ...utils.scraper import WebScraper
 import re
+from ...utils.props import SelectedNotAvailable
 
 
-class remotestream(WebScraper):
+class Provider(WebScraper):
     def __init__(self, base_url):
         super().__init__(base_url)
         self.base_url = base_url
         self.movdb = "https://www.themoviedb.org"
+        self.dseasonp = False
+        self.dshowp = True
 
     def search(self, q: str):
         q = input(f"[!] {self.translated[self.task]}") if q is None else q
@@ -18,35 +21,26 @@ def results(self, data: str) -> list:
         urls = []
         ids = []
         mov_or_tv = []
-        tv = self.client.get(self.movdb + f"/search/tv?query={data}&language=en").text
-        movie = self.client.get(
-            self.movdb + f"/search/movie?query={data}&language=en"
-        ).text
-        # MOVIE
-        soupm = BS(movie, self.scraper)
-        mcards = soupm.findAll("div", {"class": "card v4 tight"})
-        if mcards is not []:
-            title.extend([mcards[i].find("h2").text for i in range(len(mcards))])
-            urls.extend(["" for i in range(len(mcards))])
-            ids.extend(
-                [
-                    mcards[i].find("a")["href"].split("/")[-1].split("?")[0]
-                    for i in range(len(mcards))
-                ]
-            )
-            mov_or_tv.extend(["MOVIE" for i in range(len(mcards))])
-        soups = BS(tv, self.scraper)
-        scards = soups.findAll("div", {"class": "card v4 tight"})
-        if scards is not []:
-            title.extend([scards[i].find("h2").text for i in range(len(scards))])
-            urls.extend(["" for i in range(len(scards))])
-            ids.extend(
-                [
-                    scards[i].find("a")["href"].split("/")[-1].split("?")[0]
-                    for i in range(len(scards))
-                ]
-            )
-            mov_or_tv.extend(["TV" for i in range(len(scards))])
+        for i in range(2):
+            if i == 0:
+                get = "movie"
+            else:
+                get = "tv"
+            req = self.client.get(
+                self.movdb + f"/search/{get}?query={data}&language=en"
+            ).text
+            soup = BS(req, self.scraper)
+            cards = soup.findAll("div", {"class": "card v4 tight"})
+            if cards is not []:
+                title.extend([cards[i].find("h2").text for i in range(len(cards))])
+                urls.extend(["" for i in range(len(cards))])
+                ids.extend(
+                    [
+                        cards[i].find("a")["href"].split("/")[-1].split("?")[0]
+                        for i in range(len(cards))
+                    ]
+                )
+                mov_or_tv.extend([get.upper() for i in range(len(cards))])
         return [list(sublist) for sublist in zip(title, urls, ids, mov_or_tv)]
 
     def ask(self, id):
@@ -80,8 +74,7 @@ def cdn_url(self, id=None, season=None, episode=None):
         try:
             file = re.findall('"file":"(.*?)"', res)[0]
         except IndexError as e:
-            print("This show or movie is not available.")
-            exit(1)
+            raise SelectedNotAvailable
         return file
 
     def sd(self, name, id):
@@ -109,14 +102,14 @@ def MOV_PandDP(self, m: list, state: str = "d" or "p"):
             return
         self.play(url, name)
 
-    def TV_PandDP(self, t: list, state: str = "d" or "p" or "sd"):
-        if state == "sd":
+    def TV_PandDP(self, t: list, state: str):
+        if state == "s":
             self.sd(t[self.title], t[self.aid])
             return
         name = t[self.title]
         season, episode = self.ask(t[self.aid])
         url = self.cdn_url(t[self.aid], season, episode)
         if state == "d":
-            self.dl(url, name, season=".", episode=episode)
+            self.dl(url, name, season=season, episode=episode)
             return
         self.play(url, name)