def enqueue_audio_search(self, arg):
        """Search YouTube and add the audio streams to the
        playback queue.

        :param arg: a search string

        """
        logging.info("arg : %s", arg)
        try:
            print_msg("[YouTube] [Audio search] : '{0}'. ".format(arg))
            query = generate_search_query(arg)
            wdata = pafy.call_gdata("search", query)

            wdata2 = wdata
            count = 0
            while True:
                for track_info in get_tracks_from_json(wdata2):
                    self._add_to_playback_queue(info=track_info)
                    count += 1

                if count > 100:
                    break
                if not wdata2.get("nextPageToken"):
                    break
                query["pageToken"] = wdata2["nextPageToken"]
                wdata2 = pafy.call_gdata("search", query)

            self._update_play_queue_order()

        except ValueError:
            raise ValueError(str("Could not find any mixes : %s" % arg))
    def enqueue_audio_search(self, arg):
        """Search YouTube and add the audio streams to the
        playback queue.

        :param arg: a search string

        """
        logging.info('arg : %s', arg)
        try:
            query = generate_search_query(arg)
            wdata = pafy.call_gdata('search', query)

            wdata2 = wdata
            count = 0
            while True:
                for track_info in get_tracks_from_json(wdata2):
                    self.add_to_playback_queue(info=track_info)
                    count += 1

                if count > 100:
                    break
                if not wdata2.get('nextPageToken'):
                    break
                query['pageToken'] = wdata2['nextPageToken']
                wdata2 = pafy.call_gdata('search', query)

            self.__update_play_queue_order()

        except ValueError:
            raise ValueError(str("Could not find any mixes : %s" % arg))
Esempio n. 3
0
def ytSearch(query, max=10):
    q = {'q': query, 'part': 'id', 'maxResults': max, 'type': 'video,playlist'}
    results = pafy.call_gdata('search', q)['items']
    videosIds = [
        i['id']['videoId'] for i in results
        if i['id']['kind'] == 'youtube#video'
    ]
    playlistsIds = [
        i['id']['playlistId'] for i in results
        if i['id']['kind'] == 'youtube#playlist'
    ]
    #    print(results[0])
    ids = ','.join(videosIds)
    videos = pafy.call_gdata('videos', {
        'id': ids,
        'part': 'id,snippet,contentDetails'
    })['items']
    ids = ','.join(playlistsIds)
    playlists = pafy.call_gdata('playlists', {
        'id': ids,
        'part': 'id,snippet,contentDetails'
    })['items']
    #print(playlists)
    browsed = [
        videos.pop(0)
        if i['id']['kind'] == 'youtube#video' else playlists.pop(0)
        for i in results
    ]
    return [ProxyItem(i) for i in browsed]
    def enqueue_audio_search(self, arg):
        """Search YouTube and add the audio streams to the
        playback queue.

        :param arg: a search string

        """
        logging.info('arg : %s', arg)
        try:
            query = generate_search_query(arg)
            wdata = pafy.call_gdata('search', query)

            wdata2 = wdata
            count = 0
            while True:
                for track_info in get_tracks_from_json(wdata2):
                    self.add_to_playback_queue(info=track_info)
                    count += 1

                if count > 100:
                    break
                if not wdata2.get('nextPageToken'):
                    break
                query['pageToken'] = wdata2['nextPageToken']
                wdata2 = pafy.call_gdata('search', query)

            self.__update_play_queue_order()

        except ValueError:
            raise ValueError(str("Could not find any mixes : %s" % arg))
Esempio n. 5
0
    def api(self, bestmatch=True):
        """ Use YouTube API to search and return a list of matching videos. """
        try:
            query = {'part': 'snippet', 'maxResults': 50, 'type': 'video'}

            if const.config.music_videos_only:
                query['videoCategoryId'] = '10'

            if not self.meta_tags:
                song = self.raw_song
                query['q'] = song
            else:
                query['q'] = self.search_query
            log.debug('query: {0}'.format(query))

            data = pafy.call_gdata('search', query)
            data['items'] = list(
                filter(lambda x: x['id'].get('videoId') is not None,
                       data['items']))
            query_results = {
                'part': 'contentDetails,snippet,statistics',
                'maxResults': 50,
                'id': ','.join(i['id']['videoId'] for i in data['items'])
            }
            log.debug('query_results: {0}'.format(query_results))

            vdata = pafy.call_gdata('videos', query_results)

            videos = []
            for x in vdata['items']:
                duration_s = pafy.playlist.parseISO8591(
                    x['contentDetails']['duration'])
                youtubedetails = {
                    'link': x['id'],
                    'title': x['snippet']['title'],
                    'videotime': internals.videotime_from_seconds(duration_s),
                    'seconds': duration_s,
                    'views': x['statistics'].get('viewCount', 0)
                }
                videos.append(youtubedetails)

            if bestmatch:
                return self._best_match(videos)

            return videos
        except Exception as e:
            if ERROR_QUOTA_STR in str(e):
                if set_new_key():
                    return self.api(bestmatch)
                else:
                    log.warn("#############################################")
                    log.warn("No more YT keys. Wait until quota is restored")
                    log.warn("#############################################")

            raise e
    def enqueue_audio_mix_search(self, arg):
        """Obtain a YouTube mix associated to a given textual search and add all the
        audio streams in the mix playlist to the playback queue.

        :param arg: a search string

        """
        logging.info('arg : %s', arg)
        try:
            query = generate_search_query(arg)
            wdata = pafy.call_gdata('search', query)

            wdata2 = wdata
            count = len(self.queue)
            for track_info in get_tracks_from_json(wdata2):
                if track_info and track_info.ytid:
                    try:
                        self.enqueue_audio_mix(track_info.ytid, feelinglucky=False)
                        break
                    except ValueError:
                        logging.info('Could not find a mix. Trying another video')

            if count == len(self.queue):
                raise ValueError

        except ValueError:
            raise ValueError(str("Could not find any mixes : %s" % arg))
    def enqueue_audio_mix_search(self, arg):
        """Obtain a YouTube mix associated to a given textual search and add all the
        audio streams in the mix playlist to the playback queue.

        :param arg: a search string

        """
        logging.info('arg : %s', arg)
        try:
            query = generate_search_query(arg)
            wdata = pafy.call_gdata('search', query)

            wdata2 = wdata
            count = len(self.queue)
            for track_info in get_tracks_from_json(wdata2):
                if track_info and track_info.ytid:
                    try:
                        self.enqueue_audio_mix(track_info.ytid,
                                               feelinglucky=False)
                        break
                    except ValueError:
                        logging.info(
                            'Could not find a mix. Trying another video')

            if count == len(self.queue):
                raise ValueError

        except ValueError:
            raise ValueError(str("Could not find any mixes : %s" % arg))
