def web_archive_import_playlist(id): """Imports playlist to archive. Imports entire playlist to the first available archive. Creates new archive if all are full. Args: id (str): YouTube playlist ID. """ db = get_db() user_id = flask.session['user']['id'] for item in yt_get_playlist_items(id): video_id = item['snippet']['resourceId']['videoId'] video = yt_get_video(video_id) channel_id = video['snippet']['channelId'] archive = None for playlist in db_get_archives(): if playlist['contentDetails']['itemCount'] < 5000: archive = playlist break if archive is None: archive = yt_create_playlist() if yt_insert_to_playlist(video_id, archive['id']): if channel_id not in db[user_id]: db[user_id][channel_id] = {'played': {}, 'archived': {}} db[user_id][channel_id]['archived'][video_id] = archive['id'] update_db(db)
def web_channels_update_tracks(tracks): """Handles channel tracking using connected account. Tracks or untracks YouTube channels using connected account. Args: tracks (string): URL encoded JSON data (``channel_id``: ``tracked?``). """ db = get_db() user_id = flask.session['user']['id'] for channel_id, tracked in json.loads( urllib.parse.unquote(tracks)).items(): if tracked: if channel_id not in db[user_id]: db[user_id][channel_id] = {'played': {}, 'archived': {}} else: if channel_id in db[user_id]: channel = db[user_id][channel_id] for video_id, archive_id in channel['archived'].items(): yt_remove_from_playlist(video_id, archive_id) db[user_id].pop(channel_id) update_db(db)
def web_channels_update_query(query): """Handles channel tracking by user query. Tracks or untracks YouTube channels by user query. Args: query (string): URL encoded JSON data (``type``: ``url`` or ``id``, ``value``: ``value``). """ db = get_db() query_data = json.loads(urllib.parse.unquote(query)) user_id = flask.session['user']['id'] if query_data['type'] == 'url': url = query_data['value'] if '/user/' in url: user = re.search('^.+\/user\/([^\/]+)(\/.*|$)', url, re.IGNORECASE).group(1) channel = yt_get_channel('snippet', user=user) db[user_id][channel['id']] = {'played': {}, 'archived': {}} elif '/channel/' in url: channel_id = url.rsplit('/', 1)[-1] channel = yt_get_channel('snippet', channel_id=channel_id) db[user_id][channel['id']] = {'played': {}, 'archived': {}} else: raise elif query_data['type'] == 'user': channel = yt_get_channel('snippet', user=query_data['value']) db[user_id][channel['id']] = {'played': {}, 'archived': {}} elif query_data['type'] == 'id': channel = yt_get_channel('snippet', id=query_data['value']) db[user_id][channel['id']] = {'played': {}, 'archived': {}} update_db(db)
def api_video_unplay(channel=None, video=None): """API video unplay route handler. Handles marking video as unplayed. Args: channel (Optional[str]): YouTube channel ID. video (Optional[str]): YouTube video ID. Returns: flask.Response: Whether operation has succeeded (bool in JSON). """ try: auth_check() except Exception as e: return flask.jsonify(False) if channel is not None and video is not None: db = get_db() if video in db[flask.session['user']['id']][channel]['played']: db[flask.session['user']['id']][channel]['played'].pop(video) update_db(db) return flask.jsonify(True)
def api_video_play(channel=None, video=None): """API video play route handler. Handles marking video as played. Args: channel (Optional[str]): YouTube channel ID. video (Optional[str]): YouTube video ID. Returns: flask.Response: Whether operation has succeeded (bool in JSON). """ try: auth_check() except Exception as e: return flask.jsonify(False) if channel is not None and video is not None: db = get_db() user_id = flask.session['user']['id'] if video not in db[user_id][channel]['played']: db[user_id][channel]['played'][video] = ( datetime.datetime.utcnow().replace( microsecond=0, tzinfo=datetime.timezone.utc).isoformat()) update_db(db) return flask.jsonify(True)
def api_video_unarchive(channel=None, video=None): """API video unarchive route handler. Handles video unarchiving. Args: channel (Optional[str]): YouTube channel ID. video (Optional[str]): YouTube video ID. Returns: flask.Response: Whether operation has succeeded (bool in JSON). """ try: auth_check() except Exception as e: return flask.jsonify(False) if channel is not None and video is not None: db = get_db() user_id = flask.session['user']['id'] if video in db[user_id][channel]['archived']: if yt_remove_from_playlist( video, db[user_id][channel]['archived'][video]): db[user_id][channel]['archived'].pop(video) update_db(db) else: return flask.jsonify(False) return flask.jsonify(True)
def auth_oauth2callback(): """OAuth 2.0 callback route handler. Completes authorization process (stores obtained credentials, gets user information and registers him if needed) and redirects to index. Returns: flask.Response: Index page. """ state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES, state=state) flow.redirect_uri = flask.url_for('oauth2callback', _external=True) authorization_response = flask.request.url flow.fetch_token(authorization_response=authorization_response) credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, 'scopes': credentials.scopes } flask.session['user'] = yt_get_user() db = get_db() if flask.session['user']['id'] not in db: db[flask.session['user']['id']] = {} update_db(db) return flask.redirect(flask.url_for('index'))
def test_get_db(): flexmock(builtins, open=open(DB_FIXTURE_PATH)) assert get_db() == { 'user_id': { 'channel_id': { 'archived': { 'video_id': 'playlist_id' }, 'played': { 'video_id': 'timestamp' } } } }
def yt_get_channel_videos(channel_id): """Gets YouTube channel videos. Gets all uploaded videos for given YouTube channel. Includes information whether they were ``played`` or ``archived`` from the database. Args: channel_id (str): YouTube channel ID. Returns: list: YouTube videos uploaded by given channel. """ db = get_db() client = yt_get_client() try: uploaded_id = client.channels().list( part='contentDetails', id=channel_id).execute( )['items'][0]['contentDetails']['relatedPlaylists']['uploads'] kwargs = { 'part': 'snippet', 'playlistId': uploaded_id, 'maxResults': 50 } items = [] while True: response = client.playlistItems().list(**kwargs).execute() for item in response['items']: video_id = item['snippet']['resourceId']['videoId'] item['played'] = db_get_video(video_id, channel_id, 'played') item['archived'] = db_get_video(video_id, channel_id, 'archived') items.append(item) if 'nextPageToken' not in response: return items else: kwargs['pageToken'] = response['nextPageToken'] except googleapiclient.errors.Error: return []
def yt_get_video(video_id): """Gets YouTube video. Gets information about YouTube video including its rating, playlists, comments and data from the database (``played``, ``archived``). Args: video_id (str): YouTube video ID. Returns: dict: YouTube video. """ db = get_db() client = yt_get_client() try: video = client.videos().list( part='snippet,contentDetails,statistics,status', id=video_id).execute()['items'][0] channel_id = video['snippet']['channelId'] video['played'] = db_get_video(video['id'], channel_id, 'played') video['archived'] = db_get_video(video['id'], channel_id, 'archived') video['playlists'] = {} video['rating'] = client.videos().getRating( id=video_id).execute()['items'][0]['rating'] for playlist_id, data in yt_get_playlists(no_items=True).items(): video['playlists'][playlist_id] = {} video['playlists'][playlist_id]['title'] = data['title'] if video['id'] in data['videos']: video['playlists'][playlist_id]['included'] = True else: video['playlists'][playlist_id]['included'] = False video['comments'] = yt_get_comments(video_id) except googleapiclient.errors.Error: return {} return video
def api_video_archive(channel=None, video=None): """API video archive route handler. Handles video archiving. Args: channel (Optional[str]): YouTube channel ID. video (Optional[str]): YouTube video ID. Returns: flask.Response: Whether operation has succeeded (bool in JSON). """ try: auth_check() except Exception as e: return flask.jsonify(False) if channel is not None and video is not None: db = get_db() archive = None for playlist in db_get_archives(): if playlist['contentDetails']['itemCount'] < 5000: archive = playlist break if archive is None: archive = yt_create_playlist() if yt_insert_to_playlist(video, archive['id']): db[flask.session['user'] ['id']][channel]['archived'][video] = archive['id'] update_db(db) return flask.jsonify(True) else: return flask.jsonify(False)