├── README.md ├── screenshot.png └── waiting.py /README.md: -------------------------------------------------------------------------------- 1 | # Udacity-queue-position 2 | Find your place in the Udacity reviews queue with this simple script 3 | 4 | ### Requirements 5 | ` 6 | pip install termcolor 7 | ` 8 | ### How to run 9 | ` 10 | python waiting.py -T [YOUR API KEY] 11 | ` 12 | 13 | ![screenshot](screenshot.png) 14 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spirosrap/Udacity-queue-position/e231d5d27dc13a60dd552386d462d980f65d45d3/screenshot.png -------------------------------------------------------------------------------- /waiting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import signal 3 | import sys 4 | import argparse 5 | import logging 6 | import os 7 | import requests 8 | import time 9 | import pytz 10 | from dateutil import parser 11 | from datetime import datetime, timedelta 12 | 13 | import json 14 | from termcolor import colored 15 | 16 | utc = pytz.UTC 17 | 18 | # Script config 19 | BASE_URL = 'https://review-api.udacity.com/api/v1' 20 | CERTS_URL = '{}/me/certifications.json'.format(BASE_URL) 21 | ME_URL = '{}/me'.format(BASE_URL) 22 | ME_REQUEST_URL = '{}/me/submission_requests.json'.format(BASE_URL) 23 | CREATE_REQUEST_URL = '{}/submission_requests.json'.format(BASE_URL) 24 | DELETE_URL_TMPL = '{}/submission_requests/{}.json' 25 | GET_REQUEST_URL_TMPL = '{}/submission_requests/{}.json' 26 | PUT_REQUEST_URL_TMPL = '{}/submission_requests/{}.json' 27 | REFRESH_URL_TMPL = '{}/submission_requests/{}/refresh.json' 28 | ASSIGNED_COUNT_URL = '{}/me/submissions/assigned_count.json'.format(BASE_URL) 29 | ASSIGNED_URL = '{}/me/submissions/assigned.json'.format(BASE_URL) 30 | 31 | REVIEW_URL = 'https://review.udacity.com/#!/submissions/{sid}' 32 | REQUESTS_PER_SECOND = 1 # Please leave this alone. 33 | 34 | WAIT_URL = '{}/submission_requests/{}/waits.json' 35 | 36 | 37 | # Get a list of contacts 38 | project = {} 39 | 40 | 41 | logging.basicConfig(format='|%(asctime)s| %(message)s') 42 | logger = logging.getLogger(__name__) 43 | logger.setLevel(logging.INFO) 44 | 45 | headers = None 46 | 47 | def request_reviews(token): 48 | global headers 49 | headers = {'Authorization': token, 'Content-Length': '0'} 50 | 51 | me_req_resp = requests.get(ME_REQUEST_URL, headers=headers) 52 | current_request = me_req_resp.json()[0] if me_req_resp.status_code == 200 and len(me_req_resp.json()) > 0 else None 53 | 54 | if current_request is None: 55 | print("Run the grading assigner first") 56 | return 57 | else: 58 | certs_resp = requests.get(CERTS_URL, headers=headers) 59 | certs_resp.raise_for_status() 60 | certs = certs_resp.json() 61 | 62 | project_ids = [cert['project']['id'] for cert in certs if cert['status'] == 'certified'] 63 | project_names = [cert['project']['name'] for cert in certs if cert['status'] == 'certified'] 64 | project_prices = [cert['project']['price'] for cert in certs if cert['status'] == 'certified'] 65 | 66 | for p in range(0,len(project_ids)): 67 | project[project_ids[p]] = project_names[p].split(":")[0] + ": $" + project_prices[p] 68 | 69 | 70 | # print(current_request['id']) 71 | url = WAIT_URL.format(BASE_URL, current_request['id']) 72 | get_req_respo = requests.get(url, headers=headers) 73 | wait_request = get_req_respo.json() if get_req_respo.status_code == 200 and len(get_req_respo.json()) > 0 else None 74 | 75 | old_wait_request = wait_request 76 | 77 | while True: 78 | if current_request is None: 79 | print("Run the grading assigner first") 80 | return 81 | else: 82 | 83 | current_request = me_req_resp.json()[0] if me_req_resp.status_code == 200 and len(me_req_resp.json()) > 0 else None 84 | if current_request is None: 85 | print("Run the grading assigner first") 86 | return 87 | # print(current_request['id']) 88 | url = WAIT_URL.format(BASE_URL, current_request['id']) 89 | get_req_respo = requests.get(url, headers=headers) 90 | wait_request = get_req_respo.json() if get_req_respo.status_code == 200 and len(get_req_respo.json()) > 0 else None 91 | os.system('clear') 92 | for i in range(0,len(wait_request)): 93 | position = wait_request[i]["position"] 94 | project_id = wait_request[i]["project_id"] 95 | 96 | if (len(old_wait_request) > 0 and (position != old_wait_request[i]["position"])): 97 | # print(colored(str(position),attrs = ['bold','blink']) + " : " + colored(project[project_id],attrs=['bold','blink'])) 98 | print(colored(str(position),attrs = ['bold']) + " : " + colored(project[project_id],attrs=['bold']) + "(" + str(old_wait_request[i]["position"] - position) +")") 99 | else: 100 | print(str(position) + " : " + project[project_id]) 101 | 102 | time.sleep(5.0) 103 | 104 | 105 | if __name__ == "__main__": 106 | cmd_parser = argparse.ArgumentParser(description = 107 | "Find where you stand in the queue" 108 | ) 109 | cmd_parser.add_argument('--auth-token', '-T', dest='token', 110 | metavar='TOKEN', type=str, 111 | action='store', default=os.environ.get('UDACITY_AUTH_TOKEN'), 112 | help=""" 113 | Your Udacity auth token. To obtain, login to review.udacity.com, open the Javascript console, and copy the output of `JSON.parse(localStorage.currentUser).token`. This can also be stored in the environment variable UDACITY_AUTH_TOKEN. 114 | """ 115 | ) 116 | cmd_parser.add_argument('--debug', '-d', action='store_true', help='Turn on debug statements.') 117 | args = cmd_parser.parse_args() 118 | 119 | if not args.token: 120 | cmd_parser.print_help() 121 | cmd_parser.exit() 122 | 123 | if args.debug: 124 | logger.setLevel(logging.DEBUG) 125 | 126 | request_reviews(args.token) 127 | 128 | --------------------------------------------------------------------------------