def __init__(self): super(Database, self).__init__() self._crawlerManager = CrawlerManager() self._playHistoryCursor = len(self._getPlayHistory()) - 1 self._initDelayTimer() self._crawlerManager.infoGot.connect(self.crawlerGotInfo)
class Database(QObject): playlistItemAdded = pyqtSignal(str, str, str, arguments=["name", "url", "category"]) importDone = pyqtSignal(str, arguments=["filename"]) itemVInfoGot = pyqtSignal(str, str, arguments=["url", "vinfo"]) def __init__(self): super(Database, self).__init__() self._crawlerManager = CrawlerManager() self._playHistoryCursor = len(self._getPlayHistory()) - 1 self._initDelayTimer() self._crawlerManager.infoGot.connect(self.crawlerGotInfo) def _initDelayTimer(self): self._delayCommitTimer = QTimer() self._delayCommitTimer.setSingleShot(True) self._delayCommitTimer.setInterval(500) self._delayCommitTimer.timeout.connect(lambda: _database_file.commit()) @contextmanager def _delayCommit(self): _database_file.set_autocommit(False) _database_file.begin() yield _database_file.set_autocommit(True) self._delayCommitTimer.start() # internal helper functions def _getPlayHistory(self): tuples = PlayHistoryItemModel.select( PlayHistoryItemModel.url).order_by( PlayHistoryItemModel.id.asc()).tuples() return map(lambda x: x[0], tuples) if tuples else [] def _getOrNewPlaylistCategory(self, categoryName): try: category = PlaylistCategoryModel.get( PlaylistCategoryModel.name == categoryName) except DoesNotExist: category = PlaylistCategoryModel.create(name=categoryName) return category def _getOrNewPlaylistItem(self, itemName, itemUrl): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) except DoesNotExist: item = PlaylistItemModel.create(name=itemName, url=itemUrl) return item @pyqtSlot(str, str) def crawlerGotInfo(self, url, result): self.itemVInfoGot.emit(url, result) self.setPlaylistItemVInfo(url, result) # Playlist operations @pyqtSlot(result=str) def getPlaylistContent(self): queryResults = PlaylistItemModel \ .select(PlaylistItemModel,) \ .join(PlaylistCategoryModel, JOIN_LEFT_OUTER) \ .aggregate_rows() contentCache = [] if os.path.exists(PLAYLIST_CACHE_FILE): with open(PLAYLIST_CACHE_FILE) as _file: _cache = _file.read() contentCache = json.loads(_cache) if len(contentCache) == queryResults.count(): return json.dumps(contentCache) else: content = [] for result in queryResults: category = result.category.name if result.category else "" content.append({ "category": category, "name": result.name, "url": result.url }) return json.dumps(content) @pyqtSlot(str) def setPlaylistContentCache(self, cache): with open(PLAYLIST_CACHE_FILE, "w") as _file: _file.write(cache.encode("utf-8")) @pyqtSlot(str, result=bool) def containsPlaylistItem(self, itemUrl): try: PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) except DoesNotExist: return False return True @pyqtSlot(str, result=bool) def containsPlaylistCategory(self, categoryName): try: PlaylistCategoryModel.get( PlaylistCategoryModel.name == categoryName) except DoesNotExist: return False return True @pyqtSlot(str, str, str) def addPlaylistItem(self, itemName, itemUrl, categoryName): if not self.containsPlaylistItem(itemUrl): item = PlaylistItemModel.create(name=itemName, url=itemUrl) if categoryName: item.category = self._getOrNewPlaylistCategory(categoryName) item.save() self.playlistItemAdded.emit(itemName, itemUrl, categoryName) @pyqtSlot(str) def addPlaylistCategory(self, categoryName): self._getOrNewPlaylistCategory(categoryName) @pyqtSlot(str) @_database_file.commit_on_success def addPlaylistCITuples(self, tuples): tuples = json.loads(tuples) for tuple in tuples: category = tuple[0] url = tuple[1] urlIsNativeFile = utils.urlIsNativeFile(url) result = os.path.basename(url) itemName = result if urlIsNativeFile else url self.addPlaylistItem(itemName, url, category) @pyqtSlot(str) def removePlaylistItem(self, itemUrl): try: target = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) target.delete_instance() # TODO: remove empty category here except DoesNotExist: pass @pyqtSlot(str) @_database_file.commit_on_success def removePlaylistCategory(self, categoryName): try: itemsInCategory = PlaylistItemModel \ .select(PlaylistItemModel, PlaylistCategoryModel) \ .join(PlaylistCategoryModel, JOIN_LEFT_OUTER) \ .where(PlaylistCategoryModel.name == categoryName) for item in itemsInCategory: item.delete_instance() target = PlaylistCategoryModel.get( PlaylistCategoryModel.name == categoryName) target.delete_instance() except DoesNotExist: pass @pyqtSlot() def clearPlaylist(self): PlaylistCategoryModel.delete().execute() PlaylistItemModel.delete().execute() PlayHistoryItemModel.delete().execute() @pyqtSlot(str) def exportPlaylist(self, filename): playlist = DMPlaylist() queryResults = PlaylistItemModel \ .select(PlaylistItemModel,) \ .join(PlaylistCategoryModel, JOIN_LEFT_OUTER) \ .aggregate_rows() for result in queryResults: info = json.loads(result.info) if result.info else {} played = str(info.get("played")) or "" if result.category: cate = playlist.appendCategory( result.category.name.encode("utf-8")) cate.appendItem(result.name.encode("utf-8"), result.url.encode("utf-8"), played) else: playlist.appendItem(result.name.encode("utf-8"), result.url.encode("utf-8"), played) playlist.writeTo(filename) @pyqtSlot(str) @_database_file.commit_on_success def importPlaylist(self, filename): playlist = DMPlaylist.readFrom(filename) for category in playlist.getAllCategories(): for item in category.getAllItems(): self.addPlaylistCategory(category.name) self.addPlaylistItem(item.name, item.source, category.name) self.setPlaylistItemPlayed(item.source, item.played) for item in playlist.getAllItems(): self.addPlaylistItem(item.name, item.source, "") self.setPlaylistItemPlayed(item.source, item.played) self.importDone.emit(filename) @pyqtSlot(str, result=int) def getPlaylistItemPlayed(self, itemUrl): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} return info.get("played") or 0 except DoesNotExist: return 0 @pyqtSlot(str, int) def setPlaylistItemPlayed(self, itemUrl, itemPlayed): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["played"] = itemPlayed item.info = json.dumps(info) item.save() except DoesNotExist: pass @pyqtSlot(str, result=int) def getPlaylistItemRotation(self, itemUrl): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} return info.get("rotation") or 0 except DoesNotExist: return 0 @pyqtSlot(str, int) def setPlaylistItemRotation(self, itemUrl, itemRotation): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["rotation"] = itemRotation item.info = json.dumps(info) item.save() except DoesNotExist: pass @pyqtSlot(str, result=str) def getPlaylistItemSubtitle(self, itemUrl): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} subtitle = info.get("subtitle") or "" if subtitle.startswith("{") and subtitle.endswith("}"): return subtitle else: return json.dumps({"path": subtitle, "delay": 0}) except DoesNotExist: return "" @pyqtSlot(str, str, int) def setPlaylistItemSubtitle(self, itemUrl, subtitle, delay): try: with self._delayCommit(): item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["subtitle"] = json.dumps({ "path": subtitle, "delay": delay }) item.info = json.dumps(info) item.save() except DoesNotExist: pass # this getter is asynchronized because there's maybe some items that has no # video_info stored, so you need connect to the itemVInfoGot signal to # respond to this getter. @pyqtSlot(str) def getPlaylistItemVInfo(self, itemUrl): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} if info.get("video_info"): self.itemVInfoGot.emit(itemUrl, info.get("video_info")) else: self._crawlerManager.crawl(itemUrl, True) except DoesNotExist: self._crawlerManager.crawl(itemUrl, True) def setPlaylistItemVInfo(self, itemUrl, videoInfo): try: item = PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["video_info"] = videoInfo item.info = json.dumps(info) item.save() except DoesNotExist: pass # Play history operations @pyqtSlot() def clearPlayHistory(self): PlayHistoryItemModel.delete().execute() self._playHistoryCursor = len(self._getPlayHistory()) - 1 @pyqtSlot(str, bool) def appendPlayHistoryItem(self, itemUrl, resetCursor): PlayHistoryItemModel.create(url=itemUrl) if resetCursor: self._playHistoryCursor = len(self._getPlayHistory()) - 1 @pyqtSlot(result=str) def playHistoryGetPrevious(self): playHistory = self._getPlayHistory() self._playHistoryCursor = max(0, self._playHistoryCursor - 1) if playHistory: return playHistory[self._playHistoryCursor] else: return ""
class Database(QObject): playlistItemAdded = pyqtSignal(str, str, str, arguments=["name", "url", "category"]) importDone = pyqtSignal(str, arguments=["filename"]) itemVInfoGot = pyqtSignal(str, str, arguments=["url", "vinfo"]) def __init__(self): super(Database, self).__init__() self._crawlerManager = CrawlerManager() self._playHistoryCursor = len(self._getPlayHistory()) - 1 self._crawlerManager.infoGot.connect(self.crawlerGotInfo) # internal helper functions def _getPlayHistory(self): tuples = PlayHistoryItemModel.select(PlayHistoryItemModel.url).order_by( PlayHistoryItemModel.id.asc()).tuples() return map(lambda x: x[0], tuples) if tuples else [] def _getOrNewPlaylistCategory(self, categoryName): try: category = PlaylistCategoryModel.get( PlaylistCategoryModel.name == categoryName) except DoesNotExist: category = PlaylistCategoryModel.create(name=categoryName) return category def _getOrNewPlaylistItem(self, itemName, itemUrl): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) except DoesNotExist: item = PlaylistItemModel.create(name=itemName, url=itemUrl) return item @pyqtSlot(str, str) def crawlerGotInfo(self, url, result): self.itemVInfoGot.emit(url, result) self.setPlaylistItemVInfo(url, result) # Playlist operations @pyqtSlot(result=str) def getPlaylistContent(self): queryResults = PlaylistItemModel \ .select(PlaylistItemModel,) \ .join(PlaylistCategoryModel, JOIN_LEFT_OUTER) \ .aggregate_rows() contentCache = [] if os.path.exists(PLAYLIST_CACHE_FILE): with open(PLAYLIST_CACHE_FILE) as _file: _cache = _file.read() contentCache = json.loads(_cache) if len(contentCache) == queryResults.count(): return json.dumps(contentCache) else: content = [] for result in queryResults: category = result.category.name if result.category else "" content.append({ "category": category, "name": result.name, "url": result.url }) return json.dumps(content) @pyqtSlot(str) def setPlaylistContentCache(self, cache): with open(PLAYLIST_CACHE_FILE, "w") as _file: _file.write(cache.encode("utf-8")) @pyqtSlot(str, result=bool) def containsPlaylistItem(self, itemUrl): try: PlaylistItemModel.get(PlaylistItemModel.url == itemUrl) except DoesNotExist: return False return True @pyqtSlot(str, result=bool) def containsPlaylistCategory(self, categoryName): try: PlaylistCategoryModel.get( PlaylistCategoryModel.name == categoryName) except DoesNotExist: return False return True @pyqtSlot(str, str, str) def addPlaylistItem(self, itemName, itemUrl, categoryName): if not self.containsPlaylistItem(itemUrl): item = PlaylistItemModel.create(name=itemName, url=itemUrl) if categoryName: item.category = self._getOrNewPlaylistCategory(categoryName) item.save() self.playlistItemAdded.emit(itemName, itemUrl, categoryName) @pyqtSlot(str) def addPlaylistCategory(self, categoryName): self._getOrNewPlaylistCategory(categoryName) @pyqtSlot(str) @_database_file.commit_on_success def addPlaylistCITuples(self, tuples): tuples = json.loads(tuples) for tuple in tuples: category = tuple[0] url = tuple[1] urlIsNativeFile = utils.urlIsNativeFile(url) result = os.path.basename(url) itemName = result if urlIsNativeFile else url self.addPlaylistItem(itemName, url, category) @pyqtSlot(str) def removePlaylistItem(self, itemUrl): try: target = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) target.delete_instance() # TODO: remove empty category here except DoesNotExist: pass @pyqtSlot(str) @_database_file.commit_on_success def removePlaylistCategory(self, categoryName): try: itemsInCategory = PlaylistItemModel \ .select(PlaylistItemModel, PlaylistCategoryModel) \ .join(PlaylistCategoryModel, JOIN_LEFT_OUTER) \ .where(PlaylistCategoryModel.name == categoryName) for item in itemsInCategory: item.delete_instance() target = PlaylistCategoryModel.get( PlaylistCategoryModel.name == categoryName) target.delete_instance() except DoesNotExist: pass @pyqtSlot() def clearPlaylist(self): PlaylistCategoryModel.delete().execute() PlaylistItemModel.delete().execute() PlayHistoryItemModel.delete().execute() @pyqtSlot(str) def exportPlaylist(self, filename): playlist = DMPlaylist() queryResults = PlaylistItemModel \ .select(PlaylistItemModel,) \ .join(PlaylistCategoryModel, JOIN_LEFT_OUTER) \ .aggregate_rows() for result in queryResults: info = json.loads(result.info) if result.info else {} played = str(info.get("played")) or "" if result.category: cate = playlist.appendCategory( result.category.name.encode("utf-8")) cate.appendItem(result.name.encode("utf-8"), result.url.encode("utf-8"), played) else: playlist.appendItem(result.name.encode("utf-8"), result.url.encode("utf-8"), played) playlist.writeTo(filename) @pyqtSlot(str) @_database_file.commit_on_success def importPlaylist(self, filename): playlist = DMPlaylist.readFrom(filename) for category in playlist.getAllCategories(): for item in category.getAllItems(): self.addPlaylistCategory(category.name) self.addPlaylistItem(item.name, item.source, category.name) self.setPlaylistItemPlayed(item.source, item.played) for item in playlist.getAllItems(): self.addPlaylistItem(item.name, item.source, "") self.setPlaylistItemPlayed(item.source, item.played) self.importDone.emit(filename) @pyqtSlot(str, result=int) def getPlaylistItemPlayed(self, itemUrl): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} return info.get("played") or 0 except DoesNotExist: return 0 @pyqtSlot(str, int) def setPlaylistItemPlayed(self, itemUrl, itemPlayed): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["played"] = itemPlayed item.info = json.dumps(info) item.save() except DoesNotExist: pass @pyqtSlot(str, result=int) def getPlaylistItemRotation(self, itemUrl): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} return info.get("rotation") or 0 except DoesNotExist: return 0 @pyqtSlot(str, int) def setPlaylistItemRotation(self, itemUrl, itemRotation): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["rotation"] = itemRotation item.info = json.dumps(info) item.save() except DoesNotExist: pass @pyqtSlot(str, result=str) def getPlaylistItemSubtitle(self, itemUrl): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} return info.get("subtitle") or "" except DoesNotExist: return "" @pyqtSlot(str, str) def setPlaylistItemSubtitle(self, itemUrl, subtitle): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["subtitle"] = subtitle item.info = json.dumps(info) item.save() except DoesNotExist: pass # this getter is asynchronized because there's maybe some items that has no # video_info stored, so you need connect to the itemVInfoGot signal to # respond to this getter. @pyqtSlot(str) def getPlaylistItemVInfo(self, itemUrl): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} if info.get("video_info"): self.itemVInfoGot.emit(itemUrl, info.get("video_info")) else: self._crawlerManager.crawl(itemUrl, True) except DoesNotExist: self._crawlerManager.crawl(itemUrl, True) def setPlaylistItemVInfo(self, itemUrl, videoInfo): try: item = PlaylistItemModel.get( PlaylistItemModel.url == itemUrl) info = json.loads(item.info) if item.info else {} info["video_info"] = videoInfo item.info = json.dumps(info) item.save() except DoesNotExist: pass # Play history operations @pyqtSlot() def clearPlayHistory(self): PlayHistoryItemModel.delete().execute() self._playHistoryCursor = len(self._getPlayHistory()) - 1 @pyqtSlot(str, bool) def appendPlayHistoryItem(self, itemUrl, resetCursor): PlayHistoryItemModel.create(url=itemUrl) if resetCursor: self._playHistoryCursor = len(self._getPlayHistory()) - 1 @pyqtSlot(result=str) def playHistoryGetPrevious(self): playHistory = self._getPlayHistory() self._playHistoryCursor = max(0, self._playHistoryCursor - 1) if playHistory: return playHistory[self._playHistoryCursor] else: return ""