11import os
22import re
3- import requests
43from pathlib import Path
4+ import requests
55
66SRC_DIR = "Solutions"
77SITE_README_PATH = Path ("Site_README.md" )
88GITHUB_README_PATH = Path ("README.md" )
9+ LINK_ICON = "🔗"
910
10- LINK_ICON = "🔗" # Unicode link icon
11-
12- def fetch_problem_data (slug : str ):
13- """Fetch problem number, difficulty, and tags from LeetCode GraphQL API."""
11+ def fetch_question_details (slug : str ):
12+ """Fetch difficulty and tags from LeetCode GraphQL API."""
1413 url = "https://leetcode.com/graphql"
1514 query = {
1615 "query" : """
1716 query getQuestionDetail($titleSlug: String!) {
1817 question(titleSlug: $titleSlug) {
19- frontendQuestionId
2018 difficulty
21- topicTags { name }
19+ topicTags {
20+ name
21+ slug
22+ }
2223 }
2324 }
2425 """ ,
2526 "variables" : {"titleSlug" : slug },
2627 }
27- headers = {
28- "Content-Type" : "application/json" ,
29- "User-Agent" : "Mozilla/5.0" ,
30- "Referer" : f"https://leetcode.com/problems/{ slug } /"
31- }
3228 try :
33- resp = requests .post (url , json = query , headers = headers , timeout = 10 )
29+ resp = requests .post (url , json = query , timeout = 10 )
3430 resp .raise_for_status ()
35- data = resp .json ()["data" ]["question" ]
36- number = data .get ("frontendQuestionId" , "" )
37- difficulty = data .get ("difficulty" , "" )
38- tags = [t ["name" ] for t in data .get ("topicTags" , [])]
39- return number , difficulty , tags
31+ data = resp .json ()
32+ question = data .get ("data" , {}).get ("question" )
33+ if not question :
34+ print (f"⚠️ No question data returned for slug: { slug } " )
35+ return "" , []
36+ difficulty = question .get ("difficulty" , "" )
37+ tags = [tag .get ("name" ) for tag in question .get ("topicTags" , []) if tag .get ("name" )]
38+ return difficulty , tags
4039 except Exception as e :
41- print (f"Failed to fetch { slug } : { e } " )
42- return "" , "" , []
40+ print (f"❌ Failed to fetch question details for { slug } : { e } " )
41+ return "" , []
4342
44- # MkDocs HTML badge
43+ # MkDocs badge
4544def difficulty_badge_site (difficulty : str ) -> str :
4645 colors = {"Easy" : "#46c6c2" , "Medium" : "#fac31d" , "Hard" : "#f8615c" }
46+ color = colors .get (difficulty , "#9E9E9E" )
4747 if not difficulty :
4848 return ""
49- color = colors .get (difficulty , "#9E9E9E" )
5049 return f'<span style="background-color:#ffffff1a; color:{ color } ; padding:2px 6px; border-radius:6px;">{ difficulty } </span>'
5150
52- # GitHub Shields.io badge
51+ # GitHub badge
5352def difficulty_badge_github (difficulty : str ) -> str :
5453 colors = {"Easy" : "4c1" , "Medium" : "f9c851" , "Hard" : "e05d44" }
54+ color = colors .get (difficulty , "9e9e9e" )
5555 if not difficulty :
5656 return ""
57- color = colors .get (difficulty , "9e9e9e" )
5857 badge_url = f"https://img.shields.io/badge/Difficulty-{ difficulty } -{ color } .svg"
5958 return f""
6059
@@ -63,40 +62,40 @@ def generate_table_rows(problems, badge_func):
6362 for slug , number , title , difficulty , tags in problems :
6463 diff_badge = badge_func (difficulty )
6564 tags_str = ", " .join (tags )
66- solution_link = f"https://leetcode.romitsagu.com/solutions/leetcode{ number } # /"
65+ solution_link = f"https://leetcode.romitsagu.com/solutions/leetcode{ number } /"
6766 icon_md = f"[{ LINK_ICON } ]({ solution_link } )"
6867 rows .append (f"| { title } | { icon_md } | { diff_badge } | { tags_str } |" )
6968 return "\n " .join (rows )
7069
7170def update_readme (readme_path , rows_str ):
71+ """Update the README table; creates one if not present."""
7272 if not readme_path .exists ():
7373 raise FileNotFoundError (f"{ readme_path } does not exist" )
7474
7575 readme_text = readme_path .read_text ()
76- pattern = re .compile (
77- r'(\| Problem \| Solution \| Difficulty \| Tags \|\n\|[-| ]+\|\n)(.*?)(\n|$)' ,
76+ # Match the full table
77+ table_pattern = re .compile (
78+ r'(\| Problem \| Solution \| Difficulty \| Tags \s*\|\n\|[-| ]+\|\n)(.*?)(?=\n\| |\Z)' ,
7879 re .DOTALL
7980 )
8081
81- if pattern .search (readme_text ):
82- updated_text = pattern .sub (r"\1" + rows_str + r"\3" , readme_text )
83- print (f"Updated table rows in { readme_path .name } " )
82+ if table_pattern .search (readme_text ):
83+ updated_text = table_pattern .sub (r"\1" + rows_str , readme_text )
84+ print (f"✅ Updated table rows in { readme_path .name } " )
8485 else :
8586 new_table = (
8687 "| Problem | Solution | Difficulty | Tags |\n "
8788 "|---------|---------|------------|------|\n "
8889 + rows_str
8990 )
9091 updated_text = readme_text .strip () + "\n \n " + new_table
91- print (f"Added new table in { readme_path .name } " )
92+ print (f"✅ Added new table in { readme_path .name } " )
9293
9394 readme_path .write_text (updated_text )
94- print (f"{ readme_path .name } updated successfully." )
9595
9696def main ():
9797 problems = []
9898
99- # Step 1: Read all problem folders and fetch data
10099 for folder in sorted (os .listdir (SRC_DIR )):
101100 folder_path = Path (SRC_DIR ) / folder
102101 if not folder_path .is_dir ():
@@ -109,15 +108,12 @@ def main():
109108 folder_number = str (int (folder_number ))
110109 title = f"{ folder_number } . " + " " .join ([w .capitalize () for w in slug .split ("-" )])
111110
112- # Fetch API data once
113- number , difficulty , tags = fetch_problem_data (slug )
114- problems .append ((slug , number , title , difficulty , tags ))
111+ difficulty , tags = fetch_question_details (slug )
112+ problems .append ((slug , folder_number , title , difficulty , tags ))
115113
116- # Step 2: Generate table rows
117114 site_rows = generate_table_rows (problems , difficulty_badge_site )
118115 github_rows = generate_table_rows (problems , difficulty_badge_github )
119116
120- # Step 3: Update both READMEs
121117 update_readme (SITE_README_PATH , site_rows )
122118 update_readme (GITHUB_README_PATH , github_rows )
123119
0 commit comments