text: import re
  
  from livecli import PluginError
  from livecli.plugin import Plugin, PluginOptions
  from livecli.plugin.api import validate
  from livecli.stream import HLSStream
  from livecli.stream import RTMPStream
  from livecli.plugin.api import http
  from livecli.compat import urljoin
  
  __livecli_docs__ = {
      "domains": [
          "liveedu.tv",
          "livecoding.tv"
      ],
      "geo_blocked": [],
      "notes": "Some streams require a login.",
      "live": True,
      "vod": False,
      "last_update": "2017-04-03",
  }
  
  
  class LiveEdu(Plugin):
      login_url = "https://www.liveedu.tv/accounts/login/"
      url_re = re.compile(r"https?://(?:\w+\.)?(?:livecoding|liveedu)\.tv/")
      config_re = re.compile(r"""\Wconfig.(?P<key>\w+)\s*=\s*(?P<q>['"])(?P<value>.*?)(?P=q);""")
      csrf_re = re.compile(r'''"csrfToken"\s*:\s*"(\w+)"''')
      api_schema = validate.Schema({
          "viewing_urls": {
              validate.optional("error"): validate.text,
              validate.optional("urls"): [{
                  "src": validate.url(),
                  "type": validate.text,
                  validate.optional("res"): int,
                  validate.optional("label"): validate.text,
              }]
          }
      })
      config_schema = validate.Schema({
          "selectedVideoHID": validate.text,
          "livestreamURL": validate.text,
          "videosURL": validate.text
      })
  
      options = PluginOptions({
          "email": None,
          "password": None
      })
  
      @classmethod
      def can_handle_url(cls, url):
          return cls.url_re.match(url) is not None
  
      def login(self):
          """
          Attempt a login to LiveEdu.tv
          """
          email = self.get_option("email")
          password = self.get_option("password")
  
          if email and password:
              res = http.get(self.login_url)
              csrf_match = self.csrf_re.search(res.text)
              token = csrf_match and csrf_match.group(1)
              self.logger.debug("Attempting login as {0} (token={1})", email, token)
  
              res = http.post(self.login_url,
                              data=dict(login=email, password=password, csrfmiddlewaretoken=token),
                              allow_redirects=False,
                              raise_for_status=False,
                              headers={"Referer": self.login_url})
  
              if res.status_code != 302:
                  self.logger.error("Failed to login to LiveEdu account: {0}", email)
  
      def _get_streams(self):
          """
          Get the config object from the page source and call the
          API to get the list of streams
          :return:
          """
          # attempt a login
          self.login()
  
          res = http.get(self.url)
          # decode the config for the page
          matches = self.config_re.finditer(res.text)
          try:
              config = self.config_schema.validate(dict(
                  [m.group("key", "value") for m in matches]
              ))
          except PluginError:
              return
  
          if config["selectedVideoHID"]:
              self.logger.debug("Found video hash ID: {0}", config["selectedVideoHID"])
              api_url = urljoin(self.url, urljoin(config["videosURL"], config["selectedVideoHID"]))
          elif config["livestreamURL"]:
              self.logger.debug("Found live stream URL: {0}", config["livestreamURL"])
              api_url = urljoin(self.url, config["livestreamURL"])
          else:
              return
  
          ares = http.get(api_url)
          data = http.json(ares, schema=self.api_schema)
          viewing_urls = data["viewing_urls"]
  
          if "error" in viewing_urls:
              self.logger.error("Failed to load streams: {0}", viewing_urls["error"])
          else:
              for url in viewing_urls["urls"]:
                  try:
                      label = "{0}p".format(url.get("res", url["label"]))
                  except KeyError:
                      label = "live"
  
                  if url["type"] == "rtmp/mp4" and RTMPStream.is_usable(self.session):
                      params = {
                          "rtmp": url["src"],
                          "pageUrl": self.url,
                          "live": True,
                      }
                      yield label, RTMPStream(self.session, params)
  
                  elif url["type"] == "application/x-mpegURL":
                      for s in HLSStream.parse_variant_playlist(self.session, url["src"]).items():
                          yield s
  
  
  __plugin__ = LiveEdu
  