master
Ethan Dalool 2016-11-17 22:24:52 -08:00
parent 15c9e1fcfd
commit b0187f3269
14 changed files with 405 additions and 10 deletions

View File

@ -3,8 +3,18 @@ Open Dir DL
The open directory downloader. The open directory downloader.
## Installation
pip install requirements.txt
## Usage
See inside opendirdl.py for usage instructions. See inside opendirdl.py for usage instructions.
 
### Changelog
- **[addition]** A new feature was added. - **[addition]** A new feature was added.
- **[bugfix]** Incorrect behavior was fixed. - **[bugfix]** Incorrect behavior was fixed.
- **[change]** An existing feature was slightly modified or parameters were renamed. - **[change]** An existing feature was slightly modified or parameters were renamed.
@ -33,7 +43,7 @@ See inside opendirdl.py for usage instructions.
- 2016 08 10 - 2016 08 10
- **[addition]** Added clickable links to each directory on HTML tree pages. - **[addition]** Added clickable links to each directory on HTML tree pages.
- **[bugfix]** Fixed bug in smart_insert caused by 404's being considered falsey, triggering the 'one and only one' exception. - **[bugfix]** Fixed bug in smart_insert caused by 404's being considered falsey, triggering the 'one and only one' exception.
- **[bugfix]** Fixed bug in smart_insert where 404'd URLs were not being dele`ted from the database. - **[bugfix]** Fixed bug in smart_insert where 404'd URLs were not being deleted from the database.
- 2016 08 02 - 2016 08 02
- **[cleanup]** Removed the need for div IDs on the Tree pages by making the collapse button use `this.nextSibling`. - **[cleanup]** Removed the need for div IDs on the Tree pages by making the collapse button use `this.nextSibling`.
@ -52,7 +62,7 @@ See inside opendirdl.py for usage instructions.
- 2016 07 25 - 2016 07 25
- **[change]** Bytespersecond is now parsed by `bytestring.parsebytes` rather than `eval`, so you can write "100k" as opposed to "100 * 1024" etc. - **[change]** Bytespersecond is now parsed by `bytestring.parsebytes` rather than `eval`, so you can write "100k" as opposed to "100 * 1024" etc.
- **[removal]** Removed the `Downloader` class after watching [this Jack Diederich talk](https://youtu.be/o9pEzgHorH0) about unecessary classes. - **[removal]** Removed the `Downloader` class and replaced it with a function, because it only had one real method anyway.
- 2016 07 19 - 2016 07 19
- **[addition]** Gave the HTML tree divs a very gentle shadow and alternating colors to help with depth perception. - **[addition]** Gave the HTML tree divs a very gentle shadow and alternating colors to help with depth perception.

View File

@ -1,4 +1,4 @@
import bytestring from voussoirkit import bytestring
import downloady import downloady
import ratemeter import ratemeter
import requests import requests

View File

@ -233,7 +233,7 @@ def colorama_print(text):
alternator = False alternator = False
terminal_size = shutil.get_terminal_size()[0] terminal_size = shutil.get_terminal_size()[0]
for line in text.split('\n'): for line in text.split('\n'):
line += ' ' * (terminal_size - (len(line)+1)) line = line.ljust(terminal_size, ' ')
if HAS_COLORAMA: if HAS_COLORAMA:
if alternator: if alternator:
sys.stdout.write(colorama.Fore.BLACK) sys.stdout.write(colorama.Fore.BLACK)
@ -242,7 +242,8 @@ def colorama_print(text):
sys.stdout.write(colorama.Fore.WHITE) sys.stdout.write(colorama.Fore.WHITE)
sys.stdout.write(colorama.Back.BLACK) sys.stdout.write(colorama.Back.BLACK)
alternator = not alternator alternator = not alternator
print(line) # \r because the ljust puts us on the next line, no need for \n
print(line, end='\r', flush=True)
if HAS_COLORAMA: if HAS_COLORAMA:
sys.stdout.write(colorama.Back.RESET) sys.stdout.write(colorama.Back.RESET)
sys.stdout.write(colorama.Fore.RESET) sys.stdout.write(colorama.Fore.RESET)
@ -274,11 +275,20 @@ def multi_line_input():
return userinput.strip() return userinput.strip()
def nicewrap(message, width, paddingleft): def nicewrap(message, width, paddingleft):
# http://stackoverflow.com/a/26538082 ########################## # http://stackoverflow.com/a/26538082
message = '\n'.join(['\n'.join(textwrap.wrap(line, width,####### message = message.split('\n')
break_long_words=True, replace_whitespace=False))########## message = [
for line in message.split('\n')])########################## textwrap.wrap(
################################################################ line,
width,
break_long_words=True,
replace_whitespace=False,
)
for line in message
]
message = ['\n'.join(line) for line in message]
message = '\n'.join(message)
message = message.strip() message = message.strip()
message = message.replace('\n', '\n' + (' '*paddingleft)) message = message.replace('\n', '\n' + (' '*paddingleft))
return message return message

