Пример #1
0
    def on_start(self):

        proxy = httpclient.format_proxy(self.config["proxy"])
        youtube.Video.proxy = proxy
        headers = {
            "user-agent": httpclient.format_user_agent(self.user_agent),
            "Cookie": "PREF=hl=en;",
            "Accept-Language": "en;q=0.8",
        }

        if youtube.api_enabled is True:
            if youtube_api.youtube_api_key is None:
                logger.error("No YouTube API key provided, disabling API")
                youtube.api_enabled = False
            else:
                youtube.Entry.api = youtube_api.API(proxy, headers)
                if youtube.Entry.search(q="test") is None:
                    logger.error(
                        "Failed to verify YouTube API key, disabling API"
                    )
                    youtube.api_enabled = False
                else:
                    logger.info("YouTube API key verified")

        if youtube.api_enabled is False:
            # regex based api
            # logger.info("Using scrAPI")
            # youtube.Entry.api = youtube_scrapi.scrAPI(proxy, headers)

            # # beautiful soup 4 based api
            logger.info("using bs4API")
            youtube.Entry.api = youtube_bs4api.bs4API(proxy, headers)
Пример #2
0
    def search(cls, q):
        """
        Search for both videos and playlists using a single API call. Fetches
        only title, thumbnails, channel (extra queries are needed for length and
        video_count)
        """
        def create_object(item):
            set_api_data = ["title", "channel"]
            if item["id"]["kind"] == "youtube#video":
                obj = Video.get(item["id"]["videoId"])
                if "contentDetails" in item:
                    set_api_data.append("length")
            elif item["id"]["kind"] == "youtube#playlist":
                obj = Playlist.get(item["id"]["playlistId"])
                if "contentDetails" in item:
                    set_api_data.append("video_count")
            else:
                obj = []
                return obj
            if "thumbnails" in item["snippet"]:
                set_api_data.append("thumbnails")
            obj._set_api_data(set_api_data, item)
            return obj

        try:
            data = cls.api.search(q)
        except Exception as e:
            logger.error('search error "%s"', e)
            return None
        try:
            return list(map(create_object, data["items"]))
        except Exception as e:
            logger.error('map error "%s"', e)
            return None
Пример #3
0
    def search(cls, q):
        def create_object(item):
            set_api_data = ['title', 'channel']
            if item['id']['kind'] == 'youtube#video':
                obj = Video.get(item['id']['videoId'])
                if 'contentDetails' in item:
                    set_api_data.append('length')
            elif item['id']['kind'] == 'youtube#playlist':
                obj = Playlist.get(item['id']['playlistId'])
                if 'contentDetails' in item:
                    set_api_data.append('video_count')
            # elif item['id']['kind'] == 'youtube#radiolist':
            #     obj = Video.get(item['id']['videoId'])
            #     set_api_data = ['title', 'video_count']
            else:
                obj = []
                return obj
            if 'thumbnails' in item:
                set_api_data.append('thumbnails')
            obj._set_api_data(set_api_data, item)
            return obj

        try:
            data = cls.api.search(q)
        except Exception as e:
            logger.error('search error "%s"', e)
            return None
        try:
            return map(create_object, data['items'])
        except Exception as e:
            logger.error('map error "%s"', e)
            return None
Пример #4
0
    def on_start(self):

        proxy = httpclient.format_proxy(self.config['proxy'])
        youtube.Video.proxy = proxy
        headers = {
            'user-agent': httpclient.format_user_agent(self.user_agent),
            'Cookie': 'PREF=hl=en;',
            'Accept-Language': 'en;q=0.8'
        }

        if youtube.api_enabled is True:
            if youtube.API.youtube_api_key is None:
                logger.error('No YouTube API key provided, disabling API')
                youtube.api_enabled = False
            else:
                youtube.Entry.api = youtube.API(proxy, headers)
                if youtube.Entry.search(q='test') is None:
                    logger.error(
                        'Failed to verify YouTube API key, disabling API')
                    youtube.api_enabled = False
                else:
                    logger.info('YouTube API key verified')

        if youtube.api_enabled is False:
            logger.info('Using scrAPI')
            youtube.Entry.api = youtube.scrAPI(proxy, headers)