Esempio n. 8
0
File: server.py Progetto: karrug/ytm
async def time(websocket, path):
    async for message in websocket:
        message = json.loads(message)
        qs = {'q': message['q'], 'maxResults': 10, 'part': 'id,snippet'}
        gdata = pafy.call_gdata('search', qs)
        with youtube_dl.YoutubeDL({'format': 'bestaudio/best'}) as ydl:
            for item in gdata['items']:
                try:
                    result = {
                        'extracted': False,
                        'id': item['id']['videoId'],
                        'title': item['snippet']['title']
                    }
                    await websocket.send(json.dumps(result))
                except KeyError:
                    pass
            for item in gdata['items']:
                try:
                    url = "https://www.youtube.com/watch?v=" + item['id'][
                        'videoId']
                    info_dict = ydl.extract_info(url, download=False)
                    result = {
                        'extracted': True,
                        'id': item['id']['videoId'],
                        'url': info_dict.get('url', '#'),
                        'title': item['snippet']['title']
                    }
                    await websocket.send(json.dumps(result))
                except KeyError:
                    pass
Esempio n. 9
0
def _search(progtext, qs=None, msg=None, failmsg=None):
    """ Perform memoized url fetch, display progtext. """

    loadmsg = "Searching for '%s%s%s'" % (c.y, progtext, c.w)

    wdata = pafy.call_gdata('search', qs)

    def iter_songs():
        wdata2 = wdata
        while True:
            for song in get_tracks_from_json(wdata2):
                yield song

            if not wdata2.get('nextPageToken'):
                break
            qs['pageToken'] = wdata2['nextPageToken']
            wdata2 = pafy.call_gdata('search', qs)

    # The youtube search api returns a maximum of 500 results
    length = min(wdata['pageInfo']['totalResults'], 500)
    slicer = util.IterSlicer(iter_songs(), length)

    paginatesongs(slicer,
                  length=length,
                  msg=msg,
                  failmsg=failmsg,
                  loadmsg=loadmsg)
Esempio n. 10
0
def channelfromname(user):
    """ Query channel id from username. """

    cached = userdata_cached(user)
    if cached:
        user, channel_id = cached
    else:
        # if the user is looked for by their display name,
        # we have to sent an additional request to find their
        # channel id
        qs = {'part': 'id,snippet',
              'forUsername': user,
              'key': config.API_KEY.get}

        try:
            userinfo = pafy.call_gdata('channels', qs)['items']
            if len(userinfo) > 0:
                snippet = userinfo[0].get('snippet', {})
                channel_id = userinfo[0].get('id', user)
                username = snippet.get('title', user)
                user = cache_userdata(user, username, channel_id)[0]
            else:
                g.message = "User {} not found.".format(c.y + user + c.w)
                return

        except pafy.GdataError as e:
            g.message = "Could not retrieve information for user {}\n{}".format(
                c.y + user + c.w, e)
            util.dbg('Error during channel request for user {}:\n{}'.format(
                user, e))
            return

    # at this point, we know the channel id associated to a user name
    return (user, channel_id)
    def api(self, bestmatch=True):
        """ Use YouTube API to search and return a list of matching videos. """

        query = {"part": "snippet", "maxResults": 50, "type": "video"}

        if const.args.music_videos_only:
            query["videoCategoryId"] = "10"

        if not self.meta_tags:
            song = self.raw_song
            query["q"] = song
        else:
            query["q"] = self.search_query
        log.debug("query: {0}".format(query))

        data = pafy.call_gdata("search", query)
        data["items"] = list(
            filter(lambda x: x["id"].get("videoId") is not None,
                   data["items"]))
        query_results = {
            "part": "contentDetails,snippet,statistics",
            "maxResults": 50,
            "id": ",".join(i["id"]["videoId"] for i in data["items"]),
        }
        log.debug("query_results: {0}".format(query_results))

        vdata = pafy.call_gdata("videos", query_results)

        videos = []
        for x in vdata["items"]:
            duration_s = pafy.playlist.parseISO8591(
                x["contentDetails"]["duration"])
            youtubedetails = {
                "link": x["id"],
                "title": x["snippet"]["title"],
                "videotime": internals.videotime_from_seconds(duration_s),
                "seconds": duration_s,
            }
            if self.meta_tags["name"] in x["snippet"]["title"]:
                videos.append(youtubedetails)

        log.error("I'm hot")
        if bestmatch:
            return self._best_match(videos)

        return videos