49
Toolbox/bitrate_chart.py Normal file
View File

@ -0,0 +1,49 @@
'''
bitrate | 01 | 1:00 | 30:00 | 1:00:00 | 1:30:00 | 2:00:00
-: | -: | -: | -: | -: | -: | -:
128 kbps | 16.000 KiB | 960.000 KiB | 28.125 MiB | 56.250 MiB | 84.375 MiB | 112.500 MiB
256 kbps | 32.000 KiB | 1.875 MiB | 56.250 MiB | 112.500 MiB | 168.750 MiB | 225.000 MiB
320 kbps | 40.000 KiB | 2.344 MiB | 70.312 MiB | 140.625 MiB | 210.938 MiB | 281.250 MiB
500 kbps | 62.500 KiB | 3.662 MiB | 109.863 MiB | 219.727 MiB | 329.590 MiB | 439.453 MiB
640 kbps | 80.000 KiB | 4.688 MiB | 140.625 MiB | 281.250 MiB | 421.875 MiB | 562.500 MiB
738 kbps | 92.250 KiB | 5.405 MiB | 162.158 MiB | 324.316 MiB | 486.475 MiB | 648.633 MiB
1024 kbps | 128.000 KiB | 7.500 MiB | 225.000 MiB | 450.000 MiB | 675.000 MiB | 900.000 MiB
2048 kbps | 256.000 KiB | 15.000 MiB | 450.000 MiB | 900.000 MiB | 1.318 GiB | 1.758 GiB
2330 kbps | 291.271 KiB | 17.067 MiB | 512.000 MiB | 1.000 GiB | 1.500 GiB | 2.000 GiB
3072 kbps | 384.000 KiB | 22.500 MiB | 675.000 MiB | 1.318 GiB | 1.978 GiB | 2.637 GiB
4096 kbps | 512.000 KiB | 30.000 MiB | 900.000 MiB | 1.758 GiB | 2.637 GiB | 3.516 GiB
4660 kbps | 582.543 KiB | 34.133 MiB | 1.000 GiB | 2.000 GiB | 3.000 GiB | 4.000 GiB
6144 kbps | 768.000 KiB | 45.000 MiB | 1.318 GiB | 2.637 GiB | 3.955 GiB | 5.273 GiB
8192 kbps | 1.000 MiB | 60.000 MiB | 1.758 GiB | 3.516 GiB | 5.273 GiB | 7.031 GiB
12288 kbps | 1.500 MiB | 90.000 MiB | 2.637 GiB | 5.273 GiB | 7.910 GiB | 10.547 GiB
16384 kbps | 2.000 MiB | 120.000 MiB | 3.516 GiB | 7.031 GiB | 10.547 GiB | 14.062 GiB
'''
import sys
sys.path.append('C:\\git\\else\\bytestring')
import bytestring
import kbps
times = ['01', '1:00', '30:00', '1:00:00', '1:30:00', '2:00:00']
rates = [128, 256, 320, 500, 640, 738, 1024, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 2330.17, 4660.34]
times.sort(key=lambda x: kbps.hms_s(x))
rates.sort()
table = []
table.append('bitrate | ' + ' | '.join(times))
table.append('-: | ' * (len(times)+1))
for r in rates:
l = []
l.append('%d kbps' % r)
for t in times:
l.append(bytestring.bytestring(kbps.calc(kbps.hms_s(t), r)))
l = ' | '.join(l)
table.append(l)
#print('\n'.join(table))
columns = [[b.strip() for b in a] for a in zip(*[x.split('|') for x in table])]
for (index, column) in enumerate(columns):
width = max((len(x) for x in column))
columns[index] = [x.rjust(width, ' ') for x in column]
table = [' | '.join(a) for a in zip(*columns)]
#print(columns)
print('\n'.join(table))

12
Toolbox/clipboard.py Normal file
View File

@ -0,0 +1,12 @@
import pyperclip
import sys
if len(sys.argv) > 1:
sys.path.append('C:\\git\\else\\Clipext'); import clipext
stuff = clipext.resolve(sys.argv[1])
pyperclip.copy(stuff)
else:
text = pyperclip.paste()
text = text.replace('\r', '')
print(text)

35
Toolbox/contentreplace.py Normal file
View File

