qutebrowser-1.1.1/ 0000755 0001750 0001751 00000000000 13230704465 015207 5 ustar florian florian 0000000 0000000 qutebrowser-1.1.1/scripts/ 0000755 0001750 0001751 00000000000 13230704465 016676 5 ustar florian florian 0000000 0000000 qutebrowser-1.1.1/scripts/dictcli.py 0000755 0001750 0001751 00000021652 13230703634 020671 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017 Michal Siedlaczek
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""A script installing Hunspell dictionaries.
Use: python -m scripts.dictcli [-h] {list,update,remove-old,install} ...
"""
import argparse
import base64
import json
import os
import sys
import re
import urllib.request
import attr
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
from qutebrowser.browser.webengine import spell
from qutebrowser.config import configdata
API_URL = 'https://chromium.googlesource.com/chromium/deps/hunspell_dictionaries.git/+/master/'
class InvalidLanguageError(Exception):
"""Raised when requesting invalid languages."""
def __init__(self, invalid_langs):
msg = 'invalid languages: {}'.format(', '.join(invalid_langs))
super().__init__(msg)
@attr.s
class Language:
"""Dictionary language specs."""
code = attr.ib()
name = attr.ib()
remote_filename = attr.ib()
local_filename = attr.ib(default=None)
_file_extension = attr.ib('bdic', init=False)
def __attrs_post_init__(self):
if self.local_filename is None:
self.local_filename = spell.local_filename(self.code)
@property
def remote_path(self):
"""Resolve the filename with extension the remote dictionary."""
return '.'.join([self.remote_filename, self._file_extension])
@property
def local_path(self):
"""Resolve the filename with extension the local dictionary."""
if self.local_filename is None:
return None
return '.'.join([self.local_filename, self._file_extension])
@property
def remote_version(self):
"""Resolve the version of the local dictionary."""
return spell.version(self.remote_path)
@property
def local_version(self):
"""Resolve the version of the local dictionary."""
local_path = self.local_path
if local_path is None:
return None
return spell.version(local_path)
def get_argparser():
"""Get the argparse parser."""
desc = 'Install and manage Hunspell dictionaries for QtWebEngine.'
parser = argparse.ArgumentParser(prog='dictcli',
description=desc)
subparsers = parser.add_subparsers(help='Command', dest='cmd')
subparsers.required = True
subparsers.add_parser('list',
help='Display the list of available languages.')
subparsers.add_parser('update',
help='Update dictionaries')
subparsers.add_parser('remove-old',
help='Remove old versions of dictionaries.')
install_parser = subparsers.add_parser('install',
help='Install dictionaries')
install_parser.add_argument('language',
nargs='*',
help="A list of languages to install.")
return parser
def version_str(version):
return '.'.join(str(n) for n in version)
def print_list(languages):
"""Print the list of available languages."""
pat = '{:<7}{:<26}{:<8}{:<5}'
print(pat.format('Code', 'Name', 'Version', 'Installed'))
for lang in languages:
remote_version = version_str(lang.remote_version)
local_version = '-'
if lang.local_version is not None:
local_version = version_str(lang.local_version)
if lang.local_version < lang.remote_version:
local_version += ' - update available!'
print(pat.format(lang.code, lang.name, remote_version, local_version))
def valid_languages():
"""Return a mapping from valid language codes to their names."""
option = configdata.DATA['spellcheck.languages']
return option.typ.valtype.valid_values.descriptions
def parse_entry(entry):
"""Parse an entry from the remote API."""
dict_re = re.compile(r"""
(?P(?P[a-z]{2}(-[A-Z]{2})?).*)\.bdic
""", re.VERBOSE)
match = dict_re.fullmatch(entry['name'])
if match is not None:
return match.group('code'), match.group('filename')
else:
return None
def language_list_from_api():
"""Return a JSON with a list of available languages from Google API."""
listurl = API_URL + '?format=JSON'
response = urllib.request.urlopen(listurl)
# A special 5-byte prefix must be stripped from the response content
# See: https://github.com/google/gitiles/issues/22
# https://github.com/google/gitiles/issues/82
json_content = response.read()[5:]
entries = json.loads(json_content.decode('utf-8'))['entries']
parsed_entries = [parse_entry(entry) for entry in entries]
return [entry for entry in parsed_entries if entry is not None]
def latest_yet(code2file, code, filename):
"""Determine whether the latest version so far."""
if code not in code2file:
return True
return spell.version(code2file[code]) < spell.version(filename)
def available_languages():
"""Return a list of Language objects of all available languages."""
lang_map = valid_languages()
api_list = language_list_from_api()
code2file = {}
for code, filename in api_list:
if latest_yet(code2file, code, filename):
code2file[code] = filename
return [
Language(code, name, code2file[code])
for code, name in lang_map.items()
if code in code2file
]
def download_dictionary(url, dest):
"""Download a decoded dictionary file."""
response = urllib.request.urlopen(url)
decoded = base64.decodebytes(response.read())
with open(dest, 'bw') as dict_file:
dict_file.write(decoded)
def filter_languages(languages, selected):
"""Filter a list of languages based on an inclusion list.
Args:
languages: a list of languages to filter
selected: a list of keys to select
"""
filtered_languages = []
for language in languages:
if language.code in selected:
filtered_languages.append(language)
selected.remove(language.code)
if selected:
raise InvalidLanguageError(selected)
return filtered_languages
def install_lang(lang):
"""Install a single lang given by the argument."""
lang_url = API_URL + lang.remote_path + '?format=TEXT'
if not os.path.isdir(spell.dictionary_dir()):
msg = '{} does not exist, creating the directory'
print(msg.format(spell.dictionary_dir()))
os.makedirs(spell.dictionary_dir())
print('Downloading {}'.format(lang_url))
dest = os.path.join(spell.dictionary_dir(), lang.remote_path)
download_dictionary(lang_url, dest)
print('Done.')
def install(languages):
"""Install languages."""
for lang in languages:
try:
print('Installing {}: {}'.format(lang.code, lang.name))
install_lang(lang)
except PermissionError as e:
sys.exit(str(e))
def update(languages):
"""Update the given languages."""
installed = [lang for lang in languages if lang.local_version is not None]
for lang in installed:
if lang.local_version < lang.remote_version:
print('Upgrading {} from {} to {}'.format(
lang.code,
version_str(lang.local_version),
version_str(lang.remote_version)))
install_lang(lang)
def remove_old(languages):
"""Remove old versions of languages."""
installed = [lang for lang in languages if lang.local_version is not None]
for lang in installed:
local_files = spell.local_files(lang.code)
for old_file in local_files[1:]:
os.remove(os.path.join(spell.dictionary_dir(), old_file))
def main():
if configdata.DATA is None:
configdata.init()
parser = get_argparser()
argv = sys.argv[1:]
args = parser.parse_args(argv)
languages = available_languages()
if args.cmd == 'list':
print_list(languages)
elif args.cmd == 'update':
update(languages)
elif args.cmd == 'remove-old':
remove_old(languages)
elif not args.language:
sys.exit('You must provide a list of languages to install.')
else:
try:
install(filter_languages(languages, args.language))
except InvalidLanguageError as e:
print(e)
if __name__ == '__main__':
main()
qutebrowser-1.1.1/scripts/testbrowser/ 0000755 0001750 0001751 00000000000 13230704465 021261 5 ustar florian florian 0000000 0000000 qutebrowser-1.1.1/scripts/testbrowser/testbrowser_webengine.py 0000755 0001750 0001751 00000003106 13230703634 026241 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler)
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Very simple browser for testing purposes."""
import sys
import argparse
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
def parse_args():
"""Parse commandline arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('url', help='The URL to open')
return parser.parse_known_args()[0]
if __name__ == '__main__':
args = parse_args()
app = QApplication(sys.argv)
wv = QWebEngineView()
wv.loadStarted.connect(lambda: print("Loading started"))
wv.loadProgress.connect(lambda p: print("Loading progress: {}%".format(p)))
wv.loadFinished.connect(lambda: print("Loading finished"))
wv.load(QUrl.fromUserInput(args.url))
wv.show()
app.exec_()
qutebrowser-1.1.1/scripts/testbrowser/testbrowser_webkit.py 0000755 0001750 0001751 00000003471 13230703634 025570 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler)
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Very simple browser for testing purposes."""
import sys
import argparse
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView
def parse_args():
"""Parse commandline arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('url', help='The URL to open')
parser.add_argument('--plugins', '-p', help='Enable plugins',
default=False, action='store_true')
return parser.parse_known_args()[0]
if __name__ == '__main__':
args = parse_args()
app = QApplication(sys.argv)
wv = QWebView()
wv.loadStarted.connect(lambda: print("Loading started"))
wv.loadProgress.connect(lambda p: print("Loading progress: {}%".format(p)))
wv.loadFinished.connect(lambda: print("Loading finished"))
if args.plugins:
wv.settings().setAttribute(QWebSettings.PluginsEnabled, True)
wv.load(QUrl.fromUserInput(args.url))
wv.show()
app.exec_()
qutebrowser-1.1.1/scripts/open_url_in_instance.sh 0000755 0001750 0001751 00000001031 13230703634 023422 0 ustar florian florian 0000000 0000000 #!/bin/bash
# initial idea: Florian Bruhin (The-Compiler)
# author: Thore Bödecker (foxxx0)
_url="$1"
_qb_version='1.0.4'
_proto_version=1
_ipc_socket="${XDG_RUNTIME_DIR}/qutebrowser/ipc-$(echo -n "$USER" | md5sum | cut -d' ' -f1)"
_qute_bin="/usr/bin/qutebrowser"
printf '{"args": ["%s"], "target_arg": null, "version": "%s", "protocol_version": %d, "cwd": "%s"}\n' \
"${_url}" \
"${_qb_version}" \
"${_proto_version}" \
"${PWD}" | socat - UNIX-CONNECT:"${_ipc_socket}" 2>/dev/null || "$_qute_bin" "$@" &
qutebrowser-1.1.1/scripts/link_pyqt.py 0000644 0001750 0001751 00000016020 13230703634 021256 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler)
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Symlink PyQt into a given virtualenv."""
import os
import os.path
import argparse
import shutil
import sys
import subprocess
import tempfile
import filecmp
class Error(Exception):
"""Exception raised when linking fails."""
pass
def run_py(executable, *code):
"""Run the given python code with the given executable."""
if os.name == 'nt' and len(code) > 1:
# Windows can't do newlines in arguments...
oshandle, filename = tempfile.mkstemp()
with os.fdopen(oshandle, 'w') as f:
f.write('\n'.join(code))
cmd = [executable, filename]
try:
ret = subprocess.run(cmd, universal_newlines=True, check=True,
stdout=subprocess.PIPE).stdout
finally:
os.remove(filename)
else:
cmd = [executable, '-c', '\n'.join(code)]
ret = subprocess.run(cmd, universal_newlines=True, check=True,
stdout=subprocess.PIPE).stdout
return ret.rstrip()
def verbose_copy(src, dst, *, follow_symlinks=True):
"""Copy function for shutil.copytree which prints copied files."""
if '-v' in sys.argv:
print('{} -> {}'.format(src, dst))
shutil.copy(src, dst, follow_symlinks=follow_symlinks)
def get_ignored_files(directory, files):
"""Get the files which should be ignored for link_pyqt() on Windows."""
needed_exts = ('.py', '.dll', '.pyd', '.so')
ignored_dirs = ('examples', 'qml', 'uic', 'doc')
filtered = []
for f in files:
ext = os.path.splitext(f)[1]
full_path = os.path.join(directory, f)
if os.path.isdir(full_path) and f in ignored_dirs:
filtered.append(f)
elif (ext not in needed_exts) and os.path.isfile(full_path):
filtered.append(f)
return filtered
def needs_update(source, dest):
"""Check if a file to be linked/copied needs to be updated."""
if os.path.islink(dest):
# No need to delete a link and relink -> skip this
return False
elif os.path.isdir(dest):
diffs = filecmp.dircmp(source, dest)
ignored = get_ignored_files(source, diffs.left_only)
has_new_files = set(ignored) != set(diffs.left_only)
return (has_new_files or diffs.right_only or diffs.common_funny or
diffs.diff_files or diffs.funny_files)
else:
return not filecmp.cmp(source, dest)
def get_lib_path(executable, name, required=True):
"""Get the path of a python library.
Args:
executable: The Python executable to use.
name: The name of the library to get the path for.
required: Whether Error should be raised if the lib was not found.
"""
code = [
'try:',
' import {}'.format(name),
'except ImportError as e:',
' print("ImportError: " + str(e))',
'else:',
' print("path: " + {}.__file__)'.format(name)
]
output = run_py(executable, *code)
try:
prefix, data = output.split(': ')
except ValueError:
raise ValueError("Unexpected output: {!r}".format(output))
if prefix == 'path':
return data
elif prefix == 'ImportError':
if required:
raise Error("Could not import {} with {}: {}!".format(
name, executable, data))
else:
return None
else:
raise ValueError("Unexpected output: {!r}".format(output))
def link_pyqt(executable, venv_path):
"""Symlink the systemwide PyQt/sip into the venv.
Args:
executable: The python executable where the source files are present.
venv_path: The path to the virtualenv site-packages.
"""
sip_file = get_lib_path(executable, 'sip')
sipconfig_file = get_lib_path(executable, 'sipconfig', required=False)
pyqt_dir = os.path.dirname(get_lib_path(executable, 'PyQt5.QtCore'))
for path in [sip_file, sipconfig_file, pyqt_dir]:
if path is None:
continue
fn = os.path.basename(path)
dest = os.path.join(venv_path, fn)
if os.path.exists(dest):
if needs_update(path, dest):
remove(dest)
else:
continue
copy_or_link(path, dest)
def copy_or_link(source, dest):
"""Copy or symlink source to dest."""
if os.name == 'nt':
if os.path.isdir(source):
print('{} -> {}'.format(source, dest))
shutil.copytree(source, dest, ignore=get_ignored_files,
copy_function=verbose_copy)
else:
print('{} -> {}'.format(source, dest))
shutil.copy(source, dest)
else:
print('{} -> {}'.format(source, dest))
os.symlink(source, dest)
def remove(filename):
"""Remove a given filename, regardless of whether it's a file or dir."""
if os.path.isdir(filename):
shutil.rmtree(filename)
else:
os.unlink(filename)
def get_venv_lib_path(path):
"""Get the library path of a virtualenv."""
subdir = 'Scripts' if os.name == 'nt' else 'bin'
executable = os.path.join(path, subdir, 'python')
return run_py(executable,
'from distutils.sysconfig import get_python_lib',
'print(get_python_lib())')
def get_tox_syspython(tox_path):
"""Get the system python based on a virtualenv created by tox."""
path = os.path.join(tox_path, '.tox-config1')
with open(path, encoding='ascii') as f:
line = f.readline()
_md5, sys_python = line.rstrip().split(' ', 1)
return sys_python
def main():
parser = argparse.ArgumentParser()
parser.add_argument('path', help="Base path to the venv.")
parser.add_argument('--tox', help="Add when called via tox.",
action='store_true')
args = parser.parse_args()
if args.tox:
# Workaround for the lack of negative factors in tox.ini
if 'LINK_PYQT_SKIP' in os.environ:
print('LINK_PYQT_SKIP set, exiting...')
sys.exit(0)
executable = get_tox_syspython(args.path)
else:
executable = sys.executable
venv_path = get_venv_lib_path(args.path)
link_pyqt(executable, venv_path)
if __name__ == '__main__':
try:
main()
except Error as e:
print(str(e), file=sys.stderr)
sys.exit(1)
qutebrowser-1.1.1/scripts/setupcommon.py 0000644 0001750 0001751 00000004614 13230703634 021623 0 ustar florian florian 0000000 0000000 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler)
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Data used by setup.py and the PyInstaller qutebrowser.spec."""
import sys
import os
import os.path
import subprocess
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
if sys.hexversion >= 0x03000000:
open_file = open
else:
import codecs
open_file = codecs.open
BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
os.path.pardir)
def _git_str():
"""Try to find out git version.
Return:
string containing the git commit ID and timestamp.
None if there was an error or we're not in a git repo.
"""
if BASEDIR is None:
return None
if not os.path.isdir(os.path.join(BASEDIR, ".git")):
return None
try:
# https://stackoverflow.com/questions/21017300/21017394#21017394
commit_hash = subprocess.run(
['git', 'describe', '--match=NeVeRmAtCh', '--always', '--dirty'],
cwd=BASEDIR, check=True,
stdout=subprocess.PIPE).stdout.decode('UTF-8').strip()
date = subprocess.run(
['git', 'show', '-s', '--format=%ci', 'HEAD'],
cwd=BASEDIR, check=True,
stdout=subprocess.PIPE).stdout.decode('UTF-8').strip()
return '{} ({})'.format(commit_hash, date)
except (subprocess.CalledProcessError, OSError):
return None
def write_git_file():
"""Write the git-commit-id file with the current commit."""
gitstr = _git_str()
if gitstr is None:
gitstr = ''
path = os.path.join(BASEDIR, 'qutebrowser', 'git-commit-id')
with open_file(path, 'w', encoding='ascii') as f:
f.write(gitstr)
qutebrowser-1.1.1/scripts/hist_importer.py 0000755 0001750 0001751 00000013534 13230704277 022152 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017 Florian Bruhin (The Compiler)
# Copyright 2017 Josefson Souza
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Tool to import browser history from other browsers."""
import argparse
import sqlite3
import sys
import os
class Error(Exception):
"""Exception for errors in this module."""
pass
def parse():
"""Parse command line arguments."""
description = ("This program is meant to extract browser history from your"
" previous browser and import them into qutebrowser.")
epilog = ("Databases:\n\n\tqutebrowser: Is named 'history.sqlite' and can "
"be found at your --basedir. In order to find where your "
"basedir is you can run ':open qute:version' inside qutebrowser."
"\n\n\tFirefox: Is named 'places.sqlite', and can be found at "
"your system's profile folder. Check this link for where it is "
"located: http://kb.mozillazine.org/Profile_folder"
"\n\n\tChrome: Is named 'History', and can be found at the "
"respective User Data Directory. Check this link for where it is"
"located: https://chromium.googlesource.com/chromium/src/+/"
"master/docs/user_data_dir.md\n\n"
"Example: hist_importer.py -b firefox -s /Firefox/Profile/"
"places.sqlite -d /qutebrowser/data/history.sqlite")
parser = argparse.ArgumentParser(
description=description, epilog=epilog,
formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('-b', '--browser', dest='browser', required=True,
type=str, help='Browsers: {firefox, chrome}')
parser.add_argument('-s', '--source', dest='source', required=True,
type=str, help='Source: Full path to the sqlite data'
'base file from the source browser.')
parser.add_argument('-d', '--dest', dest='dest', required=True, type=str,
help='\nDestination: Full path to the qutebrowser '
'sqlite database')
return parser.parse_args()
def open_db(data_base):
"""Open connection with database."""
if os.path.isfile(data_base):
return sqlite3.connect(data_base)
raise Error('The file {} does not exist.'.format(data_base))
def extract(source, query):
"""Get records from source database.
Args:
source: File path to the source database where we want to extract the
data from.
query: The query string to be executed in order to retrieve relevant
attributes as (datetime, url, time) from the source database according
to the browser chosen.
"""
try:
conn = open_db(source)
cursor = conn.cursor()
cursor.execute(query)
history = cursor.fetchall()
conn.close()
return history
except sqlite3.OperationalError as op_e:
raise Error('Could not perform queries on the source database: '
'{}'.format(op_e))
def clean(history):
"""Clean up records from source database.
Receives a list of record and sanityze them in order for them to be
properly imported to qutebrowser. Sanitation requires adding a 4th
attribute 'redirect' which is filled with '0's, and also purging all
records that have a NULL/None datetime attribute.
Args:
history: List of records (datetime, url, title) from source database.
"""
# replace missing titles with an empty string
for index, record in enumerate(history):
if record[1] is None:
cleaned = list(record)
cleaned[1] = ''
history[index] = tuple(cleaned)
nulls = [record for record in history if None in record]
for null_record in nulls:
history.remove(null_record)
history = [list(record) for record in history]
for record in history:
record.append('0')
return history
def insert_qb(history, dest):
"""Insert history into dest database.
Args:
history: List of records.
dest: File path to the destination database, where history will be
inserted.
"""
conn = open_db(dest)
cursor = conn.cursor()
cursor.executemany(
'INSERT INTO History (url,title,atime,redirect) VALUES (?,?,?,?)',
history
)
cursor.execute('DROP TABLE CompletionHistory')
conn.commit()
conn.close()
def run():
"""Main control flux of the script."""
args = parse()
browser = args.browser.lower()
source, dest = args.source, args.dest
query = {
'firefox': 'select url,title,last_visit_date/1000000 as date '
'from moz_places',
'chrome': 'select url,title,last_visit_time/10000000 as date '
'from urls',
}
if browser not in query:
raise Error('Sorry, the selected browser: "{}" is not '
'supported.'.format(browser))
else:
history = extract(source, query[browser])
history = clean(history)
insert_qb(history, dest)
def main():
try:
run()
except Error as e:
sys.exit(str(e))
if __name__ == "__main__":
main()
qutebrowser-1.1.1/scripts/keytester.py 0000644 0001750 0001751 00000003276 13202372777 021305 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler)
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Small test script to show key presses.
Use python3 -m scripts.keytester to launch it.
"""
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout
from qutebrowser.utils import utils
class KeyWidget(QWidget):
"""Widget displaying key presses."""
def __init__(self, parent=None):
super().__init__(parent)
self._layout = QHBoxLayout(self)
self._label = QLabel(text="Waiting for keypress...")
self._layout.addWidget(self._label)
def keyPressEvent(self, e):
"""Show pressed keys."""
lines = [
str(utils.keyevent_to_string(e)),
'',
'key: 0x{:x}'.format(int(e.key())),
'modifiers: 0x{:x}'.format(int(e.modifiers())),
'text: {!r}'.format(e.text()),
]
self._label.setText('\n'.join(lines))
app = QApplication([])
w = KeyWidget()
w.show()
app.exec_()
qutebrowser-1.1.1/scripts/utils.py 0000644 0001750 0001751 00000004672 13202372777 020427 0 ustar florian florian 0000000 0000000 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler)
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Utility functions for scripts."""
import os
import os.path
# Import side-effects are an evil thing, but here it's okay so scripts using
# colors work on Windows as well.
try:
import colorama
except ImportError:
colorama = None
else:
colorama.init()
use_color = os.name != 'nt' or colorama
fg_colors = {
'black': 30,
'red': 31,
'green': 32,
'yellow': 33,
'blue': 34,
'magenta': 35,
'cyan': 36,
'white': 37,
'reset': 39,
}
bg_colors = {name: col + 10 for name, col in fg_colors.items()}
term_attributes = {
'bright': 1,
'dim': 2,
'normal': 22,
'reset': 0,
}
def _esc(code):
"""Get an ANSI color code based on a color number."""
return '\033[{}m'.format(code)
def print_col(text, color):
"""Print a colorized text."""
if use_color:
fg = _esc(fg_colors[color.lower()])
reset = _esc(fg_colors['reset'])
print(''.join([fg, text, reset]))
else:
print(text)
def print_title(text):
"""Print a title."""
print_col("==================== {} ====================".format(text),
'yellow')
def print_subtitle(text):
"""Print a subtitle."""
print_col("------ {} ------".format(text), 'cyan')
def print_bold(text):
"""Print a bold text."""
if use_color:
bold = _esc(term_attributes['bright'])
reset = _esc(term_attributes['reset'])
print(''.join([bold, text, reset]))
else:
print(text)
def change_cwd():
"""Change the scripts cwd if it was started inside the script folder."""
cwd = os.getcwd()
if os.path.split(cwd)[1] == 'scripts':
os.chdir(os.path.join(cwd, os.pardir))
qutebrowser-1.1.1/scripts/__init__.py 0000644 0001750 0001751 00000000123 13202372777 021011 0 ustar florian florian 0000000 0000000 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
"""Various utility scripts."""
qutebrowser-1.1.1/scripts/importer.py 0000755 0001750 0001751 00000027126 13230703634 021121 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Claude (longneck)
# Copyright 2014-2017 Florian Bruhin (The Compiler)
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
"""Tool to import data from other browsers.
Currently importing bookmarks from Netscape Bookmark files and Mozilla
profiles is supported.
"""
import argparse
import sqlite3
import os
import urllib.parse
import json
import string
browser_default_input_format = {
'chromium': 'chrome',
'chrome': 'chrome',
'ie': 'netscape',
'firefox': 'mozilla',
'seamonkey': 'mozilla',
'palemoon': 'mozilla',
}
def main():
args = get_args()
bookmark_types = []
output_format = None
input_format = args.input_format
if args.search_output:
bookmark_types = ['search']
if args.oldconfig:
output_format = 'oldsearch'
else:
output_format = 'search'
else:
if args.bookmark_output:
output_format = 'bookmark'
elif args.quickmark_output:
output_format = 'quickmark'
if args.import_bookmarks:
bookmark_types.append('bookmark')
if args.import_keywords:
bookmark_types.append('keyword')
if not bookmark_types:
bookmark_types = ['bookmark', 'keyword']
if not output_format:
output_format = 'quickmark'
if not input_format:
if args.browser:
input_format = browser_default_input_format[args.browser]
else:
#default to netscape
input_format = 'netscape'
import_function = {
'netscape': import_netscape_bookmarks,
'mozilla': import_moz_places,
'chrome': import_chrome,
}
import_function[input_format](args.bookmarks, bookmark_types,
output_format)
def get_args():
"""Get the argparse parser."""
parser = argparse.ArgumentParser(
epilog="To import bookmarks from Chromium, Firefox or IE, "
"export them to HTML in your browsers bookmark manager. ")
parser.add_argument(
'browser',
help="Which browser? {%(choices)s}",
choices=browser_default_input_format.keys(),
nargs='?',
metavar='browser')
parser.add_argument(
'-i',
'--input-format',
help='Which input format? (overrides browser default; "netscape" if '
'neither given)',
choices=set(browser_default_input_format.values()),
required=False)
parser.add_argument(
'-b',
'--bookmark-output',
help="Output in bookmark format.",
action='store_true',
default=False,
required=False)
parser.add_argument(
'-q',
'--quickmark-output',
help="Output in quickmark format (default).",
action='store_true',
default=False,
required=False)
parser.add_argument(
'-s',
'--search-output',
help="Output config.py search engine format (negates -B and -K)",
action='store_true',
default=False,
required=False)
parser.add_argument(
'--oldconfig',
help="Output search engine format for old qutebrowser.conf format",
default=False,
action='store_true',
required=False)
parser.add_argument(
'-B',
'--import-bookmarks',
help="Import plain bookmarks (can be combiend with -K)",
action='store_true',
default=False,
required=False)
parser.add_argument(
'-K',
'--import-keywords',
help="Import keywords (can be combined with -B)",
action='store_true',
default=False,
required=False)
parser.add_argument(
'bookmarks',
help="Bookmarks file (html format) or "
"profile folder (Mozilla format)")
args = parser.parse_args()
return args
def search_escape(url):
"""Escape URLs such that preexisting { and } are handled properly.
Will obviously trash a properly-formatted qutebrowser URL.
"""
return url.replace('{', '{{').replace('}', '}}')
def opensearch_convert(url):
"""Convert a basic OpenSearch URL into something qutebrowser can use.
Exceptions:
KeyError:
An unknown and required parameter is present in the URL. This
usually means there's browser/addon specific functionality needed
to build the URL (I'm looking at you and your browser, Google) that
obviously won't be present here.
"""
subst = {
'searchTerms': '%s', # for proper escaping later
'language': '*',
'inputEncoding': 'UTF-8',
'outputEncoding': 'UTF-8'
}
# remove optional parameters (even those we don't support)
for param in string.Formatter().parse(url):
if param[1]:
if param[1].endswith('?'):
url = url.replace('{' + param[1] + '}', '')
elif param[2] and param[2].endswith('?'):
url = url.replace('{' + param[1] + ':' + param[2] + '}', '')
return search_escape(url.format(**subst)).replace('%s', '{}')
def import_netscape_bookmarks(bookmarks_file, bookmark_types, output_format):
"""Import bookmarks from a NETSCAPE-Bookmark-file v1.
Generated by Chromium, Firefox, IE and possibly more browsers. Not all
export all possible bookmark types:
- Firefox mostly works with everything
- Chrome doesn't support keywords at all; searches are a separate
database
"""
import bs4
with open(bookmarks_file, encoding='utf-8') as f:
soup = bs4.BeautifulSoup(f, 'html.parser')
bookmark_query = {
'search': lambda tag: (
(tag.name == 'a') and
('shortcuturl' in tag.attrs) and
('%s' in tag['href'])),
'keyword': lambda tag: (
(tag.name == 'a') and
('shortcuturl' in tag.attrs) and
('%s' not in tag['href'])),
'bookmark': lambda tag: (
(tag.name == 'a') and
('shortcuturl' not in tag.attrs) and
(tag.string)),
}
output_template = {
'search': {
'search':
"c.url.searchengines['{tag[shortcuturl]}'] = "
"'{tag[href]}' #{tag.string}"
},
'oldsearch': {
'search': '{tag[shortcuturl]} = {tag[href]} #{tag.string}',
},
'bookmark': {
'bookmark': '{tag[href]} {tag.string}',
'keyword': '{tag[href]} {tag.string}'
},
'quickmark': {
'bookmark': '{tag.string} {tag[href]}',
'keyword': '{tag[shortcuturl]} {tag[href]}'
}
}
bookmarks = []
for typ in bookmark_types:
tags = soup.findAll(bookmark_query[typ])
for tag in tags:
if typ == 'search':
tag['href'] = search_escape(tag['href']).replace('%s', '{}')
if tag['href'] not in bookmarks:
bookmarks.append(
output_template[output_format][typ].format(tag=tag))
for bookmark in bookmarks:
print(bookmark)
def import_moz_places(profile, bookmark_types, output_format):
"""Import bookmarks from a Mozilla profile's places.sqlite database."""
place_query = {
'bookmark': (
"SELECT DISTINCT moz_bookmarks.title,moz_places.url "
"FROM moz_bookmarks,moz_places "
"WHERE moz_places.id=moz_bookmarks.fk "
"AND moz_places.id NOT IN (SELECT place_id FROM moz_keywords) "
"AND moz_places.url NOT LIKE 'place:%';"
), # Bookmarks with no keywords assigned
'keyword': (
"SELECT moz_keywords.keyword,moz_places.url "
"FROM moz_keywords,moz_places,moz_bookmarks "
"WHERE moz_places.id=moz_bookmarks.fk "
"AND moz_places.id=moz_keywords.place_id "
"AND moz_places.url NOT LIKE '%!%s%' ESCAPE '!';"
), # Bookmarks with keywords assigned but no %s substitution
'search': (
"SELECT moz_keywords.keyword, "
" moz_bookmarks.title, "
" search_conv(moz_places.url) AS url "
"FROM moz_keywords,moz_places,moz_bookmarks "
"WHERE moz_places.id=moz_bookmarks.fk "
"AND moz_places.id=moz_keywords.place_id "
"AND moz_places.url LIKE '%!%s%' ESCAPE '!';"
) # bookmarks with keyword and %s substitution
}
out_template = {
'bookmark': {
'bookmark': '{url} {title}',
'keyword': '{url} {keyword}'
},
'quickmark': {
'bookmark': '{title} {url}',
'keyword': '{keyword} {url}'
},
'oldsearch': {
'search': '{keyword} {url} #{title}'
},
'search': {
'search': "c.url.searchengines['{keyword}'] = '{url}' #{title}"
}
}
def search_conv(url):
return search_escape(url).replace('%s', '{}')
places = sqlite3.connect(os.path.join(profile, "places.sqlite"))
places.create_function('search_conv', 1, search_conv)
places.row_factory = sqlite3.Row
c = places.cursor()
for typ in bookmark_types:
c.execute(place_query[typ])
for row in c:
print(out_template[output_format][typ].format(**row))
def import_chrome(profile, bookmark_types, output_format):
"""Import bookmarks and search keywords from Chrome-type profiles.
On Chrome, keywords and search engines are the same thing and handled in
their own database table; bookmarks cannot have associated keywords. This
is why the dictionary lookups here are much simpler.
"""
out_template = {
'bookmark': '{url} {name}',
'quickmark': '{name} {url}',
'search': "c.url.searchengines['{keyword}'] = '{url}'",
'oldsearch': '{keyword} {url}'
}
if 'search' in bookmark_types:
webdata = sqlite3.connect(os.path.join(profile, 'Web Data'))
c = webdata.cursor()
c.execute('SELECT keyword,url FROM keywords;')
for keyword, url in c:
try:
url = opensearch_convert(url)
print(out_template[output_format].format(
keyword=keyword, url=url))
except KeyError:
print('# Unsupported parameter in url for {}; skipping....'.
format(keyword))
else:
with open(os.path.join(profile, 'Bookmarks'), encoding='utf-8') as f:
bookmarks = json.load(f)
def bm_tree_walk(bm, template):
"""Recursive function to walk through bookmarks."""
assert 'type' in bm, bm
if bm['type'] == 'url':
if urllib.parse.urlparse(bm['url']).scheme != 'chrome':
print(template.format(**bm))
elif bm['type'] == 'folder':
for child in bm['children']:
bm_tree_walk(child, template)
for root in bookmarks['roots'].values():
bm_tree_walk(root, out_template[output_format])
if __name__ == '__main__':
main()
qutebrowser-1.1.1/MANIFEST.in 0000644 0001750 0001751 00000002345 13230703634 016746 0 ustar florian florian 0000000 0000000 recursive-include qutebrowser *.py
recursive-include qutebrowser/img *.svg *.png
recursive-include qutebrowser/test *.py
recursive-include qutebrowser/javascript *.js
graft qutebrowser/html
graft qutebrowser/3rdparty
graft icons
graft doc/img
graft misc/apparmor
graft misc/userscripts
recursive-include scripts *.py *.sh
include qutebrowser/utils/testfile
include qutebrowser/git-commit-id
include LICENSE doc/* README.asciidoc
include misc/qutebrowser.desktop
include misc/qutebrowser.appdata.xml
include misc/Makefile
include requirements.txt
include tox.ini
include qutebrowser.py
include misc/cheatsheet.svg
include qutebrowser/config/configdata.yml
prune www
prune scripts/dev
prune scripts/testbrowser/cpp
prune .github
exclude scripts/asciidoc2html.py
exclude doc/notes
recursive-exclude doc *.asciidoc
include doc/qutebrowser.1.asciidoc
include doc/changelog.asciidoc
prune tests
prune qutebrowser/3rdparty
prune misc/requirements
prune misc/docker
exclude pytest.ini
exclude qutebrowser.rcc
exclude qutebrowser/javascript/.eslintrc.yaml
exclude qutebrowser/javascript/.eslintignore
exclude doc/help
exclude .*
exclude misc/appveyor_install.py
exclude misc/qutebrowser.spec
exclude misc/qutebrowser.nsi
global-exclude __pycache__ *.pyc *.pyo
qutebrowser-1.1.1/setup.cfg 0000644 0001750 0001751 00000000046 13230704465 017030 0 ustar florian florian 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
qutebrowser-1.1.1/misc/ 0000755 0001750 0001751 00000000000 13230704465 016142 5 ustar florian florian 0000000 0000000 qutebrowser-1.1.1/misc/qutebrowser.appdata.xml 0000644 0001750 0001751 00000003236 13230703634 022660 0 ustar florian florian 0000000 0000000
org.qutebrowser.qutebrowserCC-BY-SA-3.0GPL-3.0qutebrowserA keyboard-driven web browser
qutebrowser is a keyboard-focused browser with a minimal GUI.
It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl,
and is based on Python and PyQt5.
NetworkWebBrowserqutebrowserqutebrowser.desktophttps://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/main.pnghttps://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/downloads.pnghttps://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/completion.pnghttps://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/hints.pnghttps://www.qutebrowser.orghttps://qutebrowser.org/doc/faq.htmlhttps://qutebrowser.org/doc/help/https://github.com/qutebrowser/qutebrowser/issues/https://github.com/qutebrowser/qutebrowser#donating
qutebrowser-1.1.1/misc/apparmor/ 0000755 0001750 0001751 00000000000 13230704465 017763 5 ustar florian florian 0000000 0000000 qutebrowser-1.1.1/misc/apparmor/usr.bin.qutebrowser 0000644 0001750 0001751 00000001745 13202372777 023664 0 ustar florian florian 0000000 0000000 # AppArmor profile for qutebrowser
# Tested on Debian jessie
#include
profile qutebrowser /usr/{local/,}bin/qutebrowser {
#include
#include
#include
#include
#include
#include
#include
#include
#include
capability dac_override,
/usr/{local/,}bin/ r,
/usr/{local/,}bin/qutebrowser rix,
/usr/bin/python3.? r,
/usr/lib/python3/ mr,
/usr/lib/python3/** mr,
/usr/lib/python3.?/ r,
/usr/lib/python3.?/** mr,
/usr/local/lib/python3.?/** r,
/proc/*/mounts r,
owner /tmp/** rwkl,
owner /run/user/*/ rw,
owner /run/user/*/** krw,
@{HOME}/.config/qutebrowser/** krw,
@{HOME}/.local/share/qutebrowser/** krw,
@{HOME}/.cache/qutebrowser/** krw,
@{HOME}/.gstreamer-0.10/* r,
}
qutebrowser-1.1.1/misc/qutebrowser.rcc 0000644 0001750 0001751 00000000735 13202372777 021230 0 ustar florian florian 0000000 0000000 icons/qutebrowser-16x16.pngicons/qutebrowser-24x24.pngicons/qutebrowser-32x32.pngicons/qutebrowser-48x48.pngicons/qutebrowser-64x64.pngicons/qutebrowser-96x96.pngicons/qutebrowser-128x128.pngicons/qutebrowser-256x256.pngicons/qutebrowser-512x512.png
qutebrowser-1.1.1/misc/Makefile 0000644 0001750 0001751 00000002030 13230703634 017572 0 ustar florian florian 0000000 0000000 PYTHON = python3
DESTDIR = /
ICONSIZES = 16 24 32 48 64 128 256 512
.PHONY: install
doc/qutebrowser.1.html:
a2x -f manpage doc/qutebrowser.1.asciidoc
install: doc/qutebrowser.1.html
$(PYTHON) setup.py install --root="$(DESTDIR)" --optimize=1
install -Dm644 doc/qutebrowser.1 \
"$(DESTDIR)/usr/share/man/man1/qutebrowser.1"
install -Dm644 misc/qutebrowser.desktop \
"$(DESTDIR)/usr/share/applications/qutebrowser.desktop"
$(foreach i,$(ICONSIZES),install -Dm644 "icons/qutebrowser-$(i)x$(i).png" \
"$(DESTDIR)/usr/share/icons/hicolor/$(i)x$(i)/apps/qutebrowser.png";)
install -Dm644 icons/qutebrowser.svg \
"$(DESTDIR)/usr/share/icons/hicolor/scalable/apps/qutebrowser.svg"
install -Dm755 -t "$(DESTDIR)/usr/share/qutebrowser/userscripts/" \
$(wildcard misc/userscripts/*)
install -Dm755 -t "$(DESTDIR)/usr/share/qutebrowser/scripts/" \
$(filter-out scripts/__init__.py scripts/__pycache__ scripts/dev \
scripts/testbrowser scripts/asciidoc2html.py scripts/setupcommon.py \
scripts/link_pyqt.py,$(wildcard scripts/*))
qutebrowser-1.1.1/misc/qutebrowser.desktop 0000644 0001750 0001751 00000000573 13230703634 022121 0 ustar florian florian 0000000 0000000 [Desktop Entry]
Name=qutebrowser
GenericName=Web Browser
Icon=qutebrowser
Type=Application
Categories=Network;WebBrowser;
Exec=qutebrowser %u
Terminal=false
StartupNotify=false
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/qute;
Keywords=Browser
qutebrowser-1.1.1/misc/userscripts/ 0000755 0001750 0001751 00000000000 13230704465 020530 5 ustar florian florian 0000000 0000000 qutebrowser-1.1.1/misc/userscripts/qutedmenu 0000755 0001750 0001751 00000002746 13230703634 022473 0 ustar florian florian 0000000 0000000 #!/usr/bin/env bash
# Handle open -s && open -t with bemenu
#:bind o spawn --userscript /path/to/userscripts/qutedmenu open
#:bind O spawn --userscript /path/to/userscripts/qutedmenu tab
# If you would like to set a custom colorscheme/font use these dirs.
# https://github.com/halfwit/dotfiles/blob/master/.config/dmenu/bemenucolors
readonly confdir=${XDG_CONFIG_HOME:-$HOME/.config}
readonly optsfile=$confdir/dmenu/bemenucolors
create_menu() {
# Check quickmarks
while read -r url; do
printf -- '%s\n' "$url"
done < "$QUTE_CONFIG_DIR"/quickmarks
# Next bookmarks
while read -r url _; do
printf -- '%s\n' "$url"
done < "$QUTE_CONFIG_DIR"/bookmarks/urls
# Finally history
while read -r _ url; do
printf -- '%s\n' "$url"
done < "$QUTE_DATA_DIR"/history
}
get_selection() {
opts+=(-p qutebrowser)
#create_menu | dmenu -l 10 "${opts[@]}"
create_menu | bemenu -l 10 "${opts[@]}"
}
# Main
# https://github.com/halfwit/dotfiles/blob/master/.config/dmenu/font
[[ -s $confdir/dmenu/font ]] && read -r font < "$confdir"/dmenu/font
[[ $font ]] && opts+=(-fn "$font")
# shellcheck source=/dev/null
[[ -s $optsfile ]] && source "$optsfile"
url=$(get_selection)
url=${url/*http/http}
# If no selection is made, exit (escape pressed, e.g.)
[[ ! $url ]] && exit 0
case $1 in
open) printf '%s' "open $url" >> "$QUTE_FIFO" || qutebrowser "$url" ;;
tab) printf '%s' "open -t $url" >> "$QUTE_FIFO" || qutebrowser "$url" ;;
esac
qutebrowser-1.1.1/misc/userscripts/cast 0000755 0001750 0001751 00000011551 13230703634 021410 0 ustar florian florian 0000000 0000000 #!/usr/bin/env bash
#
# Behaviour
# Userscript for qutebrowser which casts the url passed in $1 to the default
# ChromeCast device in the network using the program `castnow`
#
# Usage
# You can launch the script from qutebrowser as follows:
# spawn --userscript ${PATH_TO_FILE} {url}
#
# Then, you can control the chromecast by launching the simple command
# `castnow` in a shell which will connect to the running castnow instance.
#
# For stopping the script, issue the command `pkill -f castnow` which would
# then let the rest of the userscript execute for cleaning temporary file.
#
# Thanks
# This userscript borrows Thorsten Wißmann's javascript code from his `mpv`
# userscript.
#
# Dependencies
# - castnow, https://github.com/xat/castnow
#
# Author
# Simon Désaulniers
if [ -z "$QUTE_FIFO" ] ; then
cat 1>&2 <&2
else
echo "message-$cmd '${msg//\'/\\\'}'" >> "$QUTE_FIFO"
fi
}
js() {
cat <
The video is being cast on your ChromeCast device.
In order to restore this particular video
click here.
";
replacement.style.position = "relative";
replacement.style.zIndex = "100003000000";
replacement.style.fontSize = "1rem";
replacement.style.textAlign = "center";
replacement.style.verticalAlign = "middle";
replacement.style.height = "100%";
replacement.style.background = "#101010";
replacement.style.color = "white";
replacement.style.border = "4px dashed #545454";
replacement.style.padding = "2em";
replacement.style.margin = "auto";
App.all_replacements[i] = replacement;
App.backup_videos[i] = video;
video.parentNode.replaceChild(replacement, video);
}
function restore_video(obj, index) {
obj = App.all_replacements[index];
video = App.backup_videos[index];
console.log(video);
obj.parentNode.replaceChild(video, obj);
}
/** force repainting the video, thanks to:
* http://martinwolf.org/2014/06/10/force-repaint-of-an-element-with-javascript/
*/
var siteHeader = document.getElementById('header');
siteHeader.style.display='none';
siteHeader.offsetHeight; // no need to store this anywhere, the reference is enough
siteHeader.style.display='block';
EOF
}
printjs() {
js | sed 's,//.*$,,' | tr '\n' ' '
}
echo "jseval -q $(printjs)" >> "$QUTE_FIFO"
tmpdir=$(mktemp -d)
file_to_cast=${tmpdir}/qutecast
program_=$(command -v castnow)
if [[ "${program_}" == "" ]]; then
msg error "castnow can't be found..."
exit 1
fi
# kill any running instance of castnow
pkill -f "${program_}"
# start youtube download in stream mode (-o -) into temporary file
youtube-dl -qo - "$1" > "${file_to_cast}" &
ytdl_pid=$!
msg info "Casting $1" >> "$QUTE_FIFO"
# start castnow in stream mode to cast on ChromeCast
tail -F "${file_to_cast}" | ${program_} -
# cleanup remaining background process and file on disk
kill ${ytdl_pid}
rm -rf "${tmpdir}"
qutebrowser-1.1.1/misc/userscripts/ripbang 0000755 0001750 0001751 00000001702 13216012203 022062 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python
#
# Adds DuckDuckGo bang as searchengine.
#
# Usage:
# :spawn --userscript ripbang [bang]...
#
# Example:
# :spawn --userscript ripbang amazon maps
#
from __future__ import print_function
import os, re, requests, sys
try:
from urllib.parse import unquote
except ImportError:
from urllib import unquote
for argument in sys.argv[1:]:
bang = '!' + argument
r = requests.get('https://duckduckgo.com/',
params={'q': bang + ' SEARCHTEXT'})
searchengine = unquote(re.search("url=[^']+", r.text).group(0))
searchengine = searchengine.replace('url=', '')
searchengine = searchengine.replace('/l/?kh=-1&uddg=', '')
searchengine = searchengine.replace('SEARCHTEXT', '{}')
if os.getenv('QUTE_FIFO'):
with open(os.environ['QUTE_FIFO'], 'w') as fifo:
fifo.write('set searchengines %s %s' % (bang, searchengine))
else:
print('%s %s' % (bang, searchengine))
qutebrowser-1.1.1/misc/userscripts/rss 0000755 0001750 0001751 00000007077 13230703634 021275 0 ustar florian florian 0000000 0000000 #!/bin/sh
# Copyright 2016 Jan Verbeek (blyxxyz)
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
# This script keeps track of URLs in RSS feeds and opens new ones.
# New feeds can be added with ':spawn -u /path/to/userscripts/rss add' or
# ':spawn -u /path/to/userscripts/rss '.
# New items can be opened with ':spawn -u /path/to/userscripts/rss'.
# The script doesn't really parse XML, and searches for things that look like
# item links. It might open things that aren't real links, and it might miss
# real links.
config_dir="$HOME/.qute-rss"
add_feed () {
touch "feeds"
if grep -Fq "$1" "feeds"; then
notice "$1 is saved already."
else
printf '%s\n' "$1" >> "feeds"
fi
}
# Show an error message and exit
fail () {
echo "message-error '$*'" > "$QUTE_FIFO"
exit 1
}
# Get a sorted list of item URLs from a RSS feed
get_items () {
$curl "$@" | grep "$text_only" -zo -e ']*>[^<>]*' \
-e ']*>[^<>]*' \
-e ']*href="[^"]*"' |
grep "$text_only" -o 'http[^<>"]*' | sort | uniq
}
# Show an info message
notice () {
echo "message-info '$*'" > "$QUTE_FIFO"
}
# Update a database of a feed and open new URLs
read_items () {
cd read_urls || return 1
feed_file="$(echo "$1" | tr -d /)"
feed_temp_file="$(mktemp "$feed_file.tmp.XXXXXXXXXX")"
feed_new_items="$(mktemp "$feed_file.new.XXXXXXXXXX")"
get_items "$1" > "$feed_temp_file"
if [ ! -s "$feed_temp_file" ]; then
notice "No items found for $1."
rm "$feed_temp_file" "$feed_new_items"
elif [ ! -f "$feed_file" ]; then
notice "$1 is a new feed. All items will be marked as read."
mv "$feed_temp_file" "$feed_file"
rm "$feed_new_items"
else
sort -o "$feed_file" "$feed_file"
comm -2 -3 "$feed_temp_file" "$feed_file" | tee "$feed_new_items"
cat "$feed_new_items" >> "$feed_file"
sort -o "$feed_file" "$feed_file"
rm "$feed_temp_file" "$feed_new_items"
fi | while read -r item; do
echo "open -t $item" > "$QUTE_FIFO"
done
}
if [ ! -d "$config_dir/read_urls" ]; then
notice "Creating configuration directory."
mkdir -p "$config_dir/read_urls"
fi
cd "$config_dir" || exit 1
if [ $# != 0 ]; then
for arg in "$@"; do
if [ "$arg" = "add" ]; then
add_feed "$QUTE_URL"
else
add_feed "$arg"
fi
done
exit
fi
if [ ! -f "feeds" ]; then
fail "Add feeds by running ':spawn -u rss add' or ':spawn -u rss '."
fi
if curl --version >&-; then
curl="curl -sL"
elif wget --version >&-; then
curl="wget -qO -"
else
fail "Either curl or wget is needed to run this script."
fi
# Detect GNU grep so we can force it to treat everything as text
if < /dev/null grep --help 2>&1 | grep -q -- -a; then
text_only="-a"
fi
while read -r feed_url; do
read_items "$feed_url" &
done < "$config_dir/feeds"
wait
qutebrowser-1.1.1/misc/userscripts/open_download 0000755 0001750 0001751 00000006414 13230703634 023310 0 ustar florian florian 0000000 0000000 #!/usr/bin/env bash
# Both standalone script and qutebrowser userscript that opens a rofi menu with
# all files from the download director and opens the selected file. It works
# both as a userscript and a standalone script that is called from outside of
# qutebrowser.
#
# Suggested keybinding (for "show downloads"):
# spawn --userscript ~/.config/qutebrowser/open_download
# sd
#
# Requirements:
# - rofi (in a recent version)
# - xdg-open and xdg-mime
# - You should configure qutebrowser to download files to a single directory
# - It comes in handy if you enable downloads.remove_finished. If you want to
# see the recent downloads, just press "sd".
#
# Thorsten Wißmann, 2015 (thorsten` on freenode)
# Any feedback is welcome!
set -e
# open a file from the download directory using rofi
DOWNLOAD_DIR=${DOWNLOAD_DIR:-$QUTE_DOWNLOAD_DIR}
DOWNLOAD_DIR=${DOWNLOAD_DIR:-$HOME/Downloads}
# the name of the rofi command
ROFI_CMD=${ROFI_CMD:-rofi}
ROFI_ARGS=${ROFI_ARGS:-}
msg() {
local cmd="$1"
shift
local msg="$*"
if [ -z "$QUTE_FIFO" ] ; then
echo "$cmd: $msg" >&2
else
echo "message-$cmd '${msg//\'/\\\'}'" >> "$QUTE_FIFO"
fi
}
die() {
msg error "$*"
if [ -n "$QUTE_FIFO" ] ; then
# when run as a userscript, the above error message already informs the
# user about the failure, and no additional "userscript exited with status
# 1" is needed.
exit 0;
else
exit 1;
fi
}
if ! [ -d "$DOWNLOAD_DIR" ] ; then
die "Download directory »$DOWNLOAD_DIR« not found!"
fi
if ! which "${ROFI_CMD}" > /dev/null ; then
die "Rofi command »${ROFI_CMD}« not found in PATH!"
fi
rofi_default_args=(
-monitor -2 # place above window
-location 6 # aligned at the bottom
-width 100 # use full window width
-i
-no-custom
-format i # make rofi return the index
-l 10
-p 'Open download:' -dmenu
)
crop-first-column() {
local maxlength=${1:-40}
local expression='s|^\([^\t]\{0,'"$maxlength"'\}\)[^\t]*\t|\1\t|'
sed "$expression"
}
ls-files() {
# add the slash at the end of the download dir enforces to follow the
# symlink, if the DOWNLOAD_DIR itself is a symlink
# shellcheck disable=SC2010
ls -Q --quoting-style escape -h -o -1 -A -t "${DOWNLOAD_DIR}/" \
| grep '^[-]' \
| cut -d' ' -f3- \
| sed 's,^\(.*[^\]\) \(.*\)$,\2\t\1,' \
| sed 's,\\\(.\),\1,g'
}
mapfile -t entries < <(ls-files)
# we need to manually check that there are items, because rofi doesn't show up
# if there are no items and -no-custom is passed to rofi.
if [ "${#entries[@]}" -eq 0 ] ; then
die "Download directory »${DOWNLOAD_DIR}« empty"
fi
line=$(printf '%s\n' "${entries[@]}" \
| crop-first-column 55 \
| column -s $'\t' -t \
| $ROFI_CMD "${rofi_default_args[@]}" "$ROFI_ARGS") || true
if [ -z "$line" ]; then
exit 0
fi
file="${entries[$line]}"
file="${file%%$'\t'*}"
path="$DOWNLOAD_DIR/$file"
filetype=$(xdg-mime query filetype "$path")
application=$(xdg-mime query default "$filetype")
if [ -z "$application" ] ; then
die "Do not know how to open »$file« of type $filetype"
fi
msg info "Opening »$file« (of type $filetype) with ${application%.desktop}"
xdg-open "$path" &
qutebrowser-1.1.1/misc/userscripts/openfeeds 0000755 0001750 0001751 00000002747 13216012203 022422 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2015 jnphilipp
# Copyright 2016-2017 Florian Bruhin (The Compiler)
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
# Opens all links to feeds defined in the head of a site
#
# Ideal for use with tabs_are_windows. Set a hotkey to launch this script, then:
# :bind gF spawn --userscript openfeeds
#
# Use the hotkey to open the feeds in new tab/window, press 'gF' to open
#
import os
import re
from bs4 import BeautifulSoup
from urllib.parse import urljoin
with open(os.environ['QUTE_HTML'], 'r') as f:
soup = BeautifulSoup(f)
with open(os.environ['QUTE_FIFO'], 'w') as f:
for link in soup.find_all('link', rel='alternate', type=re.compile(r'application/((rss|rdf|atom)\+)?xml|text/xml')):
f.write('open -t %s\n' % urljoin(os.environ['QUTE_URL'], link.get('href')))
qutebrowser-1.1.1/misc/userscripts/readability 0000755 0001750 0001751 00000002333 13216012203 022732 0 ustar florian florian 0000000 0000000 #!/usr/bin/env python
#
# Executes python-readability on current page and opens the summary as new tab.
#
# Depends on the python-readability package, or its fork:
#
# - https://github.com/buriy/python-readability
# - https://github.com/bookieio/breadability
#
# Usage:
# :spawn --userscript readability
#
from __future__ import absolute_import
import codecs, os
tmpfile=os.path.expanduser('~/.local/share/qutebrowser/userscripts/readability.html')
if not os.path.exists(os.path.dirname(tmpfile)):
os.makedirs(os.path.dirname(tmpfile))
with codecs.open(os.environ['QUTE_HTML'], 'r', 'utf-8') as source:
data = source.read()
try:
from breadability.readable import Article as reader
doc = reader(data)
content = doc.readable
except ImportError:
from readability import Document
doc = Document(data)
content = doc.summary().replace('', '%s' % doc.title())
with codecs.open(tmpfile, 'w', 'utf-8') as target:
target.write('')
target.write(content)
with open(os.environ['QUTE_FIFO'], 'w') as fifo:
fifo.write('open -t %s' % tmpfile)
qutebrowser-1.1.1/misc/userscripts/qutebrowser_viewsource 0000755 0001750 0001751 00000002205 13202372777 025320 0 ustar florian florian 0000000 0000000 #!/usr/bin/env bash
# Copyright 2015 Zach-Button
# Copyright 2016-2017 Florian Bruhin (The Compiler)
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see .
#
# This script fetches the unprocessed HTML source for a page and opens it in vim.
# :bind gf spawn --userscript qutebrowser_viewsource
#
# Caveat: Does not use authentication of any kind. Add it in if you want it to.
#
path=$(mktemp --tmpdir qutebrowser_XXXXXXXX.html)
curl "$QUTE_URL" > "$path"
urxvt -e vim "$path"
rm "$path"
qutebrowser-1.1.1/misc/userscripts/view_in_mpv 0000755 0001750 0001751 00000012015 13230703634 022774 0 ustar florian florian 0000000 0000000 #!/usr/bin/env bash
#
# Behavior:
# Userscript for qutebrowser which views the current web page in mpv using
# sensible mpv-flags. While viewing the page in MPV, all