ytdl-org/youtube-dl · error · ExtractorError

Video %s is not available

Error message

Video %s is not available

What it means

SpankBangIE downloads the /video page (rewritten from /embed, with a country=US cookie) and greps for an element whose id or class starts with 'video_removed'. A match means the clip was taken down, so it raises 'Video <id> is not available' as an expected error before format parsing.

Source

Thrown at youtube_dl/extractor/spankbang.py:80

        'url': 'https://m.spankbang.com/3vvn/play',
        'only_matching': True,
    }, {
        'url': 'https://spankbang.com/2y3td/embed/',
        'only_matching': True,
    }, {
        'url': 'https://spankbang.com/2v7ik-7ecbgu/playlist/latina+booty',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        video_id = mobj.group('id') or mobj.group('id_2')
        webpage = self._download_webpage(
            url.replace('/%s/embed' % video_id, '/%s/video' % video_id),
            video_id, headers={'Cookie': 'country=US'})

        if re.search(r'<[^>]+\b(?:id|class)=["\']video_removed', webpage):
            raise ExtractorError(
                'Video %s is not available' % video_id, expected=True)

        formats = []

        def extract_format(format_id, format_url):
            f_url = url_or_none(format_url)
            if not f_url:
                return
            f = parse_resolution(format_id)
            ext = determine_ext(f_url)
            if format_id.startswith('m3u8') or ext == 'm3u8':
                formats.extend(self._extract_m3u8_formats(
                    f_url, video_id, 'mp4', entry_protocol='m3u8_native',
                    m3u8_id='hls', fatal=False))
            elif format_id.startswith('mpd') or ext == 'mpd':
                formats.extend(self._extract_mpd_formats(
                    f_url, video_id, mpd_id='dash', fatal=False))
            elif ext == 'mp4' or f.get('width') or f.get('height'):

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Open the URL in a browser (from the same region) to read the exact removal notice.
  2. Search the site for re-uploads under a different id.
  3. If the notice says region-restricted, a VPN to the allowed region may make it extractable.
  4. Verify the URL slug - truncated ids land on removal-style pages.
Defensive patterns

Strategy: try-catch

Validate before calling

webpage = requests.get(rewritten_video_url, headers={'Cookie': 'country=US'}).text
if re.search(r'<[^>]+\b(?:id|class)=["\']video_removed', webpage):
    skip(video_id)

Type guard

def video_was_removed(webpage: str) -> bool:
    return bool(re.search(r'<[^>]+\b(?:id|class)=["\']video_removed', webpage))

Try / catch

try:
    extract(url)
except ExtractorError as e:
    if 'is not available' in str(e):
        drop_from_queue(video_id)
    else:
        raise

Prevention

When it happens

Trigger: Extracting a spankbang.com URL whose page contains e.g. <div class="video_removed"> - i.e. removed for DMCA/terms, deleted by the uploader, or region-swapped content that the US-cookie route cannot see. The state-specific variants (removed in your region, by uploader, etc.) all match this check.

Common situations: DMCA takedowns (very frequent on this site); uploader deletions; clips removed for US viewers specifically - the extractor forces country=US, so content legal only elsewhere always looks removed; mistyped slug.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/6038cdf82f086683. Report an issue: GitHub.