enjoy playlists without youtube_api

Esse commit está contido em:
Talha Asghar
2022-02-06 15:07:51 +05:00
commit 5490c240e4
11 arquivos alterados com 122 adições e 111 exclusões
+2 -1
Ver Arquivo
@@ -18,4 +18,5 @@ tags
.env
env/
.idea/
venv/
venv/
test.py
+1 -1
Ver Arquivo
@@ -1,3 +1,3 @@
# This file is used by clients to check for updates
version 1.1.1
version 1.1.2
+1 -1
Ver Arquivo
@@ -1,5 +1,5 @@
__version__ = "1.1.1"
__notes__ = "released on 28 Jan 2022"
__notes__ = "released on 06 Feb 2022"
__author__ = "iamtalhaasghar"
__license__ = "GPLv3"
__url__ = "https://github.com/iamtalhaasghar/yewtube"
+2 -2
Ver Arquivo
@@ -10,7 +10,7 @@ from xml.etree import ElementTree as ET
from .. import c, g, screen, __version__, __url__, content, config, util
from . import command
from .songlist import paginatesongs
from .search import generate_search_qs, get_tracks_from_json
from .search import get_tracks_from_json
def show_message(message, col=c.r, update=False):
@@ -120,7 +120,7 @@ def _match_tracks(artist, title, mb_tracks):
dtime(length)))
q = "%s %s" % (artist, ttitle)
w = q = ttitle if artist == "Various Artists" else q
query = generate_search_qs(w, 0)
query = w#generate_search_qs(w, 0)
util.dbg(query)
# perform fetch
+69 -86
Ver Arquivo
@@ -29,12 +29,12 @@ DAYS = dict(day = 1,
year = 365)
def _search(progtext, qs=None, msg=None, failmsg=None):
def _search(progtext, query, msg=None, failmsg=None):
""" Perform memoized url fetch, display progtext. """
loadmsg = "Searching for '%s%s%s'" % (c.y, progtext, c.w)
wdata = pafy.video_search(qs['q'])
wdata = pafy.video_search(query)
def iter_songs():
wdata2 = wdata
while True:
@@ -43,7 +43,7 @@ def _search(progtext, qs=None, msg=None, failmsg=None):
if type(wdata2) is list or not wdata2.get('nextPageToken'):
break
qs['pageToken'] = None#wdata2['nextPageToken']
query = None#wdata2['nextPageToken']
wdata2 = None#pafy.call_gdata('search', qs)
# The youtube search api returns a maximum of 500 results
@@ -67,40 +67,40 @@ def token(page):
return b64.strip('=')
def generate_search_qs(term, match='term', videoDuration='any', after=None, category=None, is_live=False):
""" Return query string. """
aliases = dict(views='viewCount')
qs = {
'q': term,
'maxResults': 50,
'safeSearch': "none",
'order': aliases.get(config.ORDER.get, config.ORDER.get),
'part': 'id,snippet',
'type': 'video',
'videoDuration': videoDuration
#,'key': config.API_KEY.get
}
if after:
after = after.lower()
qs['publishedAfter'] = '%sZ' % (datetime.utcnow() - timedelta(days=DAYS[after])).isoformat() \
if after in DAYS.keys() else '%s%s' % (after, 'T00:00:00Z' * (len(after) == 10))
if match == 'related':
qs['relatedToVideoId'] = term
del qs['q']
if config.SEARCH_MUSIC.get:
qs['videoCategoryId'] = 10
if category:
qs['videoCategoryId'] = category
if is_live:
qs['eventType'] = "live"
return qs
# def generate_search_qs(term, match='term', videoDuration='any', after=None, category=None, is_live=False):
# """ Return query string. """
#
# aliases = dict(views='viewCount')
# qs = {
# 'q': term,
# 'maxResults': 50,
# 'safeSearch': "none",
# 'order': aliases.get(config.ORDER.get, config.ORDER.get),
# 'part': 'id,snippet',
# 'type': 'video',
# 'videoDuration': videoDuration
# #,'key': config.API_KEY.get
# }
#
# if after:
# after = after.lower()
# qs['publishedAfter'] = '%sZ' % (datetime.utcnow() - timedelta(days=DAYS[after])).isoformat() \
# if after in DAYS.keys() else '%s%s' % (after, 'T00:00:00Z' * (len(after) == 10))
#
# if match == 'related':
# qs['relatedToVideoId'] = term
# del qs['q']
#
# if config.SEARCH_MUSIC.get:
# qs['videoCategoryId'] = 10
#
# if category:
# qs['videoCategoryId'] = category
#
# if is_live:
# qs['eventType'] = "live"
#
# return qs
def userdata_cached(userterm):
@@ -208,7 +208,7 @@ def usersearch_id(user, channel_id, term):
for an optional search term with the user (i.e. the channel)
identified by its ID """
query = generate_search_qs(term)
query = None#generate_search_qs(term)
aliases = dict(views='viewCount') # The value of the config item is 'views' not 'viewCount'
if config.USER_ORDER.get:
query['order'] = aliases.get(config.USER_ORDER.get,
@@ -230,22 +230,21 @@ Use 'set search_music False' to show results not in the Music category.""" % ter
failmsg = "User %s not found or has no videos." % termuser[1]
msg = str(msg).format(c.w, c.y, c.y, term, user)
_search(progtext, query, msg, failmsg)
_search(progtext, term, msg, failmsg)
def related_search(vitem):
""" Fetch uploads by a YouTube user. """
query = generate_search_qs(vitem.ytid, match='related')
if query.get('videoCategoryId'):
del query['videoCategoryId']
""" Fetch videos related to vitem
vitem = {'description': str, 'length': int, 'title': str, 'ytid': str}
"""
t = vitem.title
ttitle = t[:48].strip() + ".." if len(t) > 49 else t
msg = "Videos related to %s%s%s" % (c.y, ttitle, c.w)
failmsg = "Related to %s%s%s not found" % (c.y, vitem.ytid, c.w)
_search(ttitle, query, msg, failmsg)
_search(ttitle, vitem.title, msg, failmsg)
# Livestream category search
@@ -309,12 +308,11 @@ def search(term):
return
logging.info("search for %s", term)
query = generate_search_qs(term, videoDuration=video_duration, after=after,
category=args.category, is_live=args.live)
query = None#generate_search_qs(term, videoDuration=video_duration, after=after, category=args.category, is_live=args.live)
msg = "Search results for %s%s%s" % (c.y, term, c.w)
failmsg = "Found nothing for %s%s%s" % (c.y, term, c.w)
_search(term, query, msg, failmsg)
_search(term, term, msg, failmsg)
@command(r'u(?:ser)?pl\s(.*)', 'userpl', 'upl')
@@ -350,35 +348,31 @@ def pl_search(term, page=0, splash=True, is_user=False):
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
# qs = generate_search_qs(term)
# qs['pageToken'] = token(page)
# qs['type'] = 'playlist'
# if 'videoCategoryId' in qs:
# del qs['videoCategoryId'] # Incompatable with type=playlist
pldata = None#pafy.call_gdata('search', qs)
pldata = pafy.playlist_search(term)
id_list = [i.get('id', {}).get('playlistId')
for i in pldata.get('items', ())
if i['id']['kind'] == 'youtube#playlist']
#id_list = [i.get('id', {}) for i in pldata]
result_count = min(pldata['pageInfo']['totalResults'], 500)
qs = {'part': 'contentDetails,snippet',
'maxResults': 50}
result_count = len(pldata)
#todo: what is the purpose of this code? #qs = {'part': 'contentDetails,snippet','maxResults': 50}
if is_user:
if page:
qs['pageToken'] = token(page)
qs['channelId'] = channel_id
pass #qs['pageToken'] = token(page)
pass #qs['channelId'] = channel_id
else:
qs['id'] = ','.join(id_list)
pass #qs['id'] = ','.join(id_list)
pldata = None#pafy.call_gdata('playlists', qs)
pldata = pafy.playlist_search(term)
playlists = get_pl_from_json(pldata)[:util.getxy().max_results]
if is_user:
result_count = pldata['pageInfo']['totalResults']
# if is_user:
# result_count = pldata['pageInfo']['totalResults']
if playlists:
g.last_search_query = (pl_search, {"term": term, "is_user": is_user})
@@ -399,7 +393,7 @@ def get_pl_from_json(pldata):
""" Process json playlist data. """
try:
items = pldata['items']
items = pldata
except KeyError:
items = []
@@ -407,15 +401,14 @@ def get_pl_from_json(pldata):
results = []
for item in items:
snippet = item['snippet']
results.append(dict(
link=item["id"],
size=item["contentDetails"]["itemCount"],
title=snippet["title"],
author=snippet["channelTitle"],
created=snippet["publishedAt"],
updated=snippet['publishedAt'], #XXX Not available in API?
description=snippet["description"]))
size=item["videoCount"],
title=item["title"],
author=item['channel']["name"],
created=item.get("publishedAt"),
updated=item.get('publishedAt'), #XXX Not available in API?
description=item.get("description")))
return results
@@ -448,17 +441,7 @@ def get_tracks_from_json(jsons):
for item in jsons:
try:
ytid = get_track_id_from_json(item)
duration = item.get('duration')
if duration:
duration_tokens = duration.split(":")
if len(duration_tokens) == 2:
duration = int(duration_tokens[0]) * 60 + int(duration_tokens[1])
else:
duration = int(duration_tokens[0]) * 3600 + int(duration_tokens[1]) * 60 + int(duration_tokens[2])
else:
duration = 30
duration = util.parse_video_length(item.get('duration'))
stats = item.get('statistics', {})
snippet = item.get('snippet', {})
title = item.get('title', '').strip()
+6 -6
Ver Arquivo
@@ -2,7 +2,7 @@ import math
import random
from .. import g, c, screen, streams, content, util
from .. import g, c, screen, streams, content, util, pafy
from ..playlist import Video
from . import command, PL
@@ -83,16 +83,16 @@ def plist(parturl):
ytpl, plitems = g.pafy_pls[parturl]
else:
util.dbg("%sFetching playlist using pafy%s", c.y, c.w)
ytpl = None#pafy.get_playlist2(parturl)
plitems = util.IterSlicer(ytpl)
ytpl = pafy.get_playlist(parturl)
plitems = util.IterSlicer(ytpl['videos'])
g.pafy_pls[parturl] = (ytpl, plitems)
def pl_seg(s, e):
return [Video(i.videoid, i.title, i.length) for i in plitems[s:e]]
return [Video(i['id'], i['title'], util.parse_video_length(i['duration'])) for i in plitems[s:e]]
msg = "Showing YouTube playlist %s" % (c.y + ytpl.title + c.w)
msg = "Showing YouTube playlist %s" % (c.y + ytpl['info']['title'] + c.w)
loadmsg = "Retrieving YouTube playlist"
paginatesongs(pl_seg, length=len(ytpl), msg=msg, loadmsg=loadmsg)
paginatesongs(pl_seg, length=len(ytpl['videos']), msg=msg, loadmsg=loadmsg)
@command(r'(rm|add)\s*(-?\d[-,\d\s]{,250})', 'rm', 'add')
+2 -2
Ver Arquivo
@@ -15,7 +15,7 @@ except ImportError:
from .. import c, g, screen, __version__, __url__, content, config, util
from . import command
from .songlist import paginatesongs
from .search import generate_search_qs, get_tracks_from_json
from .search import get_tracks_from_json
def generate_credentials():
@@ -136,7 +136,7 @@ def _match_tracks(tracks):
dtime(length)))
q = "%s %s" % (artist, ttitle)
w = q = ttitle if artist == "Various Artists" else q
query = generate_search_qs(w, 0)
query = w#generate_search_qs(w, 0)
util.dbg(query)
# perform fetch
+3 -7
Ver Arquivo
@@ -264,14 +264,10 @@ def _get_version_info():
# pafy_version += " (" + pafy.backend + " backend)"
# if pafy.backend == "youtube-dl":
import youtube_dl
youtube_dl_version = youtube_dl.version.__version__
from yt_dlp.version import __version__ as ytdlp_version
out = "yewtube version : " + __version__
out += "\n notes : " + __notes__
#out += "\npafy version : " + pafy_version
if youtube_dl_version:
out += "\nyoutube-dl version : " + youtube_dl_version
out = "yewtube version : " + __version__ +" "+ __notes__
out += "\nyt_dlp version : " + ytdlp_version
out += "\nPython version : " + sys.version
out += "\nProcessor : " + platform.processor()
out += "\nMachine type : " + platform.machine()
+20 -3
Ver Arquivo
@@ -1,5 +1,5 @@
from youtubesearchpython import VideosSearch
import yt_dlp
from youtubesearchpython import VideosSearch, ChannelsSearch, PlaylistsSearch, Suggestions, Playlist
import yt_dlp, random
class MyLogger:
def debug(self, msg):
@@ -24,7 +24,24 @@ def get_video_streams(ytid):
with yt_dlp.YoutubeDL({'logger':MyLogger()}) as ydl:
info_dict = ydl.extract_info(ytid, download=False)
return [i for i in info_dict['formats'] if i.get('format_note') != 'storyboard']
def video_search(query):
videosSearch = VideosSearch(query, limit=50)
wdata = videosSearch.result()['result']
return wdata
return wdata
def channel_search(query):
channelsSearch = ChannelsSearch(query, limit=50, region='US')
return channelsSearch.result()['result']
def playlist_search(query):
playlistsSearch = PlaylistsSearch(query, limit=50)
return playlistsSearch.result()['result']
def get_playlist(playlist_id):
playlist = Playlist.get('https://www.youtube.com/playlist?list=%s' % playlist_id)
return playlist
def get_video_title_suggestions(query):
suggestions = Suggestions(language = 'en', region = 'US')
related_searches = suggestions.get(query)['result']
return related_searches[random.randint(0,len(related_searches))]
+15
Ver Arquivo
@@ -342,6 +342,8 @@ def real_len(u, alt=False):
def yt_datetime(yt_date_time):
""" Return a time object, locale formated date string and locale formatted time string. """
if yt_date_time is None:
return ['Unknown', 'Unknown', 'Unknown']
time_obj = time.strptime(yt_date_time, "%Y-%m-%dT%H:%M:%SZ")
locale_date = time.strftime("%x", time_obj)
locale_time = time.strftime("%X", time_obj)
@@ -593,3 +595,16 @@ class CommandCompleter:
def add_cmd(self, val):
if(not val in self.COMMANDS):
self.COMMANDS.append(val)
def parse_video_length(duration):
'''
Converts HH:MM:SS to a single integer .i.e. total number of seconds
'''
if duration:
duration_tokens = duration.split(":")
if len(duration_tokens) == 2:
return int(duration_tokens[0]) * 60 + int(duration_tokens[1])
else:
return int(duration_tokens[0]) * 3600 + int(duration_tokens[1]) * 60 + int(duration_tokens[2])
else:
return 10
+1 -2
Ver Arquivo
@@ -1,4 +1,3 @@
pyreadline
yt-dlp
youtube-search-python
youtube_dl
youtube-search-python