Esempio n. 12
0
def _fetch_commentreplies(parentid):
    return pafy.call_gdata(
        'comments', {
            'parentId': parentid,
            'part': 'snippet',
            'textFormat': 'plainText',
            'maxResults': 50
        }).get('items', [])
Esempio n. 13
0
    def api(self):
        """ Use YouTube API to search and return a list of matching videos. """

        query = {'part': 'snippet', 'maxResults': 50, 'type': 'video'}

        if const.args.music_videos_only:
            query['videoCategoryId'] = '10'

        if not self.meta_tags:
            song = self.raw_song
            query['q'] = song
        else:
            song = '{0} - {1}'.format(self.meta_tags['artists'][0]['name'],
                                      self.meta_tags['name'])
            query['q'] = song
        log.debug('query: {0}'.format(query))

        data = pafy.call_gdata('search', query)
        data['items'] = list(
            filter(lambda x: x['id'].get('videoId') is not None,
                   data['items']))
        query_results = {
            'part': 'contentDetails,snippet,statistics',
            'maxResults': 50,
            'id': ','.join(i['id']['videoId'] for i in data['items'])
        }
        log.debug('query_results: {0}'.format(query_results))

        vdata = pafy.call_gdata('videos', query_results)

        videos = []
        for x in vdata['items']:
            duration_s = pafy.playlist.parseISO8591(
                x['contentDetails']['duration'])
            youtubedetails = {
                'link': x['id'],
                'title': x['snippet']['title'],
                'videotime': internals.videotime_from_seconds(duration_s),
                'seconds': duration_s
            }
            videos.append(youtubedetails)
            if not self.meta_tags:
                break

        return self._best_match(videos)
Esempio n. 14
0
    def perform_search(self, query, *args, **kwargs):
        """
        Search songs on youtube.
        """
        qs = generate_search_query(query, api_key=self.config.get('api_key'))

        yresult = pafy.call_gdata('search', qs)

        return get_songs_from_result(yresult)
Esempio n. 15
0
def video_results(video_ids):
    query = {
        'id': ','.join(video_ids),
        'part': 'snippet,statistics,contentDetails',
        'key': conf.api_key,
    }

    videos = pafy.call_gdata('videos', query)
    return videos
Esempio n. 16
0
def find_best_match(query):
    """Find the best(first)"""
    # This assumes that the first match is the best one
    qs = search.generate_search_qs(query)
    wdata = pafy.call_gdata("search", qs)
    results = search.get_tracks_from_json(wdata)
    if results:
        res, score = album_search._best_song_match(results, query, 0.1, 1.0, 0.0)
        return res
Esempio n. 17
0
def find_best_match(query):
    """Find the best(first)"""
    # This assumes that the first match is the best one
    qs = search.generate_search_qs(query)
    wdata = pafy.call_gdata('search', qs)
    results = search.get_tracks_from_json(wdata)
    if results:
        res, score = album_search._best_song_match(
            results, query, 0.1, 1.0, 0.0)
        return res
Esempio n. 18
0
    def iter_songs():
        wdata2 = wdata
        while True:
            for song in get_tracks_from_json(wdata2):
                yield song

            if not wdata2.get('nextPageToken'):
                break
            qs['pageToken'] = wdata2['nextPageToken']
            wdata2 = pafy.call_gdata('search', qs)
Esempio n. 19
0
def _fetch_commentreplies(parentid):
    return pafy.call_gdata(
        "comments",
        {
            "parentId": parentid,
            "part": "snippet",
            "textFormat": "plainText",
            "maxResults": 50,
        },
    ).get("items", [])
Esempio n. 20
0
    def iter_songs():
        wdata2 = wdata
        while True:
            for song in get_tracks_from_json(wdata2):
                yield song

            if not wdata2.get('nextPageToken'):
                break
            qs['pageToken'] = wdata2['nextPageToken']
            wdata2 = pafy.call_gdata('search', qs)
Esempio n. 21
0
def get_item_info(ytid):
    """
    Fetchs data from single item from youtube
    """
    qs = {'part': 'contentDetails,statistics,snippet',
          'id': ','.join([ytid])}

    wdata = pafy.call_gdata('videos', qs)
    items_vidinfo = wdata.get('items', [])

    return items_vidinfo[0] if items_vidinfo else {}
Esempio n. 22
0
def description_generator(text):
    """ Fetches a videos description and parses it for
        <artist> - <track> combinations
    """
    if not isinstance(g.model, Playlist):
        g.message = util.F("mkp desc unknown")
        return

    # Use only the first result, for now
    num = text.replace("--description", "")
    num = num.replace("-d", "")
    num = util.number_string_to_list(num)[0]

    query = {}
    query['id'] = g.model[num].ytid
    query['part'] = 'snippet'
    query['maxResults'] = '1'
    data = pafy.call_gdata('videos', query)['items'][0]['snippet']
    title = "mkp %s" % data['title']
    data = util.fetch_songs(data['description'], data['title'])

    columns = [
        {
            "name": "idx",
            "size": 3,
            "heading": "Num"
        },
        {
            "name": "artist",
            "size": 30,
            "heading": "Artist"
        },
        {
            "name": "title",
            "size": "remaining",
            "heading": "Title"
        },
    ]

    def run_m(idx):
        """ Create playlist based on the
            results selected
        """
        create_playlist(idx, title)

    if data:
        data = [listview.ListSongtitle(x) for x in data]
        g.content = listview.ListView(columns, data, run_m)
        g.message = util.F("mkp desc which data")
    else:
        g.message = util.F("mkp no valid")

    return
