# Buggy code
def _real_extract(self, url):
    video_id = self._match_id(url)

    # Get video webpage. We are not actually interested in it for normal
    # cases, but need the cookies in order to be able to download the
    # info webpage
    webpage, handle = self._download_webpage_handle(
        "http://www.nicovideo.jp/watch/" + video_id, video_id
    )
    if video_id.startswith("so"):
        video_id = self._match_id(handle.geturl())

    video_info = self._download_xml(
        "http://ext.nicovideo.jp/api/getthumbinfo/" + video_id,
        video_id,
        note="Downloading video info page",
    )

    # Get flv info
    flv_info_webpage = self._download_webpage(
        "http://flapi.nicovideo.jp/api/getflv/" + video_id + "?as3=1",
        video_id,
        "Downloading flv info",
    )

    flv_info = compat_urlparse.parse_qs(flv_info_webpage)
    if "url" not in flv_info:
        if "deleted" in flv_info:
            raise ExtractorError("The video has been deleted.", expected=True)
        elif "closed" in flv_info:
            raise ExtractorError(
                "Niconico videos now require logging in", expected=True
            )
        elif "error" in flv_info:
            raise ExtractorError(
                "%s reports error: %s" % (self.IE_NAME, flv_info["error"][0]),
                expected=True,
            )
        else:
            raise ExtractorError("Unable to find video URL")

    video_real_url = flv_info["url"][0]

    # Start extracting information
    title = xpath_text(video_info, ".//title")
    if not title:
        title = self._og_search_title(webpage, default=None)
    if not title:
        title = self._html_search_regex(
            r'<span[^>]+class="videoHeaderTitle"[^>]*>([^<]+)</span>',
            webpage,
            "video title",
        )

    watch_api_data_string = self._html_search_regex(
        r'<div[^>]+id="watchAPIDataContainer"[^>]+>([^<]+)</div>',
        webpage,
        "watch api data",
        default=None,
    )
    watch_api_data = (
        self._parse_json(watch_api_data_string, video_id)
        if watch_api_data_string
        else {}
    )
    video_detail = watch_api_data.get("videoDetail", {})

    extension = xpath_text(video_info, ".//movie_type")
    if not extension:
        extension = determine_ext(video_real_url)

    thumbnail = (
        xpath_text(video_info, ".//thumbnail_url")
        or self._html_search_meta("image", webpage, "thumbnail", default=None)
        or video_detail.get("thumbnail")
    )

    description = xpath_text(video_info, ".//description")

    timestamp = parse_iso8601(xpath_text(video_info, ".//first_retrieve"))
    if not timestamp:
        match = self._html_search_meta(
            "datePublished", webpage, "date published", default=None
        )
        if match:
            timestamp = parse_iso8601(match.replace("+", ":00+"))
    if not timestamp and video_detail.get("postedAt"):
        timestamp = parse_iso8601(
            video_detail["postedAt"].replace("/", "-"),
            delimiter=" ",
            timezone=datetime.timedelta(hours=9),
        )

    view_count = int_or_none(xpath_text(video_info, ".//view_counter"))
    if not view_count:
        match = self._html_search_regex(
            r">Views: <strong[^>]*>([^<]+)</strong>",
            webpage,
            "view count",
            default=None,
        )
        if match:
            view_count = int_or_none(match.replace(",", ""))
    view_count = view_count or video_detail.get("viewCount")

    comment_count = int_or_none(xpath_text(video_info, ".//comment_num"))
    if not comment_count:
        match = self._html_search_regex(
            r">Comments: <strong[^>]*>([^<]+)</strong>",
            webpage,
            "comment count",
            default=None,
        )
        if match:
            comment_count = int_or_none(match.replace(",", ""))
    comment_count = comment_count or video_detail.get("commentCount")

    duration = parse_duration(
        xpath_text(video_info, ".//length")
        or self._html_search_meta(
            "video:duration", webpage, "video duration", default=None
        )
    ) or video_detail.get("length")

    webpage_url = xpath_text(video_info, ".//watch_url") or url

    if video_info.find(".//ch_id") is not None:
        uploader_id = video_info.find(".//ch_id").text
        uploader = video_info.find(".//ch_name").text
    elif video_info.find(".//user_id") is not None:
        uploader_id = video_info.find(".//user_id").text
        uploader = video_info.find(".//user_nickname").text
    else:
        uploader_id = uploader = None

    return {
        "id": video_id,
        "url": video_real_url,
        "title": title,
        "ext": extension,
        "format_id": "economy" if video_real_url.endswith("low") else "normal",
        "thumbnail": thumbnail,
        "description": description,
        "uploader": uploader,
        "timestamp": timestamp,
        "uploader_id": uploader_id,
        "view_count": view_count,
        "comment_count": comment_count,
        "duration": duration,
        "webpage_url": webpage_url,
    }


