def handleQuery(query): results = [] if query.isTriggered: if len(query.string) > 2: pattern = re.compile(query.string, re.IGNORECASE) proc = subprocess.Popen([ 'locate', '-i' if query.trigger == "''" else "-bi", query.string ], stdout=subprocess.PIPE) for line in proc.stdout: path = line.decode().strip() basename = os.path.basename(path) results.append( Item(id=path, icon=iconPath, text=pattern.sub(lambda m: "<u>%s</u>" % m.group(0), basename), subtext=path, completion="%s%s" % (__triggers__, basename), actions=[UrlAction("Open", "file://%s" % path)])) else: results.append( Item(id=__title__, icon=iconPath, text="Update locate database", subtext="Type at least three chars for a seach", actions=[ TermAction("Update database", ["sudo", "updatedb"]) ])) return results
def handleQuery(query): if query.isTriggered: return [ Item(id="%s-whole-screen" % __title__, icon=iconPath, text="Screen", subtext="Take a screenshot of the whole screen", actions=[ FuncAction("Take screenshot of whole screen", lambda: doScreenshot([])), FuncAction("Take screenshot of multiple displays", lambda: doScreenshot(["--multidisp"])), ]), Item(id="%s-area-of-screen" % __title__, icon=iconPath, text="Area", subtext="Draw a rectangle with your mouse to capture an area", actions=[ FuncAction("Take screenshot of selected area", lambda: doScreenshot(["--select"])), ]), Item(id="%s-current-window" % __title__, icon=iconPath, text="Window", subtext="Take a screenshot of the current active window", actions=[ FuncAction( "Take screenshot of window with borders", lambda: doScreenshot(["--focused", "--border"])), FuncAction("Take screenshot of window without borders", lambda: doScreenshot(["--focused"])), ]), ]
def handleQuery(query): results = [] if query.isTriggered: # avoid rate limiting sleep(0.2) if not query.isValid: return item = Item(id=__title__, icon=iconPath, text=__title__, actions=[ ProcAction("Open the language configuration file.", commandline=[ "xdg-open", language_configuration_file ]) ]) if len(query.string) >= 2: for lang in languages: try: url = urltmpl % (lang, urllib.parse.quote_plus( query.string)) req = urllib.request.Request(url, headers={'User-Agent': ua}) with urllib.request.urlopen(req) as response: #print(type()) #try: data = json.loads(response.read().decode()) #except TypeError as typerr: # print("Urgh this type.error. %s" % typerr) translText = data[0][0][0] sourceText = data[2] if sourceText == lang: continue else: results.append( Item(id=__title__, icon=iconPath, text="%s" % (translText), subtext="%s" % lang.upper(), actions=[ ClipAction( "Copy translation to clipboard", translText), UrlAction( "Open in your Browser", urlbrowser % (lang, query.string)) ])) except urllib.error.URLError as urlerr: print("Check your internet connection: %s" % urlerr) item.subtext = "Check your internet connection." return item else: item.subtext = "Enter a query: 'mtr <text>'. Languages {%s}" % ", ".join( languages) return item return results
def createItems(windows, spans=None): results = [] # print('spans: ', spans) # [print(w.wm_name) for w in windows] # print(len(windows)) for win in windows: if spans: text_subtext = highlightText(win, spans[win.wid]) else: text_subtext = { 'text': '%s: %s' % (win.desktop, win.wm_class.split('.')[-1].replace('-', ' ')), 'subtext': '%s➜%s' % (win.wm_class.split('.')[-1], win.wm_name) } win_instance, win_class = win.wm_class.replace(' ', '-').split('.') iconPath = iconLookup(win_instance) or iconLookup(win_class.lower()) results.append( Item(id="%s%s" % (__title__, win.wm_class), **text_subtext, icon=iconPath, actions=[ ProcAction(text="Switch Window", commandline=["wmctrl", '-i', '-a', win.wid]), ProcAction(text="Move window to this desktop", commandline=["wmctrl", '-i', '-R', win.wid]), ProcAction(text="Close the window gracefully.", commandline=["wmctrl", '-c', win.wid]) ])) return results
def handleList(query): if len(config.sections()) == 0: # Try to reload the config. config.read(calendar_configuration_file) if len(config.sections()) == 0: info("No sections defined in config.") return Item(id="config", icon=unresolved_todo, text="Configuration not complete", subtext="No sections in the Configuration file", actions=[ ProcAction( text="Edit configuration in default editor", commandline=['xdg-open', calendar_configuration_file], cwd="~"), ClipAction( text="Copy the path of the configuration file", clipboardText=calendar_configuration_file) ]) else: connections.set_connections(config) connections.load_todos() items = [] connections.refresh() for todo in connections.query(query.string): items.append(buildItem(todo)) return items
def handleQuery(query): if query.isTriggered: query.disableSort() files = getConfigFiles() all_connections = [getConnectionProperties(f) for f in files] stripped = query.string.strip() results = [] if stripped: # specific query by the user for p in all_connections: # search in names and groups if search(stripped, p[0], IGNORECASE) or search(stripped, p[1], IGNORECASE): results.append(getAsItem(*p)) else: # nothing specified yet, show all possible connections for p in all_connections: results.append(getAsItem(*p)) # add it at the very end - fallback choice in case none of the connections is what the # user wants results.append( Item( id=__title__, icon=ICON_PATH, text=__title__, subtext=__doc__, actions=[FuncAction("Open Remmina", runRemmina)], ) ) return results
def handleQuery(query): if query.isTriggered: results = [] uid = os.getuid() for dir_entry in os.scandir('/proc'): try: if dir_entry.name.isdigit() and dir_entry.stat().st_uid == uid: proc_command = open(os.path.join(dir_entry.path, 'comm'), 'r').read().strip() if query.string in proc_command: proc_cmdline = open( os.path.join(dir_entry.path, 'cmdline'), 'r').read().strip().replace("\0", " ") results.append( Item(id="kill_%s" % proc_cmdline, icon=iconPath, text=proc_command.replace( query.string, "<u>%s</u>" % query.string), subtext=proc_cmdline, actions=[ FuncAction("Terminate", lambda pid=int(dir_entry.name): os.kill(pid, SIGTERM)), FuncAction("Kill", lambda pid=int(dir_entry.name): os.kill(pid, SIGKILL)) ])) except FileNotFoundError: # TOCTOU dirs may disappear continue except IOError: # TOCTOU dirs may disappear continue return results
def getAsItem(name, group, server, proto, file): return Item( id=__title__, icon=PROTOCOL_ICONS_PATH % (proto.lower()), text=(name, "%s/ %s" % (group, name))[len(group) > 0], subtext="%s %s" % (proto, server), actions=[FuncAction("Open connection", lambda cf=file: runRemmina(cf))], )
def handleQuery(query): if query.string.strip() and "trash".startswith(query.string.lower()): pattern = re.compile(query.string, re.IGNORECASE) return Item(id="trash-open", icon=iconPath, text=pattern.sub(lambda m: "<u>%s</u>" % m.group(0), "Trash"), subtext="Show trash folder", completion="trash", actions=[UrlAction("Show", "trash:///")])
def handleQuery(query): if query.isTriggered: return Item(id=__title__, icon=iconPath, text=__title__, subtext="Look up '%s' using %s" % (query.string, __title__), actions=[ ProcAction("Start query in %s" % __title__, ["goldendict", query.string]) ])
def buildItem(completion, dst, number, padding=0): item = Item(id=__title__, completion=completion) try: src = base_prefixes[number[:2]] dst = int(dst) padding = int(padding) integer = int(number, src) item.text = np.base_repr(integer, dst) if integer >= 0 and len(item.text) < padding: item.text = '0' * (padding - len(item.text)) + item.text item.subtext = "Base %s representation of %s (base %s)" % (dst, number, src) item.addAction(ClipAction("Copy to clipboard", item.text)) except Exception as e: item.text = e.__class__.__name__ item.subtext = str(e) return item
def searchMovies(query): query_url = "http://www.omdbapi.com/?s={}&apikey=e389610c".format( query.string.strip()) try: res = http.request("GET", query_url) data = json.loads(res.data) except: critical("No Internet!") return [ Item( id=__prettyname__, icon=iconLookup("dialog-warning"), text="Is internet working?", subtext="We could not query, check your internet connection", completion=query.rawString, ) ] itemArr = [] if data["Response"] == "True": return [ Item( id=__prettyname__, icon=_get_icon("movie"), text="{}".format(mediaItem["Title"]), subtext= f"Type: {mediaItem['Type'].capitalize()}. Press tab for more info!", completion=__triggers__ + "id: " + mediaItem["imdbID"], ) for mediaItem in data["Search"] ] else: return Item( id=__prettyname__, icon=iconLookup("dialog-warning"), text="Too many results", subtext="Too many results returned, Please be specifics", completion=query.rawString, )
def handleQuery(query): if query.isTriggered: fields = query.string.split() if len(fields) == 2: return buildItem(query.rawString, fields[0], fields[1]) else: item = Item(id=__title__) item.text = __title__ item.subtext = "Enter a query in the form of \"<dstbase> <number>\"" return item else: fields = query.string.split() if len(fields) < 2: return src = base_prefixes[fields[:3]] number = fields[1] padding = 0 if len(fields) < 3 else fields[2] results = [] for dst in sorted(base_prefixes.values().append(8)): if dst == src: continue results.append(buildItem(query.rawString, dst, number, padding)) return results
def handleQuery(query): if query.isTriggered: if len(query.string.strip()) >= 3: if query.string.strip().startswith("id:"): mid = query.string.strip().replace("id: ", "") return movieInfo(mid) return searchMovies(query) else: return Item( id=__prettyname__, icon=_get_icon("movie"), text=__prettyname__, subtext="Type in the movie name", completion=query.rawString, )
def handleQuery(query): if not query.isTriggered: return item = Item(icon=ICON_PATH) stripped = query.string.strip() if stripped: with NamedTemporaryFile() as f: f.write(bytes(stripped, 'utf-8')) f.flush() output = subprocess.check_output(['wolframscript', '-print', '-f', f.name]) result = str(output.strip(), 'utf-8') item.text = result item.subtext = 'Result' item.addAction(ClipAction('Copy result to clipboard', result)) else: item.text = '' item.subtext = 'Type a Mathematica expression' return item
def handleQuery(query): results = [] # add all matching commands stripped = query.string.strip().lower().split() if stripped: for title, command in commands.items(): # query is split on spaces and each part must be in the command title title_lower = title.lower() if all(strip in title_lower for strip in stripped): results.append( Item(id=title, text=title, subtext=' '.join(command), actions=[ ProcAction("Run", command), ])) return results
def handleQuery(query): stripped = query.string.strip().lower() if stripped: results = [] for line in subprocess.check_output(['wmctrl', '-lG', '-x']).splitlines(): try: win = Window(*parseWindow(line)) if win.desktop == "-1": continue win_instance, win_class = win.wm_class.replace(' ', '-').split('.') matches = [ win_instance.lower(), win_class.lower(), win.wm_name.lower() ] if any(stripped in match for match in matches): iconPath = iconLookup(win_instance) or iconLookup( win_class.lower()) results.append( Item(id="%s%s" % (__title__, win.wm_class), icon=iconPath, text="%s - <i>Display %s</i>" % (win_class.replace('-', ' '), win.display), subtext=win.wm_name, actions=[ ProcAction("Switch Window", ["wmctrl", '-i', '-a', win.wid]), ProcAction("Move window to this desktop", ["wmctrl", '-i', '-R', win.wid]), ProcAction("Close the window gracefully.", ["wmctrl", '-c', win.wid]) ])) except: continue return results
def handleAdd(query): actions = [] onehour = datetime.datetime.now() + datetime.timedelta(hours=1) tomorrow = datetime.datetime.now() + datetime.timedelta(days=1) tomorrow.replace(hour=9, minute=0, second=0) # always 9 AM nextweek = datetime.datetime.now() + datetime.timedelta(days=7) nextweek.replace(hour=9, minute=0, second=0) # always 9 AM for name in connections.config.sections(): actions.append( FuncAction(text=f"Create todo in {name}", callable=lambda: connections.createTodo( name, query.string)) ) actions.append( FuncAction(text=f"Create todo in {name} for in one hour", callable=lambda: connections.createTodo( name, query.string, onehour)) ) actions.append( FuncAction(text=f"Create todo in {name} for tomorrow", callable=lambda: connections.createTodo( name, query.string, tomorrow)) ) actions.append( FuncAction(text=f"Create todo in {name} for next week", callable=lambda: connections.createTodo( name, query.string, nextweek)) ) return Item( id=f"newtodo-{query.string}", text=query.string, subtext="Create a new todo", icon=iconLookup("add"), actions=actions )
def buildVmItem(vm): item = Item(id=vm.__uuid__, icon=iconPath, text=vm.name, subtext="{vm.state}".format(vm=vm), completion=vm.name) if vm.state == MachineState.powered_off: #1 item.addAction( FuncAction(text="Start virtual machine", callable=lambda: startVm(vm))) if vm.state == MachineState.saved: #2 item.addAction( FuncAction(text="Restore virtual machine", callable=lambda: startVm(vm))) item.addAction( FuncAction(text="Discard saved state", callable=lambda: discardSavedVm(vm))) if vm.state == MachineState.aborted: #4 item.addAction( FuncAction(text="Start virtual machine", callable=lambda: startVm(vm))) if vm.state == MachineState.running: #5 item.addAction( FuncAction(text="Save virtual machine", callable=lambda: saveVm(vm))) item.addAction( FuncAction(text="Power off via ACPI event (Power button)", callable=lambda: acpiPowerVm(vm))) item.addAction( FuncAction(text="Turn off virtual machine", callable=lambda: stopVm(vm))) item.addAction( FuncAction(text="Pause virtual machine", callable=lambda: pauseVm(vm))) if vm.state == MachineState.paused: #6 item.addAction( FuncAction(text="Resume virtual machine", callable=lambda: resumeVm(vm))) return item
def handleQuery(query): if query.isTriggered: fields = query.string.split() if len(fields) == 1: src = "de" dst = "en" txt = " ".join(fields) elif len(fields) >= 2: if fields[0] == ">": src = "de" dst = "en" txt = " ".join(fields[1:]) elif fields[0] == "<": src = "en" dst = "de" txt = " ".join(fields[1:]) else: src = fields[0] dst = fields[1] txt = " ".join(fields[2:]) # If neither source nor destination are valid languages, assume that it is a standard case with # multiple words (cc kinder erziehen) if src not in AVAILABLE_LANGUAGES and dst not in AVAILABLE_LANGUAGES: src = "de" dst = "en" txt = " ".join(fields) elif src not in ["de", "en"] and dst not in ["de", "en"]: item = Item(id=__title__, icon=iconPath, completion=query.rawString) item.text = "Unsupported language combination!" item.subtext = "One language must be one of ['en', 'de']." return item elif src not in AVAILABLE_LANGUAGES or dst not in AVAILABLE_LANGUAGES: item = Item(id=__title__, icon=iconPath, completion=query.rawString) item.text = "Unsupported language!" item.subtext = "Source and destination language must be one of %s." % [ x for x in AVAILABLE_LANGUAGES.keys() ] return item else: item = Item(id=__title__, icon=iconPath, completion=query.rawString) item.text = __title__ item.subtext = "Enter a query in the form of \"<srclang> <dstlang> <text>\"" return item result = Dict.translate(txt, src, dst) items = [] for input_word, output_word in result.translation_tuples: # critical(input_word + " | " + output_word) # Select correct value as translation # Dict.cc can only do <any language> <-> German or English # If src->dst are de->en or en->de, de is always the output # If src or dst is something else, it can vary, but we can detect that: # * If src or dst is german, from or to is "Deutsch", the other one is the other language # * If src or dst is english, form or to is "English", the other one is the other language if src == "de" and dst == "en": inp = output_word output = input_word elif src == "en" and dst == "de": inp = input_word output = output_word elif src == "de": inp, output = resolve(result.from_lang, result.to_lang, input_word, output_word, "Deutsch", True) elif dst == "de": inp, output = resolve(result.from_lang, result.to_lang, input_word, output_word, "Deutsch", False) elif src == "en": inp, output = resolve(result.from_lang, result.to_lang, input_word, output_word, "English", True) elif dst == "en": inp, output = resolve(result.from_lang, result.to_lang, input_word, output_word, "English", False) else: inp, output = error_text item = Item(id=__title__, icon=iconPath, completion=query.rawString) item.text = output item.subtext = "%s->%s translation of '%s'" % (src, dst, inp) item.addAction(ClipAction("Copy translation to clipboard", output)) items.append(item) # If there where no results if len(items) == 0: item = Item(id=__title__, icon=iconPath, completion=query.rawString) item.text = "No results found!" items.append(item) else: # Add URL entry item = Item(id=__title__, icon=iconPath, completion=query.rawString) item.addAction(UrlAction("Open dict.cc", result.request_url)) item.text = "Show all results (opens browser)" item.subtext = "Tip: You can scroll Alberts result list with your arrow keys to show more results." items.insert(0, item) return items
def movieInfo(mid): query_url = "http://www.omdbapi.com/?i={}&apikey=e389610c".format(mid) try: res = http.request("GET", query_url) data = json.loads(res.data) except: critical("No Internet!") return [ Item( id=__prettyname__, icon=iconLookup("dialog-warning"), text="Is internet working?", subtext="We could not query, check your internet connection", ) ] itemArr = [] if data["Response"] == "True": # Append movie name itemArr.append( Item( id=__prettyname__, icon=_get_icon("movie"), text=data["Title"], subtext="Title", )) # Append movie genre itemArr.append( Item( id=__prettyname__, icon=_get_icon("genre"), text=data["Genre"], subtext="Genre", )) # Append director itemArr.append( Item( id=__prettyname__, icon=_get_icon("director"), text=data["Director"], subtext="Director", )) # Append Actors itemArr.append( Item( id=__prettyname__, icon=_get_icon("actors"), text=data["Actors"], subtext="Actors", )) # Append Plot itemArr.append( Item( id=__prettyname__, icon=_get_icon("plot"), text=data["Plot"], subtext="Plot", )) # Append Awards itemArr.append( Item( id=__prettyname__, icon=_get_icon("awards"), text=data["Awards"], subtext="Awards", )) # Append Metascore itemArr.append( Item( id=__prettyname__, icon=_get_icon("metacritic"), text=data["Metascore"], subtext="Metascore", )) # Append imdbRating imdb_url = "https://www.imdb.com/title/" + mid itemArr.append( Item( id=__prettyname__, icon=_get_icon("imdb"), text=data["imdbRating"], subtext="IMDB Rating, Click to open on IMDB", actions=[UrlAction("Open article on Wikipedia", imdb_url)], )) # TODO : Append Rotten tomatoes rating # Open on IMDB return itemArr else: critical("No Internet!") return [ Item( id=__prettyname__, icon=iconLookup("dialog-warning"), text="Movie Not found", subtext="Movie does not exist in database", ) ] return Item(id=__prettyname__, icon=iconLookup("dialog-warning"), text=str(mid))
def handleQuery(query): if query.isTriggered: if not query.string.strip(): return Item( id="%s-update" % __name__, icon=iconPath, text="Pacman package manager", subtext="Enter the package you are looking for or hit enter to update.", completion=__triggers__, actions=[ TermAction("Update the system (no confirm)", "sudo pacman -Syu --noconfirm"), TermAction("Update the system", "sudo pacman -Syu") ] ) time.sleep(0.1) if not query.isValid: return # Get data. Results are sorted so we can merge in O(n) proc_s = subprocess.Popen(["expac", "-Ss", "%n\t%v\t%r\t%d\t%u\t%E", query.string], stdout=subprocess.PIPE, universal_newlines=True) proc_q = subprocess.Popen(["expac", "-Qs", "%n", query.string], stdout=subprocess.PIPE, universal_newlines=True) proc_q.wait() items = [] pattern = re.compile(query.string, re.IGNORECASE) local_pkgs = set(proc_q.stdout.read().split('\n')) remote_pkgs = [tuple(line.split('\t')) for line in proc_s.stdout.read().split('\n')[:-1]] # newline at end for pkg_name, pkg_vers, pkg_repo, pkg_desc, pkg_purl, pkg_deps in remote_pkgs: if not pattern.search(pkg_name): continue pkg_installed = True if pkg_name in local_pkgs else False item = Item( id="%s:%s:%s" % (__name__, pkg_repo, pkg_name), icon=iconPath, text="%s <i>%s</i> [%s]" % (pattern.sub(lambda m: "<u>%s</u>" % m.group(0), pkg_name), pkg_vers, pkg_repo), subtext=("<b>[Installed]</b> %s%s" if pkg_installed else "%s%s") % (pkg_desc, (" <i>(%s)</i>" % pkg_deps) if pkg_deps else ""), completion="%s%s" % (query.trigger, pkg_name) ) items.append(item) if pkg_installed: item.addAction(TermAction("Remove", "sudo pacman -Rs %s" % pkg_name)) item.addAction(TermAction("Reinstall", "sudo pacman -S %s" % pkg_name)) else: item.addAction(TermAction("Install", "sudo pacman -S %s" % pkg_name)) item.addAction(UrlAction("Show on packages.archlinux.org", "https://www.archlinux.org/packages/%s/x86_64/%s/" % (pkg_repo, pkg_name))) if pkg_purl: item.addAction(UrlAction("Show project website", pkg_purl)) if items: return items else: return Item( id="%s-empty" % __name__, icon=iconPath, text="Search on archlinux.org", subtext="No results found in the local database", actions=[ UrlAction("Search on archlinux.org", "https://www.archlinux.org/packages/?q=%s" % query.string.strip()) ] ) elif len(query.string.strip()) > 0 and ("pacman".startswith(query.string.lower()) or "update".startswith(query.string.lower())): return Item( id="%s-update" % __name__, icon=iconPath, text="Update all packages on the system", subtext="Synchronizes the repository databases and updates the system's packages", actions=[ TermAction("Update the system (no confirm)", "sudo pacman -Syu --noconfirm"), TermAction("Update the system", "sudo pacman -Syu") ] )
def buildItem(todo): obj = todo["todo"] uid = obj.vtodo.uid.valueRepr() text = "{}: {}".format(todo["source"][0], obj.vtodo.summary.valueRepr()) iconPath = unresolved_todo subtext = "no due date" urgency = ItemBase.Urgency.Alert onehour = datetime.datetime.now() + datetime.timedelta(hours=1) tonight = datetime.datetime.now() tonight = tonight.replace(hour=16, minute=0, second=0) tomorrow = datetime.datetime.now() + datetime.timedelta(days=1) tomorrow.replace(hour=9, minute=0, second=0) # always 9 AM nextweek = datetime.datetime.now() + datetime.timedelta(days=7) nextweek.replace(hour=9, minute=0, second=0) # always 9 AM if "due" in obj.vtodo.contents.keys(): dueDate: datetime = obj.vtodo.due.valueRepr() if not isinstance(dueDate, datetime.datetime): dueDate = datetime.datetime.combine( dueDate, datetime.datetime.min.time()) # dueDate = dueDate.replace( # hour=9, minute=0, second=0) # always 9 am if dueDate.tzinfo is None: dueDate = dueDate.astimezone() info(dueDate) now = datetime.datetime.now().astimezone() info(now) if dueDate < now: subtext = "� due: {:%Y-%m-%d %H:%M}".format(dueDate) urgency = ItemBase.Urgency.Normal elif (dueDate - now) < datetime.timedelta(hours=12): subtext = "⚠� due: {:%Y-%m-%d %H:%M}".format(dueDate) urgency = ItemBase.Urgency.Notification else: subtext = "🕑 due: {:%Y-%m-%d %H:%M}".format(dueDate) else: dueDate = datetime.datetime.now() return Item( id=f'{dueDate.timestamp()}', text=text, subtext=subtext, icon=iconPath, completion=f't {obj.vtodo.summary.valueRepr()}', urgency=urgency, actions=[FuncAction(text="Mark done", callable=lambda: connections.markDone( todo["source"][0], uid)), FuncAction(text="Postpone for one hour", callable=lambda: connections.postpone( todo["source"][0], uid, onehour)), FuncAction(text="Postpone ' till 4 P.M.'", callable=lambda: connections.postpone( todo["source"][0], uid, tonight)), FuncAction(text="Postpone 'till tomorrow", callable=lambda: connections.postpone( todo["source"][0], uid, tomorrow)), FuncAction(text="Postpone 'till next week", callable=lambda: connections.postpone( todo["source"][0], uid, nextweek)), FuncAction(text="Reload todo's", callable=lambda: connections.load_todos()), ] )
def handleQuery(query): if query.isTriggered and query.string.strip(): # avoid rate limiting time.sleep(0.2) if not query.isValid: return info("Searching YouTube for '{}'".format(query.string)) req = Request(headers=HEADERS, url='https://www.youtube.com/results?{}'.format( urlencode({'search_query': query.string.strip()}))) with urlopen(req) as response: responseBytes = response.read() match = re.search(DATA_REGEX, responseBytes.decode()) if match is None: critical( "Failed to receive expected data from YouTube. This likely means API changes, but could just be a failed request." ) logHtml(responseBytes) return results = json.loads(match.group(3)) results = results['contents']['twoColumnSearchResultsRenderer'][ 'primaryContents']['sectionListRenderer']['contents'][0][ 'itemSectionRenderer']['contents'] items = [] for result in results: for type, data in result.items(): try: if type == 'videoRenderer': subtext = ['Video'] action = 'Watch on Youtube' link = 'watch?v={}'.format(data['videoId']) if 'lengthText' in data: subtext.append(textFrom(data['lengthText'])) if 'shortViewCountText' in data: subtext.append( textFrom(data['shortViewCountText'])) if 'publishedTimeText' in data: subtext.append( textFrom(data['publishedTimeText'])) elif type == 'channelRenderer': subtext = ['Channel'] action = 'Show on Youtube' link = 'channel/{}'.format(data['channelId']) if 'videoCountText' in data: subtext.append(textFrom( data['videoCountText'])) if 'subscriberCountText' in data: subtext.append( textFrom(data['subscriberCountText'])) else: continue except Exception as e: critical(e) critical(json.dumps(result, indent=4)) item = Item( id=__title__, icon=data['thumbnail']['thumbnails'][0]['url'].split( '?', 1)[0] if data['thumbnail']['thumbnails'] else __icon__, text=textFrom(data['title']), subtext=' | '.join(subtext), actions=[ UrlAction(action, 'https://www.youtube.com/' + link) ]) items.append(item) return items
def handleQuery(query): if query.isTriggered: if query.string.strip(): args = query.string.strip().split(maxsplit=1) fields = args[0].split(":") name = args[1] if 1 < len(args) else '' if not all(field.isdigit() or field == '' for field in fields): return Item( id=__title__, text="Invalid input", subtext= "Enter a query in the form of '%s[[hours:]minutes:]seconds [name]'" % __triggers__, icon=iconPath) seconds = 0 fields.reverse() for i in range(len(fields)): seconds += int(fields[i] if fields[i] else 0) * (60**i) return Item(id=__title__, text=str(timedelta(seconds=seconds)), subtext='Set a timer with name "%s"' % name if name else 'Set a timer', icon=iconPath, actions=[ FuncAction( "Set timer", lambda sec=seconds: startTimer(sec, name)) ]) else: # List timers items = [] for timer in timers: m, s = divmod(timer.interval, 60) h, m = divmod(m, 60) identifier = "%d:%02d:%02d" % (h, m, s) timer_name_with_quotes = '"%s"' % timer.name if timer.name else '' items.append( Item(id=__title__, text='Delete timer <i>%s [%s]</i>' % (timer_name_with_quotes, identifier), subtext="Times out %s" % strftime("%X", localtime(timer.end)), icon=iconPath, actions=[ FuncAction("Delete timer", lambda timer=timer: deleteTimer(timer)) ])) if items: return items # Display hint item return Item( id=__title__, text="Add timer", subtext= "Enter a query in the form of '%s[[hours:]minutes:]seconds [name]'" % __triggers__, icon=iconPath)