Esempio n. 23
0
 def _get_video_gdata(self, video_id):
     """ Return json string containing video metadata from gdata api. """
     if self.callback:
         self.callback("Fetching video gdata")
     query = {'part': 'id,snippet,statistics',
              'maxResults': 1,
              'id': video_id}
     gdata = call_gdata('videos', query)
     dbg("Fetched video gdata")
     if self.callback:
         self.callback("Fetched video gdata")
     return gdata
Esempio n. 24
0
File: utils.py Progetto: karrug/ytm
def get_results(q):
    results = []
    qs = {'q': q, 'maxResults': 12, 'part': 'id,snippet'}
    pafy.set_api_key(os.environ['PAFY_API_KEY'])
    gdata = pafy.call_gdata('search', qs)
    with youtube_dl.YoutubeDL({'format': 'bestaudio/best'}) as ydl:
        for item in gdata['items']:
            try:
                result = {'extracted': False, 'id': item['id']['videoId'], 'title': item['snippet']['title']}
                results.append(result)
            except KeyError:
                pass
    return results
Esempio n. 25
0
def fetch_comments(item):
    """ Fetch comments for item using gdata. """
    # pylint: disable=R0912
    # pylint: disable=R0914
    ytid, title = item.ytid, item.title
    util.dbg("Fetching comments for %s", c.c("y", ytid))
    screen.writestatus("Fetching comments for %s" % c.c("y", title[:55]))
    qs = {
        "textFormat": "plainText",
        "videoId": ytid,
        "maxResults": 50,
        "part": "snippet",
    }

    jsdata = None
    try:
        jsdata = pafy.call_gdata("commentThreads", qs)
    except pafy.util.GdataError as e:
        raise pafy.util.GdataError(
            str(e).replace(
                ' identified by the <code><a href="/youtube/v3/docs/commentThreads/list#videoId">videoId</a></code> parameter',
                "",
            ))
    coms = [x.get("snippet", {}) for x in jsdata.get("items", [])]

    # skip blanks
    coms = [
        x for x in coms if len(
            x.get("topLevelComment", {}).get("snippet", {}).get(
                "textDisplay", "").strip())
    ]

    if not len(coms):
        g.message = "No comments for %s" % item.title[:50]
        g.content = generate_songlist_display()
        return

    commentstext = ""

    for n, com in enumerate(coms, 1):
        snippet = com.get("topLevelComment", {}).get("snippet", {})
        commentstext += _format_comment(snippet, n, len(coms))
        if com.get("totalReplyCount") > 0:
            replies = _fetch_commentreplies(
                com.get("topLevelComment").get("id"))
            for n, com in enumerate(reversed(replies), 1):
                commentstext += _format_comment(com.get("snippet", {}), n,
                                                len(replies), True)

    g.current_page = 0
    g.content = content.StringContent(commentstext)
Esempio n. 26
0
    def get(self):
        results = []
        if 'qs' in request.args:
            term = request.args['qs']
            wdata = pafy.call_gdata('search', generate_search_qs(term))
            for item in wdata['items']:

                song = {
                    'title': item['snippet']['title'],
                    'video_id': get_track_id_from_json(item)
                }
                results.append(song)

        return jsonify({'results': results}), 200
Esempio n. 27
0
    def _perform_api_call(self):
        # Include nextPageToken if it is set
        qry = dict(pageToken=self.nextpagetoken,
                   **(self.queries)) if self.nextpagetoken else self.queries

        # Run query
        util.dbg("CQ.query", qry)
        data = pafy.call_gdata(self.api, qry)

        self.maxresults = int(data.get("pageInfo").get("totalResults"))
        self.nextpagetoken = data.get("nextPageToken")

        for obj in data.get("items"):
            self.pdata.append(self.datatype(obj))
Esempio n. 28
0
def search_results(term, content, results, category, duration, order):
    query = {
        'part': 'id',
        'safeSearch': 'none',
        'maxResults': results,
        'type': content,
        'key': conf.api_key,
        'videoCategoryId': category,
        'videoDuration': duration,
        'q': term,
        'order': order
    }

    search = pafy.call_gdata('search', query)
    return search
def get_tracks_from_json(jsons, howmany=0):
    """ Get search results from pafy's call_gdata response

        :param jsons: The result of calling pafy.call_gdata('search', query)
        :param howmany: The maximum number of tracks to retrieve (0 means, no limit)

    """

    items = jsons.get("items")
    if not items:
        logging.info("got unexpected data or no search results")
        return ()

    # fetch detailed information about items from videos API
    query_string = {
        'part': 'contentDetails,statistics,snippet',
        'id': ','.join([get_track_id_from_json(i) for i in items])
    }

    wdata = pafy.call_gdata('videos', query_string)

    items_vidinfo = wdata.get('items', [])
    # enhance search results by adding information from videos API response
    for searchresult, vidinfoitem in zip(items, items_vidinfo):
        searchresult.update(vidinfoitem)

    # populate list of video objects
    songs = []
    for item in items:

        try:

            ytid = get_track_id_from_json(item)
            snippet = item.get('snippet', {})
            title = snippet.get('title', '').strip()
            info = VideoInfo(ytid=ytid, title=title)

        except Exception as exception:

            logging.info('Error during metadata extraction/instantiation of ' +
                         'search result {}\n{}'.format(ytid, exception))

        songs.append(info)
        if howmany != 0 and len(songs) == howmany:
            break

    # return video objects
    return songs
