diff --git a/rofi_menu/contrib/web_search/__init__.py b/rofi_menu/contrib/web_search/__init__.py new file mode 100644 index 0000000..30b1c2a --- /dev/null +++ b/rofi_menu/contrib/web_search/__init__.py @@ -0,0 +1,5 @@ +from .search_menu import SearchItem, SearchMenu +from .google import GoogleENItem, GoogleENMenu, GoogleDEItem, GoogleDEMenu +from .startpage import StartpageENItem, StartpageENMenu, StartpageDEItem, StartpageDEMenu +from .wikipedia import WikipediaENItem, WikipediaENMenu, WikipediaDEItem, WikipediaDEMenu +from .wolfram import WolframItem, WolframMenu diff --git a/rofi_menu/contrib/web_search/ecosia.py b/rofi_menu/contrib/web_search/ecosia.py new file mode 100644 index 0000000..52cc5d0 --- /dev/null +++ b/rofi_menu/contrib/web_search/ecosia.py @@ -0,0 +1,38 @@ +from typing import Optional +from rofi_menu.contrib.web_search.search_menu import SearchMenu, SearchItem +from rofi_menu.main import run +import json +from urllib.parse import urlencode, urlunparse +from urllib.request import urlopen +import ssl + +context = ssl.create_default_context() + + +class EcosiaItem(SearchItem): + search_command = "firefox https://www.ecosia.org/search?q={searchstring}" + + +class EcosiaMenu(SearchMenu): + prompt = "Ecosia{langEmoji}" + lang = "" + langEmoji = "" + suggestionItem = EcosiaItem + + def __init__(self, *args, **kwargs): + self.prompt = self.__class__.prompt.format(langEmoji= self.__class__.langEmoji) + super().__init__(*args, **kwargs) + + async def request_suggestions(self, meta): + query = {"q" : meta.user_input} + if not self.__class__.lang == "": + query["mkt"] = self.__class__.lang + url = urlunparse(("https", "ac.ecosia.org", "", "", urlencode(query), "")) + with urlopen(url) as response: + data = json.loads(response.read().decode()) + return data["suggestions"] + + +def main(lang: Optional[str] = None): + Menu = EcosiaMenu + run(Menu()) diff --git a/rofi_menu/contrib/web_search/google.py b/rofi_menu/contrib/web_search/google.py new file mode 100644 index 0000000..93330d1 --- /dev/null +++ b/rofi_menu/contrib/web_search/google.py @@ -0,0 +1,70 @@ +from typing import Optional +from rofi_menu.contrib.web_search.search_menu import SearchMenu, SearchItem +from rofi_menu.main import run +import json +from urllib.parse import urlencode, urlunparse +from urllib.request import urlopen, Request +import sys +import ssl + +context = ssl.create_default_context() + + +class GoogleItem(SearchItem): + search_command = "firefox https://www.google.com/search?q={searchstring}" + + +class GoogleMenu(SearchMenu): + prompt = "Google{langEmoji}" + lang = "" + langEmoji = "" + suggestionItem = GoogleItem + + def __init__(self, *args, **kwargs): + self.prompt = self.__class__.prompt.format(langEmoji= self.__class__.langEmoji) + super().__init__(*args, **kwargs) + + async def request_suggestions(self, meta): + query = {"q": meta.user_input, "output": "firefox", "format": "json", "num": "10"} + if not self.__class__.lang == "": + query["hl"] = self.__class__.lang + url = urlunparse(("https", "suggestqueries.google.com", "complete/search", "", urlencode(query), "")) + with urlopen(Request(url, headers={"User-Agent": "Mozilla"})) as response: + #print(bytearray(response.read()), file=sys.stderr, flush=True) + data = response.read() + try: + decode = data.decode("utf-8") + except UnicodeDecodeError: + decode = data.decode("iso-8859-1") + data = json.loads(decode) + return data[1] + + +class GoogleDEItem(GoogleItem): + search_command = "firefox https://www.google.com/search?q={searchstring}&hl=de" + + +class GoogleDEMenu(GoogleMenu): + lang= "de" + langEmoji = u"🇩🇪" + suggestionItem = GoogleDEItem + + +class GoogleENItem(GoogleItem): + search_command = "firefox https://www.google.com/search?q={searchstring}&hl=en" + + +class GoogleENMenu(GoogleMenu): + lang = "en" + langEmoji = u"🇬🇧" + suggestionItem = GoogleENItem + + +def main(lang: Optional[str] = None): + if lang is not None and lang == "de": + Menu = GoogleDEMenu + elif lang is not None and lang == "en": + Menu = GoogleENMenu + else: + Menu = GoogleMenu + run(Menu()) diff --git a/rofi_menu/contrib/web_search/search_menu.py b/rofi_menu/contrib/web_search/search_menu.py new file mode 100644 index 0000000..f9fb4fb --- /dev/null +++ b/rofi_menu/contrib/web_search/search_menu.py @@ -0,0 +1,48 @@ +from rofi_menu.menu import Menu, Operation, MetaStore +from rofi_menu.contrib.shell import ShellItem +from urllib.parse import quote_plus +from typing import Type +import sys + + +class SearchItem(ShellItem): + search_command: str = "" + + def __init__(self, searchstring: str = "", **kwargs): + command = self.__class__.search_command.format(searchstring = quote_plus(searchstring)) + super().__init__(text = searchstring, command = command, **kwargs) + + +class SearchMenu(Menu): + suggestionItem: Type[SearchItem] = SearchItem + allow_user_input = True + + async def generate_menu_items(self, meta: MetaStore): + print("reading suggestions", file = sys.stderr, flush = True) + suggestions = meta.state_manager.get("suggestion_list", list()) + meta.debug = False + return [self.__class__.suggestionItem(s) for s in suggestions] + + async def request_suggestions(self, meta: MetaStore): + return list() + + async def on_user_input(self, meta: MetaStore): + """request auto complete date from service if available""" + print("executing on_user_input", file = sys.stderr, flush = True) + print(meta.user_input, file = sys.stderr) + if meta.user_input is not None: + print("fetching suggestions", file = sys.stderr) + suggestions = await self.request_suggestions(meta) + else: + print("no suggestion", file = sys.stderr, flush = True) + suggestions = list() + print(suggestions, file = sys.stderr, flush = True) + if meta.user_input in suggestions: + suggestions.remove(meta.user_input) + suggestions.insert(0, meta.user_input) + meta.state_manager["suggestion_list"] = suggestions + self.items = await self.build_menu_items(meta) + print([i.command for i in self.items], file = sys.stderr, flush=True) + # return Operation.output_menu(await self.handle_render(meta)) + return Operation.refresh_menu() + diff --git a/rofi_menu/contrib/web_search/startpage.py b/rofi_menu/contrib/web_search/startpage.py new file mode 100644 index 0000000..fe66e0a --- /dev/null +++ b/rofi_menu/contrib/web_search/startpage.py @@ -0,0 +1,63 @@ +from typing import Optional +from rofi_menu.contrib.web_search.search_menu import SearchMenu, SearchItem +from rofi_menu.main import run +import json +from urllib.parse import urlencode, urlunparse +from urllib.request import urlopen +import ssl + +context = ssl.create_default_context() + + +class StartpageItem(SearchItem): + search_command = "firefox https://www.startpage.com/do/dsearch?query={searchstring}" + + +class StartpageMenu(SearchMenu): + prompt = "StartPage{langEmoji}" + lang = "" + langEmoji = "" + suggestionItem = StartpageItem + + def __init__(self, *args, **kwargs): + self.prompt = self.__class__.prompt.format(langEmoji= self.__class__.langEmoji) + super().__init__(*args, **kwargs) + + async def request_suggestions(self, meta): + query = {"q" : meta.user_input, "limit": "10", "format": "json"} + if not self.__class__.lang == "": + query["lang"] = self.__class__.lang + url = urlunparse(("https", "www.startpage.com", "suggestions", "", urlencode(query), "")) + with urlopen(url) as response: + data = json.loads(response.read().decode()) + return list(map(lambda el: el["text"], data["suggestions"])) + + +class StartpageDEItem(StartpageItem): + search_command = "firefox https://www.startpage.com/do/dsearch?query={searchstring}&lang=deutsch" + + +class StartpageDEMenu(StartpageMenu): + lang= "deutsch" + langEmoji = u"🇩🇪" + suggestionItem = StartpageDEItem + + +class StartpageENItem(StartpageItem): + search_command = "firefox https://www.startpage.com/do/dsearch?query={searchstring}&lang=english" + + +class StartpageENMenu(StartpageMenu): + lang = "english" + langEmoji = u"🇬🇧" + suggestionItem = StartpageENItem + + +def main(lang: Optional[str] = None): + if lang is not None and lang == "de": + Menu = StartpageDEMenu + elif lang is not None and lang == "en": + Menu = StartpageENMenu + else: + Menu = StartpageMenu + run(Menu()) diff --git a/rofi_menu/contrib/web_search/wikipedia.py b/rofi_menu/contrib/web_search/wikipedia.py new file mode 100644 index 0000000..c73732a --- /dev/null +++ b/rofi_menu/contrib/web_search/wikipedia.py @@ -0,0 +1,61 @@ +from typing import Optional +from rofi_menu.contrib.web_search.search_menu import SearchMenu, SearchItem +from rofi_menu.main import run +import json +from urllib.parse import urlencode, urlunparse +from urllib.request import urlopen +import ssl + +context = ssl.create_default_context() + + +class WikipediaItem(SearchItem): + search_command = "firefox https://wikipedia.org/wiki/{searchstring}" + + +class WikipediaMenu(SearchMenu): + prompt = "Wikipedia{langEmoji}" + sub = "" + langEmoji = "" + suggestionItem = WikipediaItem + + def __init__(self, *args, **kwargs): + self.prompt = self.__class__.prompt.format(langEmoji= self.__class__.langEmoji) + super().__init__(*args, **kwargs) + + async def request_suggestions(self, meta): + query = {"search": meta.user_input, "limit": "10", "format": "json", "namespace": "0", "formatversion": "2", "action": "opensearch"} + url = urlunparse(("https", f"{self.__class__.sub}wikipedia.org", "w/api.php", "", urlencode(query), "")) + with urlopen(url) as response: + data = json.loads(response.read().decode()) + return [s.replace(" ", "_") for s in data[1]] + + +class WikipediaDEItem(WikipediaItem): + search_command = "firefox https://de.wikipedia.org/wiki/{searchstring}" + + +class WikipediaDEMenu(WikipediaMenu): + sub = "de." + langEmoji = u"🇩🇪" + suggestionItem = WikipediaDEItem + + +class WikipediaENItem(WikipediaItem): + search_command = "firefox https://en.wikipedia.org/wiki/{searchstring}" + + +class WikipediaENMenu(WikipediaMenu): + sub = "en." + langEmoji = u"🇬🇧" + suggestionItem = WikipediaENItem + + +def main(lang: Optional[str] = None): + if lang is not None and lang == "de": + Menu = WikipediaDEMenu + elif lang is not None and lang == "en": + Menu = WikipediaENMenu + else: + Menu = WikipediaMenu + run(Menu()) diff --git a/rofi_menu/contrib/web_search/wolfram.py b/rofi_menu/contrib/web_search/wolfram.py new file mode 100644 index 0000000..a584ed5 --- /dev/null +++ b/rofi_menu/contrib/web_search/wolfram.py @@ -0,0 +1,30 @@ +from typing import Optional +from rofi_menu.contrib.web_search.search_menu import SearchMenu, SearchItem +from rofi_menu.main import run +import json +from urllib.parse import urlencode, urlunparse +from urllib.request import urlopen +import ssl + +context = ssl.create_default_context() + + +class WolframItem(SearchItem): + search_command = "firefox https://www.wolframalpha.com/input?i={searchstring}" + + +class WolframMenu(SearchMenu): + prompt = "wolfram|α" + suggestionItem = WolframItem + + async def request_suggestions(self, meta): + query = {"i": meta.user_input} + url = urlunparse(("https", "www.wolframalpha.com", "n/v1/api/autocomplete/", "", urlencode(query), "")) + with urlopen(url) as response: + data = json.loads(response.read().decode()) + return [d["input"] for d in data["results"]] + + +def main(lang: Optional[str] = None): + Menu = WolframMenu + run(Menu()) diff --git a/rofi_menu/contrib/web_search/youtube.py b/rofi_menu/contrib/web_search/youtube.py new file mode 100644 index 0000000..7842914 --- /dev/null +++ b/rofi_menu/contrib/web_search/youtube.py @@ -0,0 +1,71 @@ +from typing import Optional +from rofi_menu.contrib.web_search.search_menu import SearchMenu, SearchItem +from rofi_menu.main import run +import json +from urllib.parse import urlencode, urlunparse +from urllib.request import urlopen, Request +import sys +import ssl +import re +context = ssl.create_default_context() + + +class YoutubeItem(SearchItem): + search_command = "firefox https://www.youtube.com/results?search_query={searchstring}&search_type=&aq=f" + + +class YoutubeMenu(SearchMenu): + prompt = "YouTube{langEmoji}" + lang = "" + langEmoji = "" + suggestionItem = YoutubeItem + + def __init__(self, *args, **kwargs): + self.prompt = self.__class__.prompt.format(langEmoji= self.__class__.langEmoji) + super().__init__(*args, **kwargs) + + async def request_suggestions(self, meta): + query = {"q": meta.user_input, "client": "youtube", "num": "10"} + if not self.__class__.lang == "": + query["hl"] = self.__class__.lang + url = urlunparse(("https", "clients1.google.com", "complete/search", "", urlencode(query), "")) + with urlopen(Request(url, headers={"User-Agent": "Mozilla"})) as response: + #print(bytearray(response.read()), file=sys.stderr, flush=True) + data = response.read() + try: + decode = data.decode("utf-8") + except UnicodeDecodeError: + decode = data.decode("iso-8859-1") + data = json.loads(re.match(r".*\((.*)\)", decode).group(1))[1] + return [s[0] for s in data] + + +"""choosing a language seems useless, because cookies overwrite the settings from the url""" +class YoutubeDEItem(YoutubeItem): + search_command = "firefox https://www.youtube.com/results?search_query={searchstring}&search_type=&aq=f&hl=de" + + +class YoutubeDEMenu(YoutubeMenu): + lang= "de" + langEmoji = u"🇩🇪" + suggestionItem = YoutubeDEItem + + +class YoutubeENItem(YoutubeItem): + search_command = "firefox https://www.youtube.com/results?search_query={searchstring}&search_type=&aq=f&hl=en" + + +class YoutubeENMenu(YoutubeMenu): + lang = "en" + langEmoji = u"🇬🇧" + suggestionItem = YoutubeENItem + + +def main(lang: Optional[str] = None): + if lang is not None and lang == "de": + Menu = YoutubeDEMenu + elif lang is not None and lang == "en": + Menu = YoutubeENMenu + else: + Menu = YoutubeMenu + run(Menu())