Beispiel #1
0
 def __init__(self, key):
     self.youtube = apiclient.discovery.build(
         cache_discovery=False,
         developerKey=key,
         serviceName='youtube',
         version='v3',
     )
     self.log = vlogging.getLogger(__name__)
Beispiel #2
0
    def __init__(
        self,
        youtube,
        create=True,
        data_directory=None,
        log_level=vlogging.NOTSET,
        skip_version_check=False,
    ):
        super().__init__()
        self.youtube = youtube

        # DATA DIR PREP
        if data_directory is None:
            data_directory = constants.DEFAULT_DATADIR

        self.data_directory = pathclass.Path(data_directory)

        if self.data_directory.exists and not self.data_directory.is_dir:
            raise exceptions.BadDataDirectory(
                self.data_directory.absolute_path)

        # LOGGING
        self.log = vlogging.getLogger(
            f'{__name__}:{self.data_directory.absolute_path}')
        self.log.setLevel(log_level)
        self.youtube.log.setLevel(log_level)

        # DATABASE
        self.database_filepath = self.data_directory.with_child(
            constants.DEFAULT_DBNAME)
        existing_database = self.database_filepath.exists
        if not existing_database and not create:
            msg = f'"{self.database_filepath.absolute_path}" does not exist and create is off.'
            raise FileNotFoundError(msg)

        self.data_directory.makedirs(exist_ok=True)
        self.sql = sqlite3.connect(self.database_filepath.absolute_path)

        if existing_database:
            if not skip_version_check:
                self._check_version()
            self._load_pragmas()
        else:
            self._first_time_setup()

        # CONFIG
        self.config_filepath = self.data_directory.with_child(
            constants.DEFAULT_CONFIGNAME)
        self.load_config()

        self.caches = {
            'channel': cacheclass.Cache(maxlen=20_000),
            'video': cacheclass.Cache(maxlen=50_000),
        }
Beispiel #3
0
import argparse
import sys

from voussoirkit import pipeable
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'printstdout')


def printstdout_argparse(args):
    for text in args.texts:
        text = pipeable.input(text)
        for line in text:
            pipeable.stdout(line)


def main(argv):
    argv = vlogging.main_level_by_argv(argv)

    parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument('texts', nargs='+')
    parser.set_defaults(func=printstdout_argparse)

    args = parser.parse_args(argv)
    return args.func(args)


if __name__ == '__main__':
    raise SystemExit(main(sys.argv[1:]))
Beispiel #4
0
import argparse
import logging
import requests
import sqlite3
import sys
import time

from voussoirkit import backoff
from voussoirkit import betterhelp
from voussoirkit import ratelimiter
from voussoirkit import sqlhelpers
from voussoirkit import threadpool
from voussoirkit import vlogging

log = vlogging.getLogger('hnarchive')

VERSION = 1

HEADERS = {
    'User-Agent': f'voussoir/hnarchive v{VERSION}.',
}

DB_INIT = '''
PRAGMA user_version = 1;
CREATE TABLE IF NOT EXISTS items(
    id INT PRIMARY KEY NOT NULL,
    deleted INT,
    type TEXT,
    author TEXT,
    time INT,
    text TEXT,
Beispiel #5
0
import shutil
import subprocess
import sys
import time
import traceback

from voussoirkit import betterhelp
from voussoirkit import bytestring
from voussoirkit import operatornotify
from voussoirkit import pathclass
from voussoirkit import subproctools
from voussoirkit import vlogging
from voussoirkit import winglob
from voussoirkit import winwhich

log = vlogging.getLogger(__name__, 'rarpar')

WINRAR = winwhich.which('winrar')
PAR2 = winwhich.which('phpar2')

RESERVE_SPACE_ON_DRIVE = 5 * bytestring.GIBIBYTE

COMPRESSION_STORE = 0
COMPRESSION_MAX = 5


class RarParException(Exception):
    pass


class RarExists(RarParException):
Beispiel #6
0
    A string like "50g" or "100 gb"

drive:
    Filepath to the drive you want to check. Defaults to cwd drive.
'''
import argparse
import os
import shutil
import sys