Esempio n. 30
0
    def _perform_api_call(self):
        # Include nextPageToken if it is set
        qry = dict(
            pageToken=self.nextpagetoken,
            **(self.queries)
            ) if self.nextpagetoken else self.queries

        # Run query
        util.dbg("CQ.query", qry)
        data = pafy.call_gdata(self.api, qry)
        
        self.maxresults = int(data.get("pageInfo").get("totalResults"))
        self.nextpagetoken = data.get("nextPageToken")

        for obj in data.get("items"):
            self.pdata.append(self.datatype(obj))
def get_tracks_from_json(jsons, howmany=0):
    """ Get search results from pafy's call_gdata response

        :param jsons: The result of calling pafy.call_gdata('search', query)
        :param howmany: The maximum number of tracks to retrieve (0 means, no limit)

    """

    items = jsons.get("items")
    if not items:
        logging.info("got unexpected data or no search results")
        return ()

    # fetch detailed information about items from videos API
    query_string = {'part':'contentDetails,statistics,snippet',
                    'id': ','.join([get_track_id_from_json(i) for i in items])}

    wdata = pafy.call_gdata('videos', query_string)

    items_vidinfo = wdata.get('items', [])
    # enhance search results by adding information from videos API response
    for searchresult, vidinfoitem in zip(items, items_vidinfo):
        searchresult.update(vidinfoitem)

    # populate list of video objects
    songs = []
    for item in items:

        try:

            ytid = get_track_id_from_json(item)
            snippet = item.get('snippet', {})
            title = snippet.get('title', '').strip()
            info = VideoInfo(ytid=ytid, title=title)

        except Exception as exception:

            logging.info('Error during metadata extraction/instantiation of ' +
                         'search result {}\n{}'.format(ytid, exception))

        songs.append(info)
        if howmany != 0 and len(songs) == howmany:
            break

    # return video objects
    return songs
Esempio n. 32
0
def search(q, channel):
    search_query = {
        'q': q,
        'maxResults': min(50,
                          int(app.configuration["query"]["limit_results"])),
        'part': 'id,snippet',
        'type': 'video'
    }
    if channel:
        search_query['channelId'] = channel
    print(search_query)
    result = pafy.call_gdata('search', search_query)
    return [{
        'id': 'https://www.youtube.com/watch?v=%s' % item['id']['videoId'],
        'album': 'YouTube',
        'artist': item['snippet']['channelTitle'],
        'title': item['snippet']['title']
    } for item in result['items'] if item['id']['kind'] == "youtube#video"]
Esempio n. 33
0
def fetch_comments(item):
    """ Fetch comments for item using gdata. """
    # pylint: disable=R0912
    # pylint: disable=R0914
    ytid, title = item.ytid, item.title
    util.dbg("Fetching comments for %s", c.c("y", ytid))
    screen.writestatus("Fetching comments for %s" % c.c("y", title[:55]))
    qs = {
        'textFormat': 'plainText',
        'videoId': ytid,
        'maxResults': 50,
        'part': 'snippet'
    }

    jsdata = pafy.call_gdata('commentThreads', qs)

    coms = [x.get('snippet', {}) for x in jsdata.get('items', [])]

    # skip blanks
    coms = [
        x for x in coms if len(
            x.get('topLevelComment', {}).get('snippet', {}).get(
                'textDisplay', '').strip())
    ]

    if not len(coms):
        g.message = "No comments for %s" % item.title[:50]
        g.content = generate_songlist_display()
        return

    commentstext = ''

    for n, com in enumerate(coms, 1):
        snippet = com.get('topLevelComment', {}).get('snippet', {})
        commentstext += _format_comment(snippet, n, len(coms))
        if com.get('totalReplyCount') > 0:
            replies = _fetch_commentreplies(
                com.get('topLevelComment').get('id'))
            for n, com in enumerate(reversed(replies), 1):
                commentstext += _format_comment(com.get('snippet', {}), n,
                                                len(replies), True)

    g.current_page = 0
    g.content = content.StringContent(commentstext)
Esempio n. 34
0
def get_songs_from_result(yresult):
    """
    Return items from youtube search result
    """
    items = yresult.get("items")
    if not items:
        # TODO: logger
        print('Result withou items')
        return ()

    # fetch detailed information about items from videos API
    id_list = [get_track_id_from_json(i)
               for i in items
               if i['id']['kind'] == 'youtube#video']

    qs = {'part': 'contentDetails,statistics,snippet',
          'id': ','.join(id_list)}

    wdata = pafy.call_gdata('videos', qs)

    items_vidinfo = wdata.get('items', [])
    # enhance search results by adding information from videos API response
    for searchresult, vidinfoitem in zip(items, items_vidinfo):
        searchresult.update(vidinfoitem)

    # populate list of video objects
    songs = []
    for item in items:
        ytid = get_track_id_from_json(item)
        duration = item.get('contentDetails', {}).get('duration')
        duration = get_duration_from_duration(duration)

        snippet = item.get('snippet', {})
        title = snippet.get('title', '').strip()

        duration = format_int_duration(duration)

        current = Song(title=title, duration=duration, source=SOURCE_NAME, available=False, search_id=ytid)
        songs.append(current)

    return songs
