File indexing completed on 2024-04-14 15:31:35

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()