-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfirefox.py
286 lines (240 loc) · 9.64 KB
/
firefox.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
from util import WoxEx, WoxAPI, load_module, Log
with load_module():
import sqlite3
import configparser
import os
import webbrowser
import json
import browser
from os import path
from typing import List
PROFILE_INI = "profiles.ini"
PLACES_SQLITE = 'places.sqlite'
CONFIG_JSON = 'config.json'
CONFIG_JSON_PATH = os.path.abspath(os.getcwd()) + '\\' + CONFIG_JSON
DEFAULT_CONFIG = {
"db_path": "",
"enable_history": False
}
DEFAULT_CONTEXT = [{
'Title': f'Open config.json',
'SubTitle': f'',
'IcoPath': 'img\\config.ico',
'JsonRPCAction': {
'method': 'open_config',
'parameters': [CONFIG_JSON_PATH]
}
}, {
'Title': f'Enable/Disable history search',
'SubTitle': f'',
'IcoPath': 'img\\history.ico',
'JsonRPCAction': {
'method': 'switch_history',
'parameters': []
}
}]
class Main(WoxEx):
def query(self, param):
q = param.strip()
if not q:
return DEFAULT_CONTEXT
db_path = self.get_config()['db_path']
if not db_path:
results = [{
'Title': f'Cannot find {PLACES_SQLITE}',
'SubTitle': f'Please set up the "db_path" in your {CONFIG_JSON} in the plugin dir',
'IcoPath': 'img\\firefox.ico',
'JsonRPCAction': {
'method': 'open_config',
'parameters': [CONFIG_JSON_PATH]
}
}]
return results
results = self.get_results(db_path=db_path, sql=self.generate_sql(q))
return results
def context_menu(self, data):
results = []
for browser_name in browser.PROGRAMS:
if browser.get_path(browser_name):
results.append({
"Title": f"Open With {browser_name}",
"SubTitle": str(data),
"IcoPath": f"img\\{browser_name}.ico",
'JsonRPCAction': {
'method': 'open_url',
'parameters': [str(data), browser_name]
}
})
results.append({
'Title': f'Delete',
'SubTitle': f'',
'IcoPath': 'img\\Delete.ico',
'JsonRPCAction': {
'method': 'delete_item',
'parameters': [data]
}
})
return results
def get_config(self) -> dict:
if not path.exists(CONFIG_JSON_PATH):
self.set_config({})
try:
with open(CONFIG_JSON_PATH, 'r', encoding='utf-8') as f:
data = json.load(f)
except (IOError, ValueError) as e:
return
return data
def set_config(self, data: dict):
if not data:
db_path = self.search_db()
data = DEFAULT_CONFIG
data['db_path'] = db_path
with open(CONFIG_JSON_PATH, 'w', encoding='utf-8') as outfile:
json.dump(data, outfile, indent=4)
def generate_sql(self, keyword: str) -> List[str]:
results = []
new_keyword = '%'.join(keyword.split())
cond1 = f"'{new_keyword}%'"
cond2 = f"'%{new_keyword}%'"
enable_history = self.get_config()["enable_history"]
if enable_history:
results.append(f'''select case when b.title is not null then b.title
else p.title
end as title,
visit_count,
url,
frecency,
p.id
from moz_places as p
left outer join moz_bookmarks as b on b.fk = p.id
where lower(b.title) like {cond2} or lower(p.title) like {cond2}
or lower(p.url) like {cond2}
order by frecency desc
limit 100'''
)
else:
results.append(f'''select b.title, visit_count, url, frecency, b.id
from moz_bookmarks as b
join moz_places as p on b.fk = p.id
where lower(b.title) like {cond1}
order by frecency desc '''
)
results.append(f'''select b.title, visit_count, url, frecency, b.id
from moz_bookmarks as b
left outer join moz_places as p on b.fk = p.id
where lower(b.title) like {cond2}
and lower(b.title) not like {cond1}
order by frecency desc '''
)
results.append(f'''select b.title, visit_count, url, frecency, b.id
from moz_bookmarks as b
left outer join moz_places as p on b.fk = p.id
where lower(p.url) like {cond2}
order by frecency desc '''
)
return results
def search_db(self) -> str:
results = []
for root, dirs, files in os.walk(os.environ['APPDATA']):
if PROFILE_INI in files:
temp = dict()
temp['path'] = path.join(root, PROFILE_INI)
temp['root'] = root
temp['mtime'] = os.stat(temp['path']).st_mtime
results += [temp]
results.sort(key=lambda k: k['mtime'], reverse=True)
profiles_ini_path = ''
if results:
profiles_ini_path = results[0]
else:
return
config = configparser.ConfigParser()
config.read(profiles_ini_path['path'], encoding='utf-8')
install = config.sections()[0]
profile_path = config[install]['Default']
if not profile_path:
return
if os.path.isabs(profile_path):
db_path = profile_path + '\\' + PLACES_SQLITE
else:
os.chdir(profiles_ini_path['root'])
db_path = os.path.abspath(profile_path) + '\\' + PLACES_SQLITE
return db_path
def get_results(self, db_path: str, sql: List[str]) -> List[dict]:
results = []
try:
conn = sqlite3.connect(db_path)
c = conn.cursor()
for statement in sql:
for item in c.execute(statement):
result = dict()
title = item[0]
url = item[2]
id = item[4]
result = {
'Title': title,
'SubTitle': url,
'IcoPath': 'img\\Firefox.ico',
"ContextData": url + f" "
f" "
f" id={id}",
'JsonRPCAction': {
'method': 'open_url',
'parameters': [url]
}
}
results += [result]
except sqlite3.OperationalError:
results = [{
'Title': f'Cannot get data from "{db_path}"',
'SubTitle': f'Check the "db_path" configuration in your {CONFIG_JSON} in the plugin dir',
'IcoPath': 'img\\firefox.ico',
'JsonRPCAction': {
'method': 'open_config',
'parameters': [CONFIG_JSON_PATH]
}
}]
finally:
conn.close()
return results
def open_url(self, url=None, browser_name=None):
if not browser_name:
webbrowser.open(url)
else:
browser_path = browser.get_path(browser_name)
webbrowser.register(browser_name, None, webbrowser.BackgroundBrowser(browser_path))
webbrowser.get(browser_name).open_new_tab(url)
def open_config(self, dir=None):
self.get_config()
if dir:
os.startfile(dir)
def switch_history(self):
config = self.get_config()
if config['enable_history']:
config['enable_history'] = False
else:
config['enable_history'] = True
self.set_config(config)
def delete_item(self, cdata: str):
config = self.get_config()
index = cdata.find(' id=')
if index == -1:
return
index = index + 4
sql = ''
if config['enable_history']:
sql = f'delete from moz_places where id = {cdata[index:]}'
else:
sql = f'delete from moz_bookmarks where id = {cdata[index:]}'
if sql:
try:
conn = sqlite3.connect(config['db_path'])
c = conn.cursor()
c.execute(sql)
conn.commit()
except sqlite3.OperationalError:
raise
finally:
conn.close()
if __name__ == '__main__':
Main()