from voussoirkit import betterhelp
from voussoirkit import bytestring
from voussoirkit import dotdict
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'reserve_disk_space')


class NotEnoughSpace(Exception):
    def __init__(self, free, reserve, drive):
        self.free = free
        self.reserve = reserve
        self.drive = drive


def reserve_disk_space(reserve, drive):
    drive = drive.replace('\\', os.sep).replace('/', os.sep)
    drive = os.path.abspath(drive)
    drive = os.path.splitdrive(drive)[0]

    log.debug('Checking drive %s', drive)
Beispiel #7
0
    See voussoirkit.operatornotify.py for details.
'''
import argparse
import bs4
import requests
import sys
import time

from voussoirkit import backoff
from voussoirkit import betterhelp
from voussoirkit import downloady
from voussoirkit import operatornotify
from voussoirkit import pathclass
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'fdroidapk')

session = requests.Session()


def get_apk_url(package_name):
    url = f'https://f-droid.org/en/packages/{package_name}'
    log.debug('Downloading page %s', url)
    response = session.get(url, timeout=30)
    response.raise_for_status()
    soup = bs4.BeautifulSoup(response.text, 'html.parser')
    li = soup.find('li', {'class': 'package-version'})
    aa = li.find_all('a')
    aa = [a for a in aa if a.get('href', '').endswith('.apk')]
    apk_url = aa[0]['href']
    return apk_url
Beispiel #8
0
import os
import praw3 as praw
import requests
import sqlite3
import string
import sys
import time
import traceback

from voussoirkit import operatornotify
from voussoirkit import httperrors
httperrors.monkeypatch_requests()
from voussoirkit import sqlhelpers
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'newsletterly')

####################################################################################################
# CONFIGURATION ####################################################################################


# https://www.reddit.com/comments/3cm1p8/how_to_make_your_bot_use_oauth2/
import newsletterly_credentials
# Username is not used for login purposes, just message text
SELF_USERNAME = newsletterly_credentials.USERNAME
USERAGENT = newsletterly_credentials.USERAGENT
APP_ID = newsletterly_credentials.APP_ID
APP_SECRET = newsletterly_credentials.APP_SECRET
APP_URI = newsletterly_credentials.APP_URI
APP_REFRESH = newsletterly_credentials.APP_REFRESH
Beispiel #9
0
import PIL.Image
import argparse
import sys

from voussoirkit import pipeable
from voussoirkit import sentinel
from voussoirkit import vlogging
from voussoirkit import winglob

log = vlogging.getLogger(__name__, 'stitch')

VERTICAL = sentinel.Sentinel('vertical')
HORIZONTAL = sentinel.Sentinel('horizontal')


def stitch_argparse(args):
    patterns = pipeable.input_many(args.image_files,
                                   skip_blank=True,
                                   strip=True)
    files = [file for pattern in patterns for file in winglob.glob(pattern)]
    images = [PIL.Image.open(file) for file in files]
    if args.vertical:
        direction = VERTICAL
    else:
        direction = HORIZONTAL

    gapcount = len(images) - 1

    if direction is HORIZONTAL:
        width = sum(i.size[0] for i in images) + (gapcount * args.gap)
        height = max(i.size[1] for i in images)
Beispiel #10
0
import argparse
import datetime
import gzip
import PIL.Image
import random
import requests
import sqlite3
import sys
import time

from voussoirkit import threadpool
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'pixelcanvasdl')
vlogging.getLogger('urllib3.connectionpool').setLevel(vlogging.CRITICAL)

WHITE = (255, 255, 255)
LIGHTGRAY = (228, 228, 228)
DARKGRAY = (136, 136, 136)
BLACK = (34, 34, 34)
PINK = (255, 167, 209)
RED = (229, 0, 0)
ORANGE = (229, 149, 0)
BROWN = (160, 106, 66)
YELLOW = (229, 217, 0)
LIGHTGREEN = (148, 224, 68)
DARKGREEN = (2, 190, 1)
LIGHTBLUE = (0, 211, 221)
MEDIUMBLUE = (0, 131, 199)
DARKBLUE = (0, 0, 234)
LIGHTPURPLE = (207, 110, 228)
Beispiel #11
0
import sys
import time

from voussoirkit import backoff
from voussoirkit import betterhelp
from voussoirkit import httperrors
from voussoirkit import mutables
from voussoirkit import operatornotify
from voussoirkit import pathclass
from voussoirkit import ratelimiter
from voussoirkit import sqlhelpers
from voussoirkit import threadpool
from voussoirkit import treeclass
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'hnarchive')

VERSION = '1.0.0'

HEADERS = {
    'User-Agent': f'voussoir/hnarchive v{VERSION}.',
}

session = requests.Session()
session.headers.update(HEADERS)

DB_INIT = '''
BEGIN;
PRAGMA user_version = 1;
CREATE TABLE IF NOT EXISTS items(
    id INT PRIMARY KEY NOT NULL,
Beispiel #12
0
import argparse
import collections
import os
import shutil
import sys

from voussoirkit import passwordy
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import spinal
from voussoirkit import vlogging
from voussoirkit import winglob

log = vlogging.getLogger(__name__, 'sole_subdir_lift')

def sole_lift_argparse(args):
    starting = pathclass.Path(args.starting)
    queue = collections.deque()
    queue.extend(spinal.walk(starting, yield_files=False, yield_directories=True))
    while len(queue) > 0:
        directory = queue.popleft()

        if not directory.exists:
            log.debug('%s no longer exists.', directory)
            continue

        if directory not in starting:
            log.debug('%s is outside of starting.', directory)
            continue

        children = directory.listdir()
Beispiel #13
0
import argparse
import codecs
import os
import pyperclip
import re
import sys

from voussoirkit import interactive
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import spinal
from voussoirkit import vlogging
from voussoirkit import winglob

log = vlogging.getLogger(__name__, 'contentreplace')


def contentreplace(file,
                   replace_from,
                   replace_to,
                   autoyes=False,
                   do_regex=False):
    file = pathclass.Path(file)
    with file.open('r', encoding='utf-8') as f:
        content = f.read()

    if do_regex:
        occurances = len(re.findall(replace_from, content, flags=re.MULTILINE))
    else:
        occurances = content.count(replace_from)
Beispiel #14
0
import argparse
import os
import re
import sys

from voussoirkit import interactive
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import vlogging
from voussoirkit import winglob

log = vlogging.getLogger(__name__, 'adbinstall')


def natural_sorter(x):
    '''
    Used for sorting files in 'natural' order instead of lexicographic order,
    so that you get 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
    instead of 1 10 11 12 13 2 3 4 5 ...
    Thank you Mark Byers
    http://stackoverflow.com/a/11150413
    '''
    convert = lambda text: int(text) if text.isdigit() else text.lower()
    alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
    return alphanum_key(x)


def adbinstall_argparse(args):
    patterns = pipeable.input_many(args.apks, skip_blank=True, strip=True)
    apks = [file for pattern in patterns for file in winglob.glob(pattern)]
    installs = []
Beispiel #15
0
import argparse
import flask; from flask import request
import os
import pyperclip
import sys

from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'heresmyclipboard')

