Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/lastfm.py (Python)

Code before:
# coding: utf-8
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..utils import int_or_none, format_field


class LastFMPlaylistBaseIE(InfoExtractor):
    def _entries(self, url, playlist_id):
        webpage = self._download_webpage(url, playlist_id)
        start_page_number = int_or_none(self._search_regex(
            r'\bpage=(\d+)', url, 'page', default=None)) or 1

        last_page_number = int_or_none(self._search_regex(
            r'>(\d+)</a>[^<]*</li>[^<]*<li[^>]+class="pagination-next', webpage, 'last_page', default=None))

        for page_number in range(start_page_number, (last_page_number or start_page_number) + 1):
            webpage = self._download_webpage(
                url, playlist_id,
                note='Downloading page %d%s' % (page_number, format_field(last_page_number, template=' of %d')),
                query={'page': page_number})
            page_entries = [
                self.url_result(player_url, 'Youtube')
                for player_url in set(re.findall(r'data-youtube-url="([^"]+)"', webpage))
            ]

            for e in page_entries:
                yield e

    def _real_extract(self, url):
        playlist_id = self._match_id(url)
        return self.playlist_result(self._entries(url, playlist_id), playlist_id)


class LastFMPlaylistIE(LastFMPlaylistBaseIE):
    _VALID_URL = r'https?://(?:www\.)?last\.fm/(music|tag)/(?P<id>[^/]+)/?[^/]+?$'
    _TESTS = [{
        'url': 'https://www.last.fm/music/Oasis/(What%27s+the+Story)+Morning+Glory%3F',
        'info_dict': {
            'id': 'Oasis',

Review comment (suggestion):
```suggestion
        start_page_number = int(self._search_regex(
            r'\bpage=(\d+)', url, 'page', default=None)) or 1

        last_page_number = int(self._search_regex(
            r'>(\d+)</a>[^<]*</li>[^<]*<li[^>]+class="pagination-next', webpage, 'last_page', default=None))
```
since it's matched with `/d+`

Code after:
# coding: utf-8
from __future__ import unicode_literals

import re

from .common import InfoExtractor
from ..utils import int_or_none, format_field


class LastFMPlaylistBaseIE(InfoExtractor):
    def _entries(self, url, playlist_id):
        webpage = self._download_webpage(url, playlist_id)
        start_page_number = int_or_none(self._search_regex(
            r'\bpage=(\d+)', url, 'page', default=None)) or 1
        last_page_number = int_or_none(self._search_regex(
            r'>(\d+)</a>[^<]*</li>[^<]*<li[^>]+class="pagination-next', webpage, 'last_page', default=None))

        for page_number in range(start_page_number, (last_page_number or start_page_number) + 1):
            webpage = self._download_webpage(
                url, playlist_id,
                note='Downloading page %d%s' % (page_number, format_field(last_page_number, template=' of %d')),
                query={'page': page_number})
            page_entries = [
                self.url_result(player_url, 'Youtube')
                for player_url in set(re.findall(r'data-youtube-url="([^"]+)"', webpage))
            ]

            for e in page_entries:
                yield e

    def _real_extract(self, url):
        playlist_id = self._match_id(url)
        return self.playlist_result(self._entries(url, playlist_id), playlist_id)


class LastFMPlaylistIE(LastFMPlaylistBaseIE):
    _VALID_URL = r'https?://(?:www\.)?last\.fm/(music|tag)/(?P<id>[^/]+)(?:/[^/]+)?/?(?:[?#]|$)'
    _TESTS = [{
        'url': 'https://www.last.fm/music/Oasis/(What%27s+the+Story)+Morning+Glory%3F',
        'info_dict': {
            'id': 'Oasis',
        },