Пример #5
0
        def job(sublist):
            try:
                data = cls.api.list_playlists([x.id for x in sublist])
                dict = {item["id"]: item for item in data["items"]}
            except Exception as e:
                logger.error('list_playlists error "%s"', e)
                dict = {}

            for pl in sublist:
                pl._set_api_data(fields, dict.get(pl.id))
Пример #6
0
        def job(sublist):
            try:
                data = cls.api.list_videos([x.id for x in sublist])
                dict = {item["id"]: item for item in data["items"]}
            except Exception as e:
                logger.error('list_videos error "%s"', e)
                dict = {}

            for video in sublist:
                video._set_api_data(fields, dict.get(video.id))
Пример #7
0
    def translate_uri(self, uri):
        logger.info('youtube PlaybackProvider.translate_uri "%s"', uri)

        if "youtube:video/" not in uri:
            return None

        try:
            id = extract_id(uri)
            return youtube.Video.get(id).audio_url.get()
        except Exception as e:
            logger.error('translate_uri error "%s"', e)
            return None
Пример #8
0
    def search(self, query=None, uris=None, exact=False):
        # TODO Support exact search
        logger.info('youtube LibraryProvider.search "%s"', query)

        # handle only searching (queries with 'any') not browsing!
        if not (query and "any" in query):
            return None

        search_query = " ".join(query["any"])
        logger.info('Searching YouTube for query "%s"', search_query)

        try:
            entries = youtube.Entry.search(search_query)
        except Exception as e:
            logger.error('search error "%s"', e)
            return None

        # load playlist info (to get video_count) of all playlists together
        playlists = [entry for entry in entries if not entry.is_video]
        youtube.Playlist.load_info(playlists)

        tracks = []
        for entry in entries:
            if entry.is_video:
                uri_base = "youtube:video"
                album = "YouTube Video"
                length = int(entry.length.get()) * 1000
            else:
                uri_base = "youtube:playlist"
                album = "YouTube Playlist (%s videos)" % entry.video_count.get()
                length = 0

            name = entry.title.get()

            tracks.append(
                Track(
                    name=name.replace(";", ""),
                    comment=entry.id,
                    length=length,
                    artists=[Artist(name=entry.channel.get())],
                    album=Album(name=album),
                    uri="%s/%s.%s" % (uri_base, safe_url(name), entry.id),
                )
            )

        # load video info and playlist videos in the background. they should be
        # ready by the time the user adds search results to the playing queue

        for pl in playlists:
            pl.videos  # start loading

        return SearchResult(uri="youtube:search", tracks=tracks)
Пример #9
0
    def worker(cls):
        while True:
            cls.lock.acquire()
            if len(cls.jobs):
                f, args = cls.jobs.pop()
            else:
                # no more jobs, exit thread
                cls.threads_active -= 1
                cls.lock.release()
                break
            cls.lock.release()

            try:
                f(*args)
            except Exception as e:
                logger.error("youtube thread error: %s\n%s", e,
                             traceback.format_exc())
Пример #10
0
 def job():
     try:
         info = youtube_dl.YoutubeDL({
             'format': 'mp4/bestaudio/vorbis/m4a/best',
             'proxy': self.proxy,
             'nocheckcertificate': True
         }).extract_info(url="https://www.youtube.com/watch?v=%s" %
                         self.id,
                         download=False,
                         ie_key=None,
                         extra_info={},
                         process=True,
                         force_generic_extractor=False)
     except Exception as e:
         logger.error('audio_url error "%s"', e)
         self._audio_url.set(None)
         return
     self._audio_url.set(info['url'])