Esempio n. 35
0
def description_generator(text):
    """ Fetches a videos description and parses it for
        <artist> - <track> combinations
    """
    if not isinstance(g.model, Playlist):
        g.message = util.F("mkp desc unknown")
        return

    # Use only the first result, for now
    num = text.replace("--description", "")
    num = num.replace("-d", "")
    num = util.number_string_to_list(num)[0]

    query = {}
    query['id'] = g.model[num].ytid
    query['part'] = 'snippet'
    query['maxResults'] = '1'
    data = pafy.call_gdata('videos', query)['items'][0]['snippet']
    title = "mkp %s" % data['title']
    data = util.fetch_songs(data['description'], data['title'])

    columns = [
        {"name": "idx", "size": 3, "heading": "Num"},
        {"name": "artist", "size": 30, "heading": "Artist"},
        {"name": "title", "size": "remaining", "heading": "Title"},
    ]

    def run_m(idx):
        """ Create playlist based on the
            results selected
        """
        create_playlist(idx, title)

    if data:
        data = [listview.ListSongtitle(x) for x in data]
        g.content = listview.ListView(columns, data, run_m)
        g.message = util.F("mkp desc which data")
    else:
        g.message = util.F("mkp no valid")

    return
Esempio n. 36
0
    def __init__(self, playlist_url, basic, gdata, size, callback):
        playlist_id = extract_playlist_id(playlist_url)

        if not playlist_id:
            err = "Unrecognized playlist url: %s"
            raise ValueError(err % playlist_url)

        query = {'part': 'snippet, contentDetails', 'id': playlist_id}
        allinfo = call_gdata('playlists', query)

        pl = allinfo['items'][0]

        self.plid = playlist_id
        self.title = pl['snippet']['title']
        self.author = pl['snippet']['channelTitle']
        self.description = pl['snippet']['description']
        self._len = pl['contentDetails']['itemCount']
        self._basic = basic
        self._gdata = gdata
        self._size = size
        self._callback = callback
Esempio n. 37
0
def _match_tracks(artist, title, mb_tracks):
    """ Match list of tracks in mb_tracks by performing multiple searches. """
    # pylint: disable=R0914
    util.dbg("artists is %s", artist)
    util.dbg("title is %s", title)
    title_artist_str = c.g + title + c.w, c.g + artist + c.w
    util.xprint("\nSearching for %s by %s\n\n" % title_artist_str)

    def dtime(x):
        """ Format time to M:S. """
        return time.strftime("%M:%S", time.gmtime(int(x)))

    # do matching
    for track in mb_tracks:
        ttitle = track["title"]
        length = track["length"]
        util.xprint("Search :  %s%s - %s%s - %s" %
                    (c.y, artist, ttitle, c.w, dtime(length)))
        q = "%s %s" % (artist, ttitle)
        w = q = ttitle if artist == "Various Artists" else q
        query = generate_search_qs(w, 0)
        util.dbg(query)

        # perform fetch
        wdata = pafy.call_gdata("search", query)
        results = get_tracks_from_json(wdata)

        if not results:
            util.xprint(c.r + "Nothing matched :(\n" + c.w)
            continue

        s, score = _best_song_match(results, artist + " " + ttitle, length,
                                    0.5, 0.5)
        cc = c.g if score > 85 else c.y
        cc = c.r if score < 75 else cc
        util.xprint(
            "Matched:  %s%s%s - %s \n[%sMatch confidence: "
            "%s%s]\n" %
            (c.y, s.title, c.w, util.fmt_time(s.length), cc, score, c.w))
        yield s
Esempio n. 38
0
    def _get_tracks_from_json(self, jsons):
        """ Get search results from API response """

        items = jsons.get("items")
        if not items:
            logging.info("got unexpected data or no search results")
            return ()

        # fetch detailed information about items from videos API
        qs = {'part':'contentDetails,statistics,snippet',
              'id': ','.join([self._get_track_id_from_json(i) for i in items])}

        wdata = pafy.call_gdata('videos', qs)

        items_vidinfo = wdata.get('items', [])
        # enhance search results by adding information from videos API response
        for searchresult, vidinfoitem in zip(items, items_vidinfo):
            searchresult.update(vidinfoitem)

        # populate list of video objects
        songs = []
        for item in items:

            try:

                ytid = self._get_track_id_from_json(item)
                snippet = item.get('snippet', {})
                title = snippet.get('title', '').strip()
                info = VideoInfo(ytid=ytid, title=title)

            except Exception as e:

                logging.info('Error during metadata extraction/instantiation of ' +
                    'search result {}\n{}'.format(ytid, e))

            songs.append(info)

        # return video objects
        return songs
Esempio n. 39
0
def _match_tracks(artist, title, mb_tracks):
    """ Match list of tracks in mb_tracks by performing multiple searches. """
    # pylint: disable=R0914
    util.dbg("artists is %s", artist)
    util.dbg("title is %s", title)
    title_artist_str = c.g + title + c.w, c.g + artist + c.w
    util.xprint("\nSearching for %s by %s\n\n" % title_artist_str)

    def dtime(x):
        """ Format time to M:S. """
        return time.strftime('%M:%S', time.gmtime(int(x)))

    # do matching
    for track in mb_tracks:
        ttitle = track['title']
        length = track['length']
        util.xprint("Search :  %s%s - %s%s - %s" % (c.y, artist, ttitle, c.w,
                                                    dtime(length)))
        q = "%s %s" % (artist, ttitle)
        w = q = ttitle if artist == "Various Artists" else q
        query = generate_search_qs(w, 0)
        util.dbg(query)

        # perform fetch
        wdata = pafy.call_gdata('search', query)
        results = get_tracks_from_json(wdata)

        if not results:
            util.xprint(c.r + "Nothing matched :(\n" + c.w)
            continue

        s, score = _best_song_match(
            results, artist + " " + ttitle, length, .5, .5)
        cc = c.g if score > 85 else c.y
        cc = c.r if score < 75 else cc
        util.xprint("Matched:  %s%s%s - %s \n[%sMatch confidence: "
                    "%s%s]\n" % (c.y, s.title, c.w, util.fmt_time(s.length),
                                 cc, score, c.w))
        yield s