site = flask.Flask(__name__)

TEMPLATE = '''
<html>
<body>
<pre>
{{clip}}
</pre>
</body>
</html>
'''

@site.route('/')
def root():
    clip = pyperclip.paste()
    return flask.render_template_string(TEMPLATE, clip=clip)

def heresmyclipboard_argparse(args):
    log.info(f'Starting server on port {args.port}, pid={os.getpid()}')
    site.run(host='0.0.0.0', port=args.port)
Beispiel #16
0
import argparse
import re
import subprocess
import sys

from voussoirkit import pathclass
from voussoirkit import winglob
from voussoirkit import winwhich
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'ffstreams')

AUDIO_EXTENSIONS = {
    'aac': 'm4a',
    'ac3': 'ac3',
    'flac': 'flac',
    'mp3': 'mp3',
    'opus': 'opus',
    'vorbis': 'ogg',
    '*': 'mka',
}

SUBTITLE_EXTENSIONS = {
    'ass': 'ass',
    'subrip': 'srt',
    '*': 'mks',
}

FFMPEG = winwhich.which('ffmpeg')

def make_maps(input_file, prefix, search_pattern, extension_map, moveto=None):
Beispiel #17
0
import bs4
import requests

from voussoirkit import vlogging

from . import exceptions

log = vlogging.getLogger(__name__)