Пример #11
0
        def job():
            data = {"items": []}
            page = ""
            while (page is not None
                   and len(data["items"]) < self.playlist_max_videos):
                try:
                    max_results = min(
                        int(self.playlist_max_videos) - len(data["items"]), 50)
                    result = self.api.list_playlistitems(
                        self.id, page, max_results)
                except Exception as e:
                    logger.error('list playlist items error "%s"', e)
                    break
                if "error" in result:
                    logger.error(
                        "error in list playlist items data for",
                        "playlist {}, page {}".format(self.id, page),
                    )
                    break
                page = result.get("nextPageToken") or None
                data["items"].extend(result["items"])

            del data["items"][int(self.playlist_max_videos):]

            myvideos = []

            for item in data["items"]:
                set_api_data = ["title", "channel"]
                if "contentDetails" in item:
                    set_api_data.append("length")
                if "thumbnails" in item["snippet"]:
                    set_api_data.append("thumbnails")
                video = Video.get(item["snippet"]["resourceId"]["videoId"])
                video._set_api_data(set_api_data, item)
                myvideos.append(video)

            # start loading video info in the background
            Video.load_info([
                x for _, x in zip(range(self.playlist_max_videos), myvideos)
            ])  # noqa: E501

            self._videos.set([
                x for _, x in zip(range(self.playlist_max_videos), myvideos)
            ])  # noqa: E501
Пример #12
0
    def translate_uri(self, uri):
        """
        Called when a track us ready to play, we need to return the actual url of
        the audio. uri must be of the form youtube:video/<title>.<id>
        (only videos can be played, playlists are expended into tracks by
        YouTubeLibraryProvider.lookup)
        """

        logger.info('youtube PlaybackProvider.translate_uri "%s"', uri)

        if "youtube:video/" not in uri:
            return None

        try:
            id = extract_id(uri)
            return youtube.Video.get(id).audio_url.get()
        except Exception as e:
            logger.error('translate_uri error "%s"', e)
            return None
Пример #13
0
 def job():
     try:
         info = youtube_dl.YoutubeDL({
             "format": "bestaudio/best",
             "proxy": self.proxy,
             "nocheckcertificate": True,
         }).extract_info(
             url="https://www.youtube.com/watch?v=%s" % self.id,
             download=False,
             ie_key=None,
             extra_info={},
             process=True,
             force_generic_extractor=False,
         )
     except Exception as e:
         logger.error('audio_url error "%s"', e)
         self._audio_url.set(None)
         return
     self._audio_url.set(info["url"])
Пример #14
0
        def job():
            all_videos = []
            page = ''
            while page is not None \
                    and len(all_videos) < self.playlist_max_videos:
                try:
                    max_results = min(
                        self.playlist_max_videos - len(all_videos), 50)
                    data = self.api.list_playlistitems(self.id, page,
                                                       max_results)
                except Exception as e:
                    logger.error('list playlist items error "%s"', e)
                    break
                if 'error' in data:
                    logger.error('error in list playlist items data')
                    break
                page = data.get('nextPageToken') or None

                myvideos = []

                for item in data['items']:
                    set_api_data = ['title', 'channel']
                    if 'contentDetails' in item:
                        set_api_data.append('length')
                    if 'thumbnails' in item['snippet']:
                        set_api_data.append('thumbnails')
                    video = Video.get(item['snippet']['resourceId']['videoId'])
                    video._set_api_data(set_api_data, item)
                    myvideos.append(video)

                all_videos += myvideos

                # start loading video info for this batch in the background
                Video.load_info([
                    x
                    for _, x in zip(range(self.playlist_max_videos), myvideos)
                ])  # noqa: E501

            self._videos.set([
                x for _, x in zip(range(self.playlist_max_videos), all_videos)
            ])  # noqa: E501