def artist_from_title(title):
    """ Try to determine an artist by doing a search on the video
        and try to find the most common element by n number of times looking
        for the most common substring in a subset of the results from youtube
    """
    query = {}
    query['q'] = title
    query['type'] = 'video'
    query['fields'] = "items(snippet(title))"
    query['maxResults'] = 50
    query['part'] = "snippet"

    results = pafy.call_gdata('search', query)['items']
    titles = [x['snippet']['title'].upper() for x in results]

    alts = {}
    for _ in range(100):
        random.shuffle(titles)
        subset = titles[:10]
        string = long_substr(subset).strip()
        if len(string) > 3:
            alts[string] = alts.get(string, 0) + 1

    best_string = None
    if len(alts) == 1:
        best_string = list(alts.keys())[0].capitalize()
    else:
        best_guess = 99999
        best_string = None

        for key in list(alts.keys()):
            current_guess = title.upper().find(key)
            if current_guess < best_guess:
                best_guess = current_guess
                best_string = key.capitalize()

    best_string = re.sub(r"([^\w]+)$", "", best_string)
    best_string = re.sub(r"^([^\w]+)", "", best_string)
    return best_string
Esempio n. 41
0
def fetch_comments(item):
    """ Fetch comments for item using gdata. """
    # pylint: disable=R0912
    # pylint: disable=R0914
    ytid, title = item.ytid, item.title
    util.dbg("Fetching comments for %s", c.c("y", ytid))
    screen.writestatus("Fetching comments for %s" % c.c("y", title[:55]))
    qs = {'textFormat': 'plainText',
          'videoId': ytid,
          'maxResults': 50,
          'part': 'snippet'}

    # XXX should comment threads be expanded? this would require
    # additional requests for comments responding on top level comments

    jsdata = pafy.call_gdata('commentThreads', qs)

    coms = jsdata.get('items', [])
    coms = [x.get('snippet', {}) for x in coms]
    coms = [x.get('topLevelComment', {}) for x in coms]
    # skip blanks
    coms = [x for x in coms if len(x.get('snippet', {}).get('textDisplay', '').strip())]
    if not len(coms):
        g.message = "No comments for %s" % item.title[:50]
        g.content = generate_songlist_display()
        return

    commentstext = ''

    for n, com in enumerate(coms, 1):
        snippet = com.get('snippet', {})
        poster = snippet.get('authorDisplayName')
        _, shortdate = util.yt_datetime(snippet.get('publishedAt', ''))
        text = snippet.get('textDisplay', '')
        cid = ("%s/%s" % (n, len(coms)))
        commentstext += ("%s %-35s %s\n" % (cid, c.c("g", poster), shortdate))
        commentstext += c.c("y", text.strip()) + '\n\n'

    g.content = content.StringContent(commentstext)
Esempio n. 42
0
def fetch_comments(item):
    """ Fetch comments for item using gdata. """
    # pylint: disable=R0912
    # pylint: disable=R0914
    ytid, title = item.ytid, item.title
    util.dbg("Fetching comments for %s", c.c("y", ytid))
    screen.writestatus("Fetching comments for %s" % c.c("y", title[:55]))
    qs = {'textFormat': 'plainText',
          'videoId': ytid,
          'maxResults': 50,
          'part': 'snippet'}

    jsdata = pafy.call_gdata('commentThreads', qs)

    coms = [x.get('snippet', {}) for x in jsdata.get('items', [])]

    # skip blanks
    coms = [x for x in coms
            if len(x.get('topLevelComment', {}).get('snippet', {}).get('textDisplay', '').strip())]

    if not len(coms):
        g.message = "No comments for %s" % item.title[:50]
        g.content = generate_songlist_display()
        return

    commentstext = ''

    for n, com in enumerate(coms, 1):
        snippet = com.get('topLevelComment', {}).get('snippet', {})
        commentstext += _format_comment(snippet, n, len(coms))
        if com.get('totalReplyCount') > 0:
            replies = _fetch_commentreplies(com.get('topLevelComment').get('id'))
            for n, com in enumerate(reversed(replies), 1):
                commentstext += _format_comment(com.get('snippet', {}),
                                                n, len(replies), True)

    g.current_page = 0
    g.content = content.StringContent(commentstext)
Esempio n. 43
0
def _search(progtext, qs=None, msg=None, failmsg=None):
    """ Perform memoized url fetch, display progtext. """

    loadmsg = "Searching for '%s%s%s'" % (c.y, progtext, c.w)

    wdata = pafy.call_gdata('search', qs)

    def iter_songs():
        wdata2 = wdata
        while True:
            for song in get_tracks_from_json(wdata2):
                yield song

            if not wdata2.get('nextPageToken'):
                break
            qs['pageToken'] = wdata2['nextPageToken']
            wdata2 = pafy.call_gdata('search', qs)

    # The youtube search api returns a maximum of 500 results
    length = min(wdata['pageInfo']['totalResults'], 500)
    slicer = util.IterSlicer(iter_songs(), length)

    paginatesongs(slicer, length=length, msg=msg, failmsg=failmsg,
            loadmsg=loadmsg)
