From 8180cedc717b9698a37b5f763183b23c6cfa2f26 Mon Sep 17 00:00:00 2001 From: ritiek Date: Fri, 18 Aug 2017 12:41:26 +0530 Subject: [PATCH 1/7] Show stream details in video information --- mps_youtube/commands/misc.py | 11 +++++++++-- mps_youtube/player.py | 22 ++++++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/mps_youtube/commands/misc.py b/mps_youtube/commands/misc.py index 927f2a63..0d1e995d 100644 --- a/mps_youtube/commands/misc.py +++ b/mps_youtube/commands/misc.py @@ -4,6 +4,7 @@ import traceback from urllib.request import urlopen from urllib.error import HTTPError, URLError +from .. import player try: # pylint: disable=F0401 @@ -207,11 +208,13 @@ def info(num): p = util.get_pafy(item) pub = datetime.strptime(str(p.published), "%Y-%m-%d %H:%M:%S") pub = util.utc2local(pub) + setattr(p, 'ytid', p.videoid) + details = player.stream_details(p)[1] screen.writestatus("Fetched") out = c.ul + "Video Info" + c.w + "\n\n" out += p.title or "" - out += "\n" + (p.description or "") - out += "\n\nAuthor : " + str(p.author) + out += "\n" + (p.description or "") + "\n" + out += "\nAuthor : " + str(p.author) out += "\nPublished : " + pub.strftime("%c") out += "\nView count : " + str(p.viewcount) out += "\nRating : " + str(p.rating)[:4] @@ -219,6 +222,10 @@ def info(num): out += "\nDislikes : " + str(p.dislikes) out += "\nCategory : " + str(p.category) out += "\nLink : " + "https://youtube.com/watch?v=%s" % p.videoid + out += "\n" + out += "\nExtension : " + details['ext'] + out += "\nQuality : " + details['quality'] + out += "\nContent : " + details['url'] out += "\n\n%s[%sPress enter to go back%s]%s" % (c.y, c.w, c.y, c.w) g.content = out diff --git a/mps_youtube/player.py b/mps_youtube/player.py index 5ad3ac2f..079059a8 100644 --- a/mps_youtube/player.py +++ b/mps_youtube/player.py @@ -42,7 +42,8 @@ def play_range(songlist, shuffle=False, repeat=False, override=False): softrepeat = repeat and len(songlist) == 1 try: - returncode = _playsong(song, override=override, softrepeat=softrepeat) + video, stream = stream_details(song, override=override, softrepeat=softrepeat) + returncode = _playsong(song, stream, video, override=override, softrepeat=softrepeat) except KeyboardInterrupt: logging.info("Keyboard Interrupt") @@ -134,7 +135,7 @@ def _mplayer_help(short=True): return lines.format(c.g, c.w) -def _playsong(song, failcount=0, override=False, softrepeat=False): +def stream_details(song, failcount=0, override=False, softrepeat=False): """ Play song using config.PLAYER called with args config.PLAYERARGS.""" # pylint: disable=R0911,R0912 if not config.PLAYER.get or not util.has_exefile(config.PLAYER.get): @@ -154,7 +155,7 @@ def _playsong(song, failcount=0, override=False, softrepeat=False): streams.get(song, force=failcount, callback=screen.writestatus) except (IOError, URLError, HTTPError, socket.timeout) as e: - util.dbg("--ioerror in _playsong call to streams.get %s", str(e)) + util.dbg("--ioerror in stream_details call to streams.get %s", str(e)) if "Youtube says" in str(e): g.message = util.F('cant get track') % (song.title + " " + str(e)) @@ -163,7 +164,7 @@ def _playsong(song, failcount=0, override=False, softrepeat=False): elif failcount < g.max_retries: util.dbg("--ioerror - trying next stream") failcount += 1 - return _playsong(song, failcount=failcount, override=override, softrepeat=softrepeat) + return stream_details(song, failcount=failcount, override=override, softrepeat=softrepeat) elif "pafy" in str(e): g.message = str(e) + " - " + song.ytid @@ -171,7 +172,7 @@ def _playsong(song, failcount=0, override=False, softrepeat=False): except ValueError: g.message = util.F('track unresolved') - util.dbg("----valueerror in _playsong call to streams.get") + util.dbg("----valueerror in stream_details call to streams.get") return try: @@ -192,13 +193,15 @@ def _playsong(song, failcount=0, override=False, softrepeat=False): if not stream: raise IOError("No streams available") + return (video, stream) + except (HTTPError) as e: # Fix for invalid streams (gh-65) - util.dbg("----htterror in _playsong call to gen_real_args %s", str(e)) + util.dbg("----htterror in stream_details call to gen_real_args %s", str(e)) if failcount < g.max_retries: failcount += 1 - return _playsong(song, failcount=failcount, override=override, softrepeat=softrepeat) + return stream_details(song, failcount=failcount, override=override, softrepeat=softrepeat) else: g.message = str(e) return @@ -210,6 +213,9 @@ def _playsong(song, failcount=0, override=False, softrepeat=False): errmsg = e.message if hasattr(e, "message") else str(e) g.message = c.r + str(errmsg) + c.w return + + +def _playsong(song, stream, video, failcount=0, override=False, softrepeat=False): size = streams.get_size(song.ytid, stream['url']) songdata = (song.ytid, stream['ext'] + " " + stream['quality'], int(size / (1024 ** 2))) @@ -226,7 +232,7 @@ def _playsong(song, failcount=0, override=False, softrepeat=False): screen.writestatus("error: retrying") time.sleep(1.2) failcount += 1 - return _playsong(song, failcount=failcount, override=override, softrepeat=softrepeat) + return _playsong(song, stream, video, failcount=failcount, override=override, softrepeat=softrepeat) history.add(song) return returncode From 99da4358ff92012239db6fdaa53f22d90da49b28 Mon Sep 17 00:00:00 2001 From: ritiek Date: Sat, 19 Aug 2017 03:11:04 +0530 Subject: [PATCH 2/7] Show stream details under stream info section --- mps_youtube/commands/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps_youtube/commands/misc.py b/mps_youtube/commands/misc.py index 0d1e995d..4d4efaf1 100644 --- a/mps_youtube/commands/misc.py +++ b/mps_youtube/commands/misc.py @@ -222,7 +222,7 @@ def info(num): out += "\nDislikes : " + str(p.dislikes) out += "\nCategory : " + str(p.category) out += "\nLink : " + "https://youtube.com/watch?v=%s" % p.videoid - out += "\n" + out += "\n\n" + c.ul + "Stream Info" + c.w + "\n" out += "\nExtension : " + details['ext'] out += "\nQuality : " + details['quality'] out += "\nContent : " + details['url'] From c186d0e22ef4bcd0b6f3875212c7b7a4d9d79839 Mon Sep 17 00:00:00 2001 From: Ritiek Malhotra Date: Sun, 20 Aug 2017 21:50:39 +0530 Subject: [PATCH 3/7] Fix down_many syntax parsing by copying regex from parse_multi() (#1) TODO: figure out if this can be simplified --- mps_youtube/commands/download.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps_youtube/commands/download.py b/mps_youtube/commands/download.py index dae674df..6e265f4f 100644 --- a/mps_youtube/commands/download.py +++ b/mps_youtube/commands/download.py @@ -124,7 +124,7 @@ def download(dltype, num): g.content = content.generate_songlist_display() -@command(r'(da|dv)\s+((?:\d+\s\d+|-\d|\d+-|\d,)(?:[\d\s,-]*))') +@command(r'(da|dv)\s+(? Date: Tue, 22 Aug 2017 20:18:41 +0530 Subject: [PATCH 4/7] Add X command to copy stream link --- mps_youtube/commands/misc.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/mps_youtube/commands/misc.py b/mps_youtube/commands/misc.py index 4d4efaf1..5a1315d7 100644 --- a/mps_youtube/commands/misc.py +++ b/mps_youtube/commands/misc.py @@ -167,6 +167,38 @@ def clip_copy(num): g.content = generate_songlist_display() +@command(r'X\s*(\d+)') +def clip_copy(num): + """ Copy item to clipboard. """ + if g.browse_mode == "normal": + + item = (g.model[int(num) - 1]) + details = player.stream_details(item)[1] + stream = details['url'] + + else: + g.message = "clipboard copy not valid in this mode" + g.content = generate_songlist_display() + return + + if has_pyperclip: + + try: + pyperclip.copy(stream) + g.message = c.y + stream + c.w + " copied" + g.content = generate_songlist_display() + + except Exception as e: + g.content = generate_songlist_display() + g.message = stream + "\nError - couldn't copy to clipboard.\n" + \ + ''.join(traceback.format_exception_only(type(e), e)) + + else: + g.message = "pyperclip module must be installed for clipboard support\n" + g.message += "see https://pypi.python.org/pypi/pyperclip/" + g.content = generate_songlist_display() + + @command(r'i\s*(\d{1,4})') def info(num): """ Get video description. """ From 9a8893d29553d07bc75acabb2adbdab541a50c84 Mon Sep 17 00:00:00 2001 From: ritiek Date: Tue, 22 Aug 2017 20:39:02 +0530 Subject: [PATCH 5/7] Add s command to fetch stream information --- mps_youtube/commands/misc.py | 38 ++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/mps_youtube/commands/misc.py b/mps_youtube/commands/misc.py index 5a1315d7..f69baf60 100644 --- a/mps_youtube/commands/misc.py +++ b/mps_youtube/commands/misc.py @@ -134,7 +134,7 @@ def comments(number): @command(r'x\s*(\d+)') def clip_copy(num): - """ Copy item to clipboard. """ + """ Copy video/playlist url to clipboard. """ if g.browse_mode == "ytpl": p = g.ytpls[int(num) - 1] @@ -169,7 +169,7 @@ def clip_copy(num): @command(r'X\s*(\d+)') def clip_copy(num): - """ Copy item to clipboard. """ + """ Copy content stream url to clipboard. """ if g.browse_mode == "normal": item = (g.model[int(num) - 1]) @@ -200,8 +200,8 @@ def clip_copy(num): @command(r'i\s*(\d{1,4})') -def info(num): - """ Get video description. """ +def video_info(num): + """ Get video information. """ if g.browse_mode == "ytpl": p = g.ytpls[int(num) - 1] @@ -240,8 +240,6 @@ def info(num): p = util.get_pafy(item) pub = datetime.strptime(str(p.published), "%Y-%m-%d %H:%M:%S") pub = util.utc2local(pub) - setattr(p, 'ytid', p.videoid) - details = player.stream_details(p)[1] screen.writestatus("Fetched") out = c.ul + "Video Info" + c.w + "\n\n" out += p.title or "" @@ -254,10 +252,30 @@ def info(num): out += "\nDislikes : " + str(p.dislikes) out += "\nCategory : " + str(p.category) out += "\nLink : " + "https://youtube.com/watch?v=%s" % p.videoid - out += "\n\n" + c.ul + "Stream Info" + c.w + "\n" - out += "\nExtension : " + details['ext'] - out += "\nQuality : " + details['quality'] - out += "\nContent : " + details['url'] + out += "\n\n%s[%sPress enter to go back%s]%s" % (c.y, c.w, c.y, c.w) + g.content = out + + +@command(r's\s*(\d{1,4})') +def stream_info(num): + """ Get stream information. """ + if g.browse_mode == "normal": + g.content = logo(c.b) + screen.update() + screen.writestatus("Fetching stream metadata..") + item = (g.model[int(num) - 1]) + streams.get(item) + p = util.get_pafy(item) + setattr(p, 'ytid', p.videoid) + details = player.stream_details(p)[1] + screen.writestatus("Fetched") + out = "\n\n" + c.ul + "Stream Info" + c.w + "\n" + out += "\nExtension : " + details['ext'] + out += "\nSize : " + str(details['size']) + out += "\nQuality : " + details['quality'] + out += "\nRaw bitrate : " + str(details['rawbitrate']) + out += "\nMedia type : " + details['mtype'] + out += "\nLink : " + details['url'] out += "\n\n%s[%sPress enter to go back%s]%s" % (c.y, c.w, c.y, c.w) g.content = out From 51e8e67e5c581a2fef4668292895986958706cb2 Mon Sep 17 00:00:00 2001 From: ritiek Date: Tue, 22 Aug 2017 20:50:52 +0530 Subject: [PATCH 6/7] Fix conflicting function names --- mps_youtube/commands/misc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps_youtube/commands/misc.py b/mps_youtube/commands/misc.py index f69baf60..05d15eee 100644 --- a/mps_youtube/commands/misc.py +++ b/mps_youtube/commands/misc.py @@ -133,7 +133,7 @@ def comments(number): @command(r'x\s*(\d+)') -def clip_copy(num): +def clipcopy_video(num): """ Copy video/playlist url to clipboard. """ if g.browse_mode == "ytpl": @@ -168,7 +168,7 @@ def clip_copy(num): @command(r'X\s*(\d+)') -def clip_copy(num): +def clipcopy_stream(num): """ Copy content stream url to clipboard. """ if g.browse_mode == "normal": From fd7c8582433b0af9379b9eddc49142d1d6828104 Mon Sep 17 00:00:00 2001 From: ritiek Date: Tue, 22 Aug 2017 22:26:07 +0530 Subject: [PATCH 7/7] Test for player only when actually playing --- mps_youtube/player.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mps_youtube/player.py b/mps_youtube/player.py index 079059a8..d5d0c150 100644 --- a/mps_youtube/player.py +++ b/mps_youtube/player.py @@ -136,16 +136,7 @@ def _mplayer_help(short=True): def stream_details(song, failcount=0, override=False, softrepeat=False): - """ Play song using config.PLAYER called with args config.PLAYERARGS.""" - # pylint: disable=R0911,R0912 - if not config.PLAYER.get or not util.has_exefile(config.PLAYER.get): - g.message = "Player not configured! Enter %sset player "\ - "%s to set a player" % (c.g, c.w) - return - - if config.NOTIFIER.get: - subprocess.Popen(shlex.split(config.NOTIFIER.get) + [song.title]) - + """Fetch stream details for a song.""" # don't interrupt preloading: while song.ytid in g.preloading: screen.writestatus("fetching item..") @@ -216,6 +207,16 @@ def stream_details(song, failcount=0, override=False, softrepeat=False): def _playsong(song, stream, video, failcount=0, override=False, softrepeat=False): + """ Play song using config.PLAYER called with args config.PLAYERARGS.""" + # pylint: disable=R0911,R0912 + if not config.PLAYER.get or not util.has_exefile(config.PLAYER.get): + g.message = "Player not configured! Enter %sset player "\ + "%s to set a player" % (c.g, c.w) + return + + if config.NOTIFIER.get: + subprocess.Popen(shlex.split(config.NOTIFIER.get) + [song.title]) + size = streams.get_size(song.ytid, stream['url']) songdata = (song.ytid, stream['ext'] + " " + stream['quality'], int(size / (1024 ** 2)))