async fetchOembedDataFromUrl(url, type, options = {}) {
        try {
            const urlObject = new URL(url);

            // YouTube has started not returning oembed <link>tags for some live URLs
            // when fetched from an IP address that's in a non-EN region.
            // We convert live URLs to watch URLs so we can go straight to the
            // oembed request via a known provider rather than going through the page fetch routine.
            const ytLiveRegex = /^\/live\/([a-zA-Z0-9_-]+)$/;
            if (urlObject.hostname.match(/(?:www\.)?youtube\.com/) && ytLiveRegex.test(urlObject.pathname)) {
                const videoId = ytLiveRegex.exec(urlObject.pathname)[1];
                urlObject.pathname = '/watch';
                urlObject.searchParams.set('v', videoId);
                url = urlObject.toString();
            }

            // Trimming solves the difference of url validation between `new URL(url)`
            // and metascraper.
            url = url.trim();

            for (const provider of this.customProviders) {
                if (await provider.canSupportRequest(urlObject)) {
                    const result = await provider.getOEmbedData(urlObject, this.externalRequest);
                    if (result !== null) {
                        return result;
                    }
                }
            }

            if (type !== 'bookmark' && type !== 'mention') {
                // if not a bookmark request, first
                // check against known oembed list
                const {url: providerUrl, provider} = findUrlWithProvider(url);
                if (provider) {
                    return this.knownProvider(providerUrl);
                }
            }

            // Not in the list, we need to fetch the content
            const {url: pageUrl, body, contentType} = await this.fetchPageHtml(url, options);

            // fetch only bookmark when explicitly requested
            if (type === 'bookmark') {
                return this.fetchBookmarkData(url, body, type);
            }

            // mentions need to return bookmark data (metadata) and body (html) for link verification
            if (type === 'mention') {
                if (contentType.includes('application/json')) {
                    // No need to fetch metadata: we have none
                    const bookmark = {
                        version: '1.0',
                        type: 'bookmark',
                        url,
                        metadata: {
                            title: null,
                            description: null,
                            publisher: null,
                            author: null,
                            thumbnail: null,
                            icon: null
                        },
                        contentType
                    };
                    return {...bookmark, body};
                }
                const bookmark = await this.fetchBookmarkData(url, body, type);
                return {...bookmark, body, contentType};
            }

            // attempt to fetch oembed

            // In case response was a redirect, see if we were
            // redirected to a known oembed
            if (pageUrl !== url) {
                const {url: providerUrl, provider} = findUrlWithProvider(pageUrl);
                if (provider) {
                    return this.knownProvider(providerUrl);
                }
            }

            let data = await this.fetchOembedData(url, body);

            // fallback to bookmark when we can't get oembed
            if (!data && !type) {
                data = await this.fetchBookmarkData(url, body, type);
            }

            // couldn't get anything, throw a validation error
            if (!data) {
                return this.unknownProvider(url);
            }

            return data;
        } catch (err) {
            // allow specific validation errors through for better error messages
            if (errors.utils.isGhostError(err) && err.errorType === 'ValidationError') {
                throw err;
            }

            // log the real error because we're going to throw a generic "Unknown provider" error
            logging.error(new errors.InternalServerError({
                message: 'Encountered error when fetching oembed',
                err
            }));

            // default to unknown provider to avoid leaking any app specifics
            return this.unknownProvider(url);
        }
    }
@param {string} url - oembed URL
@param {string} type - card type
@param {Object} [options] Specific fetch options
@param {number} [options.timeout] Change the default timeout for fetching html

@returns {Promise<Object>}