Esempio n. 44
0
def pl_search(term, page=0, splash=True, is_user=False):
    """ Search for YouTube playlists.

    term can be query str or dict indicating user playlist search.

    """
    if not term or len(term) < 2:
        g.message = c.r + "Not enough input" + c.w
        g.content = content.generate_songlist_display()
        return

    if splash:
        g.content = content.logo(c.g)
        prog = "user: "******"Searching playlists for %s" % c.y + prog + c.w
        screen.update()

    if is_user:
        ret = channelfromname(term)
        if not ret: # Error
            return
        user, channel_id = ret

    else:
        # playlist search is done with the above url and param type=playlist
        logging.info("playlist search for %s", prog)
        qs = generate_search_qs(term)
        qs['pageToken'] = token(page)
        qs['type'] = 'playlist'
        if 'videoCategoryId' in qs:
            del qs['videoCategoryId'] # Incompatable with type=playlist

        pldata = pafy.call_gdata('search', qs)

        id_list = [i.get('id', {}).get('playlistId')
                    for i in pldata.get('items', ())
                    if i['id']['kind'] == 'youtube#playlist']

        result_count = min(pldata['pageInfo']['totalResults'], 500)

    qs = {'part': 'contentDetails,snippet',
          'maxResults': 50}

    if is_user:
        if page:
            qs['pageToken'] = token(page)
        qs['channelId'] = channel_id
    else:
        qs['id'] = ','.join(id_list)

    pldata = pafy.call_gdata('playlists', qs)
    playlists = get_pl_from_json(pldata)[:util.getxy().max_results]

    if is_user:
        result_count = pldata['pageInfo']['totalResults']

    if playlists:
        g.last_search_query = (pl_search, {"term": term, "is_user": is_user})
        g.browse_mode = "ytpl"
        g.current_page = page
        g.result_count = result_count
        g.ytpls = playlists
        g.message = "Playlist results for %s" % c.y + prog + c.w
        g.content = content.generate_playlist_display()

    else:
        g.message = "No playlists found for: %s" % c.y + prog + c.w
        g.current_page = 0
        g.content = content.generate_songlist_display(zeromsg=g.message)
Esempio n. 45
0
def get_tracks_from_json(jsons):
    """ Get search results from API response """

    items = jsons.get("items")
    if not items:
        util.dbg("got unexpected data or no search results")
        return ()

    # fetch detailed information about items from videos API
    id_list = [get_track_id_from_json(i)
                for i in items
                if i['id']['kind'] == 'youtube#video']

    qs = {'part':'contentDetails,statistics,snippet',
          'id': ','.join(id_list)}

    wdata = pafy.call_gdata('videos', qs)

    items_vidinfo = wdata.get('items', [])
    # enhance search results by adding information from videos API response
    for searchresult, vidinfoitem in zip(items, items_vidinfo):
        searchresult.update(vidinfoitem)

    # populate list of video objects
    songs = []
    for item in items:

        try:

            ytid = get_track_id_from_json(item)
            duration = item.get('contentDetails', {}).get('duration')

            if duration:
                duration = ISO8601_TIMEDUR_EX.findall(duration)
                if len(duration) > 0:
                    _, hours, _, minutes, _, seconds = duration[0]
                    duration = [seconds, minutes, hours]
                    duration = [int(v) if len(v) > 0 else 0 for v in duration]
                    duration = sum([60**p*v for p, v in enumerate(duration)])
                else:
                    duration = 30
            else:
                duration = 30

            stats = item.get('statistics', {})
            snippet = item.get('snippet', {})
            title = snippet.get('title', '').strip()
            # instantiate video representation in local model
            cursong = Video(ytid=ytid, title=title, length=duration)
            likes = int(stats.get('likeCount', 0))
            dislikes = int(stats.get('dislikeCount', 0))
            #XXX this is a very poor attempt to calculate a rating value
            rating = 5.*likes/(likes+dislikes) if (likes+dislikes) > 0 else 0
            category = snippet.get('categoryId')
            publishedlocaldatetime = util.yt_datetime_local(snippet.get('publishedAt', ''))

            # cache video information in custom global variable store
            g.meta[ytid] = dict(
                # tries to get localized title first, fallback to normal title
                title=snippet.get('localized',
                                  {'title':snippet.get('title',
                                                       '[!!!]')}).get('title',
                                                                      '[!]'),
                length=str(util.fmt_time(cursong.length)),
                rating=str('{}'.format(rating))[:4].ljust(4, "0"),
                uploader=snippet.get('channelId'),
                uploaderName=snippet.get('channelTitle'),
                category=category,
                aspect="custom", #XXX
                uploaded=publishedlocaldatetime[1],
                uploadedTime=publishedlocaldatetime[2],
                likes=str(num_repr(likes)),
                dislikes=str(num_repr(dislikes)),
                commentCount=str(num_repr(int(stats.get('commentCount', 0)))),
                viewCount=str(num_repr(int(stats.get('viewCount', 0)))))

        except Exception as e:

            util.dbg(json.dumps(item, indent=2))
            util.dbg('Error during metadata extraction/instantiation of ' +
                'search result {}\n{}'.format(ytid, e))

        songs.append(cursong)

    # return video objects
    return songs
Esempio n. 46
0
def _fetch_commentreplies(parentid):
    return pafy.call_gdata('comments', {
        'parentId': parentid,
        'part': 'snippet',
        'textFormat': 'plainText',
        'maxResults': 50}).get('items', [])