@ -0,0 +1,35 @@
import codecs
import sys
filename = sys.argv[1]
replace_from = sys.argv[2]
replace_to = sys.argv[3]
try:
automatic = sys.argv[4] == '-y'
except IndexError:
automatic = False
replace_from = codecs.decode(replace_from, 'unicode_escape')
replace_to = codecs.decode(replace_to, 'unicode_escape')
f = open(filename, 'r', encoding='utf-8')
with f:
content = f.read()
occurances = content.count(replace_from)
if occurances == 0:
print('No occurances')
exit()
print('Found %d occurances.' % occurances)
if automatic:
permission = 'y'
else:
permission = input('Replace? ')
if permission.lower() not in ['y', 'yes']:
exit()
content = content.replace(replace_from, replace_to)
f = open(filename, 'w', encoding='utf-8')
with f:
f.write(content)

43
Toolbox/ffrename.py Normal file
View File

@ -0,0 +1,43 @@
import converter
import os
import re
import subprocess
import sys
import time
def main(filename):
assert os.path.isfile(filename)
ffmpeg = converter.Converter()
probe = ffmpeg.probe(filename)
new_name = filename
if '_x_' in filename:
dimensions = '%dx%d' % (probe.video.video_width, probe.video.video_height)
new_name = new_name.replace('_x_', dimensions)
if '___' in filename:
video_codec = probe.video.codec
audios = [stream for stream in probe.streams if stream.type == 'audio']
audio = max(audios, key=lambda x: x.bitrate)
audio_codec = probe.audio.codec
if any(not x for x in [video_codec, probe.video.bitrate, audio_codec, probe.audio.bitrate]):
print('Could not identify media info')
else:
video_bitrate = probe.video.bitrate // 1000
audio_bitrate = probe.audio.bitrate // 1000
video = '%s-%d' % (video_codec, video_bitrate)
audio = '%s-%d' % (audio_codec, audio_bitrate)
video = video.upper()
audio = audio.upper()
video = video.replace('H264', 'h264')
video = video.replace('HEVC', 'h265')
info = '{v}, {a}'.format(v=video, a=audio)
new_name = new_name.replace('___', info)
print(new_name)
if input('Okay?').lower() in ['y', 'yes']:
os.rename(filename, new_name)
if __name__ == '__main__':
main(sys.argv[1])

37
Toolbox/filepull.py Normal file
View File

@ -0,0 +1,37 @@
import os
import sys
sys.path.append('C:\\git\\else\\spinaltap')
import spinal
def main():
files = list(spinal.walk_generator())
cwd = os.getcwd()
files = [f for f in files if os.path.split(f.absolute_path)[0] != cwd]
if len(files) == 0:
print('No files to move')
return
duplicate_count = {}
for f in files:
basename = f.basename
duplicate_count.setdefault(basename, [])
duplicate_count[basename].append(f.absolute_path)
duplicates = ['\n'.join(sorted(copies)) for (basename, copies) in duplicate_count.items() if len(copies) > 1]
duplicates = sorted(duplicates)
if len(duplicates) > 0:
raise Exception('duplicate names:\n' + '\n'.join(duplicates))
for f in files:
print(f.basename)
print('Move %d files?' % len(files))
if input('> ').lower() in ['y', 'yes']:
for f in files:
local = os.path.join('.', f.basename)
os.rename(f.absolute_path, local)
if __name__ == '__main__':
main()

27
Toolbox/fileswith.py Normal file
View File

@ -0,0 +1,27 @@
import fnmatch
import glob
import re
import sys
sys.path.append('C:\\git\\else\\spinaltap'); import spinal
filepattern = sys.argv[1]
searchpattern = sys.argv[2]
for filename in spinal.walk_generator():
filename = filename.absolute_path
if not fnmatch.fnmatch(filename, filepattern):
continue
matches = []
handle = open(filename, 'r', encoding='utf-8')
try:
with handle:
for (index, line) in enumerate(handle):
if re.search(searchpattern, line, flags=re.IGNORECASE):
line = '%d | %s' % (index, line.strip())
matches.append(line)
except:
pass
if matches:
print(filename)
print('\n'.join(matches))
print()

32
Toolbox/kbps.py Normal file
View File

