From bce8f21127d73c84698b61eba138a6c109eeb939 Mon Sep 17 00:00:00 2001 From: geeseven <2334728+geeseven@users.noreply.github.com> Date: Sat, 5 Dec 2020 08:16:03 -0600 Subject: [PATCH 1/4] add add-nextcloud-bookmarks userscript --- misc/userscripts/README.md | 1 + misc/userscripts/add-nextcloud-bookmarks | 180 +++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100755 misc/userscripts/add-nextcloud-bookmarks diff --git a/misc/userscripts/README.md b/misc/userscripts/README.md index 669bfa664..05f824782 100644 --- a/misc/userscripts/README.md +++ b/misc/userscripts/README.md @@ -35,6 +35,7 @@ The following userscripts are included in the current directory. - [qr](./qr): Show a QR code for the current webpage via [qrencode](https://fukuchi.org/works/qrencode/). - [kodi](./kodi): Play videos in Kodi. +- [add-nextcloud-bookmarks](./add-nextcloud-bookmarks): create bookmarks in Nextcloud's Bookmarks app [castnow]: https://github.com/xat/castnow [youtube-dl]: https://rg3.github.io/youtube-dl/ diff --git a/misc/userscripts/add-nextcloud-bookmarks b/misc/userscripts/add-nextcloud-bookmarks new file mode 100755 index 000000000..d2c259dec --- /dev/null +++ b/misc/userscripts/add-nextcloud-bookmarks @@ -0,0 +1,180 @@ +#!/usr/bin/env python + +""" +Behavior: + A qutebrowser userscript that creates bookmarks in Nextcloud's Bookmarks app. + +Requirements: + requests + +userscript setup: + Optionally create ~/.config/qutebrowser/add-nextcloud-bookmarks.ini like: + +[nextcloud] +HOST=https://nextcloud.example.com +USER=username +;PASSWORD=lamepassword +DESCRIPTION=None +;TAGS=just-one +TAGS=read-me-later, added-by-qutebrowser + + If settings aren't in the configuration file, the user will be prompted during + bookmark creation. If DESCRIPTION and TAGS are set to None, they will be left + blank. If the user does not want to be prompted for a password, it is recommended + to set up an 'app password'. See the following for instructions: + https://docs.nextcloud.com/server/latest/user_manual/en/session_management.htmlmanaging-devices # noqa: E501 + +qutebrowser setup: + add bookmark via hints + config.bind('X', 'hint links userscript add-nextcloud-bookmarks') + + add bookmark of current URL + config.bind('X', 'spawn --userscript add-nextcloud-bookmarks') + +troubleshooting: + Errors detected within this userscript with have an exit of 231. All other + exit codes will come from requests. +""" + +import configparser +from base64 import b64encode +from os import environ, path +from sys import argv, exit + +from PyQt5.QtWidgets import QApplication, QInputDialog, QLineEdit +from requests import get, post + + +def get_text(name, info): + """Get input from the user.""" + _app = QApplication(argv) # noqa: F841 + if name == "password": + text, ok = QInputDialog.getText( + None, + "add-nextcloud-bookmarks userscript", + "Please enter {}".format(info), + QLineEdit.Password, + ) + else: + text, ok = QInputDialog.getText( + None, "add-nextcloud-bookmarks userscript", "Please enter {}".format(info) + ) + if not ok: + message("info", "Dialog box canceled.") + exit(0) + return text + + +def message(level, text): + """display message""" + with open(environ["QUTE_FIFO"], "w") as fifo: + fifo.write( + 'message-{} "add-nextcloud-bookmarks userscript: {}"'.format(level, text) + ) + fifo.flush() + + +if "QUTE_FIFO" not in environ: + print( + "This script is designed to run as a qutebrowser userscript, " + "not as a standalone script." + ) + exit(231) + +if "QUTE_CONFIG_DIR" not in environ: + if "XDG_CONFIG_HOME" in environ: + QUTE_CONFIG_DIR = environ["XDG_CONFIG_HOME"] + "/qutebrowser" + else: + QUTE_CONFIG_DIR = environ["HOME"] + "/.config/qutebrowser" +else: + QUTE_CONFIG_DIR = environ["QUTE_CONFIG_DIR"] + +config_file = QUTE_CONFIG_DIR + "/add-nextcloud-bookmarks.ini" +if path.isfile(config_file): + config = configparser.ConfigParser() + config.read(config_file) + settings = dict(config.items("nextcloud")) +else: + settings = {} + +settings_info = [ + ("host", "host information.", "required"), + ("user", "username.", "required"), + ("password", "password.", "required"), + ("description", "description or leave blank", "optional"), + ("tags", "tags (comma separated) or leave blank", "optional"), +] + +# check for settings that need user interaction and clear optional setting if need be +for setting in settings_info: + if setting[0] not in settings: + userInput = get_text(setting[0], setting[1]) + settings[setting[0]] = userInput + if setting[2] == "optional": + if settings[setting[0]] == "None": + settings[setting[0]] = "" + +# tags need to be formatted like [], ["one"] or ["one", two"] as a string +tags = settings["tags"] +settings["tags"] = str(tags.split(", ")).replace("'", '"') + +QUTE_URL = environ["QUTE_URL"] +api_url = settings["host"] + "/index.php/apps/bookmarks/public/rest/v2/bookmark" + +auth = b64encode(format(settings["user"] + ":" + settings["password"]).encode("utf-8")) +auth = str(auth, "utf-8") + +headers = { + "Authorization": "Basic {}".format(auth), + "Content-Type": "application/json", +} + +# check if there is already a bookmark for the URL +r = get( + "{}?url={}".format(api_url, QUTE_URL), + headers=headers, + timeout=(3.05, 27), +) +if r.status_code != 200: + message( + "error", + "Could not connect to {} with status code {}".format( + settings["host"], r.status_code + ), + ) + exit(r.status_code) + +try: + r.json()["data"][0]["id"] +except IndexError: + pass +else: + message("info", "bookmark already exists for {}".format(QUTE_URL)) + exit(0) + +if environ["QUTE_MODE"] == "hints": + QUTE_TITLE = QUTE_URL +else: + QUTE_TITLE = environ["QUTE_TITLE"] + +# JSON format +# https://nextcloud-bookmarks.readthedocs.io/en/latest/bookmark.html#create-a-bookmark +data = ( + '{"url": "' + + QUTE_URL + + '", "title": "' + + QUTE_TITLE + + '", "description": "' + + settings["description"] + + '", "tags": ' + + settings["tags"] + + "}" +) + +r = post(api_url, data=data.encode("utf-8"), headers=headers, timeout=(3.05, 27)) + +if (r.status_code) == 200: + message("info", "bookmark {} added".format(QUTE_URL)) +else: + message("error", "something went wrong {} bookmark not added".format(QUTE_URL)) + exit(r.status_code) From 4539bc1f63e639f7bd78479d0ebc0b8c3c7a29f0 Mon Sep 17 00:00:00 2001 From: geeseven <2334728+geeseven@users.noreply.github.com> Date: Sun, 6 Dec 2020 13:22:59 -0600 Subject: [PATCH 2/4] typo and clean up per review in #5939 --- misc/userscripts/add-nextcloud-bookmarks | 45 ++++++++++-------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/misc/userscripts/add-nextcloud-bookmarks b/misc/userscripts/add-nextcloud-bookmarks index d2c259dec..c0fd12de1 100755 --- a/misc/userscripts/add-nextcloud-bookmarks +++ b/misc/userscripts/add-nextcloud-bookmarks @@ -16,7 +16,7 @@ USER=username ;PASSWORD=lamepassword DESCRIPTION=None ;TAGS=just-one -TAGS=read-me-later, added-by-qutebrowser +TAGS=read-me-later,added-by-qutebrowser, Another-One If settings aren't in the configuration file, the user will be prompted during bookmark creation. If DESCRIPTION and TAGS are set to None, they will be left @@ -32,17 +32,18 @@ qutebrowser setup: config.bind('X', 'spawn --userscript add-nextcloud-bookmarks') troubleshooting: - Errors detected within this userscript with have an exit of 231. All other + Errors detected within this userscript will have an exit of 231. All other exit codes will come from requests. """ import configparser -from base64 import b64encode +from json import dumps from os import environ, path from sys import argv, exit from PyQt5.QtWidgets import QApplication, QInputDialog, QLineEdit from requests import get, post +from requests.auth import HTTPBasicAuth def get_text(name, info): @@ -69,7 +70,7 @@ def message(level, text): """display message""" with open(environ["QUTE_FIFO"], "w") as fifo: fifo.write( - 'message-{} "add-nextcloud-bookmarks userscript: {}"'.format(level, text) + 'message-{} "add-nextcloud-bookmarks userscript: {}"\n'.format(level, text) ) fifo.flush() @@ -114,24 +115,18 @@ for setting in settings_info: if settings[setting[0]] == "None": settings[setting[0]] = "" -# tags need to be formatted like [], ["one"] or ["one", two"] as a string -tags = settings["tags"] -settings["tags"] = str(tags.split(", ")).replace("'", '"') +tags = settings["tags"].split(",") QUTE_URL = environ["QUTE_URL"] api_url = settings["host"] + "/index.php/apps/bookmarks/public/rest/v2/bookmark" -auth = b64encode(format(settings["user"] + ":" + settings["password"]).encode("utf-8")) -auth = str(auth, "utf-8") - -headers = { - "Authorization": "Basic {}".format(auth), - "Content-Type": "application/json", -} +headers = {"Content-Type": "application/json"} +auth = HTTPBasicAuth(settings["user"], settings["password"]) # check if there is already a bookmark for the URL r = get( "{}?url={}".format(api_url, QUTE_URL), + auth=auth, headers=headers, timeout=(3.05, 27), ) @@ -159,21 +154,17 @@ else: # JSON format # https://nextcloud-bookmarks.readthedocs.io/en/latest/bookmark.html#create-a-bookmark -data = ( - '{"url": "' - + QUTE_URL - + '", "title": "' - + QUTE_TITLE - + '", "description": "' - + settings["description"] - + '", "tags": ' - + settings["tags"] - + "}" -) +dict = { + "url": QUTE_URL, + "title": QUTE_TITLE, + "description": settings["description"], + "tags": tags, +} +data = dumps(dict) -r = post(api_url, data=data.encode("utf-8"), headers=headers, timeout=(3.05, 27)) +r = post(api_url, data=data, headers=headers, auth=auth, timeout=(3.05, 27)) -if (r.status_code) == 200: +if r.status_code == 200: message("info", "bookmark {} added".format(QUTE_URL)) else: message("error", "something went wrong {} bookmark not added".format(QUTE_URL)) From a1e8921e9bde4b558310694ac3fa3aa626eb1a35 Mon Sep 17 00:00:00 2001 From: geeseven <2334728+geeseven@users.noreply.github.com> Date: Tue, 8 Dec 2020 12:55:00 -0600 Subject: [PATCH 3/4] fix URL --- misc/userscripts/add-nextcloud-bookmarks | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/userscripts/add-nextcloud-bookmarks b/misc/userscripts/add-nextcloud-bookmarks index c0fd12de1..4e66620dc 100755 --- a/misc/userscripts/add-nextcloud-bookmarks +++ b/misc/userscripts/add-nextcloud-bookmarks @@ -22,7 +22,7 @@ TAGS=read-me-later,added-by-qutebrowser, Another-One bookmark creation. If DESCRIPTION and TAGS are set to None, they will be left blank. If the user does not want to be prompted for a password, it is recommended to set up an 'app password'. See the following for instructions: - https://docs.nextcloud.com/server/latest/user_manual/en/session_management.htmlmanaging-devices # noqa: E501 + https://docs.nextcloud.com/server/latest/user_manual/en/session_management.html#managing-devices # noqa: E501 qutebrowser setup: add bookmark via hints From 6f9d5bf43315ec83e10cae6342e0546eb318f017 Mon Sep 17 00:00:00 2001 From: geeseven <2334728+geeseven@users.noreply.github.com> Date: Tue, 8 Dec 2020 13:02:41 -0600 Subject: [PATCH 4/4] add add-nextcloud-cookbook userscript --- misc/userscripts/README.md | 1 + misc/userscripts/add-nextcloud-cookbook | 131 ++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100755 misc/userscripts/add-nextcloud-cookbook diff --git a/misc/userscripts/README.md b/misc/userscripts/README.md index 05f824782..7e809a20a 100644 --- a/misc/userscripts/README.md +++ b/misc/userscripts/README.md @@ -36,6 +36,7 @@ The following userscripts are included in the current directory. [qrencode](https://fukuchi.org/works/qrencode/). - [kodi](./kodi): Play videos in Kodi. - [add-nextcloud-bookmarks](./add-nextcloud-bookmarks): create bookmarks in Nextcloud's Bookmarks app +- [add-nextcloud-cookbook](./add-nextcloud-cookbook): add recipes to Nextcloud's Cookbook app [castnow]: https://github.com/xat/castnow [youtube-dl]: https://rg3.github.io/youtube-dl/ diff --git a/misc/userscripts/add-nextcloud-cookbook b/misc/userscripts/add-nextcloud-cookbook new file mode 100755 index 000000000..a348417e0 --- /dev/null +++ b/misc/userscripts/add-nextcloud-cookbook @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +""" +Behavior: + A qutebrowser userscript that adds recipes to Nextcloud's Cookbook app. + +Requirements: + requests + +userscript setup: + Optionally create ~/.config/qutebrowser/add-nextcloud-cookbook.ini like: + +[nextcloud] +HOST=https://nextcloud.example.com +USER=username +;PASSWORD=lamepassword + + If settings aren't in the configuration file, the user will be prompted. + If the user does not want to be prompted for a password, it is recommended + to set up an 'app password' with 'Allow filesystem access' enabled. + See the following for instructions: + https://docs.nextcloud.com/server/latest/user_manual/en/session_management.html#managing-devices # noqa: E501 + +qutebrowser setup: + add recipe via hints + config.bind('X', 'hint links userscript add-nextcloud-cookbook') + + add recipe of current URL + config.bind('X', 'spawn --userscript add-nextcloud-cookbook') + +troubleshooting: + Errors detected within this userscript will have an exit of 231. All other + exit codes will come from requests. +""" + +import configparser +from os import environ, path +from sys import argv, exit + +from PyQt5.QtWidgets import QApplication, QInputDialog, QLineEdit +from requests import post +from requests.auth import HTTPBasicAuth + + +def get_text(name, info): + """Get input from the user.""" + _app = QApplication(argv) # noqa: F841 + if name == "password": + text, ok = QInputDialog.getText( + None, + "add-nextcloud-cookbook userscript", + "Please enter {}".format(info), + QLineEdit.Password, + ) + else: + text, ok = QInputDialog.getText( + None, "add-nextcloud-cookbook userscript", "Please enter {}".format(info) + ) + if not ok: + message("info", "Dialog box canceled.") + exit(0) + return text + + +def message(level, text): + """display message""" + with open(environ["QUTE_FIFO"], "w") as fifo: + fifo.write( + "message-{} 'add-nextcloud-cookbook userscript: {}'\n".format(level, text) + ) + fifo.flush() + + +if "QUTE_FIFO" not in environ: + print( + "This script is designed to run as a qutebrowser userscript, " + "not as a standalone script." + ) + exit(231) + +if "QUTE_CONFIG_DIR" not in environ: + if "XDG_CONFIG_HOME" in environ: + QUTE_CONFIG_DIR = environ["XDG_CONFIG_HOME"] + "/qutebrowser" + else: + QUTE_CONFIG_DIR = environ["HOME"] + "/.config/qutebrowser" +else: + QUTE_CONFIG_DIR = environ["QUTE_CONFIG_DIR"] + +config_file = QUTE_CONFIG_DIR + "/add-nextcloud-cookbook.ini" +if path.isfile(config_file): + config = configparser.ConfigParser() + config.read(config_file) + settings = dict(config.items("nextcloud")) +else: + settings = {} + +settings_info = [ + ("host", "host information.", "required"), + ("user", "username.", "required"), + ("password", "password.", "required"), +] + +# check for settings that need user interaction +for setting in settings_info: + if setting[0] not in settings: + userInput = get_text(setting[0], setting[1]) + settings[setting[0]] = userInput + +api_url = settings["host"] + "/index.php/apps/cookbook/import" +headers = {"Content-Type": "application/x-www-form-urlencoded"} +auth = HTTPBasicAuth(settings["user"], settings["password"]) +data = "url=" + environ["QUTE_URL"] + +message("info", "starting to process {}".format(environ["QUTE_URL"])) + +r = post(api_url, data=data, headers=headers, auth=auth, timeout=(3.05, 27)) + +if r.status_code == 200: + message("info", "recipe from {} added.".format(environ["QUTE_URL"])) + exit(0) +elif r.status_code == 500: + message("warning", "Cookbook app reports {}".format(r.text)) + exit(0) +else: + message( + "error", + "Could not connect to {} with status code {}".format( + settings["host"], r.status_code + ), + ) + exit(r.status_code)