text: from __future__ import unicode_literals
  
  import re
  
  from ..utils import (ExtractorError, determine_ext, int_or_none, merge_dicts,
                       str_to_int, unified_strdate, url_or_none)
  from .common import InfoExtractor
  
  
  class RedTubeIE(InfoExtractor):
      _VALID_URL = r"https?://(?:(?:\w+\.)?redtube\.com/|embed\.redtube\.com/\?.*?\bid=)(?P<id>[0-9]+)"
      _TESTS = [
          {
              "url": "http://www.redtube.com/66418",
              "md5": "fc08071233725f26b8f014dba9590005",
              "info_dict": {
                  "id": "66418",
                  "ext": "mp4",
                  "title": "Sucked on a toilet",
                  "upload_date": "20110811",
                  "duration": 596,
                  "view_count": int,
                  "age_limit": 18,
              },
          },
          {
              "url": "http://embed.redtube.com/?bgcolor=000000&id=1443286",
              "only_matching": True,
          },
          {
              "url": "http://it.redtube.com/66418",
              "only_matching": True,
          },
      ]
  
      @staticmethod
      def _extract_urls(webpage):
          return re.findall(
              r'<iframe[^>]+?src=["\'](?P<url>(?:https?:)?//embed\.redtube\.com/\?.*?\bid=\d+)',
              webpage,
          )
  
      def _real_extract(self, url):
          video_id = self._match_id(url)
          webpage = self._download_webpage(
              "http://www.redtube.com/%s" % video_id, video_id
          )
  
          ERRORS = (
              (
                  ("video-deleted-info", ">This video has been removed"),
                  "has been removed",
              ),
              (
                  (
                      "private_video_text",
                      ">This video is private",
                      ">Send a friend request to its owner to be able to view it",
                  ),
                  "is private",
              ),
          )
  
          for patterns, message in ERRORS:
              if any(p in webpage for p in patterns):
                  raise ExtractorError("Video %s %s" % (video_id, message), expected=True)
  
          info = self._search_json_ld(webpage, video_id, default={})
  
          if not info.get("title"):
              info["title"] = (
                  self._html_search_regex(
                      (
                          r'<h(\d)[^>]+class="(?:video_title_text|videoTitle|video_title)[^"]*">(?P<title>(?:(?!\1).)+)</h\1>',
                          r'(?:videoTitle|title)\s*:\s*(["\'])(?P<title>(?:(?!\1).)+)\1',
                      ),
                      webpage,
                      "title",
                      group="title",
                      default=None,
                  )
                  or self._og_search_title(webpage)
              )
  
          formats = []
          sources = self._parse_json(
              self._search_regex(
                  r"sources\s*:\s*({.+?})", webpage, "source", default="{}"
              ),
              video_id,
              fatal=False,
          )
          if sources and isinstance(sources, dict):
              for format_id, format_url in sources.items():
                  if format_url:
                      formats.append(
                          {
                              "url": format_url,
                              "format_id": format_id,
                              "height": int_or_none(format_id),
                          }
                      )
          medias = self._parse_json(
              self._search_regex(
                  r'mediaDefinition["\']?\s*:\s*(\[.+?}\s*\])',
                  webpage,
                  "media definitions",
                  default="{}",
              ),
              video_id,
              fatal=False,
          )
          if medias and isinstance(medias, list):
              for media in medias:
                  format_url = url_or_none(media.get("videoUrl"))
                  if not format_url:
                      continue
                  if media.get("format") == "hls" or determine_ext(format_url) == "m3u8":
                      formats.extend(
                          self._extract_m3u8_formats(
                              format_url,
                              video_id,
                              "mp4",
                              entry_protocol="m3u8_native",
                              m3u8_id="hls",
                              fatal=False,
                          )
                      )
                      continue
                  format_id = media.get("quality")
                  formats.append(
                      {
                          "url": format_url,
                          "format_id": format_id,
                          "height": int_or_none(format_id),
                      }
                  )
          if not formats:
              video_url = self._html_search_regex(
                  r'<source src="(.+?)" type="video/mp4">', webpage, "video URL"
              )
              formats.append({"url": video_url})
          self._sort_formats(formats)
  
          thumbnail = self._og_search_thumbnail(webpage)
          upload_date = unified_strdate(
              self._search_regex(
                  r"<span[^>]+>(?:ADDED|Published on) ([^<]+)<",
                  webpage,
                  "upload date",
                  default=None,
              )
          )
          duration = int_or_none(
              self._og_search_property("video:duration", webpage, default=None)
              or self._search_regex(
                  r"videoDuration\s*:\s*(\d+)", webpage, "duration", default=None
              )
          )
          view_count = str_to_int(
              self._search_regex(
                  (
                      r"<div[^>]*>Views</div>\s*<div[^>]*>\s*([\d,.]+)",
                      r"<span[^>]*>VIEWS</span>\s*</td>\s*<td>\s*([\d,.]+)",
                      r'<span[^>]+\bclass=["\']video_view_count[^>]*>\s*([\d,.]+)',
                  ),
                  webpage,
                  "view count",
                  default=None,
              )
          )
  
          # No self-labeling, but they describe themselves as
          # "Home of Videos Porno"
          age_limit = 18
  
          return merge_dicts(
              info,
              {
                  "id": video_id,
                  "ext": "mp4",
                  "thumbnail": thumbnail,
                  "upload_date": upload_date,
                  "duration": duration,
                  "view_count": view_count,
                  "age_limit": age_limit,
                  "formats": formats,
              },
          )
  