diff --git a/cache/cache.json b/cache/cache.json
new file mode 100644
index 0000000..5f97dee
--- /dev/null
+++ b/cache/cache.json
@@ -0,0 +1,656 @@
+{
+ "accountData": {
+ "account": "Artem_Korsakov",
+ "alias": "Artem Korsakov",
+ "location": "Russia",
+ "language": "Scala"
+ },
+ "progressData": {
+ "level": "Level 4",
+ "solved": 118,
+ "percentage": 12.6,
+ "progress": "Solved 118 out of 936 problems (12.6%)",
+ "toTheNext": "7 problems away from level 5"
+ },
+ "euleriansPlace": "You are not in Eulerians' rating",
+ "locationUrl": "https://projecteuler.net/location=Russia",
+ "languageUrl": "https://projecteuler.net/language=Scala",
+ "locationRating": {
+ "place": 999999,
+ "top100": 204,
+ "top50": 287,
+ "top25": 387,
+ "top10": 527,
+ "top5": 810,
+ "top1": 900
+ },
+ "languageRating": {
+ "place": 82,
+ "top100": 108,
+ "top50": 140,
+ "top25": 177,
+ "top10": 250,
+ "top5": 374,
+ "top1": 786
+ },
+ "levelDataArray": [
+ {
+ "level": "Level 1",
+ "members": "71201 members"
+ },
+ {
+ "level": "Level 2",
+ "members": "32115 members"
+ },
+ {
+ "level": "Level 3",
+ "members": "12279 members"
+ },
+ {
+ "level": "Level 4",
+ "members": "6199 members"
+ },
+ {
+ "level": "Level 5",
+ "members": "3074 members"
+ },
+ {
+ "level": "Level 6",
+ "members": "1908 members"
+ },
+ {
+ "level": "Level 7",
+ "members": "1048 members"
+ },
+ {
+ "level": "Level 8",
+ "members": "769 members"
+ },
+ {
+ "level": "Level 9",
+ "members": "537 members"
+ },
+ {
+ "level": "Level 10",
+ "members": "381 members"
+ },
+ {
+ "level": "Level 11",
+ "members": "249 members"
+ },
+ {
+ "level": "Level 12",
+ "members": "199 members"
+ },
+ {
+ "level": "Level 13",
+ "members": "159 members"
+ },
+ {
+ "level": "Level 14",
+ "members": "126 members"
+ },
+ {
+ "level": "Level 15",
+ "members": "90 members"
+ },
+ {
+ "level": "Level 16",
+ "members": "91 members"
+ },
+ {
+ "level": "Level 17",
+ "members": "78 members"
+ },
+ {
+ "level": "Level 18",
+ "members": "59 members"
+ },
+ {
+ "level": "Level 19",
+ "members": "45 members"
+ },
+ {
+ "level": "Level 20",
+ "members": "39 members"
+ },
+ {
+ "level": "Level 21",
+ "members": "38 members"
+ },
+ {
+ "level": "Level 22",
+ "members": "29 members"
+ },
+ {
+ "level": "Level 23",
+ "members": "27 members"
+ },
+ {
+ "level": "Level 24",
+ "members": "28 members"
+ },
+ {
+ "level": "Level 25",
+ "members": "19 members"
+ },
+ {
+ "level": "Level 26",
+ "members": "15 members"
+ },
+ {
+ "level": "Level 27",
+ "members": "12 members"
+ },
+ {
+ "level": "Level 28",
+ "members": "13 members"
+ },
+ {
+ "level": "Level 29",
+ "members": "15 members"
+ },
+ {
+ "level": "Level 30",
+ "members": "14 members"
+ },
+ {
+ "level": "Level 31",
+ "members": "14 members"
+ },
+ {
+ "level": "Level 32",
+ "members": "9 members"
+ },
+ {
+ "level": "Level 33",
+ "members": "10 members"
+ },
+ {
+ "level": "Level 34",
+ "members": "11 members"
+ },
+ {
+ "level": "Level 35",
+ "members": "13 members"
+ },
+ {
+ "level": "Level 36",
+ "members": "43 members"
+ }
+ ],
+ "awardsData": [
+ {
+ "name": "Problem Solving Awards",
+ "awards": [
+ {
+ "award": "Baby Steps",
+ "link": "https://projecteuler.net/award=1",
+ "description": "Solve three problems",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "615578 members"
+ },
+ {
+ "award": "The Journey Begins",
+ "link": "https://projecteuler.net/award=2",
+ "description": "Progress to Level 1 by solving twenty-five problems",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "119573 members"
+ },
+ {
+ "award": "Decathlete",
+ "link": "https://projecteuler.net/award=3",
+ "description": "Solve ten consecutive problems",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "267966 members"
+ },
+ {
+ "award": "Flawless Fifty",
+ "link": "https://projecteuler.net/award=4",
+ "description": "Solve fifty consecutive problems",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "36441 members"
+ },
+ {
+ "award": "C for Commitment",
+ "link": "https://projecteuler.net/award=5",
+ "description": "Complete any grid",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "6975 members"
+ },
+ {
+ "award": "CC for Continued Commitment",
+ "link": "https://projecteuler.net/award=6",
+ "description": "Complete any two grids",
+ "isCompleted": false,
+ "progress": "0 / 2",
+ "percentage": 0,
+ "members": "851 members"
+ },
+ {
+ "award": "D for Dedication",
+ "link": "https://projecteuler.net/award=7",
+ "description": "Complete any five grids",
+ "isCompleted": false,
+ "progress": "0 / 5",
+ "percentage": 0,
+ "members": "76 members"
+ },
+ {
+ "award": "Three Strikes!",
+ "link": "https://projecteuler.net/award=8",
+ "description": "Get the diagonals in any three grids",
+ "isCompleted": false,
+ "progress": "1 / 3",
+ "percentage": 33.33,
+ "members": "128 members"
+ },
+ {
+ "award": "Perfect Game",
+ "link": "https://projecteuler.net/award=9",
+ "description": "Get the diagonals in all possible grids",
+ "isCompleted": false,
+ "progress": "1 / 9",
+ "percentage": 11.11,
+ "members": "25 members"
+ },
+ {
+ "award": "As Easy As Pi",
+ "link": "https://projecteuler.net/award=11",
+ "description": "Solve problems 3, 14, 15, 92, 65, 35, 89, 79, 32, 38, and 46",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "17963 members"
+ },
+ {
+ "award": "Unlucky Squares",
+ "link": "https://projecteuler.net/award=12",
+ "description": "Solve thirteen square numbered problems",
+ "isCompleted": false,
+ "progress": "11 / 13",
+ "percentage": 84.62,
+ "members": "4823 members"
+ },
+ {
+ "award": "Triangle Trophy",
+ "link": "https://projecteuler.net/award=13",
+ "description": "Solve all the triangle numbered problems below 100",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "2088 members"
+ },
+ {
+ "award": "Square Triangle",
+ "link": "https://projecteuler.net/award=14",
+ "description": "Solve thirty-six triangle numbered problems",
+ "isCompleted": false,
+ "progress": "14 / 36",
+ "percentage": 38.89,
+ "members": "133 members"
+ },
+ {
+ "award": "Prime Obsession",
+ "link": "https://projecteuler.net/award=15",
+ "description": "Solve fifty prime numbered problems",
+ "isCompleted": false,
+ "progress": "27 / 50",
+ "percentage": 54,
+ "members": "2461 members"
+ },
+ {
+ "award": "Trinary Triumph",
+ "link": "https://projecteuler.net/award=16",
+ "description": "Solve problems 1, 3, 9, 27, 81, 243, and 729",
+ "isCompleted": false,
+ "progress": "6 / 7",
+ "percentage": 85.71,
+ "members": "203 members"
+ },
+ {
+ "award": "Fibonacci Fever",
+ "link": "https://projecteuler.net/award=17",
+ "description": "Solve thirteen Fibonacci numbered problems",
+ "isCompleted": false,
+ "progress": "10 / 13",
+ "percentage": 76.92,
+ "members": "2021 members"
+ },
+ {
+ "award": "Daring Dozen",
+ "link": "https://projecteuler.net/award=18",
+ "description": "Solve twelve problems with an ID containing three digits",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "16821 members"
+ },
+ {
+ "award": "Lucky Luke",
+ "link": "https://projecteuler.net/award=19",
+ "description": "Solve fifty lucky numbered problems",
+ "isCompleted": false,
+ "progress": "24 / 50",
+ "percentage": 48,
+ "members": "1659 members"
+ },
+ {
+ "award": "Decimator",
+ "link": "https://projecteuler.net/award=21",
+ "description": "Solve one in every ten problems from problems 101 to 200",
+ "isCompleted": false,
+ "progress": "3 / 10",
+ "percentage": 30,
+ "members": "5281 members"
+ },
+ {
+ "award": "Trecenti Decimator",
+ "link": "https://projecteuler.net/award=22",
+ "description": "Solve one in every ten problems for the first 300 problems",
+ "isCompleted": false,
+ "progress": "15 / 30",
+ "percentage": 50,
+ "members": "2075 members"
+ },
+ {
+ "award": "Sicarius Decimator",
+ "link": "https://projecteuler.net/award=23",
+ "description": "I see a target. Good hunting, 47",
+ "isCompleted": false,
+ "progress": "20 / 47",
+ "percentage": 42.55,
+ "members": "1728 members"
+ },
+ {
+ "award": "Ultimus Decimator",
+ "link": "https://projecteuler.net/award=24",
+ "description": "Solve one in every ten problems in the archives",
+ "isCompleted": false,
+ "progress": "20 / 92",
+ "percentage": 21.74,
+ "members": "214 members"
+ },
+ {
+ "award": "One Percenter",
+ "link": "https://projecteuler.net/award=25",
+ "description": "Better than 99% = One badass problem solver",
+ "isCompleted": true,
+ "progress": "",
+ "percentage": 0,
+ "members": "10101 members"
+ },
+ {
+ "award": "High Flyer",
+ "link": "https://projecteuler.net/award=26",
+ "description": "Progress to the maximum level",
+ "isCompleted": false,
+ "progress": "4 / 36",
+ "percentage": 11.11,
+ "members": "69 members"
+ },
+ {
+ "award": "Perfection",
+ "link": "https://projecteuler.net/",
+ "description": "Solve every problem",
+ "isCompleted": false,
+ "progress": "118 / 936",
+ "percentage": 12.61,
+ "members": "0 members"
+ },
+ {
+ "award": "The Archivist",
+ "link": "https://projecteuler.net/award=28",
+ "description": "Solve half of the problems in the archives",
+ "isCompleted": false,
+ "progress": "118 / 463",
+ "percentage": 25.49,
+ "members": "558 members"
+ },
+ {
+ "award": "Master of Archives",
+ "link": "https://projecteuler.net/award=29",
+ "description": "Solve every problem in the archives",
+ "isCompleted": false,
+ "progress": "118 / 926",
+ "percentage": 12.74,
+ "members": "22 members"
+ },
+ {
+ "award": "On The Ball",
+ "link": "https://projecteuler.net/award=31",
+ "description": "Solve the most recent problem",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "7068 members"
+ },
+ {
+ "award": "High Five",
+ "link": "https://projecteuler.net/award=32",
+ "description": "Solve the five most recent problems",
+ "isCompleted": false,
+ "progress": "0 / 5",
+ "percentage": 0,
+ "members": "1090 members"
+ },
+ {
+ "award": "Ten Out Of Ten",
+ "link": "https://projecteuler.net/award=33",
+ "description": "Solve the ten most recent problems",
+ "isCompleted": false,
+ "progress": "0 / 10",
+ "percentage": 0,
+ "members": "596 members"
+ },
+ {
+ "award": "State Of The Art",
+ "link": "https://projecteuler.net/award=34",
+ "description": "Solve the twenty-five most recent problems",
+ "isCompleted": false,
+ "progress": "0 / 25",
+ "percentage": 0,
+ "members": "293 members"
+ },
+ {
+ "award": "Unknown Conqueror",
+ "link": "https://projecteuler.net/award=35",
+ "description": "Five times lucky, five times smart",
+ "isCompleted": false,
+ "progress": "0 / 5",
+ "percentage": 0,
+ "members": "20 members"
+ },
+ {
+ "award": "One In A Hundred",
+ "link": "https://projecteuler.net/award=41",
+ "description": "Be among the first hundred to solve a problem",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "5021 members"
+ },
+ {
+ "award": "Chart Topper",
+ "link": "https://projecteuler.net/award=42",
+ "description": "Be among the first ten to solve a problem",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "671 members"
+ },
+ {
+ "award": "Gold Medal",
+ "link": "https://projecteuler.net/award=43",
+ "description": "The first to solve a problem",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "133 members"
+ },
+ {
+ "award": "Tag Explorer",
+ "link": "https://projecteuler.net/award=45",
+ "description": "Solve at least one problem for one-hundred different tags",
+ "isCompleted": false,
+ "progress": "68 / 100",
+ "percentage": 68,
+ "members": "694 members"
+ },
+ {
+ "award": "Easy Prey",
+ "link": "https://projecteuler.net/award=51",
+ "description": "Solve the fifty easiest problems",
+ "isCompleted": false,
+ "progress": "49 / 50",
+ "percentage": 98,
+ "members": "65328 members"
+ },
+ {
+ "award": "Big Game Hunter",
+ "link": "https://projecteuler.net/award=52",
+ "description": "Solve twenty-five of the fifty hardest problems",
+ "isCompleted": false,
+ "progress": "0 / 25",
+ "percentage": 0,
+ "members": "138 members"
+ },
+ {
+ "award": "Difficulty Explorer",
+ "link": "https://projecteuler.net/award=53",
+ "description": "Solve at least one problem at ten different difficulty levels",
+ "isCompleted": false,
+ "progress": "9 / 10",
+ "percentage": 90,
+ "members": "8358 members"
+ },
+ {
+ "award": "Conquering Difficulties",
+ "link": "https://projecteuler.net/award=54",
+ "description": "Solve at least one problem at all of the difficulty levels",
+ "isCompleted": false,
+ "progress": "9 / 20",
+ "percentage": 45,
+ "members": "518 members"
+ },
+ {
+ "award": "Mount Euler",
+ "link": "https://projecteuler.net/award=55",
+ "description": "Mastering the mountain of difficulty",
+ "isCompleted": false,
+ "progress": "1 / 20",
+ "percentage": 5,
+ "members": "63 members"
+ },
+ {
+ "award": "The Centenarian",
+ "link": "https://projecteuler.net/award=59",
+ "description": "Solved a problem on one-hundred different days",
+ "isCompleted": false,
+ "progress": "31 / 100",
+ "percentage": 31,
+ "members": "647 members"
+ }
+ ]
+ },
+ {
+ "name": "Contributor Awards",
+ "awards": [
+ {
+ "award": "Bright Spark",
+ "link": "https://projecteuler.net/award=61",
+ "description": "Contributed to the development of a problem",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "147 members"
+ },
+ {
+ "award": "Brainstormer",
+ "link": "https://projecteuler.net/award=62",
+ "description": "Contributed to the development of five or more problems",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "52 members"
+ }
+ ]
+ },
+ {
+ "name": "Forum Based Awards",
+ "awards": [
+ {
+ "award": "Hello World!",
+ "link": "https://projecteuler.net/award=91",
+ "description": "Made your first permanent post",
+ "isCompleted": false,
+ "progress": "",
+ "percentage": 0,
+ "members": "5522 members"
+ },
+ {
+ "award": "Wise Words",
+ "link": "https://projecteuler.net/award=92",
+ "description": "Received five Kudos across all your permanent posts",
+ "isCompleted": false,
+ "progress": "0 / 5",
+ "percentage": 0,
+ "members": "1126 members"
+ },
+ {
+ "award": "Valued Expositor",
+ "link": "https://projecteuler.net/award=93",
+ "description": "Received twenty-five Kudos across all your permanent posts",
+ "isCompleted": false,
+ "progress": "0 / 25",
+ "percentage": 0,
+ "members": "411 members"
+ },
+ {
+ "award": "Esteemed Journalist",
+ "link": "https://projecteuler.net/award=94",
+ "description": "Received one-hundred Kudos across all your permanent posts",
+ "isCompleted": false,
+ "progress": "0 / 100",
+ "percentage": 0,
+ "members": "151 members"
+ },
+ {
+ "award": "The Guru",
+ "link": "https://projecteuler.net/award=95",
+ "description": "Received ten Kudos for a permanent post in a single problem thread",
+ "isCompleted": false,
+ "progress": "0 / 10",
+ "percentage": 0,
+ "members": "459 members"
+ }
+ ]
+ }
+ ],
+ "friends": [
+ {
+ "rank": "1",
+ "username": "fonkost",
+ "solved": 385,
+ "level": 15,
+ "awards": 21
+ },
+ {
+ "rank": "2",
+ "username": "Artem Korsakov",
+ "solved": 118,
+ "level": 4,
+ "awards": 8
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 446fc0a..695b883 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -13,18 +13,22 @@ tasks, awards, and friends' rankings.
## Features
1. **Profile Information**:
+
- Displays your Project Euler account details, including username, alias, location,
programming language, level, and number of solved problems.
2. **Progress Overview**:
+
- Shows your overall progress, including the percentage of problems solved
and your rankings in global, regional, and language-specific leaderboards.
3. **Tasks**:
+
- Lists your current tasks, such as the number of problems remaining
to reach the next level or improve your rankings.
4. **Awards**:
+
- Displays your progress toward earning Project Euler awards, including both completed and uncompleted awards.
5. **Friends**:
@@ -110,10 +114,10 @@ Solve problem 15; 27.1%
### Location progress
-This section provides an overview of your ranking in the **Location rating** on Project Euler.
-Currently, this account is **not in the Top 100**, with **118 problems solved**.
-The table below breaks down the number of problems required to reach higher ranks,
-such as Top 100, Top 50, Top 25, Top 10, Top 5, and Top 1,
+This section provides an overview of your ranking in the **Location rating** on Project Euler.
+Currently, this account is **not in the Top 100**, with **118 problems solved**.
+The table below breaks down the number of problems required to reach higher ranks,
+such as Top 100, Top 50, Top 25, Top 10, Top 5, and Top 1,
along with the number of problems remaining to achieve each milestone.
This section helps you track your progress and set goals for climbing the ranks in the Location leaderboard.
@@ -123,9 +127,9 @@ This section helps you track your progress and set goals for climbing the ranks
### Language progress
This section highlights your ranking in the **Language rating** on Project Euler.
-This account is currently in **82nd place**, with **118 problems solved**.
-The table outlines the number of problems needed to advance to higher ranks,
-such as Top 50, Top 25, Top 10, Top 5, and Top 1,
+This account is currently in **82nd place**, with **118 problems solved**.
+The table outlines the number of problems needed to advance to higher ranks,
+such as Top 50, Top 25, Top 10, Top 5, and Top 1,
along with the remaining problems required for each milestone.
This section helps you track your progress and set goals for climbing the ranks in the Language leaderboard.
@@ -134,10 +138,10 @@ This section helps you track your progress and set goals for climbing the ranks
### Level progress
-This section provides an overview of your **level progression** on Project Euler.
-It displays your current level, the number of problems you've solved,
-and how close you are to reaching the next levels.
-Additionally, it shows how many members have achieved each level,
+This section provides an overview of your **level progression** on Project Euler.
+It displays your current level, the number of problems you've solved,
+and how close you are to reaching the next levels.
+Additionally, it shows how many members have achieved each level,
giving you a sense of your standing within the community.
This section is designed to help you stay motivated and focused on your journey through Project Euler's levels.
@@ -147,11 +151,11 @@ Keep solving problems to climb higher and join the ranks of the top members!
### Awards
-This section provides an overview of the **awards** you can earn on Project Euler.
-Awards are divided into three categories: **Problem Solving Awards**, **Contributor Awards**, and **Forum Based Awards**.
+This section provides an overview of the **awards** you can earn on Project Euler.
+Awards are divided into three categories: **Problem Solving Awards**, **Contributor Awards**, and **Forum Based Awards**.
Each award has a description, the number of members who have earned it, and a progress bar to track your progress.
-This section helps you stay motivated by showcasing your achievements and highlighting areas for improvement.
+This section helps you stay motivated by showcasing your achievements and highlighting areas for improvement.
Keep solving problems, contributing, and engaging with the community to unlock more awards!
diff --git a/helpers/fetchProgress.ts b/helpers/fetchProgress.ts
index b29479b..030b05a 100644
--- a/helpers/fetchProgress.ts
+++ b/helpers/fetchProgress.ts
@@ -1,4 +1,5 @@
import { fetchWithCookies } from './fetchUtils';
+import { saveDataToFile, loadDataFromFile, checkFileExists, ensureFolderExists } from './fileUtils';
import {
parseAccountData,
parseAwardsData,
@@ -17,6 +18,7 @@ import { generateFriendsHTML } from './friendsBlock';
import {
AccountData,
AwardBlockData,
+ CacheData,
FriendData,
LevelData,
PersonalTask,
@@ -33,24 +35,58 @@ const keepAliveName = 'keep_alive';
* Fetches progress data and returns it as an HTMLElement.
* @param session - The session cookie value.
* @param keep_alive - The keep-alive cookie value.
- * @param retries - The number of retries in case of failure.
+ * @param source - The source data for generating HTML.
* @returns A Promise that resolves to an HTMLElement.
*/
export async function fetchProgress(session: string, keep_alive: string, source: Source): Promise {
- const cookies = `${sessionIdName}=${session}; ${keepAliveName}=${keep_alive}`;
+ // Define the path to the plugin's cache folder and ensure it exists
+ const folderPath = getPluginFolderPath();
+ await ensureFolderExists(folderPath);
+ const filePath = `${folderPath}/cache.json`;
+
+ // Attempt to load cached data from the file
+ const savedData = await loadDataFromFile(filePath);
+
+ // If cached data exists, generate and return HTML from it
+ if (savedData) {
+ return generateHTML(savedData, source);
+ }
+
+ // If no cached data is available, try to fetch fresh data from the server
+ const fetchedData = await tryToFetchAndSaveProgress(session, keep_alive, filePath);
+
+ // If fetching fresh data is successful, generate and return HTML from it
+ if (fetchedData) {
+ return generateHTML(fetchedData, source);
+ }
+
+ // If neither cached nor fresh data is available, create an error message
+ const errorContainer = document.createElement('div');
+ errorContainer.textContent = 'Error fetching progress. Please update your cookies in the settings and try again.';
+ return errorContainer;
+}
+
+function getPluginFolderPath(): string {
+ return `${this.app.vault.configDir}/plugins/project-euler-stats/cache`;
+}
+
+async function tryToFetchAndSaveProgress(session: string, keep_alive: string, filePath: string): Promise {
+ const cookies = `${sessionIdName}=${session}; ${keepAliveName}=${keep_alive}`;
try {
- return await tryToFetchProgress(cookies, source);
+ const cacheData = await tryToFetchProgress(cookies);
+
+ console.log('Я пошел фетчить прогресс, вот данные:', cacheData);
+
+ await saveDataToFile(filePath, cacheData);
+ return cacheData;
} catch (error) {
console.error('Error fetching progress:', error);
-
- const errorContainer = document.createElement('div');
- errorContainer.textContent = 'Error fetching progress. Please update your cookies in the settings and try again.';
- return errorContainer;
+ return null;
}
}
-async function tryToFetchProgress(cookies: string, source: Source): Promise {
+async function tryToFetchProgress(cookies: string): Promise {
const [
accountData,
progressData,
@@ -70,19 +106,7 @@ async function tryToFetchProgress(cookies: string, source: Source): Promise(url: string, parser: (html: string) => T, cookies: string): Promise {
@@ -112,43 +136,31 @@ async function fetchAwardsData(cookies: string): Promise {
return parseAwardsData(myAwardsHtml, awardsHtml);
}
-function generateHTML(
- accountData: AccountData,
- progressData: ProgressData,
- euleriansPlace: string,
- locationUrl: string,
- languageUrl: string,
- locationRating: RatingData,
- languageRating: RatingData,
- levelDataArray: LevelData[],
- awardsData: AwardBlockData[],
- friends: FriendData[],
- source: Source
-): HTMLElement {
+function generateHTML(cache: CacheData, source: Source): HTMLElement {
const container = document.createElement('div');
- const profileElement = generateProfileHTML(accountData, progressData);
+ const profileElement = generateProfileHTML(cache.accountData, cache.progressData);
container.appendChild(profileElement);
- const imageElement = generateImageHTML(accountData.account);
+ const imageElement = generateImageHTML(cache.accountData.account);
container.appendChild(imageElement);
- const progressElement = generateProgressTableHTML(accountData, progressData, locationUrl, languageUrl, euleriansPlace, locationRating, languageRating, awardsData, source);
+ const progressElement = generateProgressTableHTML(cache, source);
container.appendChild(progressElement);
- const locationRatingElement = generateRatingTableHTML(locationUrl, accountData.location, progressData.solved, locationRating);
+ const locationRatingElement = generateRatingTableHTML(cache.locationUrl, cache.accountData.location, cache.progressData.solved, cache.locationRating);
container.appendChild(locationRatingElement);
- const languageRatingElement = generateRatingTableHTML(languageUrl, accountData.language, progressData.solved, languageRating);
+ const languageRatingElement = generateRatingTableHTML(cache.languageUrl, cache.accountData.language, cache.progressData.solved, cache.languageRating);
container.appendChild(languageRatingElement);
- const levelsElement = generateLevelsTableHTML(progressData, levelDataArray);
+ const levelsElement = generateLevelsTableHTML(cache.progressData, cache.levelDataArray);
container.appendChild(levelsElement);
- const awardsElement = generateAwardsTableHTML(awardsData);
+ const awardsElement = generateAwardsTableHTML(cache.awardsData);
container.appendChild(awardsElement);
- const friendsElement = generateFriendsHTML(friends, accountData);
+ const friendsElement = generateFriendsHTML(cache.friends, cache.accountData);
container.appendChild(friendsElement);
return container;
diff --git a/helpers/fileUtils.ts b/helpers/fileUtils.ts
new file mode 100644
index 0000000..d7540ef
--- /dev/null
+++ b/helpers/fileUtils.ts
@@ -0,0 +1,32 @@
+import { App, Plugin, TFile } from 'obsidian';
+import { CacheData } from './types';
+
+export async function saveDataToFile(filePath: string, data: CacheData): Promise {
+ try {
+ const jsonData = JSON.stringify(data, null, 2);
+ await this.app.vault.adapter.write(filePath, jsonData);
+ } catch (error) {
+ console.error('Failed to save data:', error);
+ }
+}
+
+export async function loadDataFromFile(filePath: string): Promise {
+ try {
+ const jsonData = await this.app.vault.adapter.read(filePath);
+ const rawData = JSON.parse(jsonData);
+ return CacheData.fromObject(rawData);
+ } catch (error) {
+ console.error('Failed to load data:', error);
+ return null;
+ }
+}
+
+export async function checkFileExists(filePath: string): Promise {
+ return await this.app.vault.adapter.exists(filePath);
+}
+
+export async function ensureFolderExists(folderPath: string): Promise {
+ if (!await this.app.vault.adapter.exists(folderPath)) {
+ await this.app.vault.adapter.mkdir(folderPath);
+ }
+}
diff --git a/helpers/progressBlock.ts b/helpers/progressBlock.ts
index dd4312b..7f09078 100644
--- a/helpers/progressBlock.ts
+++ b/helpers/progressBlock.ts
@@ -1,4 +1,4 @@
-import { AccountData, AwardData, AwardBlockData, PersonalTask, ProgressData, RatingData, Source } from './types';
+import { AccountData, AwardData, AwardBlockData, CacheData, PersonalTask, ProgressData, RatingData, Source } from './types';
import { createProgressBar, createSectionHeader } from './commonBlocks';
interface Result {
@@ -206,39 +206,25 @@ function createTasksList(
/**
* Generates HTML for the progress table.
- * @param accountData - The account data.
- * @param progressData - The progress data.
- * @param locationUrl - The URL for the location rating.
- * @param languageUrl - The URL for the language rating.
- * @param euleriansPlace - The user's place in Eulerians' rating.
- * @param locationRating - The location rating data.
- * @param languageRating - The language rating data.
- * @param awardsData - The awards data.
+ * @param cache - The cache data.
* @param source - The source data.
* @returns The generated HTMLElement (progress table container).
*/
export function generateProgressTableHTML(
- accountData: AccountData,
- progressData: ProgressData,
- locationUrl: string,
- languageUrl: string,
- euleriansPlace: string,
- locationRating: RatingData,
- languageRating: RatingData,
- awardsData: AwardBlockData[],
+ cache: CacheData,
source: Source
): HTMLElement {
const progressContainer = document.createElement('div');
progressContainer.appendChild(createSectionHeader('Progress'));
- progressContainer.appendChild(createProgressBar(progressData.percentage));
+ progressContainer.appendChild(createProgressBar(cache.progressData.percentage));
progressContainer.appendChild(createProgressTable(
- progressData,
- euleriansPlace,
- locationUrl,
- languageUrl,
- accountData,
- locationRating,
- languageRating
+ cache.progressData,
+ cache.euleriansPlace,
+ cache.locationUrl,
+ cache.languageUrl,
+ cache.accountData,
+ cache.locationRating,
+ cache.languageRating
));
// Personal tasks section
@@ -252,11 +238,11 @@ export function generateProgressTableHTML(
tasksHeader.textContent = 'Tasks';
progressContainer.appendChild(tasksHeader);
progressContainer.appendChild(createTasksList(
- progressData,
- accountData,
- locationRating,
- languageRating,
- awardsData
+ cache.progressData,
+ cache.accountData,
+ cache.locationRating,
+ cache.languageRating,
+ cache.awardsData
));
return progressContainer;
diff --git a/helpers/types.ts b/helpers/types.ts
index 6ceb73e..2e77126 100644
--- a/helpers/types.ts
+++ b/helpers/types.ts
@@ -8,6 +8,15 @@ export class AccountData {
public location: string,
public language: string
) {}
+
+ static fromObject(obj: any): AccountData {
+ return new AccountData(
+ obj.account,
+ obj.alias,
+ obj.location,
+ obj.language
+ );
+ }
}
/**
@@ -21,6 +30,16 @@ export class ProgressData {
public progress: string,
public toTheNext: string
) {}
+
+ static fromObject(obj: any): ProgressData {
+ return new ProgressData(
+ obj.level,
+ obj.solved,
+ obj.percentage,
+ obj.progress,
+ obj.toTheNext
+ );
+ }
}
/**
@@ -36,6 +55,18 @@ export class RatingData {
public top5: number,
public top1: number
) {}
+
+ static fromObject(obj: any): RatingData {
+ return new RatingData(
+ obj.place,
+ obj.top100,
+ obj.top50,
+ obj.top25,
+ obj.top10,
+ obj.top5,
+ obj.top1
+ );
+ }
}
/**
@@ -51,6 +82,13 @@ export class LevelData {
public level: string,
public members: string
) {}
+
+ static fromObject(obj: any): LevelData {
+ return new LevelData(
+ obj.level,
+ obj.members
+ );
+ }
}
/**
@@ -67,6 +105,13 @@ export class AwardBlockData {
public awards: AwardData[]
) {}
+ static fromObject(obj: any): AwardBlockData {
+ return new AwardBlockData(
+ obj.name,
+ obj.awards.map((award: any) => AwardData.fromObject(award))
+ );
+ }
+
/**
* Calculates the number of completed awards in this block.
* @returns The number of completed awards.
@@ -99,6 +144,18 @@ export class AwardData {
public percentage: number,
public members: string
) {}
+
+ static fromObject(obj: any): AwardData {
+ return new AwardData(
+ obj.award,
+ obj.link,
+ obj.description,
+ obj.isCompleted,
+ obj.progress,
+ obj.percentage,
+ obj.members
+ );
+ }
}
export class FriendData {
@@ -109,6 +166,46 @@ export class FriendData {
public level: number,
public awards: number
) {}
+
+ static fromObject(obj: any): FriendData {
+ return new FriendData(
+ obj.rank,
+ obj.username,
+ obj.solved,
+ obj.level,
+ obj.awards
+ );
+ }
+}
+
+export class CacheData {
+ constructor(
+ public accountData: AccountData,
+ public progressData: ProgressData,
+ public euleriansPlace: string,
+ public locationUrl: string,
+ public languageUrl: string,
+ public locationRating: RatingData,
+ public languageRating: RatingData,
+ public levelDataArray: LevelData[],
+ public awardsData: AwardBlockData[],
+ public friends: FriendData[]
+ ) {}
+
+ static fromObject(obj: any): CacheData {
+ return new CacheData(
+ AccountData.fromObject(obj.accountData),
+ ProgressData.fromObject(obj.progressData),
+ obj.euleriansPlace,
+ obj.locationUrl,
+ obj.languageUrl,
+ RatingData.fromObject(obj.locationRating),
+ RatingData.fromObject(obj.languageRating),
+ obj.levelDataArray.map((level: any) => LevelData.fromObject(level)),
+ obj.awardsData.map((awardBlock: any) => AwardBlockData.fromObject(awardBlock)),
+ obj.friends.map((friend: any) => FriendData.fromObject(friend))
+ );
+ }
}
export class Source {