Warning, file /plasma-bigscreen/youtube-voice-application/__init__.py was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 # -*- coding: utf-8 -*- 0002 0003 import time 0004 import urllib 0005 from os.path import dirname, join 0006 import sys 0007 import json 0008 import base64 0009 import re 0010 import timeago, datetime 0011 import dateutil.parser 0012 import requests 0013 import yt_dlp 0014 if sys.version_info[0] < 3: 0015 from urllib import quote 0016 from urllib2 import urlopen 0017 else: 0018 from urllib.request import urlopen 0019 from urllib.parse import quote, urlencode 0020 from adapt.intent import IntentBuilder 0021 from bs4 import BeautifulSoup, SoupStrainer 0022 from mycroft.skills.core import MycroftSkill, intent_handler, intent_file_handler 0023 from mycroft.messagebus.message import Message 0024 from mycroft.util.log import LOG 0025 from collections import deque 0026 from json_database import JsonStorage 0027 from .tempfix.search.searcher import YoutubeSearcher 0028 from yt_dlp import YoutubeDL 0029 0030 __author__ = 'aix' 0031 0032 class YoutubeSkill(MycroftSkill): 0033 def __init__(self): 0034 super(YoutubeSkill, self).__init__(name="YoutubeSkill") 0035 self.nextpage_url = None 0036 self.previouspage_url = None 0037 self.live_category = None 0038 self.recentList = deque() 0039 self.recentPageObject = {} 0040 self.nextSongList = None 0041 self.lastSong = None 0042 self.videoPageObject = {} 0043 self.isTitle = None 0044 self.trendCategoryList = {} 0045 self.newsCategoryList = {} 0046 self.musicCategoryList = {} 0047 self.techCategoryList = {} 0048 self.polCategoryList = {} 0049 self.gamingCategoryList = {} 0050 self.searchCategoryList = {} 0051 self.recentCategoryList = {} 0052 self.recentWatchListObj = {} 0053 self.storeDB = None 0054 self.recent_db = None 0055 self.quackAPIWorker="J0dvb2dsZWJvdC8yLjEgKCtodHRwOi8vd3d3Lmdvb2dsZS5jb20vYm90Lmh0bWwpJw==" 0056 self.quackagent = {'User-Agent' : base64.b64decode(self.quackAPIWorker)} 0057 self.yts = YoutubeSearcher() 0058 0059 def initialize(self): 0060 self.load_data_files(dirname(__file__)) 0061 self.storeDB = join(self.file_system.path, 'youtube-recent.db') 0062 self.recent_db = JsonStorage(self.storeDB) 0063 0064 self.bus.on('youtube-skill.aiix.home', self.launcherId) 0065 0066 youtubepause = IntentBuilder("YoutubePauseKeyword"). \ 0067 require("YoutubePauseKeyword").build() 0068 self.register_intent(youtubepause, self.youtubepause) 0069 0070 youtuberesume = IntentBuilder("YoutubeResumeKeyword"). \ 0071 require("YoutubeResumeKeyword").build() 0072 self.register_intent(youtuberesume, self.youtuberesume) 0073 0074 youtubesearchpage = IntentBuilder("YoutubeSearchPageKeyword"). \ 0075 require("YoutubeSearchPageKeyword").build() 0076 self.register_intent(youtubesearchpage, self.youtubesearchpage) 0077 0078 youtubelauncherId = IntentBuilder("YoutubeLauncherId"). \ 0079 require("YoutubeLauncherIdKeyword").build() 0080 self.register_intent(youtubelauncherId, self.launcherId) 0081 0082 self.add_event('aiix.youtube-skill.playvideo_id', self.play_event) 0083 0084 self.gui.register_handler('YoutubeSkill.SearchLive', 0085 self.searchLive) 0086 0087 self.gui.register_handler('YoutubeSkill.NextPage', self.searchNextPage) 0088 self.gui.register_handler('YoutubeSkill.PreviousPage', self.searchPreviousPage) 0089 self.gui.register_handler('YoutubeSkill.NextAutoPlaySong', self.nextSongForAutoPlay) 0090 self.gui.register_handler('YoutubeSkill.RefreshWatchList', self.refreshWatchList) 0091 self.gui.register_handler('YoutubeSkill.ClearDB', self.clear_db) 0092 self.gui.register_handler('YoutubeSkill.ReplayLast', self.youtube_repeat_last) 0093 0094 0095 def get_best_video_url(self, video_id): 0096 # Use dlp to get the best video of type mp4 url from a video ID 0097 ydl_opts = { 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' } 0098 try: 0099 ydl = YoutubeDL(ydl_opts) 0100 info = ydl.extract_info(video_id, download=False) 0101 video_container = [] 0102 best_format = None 0103 for f in info['formats']: 0104 if f['acodec'] != 'none' and f['vcodec'] != 'none': 0105 video_container.append(f) 0106 # sort video_container based on format_note using sorting table: 0107 if 'format_note' in video_container[0]: 0108 sort_table = ["1080p", "720p", "480p", "360p", "240p", "144p"] 0109 video_container = sorted(video_container, key=lambda f: sort_table.index(f['format_note'])) 0110 best_format = video_container[0].get('url') 0111 return best_format 0112 else: 0113 # sort video_container based on format_id using sorting table in descending order: 0114 video_container = sorted(video_container, key=lambda f: f['format_id'], reverse=True) 0115 best_format = video_container[0].get('url') 0116 return best_format 0117 except Exception as e: 0118 LOG.error("Error: " + str(e)) 0119 return None 0120 0121 def extract_video_meta_from_dlp(self, video_id): 0122 # extract video information like title, views, published time and channel name 0123 ydl_opts = { 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' } 0124 ydl = YoutubeDL(ydl_opts) 0125 info = ydl.extract_info(video_id, download=False) 0126 video_info = {} 0127 video_info['title'] = info['title'] 0128 video_info['views'] = info['view_count'] 0129 video_info['published'] = info['upload_date'] 0130 video_info['channel'] = info['uploader'] 0131 return video_info 0132 0133 def launcherId(self, message): 0134 self.show_homepage({}) 0135 0136 @intent_file_handler('youtubeopenapp.intent') 0137 def launch_home_and_search_category(self, message): 0138 self.speak("Loading Up Youtube For You") 0139 self.show_homepage({}) 0140 0141 def getListSearch(self, text): 0142 query = quote(text) 0143 url = "https://www.youtube.com/results?search_query=" + quote(query) 0144 response = requests.get(url, headers=self.quackagent) 0145 html = response.text 0146 a_tag = SoupStrainer('a') 0147 soup = BeautifulSoup(html, 'html.parser', parse_only=a_tag) 0148 for vid in soup.findAll(attrs={'class': 'yt-uix-tile-link'}): 0149 if "googleads" not in vid['href'] and not vid['href'].startswith( 0150 u"/user") and not vid['href'].startswith(u"/channel"): 0151 id = vid['href'].split("v=")[1].split("&")[0] 0152 return id 0153 0154 def moreRandomListSearch(self, text): 0155 LOG.info(text) 0156 query = quote(text) 0157 try: 0158 querySplit = text.split() 0159 LOG.info(querySplit) 0160 searchQuery = "*," + quote(querySplit[0]) + quote(querySplit[1]) + ",*" 0161 0162 except: 0163 LOG.info("fail") 0164 searchQuery = "*," + quote(query) + ",*" 0165 0166 LOG.info(searchQuery) 0167 return searchQuery 0168 0169 0170 def searchLive(self, message): 0171 videoList = [] 0172 videoList.clear() 0173 videoPageObject = {} 0174 try: 0175 query = message.data["Query"] 0176 LOG.info("I am in search Live") 0177 self.searchCategoryList["videoList"] = self.build_category_list(quote(query)) 0178 self.gui["searchListBlob"] = self.searchCategoryList 0179 self.gui["previousAvailable"] = False 0180 self.gui["nextAvailable"] = True 0181 self.gui["bgImage"] = quote(query) 0182 self.gui.show_page("YoutubeLiveSearch.qml", override_idle=True) 0183 except: 0184 LOG.debug("error") 0185 0186 def searchNextPage(self, message): 0187 getCategory = message.data["Category"] 0188 LOG.info(getCategory) 0189 if getCategory == "News": 0190 LOG.info("In Category News") 0191 newsAdditionalPages = self.process_additional_pages("news") 0192 self.newsCategoryList['videoList'] = self.build_category_list_from_url("https://www.youtube.com" + newsAdditionalPages[0]) 0193 self.gui["newsNextAvailable"] = False 0194 self.gui["newsListBlob"] = self.newsCategoryList 0195 if getCategory == "Music": 0196 LOG.info("In Category Music") 0197 musicAdditionalPages = self.process_additional_pages("music") 0198 self.musicCategoryList['videoList'] = self.build_category_list_from_url("https://www.youtube.com" + musicAdditionalPages[0]) 0199 self.gui["musicNextAvailable"] = False 0200 self.gui["musicListBlob"] = self.musicCategoryList 0201 if getCategory == "Technology": 0202 LOG.info("In Category Technology") 0203 technologyAdditionalPages = self.process_additional_pages("technology") 0204 self.techCategoryList['videoList'] = self.build_category_list_from_url("https://www.youtube.com" + technologyAdditionalPages[0]) 0205 self.gui["techNextAvailable"] = False 0206 self.gui["techListBlob"] = self.techCategoryList 0207 if getCategory == "Politics": 0208 LOG.info("In Category Politics") 0209 politicsAdditionalPages = self.process_additional_pages("politics") 0210 self.polCategoryList['videoList'] = self.build_category_list_from_url("https://www.youtube.com" + politicsAdditionalPages[0]) 0211 self.gui["polNextAvailable"] = False 0212 self.gui["polListBlob"] = self.polCategoryList 0213 if getCategory == "Gaming": 0214 LOG.info("In Category Gaming") 0215 gamingAdditionalPages = self.process_additional_pages("gaming") 0216 self.gamingCategoryList['videoList'] = self.build_category_list_from_url("https://www.youtube.com" + gamingAdditionalPages[0]) 0217 self.gui["gamingNextAvailable"] = False 0218 self.gui["gamingListBlob"] = self.gamingCategoryList 0219 if getCategory == "Search": 0220 LOG.info("In Search") 0221 0222 def searchPreviousPage(self, message): 0223 getCategory = message.data["Category"] 0224 LOG.info(getCategory) 0225 if getCategory == "News": 0226 LOG.info("In Category News") 0227 newsAdditionalPages = self.process_additional_pages("news") 0228 self.newsCategoryList['videoList'] = self.build_category_list_from_url(newsAdditionalPages[1]) 0229 self.gui["newsNextAvailable"] = True 0230 self.gui["newsListBlob"] = self.newsCategoryList 0231 if getCategory == "Music": 0232 LOG.info("In Category Music") 0233 musicAdditionalPages = self.process_additional_pages("music") 0234 self.musicCategoryList['videoList'] = self.build_category_list_from_url(musicAdditionalPages[1]) 0235 self.gui["musicNextAvailable"] = True 0236 self.gui["musicListBlob"] = self.musicCategoryList 0237 if getCategory == "Technology": 0238 LOG.info("In Category Technology") 0239 technologyAdditionalPages = self.process_additional_pages("technology") 0240 self.techCategoryList['videoList'] = self.build_category_list_from_url(technologyAdditionalPages[1]) 0241 self.gui["techNextAvailable"] = True 0242 self.gui["techListBlob"] = self.techCategoryList 0243 if getCategory == "Politics": 0244 LOG.info("In Category Politics") 0245 politicsAdditionalPages = self.process_additional_pages("politics") 0246 self.polCategoryList['videoList'] = self.build_category_list_from_url(politicsAdditionalPages[1]) 0247 self.gui["polNextAvailable"] = True 0248 self.gui["polListBlob"] = self.polCategoryList 0249 if getCategory == "Gaming": 0250 LOG.info("In Category Gaming") 0251 gamingAdditionalPages = self.process_additional_pages("gaming") 0252 self.gamingCategoryList['videoList'] = self.build_category_list_from_url(gamingAdditionalPages[1]) 0253 self.gui["gamingNextAvailable"] = True 0254 self.gui["gamingListBlob"] = self.gamingCategoryList 0255 if getCategory == "Search": 0256 LOG.info("In Search") 0257 0258 def getTitle(self, text): 0259 query = quote(text) 0260 url = "https://www.youtube.com/results?search_query=" + quote(query) 0261 response = requests.get(url, headers=self.quackagent) 0262 html = response.text 0263 soup = BeautifulSoup(html) 0264 for vid in soup.findAll(attrs={'class': 'yt-uix-tile-link'}): 0265 if "googleads" not in vid['href'] and not vid['href'].startswith( 0266 u"/user") and not vid['href'].startswith(u"/channel"): 0267 videoTitle = vid['title'] 0268 return videoTitle 0269 0270 0271 @intent_file_handler('youtube.intent') 0272 def youtube(self, message): 0273 self.stop() 0274 self.gui.clear() 0275 0276 utterance = message.data['videoname'].lower() 0277 self.youtube_play_video(utterance) 0278 0279 def youtube_play_video(self, utterance): 0280 self.gui["setTitle"] = "" 0281 self.gui["video"] = "" 0282 self.gui["status"] = "stop" 0283 self.gui["currenturl"] = "" 0284 self.gui["videoListBlob"] = "" 0285 self.gui["recentListBlob"] = "" 0286 self.gui["videoThumb"] = "" 0287 url = "https://www.youtube.com/results?search_query=" + quote(utterance) 0288 response = requests.get(url, headers=self.quackagent) 0289 html = response.text 0290 a_tag = SoupStrainer('a') 0291 soup = BeautifulSoup(html, 'html.parser', parse_only=a_tag) 0292 self.gui["video"] = "" 0293 self.gui["status"] = "stop" 0294 self.gui["currenturl"] = "" 0295 self.gui["videoListBlob"] = "" 0296 self.gui["recentListBlob"] = "" 0297 self.gui["videoThumb"] = "" 0298 video_query_str = str(quote(utterance)) 0299 #print(video_query_str) 0300 abc = self.yts.search_youtube(video_query_str, render="videos") 0301 vid = abc['videos'][0]['url'] 0302 stream_url = self.get_best_video_url(vid) 0303 if stream_url is not None: 0304 getvid = vid.split("v=")[1].split("&")[0] 0305 thumb = "https://img.youtube.com/vi/{0}/0.jpg".format(getvid) 0306 self.gui["videoThumb"] = thumb 0307 self.lastSong = vid 0308 self.gui["status"] = str("play") 0309 self.gui["video"] = str(stream_url) 0310 self.gui["currenturl"] = str(vid) 0311 self.gui["currenttitle"] = abc['videos'][0]['title'] 0312 self.gui["setTitle"] = abc['videos'][0]['title'] 0313 self.gui["viewCount"] = abc['videos'][0]['views'] 0314 self.gui["publishedDate"] = abc['videos'][0]['published_time'] 0315 self.gui["videoAuthor"] = abc['videos'][0]['channel_name'] 0316 self.gui["videoListBlob"] = "" 0317 self.gui["recentListBlob"] = "" 0318 self.gui["nextSongBlob"] = "" 0319 self.gui.show_pages(["YoutubePlayer.qml", "YoutubeSearch.qml"], 0, override_idle=True) 0320 #self.gui.show_page("YoutubeSearch.qml", override_idle=True) 0321 self.gui["currenttitle"] = self.getTitle(utterance) 0322 LOG.info("Video Published On") 0323 recentVideoDict = {"videoID": getvid, "videoTitle": abc['videos'][0]['title'], "videoImage": thumb, "videoChannel": abc['videos'][0]['channel_name'], "videoViews": abc['videos'][0]['views'], "videoUploadDate": abc['videos'][0]['published_time'], "videoDuration": abc['videos'][0]['length']} 0324 self.buildHistoryModel(recentVideoDict) 0325 self.gui["recentListBlob"] = self.recent_db 0326 self.youtubesearchpagesimple(getvid) 0327 self.isTitle = abc['videos'][0]['title'] 0328 self.gui["recentListBlob"] = self.recent_db 0329 else: 0330 self.speak("Sorry, I can't find the video.") 0331 0332 def process_ytl_stream(self, streams): 0333 _videostreams = [] 0334 for z in range(len(streams)): 0335 if streams[z].get("vcodec") != "none": 0336 if streams[z].get("acodec") != "none": 0337 _videostreams.append(streams[z]) 0338 0339 for a in range(len(_videostreams)): 0340 if _videostreams[a]["format_note"] == "720p": 0341 return _videostreams[a]["url"] 0342 elif _videostreams[a]["format_note"] == "480p": 0343 return _videostreams[a]["url"] 0344 elif _videostreams[a]["format_note"] == "360p": 0345 return _videostreams[a]["url"] 0346 elif _videostreams[a]["format_note"] == "240p": 0347 return _videostreams[a]["url"] 0348 elif _videostreams[a]["format_note"] == "144p": 0349 return _videostreams[a]["url"] 0350 0351 def youtubepause(self, message): 0352 self.gui["status"] = str("pause") 0353 self.gui.show_page("YoutubePlayer.qml") 0354 0355 def youtuberesume(self, message): 0356 self.gui["status"] = str("play") 0357 self.gui.show_page("YoutubePlayer.qml") 0358 0359 def youtubesearchpage(self, message): 0360 self.stop() 0361 videoList = [] 0362 videoList.clear() 0363 videoPageObject = {} 0364 utterance = message.data.get('utterance').lower() 0365 utterance = utterance.replace( 0366 message.data.get('YoutubeSearchPageKeyword'), '') 0367 vid = self.getListSearch(utterance) 0368 url = "https://www.youtube.com/results?search_query=" + vid 0369 response = requests.get(url, headers=self.quackagent) 0370 html = response.text 0371 videoList = self.process_soup_additional(html) 0372 videoPageObject['videoList'] = videoList 0373 self.gui["videoListBlob"] = videoPageObject 0374 self.gui["recentListBlob"] = self.recent_db 0375 self.gui.show_page("YoutubeSearch.qml") 0376 0377 def youtubesearchpagesimple(self, query): 0378 LOG.info(query) 0379 videoList = [] 0380 videoList.clear() 0381 videoPageObject = {} 0382 yts = YoutubeSearcher() 0383 vidslist = yts.watchlist_search(video_id=query) 0384 for x in range(len(vidslist['watchlist_videos'])): 0385 videoID = vidslist['watchlist_videos'][x]['videoId'] 0386 videoTitle = vidslist['watchlist_videos'][x]['title'] 0387 videoImage = "https://img.youtube.com/vi/{0}/0.jpg".format(videoID) 0388 videoUploadDate = vidslist['watchlist_videos'][x]['published_time'] 0389 videoDuration = vidslist['watchlist_videos'][x]['length'] 0390 videoViews = vidslist['watchlist_videos'][x]['views'] 0391 videoChannel = vidslist['watchlist_videos'][x]['channel_name'] 0392 videoList.append({"videoID": videoID, "videoTitle": videoTitle, "videoImage": videoImage, "videoChannel": videoChannel, "videoViews": videoViews, "videoUploadDate": videoUploadDate, "videoDuration": videoDuration}) 0393 0394 videoPageObject['videoList'] = videoList 0395 self.gui["videoListBlob"] = videoPageObject 0396 self.gui["recentListBlob"] = self.recent_db 0397 0398 def show_homepage(self, message): 0399 LOG.info("I AM IN HOME PAGE FUNCTION") 0400 self.gui.clear() 0401 0402 self.gui["loadingStatus"] = "" 0403 self.gui.show_page("YoutubeLogo.qml") 0404 self.process_home_page() 0405 0406 def process_home_page(self): 0407 LOG.info("I AM IN HOME PROCESS PAGE FUNCTION") 0408 self.gui["loadingStatus"] = "Fetching Trends" 0409 self.trendCategoryList['videoList'] = self.build_category_list_from_url("https://www.youtube.com/feed/trending") 0410 if self.trendCategoryList['videoList']: 0411 LOG.info("Trends Not Empty") 0412 else: 0413 LOG.info("Trying To Rebuild Trends List") 0414 self.trendCategoryList['videoList'] = self.build_category_list_from_url("https://www.youtube.com/feed/trending") 0415 self.gui["loadingStatus"] = "Fetching News" 0416 self.newsCategoryList['videoList'] = self.build_category_list("news") 0417 if self.newsCategoryList['videoList']: 0418 LOG.info("News Not Empty") 0419 else: 0420 LOG.info("Trying To Rebuild News List") 0421 self.newsCategoryList['videoList'] = self.build_category_list("news") 0422 0423 self.build_recent_watch_list(20) 0424 self.gui.clear() 0425 0426 self.show_search_page() 0427 0428 self.musicCategoryList['videoList'] = self.build_category_list("music") 0429 if self.musicCategoryList['videoList']: 0430 LOG.info("Music Not Empty") 0431 else: 0432 LOG.info("Trying To Rebuild Music List") 0433 self.musicCategoryList['videoList'] = self.build_category_list("music") 0434 self.gui["musicListBlob"] = self.musicCategoryList 0435 0436 self.techCategoryList['videoList'] = self.build_category_list("technology") 0437 if self.techCategoryList['videoList']: 0438 LOG.info("Tech Not Empty") 0439 else: 0440 LOG.info("Trying To Rebuild Tech List") 0441 self.techCategoryList['videoList'] = self.build_category_list("technology") 0442 self.gui["techListBlob"] = self.techCategoryList 0443 0444 self.polCategoryList['videoList'] = self.build_category_list("politics") 0445 if self.polCategoryList['videoList']: 0446 LOG.info("Pol Not Empty") 0447 else: 0448 LOG.info("Trying To Rebuild Pol List") 0449 self.polCategoryList['videoList'] = self.build_category_list("politics") 0450 self.gui["polListBlob"] = self.polCategoryList 0451 0452 self.gamingCategoryList['videoList'] = self.build_category_list("gaming") 0453 if self.gamingCategoryList['videoList']: 0454 LOG.info("Gaming Not Empty") 0455 else: 0456 LOG.info("Trying To Rebuild Pol List") 0457 self.gamingCategoryList['videoList'] = self.build_category_list("gaming") 0458 self.gui["gamingListBlob"] = self.gamingCategoryList 0459 0460 LOG.info("I AM NOW IN REMOVE LOGO PAGE FUNCTION") 0461 0462 def show_search_page(self): 0463 LOG.info("I AM NOW IN SHOW SEARCH PAGE FUNCTION") 0464 LOG.info(self.techCategoryList) 0465 self.gui["recentHomeListBlob"] = self.recentWatchListObj 0466 self.gui["recentListBlob"] = self.recent_db 0467 self.gui["trendListBlob"] = self.trendCategoryList 0468 self.gui["newsListBlob"] = self.newsCategoryList 0469 self.gui["newsNextAvailable"] = True 0470 self.gui["musicListBlob"] = self.musicCategoryList 0471 self.gui["musicNextAvailable"] = True 0472 self.gui["techListBlob"] = self.techCategoryList 0473 self.gui["techNextAvailable"] = True 0474 self.gui["polListBlob"] = self.polCategoryList 0475 self.gui["polNextAvailable"] = True 0476 self.gui["gamingListBlob"] = self.gamingCategoryList 0477 self.gui["gamingNextAvailable"] = True 0478 self.gui["searchListBlob"] = "" 0479 self.gui["previousAvailable"] = False 0480 self.gui["nextAvailable"] = True 0481 self.gui["bgImage"] = self.live_category 0482 self.gui.show_page("YoutubeLiveSearch.qml", override_idle=True) 0483 0484 0485 def play_event(self, message): 0486 urlvideo = "http://www.youtube.com/watch?v={0}".format(message.data['vidID']) 0487 self.lastSong = message.data['vidID'] 0488 try: 0489 video = self.yts.extract_video_meta(urlvideo) 0490 self.gui["publishedDate"] = self.build_upload_date_non_vui(video.get('published_time')) 0491 except: 0492 video = self.extract_video_meta_from_dlp(urlvideo) 0493 self.gui["publishedDate"] = video.get('published') 0494 playurl = self.get_best_video_url(urlvideo) 0495 if playurl is not None: 0496 self.speak("Playing") 0497 self.gui["video"] = str(playurl) 0498 self.gui["status"] = str("play") 0499 self.gui["currenturl"] = str(message.data['vidID']) 0500 self.gui["currenttitle"] = str(message.data['vidTitle']) 0501 #print(video.keys()) 0502 self.gui["setTitle"] = video.get('title') 0503 self.gui["viewCount"] = video.get('views') 0504 self.gui["videoAuthor"] = video.get('channel_name') 0505 self.gui["nextSongBlob"] = "" 0506 videoTitleSearch = str(message.data['vidTitle']).join(str(message.data['vidTitle']).split()[:-1]) 0507 self.gui.show_pages(["YoutubePlayer.qml", "YoutubeSearch.qml"], 0, override_idle=True) 0508 thumb = "https://img.youtube.com/vi/{0}/maxresdefault.jpg".format(message.data['vidID']) 0509 recentVideoDict = {"videoID": message.data['vidID'], "videoTitle": message.data['vidTitle'], "videoImage": message.data['vidImage'], "videoChannel": message.data['vidChannel'], "videoViews": message.data['vidViews'], "videoUploadDate": message.data['vidUploadDate'], "videoDuration": message.data['vidDuration']} 0510 self.buildHistoryModel(recentVideoDict) 0511 self.gui["recentListBlob"] = self.recent_db 0512 self.youtubesearchpagesimple(message.data['vidID']) 0513 self.isTitle = video.get('title') 0514 else: 0515 self.speak("Sorry, I can't find the video.") 0516 0517 def stop(self): 0518 self.enclosure.bus.emit(Message("metadata", {"type": "stop"})) 0519 pass 0520 0521 def process_soup(self, htmltype): 0522 videoList = [] 0523 videoList.clear() 0524 soup = BeautifulSoup(htmltype) 0525 for vid in soup.findAll(attrs={'class': 'yt-uix-tile-link'}): 0526 if "googleads" not in vid['href'] and not vid['href'].startswith( 0527 u"/user") and not vid['href'].startswith(u"/channel"): 0528 LOG.info(vid) 0529 videoID = vid['href'].split("v=")[1].split("&")[0] 0530 videoTitle = vid['title'] 0531 videoImage = "https://i.ytimg.com/vi/{0}/hqdefault.jpg".format(videoID) 0532 videoList.append({"videoID": videoID, "videoTitle": videoTitle, "videoImage": videoImage}) 0533 0534 if len(videoList) > 1: 0535 self.nextSongList = videoList[1] 0536 else: 0537 self.nextSongList = videoList[0] 0538 0539 return videoList 0540 0541 def process_soup_additional(self, htmltype): 0542 videoList = [] 0543 videoList.clear() 0544 soup = BeautifulSoup(htmltype) 0545 getVideoDetails = zip(soup.findAll(attrs={'class': 'yt-uix-tile-link'}), soup.findAll(attrs={'class': 'yt-lockup-byline'}), soup.findAll(attrs={'class': 'yt-lockup-meta-info'}), soup.findAll(attrs={'class': 'video-time'})) 0546 for vid in getVideoDetails: 0547 if "googleads" not in vid[0]['href'] and not vid[0]['href'].startswith( 0548 u"/user") and not vid[0]['href'].startswith(u"/channel") and not vid[0]['href'].startswith('/news') and not vid[0]['href'].startswith('/music') and not vid[0]['href'].startswith('/technology') and not vid[0]['href'].startswith('/politics') and not vid[0]['href'].startswith('/gaming'): 0549 videoID = vid[0]['href'].split("v=")[1].split("&")[0] 0550 videoTitle = vid[0]['title'] 0551 videoImage = "https://i.ytimg.com/vi/{0}/hqdefault.jpg".format(videoID) 0552 videoChannel = vid[1].contents[0].string 0553 videoUploadDate = vid[2].contents[0].string 0554 videoDuration = vid[3].contents[0].string 0555 if "watching" in vid[2].contents[0].string: 0556 videoViews = "Live" 0557 else: 0558 try: 0559 videoViews = vid[2].contents[1].string 0560 except: 0561 videoViews = "Playlist" 0562 0563 videoList.append({"videoID": videoID, "videoTitle": videoTitle, "videoImage": videoImage, "videoChannel": videoChannel, "videoViews": videoViews, "videoUploadDate": videoUploadDate, "videoDuration": videoDuration}) 0564 0565 return videoList 0566 0567 def process_additional_pages(self, category): 0568 url = "https://www.youtube.com/results?search_query={0}".format(category) 0569 response = requests.get(url, headers=self.quackagent) 0570 html = response.text 0571 soup = BeautifulSoup(html) 0572 buttons = soup.findAll('a', attrs={'class':"yt-uix-button vve-check yt-uix-sessionlink yt-uix-button-default yt-uix-button-size-default"}) 0573 try: 0574 nPage = buttons[0]['href'] 0575 except: 0576 nPage = self.process_additional_pages_fail(category) 0577 pPage = url 0578 addPgObj = [nPage, pPage] 0579 0580 return addPgObj 0581 0582 def process_additional_pages_fail(self, category): 0583 url = None 0584 if category == "news": 0585 url = "/results?search_query=world+news" 0586 if category == "music": 0587 url = "/results?search_query=latest+music" 0588 if category == "technology": 0589 url = "/results?search_query=latest+tech" 0590 if category == "politics": 0591 url = "/results?search_query=latest+politics" 0592 if category == "gaming": 0593 url = "/results?search_query=latest+games" 0594 0595 return url 0596 0597 0598 def nextSongForAutoPlay(self): 0599 self.gui["nextSongBlob"] = self.nextSongList 0600 0601 def refreshWatchList(self, message): 0602 print("Currently Disabled, Skipping Step") 0603 #try: 0604 #print("todo") 0605 #self.youtubesearchpagesimple(self.lastSong) 0606 #except: 0607 #self.youtubesearchpagesimple(self.lastSong) 0608 0609 @intent_file_handler('youtube-repeat.intent') 0610 def youtube_repeat_last(self): 0611 urlvideo = "http://www.youtube.com/watch?v={0}".format(self.lastSong) 0612 video = self.yts.extract_video_meta(urlvideo) 0613 playurl = self.get_best_video_url(urlvideo) 0614 self.gui["status"] = str("play") 0615 self.gui["video"] = str(playurl) 0616 self.gui["currenturl"] = "" 0617 self.gui["currenttitle"] = video.get('title') 0618 self.gui["setTitle"] = video.get('title') 0619 self.gui["viewCount"] = video.get('views') 0620 self.gui["publishedDate"] = self.build_upload_date_non_vui(video.get('published_time')) 0621 self.gui["videoAuthor"] = video.get('channel_name') 0622 self.gui["videoListBlob"] = "" 0623 self.gui["recentListBlob"] = "" 0624 self.gui["nextSongTitle"] = "" 0625 self.gui["nextSongImage"] = "" 0626 self.gui["nextSongID"] = "" 0627 self.gui.show_pages(["YoutubePlayer.qml", "YoutubeSearch.qml"], 0, override_idle=True) 0628 self.youtubesearchpagesimple(self.lastSong) 0629 self.isTitle = video.get('title') 0630 0631 def build_category_list(self, category): 0632 LOG.info("Building For Category" + category) 0633 videoList = [] 0634 yts = YoutubeSearcher() 0635 vidslist = yts.search_youtube(category, render="videos") 0636 for x in range(len(vidslist['videos'])): 0637 videoID = vidslist['videos'][x]['videoId'] 0638 videoTitle = vidslist['videos'][x]['title'] 0639 videoImage = vidslist['videos'][x]['thumbnails'][0]['url'] 0640 vidImgFix = str(videoImage).split("?")[0] 0641 videoUploadDate = vidslist['videos'][x]['published_time'] 0642 videoDuration = vidslist['videos'][x]['length'] 0643 videoViews = vidslist['videos'][x]['views'] 0644 videoChannel = vidslist['videos'][x]['channel_name'] 0645 videoList.append({"videoID": videoID, "videoTitle": videoTitle, "videoImage": vidImgFix, "videoChannel": videoChannel, "videoViews": videoViews, "videoUploadDate": videoUploadDate, "videoDuration": videoDuration}) 0646 0647 return videoList 0648 0649 def build_category_list_from_url(self, category): 0650 videoList = [] 0651 yts = YoutubeSearcher() 0652 vidslist = yts.page_search(page_type=category) 0653 for x in range(len(vidslist['page_videos'])): 0654 videoID = vidslist['page_videos'][x]['videoId'] 0655 videoTitle = vidslist['page_videos'][x]['title'] 0656 videoImage = vidslist['page_videos'][x]['thumbnails'][0]['url'] 0657 vidImgFix = str(videoImage).split("?")[0] 0658 videoUploadDate = vidslist['page_videos'][x]['published_time'] 0659 videoDuration = vidslist['page_videos'][x]['length'] 0660 videoViews = vidslist['page_videos'][x]['views'] 0661 videoChannel = vidslist['page_videos'][x]['channel_name'] 0662 videoList.append({"videoID": videoID, "videoTitle": videoTitle, "videoImage": vidImgFix, "videoChannel": videoChannel, "videoViews": videoViews, "videoUploadDate": videoUploadDate, "videoDuration": videoDuration}) 0663 0664 return videoList 0665 0666 def clear_db(self): 0667 LOG.info("In DB Clear") 0668 self.recent_db.clear() 0669 self.recent_db.store() 0670 self.gui["recentListBlob"] = "" 0671 0672 def buildHistoryModel(self, dictItem): 0673 LOG.info("In Build History Model") 0674 if 'recentList' in self.recent_db.keys(): 0675 myCheck = self.checkIfHistoryItem(dictItem) 0676 if myCheck == True: 0677 LOG.info("In true") 0678 #LOG.info(dictItem) 0679 self.moveHistoryEntry(dictItem) 0680 elif myCheck == False: 0681 LOG.info("In false") 0682 #LOG.info(dictItem) 0683 self.addHistoryEntry(dictItem) 0684 0685 else: 0686 recentListItem = [] 0687 recentListItem.insert(0, dictItem) 0688 self.recent_db['recentList'] = recentListItem 0689 LOG.info("In Build History Recent Not Found Creating") 0690 self.recent_db.store() 0691 self.build_recent_watch_list(20) 0692 self.gui["recentHomeListBlob"] = self.recentWatchListObj 0693 0694 def checkIfHistoryItem(self, dictItem): 0695 hasHistoryItem = False 0696 for dict_ in [x for x in self.recent_db['recentList'] if x["videoID"] == dictItem["videoID"]]: 0697 hasHistoryItem = True 0698 return hasHistoryItem 0699 0700 def moveHistoryEntry(self, dictItem): 0701 res = [i for i in self.recent_db['recentList'] if not (i['videoID'] == dictItem["videoID"])] 0702 self.recent_db['recentList'] = res 0703 self.recent_db['recentList'].insert(0, dictItem) 0704 self.recent_db.store() 0705 self.build_recent_watch_list(20) 0706 self.gui["recentHomeListBlob"] = self.recentWatchListObj 0707 0708 def addHistoryEntry(self, dictItem): 0709 self.recent_db['recentList'].insert(0, dictItem) 0710 self.recent_db.store() 0711 self.build_recent_watch_list(20) 0712 self.gui["recentHomeListBlob"] = self.recentWatchListObj 0713 0714 def build_recent_watch_list(self, count): 0715 if 'recentList' in self.recent_db.keys(): 0716 recentWatchListRaw = self.recent_db['recentList'] 0717 recentWatchListModded = recentWatchListRaw[0:count] 0718 self.recentWatchListObj['recentList'] = recentWatchListModded 0719 else: 0720 emptyList = [] 0721 self.recentWatchListObj['recentList'] = emptyList 0722 0723 def build_upload_date(self, update): 0724 now = datetime.datetime.now() + datetime.timedelta(seconds = 60 * 3.4) 0725 date = dateutil.parser.parse(update) 0726 naive = date.replace(tzinfo=None) 0727 dtstring = timeago.format(naive, now) 0728 return dtstring 0729 0730 def build_upload_date_non_vui(self, update): 0731 if update == "Live": 0732 return update 0733 else: 0734 now = datetime.datetime.now() + datetime.timedelta(seconds = 60 * 3.4) 0735 date = update 0736 naive = date.replace(tzinfo=None) 0737 dtstring = timeago.format(naive, now) 0738 return dtstring 0739 0740 def add_view_string(self, viewcount): 0741 val = viewcount 0742 count = re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val) 0743 views = count + " views" 0744 LOG.info(views) 0745 return views 0746 0747 def process_soup_watchlist(self, html): 0748 videoList = [] 0749 videoList.clear() 0750 soup = BeautifulSoup(html) 0751 currentVideoSection = soup.find('div', attrs={'class': 'watch-sidebar'}) 0752 getVideoDetails = zip(currentVideoSection.findAll(attrs={'class': 'yt-uix-sessionlink'}), currentVideoSection.findAll(attrs={'class': 'attribution'}), currentVideoSection.findAll(attrs={'class': 'yt-uix-simple-thumb-wrap'}), currentVideoSection.findAll(attrs={'class': 'video-time'}), currentVideoSection.findAll(attrs={'class': 'view-count'})) 0753 for vid in getVideoDetails: 0754 if "googleads" not in vid[0]['href'] and not vid[0]['href'].startswith( 0755 u"/user") and not vid[0]['href'].startswith(u"/channel") and not vid[0]['href'].startswith('/news') and not vid[0]['href'].startswith('/music') and not vid[0]['href'].startswith('/technology') and not vid[0]['href'].startswith('/politics') and not vid[0]['href'].startswith('/gaming') and "title" in vid[0].attrs: 0756 videoID = vid[0]['href'].split("v=")[1].split("&")[0] 0757 videoTitle = vid[0]['title'] 0758 videoImage = "https://i.ytimg.com/vi/{0}/hqdefault.jpg".format(videoID) 0759 videoChannel = vid[1].contents[0].string 0760 videoUploadDate = " " 0761 videoDuration = vid[3].contents[0].string 0762 videoViews = vid[4].text 0763 0764 videoList.append({"videoID": videoID, "videoTitle": videoTitle, "videoImage": videoImage, "videoChannel": videoChannel, "videoViews": videoViews, "videoUploadDate": videoUploadDate, "videoDuration": videoDuration}) 0765 0766 return videoList 0767 0768 0769 def create_skill(): 0770 return YoutubeSkill()