88from urllib .parse import unquote
99
1010try :
11- from .utils import PROFICIENCY_MAJOR_VERSION
11+ from .utils import get_mediawiki_db_path
1212 from .x_ray_share import FUZZ_THRESHOLD , XRayEntity
1313except ImportError :
14- from utils import PROFICIENCY_MAJOR_VERSION
14+ from utils import get_mediawiki_db_path
1515 from x_ray_share import FUZZ_THRESHOLD , XRayEntity
1616
1717# https://www.mediawiki.org/wiki/API:Get_the_contents_of_a_page
@@ -39,36 +39,32 @@ def __init__(
3939 self .lang = lang
4040 self .is_wikipedia = api_url == ""
4141 self .api_url = (
42- f"https://{ lang } .wikipedia.org/w/api.php" if self . is_wikipedia else api_url
42+ f"https://{ lang } .wikipedia.org/w/api.php" if api_url == "" else api_url
4343 )
44- self .db_conn = self .init_db (plugin_path )
44+ self .db_conn = self .init_db (get_mediawiki_db_path ( lang , api_url , plugin_path ) )
4545 self .session = self .init_requests_session (useragent , lang_variant )
4646 self .sitename = "Wikipedia" if self .is_wikipedia else ""
4747 self .has_extracts_api = True if self .is_wikipedia else False
48+ self .has_tocdata_api = True if self .is_wikipedia else False
4849 if not self .is_wikipedia :
4950 self .get_api_info ()
5051
51- def init_db (self , plugin_path : Path ) -> sqlite3 .Connection :
52- domain = (
53- self .api_url .removeprefix ("https://" )
54- .removeprefix ("http://" )
55- .split ("/" , 1 )[0 ]
56- )
57- db_path = plugin_path .parent .joinpath (f"worddumb-mediawiki/{ domain } .db" )
52+ def init_db (self , db_path : Path ) -> sqlite3 .Connection :
5853 if not db_path .parent .exists ():
5954 db_path .parent .mkdir ()
60-
55+ db_exists = db_path . exists ()
6156 db_conn = sqlite3 .connect (db_path )
62- db_conn .execute (
63- """
64- CREATE TABLE IF NOT EXISTS pages (
65- title TEXT PRIMARY KEY COLLATE NOCASE,
66- description TEXT,
67- wikidata_item TEXT,
68- redirect_to TEXT
57+ if not db_exists :
58+ db_conn .execute (
59+ """
60+ CREATE TABLE pages (
61+ title TEXT PRIMARY KEY COLLATE NOCASE,
62+ description TEXT,
63+ wikidata_item TEXT,
64+ redirect_to TEXT,
65+ redirect_fragment TEXT)
66+ """
6967 )
70- """
71- )
7268 return db_conn
7369
7470 def init_requests_session (self , useragent : str , lang_variant : str ):
@@ -104,6 +100,18 @@ def get_api_info(self) -> None:
104100 for module in data .get ("paraminfo" , {}).get ("modules" , []):
105101 if module .get ("name" , "" ) == "extracts" :
106102 self .has_extracts_api = True
103+ result = self .session .get (
104+ self .api_url , params = {"action" : "paraminfo" , "modules" : "parse" }
105+ )
106+ if result .ok :
107+ data = result .json ()
108+ for param in (
109+ data .get ("paraminfo" , {}).get ("modules" , []).get ("parameters" , [])
110+ ):
111+ if param .get ("name" , "" ) == "prop" and "tocdata" in param .get (
112+ "type" , ""
113+ ):
114+ self .has_tocdata_api = True
107115
108116 def add_cache (self , title : str , intro : str , wikidata_item : str | None ) -> None :
109117 self .db_conn .execute (
@@ -115,21 +123,35 @@ def add_cache(self, title: str, intro: str, wikidata_item: str | None) -> None:
115123 )
116124
117125 def has_cache (self , title : str ) -> bool :
118- for _ in self .db_conn .execute (
119- "SELECT title FROM pages WHERE title = ? LIMIT 1" , (title ,)
120- ):
121- return True
126+ if not self .is_wikipedia :
127+ for _ in self .db_conn .execute (
128+ "SELECT title FROM pages WHERE title = ?" , (title ,)
129+ ):
130+ return True
131+ else :
132+ return self .get_cache (title ) is not None
122133 return False
123134
135+ def get_redirect_section (self , title : str ) -> tuple [str , str ] | None :
136+ if self .is_wikipedia :
137+ for redirect_to , redirect_fragment in self .db_conn .execute (
138+ "SELECT redirect_to, redirect_fragment FROM pages WHERE title = ?" ,
139+ (title ,),
140+ ):
141+ if redirect_fragment is not None :
142+ return redirect_to , redirect_fragment
143+ return None
144+
124145 def get_cache (self , title : str ) -> MediaWikiCache | None :
125146 for desc , wikidata_item in self .db_conn .execute (
126147 """
127148 SELECT description, wikidata_item
128- FROM pages WHERE title = ?
149+ FROM pages WHERE title = ? AND (
150+ redirect_to IS NULL OR redirect_fragment IS NOT NULL)
129151 UNION ALL
130152 SELECT a.description, a.wikidata_item
131153 FROM pages a JOIN pages b ON a.title = b.redirect_to
132- WHERE b.title = ?
154+ WHERE b.title = ? AND b.redirect_fragment IS NULL
133155 LIMIT 1
134156 """ ,
135157 (title , title ),
@@ -140,20 +162,25 @@ def get_cache(self, title: str) -> MediaWikiCache | None:
140162 return None
141163
142164 def add_redirect (self , source_title : str , dest_title : str ) -> None :
143- self .db_conn .execute (
144- "INSERT OR IGNORE INTO pages (title, redirect_to) VALUES(?, ?)" ,
145- (source_title , dest_title ),
146- )
165+ if not self .is_wikipedia :
166+ self .db_conn .execute (
167+ "INSERT OR IGNORE INTO pages (title, redirect_to) VALUES(?, ?)" ,
168+ (source_title , dest_title ),
169+ )
147170
148171 def add_no_desc_titles (self , titles : set [str ]) -> None :
149172 # not found this title from MediaWiki
150- self .db_conn .executemany (
151- "INSERT OR IGNORE INTO pages (title) VALUES(?)" , ((t ,) for t in titles )
152- )
173+ if not self .is_wikipedia :
174+ self .db_conn .executemany (
175+ "INSERT OR IGNORE INTO pages (title) VALUES(?)" , ((t ,) for t in titles )
176+ )
153177
154178 def redirect_to_page (self , title : str ) -> str :
155179 for (redirect_to ,) in self .db_conn .execute (
156- "SELECT redirect_to FROM pages WHERE title = ?" , (title ,)
180+ """
181+ SELECT redirect_to FROM pages WHERE title = ? AND redirect_fragment IS NULL
182+ """ ,
183+ (title ,),
157184 ):
158185 return redirect_to
159186 return ""
@@ -227,15 +254,17 @@ def get_section_text(
227254 self .api_url ,
228255 params = {
229256 "action" : "parse" ,
230- "prop" : "sections" ,
257+ "prop" : "tocdata" if self . has_tocdata_api else " sections" ,
231258 "page" : page ,
232259 },
233260 )
234261 if not r .ok :
235262 return
236263 result = r .json ()
237- for section in result .get ("parse" , {}).get ("sections" , []):
238- if section ["line" ] in section_to_titles :
264+ for section in result .get (
265+ "tocdata" if self .has_tocdata_api else "sections" , {}
266+ ).get ("sections" , []):
267+ if section ["anchor" ] in section_to_titles :
239268 r = self .session .get (
240269 self .api_url ,
241270 params = {
@@ -260,12 +289,12 @@ def get_section_text(
260289 if not text :
261290 continue
262291 text = text .strip ()
263- redirected_from = section_to_titles [section ["line " ]]
292+ redirected_from = section_to_titles [section ["anchor " ]]
264293 self .add_cache (redirected_from , text , None )
265294 if redirected_from in titles :
266295 titles .remove (redirected_from )
267296 for source_title in converts .get (redirected_from , []):
268- self .add_redirect (source_title , page )
297+ self .add_redirect (source_title , redirected_from )
269298 if source_title in titles :
270299 titles .remove (source_title )
271300
@@ -343,7 +372,12 @@ def query(self, entities: dict[str, XRayEntity]) -> None:
343372 self .query_extracts_api (pending_entities )
344373 pending_entities .clear ()
345374 elif not self .has_cache (entity ):
346- if self .has_extracts_api :
375+ if redirect_data := self .get_redirect_section (entity ):
376+ redirect_to , redirect_fragment = redirect_data
377+ self .get_section_text (
378+ {redirect_to : {redirect_fragment : entity }}, {}, set ()
379+ )
380+ elif self .has_extracts_api :
347381 pending_entities .add (entity )
348382 else :
349383 self .query_parse_api (entity )
0 commit comments