From 709239dfcaa95d82a53d08ac5eb018b23e04ef41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20=E2=80=9CFrogeye=E2=80=9D=20Preud=27homme?= Date: Sun, 27 Dec 2020 14:20:44 +0100 Subject: [PATCH] rssViedos mostly --- config/automatrop/roles/color/tasks/main.yml | 5 +- config/ccache.conf | 1 + config/flake8 | 3 + config/i3/config.j2 | 4 +- config/pycodestyle | 3 + config/scripts/crepuscule | 8 + config/scripts/jour | 8 + config/scripts/mediaDuration | 58 +++++ config/scripts/nuit | 8 + config/scripts/rssVideos | 215 ++++++++++++++----- config/scripts/smtpdummy | 176 +++++++++++---- config/scripts/videoQuota | 55 +++++ config/scripts/wttr | 2 +- config/shell/commonrc | 22 ++ config/shell/shenv | 2 +- config/vim/pluginconfig.vim | 17 +- config/vim/vimconfig.vim | 3 + 17 files changed, 479 insertions(+), 111 deletions(-) create mode 100644 config/ccache.conf create mode 100644 config/flake8 create mode 100644 config/pycodestyle create mode 100755 config/scripts/crepuscule create mode 100755 config/scripts/jour create mode 100755 config/scripts/mediaDuration create mode 100755 config/scripts/nuit create mode 100755 config/scripts/videoQuota diff --git a/config/automatrop/roles/color/tasks/main.yml b/config/automatrop/roles/color/tasks/main.yml index d32f2f5..edcf166 100644 --- a/config/automatrop/roles/color/tasks/main.yml +++ b/config/automatrop/roles/color/tasks/main.yml @@ -86,7 +86,7 @@ - name: Download base16 theme for qutebrowser get_url: - url: "https://raw.githubusercontent.com/theova/base16-qutebrowser/master/themes/default/base16-{{ base16_scheme }}.config.py" + url: "https://raw.githubusercontent.com/theova/base16-qutebrowser/main/themes/default/base16-{{ base16_scheme }}.config.py" dest: "{{ ansible_env.HOME }}/.config/qutebrowser/theme.py" mode: "u+rw,g=r,o=r" notify: @@ -111,8 +111,7 @@ dest: "{{ ansible_env.HOME }}/.config/dunst/dunstrc" mode: "u+rw,g=r,o=r" -# TODO mechanism to switching light/dark quickly -# TODO dunst (template online, but not to my liking) +# TODO Generate themes locally because not being able to switch themes because GitHub being down is just silly # TODO bar (might change bar in the future, so...) # TODO highlight (there IS a template but the colors look different from vim and mostly the same from when there's no config) # TODO https://github.com/makuto/auto-base16-theme ? :P diff --git a/config/ccache.conf b/config/ccache.conf new file mode 100644 index 0000000..ec8132c --- /dev/null +++ b/config/ccache.conf @@ -0,0 +1 @@ +ccache_dir = $HOME/.cache/ccache diff --git a/config/flake8 b/config/flake8 new file mode 100644 index 0000000..b66470c --- /dev/null +++ b/config/flake8 @@ -0,0 +1,3 @@ +[flake8] +# Compatibility with Black +max-line-length = 88 diff --git a/config/i3/config.j2 b/config/i3/config.j2 index a9e8841..111b1b2 100644 --- a/config/i3/config.j2 +++ b/config/i3/config.j2 @@ -381,7 +381,7 @@ exec --no-startup-id keynav # Keyboard cursor controller # exec --no-startup-id ~/.config/i3/ashuffle # MPD Auto-refill exec --no-startup-id autorandr --change --force # Screen configuration and everything that depends on it exec --no-startup-id ~/.config/i3/batteryNotify -d # Battery state notification -exec --no-startup-id ~/.config/i3/aw_start # Activity tracker +# exec --no-startup-id ~/.config/i3/aw_start # Activity tracker {{ lookup('file', ansible_env.HOME + '/.config/i3/theme') }} @@ -389,7 +389,7 @@ set $ignore #ff00ff # Basic color configuration using the Base16 variables for windows and borders. # Property Name Border BG Text Indicator Child Border -client.focused $base00 $base00 $base05 $base00 $base07 +client.focused $base0B $base0B $base00 $base00 $base0B client.focused_inactive $base02 $base02 $base05 $base02 $base02 client.unfocused $base05 $base04 $base00 $base04 $base00 client.urgent $base0F $base08 $base00 $base08 $base0F diff --git a/config/pycodestyle b/config/pycodestyle new file mode 100644 index 0000000..c89fb1c --- /dev/null +++ b/config/pycodestyle @@ -0,0 +1,3 @@ +[pycodestyle] +# Compatibility with Black +max-line-length = 88 diff --git a/config/scripts/crepuscule b/config/scripts/crepuscule new file mode 100755 index 0000000..cccd794 --- /dev/null +++ b/config/scripts/crepuscule @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# TODO De-hardcode + +cd ~/.dotfiles/config/automatrop +echo 30000 | sudo tee /sys/class/backlight/intel_backlight/brightness +xrandr --output HDMI-0 --brightness 1 +ansible-playbook playbooks/default.yml -e base16_scheme=solarized-dark diff --git a/config/scripts/jour b/config/scripts/jour new file mode 100755 index 0000000..d651683 --- /dev/null +++ b/config/scripts/jour @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# TODO De-hardcode + +cd ~/.dotfiles/config/automatrop +echo 30000 | sudo tee /sys/class/backlight/intel_backlight/brightness +xrandr --output HDMI-0 --brightness 1 +ansible-playbook playbooks/default.yml -e base16_scheme=solarized-light diff --git a/config/scripts/mediaDuration b/config/scripts/mediaDuration new file mode 100755 index 0000000..153f48d --- /dev/null +++ b/config/scripts/mediaDuration @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +import os +import sys +import subprocess +import logging + +import coloredlogs + +coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s') +log = logging.getLogger() + + +def duration_file(path: str) -> float: + cmd = [ + "ffprobe", + "-v", + "error", + "-show_entries", + "format=duration", + "-of", + "default=noprint_wrappers=1:nokey=1", + path, + ] + run = subprocess.run(cmd, stdout=subprocess.PIPE) + ret = run.stdout.decode().strip() + if run.returncode != 0: + log.warning(f"{path}: unable to get duration") + elif ret == 'N/A': + log.warning(f"{path}: has no duration") + else: + try: + return float(ret) + except ValueError: + log.error(f"{path}: returned {ret}") + return 0 + + +def duration_directory(path: str) -> float: + total = 0.0 + for root, dirs, files in os.walk(path): + for f in files: + fullPath = os.path.join(root, f) + total += duration_file(fullPath) + return total + + +total = 0.0 +for arg in sys.argv[1:]: + if os.path.isfile(arg): + total += duration_file(arg) + elif os.path.isdir(arg): + total += duration_directory(arg) + else: + raise FileNotFoundError(f"No such file or directory: '{arg}'") + + +print(total) diff --git a/config/scripts/nuit b/config/scripts/nuit new file mode 100755 index 0000000..03ce6e9 --- /dev/null +++ b/config/scripts/nuit @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# TODO De-hardcode + +cd ~/.dotfiles/config/automatrop +echo 1 | sudo tee /sys/class/backlight/intel_backlight/brightness +xrandr --output HDMI-0 --brightness 0.5 +ansible-playbook playbooks/default.yml -e base16_scheme=solarized-dark diff --git a/config/scripts/rssVideos b/config/scripts/rssVideos index 500f811..1afeb70 100755 --- a/config/scripts/rssVideos +++ b/config/scripts/rssVideos @@ -10,10 +10,10 @@ with the unread items (non-video links are ignored). # TODO Distribute this correclty, in the meanwhile please do # pip install --user youtube-dl ConfigArgParse progressbar2 -# TODO Allow to specify youtube_dl options (e.g. subtitles) -# TODO Restrict quality (it's not that I don't like 8GB 4K videos but...) +# TODO Better logging (youtube-dl allow to pass loggers) -from typing import Dict, Set +import sys +from typing import Dict, Set, Tuple import urllib.request import urllib.parse import os @@ -22,27 +22,69 @@ import youtube_dl import configargparse -if __name__ == "__main__": +def get_args() -> configargparse.Namespace: + defaultConfigPath = os.path.join( + os.path.expanduser(os.getenv("XDG_CONFIG_PATH", "~/.config/")), "rssVideos" + ) - defaultConfigPath = os.path.join(os.path.expanduser( - os.getenv('XDG_CONFIG_PATH', '~/.config/')), 'rssVideos') - - - parser = configargparse.ArgParser(description="Download videos linked in " + - "a RSS feed (e.g. an unread feed from " + - "an RSS aggregator", - default_config_files=[defaultConfigPath]) - parser.add('-c', '--config', required=False, is_config_file=True, - help='Configuration file') - parser.add('--feed', help='URL of the RSS feed (must be public for now)', - env_var='RSS_VIDEOS_FEED', required=True) - parser.add('--videos', help='Directory to store videos', - env_var='RSS_VIDEOS_VIDEO_DIR', required=True) - parser.add('-n', '--dryrun', help='Do not download the videos', - action='store_const', const=True, default=False) - # TODO This feature might require additional documentation and an on/off switc - parser.add('--track', help='Directory where download videos are maked (so they are not downloaded twice)', - env_var='RSS_VIDEOS_TRACK', required=False, default='.rssVideos') + parser = configargparse.ArgParser( + description="Download videos linked in " + + "a RSS feed (e.g. an unread feed from " + + "an RSS aggregator", + default_config_files=[defaultConfigPath], + ) + parser.add( + "-c", "--config", required=False, is_config_file=True, help="Configuration file" + ) + parser.add( + "--feed", + help="URL of the RSS feed (must be public for now)", + env_var="RSS_VIDEOS_FEED", + required=True, + ) + parser.add( + "--videos", + help="Directory to store videos", + env_var="RSS_VIDEOS_VIDEO_DIR", + required=True, + ) + parser.add( + "-n", + "--dryrun", + help="Do not download the videos", + action="store_const", + const=True, + default=False, + ) + # TODO This feature might require additional documentation and an on/off switch + parser.add( + "--track", + help="Directory where download videos are marked " + + "to not download them after deletion.", + env_var="RSS_VIDEOS_TRACK", + required=False, + default=".rssVideos", + ) + parser.add( + "--max-duration", + help="Skip video longer than this amount of seconds", + env_var="RSS_VIDEOS_MAX_DURATION", + type=int, + default=0, + ) + parser.add( + "--format", + help="Use this format to download videos." + + " See FORMAT SELECTION in youtube-dl(1)", + env_var="RSS_VIDEOS_FORMAT", + default="bestvideo+bestaudio/best", + ) + parser.add( + "--subtitles", + help="Download all subtitles", + env_var="RSS_VIDEOS_SUBTITLES", + action="store_true", + ) args = parser.parse_args() args.videos = os.path.realpath(os.path.expanduser(args.videos)) @@ -50,54 +92,70 @@ if __name__ == "__main__": if not os.path.isabs(args.track): args.track = os.path.realpath(os.path.join(args.videos, args.track)) - os.makedirs(args.videos, exist_ok=True) - os.makedirs(args.track, exist_ok=True) + return args - # Read the feed XML, get the links - print("→ Retrieveing RSS feed") - links: Set[str] = set() +def get_links(args: configargparse.Namespace) -> Set[str]: + """ + Read the feed XML, get the links + """ + links = set() with urllib.request.urlopen(args.feed) as request: with minidom.parse(request) as xmldoc: - for item in xmldoc.getElementsByTagName('item'): + for item in xmldoc.getElementsByTagName("item"): try: - linkNode = item.getElementsByTagName('link')[0] + linkNode = item.getElementsByTagName("link")[0] link: str = linkNode.childNodes[0].data links.add(link) except BaseException as e: print("Error while getting link from item:", e) continue + return links - # Filter out non-video links and store video download info - # and associated filename - print(f"→ Getting infos on {len(links)} unread articles") - videosInfos: Dict[str, str] = {} +def get_video_infos( + args: configargparse.Namespace, ydl_opts: Dict, links: Set[str] +) -> Dict[str, Dict]: + """ + Filter out non-video links and store video download info + and associated filename + """ + videosInfos = dict() - ydl_opts = { - "simulate": True, - "quiet": True - } - with youtube_dl.YoutubeDL(ydl_opts) as ydl: + dry_ydl_opts = ydl_opts.copy() + dry_ydl_opts.update({"simulate": True, "quiet": True}) + with youtube_dl.YoutubeDL(dry_ydl_opts) as ydl: for link in links: print(f"Researching {link}...") try: infos = ydl.extract_info(link) + if args.max_duration > 0 and infos["duration"] > args.max_duration: + print( + f"{infos['title']}: Skipping as longer than max duration: " + f"{infos['duration']} > {args.max_duration}" + ) + continue filepath = ydl.prepare_filename(infos) filename, extension = os.path.splitext(filepath) videosInfos[filename] = infos + print(f"{infos['title']}: Added") + except BaseException as e: print(e) continue - # Read the directory content, delete everything that's not a - # video on the download list or already downloaded - print(f"→ Deciding on what to do for {len(videosInfos)} videos") + return videosInfos - # Getting information on the video directory - videosDownloaded: Set[str] = set() - videosPartiallyDownloaded: Set[str] = set() +def get_downloaded_videos( + args: configargparse.Namespace, videosInfos: Dict[str, Dict] +) -> Tuple[Set[str], Set[str]]: + videosDownloaded = set() + videosPartiallyDownloaded = set() + """ + Read the directory content, delete everything that's not a + video on the download list or already downloaded + """ for filepath in os.listdir(args.videos): fullpath = os.path.join(args.videos, filepath) @@ -106,12 +164,19 @@ if __name__ == "__main__": filename, extension = os.path.splitext(filepath) for onlineFilename in videosInfos.keys(): - # Full name already there: completly downloaded → remove from the download list + # Full name already there: completly downloaded + # → remove from the download list if filename == onlineFilename: videosDownloaded.add(onlineFilename) break - # Partial name already there: not completly downloaded → keep on the download list elif filename.startswith(onlineFilename): + # Subtitle file + # → ignore + if filename.endswith(".vtt"): + break + + # Partial name already there: not completly downloaded + # → keep on the download list videosPartiallyDownloaded.add(onlineFilename) break # Unrelated filename: delete @@ -119,10 +184,17 @@ if __name__ == "__main__": print(f"Deleting: {filename}") os.unlink(fullpath) - # Getting informations on the tracking directory + return videosDownloaded, videosPartiallyDownloaded - # Videos that were once downloaded using this tool - videosTracked: Set[str] = set() + +def get_tracked_videos(args: configargparse.Namespace, known: Set[str]) -> Set[str]: + """ + Return videos previously downloaded (=tracked) amongst the unread videos. + This is stored in the tracking directory as empty extension-less files. + Other tracking markers (e.g. for now read videos) are deleted. + """ + + videosTracked = set() for filepath in os.listdir(args.track): fullpath = os.path.join(args.track, filepath) @@ -130,18 +202,39 @@ if __name__ == "__main__": continue # Here filename is a filepath as no extension - if filepath in videosInfos: + if filepath in known: videosTracked.add(filepath) else: os.unlink(fullpath) + return videosTracked + + +def main() -> None: + + args = get_args() + + os.makedirs(args.videos, exist_ok=True) + os.makedirs(args.track, exist_ok=True) + ydl_opts = {"format": args.format, "allsubtitles": args.subtitles} + + print("→ Retrieveing RSS feed") + links = get_links(args) + + print(f"→ Getting infos on {len(links)} unread articles") + videosInfos = get_video_infos(args, ydl_opts, links) + + print(f"→ Deciding on what to do for {len(videosInfos)} videos") + videosDownloaded, videosPartiallyDownloaded = get_downloaded_videos( + args, videosInfos + ) + videosTracked = get_tracked_videos(args, set(videosInfos.keys())) + # Deciding for the rest based on the informations - - def markTracked(filename): + def markTracked(filename: str) -> None: markerPath = os.path.join(args.track, onlineFilename) - open(markerPath, 'a').close() - + open(markerPath, "a").close() videosToDownload: Set[str] = set() videosReads: Set[str] = set() @@ -169,11 +262,10 @@ if __name__ == "__main__": os.chdir(args.videos) + exit_code = 0 if not args.dryrun: # TODO Progressbar one day maybe? # We have all the info we need to make a reliable one - ydl_opts = { - } with youtube_dl.YoutubeDL(ydl_opts) as ydl: for onlineFilename in videosToDownload: infos = videosInfos[onlineFilename] @@ -183,6 +275,13 @@ if __name__ == "__main__": ydl.process_ie_result(infos, True, {}) markTracked(onlineFilename) - except: + except BaseException as e: + print(e) + exit_code = 1 continue + sys.exit(exit_code) + + +if __name__ == "__main__": + main() diff --git a/config/scripts/smtpdummy b/config/scripts/smtpdummy index 414520d..86f8b0d 100755 --- a/config/scripts/smtpdummy +++ b/config/scripts/smtpdummy @@ -1,43 +1,74 @@ #!/usr/bin/env python3 -import argparse +import base64 +import colorama +import configargparse import datetime -import time import email.utils -import subprocess +import io import pprint - - -def command(command: str) -> None: - cmd = command.encode() + b"\n" - subprocess.run(["xdotool", "type", "--file", "-"], input=cmd) - time.sleep(2) +import subprocess +import sys if __name__ == "__main__": - parser = argparse.ArgumentParser( + parser = configargparse.ArgParser( description="Generate SMTP messages to send a mail" ) now = datetime.datetime.now() now_email = email.utils.formatdate(now.timestamp(), True) - parser.add_argument("-s", "--sender", default="geoffrey@frogeye.fr") - parser.add_argument("-r", "--receiver", default="geoffrey@frogeye.fr") - parser.add_argument("-l", "--helo", default="frogeye.fr") + parser.add_argument("-o", "--origin", env_var="ORIGIN", default="localhost") parser.add_argument( - "-o", "--subject", default=f"Test message {now.strftime('%H:%M:%S')}" + "-d", "--destination", env_var="DESTINATION", default="localhost" + ) + parser.add_argument("-p", "--port", env_var="PORT", default=25) + parser.add_argument( + "-S", "--security", env_var="SECURITY", choices=["plain", "ssl", "starttls"], default='plain' ) - parser.add_argument("-m", "--me", default="Geoffrey") - parser.add_argument("-g", "--gtube", action="store_true") - parser.add_argument("-d", "--debug", action="store_true") - parser.add_argument("-b", "--body", default="") + parser.add_argument("-l", "--helo", env_var="HELO") + parser.add_argument( + "-s", "--sender", env_var="SENDER", default="geoffrey@frogeye.fr" + ) + parser.add_argument( + "-r", "--receiver", env_var="RECEIVER", default="geoffrey@frogeye.fr" + ) + # parser.add_argument("-a", "--auth", env_var="AUTH", default="PLAIN") + parser.add_argument("-u", "--user", env_var="MUSER") + parser.add_argument("-w", "--password", env_var="PASSWORD") + + parser.add_argument("-f", "--from", env_var="FROM") + parser.add_argument("-t", "--to", env_var="TO") + parser.add_argument( + "-j", + "--subject", + env_var="SUBJECT", + default=f"Test message {now.strftime('%H:%M:%S')}", + ) + + parser.add_argument("-b", "--body", env_var="BODY", default="") + parser.add_argument("-g", "--gtube", env_var="GTUBE", action="store_true") + parser.add_argument("-m", "--me", env_var="ME", default="Geoffrey") + + parser.add_argument("-y", "--dryrun", env_var="DRYRUN", action="store_true") + parser.add_argument("-q", "--quiet", env_var="QUIET", action="store_true") args = parser.parse_args() - if args.debug: - command = print + # Default values + if args.helo is None: + args.helo = args.origin + if getattr(args, "from") is None: + setattr(args, "from", args.sender) + if args.to is None: + args.to = args.receiver + if args.password: + password = args.password + args.password = '********' + + # Transmission content gtube = "" if args.gtube: @@ -49,11 +80,10 @@ XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X""" if args.body: body = f"\n\n{args.body}" - text = f"""Date: {now_email} -From: {args.sender} +From: {getattr(args, 'from')} Subject: {args.subject} -To: {args.receiver} +To: {args.to} Hello there, @@ -63,28 +93,96 @@ If you didn't expect to see this message, please contact {args.me}.{gtube}{body} Greetings, Input arguments: -{pprint.pformat(args, indent=4)} +{pprint.pformat(args.__dict__, indent=4)} -- {args.me} .""" - if not args.debug: - for i in range(3, 0, -1): - print(f"Typing mail in {i}…") - time.sleep(1) + # Transmission setup + cmd = ["ssh", args.origin] + if args.security == "plain": + cmd += ["socat", "-", f"tcp:{args.destination}:{args.port}"] + elif args.security == "ssl": + cmd += ["socat", "-", f"openssl:{args.destination}:{args.port}"] + elif args.security == "starttls": + cmd += [ + "openssl", + "s_client", + "-starttls", + "smtp", + "-crlf", + "-connect", + f"{args.destination}:{args.port}", + "-quiet", + ] - command(f"EHLO {args.helo}") - command(f"MAIL FROM: <{args.sender}>") - command(f"RCPT TO: <{args.receiver}>") - command("DATA") - command(text) - command("QUIT") + if not args.quiet: + print(colorama.Fore.MAGENTA + f"# {' '.join(cmd)}" + colorama.Fore.RESET) - print("Done") + if not args.dryrun: + p = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + ) + + def recv() -> None: + if args.dryrun: + return + + assert isinstance(p.stdout, io.BufferedReader) + next = True + while next: + line = p.stdout.readline() + code = int(line[:3]) + success = code < 400 + color = colorama.Fore.GREEN if success else colorama.Fore.RED + if not args.quiet: + print(color + f"< {line[:-1].decode()}" + colorama.Fore.RESET) + next = line[3] == b"-"[0] + if not next and not success: + send("QUIT") # TODO Can loop if QUIT fails + sys.exit(1) + + def send(command: str) -> None: + if not args.quiet: + print(colorama.Fore.BLUE + f"> {command}" + colorama.Fore.RESET) + + if args.dryrun: + return + + assert isinstance(p.stdin, io.BufferedWriter) + cmd = command.encode() + b"\n" + p.stdin.write(cmd) + p.stdin.flush() + + recv() + + # Transmission + + if args.security != 'starttls': + recv() + send(f"EHLO {args.helo}") + if args.user: + encoded = base64.b64encode( + args.user.encode() + + b"\x00" + + args.user.encode() + + b"\x00" + + password.encode() + ).decode() + send(f"AUTH PLAIN {encoded}") + send(f"MAIL FROM: <{args.sender}>") + send(f"RCPT TO: <{args.receiver}>") + send("DATA") + send(text) + send("QUIT") + sys.exit(0) # For reference: - # command("RSET") - # command("VRFY") - # command("NOOP") - # command("QUIT") + # send("RSET") + # send("VRFY") + # send("NOOP") + # send("QUIT") diff --git a/config/scripts/videoQuota b/config/scripts/videoQuota new file mode 100755 index 0000000..4c63016 --- /dev/null +++ b/config/scripts/videoQuota @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +import os +import sys +import subprocess +import logging + +import coloredlogs + +coloredlogs.install(level="DEBUG", fmt="%(levelname)s %(message)s") +log = logging.getLogger() + + +def duration_file(path: str) -> float: + cmd = [ + "ffprobe", + "-v", + "error", + "-show_entries", + "format=duration", + "-of", + "default=noprint_wrappers=1:nokey=1", + path, + ] + run = subprocess.run(cmd, stdout=subprocess.PIPE, check=True) + ret = run.stdout.decode().strip() + return float(ret) + + +# Constants +audio_br_bi = 128000 + +# TODO Arguments if you feel like it +quota_by = int(sys.argv[1]) +in_file = sys.argv[2] +out_file = sys.argv[3] + +quota_bi = quota_by * 8 +duration = duration_file(in_file) +tot_br_bi = quota_bi / duration +video_br_bi = int(tot_br_bi - audio_br_bi) +assert video_br_bi > 0, "Not even enough space for audio" + +cmd = [ + "ffmpeg", + "-i", + in_file, + "-b:v", + str(video_br_bi), + "-b:a", + str(audio_br_bi), + out_file, +] + +subprocess.run(cmd, check=True) diff --git a/config/scripts/wttr b/config/scripts/wttr index 0e795dc..f1b368c 100755 --- a/config/scripts/wttr +++ b/config/scripts/wttr @@ -1,7 +1,7 @@ #!/usr/bin/env bash # change Paris to your default location -request="v2.wttr.in/$1" +request="v2.wttr.in/${1-Amsterdam}" [ "$(tput cols)" -lt 125 ] && request+='?n' curl -H "Accept-Language: ${LANG%_*}" --compressed "$request" diff --git a/config/shell/commonrc b/config/shell/commonrc index 7fdf925..203042e 100644 --- a/config/shell/commonrc +++ b/config/shell/commonrc @@ -28,6 +28,28 @@ FZF_DEFAULT_OPTS="--height 40% --layout=default" FZF_CTRL_T_OPTS="--preview '[[ -d {} ]] && ls -l --color=always {} || [[ \$(file --mime {}) =~ binary ]] && file --brief {} || (highlight -O ansi -l {} || coderay {} || rougify {} || cat {}) 2> /dev/null | head -500'" FZF_COMPLETION_OPTS="${FZF_CTRL_T_OPTS}" +# Colored ls +_colored_ls() { + \ls -lh --color=always $@ | awk ' + BEGIN { + FPAT = "([[:space:]]*[^[:space:]]+)"; + OFS = ""; + } + { + $1 = "\033[36m" $1 "\033[0m"; + $2 = "\033[31m" $2 "\033[0m"; + $3 = "\033[32m" $3 "\033[0m"; + $4 = "\033[32m" $4 "\033[0m"; + $5 = "\033[31m" $5 "\033[0m"; + $6 = "\033[34m" $6 "\033[0m"; + $7 = "\033[34m" $7 "\033[0m"; + print + } + ' +} +alias ll="_colored_ls" +alias la="_colored_ls -a" + ## FUNCTIONS ## MISC diff --git a/config/shell/shenv b/config/shell/shenv index 7072c2c..dc4fc88 100644 --- a/config/shell/shenv +++ b/config/shell/shenv @@ -26,8 +26,8 @@ export JAVA_FONTS=/usr/share/fonts/TTF # 2019-04-25 Attempt to remove .java/font # Get out of my $HOME! export BOOT9_PATH="$HOME/.local/share/citra-emu/sysdata/boot9.bin" direnv CARGOHOME "$HOME/.cache/cargo" # There are config in there that we can version if one want -direnv CCACHE_BASEDIR "$HOME/.cache/ccache" export CCACHE_CONFIGPATH="$HOME/.config/ccache.conf" +direnv CCACHE_DIR "$HOME/.cache/ccache" # The config file alone seems to be not enough direnv DASHT_DOCSETS_DIR "$HOME/.cache/dash_docsets" direnv GNUPGHOME "$HOME/.config/gnupg" direnv GOPATH "$HOME/.cache/go" diff --git a/config/vim/pluginconfig.vim b/config/vim/pluginconfig.vim index 632b36c..fb598a8 100644 --- a/config/vim/pluginconfig.vim +++ b/config/vim/pluginconfig.vim @@ -1,12 +1,12 @@ """ ALE """ -nmap :ALEFix - -let g:ale_sign_error = '×' -let g:ale_sign_warning = '!' -let g:ale_completion_enabled = 1 -let g:ale_fixers = ['autopep8', 'shfmt', 'uncrustify', 'remove_trailing_lines', 'trim_whitespace', 'phpcbf'] -let g:ale_php_phpcs_standard = '/srv/http/machines/ruleset.xml' +" nmap :ALEFix +" +" let g:ale_sign_error = '×' +" let g:ale_sign_warning = '!' +" let g:ale_completion_enabled = 1 +" let g:ale_fixers = ['autopep8', 'shfmt', 'uncrustify', 'remove_trailing_lines', 'trim_whitespace', 'phpcbf'] +" let g:ale_php_phpcs_standard = '/srv/http/machines/ruleset.xml' " For PHP, install https://pear.php.net/package/PHP_CodeSniffer @@ -182,3 +182,6 @@ au FileType markdown vmap :EasyAlign* " SmoothScroll noremap :call smooth_scroll#up(20, 5, 1) noremap :call smooth_scroll#down(20, 5, 1) + +" gutentags +let g:gutentags_cache_dir = expand('~/.cache/vim/tags') diff --git a/config/vim/vimconfig.vim b/config/vim/vimconfig.vim index af2b4f2..a112035 100644 --- a/config/vim/vimconfig.vim +++ b/config/vim/vimconfig.vim @@ -82,3 +82,6 @@ nmap jjjjjjjjjjjjjjjjjjjjj " \s to replace globally the word under the cursor nnoremap s :%s/\<\>/ + +" add extensions to syntax +au BufNewFile,BufRead *.jinja set filetype=jinja2