def on_auto_search(self, *args): # Wishlists supported by server? if self.interval == 0: log.add_warning( _("The server forbid us from doing wishlist searches.")) return False searches = self.frame.np.config.sections["server"]["autosearch"] if not searches: return True # Search for a maximum of 1 item at each search interval term = searches.pop() searches.insert(0, term) for i in self.searches.searches.values(): if i["term"] == term and i["remember"]: i["ignore"] = False self.do_wishlist_search(i["id"], term) break return True
def amarok(self): """ Function to get amarok currently playing song """ try: import dbus import dbus.glib except ImportError as error: log.add_warning(_("ERROR: amarok: failed to load dbus module: %(error)s"), {"error": error}) return None self.bus = dbus.SessionBus() player = self.bus.get_object('org.mpris.amarok', '/Player') md = player.GetMetadata() for key, value in md.items(): if key == 'mtime': # Convert seconds to minutes:seconds value = float(value) / 1000 m, s = divmod(value, 60) self.title['length'] = "%d:%02d" % (m, s) elif key == 'audio-bitrate': self.title['bitrate'] = value elif key == "location": self.title['filename'] else: self.title[key] = value self.title['nowplaying'] = self.title['artist'] + ' - ' + self.title['title'] return True
def open_uri(uri, window): """Open a URI in an external (web) browser. The given argument has to be a properly formed URI including the scheme (fe. HTTP). As of now failures will be silently discarded.""" # Situation 1, user defined a way of handling the protocol protocol = uri[:uri.find(":")] protocol_handlers = NICOTINE.np.config.sections["urls"]["protocols"] if protocol in protocol_handlers and protocol_handlers[protocol]: try: execute_command(protocol_handlers[protocol], uri) return except RuntimeError as e: log.add_warning("%s", e) if protocol == "slsk": on_soul_seek_uri(uri.strip()) # Situation 2, user did not define a way of handling the protocol if sys.platform == "win32": import webbrowser webbrowser.open(uri) return try: Gtk.show_uri_on_window(window, uri, Gdk.CURRENT_TIME) except AttributeError: screen = window.get_screen() Gtk.show_uri(screen, uri, Gdk.CURRENT_TIME)
def add_port_mapping(self, np): """ This function supports creating a Port Mapping via the UPnP IGDv1 and IGDv2 protocol. Need a reference to the np object to extract the internal LAN local from the protothread socket. Any UPnP port mapping done with IGDv2 will expire after a maximum of 7 days (lease period), according to the protocol. We set the lease period to a shorter 24 hours, and regularly renew the port mapping (see pynicotine.py). """ try: self._add_port_mapping(np) except Exception as e: log.add_warning(_('UPnP exception: %(error)s'), {'error': str(e)}) log.add_warning(_('Failed to automate the creation of UPnP Port Mapping rule.')) return log.add_debug( _('Managed to map external WAN port %(externalwanport)s ' + 'to your local host %(internalipaddress)s ' + 'port %(internallanport)s.'), { 'externalwanport': self.externalwanport, 'internalipaddress': self.internalipaddress, 'internallanport': self.internallanport } )
def set_shares(self, sharestype="normal", files=None, streams=None, mtimes=None, wordindex=None, fileindex=None): if sharestype == "normal": storable_objects = [ (files, "sharedfiles", "files.db"), (streams, "sharedfilesstreams", "streams.db"), (mtimes, "sharedmtimes", "mtimes.db"), (wordindex, "wordindex", "wordindex.db"), (fileindex, "fileindex", "fileindex.db") ] else: storable_objects = [ (files, "bsharedfiles", "buddyfiles.db"), (streams, "bsharedfilesstreams", "buddystreams.db"), (mtimes, "bsharedmtimes", "buddymtimes.db"), (wordindex, "bwordindex", "buddywordindex.db"), (fileindex, "bfileindex", "buddyfileindex.db") ] for source, destination, filename in storable_objects: if source is not None: try: self.config.sections["transfers"][destination].close() self.config.sections["transfers"][destination] = shelve.open(os.path.join(self.config.data_dir, filename), flag='n', protocol=pickle.HIGHEST_PROTOCOL) self.config.sections["transfers"][destination].update(source) except Exception as e: log.add_warning(_("Can't save %s: %s") % (filename, e)) return
def create_menu(self): try: self.tray_popup_menu_server = popup0 = PopupMenu(self, False) popup0.setup( ("#" + _("Connect"), self.frame.on_connect), ("#" + _("Disconnect"), self.frame.on_disconnect) ) self.tray_popup_menu = popup = PopupMenu(self, False) popup.setup( ("#" + _("Hide / Show Nicotine+"), self.on_hide_unhide_window), (1, _("Server"), self.tray_popup_menu_server, None), ("#" + _("Downloads"), self.on_downloads), ("#" + _("Uploads"), self.on_uploads), ("#" + _("Send Message"), self.on_open_private_chat), ("#" + _("Lookup a User's IP"), self.on_get_a_users_ip), ("#" + _("Lookup a User's Info"), self.on_get_a_users_info), ("#" + _("Lookup a User's Shares"), self.on_get_a_users_shares), ("$" + _("Away"), self.frame.on_away), ("#" + _("Preferences"), self.frame.on_settings), ("#" + _("Quit"), self.frame.on_quit) ) except Exception as e: log.add_warning(_('ERROR: tray menu, %(error)s'), {'error': e})
def load_ui_elements(ui_class, filename): try: builder = Gtk.Builder() builder.set_translation_domain('nicotine') builder.add_from_file(filename) for obj in builder.get_objects(): try: obj_name = Gtk.Buildable.get_name(obj) if not obj_name.startswith("_"): setattr(ui_class, obj_name, obj) except TypeError: pass builder.connect_signals(ui_class) except Exception as e: log.add_warning(_("Failed to load ui file %(file)s: %(error)s"), { "file": filename, "error": e }) sys.exit()
def open_uri(uri, window): """Open a URI in an external (web) browser. The given argument has to be a properly formed URI including the scheme (fe. HTTP). As of now failures will be silently discarded.""" # Situation 1, user defined a way of handling the protocol protocol = uri[:uri.find(":")] protocol_handlers = config.sections["urls"]["protocols"] if protocol in protocol_handlers and protocol_handlers[protocol]: try: execute_command(protocol_handlers[protocol], uri) return except RuntimeError as e: log.add_warning("%s", e) if protocol == "slsk": on_soul_seek_uri(uri.strip()) return # Situation 2, user did not define a way of handling the protocol try: if sys.platform == "win32": os.startfile(uri) elif sys.platform == "darwin": execute_command("open $", uri) else: Gio.AppInfo.launch_default_for_uri(uri) except Exception as error: log.add_warning(_("Failed to open URL: %s"), str(error))
def open_uri(uri, window): """Open a URI in an external (web) browser. The given argument has to be a properly formed URI including the scheme (fe. HTTP). As of now failures will be silently discarded.""" # Situation 1, user defined a way of handling the protocol protocol = uri[:uri.find(":")] if protocol in PROTOCOL_HANDLERS: if isinstance(PROTOCOL_HANDLERS[protocol], types.MethodType): PROTOCOL_HANDLERS[protocol](uri.strip()) return if PROTOCOL_HANDLERS[protocol]: try: execute_command(PROTOCOL_HANDLERS[protocol], uri) return except RuntimeError as e: log.add_warning("%s", e) # Situation 2, user did not define a way of handling the protocol if sys.platform == "win32" and webbrowser: webbrowser.open(uri) return try: Gtk.show_uri_on_window(window, uri, Gdk.CURRENT_TIME) except AttributeError: screen = window.get_screen() Gtk.show_uri(screen, uri, Gdk.CURRENT_TIME)
def on_tab_click(self, widget, event, child): if event.type == Gdk.EventType.BUTTON_PRESS: search_id = None n = self.page_num(child) page = self.get_nth_page(n) for search, data in self.searches.items(): if data[2] is None: continue if data[2].Main is page: search_id = search break if search_id is None: log.add_warning(_("Search ID was none when clicking tab")) return if event.button == 2: self.searches[search_id][2].on_close(widget) return True if event.button == 3: menu = self.tab_popup(search_id) menu.popup(None, None, None, None, event.button, event.time) return True return False
def foobar(self): """ Function to get foobar currently playing song on windows """ if sys.platform == "win32": try: from win32gui import GetWindowText, FindWindow except ImportError as error: log.add_warning(_("ERROR: foobar: failed to load win32gui module: %(error)s"), {"error": error}) return None else: log.add_warning(_("ERROR: foobar: is only supported on windows.")) return None wnd_ids = [ '{DA7CD0DE-1602-45e6-89A1-C2CA151E008E}', '{97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}', '{E7076D1C-A7BF-4f39-B771-BCBE88F2A2A8}' ] metadata = None for wnd_id in wnd_ids: wnd_txt = GetWindowText(FindWindow(wnd_id, None)) if wnd_txt: m = re.match(r"(.*)\\s+\[foobar.*", wnd_txt) if m: metadata = m.groups()[0].strip() if metadata: self.title["nowplaying"] = "now playing: " + metadata.decode('mbcs') return True else: return None
def on_search(self): self.save_columns() text = self.frame.SearchEntry.get_text().strip() if not text: return users = [] room = None search_mode = self.frame.SearchMethod.get_active_id() feedback = None if search_mode == "global": feedback = self.frame.np.pluginhandler.outgoing_global_search_event(text) if feedback is not None: text = feedback[0] elif search_mode == "rooms": name = self.frame.RoomSearchEntry.get_text() # Space after Joined Rooms is important, so it doesn't conflict # with any possible real room if name != _("Joined Rooms ") and not name.isspace(): room = name feedback = self.frame.np.pluginhandler.outgoing_room_search_event(room, text) if feedback is not None: (room, text) = feedback elif search_mode == "buddies": feedback = self.frame.np.pluginhandler.outgoing_buddy_search_event(text) if feedback is not None: text = feedback[0] elif search_mode == "user": user = self.frame.UserSearchEntry.get_text().strip() if user: users = [user] else: return feedback = self.frame.np.pluginhandler.outgoing_user_search_event(users, text) if feedback is not None: (users, text) = feedback else: log.add_warning(_("Unknown search mode, not using plugin system. Fix me!")) feedback = True if feedback is not None: self.do_search(text, search_mode, users, room)
def on_search(self): self.save_columns() text = self.frame.search_entry.get_text().strip() if not text: return users = [] room = None search_mode = self.frame.SearchMethod.get_model().get(self.frame.SearchMethod.get_active_iter(), 0)[0] if search_mode == _("Global"): mode = 0 elif search_mode == _("Rooms"): mode = 1 name = self.frame.RoomSearchCombo.get_child().get_text() # Space after Joined Rooms is important, so it doesn't conflict # with any possible real room if name != _("Joined Rooms ") and not name.isspace(): room = name elif search_mode == _("Buddies"): mode = 2 elif search_mode == _("User"): mode = 3 user = self.frame.UserSearchCombo.get_child().get_text().strip() if user != "" and not user.isspace(): users = [user] else: return else: mode = 0 feedback = None if mode == 0: feedback = self.frame.np.pluginhandler.outgoing_global_search_event(text) if feedback is not None: text = feedback[0] elif mode == 1: feedback = self.frame.np.pluginhandler.outgoing_room_search_event(room, text) if feedback is not None: (room, text) = feedback elif mode == 2: feedback = self.frame.np.pluginhandler.outgoing_buddy_search_event(text) if feedback is not None: text = feedback[0] elif mode == 3: feedback = self.frame.np.pluginhandler.outgoing_user_search_event(users) if feedback is not None: users = feedback[0] else: log.add_warning(_("Unknown search mode, not using plugin system. Fix me!")) feedback = True if feedback is not None: self.do_search(text, mode, users, room) self.frame.search_entry.set_text("")
def create_data_folder(self): """ Create the folder for storing data in (aliases, shared files etc.), if the folder doesn't exist """ try: if not os.path.isdir(self.data_dir): os.makedirs(self.data_dir) except OSError as msg: log.add_warning(_("Can't create directory '%(path)s', reported error: %(error)s"), {'path': self.data_dir, 'error': msg})
def create_config_folder(self): """ Create the folder for storing the config file in, if the folder doesn't exist """ path, fn = os.path.split(self.filename) try: if not os.path.isdir(path): os.makedirs(path) except OSError as msg: log.add_warning(_("Can't create directory '%(path)s', reported error: %(error)s"), {'path': path, 'error': msg})
def on_tab_popup(self, widget, child): search_id = self.get_search_id(child) if search_id is None: log.add_warning(_("Search ID was none when clicking tab")) return False menu = self.searches[search_id]["tab"].tab_menu menu.popup() return True
def open_file_path(file_path, command=None): """ Currently used to either open a folder or play an audio file Tries to run a user-specified command first, and falls back to the system default. """ if command and "$" in command: execute_command(command, file_path) else: try: Gio.AppInfo.launch_default_for_uri("file:///" + file_path) except GLib.Error as error: log.add_warning(_("Failed to open folder: %s"), str(error))
def other(self): try: othercommand = self.NPCommand.get_text() if othercommand == "": return None output = execute_command(othercommand, returnoutput=True) self.title["nowplaying"] = output return True except Exception as error: log.add_warning(_("ERROR: Executing '%(command)s' failed: %(error)s"), {"command": othercommand, "error": error}) return None
def tts_player(self, message): self.tts_playing = True try: execute_command(config.sections["ui"]["speechcommand"], message, background=False) except Exception as error: log.add_warning(_("Text-to-speech for message failed: %s"), str(error))
def add_row_to_model(self, row): counter, user, flag, immediatedl, h_speed, h_queue, directory, filename, h_size, h_bitrate, length, bitrate, fullpath, country, size, speed, queue = row if self.ResultGrouping.get_active_id() != "ungrouped": # Group by folder or user if user not in self.usersiters: self.usersiters[user] = self.resultsmodel.append( None, [ 0, user, self.get_flag( user, country), immediatedl, h_speed, h_queue, "", "", "", "", "", 0, "", country, 0, speed, queue ]) parent = self.usersiters[user] if self.ResultGrouping.get_active_id() == "folder_grouping": # Group by folder if directory not in self.directoryiters: self.directoryiters[directory] = self.resultsmodel.append( self.usersiters[user], [ 0, user, self.get_flag(user, country), immediatedl, h_speed, h_queue, directory, "", "", "", "", 0, fullpath.rsplit('\\', 1)[0] + '\\', country, 0, speed, queue ]) row = row[:] row[6] = "" # Directory not visible for file row if "group by folder" is enabled parent = self.directoryiters[directory] else: parent = None try: iterator = self.resultsmodel.append(parent, row) self.numvisibleresults += 1 except Exception as e: types = [] for i in row: types.append(type(i)) log.add_warning(_("Search row error: %(exception)s %(row)s"), { 'exception': e, 'row': row }) iterator = None return iterator
def write_aliases(self): self.create_config_folder() try: with open(self.filename + ".alias", "wb") as f: pickle.dump(self.aliases, f, protocol=pickle.HIGHEST_PROTOCOL) except IOError as e: log.add_warning(_("Something went wrong while opening your alias file: %s"), e) except Exception as e: log.add_warning(_("Something went wrong while saving your alias file: %s"), e)
def on_tab_click(self, widget, event, child): search_id = self.get_search_id(child) if search_id is None: log.add_warning(_("Search ID was none when clicking tab")) return False if triggers_context_menu(event): return self.on_tab_popup(widget, child) if event.button == 2: self.searches[search_id]["tab"].on_close(widget) return True return False
def load_shares(self, dbs): errors = [] for destination, shelvefile in dbs: try: self.config.sections["transfers"][destination] = shelve.open(shelvefile, protocol=pickle.HIGHEST_PROTOCOL) except Exception: errors.append(shelvefile) if errors: log.add_warning(_("Failed to process the following databases: %(names)s") % {'names': '\n'.join(errors)}) self.clear_shares() log.add_warning(_("Shared files database seems to be corrupted, rescan your shares"))
def compress_shares(self, sharestype): if sharestype == "normal": streams = self.config.sections["transfers"]["sharedfilesstreams"] elif sharestype == "buddy": streams = self.config.sections["transfers"]["bsharedfilesstreams"] if streams is None: log.add_warning(_("ERROR: No %(type)s shares database available") % {"type": sharestype}) return m = slskmessages.SharedFileList(None, streams) _thread.start_new_thread(m.make_network_message, (0, True)) if sharestype == "normal": self.compressed_shares_normal = m elif sharestype == "buddy": self.compressed_shares_buddy = m
def on_tab_popup(self, widget, child): search_id = self.get_search_id(child) if search_id is None: log.add_warning(_("Search ID was none when clicking tab")) return False menu = PopupMenu(self.frame) menu.setup( ("#" + _("Copy Search Term"), self.searches[search_id]["tab"].on_copy_search_term), ("", None), ("#" + _("Clear All Results"), self.searches[search_id]["tab"].on_clear), ("#" + _("Close All Tabs"), menu.on_close_all_tabs, self), ("#" + _("_Close Tab"), self.searches[search_id]["tab"].on_close)) menu.popup() return True
def write_aliases(self): try: f = open(self.filename + ".alias", "wb") except Exception as e: log.add_warning( _("Something went wrong while opening your alias file: %s"), e) else: try: pickle.dump(self.aliases, f, protocol=pickle.HIGHEST_PROTOCOL) f.close() except Exception as e: log.add_warning( _("Something went wrong while saving your alias file: %s"), e) finally: try: f.close() except Exception: pass
def set_image(self, status=None): if not self.is_visible(): return try: if status is not None: self.tray_status["status"] = status # Check for hilites, and display hilite icon if there is a room or private hilite if self.frame.hilites["rooms"] or self.frame.hilites["private"]: icon_name = "msg" else: # If there is no hilite, display the status icon_name = self.tray_status["status"] if icon_name != self.tray_status["last"]: self.tray_status["last"] = icon_name if self.appindicator is not None: if self.custom_icons: icon_name = "trayicon_" + icon_name else: icon_name = GLib.get_prgname() + "-" + icon_name self.trayicon.set_icon_full(icon_name, GLib.get_application_name()) else: # GtkStatusIcon fallback if self.custom_icons or self.local_icons: self.trayicon.set_from_pixbuf( self.frame.images["trayicon_" + icon_name]) else: self.trayicon.set_from_icon_name(GLib.get_prgname() + "-" + icon_name) except Exception as e: log.add_warning(_("ERROR: cannot set trayicon image: %(error)s"), {'error': e})
def on_leave(self, *args): if self.leaving: return self.leaving = True if self.room in config.sections["columns"]["chat_room"]: del config.sections["columns"]["chat_room"][self.room] if not self.meta: self.frame.np.queue.append(slskmessages.LeaveRoom(self.room)) else: if self.room == 'Public ': self.frame.np.queue.append(slskmessages.LeavePublicRoom()) self.chatrooms.leave_room(slskmessages.LeaveRoom( self.room)) # Faking protocol msg else: log.add_warning(_("Unknown meta chatroom closed")) self.frame.np.pluginhandler.leave_chatroom_notification(self.room)
def load_shares(cls, shares, dbs, reset_shares=False): errors = [] for destination, shelvefile in dbs: try: if not reset_shares: shares[destination] = shelve.open( shelvefile, protocol=pickle.HIGHEST_PROTOCOL) else: shares[destination] = shelve.open( shelvefile, flag='n', protocol=pickle.HIGHEST_PROTOCOL) except Exception: from traceback import format_exc shares[destination] = None errors.append(shelvefile) exception = format_exc() if errors: log.add_warning( _("Failed to process the following databases: %(names)s"), {'names': '\n'.join(errors)}) log.add_warning(exception) log.add_warning( _("Shared files database seems to be corrupted, rescan your shares" )) if not reset_shares: cls.load_shares(shares, dbs, reset_shares=True)
def lastfm(self): """ Function to get the last song played via lastfm api """ import http.client import json try: conn = http.client.HTTPSConnection("ws.audioscrobbler.com") except Exception as error: log.add_warning(_("ERROR: lastfm: Could not connect to audioscrobbler: %(error)s"), {"error": error}) return None try: (user, apikey) = self.NPCommand.get_text().split(';') except ValueError: log.add_warning(_("ERROR: lastfm: Please provide both your lastfm username and API key")) return None conn.request("GET", "/2.0/?method=user.getrecenttracks&user="******"&api_key=" + apikey + "&format=json", headers={"User-Agent": "Nicotine+"}) resp = conn.getresponse() data = resp.read().decode("utf-8") if resp.status != 200 or resp.reason != "OK": log.add_warning(_("ERROR: lastfm: Could not get recent track from audioscrobbler: %(error)s"), {"error": str(data)}) return None json_api = json.loads(data) lastplayed = json_api["recenttracks"]["track"][0] self.title["artist"] = lastplayed["artist"]["#text"] self.title["title"] = lastplayed["name"] self.title["album"] = lastplayed["album"]["#text"] self.title["nowplaying"] = "%s: %s - %s - %s" % (_("Last played"), self.title["artist"], self.title["album"], self.title["title"]) return True