session = requests.Session()

def _get_user_videos(channel_id):
    log.info(f'Fetching RSS for {channel_id}.')
    url = f'https://www.youtube.com/feeds/videos.xml?channel_id={channel_id}'
    response = session.get(url)
    response.raise_for_status()
    soup = bs4.BeautifulSoup(response.text, 'lxml')
    # find_all does not work on namespaced tags unless you add a limit paramter.
    video_ids = [v.text for v in soup.find_all('yt:videoid', limit=9999)]
    log.loud('RSS got %s.', video_ids)
    return video_ids

def get_user_videos(channel_id):
    try:
        return _get_user_videos(channel_id)
    except Exception:
        raise exceptions.RSSAssistFailed(f'Failed to fetch RSS videos.') from exc

def get_user_videos_since(channel_id, video_id):
    video_ids = get_user_videos(channel_id)
    try:
Beispiel #18
0
> bitwise_or file1 file2 --output file3
'''
import argparse
import os
import sys

from voussoirkit import betterhelp
from voussoirkit import interactive
from voussoirkit import operatornotify
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import vlogging
from voussoirkit import winglob

log = vlogging.getLogger(__name__, 'bitwise_or')

CHUNK_SIZE = 2**20


def bitwise_or_argparse(args):
    patterns = pipeable.input_many(args.files, skip_blank=True, strip=True)
    files = [file for pattern in patterns for file in winglob.glob(pattern)]
    files = [pathclass.Path(file) for file in files]

    if len(files) < 2:
        log.fatal('Need at least two input files.')
        return 1

    handles = [file.open('rb') for file in files]
Beispiel #19
0
import subprocess
import sys
import time
import tkinter
import traceback
import types

from voussoirkit import betterhelp
from voussoirkit import mutables
from voussoirkit import operatornotify
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import sqlhelpers
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'sb')

USERAGENT = '''
/u/GoldenSights SubredditBirthdays data collection:
Gathering the creation dates of subreddits for visualization.
More at https://github.com/voussoir/reddit/tree/master/SubredditBirthdays
'''.replace('\n', ' ').strip()

LOWERBOUND_STR = '2qh0j'
LOWERBOUND_INT = 4594339

FORMAT_MEMBER = '{idstr:>5s}, {human}, {nsfw}, {name:<25s} {subscribers:>10,}'
FORMAT_MESSAGE_NEW = 'New: {idstr:>5s} : {human} : {nsfw} : {name} : {subscribers}'
FORMAT_MESSAGE_UPDATE = 'Upd: {idstr:>5s} : {human} : {nsfw} : {name} : {subscribers} ({subscriber_diff})'

RANKS_UP_TO = 20000
Beispiel #20
0
import argparse
import sys

from voussoirkit import pipeable
from voussoirkit import vlogging

log = vlogging.getLogger(__name__, 'printstderr')

def printstderr_argparse(args):
    for text in args.texts:
        text = pipeable.input(text)
        for line in text:
            pipeable.stderr(line)

def main(argv):
    argv = vlogging.main_level_by_argv(argv)

    parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument('texts', nargs='+')
    parser.set_defaults(func=printstderr_argparse)

    args = parser.parse_args(argv)
    return args.func(args)

if __name__ == '__main__':
    raise SystemExit(main(sys.argv[1:]))