From 392af1f44cf2d59d314d0680f71ee260631d7d2f Mon Sep 17 00:00:00 2001 From: krzysiej Date: Sat, 15 Jul 2017 20:49:42 +0200 Subject: [PATCH] initial commit --- play.py | 346 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100755 play.py diff --git a/play.py b/play.py new file mode 100755 index 0000000..9863361 --- /dev/null +++ b/play.py @@ -0,0 +1,346 @@ +#!/usr/bin/python3 +#import cProfile +#import re +import requests +from datetime import datetime +#import calendar +import os +from html import unescape +import urllib.parse +#import time +import curses +import sqlite3 as lite +import youtube +#import os.path +#import math +from curses.textpad import Textbox, rectangle +#527 biale z podkreśleniem 520 szare z podkresleniem +#https://www.googleapis.com/youtube/v3/search?key=AIzaSyBwecAq2aCjRxStpOclQZNSRpJEI2HtvX0&part=snippet&type=channel&q=etho&maxResults=10 + +def get_video_id(url): + url_data = urllib.parse.urlparse(url) + query = urllib.parse.parse_qs(url_data.query) + return query['v'][0] + + +def get_valid_filename(string): + return "".join([c for c in string if c.isalpha() or c.isdigit() or c == ' ']).rstrip().replace(' ', '_') + +def file_exists(video_title): + return os.path.isfile("/public/youtube/" + get_valid_filename(video_title)+".mp4") + + + +class Mc(object): + youtube_info_url = 'http://youtube.com/get_video_info?video_id=' + youtube_channels = [] + youtube_api_key = "AIzaSyBwecAq2aCjRxStpOclQZNSRpJEI2HtvX0" + videos = {} + timestamp = 0 + longest_nick = 0 + selected_video = 0 + connection = lite.connect('/public/python/test.db') + offset = 0 + channel_id_filter = 0 + total_videos = 0 + search = '' + + + def __init__(self): + self.read_data() + self.total_videos = self.get_total_videos() + + def read_data(self): + with self.connection: + cur = self.connection.cursor() + cur.execute('SELECT id, nick, uploadsid FROM channel') + self.youtube_channels = cur.fetchall() + if self.channel_id_filter > 0: + cur.execute("SELECT nick, title, videoid, channel_id, seen FROM video JOIN channel ON video.channel_id = channel.id WHERE deleted IS NULL AND channel.id = ? AND title LIKE ? ORDER BY publishtime DESC LIMIT ?, 30", (self.channel_id_filter, '%'+self.search+'%', self.offset)) + else: + cur.execute("SELECT nick, title, videoid, channel_id, seen FROM video JOIN channel ON video.channel_id = channel.id WHERE deleted IS NULL AND title LIKE ? ORDER BY publishtime DESC LIMIT ?, 30", ('%'+self.search+'%', self.offset)) + + self.videos = cur.fetchall() + + + def lite(self, channels): + with self.connection: + cur = self.connection.cursor() + for channel in channels: + cur.execute("SELECT * FROM channel WHERE nick = :nick", {"nick": channel['nick']}) + self.connection.commit() + row = cur.fetchone() + if row == None: + cur.execute( + "INSERT INTO channel('playlist', 'nick', 'channel', 'userid', 'uploadsid') VALUES (?, ?, ?, ?, ?)", + ('1', channel['nick'], channel['channel'], channel['userid'], channel['uploadsid'])) + self.connection.commit() + + def get_video_info_url(self, video_id): + return self.youtube_info_url + video_id + + def print_videos(self, stdscr): + iterator = 0 + for video in self.videos: + is_file = "X" if file_exists(video[1]) else " " + if iterator == self.selected_video: + stdscr.addstr(iterator, 0, "[%s] %s %-60s" % (video[0].ljust(14, ' '), is_file, video[1]), curses.A_STANDOUT) + elif video[4] == 1: + stdscr.addstr(iterator, 0, "[%s] %s %-60s" % (video[0].ljust(14, ' '), is_file, video[1]), curses.color_pair(236)) + #stdscr.addstr(iterator, 0, "[%s] %s %s %-60s" % (video[0].ljust(14, ' '), is_file, video[1], iterator+self.offset), curses.color_pair(iterator+self.offset)) + + else: + #stdscr.addstr(iterator, 0, "[%s] %s %s %-60s" % (video[0].ljust(14, ' '), is_file, video[1], iterator+self.offset), curses.color_pair(iterator+self.offset)) + stdscr.addstr(iterator, 0, "[%s] %s %-60s" % (video[0].ljust(14, ' '), is_file, video[1]), curses.color_pair(255)) + iterator += 1 + + def print_botom_info(self, stdscr): + pages = int(self.total_videos) // 30 + stdscr.addstr(len(self.videos), 0, "Play [Enter] | Download [D] | Refresh [R] | Exit [Q] |", curses.A_BOLD ) + if_search = curses.color_pair(90) if len(self.search) > 0 else curses.A_BOLD + if_filter = curses.color_pair(90) if self.channel_id_filter > 0 else curses.A_BOLD + stdscr.addstr(len(self.videos), 55, "Search [S]", if_search) + stdscr.addstr(len(self.videos), 65, " | ", curses.A_BOLD) + stdscr.addstr(len(self.videos), 68, "Filter [F]" , if_filter) + stdscr.addstr(len(self.videos), 78, " | " , curses.A_BOLD) + stdscr.addstr(len(self.videos), 81, "[<-/->] | [%d / %d] " % (self.offset /30+1, pages), curses.A_BOLD) + + def get_total_videos(self): + with self.connection: + cur = self.connection.cursor() + if self.channel_id_filter > 0: + cur.execute("SELECT count(video.id) FROM video JOIN channel ON video.channel_id = channel.id AND channel.id = ? WHERE title like ?", (self.channel_id_filter, '%'+self.search+'%')) + else: + cur.execute("SELECT count(video.id) FROM video JOIN channel ON video.channel_id = channel.id WHERE title LIKE ?", ('%'+self.search+'%',)) + return int(cur.fetchone()[0]) + + def get_video_direct_urls(self, video_id): + streams = [] + data = requests.get(self.get_video_info_url(video_id)) + unescaped = unescape(data.text) + decoded = urllib.parse.parse_qs(data.text) + + for stream in decoded['url_encoded_fmt_stream_map'][0].split(','): + streams.append(urllib.parse.parse_qs(stream)) + + return streams + + def get_all_videos(self): + for id, channelName, uploadListId in self.youtube_channels: + + videos = youtube.playlistItems(uploadListId, self.youtube_api_key, True) + for row in videos: + self.save_video(id, row) + + + def get_recent_videos_silent(self, allVideos=False): + for id, channelName, uploadListId in self.youtube_channels: + videos = youtube.playlistItems(uploadListId, self.youtube_api_key, allVideos) + for row in videos: + self.save_video(id, row) + + + + + def get_recent_videos(self, stdscr): + channel_iterator = 1 + + for id, channelName, uploadListId in self.youtube_channels: + stdscr.addstr(channel_iterator, 0, '%s %d/%d' % (channelName,0,50)) + channel_iterator+=1 + + channel_iterator = 1 + for id, channelName, uploadListId in self.youtube_channels: + videos = youtube.playlistItems(uploadListId, self.youtube_api_key) + videos_iterator = 1 + for row in videos: + self.save_video(id, row) + stdscr.addstr(channel_iterator, 0, '%s %d/%d' % (channelName,videos_iterator, len(videos))) + stdscr.refresh() + videos_iterator+=1 + channel_iterator+=1 + + + + def save_video(self, channel_id, video_row): + with self.connection: + cur = self.connection.cursor() + + cur.execute( + "INSERT OR IGNORE INTO video('channel_id', 'title', 'views', 'duration', 'videoid', 'publishtime') VALUES (?, ?, ?, ?, ?, ?)", + (channel_id, video_row['title'], 0, 0, video_row['videoid'], video_row['timestamp'])) + self.connection.commit() + + + def main_loop(self, stdscr): + stdscr.keypad(True) + stdscr.clear() + + + curses.use_default_colors() + + for i in range(0, curses.COLORS): + curses.init_pair(i, i, -1); + + self.print_videos(stdscr) + mc.print_botom_info(stdscr) + curses.curs_set(0) + + + while 1: + stdscr.refresh() + + key = stdscr.getch() + + if key == curses.KEY_UP: + stdscr.refresh() + mc.selected_video -= 1 + if mc.selected_video < 0: + mc.selected_video = len(mc.videos) - 1 + elif key == curses.KEY_DOWN: + stdscr.refresh() + mc.selected_video += 1 + if mc.selected_video >= len(mc.videos): + mc.selected_video = 0 + elif key == curses.KEY_RIGHT: + stdscr.clear() + self.offset += 30; + self.read_data() + + elif key == curses.KEY_LEFT: + stdscr.clear() + if(self.offset > 30): + self.offset -= 30 + else: + self.offset = 0 + self.read_data() + elif key in [ord('F'), ord('f')]: + stdscr.clear() + if self.channel_id_filter > 0: + self.channel_id_filter = 0; + else: + self.channel_id_filter = mc.videos[mc.selected_video][3] + self.offset = 0 + self.read_data() + self.total_videos = self.get_total_videos() + + elif key in [ord('A'), ord('a')]: + stdscr.clear() + editwin = curses.newwin(1, 49, 2, 1) + stdscr.addstr(0,0,'Search channel:') + stdscr.addstr(1, 0, '+-------------------------------------------------+') + stdscr.addstr(2, 0, '| |') + stdscr.addstr(3, 0, '+-------------------------------------------------+') + + stdscr.refresh() + box = Textbox(editwin) + box.edit() + + self.searchChannel = box.gather() + + + + + elif key in [ord('S'), ord('s')]: + stdscr.clear() + editwin = curses.newwin(1,49, 2,1) + stdscr.addstr(0, 0, 'SEARCH BY TITLE:') + stdscr.addstr(1, 0, '+-------------------------------------------------+') + stdscr.addstr(2, 0, '| |') + stdscr.addstr(3, 0, '+-------------------------------------------------+') + + + stdscr.refresh() + box = Textbox(editwin) + box.edit() + + self.search = box.gather() + self.read_data() + self.total_videos = self.get_total_videos() + + stdscr.clear() + + + elif key in [ord('R'), ord('r')]: + stdscr.clear() + + stdscr.addstr(0, 0, 'REFRESHING LIST') + stdscr.refresh() + self.read_data() + self.total_videos = self.get_total_videos() + + + elif key in [ord('D'), ord('d')]: + video_id = mc.videos[mc.selected_video][2] + streams = mc.get_video_direct_urls(video_id) + + for stream in streams: + if stream['itag'][0] == "22": + os.system('wget -nv --show-progress -O "/public/youtube/%s.mp4" "%s" >> /dev/null &' % ( + get_valid_filename(mc.videos[mc.selected_video][1]), stream['url'][0])) + + elif key in [ord('Q'), ord('q')]: # esc + curses.endwin() + os._exit(0) + elif key == 10 or key == curses.KEY_ENTER: + video_id = mc.videos[mc.selected_video][2] + #stdscr.clear() + #stdscr.addstr(0, 0, '/public/youtube/' + get_valid_filename(mc.videos[mc.selected_video][1])+".mp4") + + # stdscr.refresh() + # time.sleep(4) + + with self.connection: + cur = self.connection.cursor() + cur.execute('UPDATE video SET seen = 1 WHERE videoid = ?', (video_id, )) + self.youtube_channels = cur.fetchall() + self.connection.commit() + + + + + if file_exists(mc.videos[mc.selected_video][1]): + + # stdscr.addstr(1, 1, '/public/youtube/' + get_valid_filename(mc.videos[mc.selected_video][1])+".mp4") + # stdscr.refresh() + os.system('omxplayer -b "%s"' % ("/public/youtube/" + get_valid_filename(mc.videos[mc.selected_video][1])+".mp4" )) + else: + streams = mc.get_video_direct_urls(video_id) + + for stream in streams: + # print (stream['itag']) + if stream['itag'][0] == "22": + os.system('omxplayer -b "%s"' % stream['url'][0]) + stdscr.clear() + + mc.print_videos(stdscr) + mc.print_botom_info(stdscr) + + +if __name__ == "__main__": + mc = Mc() + +#test('test') + +#print (youtube.search('generikb', 'channel', "AIzaSyBwecAq2aCjRxStpOclQZNSRpJEI2HtvX0")) + +#videos = youtube.playlistItems("UU-_VTaWqRsZ1nzZLHQIGwQA", "AIzaSyBwecAq2aCjRxStpOclQZNSRpJEI2HtvX0") +#print(videos) +#mc.get_all_videos() + +#mc.lite(channels) + +# print (mc.get_video_info_url('https://www.youtube.com/watch?v=vw61gCe2oqI')) + +# mc.get_videos('UUFKDEp9si4RmHFWJW1vYsMA') + +# mc.get_videos('UUJTWU5K7kl9EE109HBeoldA') +# os.system('clear') +# + try: + curses.wrapper(mc.main_loop) + #cProfile.run('re.compile("foo|bar")') + except KeyboardInterrupt: + curses.endwin() + os._exit(0) +