def add_subscription_local(youtube_auth, channel_id, by_username=False): """ Add a YouTube subscription (Local/DB). :param by_username: :param youtube_auth: :param channel_id: :return: """ # FIXME: Somewhat duplicate code of get_remote_subscriptions, move to own function -- START # Get ID of uploads playlist # channel_uploads_playlist_id = get_channel_uploads_playlist_id(youtube_auth, channel_id) if by_username: channel_response = get_channel_by_username(youtube_auth, channel_id) else: channel_response = get_channel_by_id(youtube_auth, channel_id) channel_uploads_playlist_id = channel_response['contentDetails'][ 'relatedPlaylists']['uploads'] channel = Channel(channel_response, channel_uploads_playlist_id, channel_list_response=True) db_channel = engine_execute_first(get_channel_by_id_stmt(channel)) if db_channel: engine_execute(update_channel_from_remote(channel)) else: # TODO: change to sqlalchemy core stmt create_logger(__name__ + ".subscriptions").info( "Added channel {} - {}".format(channel.title, channel.id)) db_session.add(channel) db_session.commit() # FIXME: Somewhat duplicate code of get_remote_subscriptions, move to own function -- END logger.info("Added subscription (Local/DB): {} / {}".format( channel_id, channel.title))
def add_subscription_remote(channel_id): """ Add a YouTube subscription (On YouTube). DEPRECATED: Google doesn't let you, see supported op table https://developers.google.com/youtube/v3/getting-started :param youtube_oauth: :param channel_id: :return: returns response or raises exception """ youtube_oauth = load_youtube() response = youtube_oauth.subscriptions().insert( part='snippet', body=dict(snippet=dict(resourceId=dict(channelId=channel_id)))) try: response.execute() except HttpError as exc_http: _msg = "Failed adding subscription to '{}', HTTP Error {}".format( channel_id, exc_http.resp.status) logger.error("{}: {}".format(_msg, exc_http.content), exc_info=exc_http) raise exc_http except Exception as exc: _msg = "Unhandled exception occurred when adding subscription to '{}'".format( channel_id) logger.critical("{} | response={}".format(_msg, response.__dict__), exc_info=exc) raise exc # FIXME: Somewhat duplicate code of get_remote_subscriptions, move to own function -- START # Get ID of uploads playlist channel_uploads_playlist_id = response['items'][0]['contentDetails'][ 'relatedPlaylists']['uploads'] channel = Channel(channel_id, channel_uploads_playlist_id) db_channel = engine_execute_first(get_channel_by_id_stmt(channel)) if db_channel: engine_execute(update_channel_from_remote(channel)) # subs.append(channel) else: # TODO: change to sqlalchemy core stmt create_logger(__name__ + ".subscriptions").info( "Added channel {} - {}".format(channel.title, channel.id)) db_session.add(channel) # subs.append(channel) db_session.commit() # FIXME: Somewhat duplicate code of get_remote_subscriptions, move to own function -- END logger.info("Added subscription: {} / {}".format( channel_id, response['snippet']['title'])) return response
def cli(no_gui, test_channels, update_watch_prio, set_watched_day): logger = create_logger(__name__) if no_gui: run_print() if update_watch_prio: videos = db_session.query(Video).all() watch_prio = read_config('Play', 'default_watch_prio') logger.debug("Setting watch_prio {}, for: {} videos".format(watch_prio, len(videos))) for video in videos: video.watch_prio = watch_prio db_session.commit() return if set_watched_day: videos = db_session.query(Video).filter(or_(Video.downloaded == True, (Video.vid_path.is_(None)))).all() for video in videos: vid_age = datetime.datetime.utcnow() - video.date_published if vid_age > datetime.timedelta(days=int(set_watched_day)): logger.debug("Setting watched, {} - {} - {}".format(vid_age, video.title, video.__dict__)) video.watched = True db_session.commit() return if test_channels: run_channels_test() else: """ PyQT raises and catches exceptions, but doesn't pass them along. Instead it just exits with a status of 1 to show an exception was caught. """ # Back up the reference to the exceptionhook sys._excepthook = sys.excepthook def my_exception_hook(exctype, value, traceback): # Ignore KeyboardInterrupt so a console python program can exit with Ctrl + C. if issubclass(exctype, KeyboardInterrupt): sys.__excepthook__(exctype, value, traceback) return # Log the exception with the logger logger.critical("Intercepted Exception", exc_info=(exctype, value, traceback)) # Call the normal Exception hook after sys._excepthook(exctype, value, traceback) # sys.exit(1) # Alternatively, exit # Set the exception hook to our wrapping function sys.excepthook = my_exception_hook run_with_gui()
def get_remote_subscriptions(youtube_oauth): """ Get a list of the authenticated user's subscriptions. :param youtube_oauth: :param stats: :param info: debug lite :param debug: :param traverse_pages: :return: [total, subs, statistics] """ subscription_list_request = youtube_oauth.subscriptions().list( part='snippet', mine=True, maxResults=50) subs = [] # Retrieve the list of subscribed channels for authenticated user's channel. update_stmts = [] channel_ids = [] while subscription_list_request: subscription_list_response = subscription_list_request.execute() # Grab information about each subscription page for page in tqdm(subscription_list_response['items'], desc="Adding and updating channels by page", disable=read_config('Debug', 'disable_tqdm')): # Get channel channel_response = channels_list( youtube_oauth, part='contentDetails', id=page['snippet']['resourceId']['channelId']) # Get ID of uploads playlist channel_uploads_playlist_id = channel_response['items'][0][ 'contentDetails']['relatedPlaylists']['uploads'] channel = Channel(page['snippet'], channel_uploads_playlist_id) db_channel = engine_execute_first(get_channel_by_id_stmt(channel)) if db_channel: engine_execute(update_channel_from_remote(channel)) subs.append(channel) else: # TODO: change to sqlalchemy core stmt create_logger(__name__ + ".subscriptions").info( "Added channel {} - {}".format(channel.title, channel.id)) db_session.add(channel) subs.append(channel) channel_ids.append(channel.id) subscription_list_request = youtube_oauth.playlistItems().list_next( subscription_list_request, subscription_list_response) delete_sub_not_in_list(channel_ids) db_session.commit() return subs
def update_download_tile(self, download_tile): result = db_session.query(DBDownloadTile).filter( DBDownloadTile.video_id == format( download_tile.video.video_id)).first() # stmt = DBDownloadTile.__table__.select().where( # text("video_id = '{}'".format(download_tile.video.video_id))) # result = engine.execute(stmt).first() if result: result.update_tile(download_tile) db_session.commit() db_session.remove() else: self.logger.warning( "Download tile not found in db, so no update was performed: {}" .format(download_tile.__dict__))
def new_download_tile(self, new_tile): lock.acquire() result = db_session.query(DBDownloadTile).filter( DBDownloadTile.video_id == format( new_tile.video.video_id)).first() if not result: download_tile = DBDownloadTile(new_tile) if not download_tile.video: self.logger.error("No video in new tile: {}".format( download_tile.__dict__), exc_info=True) return db_session.add(download_tile) db_session.commit() db_session.remove() lock.release()
def get_remote_subscriptions(youtube_oauth): """ Get a list of the authenticated user's subscriptions. :param youtube_oauth: :return: [subs] """ if youtube_oauth is None: logger.critical("YouTube API OAuth object was NoneType, aborting!") return None subscription_list_request = youtube_oauth.subscriptions().list(part='snippet', mine=True, maxResults=50) subs = [] # Retrieve the list of subscribed channels for authenticated user's channel. channel_ids = [] while subscription_list_request: subscription_list_response = subscription_list_request.execute() # Grab information about each subscription page for page in subscription_list_response['items']: # Get channel channel_response = channels_list(youtube_oauth, part='contentDetails', id=page['snippet']['resourceId']['channelId']) # Get ID of uploads playlist channel_uploads_playlist_id = channel_response['items'][0]['contentDetails']['relatedPlaylists']['uploads'] channel = Channel(page['snippet'], channel_uploads_playlist_id) db_channel = engine_execute_first(get_channel_by_id_stmt(channel)) if db_channel: engine_execute(update_channel_from_remote(channel)) subs.append(channel) else: # TODO: change to sqlalchemy core stmt create_logger(__name__ + ".subscriptions").info( "Added channel {} - {}".format(channel.title, channel.id)) db_session.add(channel) subs.append(channel) channel_ids.append(channel.id) subscription_list_request = youtube_oauth.playlistItems().list_next( subscription_list_request, subscription_list_response) delete_sub_not_in_list(channel_ids) db_session.commit() return subs
def run_channels_test(): logger.info('Running Channels Test') subscriptions = get_subscriptions(cached_subs) youtube_keys = load_keys(len(subscriptions)) test_threads = [] results = [] logger.info("Channels Test: Starting miss and pages tests") for subscription, youtube_key in (subscriptions, youtube_keys): test = RunTestsThreaded(subscription, youtube_key, results) test.start() test_threads.append(test) logger.info("Channels Test: Waiting for test threads") for thread in test_threads: thread.join() for result in results: test = Test(result[0], result[1], result[2], result[3]) db_session.add(test) db_session.commit() db_session.remove()
def new_file(self, vid_id, vid_path): vid = db_session.query(Video).get(vid_id) if vid: if not vid.downloaded: vid.vid_path = vid_path vid.date_downloaded = datetime.datetime.utcnow() vid.downloaded = True thumb_path = os.path.join(THUMBNAILS_PATH, '{}.jpg'.format(vid.video_id)) downloaded_thumbnail = os.path.isfile(thumb_path) if downloaded_thumbnail and (not vid.thumbnail_path): vid.thumbnail_path = thumb_path self.logger.warning( "Thumbnail downloaded, but path didn't exist in db, for video: {}" .format(vid.__dict__)) elif (not vid.thumbnail_path) or (not downloaded_thumbnail): if not downloaded_thumbnail: self.logger.warning( "Thumbnail path in db, but not on disk, for video: {}" .format(vid.__dict__)) self.logger.info("Downloading thumbnail for: {}".format( vid.__dict__)) download_thumbnails_threaded([vid]) self.logger.info( "Updating existing record in db: {} - {}".format( vid.title, vid.__dict__)) db_session.commit() self.model.update_subfeed_videos_from_db() self.model.update_playback_videos_from_db() else: self.logger.info( "File already downloaded by this system: {} - {}".format( vid.title, vid.__dict__)) db_session.remove() else: db_session.remove() youtube_keys = load_keys(1) self.logger.info( "Grabbing new video information from youtube: {}".format( vid_id)) response_videos = list_uploaded_videos_videos( youtube_keys[0], [vid_id], 1) if len(response_videos) > 0: video = response_videos[0] video.vid_path = vid_path video.downloaded = True video.watched = False video.date_downloaded = datetime.datetime.utcnow() self.logger.info("Downloading thumbnail: {} - {}".format( video.title, video.__dict__)) download_thumbnails_threaded([video]) self.logger.info("Adding new file to db: {} - {}".format( video.title, video.__dict__)) UpdateVideo(video, finished_listeners=[ self.model.playback_grid_view_listener. downloadedVideosChangedinDB ]).start() else: self.logger.warning( "Video with id {}, not found on youtube servers".format( vid_id))
def cli(no_gui, test_channels, update_watch_prio, set_watched_day, refresh_and_print_subfeed, print_subscriptions, print_watched_videos, print_discarded_videos, print_downloaded_videos, print_playlist_items, print_playlist_items_url_only, auth_oauth2): logger = create_logger(__name__) if update_watch_prio: videos = db_session.query(Video).all() watch_prio = read_config('Play', 'default_watch_prio') logger.debug("Setting watch_prio {}, for: {} videos".format( watch_prio, len(videos))) for video in videos: video.watch_prio = watch_prio db_session.commit() return if set_watched_day: videos = db_session.query(Video).filter( or_(Video.downloaded == True, (Video.vid_path.is_(None)))).all() for video in videos: vid_age = datetime.datetime.utcnow() - video.date_published if vid_age > datetime.timedelta(days=int(set_watched_day)): logger.debug("Setting watched, {} - {} - {}".format( vid_age, video.title, video.__dict__)) video.watched = True db_session.commit() return if test_channels: run_channels_test() if refresh_and_print_subfeed: cli_refresh_and_print_subfeed() if print_subscriptions: cached_subs = True subs = get_subscriptions(cached_subs) for channel in subs: if channel.subscribed_override: print(("[{}] {} [Subscription override]".format( channel.id, channel.title))) else: print(("[{}] {}".format(channel.id, channel.title))) if print_watched_videos: videos = db_session.query(Video).filter( and_(Video.watched is True, (Video.vid_path.isnot(None)))).all() print_functions.print_videos(videos, path_only=True) if print_discarded_videos: videos = db_session.query(Video).filter( and_(Video.discarded is True, (Video.vid_path.isnot(None)))).all() print_functions.print_videos(videos, path_only=True) if print_downloaded_videos: videos = db_session.query(Video).filter( and_(Video.downloaded is True, (Video.vid_path.isnot(None)))).all() print_functions.print_videos(videos, path_only=True) if print_playlist_items: youtube_auth_resource = load_keys(1)[0] playlist_video_items = [] youtube.youtube_requests.list_uploaded_videos(youtube_auth_resource, playlist_video_items, print_playlist_items, 50) for vid in playlist_video_items: if print_playlist_items_url_only: print(vid.url_video) else: print(vid) if auth_oauth2: youtube_oauth = youtube_auth_oauth() if youtube_oauth is None: logger.critical("Failed to authenticate YouTube API OAuth2!") return None save_youtube_resource_oauth(youtube_oauth) if no_gui: run_with_cli() else: if LEGACY_EXCEPTION_HANDLER: """ PyQT raises and catches exceptions, but doesn't pass them along. Instead it just exits with a status of 1 to show an exception was caught. """ # Back up the reference to the exceptionhook sys._excepthook = sys.excepthook def my_exception_hook(exctype, value, traceback): global exc_id, exceptions # Ignore KeyboardInterrupt so a console python program can exit with Ctrl + C. if issubclass(exctype, KeyboardInterrupt): sys.__excepthook__(exctype, value, traceback) return # Log the exception with the logger logger.exception("Intercepted Exception #{}".format(exc_id), exc_info=(exctype, value, traceback)) # Store intercepted exceptions in a reference list of lists exceptions.append([exctype, value, traceback, exc_id]) # Increment Exception Identifier exc_id += 1 # Call the normal Exception hook after # noinspection PyProtectedMember sys._excepthook(exctype, value, traceback) # sys.exit(1) # Alternatively, exit # Set the exception hook to our wrapping function sys.excepthook = my_exception_hook run_with_gui()