# Traceback (urllib.error.HTTPError)
[debug] System config: []
[debug] User config: []
[debug] Custom config: []
[debug] Command-line args: ['-u', 'PRIVATE', '-p', 'PRIVATE', '-v', '--user-agen
t', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/59.0.3071.112 Safari/537.36 Vivaldi/1.91.867.48', 'http://www.nicovideo.j
p/watch/sm1151009']
[debug] Encodings: locale cp932, fs mbcs, out cp932, pref cp932
[debug] youtube-dl version 2017.07.30.1
[debug] Python version 3.4.4 - Windows-7-6.1.7601-SP1
[debug] exe versions: ffmpeg N-86537-gae6f6d4, ffprobe N-86537-gae6f6d4
[debug] Proxy map: {}
[niconico] Logging in
[niconico] sm1151009: Downloading webpage
[niconico] sm1151009: Downloading video info page
[niconico] sm1151009: Downloading flv info
[debug] Default format spec: bestvideo+bestaudio/best
[debug] Invoking downloader on 'http://smile-cca61.nicovideo.jp/smile?v=1151009.
96367'
ERROR: unable to download video data: HTTP Error 403: Forbidden
Traceback (most recent call last):
File "C:\Users\dst\AppData\Roaming\Build archive\youtube-dl\rg3\tmpfdfxmx88\bu
ild\youtube_dl\YoutubeDL.py", line 1863, in process_info
File "C:\Users\dst\AppData\Roaming\Build archive\youtube-dl\rg3\tmpfdfxmx88\bu
ild\youtube_dl\YoutubeDL.py", line 1805, in dl
File "C:\Users\dst\AppData\Roaming\Build archive\youtube-dl\rg3\tmpfdfxmx88\bu
ild\youtube_dl\downloader\common.py", line 361, in download
File "C:\Users\dst\AppData\Roaming\Build archive\youtube-dl\rg3\tmpfdfxmx88\bu
ild\youtube_dl\downloader\http.py", line 61, in real_download
File "C:\Users\dst\AppData\Roaming\Build archive\youtube-dl\rg3\tmpfdfxmx88\bu
ild\youtube_dl\YoutubeDL.py", line 2166, in urlopen
File "C:\Python\Python34\lib\urllib\request.py", line 470, in open
File "C:\Python\Python34\lib\urllib\request.py", line 580, in http_response
File "C:\Python\Python34\lib\urllib\request.py", line 508, in error
File "C:\Python\Python34\lib\urllib\request.py", line 442, in _call_chain
File "C:\Python\Python34\lib\urllib\request.py", line 588, in http_error_defau
lt
urllib.error.HTTPError: HTTP Error 403: Forbidden
...
<end of log>

# Fixed code
def _real_extract(self, url):
    video_id = self._match_id(url)

    # Get video webpage. We are not actually interested in it for normal
    # cases, but need the cookies in order to be able to download the
    # info webpage
    webpage, handle = self._download_webpage_handle(
        "http://www.nicovideo.jp/watch/" + video_id, video_id
    )
    if video_id.startswith("so"):
        video_id = self._match_id(handle.geturl())

    api_data = self._parse_json(
        self._html_search_regex(
            'data-api-data="([^"]+)"', webpage, "API data", default="{}"
        ),
        video_id,
    )
    video_real_url = try_get(api_data, lambda x: x["video"]["smileInfo"]["url"])

    if video_real_url:

        def get_video_info(items):
            return dict_get(api_data["video"], items)
    else:
        # Get flv info
        flv_info_webpage = self._download_webpage(
            "http://flapi.nicovideo.jp/api/getflv/" + video_id + "?as3=1",
            video_id,
            "Downloading flv info",
        )

        flv_info = compat_urlparse.parse_qs(flv_info_webpage)
        if "url" not in flv_info:
            if "deleted" in flv_info:
                raise ExtractorError("The video has been deleted.", expected=True)
            elif "closed" in flv_info:
                raise ExtractorError(
                    "Niconico videos now require logging in", expected=True
                )
            elif "error" in flv_info:
                raise ExtractorError(
                    "%s reports error: %s" % (self.IE_NAME, flv_info["error"][0]),
                    expected=True,
                )
            else:
                raise ExtractorError("Unable to find video URL")

        video_real_url = flv_info["url"][0]

        video_info_xml = self._download_xml(
            "http://ext.nicovideo.jp/api/getthumbinfo/" + video_id,
            video_id,
            note="Downloading video info page",
        )

        def get_video_info(items):
            if not isinstance(items, list):
                items = [items]
            for item in items:
                ret = xpath_text(video_info_xml, ".//" + item)
                if ret:
                    return ret

    # Start extracting information
    title = get_video_info("title")
    if not title:
        title = self._og_search_title(webpage, default=None)
    if not title:
        title = self._html_search_regex(
            r'<span[^>]+class="videoHeaderTitle"[^>]*>([^<]+)</span>',
            webpage,
            "video title",
        )

    watch_api_data_string = self._html_search_regex(
        r'<div[^>]+id="watchAPIDataContainer"[^>]+>([^<]+)</div>',
        webpage,
        "watch api data",
        default=None,
    )
    watch_api_data = (
        self._parse_json(watch_api_data_string, video_id)
        if watch_api_data_string
        else {}
    )
    video_detail = watch_api_data.get("videoDetail", {})

    extension = get_video_info(["movie_type", "movieType"])
    if not extension:
        extension = determine_ext(video_real_url)

    thumbnail = (
        get_video_info(["thumbnail_url", "thumbnailURL"])
        or self._html_search_meta("image", webpage, "thumbnail", default=None)
        or video_detail.get("thumbnail")
    )

    description = get_video_info("description")

    timestamp = parse_iso8601(get_video_info("first_retrieve")) or unified_timestamp(
        get_video_info("postedDateTime")
    )
    if not timestamp:
        match = self._html_search_meta(
            "datePublished", webpage, "date published", default=None
        )
        if match:
            timestamp = parse_iso8601(match.replace("+", ":00+"))
    if not timestamp and video_detail.get("postedAt"):
        timestamp = parse_iso8601(
            video_detail["postedAt"].replace("/", "-"),
            delimiter=" ",
            timezone=datetime.timedelta(hours=9),
        )

    view_count = int_or_none(get_video_info(["view_counter", "viewCount"]))
    if not view_count:
        match = self._html_search_regex(
            r">Views: <strong[^>]*>([^<]+)</strong>",
            webpage,
            "view count",
            default=None,
        )
        if match:
            view_count = int_or_none(match.replace(",", ""))
    view_count = view_count or video_detail.get("viewCount")

    comment_count = (
        int_or_none(get_video_info("comment_num"))
        or video_detail.get("commentCount")
        or try_get(api_data, lambda x: x["thread"]["commentCount"])
    )
    if not comment_count:
        match = self._html_search_regex(
            r">Comments: <strong[^>]*>([^<]+)</strong>",
            webpage,
            "comment count",
            default=None,
        )
        if match:
            comment_count = int_or_none(match.replace(",", ""))

    duration = (
        parse_duration(
            get_video_info("length")
            or self._html_search_meta(
                "video:duration", webpage, "video duration", default=None
            )
        )
        or video_detail.get("length")
        or get_video_info("duration")
    )

    webpage_url = get_video_info("watch_url") or url

    owner = api_data.get("owner", {})
    uploader_id = get_video_info(["ch_id", "user_id"]) or owner.get("id")
    uploader = get_video_info(["ch_name", "user_nickname"]) or owner.get("nickname")

    return {
        "id": video_id,
        "url": video_real_url,
        "title": title,
        "ext": extension,
        "format_id": "economy" if video_real_url.endswith("low") else "normal",
        "thumbnail": thumbnail,
        "description": description,
        "uploader": uploader,
        "timestamp": timestamp,
        "uploader_id": uploader_id,
        "view_count": view_count,
        "comment_count": comment_count,
        "duration": duration,
        "webpage_url": webpage_url,
    }