Пример #15
0
    def lookup(self, uri):
        logger.info('youtube LibraryProvider.lookup "%s"', uri)

        video_id = playlist_id = None

        if "youtube.com" in uri:
            url = urlparse(uri.replace("yt:", "").replace("youtube:", ""))
            req = parse_qs(url.query)

            if "list" in req:
                playlist_id = req.get("list")[0]
            else:
                video_id = req.get("v")[0]
        elif "video/" in uri:
            video_id = extract_id(uri)
        else:
            playlist_id = extract_id(uri)

        if video_id:
            video = youtube.Video.get(video_id)
            video.audio_url  # start loading

            return [
                Track(
                    name=video.title.get().replace(";", ""),
                    comment=video.id,
                    length=video.length.get() * 1000,
                    artists=[Artist(name=video.channel.get())],
                    album=Album(name="YouTube Video",),
                    uri="youtube:video/%s.%s"
                    % (safe_url(video.title.get()), video.id),
                )
            ]
        else:
            playlist = youtube.Playlist.get(playlist_id)
            if not playlist.videos.get():
                logger.error('Cannot load "%s"', uri)
                return []

            # ignore videos for which no info was found (removed, etc)
            videos = [
                v for v in playlist.videos.get() if v.length.get() is not None
            ]

            # load audio_url in the background to be ready for playback
            for video in videos:
                video.audio_url  # start loading

            return [
                Track(
                    name=video.title.get().replace(";", ""),
                    comment=video.id,
                    length=video.length.get() * 1000,
                    track_no=count,
                    artists=[Artist(name=video.channel.get())],
                    album=Album(name=playlist.title.get(),),
                    uri="youtube:video/%s.%s"
                    % (safe_url(video.title.get()), video.id),
                )
                for count, video in enumerate(videos, 1)
            ]
Пример #16
0
    def lookup(self, uri):
        """
        Called when the user adds a track to the playing queue, either from the
        search results, or directly by adding a yt:http://youtube.com/.... uri.
        uri can be of the form
            [yt|youtube]:<url to youtube video>
            [yt|youtube]:<url to youtube playlist>
            youtube:video/<title>.<id>
            youtube:playlist/<title>.<id>

        If uri is a video then a single track is returned. If it's a playlist the
        list of all videos in the playlist is returned.

        We also start loading the audio_url of all videos in the background, to
        be ready for playback (see YouTubePlaybackProvider.translate_uri).
        """

        logger.info('youtube LibraryProvider.lookup "%s"', uri)

        video_id = playlist_id = None

        if "youtube.com" in uri:
            url = urlparse(uri.replace("yt:", "").replace("youtube:", ""))
            req = parse_qs(url.query)

            if "list" in req:
                playlist_id = req.get("list")[0]
            else:
                video_id = req.get("v")[0]
        elif "video/" in uri:
            video_id = extract_id(uri)
        else:
            playlist_id = extract_id(uri)

        if video_id:
            video = youtube.Video.get(video_id)
            video.audio_url  # start loading

            return [
                Track(
                    name=video.title.get().replace(";", ""),
                    comment=video.id,
                    length=video.length.get() * 1000,
                    artists=[Artist(name=video.channel.get())],
                    album=Album(name="YouTube Video", ),
                    uri="youtube:video/%s.%s" %
                    (safe_url(video.title.get()), video.id),
                )
            ]
        else:
            playlist = youtube.Playlist.get(playlist_id)
            if not playlist.videos.get():
                logger.error('Cannot load "%s"', uri)
                return []

            # ignore videos for which no info was found (removed, etc)
            videos = [
                v for v in playlist.videos.get() if v.length.get() is not None
            ]

            # load audio_url in the background to be ready for playback
            for video in videos:
                video.audio_url  # start loading

            return [
                Track(
                    name=video.title.get().replace(";", ""),
                    comment=video.id,
                    length=video.length.get() * 1000,
                    track_no=count,
                    artists=[Artist(name=video.channel.get())],
                    album=Album(name=playlist.title.get(), ),
                    uri="youtube:video/%s.%s" %
                    (safe_url(video.title.get()), video.id),
                ) for count, video in enumerate(videos, 1)
            ]