def ShowContextMenu(self, index, global_pos): if not self.menu: self.menu = QMenu() for action in self.GetPlaylistActions(): self.menu.addAction(action) self.menu.addAction(clementine.IconLoader.Load("download"), self.tr("Open " + self.HOMEPAGE_NAME + " in browser"), self.Homepage) self.menu.addAction(clementine.IconLoader.Load("view-refresh"), self.tr("Refresh streams"), self.RefreshStreams) self.menu.addSeparator() self.menu.addAction(clementine.IconLoader.Load("configure"), self.tr("Configure..."), self.settings_dialog_callback()) self.context_index = index self.menu.popup(global_pos)
class DigitallyImportedServiceBase(clementine.InternetService): # Set these in subclasses HOMEPAGE_URL = None HOMEPAGE_NAME = None STREAM_LIST_URL = None ICON_FILENAME = None SERVICE_NAME = None SERVICE_DESCRIPTION = None PLAYLISTS = [] URL_SCHEME = None SETTINGS_GROUP = "digitally_imported" def Init(self, model, settings_dialog_callback): clementine.InternetService.__init__(self, self.SERVICE_NAME, model) # We must hold a weak reference to the callback or else it makes a circular # reference between the services and Plugin from main.py. self.settings_dialog_callback = weakref.ref(settings_dialog_callback) self.url_handler = DigitallyImportedUrlHandler(self.URL_SCHEME, self) clementine.player.RegisterUrlHandler(self.url_handler) self.network = clementine.NetworkAccessManager(None) self.path = os.path.dirname(__file__) self.audio_type = 0 self.username = "" self.password = "" self.context_index = None self.menu = None self.root = None self.task_id = None self.refresh_streams_reply = None self.load_station_reply = None self.items = [] self.ReloadSettings() def ReloadSettings(self): settings = QSettings() settings.beginGroup(self.SETTINGS_GROUP) self.audio_type = int(settings.value("audio_type", 0)) self.username = unicode(settings.value("username", "")) self.password = unicode(settings.value("password", "")) def CreateRootItem(self): self.root = QStandardItem(QIcon(os.path.join(self.path, self.ICON_FILENAME)), self.SERVICE_DESCRIPTION) self.root.setData(True, clementine.InternetModel.Role_CanLazyLoad) return self.root def LazyPopulate(self, parent): if parent == self.root: # Download the list of streams the first time the user expands the root self.RefreshStreams() def ShowContextMenu(self, index, global_pos): if not self.menu: self.menu = QMenu() for action in self.GetPlaylistActions(): self.menu.addAction(action) self.menu.addAction(clementine.IconLoader.Load("download"), self.tr("Open " + self.HOMEPAGE_NAME + " in browser"), self.Homepage) self.menu.addAction(clementine.IconLoader.Load("view-refresh"), self.tr("Refresh streams"), self.RefreshStreams) self.menu.addSeparator() self.menu.addAction(clementine.IconLoader.Load("configure"), self.tr("Configure..."), self.settings_dialog_callback()) self.context_index = index self.menu.popup(global_pos) def GetCurrentIndex(self): return self.context_index def Homepage(self): QDesktopServices.openUrl(self.HOMEPAGE_URL) def RefreshStreams(self): if self.task_id is not None: return LOGGER.info("Getting stream list from '%s'", self.STREAM_LIST_URL) # Request the list of stations self.refresh_streams_reply = self.network.get(QNetworkRequest(self.STREAM_LIST_URL)) self.refresh_streams_reply.connect("finished()", self.RefreshStreamsFinished) # Give the user some indication that we're doing something self.task_id = clementine.task_manager.StartTask(self.tr("Getting streams")) def RefreshStreamsFinished(self): if self.refresh_streams_reply is None: return if self.task_id is None: return # Stop the spinner in the status bar clementine.task_manager.SetTaskFinished(self.task_id) self.task_id = None # Read the data and parse the json object inside json_data = self.refresh_streams_reply.readAll().data() streams = json.loads(json_data) # Sort by name streams = sorted(streams, key=operator.itemgetter("name")) LOGGER.info("Loaded %d streams", len(streams)) # Now we have the list of streams, so clear any existing items in the list # and insert the new ones if self.root.hasChildren(): self.root.removeRows(0, self.root.rowCount()) for stream in streams: song = clementine.Song() song.set_title(stream["name"]) song.set_artist(self.SERVICE_DESCRIPTION) song.set_url(QUrl("%s://%s" % (self.URL_SCHEME, stream["key"]))) item = QStandardItem(QIcon(":last.fm/icon_radio.png"), stream["name"]) item.setData(stream["description"], PythonQt.QtCore.Qt.ToolTipRole) item.setData(clementine.InternetModel.PlayBehaviour_SingleItem, clementine.InternetModel.Role_PlayBehaviour) item.setData(song, clementine.InternetModel.Role_SongMetadata) self.root.appendRow(item) # Keep references to the items otherwise Python will delete them self.items.append(item) def playlistitem_options(self): return clementine.PlaylistItem.Options(clementine.PlaylistItem.PauseDisabled) def LoadStation(self, key): raise NotImplementedError() def LoadPlaylistFinished(self): self.url_handler.LoadPlaylistFinished(self.load_station_reply)
def __init__(self, schid, cid, password='', path='/', parent=None, *, staticpath=False, readonly=False, downloaddir=None, iconpack=None): """ Instantiates a new object. @param schid: the id of the serverconnection handler @type schid: int @param cid: the id of the channel @type cid: int @param password: password to the channel, defaults to an empty string @type password: str @param path: path to display, defaults to the root path @type path: str @param parent: parent of the dialog; optional keyword arg; defaults to None @type parent: QWidget @param staticpath: if set to True, the initial path can't be changed by the user; optional keyword arg; defaults to False @type staticpath: bool @param readonly: if set to True, the user can't download, upload or delete files, or create new directories; optional keyword arg; defaults to False @type readonly: bool @param downloaddir: directory to download files to; optional keyword arg; defaults to None; if set to None, the TS3 client's download directory is used @type downloaddir: str @param iconpack: iconpack to load icons from; optional keyword arg; defaults to None; if set to None, the current iconpack is used @type iconpack: ts3client.IconPack """ super(QDialog, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) iconpackopened = False if not iconpack: try: iconpack = ts3client.IconPack.current() iconpack.open() iconpackopened = True except Exception as e: self.delete() raise e try: setupUi(self, pytson.getPluginPath("ressources", "filebrowser.ui"), iconpack=iconpack) self.statusbar = SmartStatusBar(self) self.layout().addWidget(self.statusbar) self.statusbar.hide() except Exception as e: self.delete() raise e err, cname = ts3lib.getChannelVariableAsString( schid, cid, ChannelProperties.CHANNEL_NAME) if err == ERROR_ok: self.setWindowTitle( self._tr("File Browser - {cname}").format(cname=cname)) else: self.setWindowTitle(self._tr("File Browser")) self.schid = schid self.cid = cid self.password = password self.path = None self.staticpath = staticpath self.readonly = readonly self.createretcode = None self.delretcode = None if not self.readonly and not downloaddir: cfg = ts3client.Config() q = cfg.query("SELECT value FROM filetransfer " "WHERE key='DownloadDir'") del cfg if q.next(): self.downloaddir = q.value("value") else: self.delete() raise Exception("Error getting DownloadDir from config") else: self.downloaddir = downloaddir if not self.readonly: menu = self.menu = QMenu(self) self.openAction = menu.addAction(QIcon(iconpack.icon("FILE_UP")), self._tr("Open")) self.openAction.connect("triggered()", self.on_openAction_triggered) self.downAction = menu.addAction(QIcon(iconpack.icon("DOWN")), self._tr("Download")) self.downAction.connect("triggered()", self.downloadFiles) self.renameAction = menu.addAction(QIcon(iconpack.icon("EDIT")), self._tr("Rename")) self.renameAction.connect("triggered()", self.on_renameAction_triggered) self.copyAction = menu.addAction(QIcon(iconpack.icon("COPY")), self._tr("Copy URL")) self.copyAction.connect("triggered()", self.on_copyAction_triggered) self.delAction = menu.addAction(QIcon(iconpack.icon("DELETE")), self._tr("Delete")) self.delAction.connect("triggered()", self.deleteFiles) self.upAction = menu.addAction(QIcon(iconpack.icon("UP")), self._tr("Upload files")) self.upAction.connect("triggered()", self.uploadFiles) self.createAction = menu.addAction(QIcon.fromTheme("folder"), self._tr("Create Folder")) self.createAction.connect("triggered()", self.createFolder) self.refreshAction = menu.addAction( QIcon(iconpack.icon("FILE_REFRESH")), self._tr("Refresh")) self.refreshAction.connect("triggered()", self.refresh) self.allactions = [ self.openAction, self.downAction, self.renameAction, self.copyAction, self.delAction, self.upAction, self.createAction, self.refreshAction ] self.collector = FileCollector(schid, cid, password, self.downloaddir) self.collector.collectionFinished.connect(self._startDownload) self.collector.collectionError.connect(self.showError) self.fileDoubleClicked = Signal() self.contextMenuRequested = Signal() self.transdlg = None self.listmodel = FileListModel(schid, cid, password, self, readonly=readonly) self.listmodel.pathChanged.connect(self.onPathChanged) self.listmodel.error.connect(self.showError) self.proxy = QSortFilterProxyModel(self) self.proxy.setSortRole(Qt.UserRole) self.proxy.setSortCaseSensitivity(Qt.CaseInsensitive) self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxy.setSourceModel(self.listmodel) self.listmodel.path = path self._adjustUi() if iconpackopened: iconpack.close() PluginHost.registerCallbackProxy(self)