-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
executable file
·230 lines (188 loc) · 8.37 KB
/
main.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
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import html_parser as parser
import database as db
import settingsManager as settings
from qtInterface.qt_interface import *
from qtInterface.qt_utilclasses import *
from lbc_utils import *
import sys
import requests
import base64
import os.path
from threading import Thread
mainApp = None
# @Brief : MainApplication is the class used to setup & manage
# the application main loop. Why a class? will you ask.
# Well we need to stay within the Qt framework so we have
# to have a class that inherits from QObject. That's why.
class MainApplication(QObject):
def __init__(self):
super(MainApplication, self).__init__()
self._curSearchQuery = ""
self._curSearchRegion = ""
self._displayedItems = []
self._pushbulletInstances = []
self._settingsManager = settings.settingsManager()
# Load Pushbullet settings on startup if available
self.setPushbulletInstances(
self._settingsManager.getPushbulletAccounts())
def onStart(self):
db.openDatabase()
def onClose(self):
db.closeDatabase()
# ******************************************
# Thread class to manage async item updates
# ******************************************
class t_UpdateItems(Thread):
def __init__(self):
super(MainApplication.t_UpdateItems, self).__init__()
self.imgThreadHandle = None
self.timer = QTimer()
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.run)
def restart(self):
self.timer.stop()
self.run()
def is_alive(self):
return super().is_alive() or self.imgThreadHandle.is_alive()
def run(self):
log(1, "Updating items...")
try:
mainApp.refreshMainWindow()
except Exception as e:
log(0, "t_UpdateItems : " + e.args[0])
finally:
self.imgThreadHandle = MainApplication.t_getImages()
self.imgThreadHandle.start()
self.timer.start(60000)
# ***************************************
# Thread class to manage images retrieval
# ***************************************
class t_getImages(Thread):
def __init__(self):
super(MainApplication.t_getImages, self).__init__()
self.writeToDBThreads = []
def is_alive(self):
isOneDBthreadAlive = True in [thread.is_alive() for thread in self.writeToDBThreads]
return super().is_alive() or isOneDBthreadAlive
def run(self):
for itemWidget in mainApp.mainWin.itemPanelWidgets:
hasImages = False
curItem = itemWidget.getItem()
if curItem and len(curItem.images) == 0:
imgURLs = parser.getAndParseItemPage(curItem.url)
if imgURLs is not None:
for url in imgURLs:
imgFile = requests.get(url)
curItem.images += [base64.b16encode(imgFile.content)]
hasImages = True
if hasImages:
self.writeToDBThreads += [
MainApplication.t_saveImagesToDB(itemWidget)]
self.writeToDBThreads[-1].start()
# *****************************************************
# Thread class to manage images recording into database
# *****************************************************
class t_saveImagesToDB(Thread):
def __init__(self, itemWidget):
super(MainApplication.t_saveImagesToDB, self).__init__()
self.itemWidget = itemWidget
self.lbcItem = itemWidget.getItem()
def run(self):
# Needed as the sqlite rule is 1 db connection per Thread
self.dbConn = db.sqlite3.connect(db.DATABASE_NAME, uri=True)
db.insertImagesIntoDatabase(self.dbConn, self.lbcItem)
self.dbConn.close()
# Update the widget to display/enable image button
self.itemWidget.setImageButtonVisibility(True)
def setPushbulletInstances(self, pbInstances):
self._pushbulletInstances = pbInstances
def getPushbulletInstances(self):
return self._pushbulletInstances
def sendPushbulletNotifications(self, items):
counter = 0
for item in items:
for pbInstance in self._pushbulletInstances:
log(3, "mainApp.pushbulletInstance number {} = ".format(
counter) + str(pbInstance))
counter += 1
pbInstance.sendLinkToDevicesInSendlist(lbcItem=item)
def getSettingsManager(self):
return self._settingsManager
def saveSettings(self):
self._settingsManager.saveSettings(self.mainWin.queryInput.text(),
self.mainWin.getRegionValueFromCombobox(),
self.getPushbulletInstances())
# ---------------
# CALLBACKS
# ---------------
def onSubmitNewSearchString(self):
self._curSearchQuery = self.mainWin.queryInput.text()
log(2, "New search string = {}".format(self._curSearchQuery))
self.saveSettings()
self.updateItemsThread.restart()
def onChangingRegion(self, newRegionValueIndex):
self._curSearchRegion = list(parser.REGIONS.keys())[newRegionValueIndex]
log(2, "New region value : {}".format(self._curSearchRegion))
def onClosingSettingsWindow(self, listOfPushbulletAccounts):
# Callback - We set the active PB accounts and save current state in
# settings file
self.setPushbulletInstances(listOfPushbulletAccounts)
self.saveSettings()
def refreshMainWindow(self):
newItems = parser.getItemsFromWebpage(
self._curSearchQuery, self._curSearchRegion)
# This method handles duplicates
db.insertItemsIntoDatabases(*newItems)
self._displayedItems = newItems[0:NB_SHOWN_ITEMS]
# Pad the list - in case we get too few items returned after a new
# search, this will empty the remaining widgets rather than have
# them display results from the previous search
while len(self._displayedItems) < NB_SHOWN_ITEMS:
self._displayedItems += [None]
curItems = mainApp.mainWin.getItems()
itemsToNotify = [
item for item in self._displayedItems if item not in curItems]
log(3, "itemsToNotify = \n{}".format(
[str(item) + "\n" for item in itemsToNotify]))
self.sendPushbulletNotifications(itemsToNotify)
self.mainWin.updateItems(*(self._displayedItems))
self.mainWin.updateStatusBar("Last updated at "
+ getCurTimeString()
+ " - "
+ str(len(itemsToNotify))
+ " new items added!")
# Application main loop. Everything starts and ends here
def main(self):
app = QApplication(sys.argv)
# Initialization of database
self.onStart()
# Let's get some handles
self.mainWin = MainWindow(self)
if os.path.exists("./resources/favicon.ico"):
self.mainWin.setWindowIcon(QIcon("./resources/favicon.ico"))
self.updateItemsThread = self.t_UpdateItems()
# Initialize "Region" combobox with values
for region in parser.REGIONS.keys():
self.mainWin.addItemToRegionCombobox(region)
# Init search from UserSettings config file if available
searchQuery, searchRegion = self._settingsManager.getSearchSettings()
if searchQuery != "" and searchRegion != "":
self._curSearchQuery = searchQuery
self._curSearchRegion = searchRegion
self.mainWin.queryInput.setText(searchQuery)
timer = QTimer()
timer.setSingleShot(True)
timer.timeout.connect(self.updateItemsThread.restart)
timer.start(1000)
self.mainWin.setWindowTitle("LeBonCoin alerter")
self.mainWin.show()
self.mainWin.updateStatusBar(
"sqlite3 version " + db.sqlite3.sqlite_version)
app.exec_()
self.onClose()
sys.exit()
if __name__ == "__main__":
mainApp = MainApplication()
mainApp.main()