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

Code before:
                    raise ExtractorError(self._parse_json(
                        e.cause.response.read().decode(), xid)['error_description'], expected=True)
                raise
            self._set_dailymotion_cookie('access_token' if username else 'client_token', token)
        return token

    def _call_api(self, object_type, xid, object_fields, note, filter_extra=None):
        if not self._HEADERS.get('Authorization'):
            token = self._get_token(xid)
            self._HEADERS['Authorization'] = 'Bearer ' + token

        resp = self._download_json(
            'https://graphql.api.dailymotion.com/', xid, note, data=json.dumps({
                'query': '''{
  %s(xid: "%s"%s) {
    %s
  }
}''' % (object_type, xid, ', ' + filter_extra if filter_extra else '', object_fields),
            }).encode(), headers=self._HEADERS)
        obj = resp['data'][object_type]
        if not obj:
            raise ExtractorError(resp['errors'][0]['message'], expected=True)
        return obj

    def _call_search_api(self, term, page, note):
        payload_living_horror = '''
fragment VIDEO_BASE_FRAGMENT on Video {
  id
  xid
  title
  createdAt
  stats {
    id
    views {
      id
      total
      __typename
    }
    __typename
  }
  channel {
    id
    xid
    name
    displayName
    accountType
    __typename
  }
  duration
  thumbnailx60: thumbnailURL(size: "x60")
  thumbnailx120: thumbnailURL(size: "x120")

Review comment (suggestion):
Yeah, this kind of sucks. I think it's probably best to use a slightly minified version on a single line:
```suggestion
        search_query = 'fragment VIDEO_BASE_FRAGMENT on Video { id xid title createdAt stats { id views { id total __typename } __typename } channel { id xid name displayName accountType __typename } duration thumbnailx60: thumbnailURL(size: "x60") thumbnailx120: thumbnailURL(size: "x120") thumbnailx240: thumbnailURL(size: "x240") thumbnailx720: thumbnailURL(size: "x720") aspectRatio __typename } fragment VIDEO_FAVORITES_FRAGMENT on Media { __typename ... on Video { id isInWatchLater __typename } ... on Live { id isInWatchLater __typename } } fragment CHANNEL_BASE_FRAG on Channel { accountType id xid name displayName isFollowed thumbnailx60: logoURL(size: "x60") thumbnailx120: logoURL(size: "x120") thumbnailx240: logoURL(size: "x240") thumbnailx720: logoURL(size: "x720") __typename } fragment PLAYLIST_BASE_FRAG on Collection { id xid name channel { id xid name displayName accountType __typename } description thumbnailx60: thumbnailURL(size: "x60") thumbnailx120: thumbnailURL(size: "x120") thumbnailx240: thumbnailURL(size: "x240") thumbnailx720: thumbnailURL(size: "x720") stats { id videos { id total __typename } __typename } __typename } fragment TOPIC_BASE_FRAG on Topic { id xid name videos(sort: "recent", first: 5) { pageInfo { hasNextPage nextPage __typename } edges { node { id ...VIDEO_BASE_FRAGMENT ...VIDEO_FAVORITES_FRAGMENT __typename } __typename } __typename } stats { id videos { id total __typename } __typename } __typename } query SEARCH_QUERY($query: String!, $shouldIncludeVideos: Boolean!, $shouldIncludeChannels: Boolean!, $shouldIncludePlaylists: Boolean!, $shouldIncludeTopics: Boolean!, $shouldIncludeLives: Boolean!, $page: Int, $limit: Int, $sortByVideos: SearchVideoSort, $durationMinVideos: Int, $durationMaxVideos: Int, $createdAfterVideos: DateTime) { search { id videos( query: $query first: $limit page: $page sort: $sortByVideos durationMin: $durationMinVideos durationMax: $durationMaxVideos createdAfter: $createdAfterVideos ) @include(if: $shouldIncludeVideos) { metadata { algorithm { uuid __typename } __typename } pageInfo { hasNextPage nextPage __typename } totalCount edges { node { id ...VIDEO_BASE_FRAGMENT ...VIDEO_FAVORITES_FRAGMENT __typename } __typename } __typename } hasLives: lives(query: $query, first: $limit, page: $page) { totalCount __typename } lives(query: $query, first: $limit, page: $page) @include(if: $shouldIncludeLives) { metadata { algorithm { uuid __typename } __typename } pageInfo { hasNextPage nextPage __typename } totalCount edges { node { id xid title thumbnail: thumbnailURL(size: "x240") thumbnailx60: thumbnailURL(size: "x60") thumbnailx120: thumbnailURL(size: "x120") thumbnailx240: thumbnailURL(size: "x240") thumbnailx720: thumbnailURL(size: "x720") audienceCount aspectRatio isOnAir channel { id xid name displayName accountType __typename } __typename } __typename } __typename } channels(query: $query, first: $limit, page: $page) @include(if: $shouldIncludeChannels) { metadata { algorithm { uuid __typename } __typename } pageInfo { hasNextPage nextPage __typename } totalCount edges { node { id ...CHANNEL_BASE_FRAG __typename } __typename } __typename } playlists: collections(query: $query, first: $limit, page: $page) @include(if: $shouldIncludePlaylists) { metadata { algorithm { uuid __typename } __typename } pageInfo { hasNextPage nextPage __typename } totalCount edges { node { id ...PLAYLIST_BASE_FRAG __typename } __typename } __typename } topics(query: $query, first: $limit, page: $page) @include(if: $shouldIncludeTopics) { metadata { algorithm { uuid __typename } __typename } pageInfo { hasNextPage nextPage __typename } totalCount edges { node { id ...TOPIC_BASE_FRAG __typename } __typename } __typename } __typename } }'
```

Code after:
        except ExtractorError as e:
            if isinstance(e.cause, HTTPError) and e.cause.status == 400:
                raise ExtractorError(self._parse_json(
                    e.cause.response.read().decode(), xid)['error_description'], expected=True)
            raise
        self._set_dailymotion_cookie('access_token' if username else 'client_token', token)
        return token

    def _call_api(self, object_type, xid, object_fields, note, filter_extra=None):
        if not self._HEADERS.get('Authorization'):
            self._HEADERS['Authorization'] = f'Bearer {self._get_token(xid)}'

        resp = self._download_json(
            'https://graphql.api.dailymotion.com/', xid, note, data=json.dumps({
                'query': '''{
  %s(xid: "%s"%s) {
    %s
  }
}''' % (object_type, xid, ', ' + filter_extra if filter_extra else '', object_fields),
            }).encode(), headers=self._HEADERS)
        obj = resp['data'][object_type]
        if not obj:
            raise ExtractorError(resp['errors'][0]['message'], expected=True)
        return obj


class DailymotionIE(DailymotionBaseInfoExtractor):
    _VALID_URL = r'''(?ix)
                    https?://
                        (?:
                            (?:(?:www|touch|geo)\.)?dailymotion\.[a-z]{2,3}/(?:(?:(?:(?:embed|swf|\#)/)|player(?:/\w+)?\.html\?)?video|swf)|
                            (?:www\.)?lequipe\.fr/video
                        )
                        [/=](?P<id>[^/?_&]+)(?:.+?\bplaylist=(?P<playlist_id>x[0-9a-z]+))?
                    '''
    IE_NAME = 'dailymotion'
    _EMBED_REGEX = [r'<(?:(?:embed|iframe)[^>]+?src=|input[^>]+id=[\'"]dmcloudUrlEmissionSelect[\'"][^>]+value=)(["\'])(?P<url>(?:https?:)?//(?:www\.)?dailymotion\.com/(?:embed|swf)/video/.+?)\1']
    _TESTS = [{
        'url': 'http://www.dailymotion.com/video/x5kesuj_office-christmas-party-review-jason-bateman-olivia-munn-t-j-miller_news',
        'md5': '074b95bdee76b9e3654137aee9c79dfe',
        'info_dict': {
            'id': 'x5kesuj',
            'ext': 'mp4',
            'title': 'Office Christmas Party Review –  Jason Bateman, Olivia Munn, T.J. Miller',
            'description': 'Office Christmas Party Review - Jason Bateman, Olivia Munn, T.J. Miller',
            'duration': 187,
            'timestamp': 1493651285,
            'upload_date': '20170501',
            'uploader': 'Deadline',
            'uploader_id': 'x1xm8ri',
            'age_limit': 0,