My Codeforces Journal is a Chrome extension that helps Codeforces users track the problems they've solved. With just a click, the extension stores the details of the current problem to a Google Spreadsheet that the user has connected. This makes it easy to maintain a personal log of problems solved over time.
Want to contribute to this chrom-extension? Go to this repo :My Codeforces Journal Development
- One-click Storage: Save the current Codeforces problem you’ve solved with a single click.
- Spreadsheet Integration: Link your own Google Spreadsheet to store and organize problems in a format that suits you.
- Problem Details Captured: The extension stores key information such as problem URL, problem name, and problem rating.
Watch this youtube video: How to get started with My Codeforces Journal
Before you can use the extension, make sure you have the following:
- A Google Spreadsheet where the problems will be stored.
- The Codeforces Journal Chrome extension installed and authorized to access your spreadsheet.
- Make sure to read COMMON ERRORS SECTION at the end of this.
- Download the
dist
folder from the following link: My Codeforces Journal - Open Chrome and go to
chrome://extensions/
. - Enable Developer mode in the top right corner.
- Click on Load unpacked and select the folder where the
dist
folder is saved. - The extension should now be visible on your extensions page.
- Pin the extension on the toolbar for easy use.
- Create a new Google Spreadsheet.
- Name the Spreadsheet as you prefer.
- Click on the "Extensions" menu, and then click on "App Script."
- Click on "Untitled" and rename this App Script file to match the name of your Spreadsheet.
- Copy the code below and paste it into the App Script editor, and save by keypressing
cmd + S
/ctrl + S
- Click on the "Deploy" button in the top right and choose "New Deployment."
- Add a description of your choice ( could be same as your SpreadSheet's name ).
- Set "Who has access" to "Anyone."
- Click "Deploy" and authorize the App Script,
- Upon clicking authorize, select the Google Account you used to create the SpreadSheet, and then you'll be shown a "Google hasn't verified this app" message
- Click on Advanced at the bottom and,
- Click on the name of the AppScript project shown, then click Allow
- Redeploy the AppScript project just to make sure your project has been authorized properly
- Copy the script URL, as this is your AppScript URL, and save it for later use in the extension.
- Again click on "Deploy" button
- Select "Manage deployments", and then a modal will show up
- Click on the "Edit" button ( the Pen icon ), and now the "deploy" button at the bottom will become active
- Click on deploy
- If there exists some error with authorization, then you will be shown the authorize button again, or else you'll be shown to copy the script URL
function doPost(e) {
try {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
// Parse the incoming request data
var data;
try {
data = JSON.parse(e.postData.contents);
} catch (parseError) {
return ContentService.createTextOutput('{"status":"error","message":"Invalid JSON format."}').setMimeType(ContentService.MimeType.TEXT);
}
// Check if the request is to check for an existing problem
if (data.action === "checkProblem") {
const problemNameColumn = sheet
.getRange("B2:B" + sheet.getLastRow())
.getValues()
.flat();
const problemExists = problemNameColumn.includes(data.problemName);
return ContentService.createTextOutput(JSON.stringify({ status: "success", exists: problemExists })).setMimeType(ContentService.MimeType.JSON);
}
// (Your existing 'initialize' and 'addProblem' logic here)
if (data.action === "initialize") {
var headers = ["Rating", "Problem", "Status", "Remarks", "Date", "Takeaway", "Topics"];
if (sheet.getLastRow() === 0 || sheet.getRange("A1").getValue() === "") {
// Initialization logic remains the same
sheet.getRange("A1:G1").merge();
sheet.getRange("A1").setValue("Codeforces Sheet");
sheet.getRange("A1").setFontSize(13).setHorizontalAlignment("center").setBackground("#ffd966");
sheet.getRange("A2:G2").setValues([headers]);
sheet.getRange("A2:G2").setFontSize(12).setHorizontalAlignment("center").setBackground("#93c47d");
sheet.setColumnWidth(1, 75);
sheet.setColumnWidth(2, 185);
sheet.setColumnWidth(3, 155);
sheet.setColumnWidth(4, 290);
sheet.setColumnWidth(5, 80);
sheet.setColumnWidth(6, 530);
sheet.setColumnWidth(7, 190);
sheet.getRange("A2:G1000").setVerticalAlignment("middle");
sheet.getRange("C2:C1000").setWrap(true);
sheet.getRange("D2:D1000").setWrap(true);
sheet.getRange("F2:F1000").setWrap(true);
sheet.getRange("G2:G1000").setWrap(true);
sheet.getRange("A2:A1000").setHorizontalAlignment("center");
sheet.getRange("B2:B1000").setHorizontalAlignment("center");
sheet.getRange("E2:E1000").setHorizontalAlignment("center");
sheet.getRange("G2:G1000").setHorizontalAlignment("center");
var newDate = new Date();
sheet.getRange("E3:E1000").setNumberFormat("dd-mmm-yyyy");
sheet.insertRowBefore(3);
sheet
.getRange("A3:G3")
.setValues([
[9999, "Problem9999Z", "Solved", "Could not implement my intuition", newDate, "I understood how recursion works", "Recursion, DP, Graph"],
]);
return ContentService.createTextOutput(
'{"status":"success","message":"Headers initialized with formatting, custom column widths, and row added."}'
).setMimeType(ContentService.MimeType.TEXT);
} else {
return ContentService.createTextOutput('{"status":"success","message":"Headers already exist."}').setMimeType(ContentService.MimeType.TEXT);
}
} else if (data.action === "addProblem") {
try {
const newRow = [data.problemRating, data.problemName, data.problemStatus, data.remarks, data.dateSolved, data.takeaways, data.problemTopics];
const lastRow = sheet.getLastRow() + 1;
sheet.appendRow(newRow);
const problemNameCell = sheet.getRange(lastRow, 2);
if (data.problemUrl) {
problemNameCell.setValue(data.problemName).setFormula(`=HYPERLINK("${data.problemUrl}", "${data.problemName}")`);
}
return ContentService.createTextOutput('{"status":"success","message":"Problem data added with hyperlink."}').setMimeType(
ContentService.MimeType.JSON
);
} catch (addError) {
return ContentService.createTextOutput('{"status":"error","message":"Failed to add problem data."}').setMimeType(
ContentService.MimeType.TEXT
);
}
}
} catch (error) {
return ContentService.createTextOutput('{"status":"error","message":"' + error.message + '"}').setMimeType(ContentService.MimeType.TEXT);
}
}
- Open any Codeforces problem page.
- Once you’ve solved the problem, click on the My Codeforces Journal extension icon, and then click on "Add Problem."
- Fill in the form, and press "Submit."
- The problem details will be automatically saved to the connected spreadsheet.
This extension requires the following permissions:
- Active Tab: To access the URL of the current tab when saving the problem.
- Storage: To store your connected spreadsheet details.
- Scripting: To run JavaScript
- Cause: This typically occurs if a non-existing Codeforces ID was submitted.
- Solution: Double-check the ID and ensure it's correct.
- Cause: This error generally means the AppScript URL provided is incorrect.
- Solution: Verify the URL and use the correct AppScript URL.
- Additional Tip: This error may also appear if your AppScript Project hasn’t been properly authorized. To ensure proper authorization:
- During the spreadsheet setup, deploy your AppScript Project twice; the second deployment will help confirm the AppScript Project is fully authorized.
- Cause: This occurs if the problem you’re trying to add has not been solved within your last 40 submissions on Codeforces.
- Solution: Ensure you’ve solved the problem recently. If not, attempt it on Codeforces before adding it to the Spreadsheet.