@ -0,0 +1,32 @@
import sys
try:
sys.path.append('C:\\git\\else\\Bytestring')
import bytestring
except ImportError:
# pip install
# https://raw.githubusercontent.com/voussoir/else/master/_voussoirkit/voussoirkit.zip
from vousoirkit import bytestring
def hms_s(hms):
hms = hms.split(':')
seconds = 0
if len(hms) == 3:
seconds += int(hms[0])*3600
hms.pop(0)
if len(hms) == 2:
seconds += int(hms[0])*60
hms.pop(0)
if len(hms) == 1:
seconds += int(hms[0])
return seconds
def calc(seconds, kbps):
final_kilobits = kbps * seconds
final_bytes = final_kilobits * 128
return final_bytes
if __name__ == '__main__':
length = sys.argv[1] # HH:MM:SS
kbps = int(sys.argv[2])
seconds = hms_s(length)
print(bytestring.bytestring(calc(seconds, kbps)))

35
Toolbox/kbpsr.py Normal file
View File

@ -0,0 +1,35 @@
import sys
try:
sys.path.append('C:\\git\\else\\Bytestring')
import bytestring
except ImportError:
# pip install
# https://raw.githubusercontent.com/voussoir/else/master/_voussoirkit/voussoirkit.zip
from vousoirkit import bytestring
def hms_s(hms):
hms = hms.split(':')
seconds = 0
if len(hms) == 3:
seconds += int(hms[0])*3600
hms.pop(0)
if len(hms) == 2:
seconds += int(hms[0])*60
hms.pop(0)
if len(hms) == 1:
seconds += int(hms[0])
return seconds
def calc(seconds, goal_bytes):
goal_kibs = goal_bytes / 1024
goal_kilobits = goal_kibs * 8
goal_kbps = goal_kilobits / seconds
goal_kbps = round(goal_kbps, 2)
return goal_kbps
if __name__ == '__main__':
length = sys.argv[1] # HH:MM:SS
goal_bytes = bytestring.parsebytes(sys.argv[2])
seconds = hms_s(length)
print(calc(seconds, goal_bytes), 'kbps')

46
Toolbox/randomfile.py Normal file
View File

@ -0,0 +1,46 @@
import math
import random
import sys
import bytestring
CHUNK_SIZE = 512 * (2 ** 10)
def listget(li, index, fallback=None):
try:
return li[index]
except IndexError:
return fallback
def rid(length=8):
import random
bits = length * 4
bits = random.getrandbits(bits)
identifier = '{:02x}'.format(bits).rjust(length, '0')
return identifier
def make_randomfile(length, filename=None):
if filename is None:
filename = rid(8) + '.txt'
chunks = math.ceil(length / CHUNK_SIZE)
written = 0
f = open(filename, 'w')
for x in range(chunks):
b = min(CHUNK_SIZE, length-written)
f.write(rid(b))
written += b
f.close()
print('Created %s' % filename)
bytes = listget(sys.argv, 1, None)
if bytes is None:
bytes = 2 ** 10
else:
bytes = bytestring.parsebytes(bytes)
filecount = 1
filename = listget(sys.argv, 2, None)
if filename is not None and filename.isdigit():
filecount = int(filename)
filename = None
for x in range(filecount):
make_randomfile(bytes, filename)

44
Toolbox/rejpg.py Normal file
View File

@ -0,0 +1,44 @@
from voussoirkit import bytestring
import io
import os
import PIL.Image
import PIL.ImageFile
import string
import sys
PIL.ImageFile.LOAD_TRUNCATED_IMAGES = True
if '/r' in sys.argv:
sys.path.append('C:\\git\\else\\spinaltap')
import spinal
walker = spinal.walk_generator()
files = list(walker)
files = [f.absolute_path for f in files]
else:
files = os.listdir()
files = [f for f in files if os.path.isfile(f)]
files = [f for f in files if any(ext in f.lower() for ext in ['.jpg', '.jpeg'])]
bytes_saved = 0
remaining_size = 0
for filename in files:
print(''.join(c for c in filename if c in string.printable))
bytesio = io.BytesIO()
i = PIL.Image.open(filename)
i.save(bytesio, format='jpeg', quality=80)
bytesio.seek(0)
new_bytes = bytesio.read()
old_size = os.path.getsize(filename)
new_size = len(new_bytes)
remaining_size += new_size
if new_size < old_size:
bytes_saved += (old_size - new_size)
f = open(filename, 'wb')
f.write(new_bytes)
f.close()
print('Saved', bytestring.bytestring(bytes_saved))
print('Remaining are', bytestring.bytestring(remaining_size))

15
Toolbox/touch.py Normal file
View File

@ -0,0 +1,15 @@
import glob
import os
import sys
glob_patterns = sys.argv[1:]
for glob_pattern in glob_patterns:
filenames = glob.glob(glob_pattern)
if len(filenames) == 0:
print(glob_pattern)
open(glob_pattern, 'a').close()
else:
for filename in filenames:
print(filename)
os.utime(filename)