-
Notifications
You must be signed in to change notification settings - Fork 933
Codeforces contests to Google Calendar #896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hey @Iron0utlaw, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there,
Sorry it took so long to review. I was hoping @unnamedd would lend a hand here since my Python knowledge is fairly low 😛
I left below some comments; aside from that and as far as I understand, this script would generate a further 3 files: token.json
, creds.json
, and data.txt
. I am not a big fan of that. Do you have any suggestion @unnamedd on how to not have so many lingering files?
|
||
# Required parameters: | ||
# @raycast.schemaVersion 1 | ||
# @raycast.title Add Codeforces Contests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @raycast.title
and @raycast.packageName
will appear together in the RootSearch. Therefor I suggest you short this up to:
# @raycast.title Add Contests
'description': 'Codeforces Contest', | ||
'start': { | ||
'dateTime': start_time, | ||
'timeZone': 'Asia/Kolkata', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is hardcoded to Kolkata in the middle of the code, it would be better to extract the timezone in a variable at the beginning of the code so it is easy to change for users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Iron0utlaw, 👋
thanks for contributing to our repository.
I wrote some comments for you.
Please, read them carefully because there are too many things we need to discuss before moving on (or not).
As soon as you finish to address them, please re-request a review for a second round.
# @raycast.packageName Codeforces | ||
|
||
# Documentation: | ||
# @raycast.description Adds codeforces contests to Google Calendar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# @raycast.description Adds codeforces contests to Google Calendar | |
# @raycast.description Adds Codeforces contests to Google Calendar |
|
||
# Documentation: | ||
# @raycast.description Adds codeforces contests to Google Calendar | ||
# @raycast.author Harsh Varshney |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# @raycast.author Harsh Varshney | |
# @raycast.authorURL https://github.com/Iron0utlaw |
@@ -0,0 +1,117 @@ | |||
#!/usr/bin/env python3 | |||
|
|||
# Install dependencies using "pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib requests" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few things I would like to raise here:
- The setup for this Script Command is not straightforward, which means that would be great if we could add the link to the Google Quickstart in order to help your user, like Google did

As far as I could see, it is not possible to not have the credentials directly here in the code itself, they need to read from credentials.json
because they will rewrite the file after finishing the authorisation process.
-
The dependencies needed to use the Script Command, you must keep them as minimum as you can.
-
Personally speaking, I'd rather to have a README file with instructions of what need to be done and installed, and also, I'd create a
requirements.txt
with all the dependencies needed to your Script Command (you can do that just runningpip3 freeze > requirements.txt
or just copying clicking in the link) -
Even though with all of that, worth to mention that Raycast run the Script Commands in a non-login environment, which means that, even with your user installing the dependencies they may not run your Script Command properly, not because of your implementation, but because of Raycast itself.
If you check my screenshot, I couldn't import requests
(one of your Python dependencies) because where the Script Command is running, requests
wasn't installed.

Which lead me to a (stupid, sorry) question: have you ever tested your Script Command on Raycast or just using the Terminal?
import os.path | ||
import time | ||
import json | ||
from pip._vendor import requests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am quite sure import requests
is more than enough.
'description': 'Codeforces Contest', | ||
'start': { | ||
'dateTime': start_time, | ||
'timeZone': 'Asia/Kolkata', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
now = time.time() | ||
LINK = "https://codeforces.com/api/contest.list?gym=false" | ||
|
||
res = requests.get(LINK) | ||
resjson = res.json() | ||
|
||
data = load_set_from_file('data.txt') | ||
|
||
for con in resjson["result"]: | ||
if con["relativeTimeSeconds"] > 0: | ||
break | ||
if con["id"] not in data: | ||
add_event(con) | ||
data.add(con["id"]) | ||
|
||
save_set_to_file('data.txt',data) | ||
|
||
print("Success") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be awesome if you convert that piece of code from the root of the file into a function.
now = time.time() | |
LINK = "https://codeforces.com/api/contest.list?gym=false" | |
res = requests.get(LINK) | |
resjson = res.json() | |
data = load_set_from_file('data.txt') | |
for con in resjson["result"]: | |
if con["relativeTimeSeconds"] > 0: | |
break | |
if con["id"] not in data: | |
add_event(con) | |
data.add(con["id"]) | |
save_set_to_file('data.txt',data) | |
print("Success") | |
def load_content(): | |
now = time.time() | |
LINK = "https://codeforces.com/api/contest.list?gym=false" | |
res = requests.get(LINK) | |
resjson = res.json() | |
data = load_set_from_file('data.txt') | |
for con in resjson["result"]: | |
if con["relativeTimeSeconds"] > 0: | |
break | |
if con["id"] not in data: | |
add_event(con) | |
data.add(con["id"]) | |
save_set_to_file('data.txt',data) | |
print("Success") | |
if __name__ == "__main__": | |
load_content() |
def jprint(obj): | ||
text = json.dumps(obj, sort_keys=True, indent=4) | ||
print(text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not being used anywhere.
def jprint(obj): | |
text = json.dumps(obj, sort_keys=True, indent=4) | |
print(text) |
data = json.load(file) | ||
return set(data) | ||
except FileNotFoundError: | ||
return set() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As part of the process of informing your user about something is missing, would be great if you print in the exception which file is missing instead of just returning a set()
, or (as you are only using to load data.txt
, you may create the file instead of showing an error.
if os.path.exists("token.json"): | ||
creds = Credentials.from_authorized_user_file("token.json", SCOPES) | ||
|
||
if not creds or not creds.valid: | ||
if creds and creds.expired and creds.refresh_token: | ||
creds.refresh(Request()) | ||
else: | ||
flow = InstalledAppFlow.from_client_secrets_file( | ||
"creds.json", SCOPES | ||
) | ||
creds = flow.run_local_server(port=0) | ||
|
||
with open("token.json", "w") as token: | ||
token.write(creds.to_json()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not good to run the authorisation process every single time you call add_event
.
You must extract that process from here into another method and call it before calling add_event
, because this method is being called inside of a for-loop
.
Hey @Iron0utlaw, Do you intend to work on this PR? |
Yes, I will start working on this |
Description
This script command is designed to incorporate upcoming Codeforces contests into Google Calendar. It leverages the Codeforces public API to retrieve information about the upcoming contests and utilizes the Google Calendar API to add them. To keep track of previously added contests, the script utilizes a
data.txt
file to store the corresponding contest IDs.Type of change
Screenshot
Dependencies / Requirements
Dependencies
API Credentials
credentials.json
ascreds.json
to the folderChecklist
@unnamedd @zzamboni It would be great if you guys could review this PR