Skip to content
Create a gist now

Instantly share code, notes, and snippets.

anonymous /dump.py secret
Created

  1. @invalid-email-address Anonymous created this gist .
    View
    211 dump.py
    @@ -0,0 +1,211 @@
    +# -*- coding: utf-8 -*-
    +from string import ascii_letters, digits
    +from warnings import filterwarnings
    +from random import randint, choice
    +from pprint import pprint
    +from time import sleep
    +import webbrowser
    +import argparse
    +import requests
    +import json
    +import sys
    +import os
    +import re
    +
    +py3 = sys.version_info[0] > 2
    +filterwarnings('ignore')
    +
    +
    +def chunks(l, n):
    + """Yield successive n-sized chunks from l."""
    + for i in range(0, len(l), n):
    + yield l[i:i+n]
    +# https://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python/312464#312464
    +
    +
    +def natural_sort(l):
    + 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 sorted(l, key=alphanum_key)
    +# https://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort/4836734#4836734
    +
    +
    +def has_numbers(input_string):
    + return any(char.isdigit() for char in input_string)
    +# https://stackoverflow.com/questions/19859282/check-if-a-string-contains-a-number/19859308#19859308
    +
    +
    +def is_installed(module):
    + try:
    + __import__(module)
    + except ImportError:
    + return False
    + return True
    +
    +
    +def fetch_captcha():
    + r = requests.get('https://8ch.net/8chan-captcha/entrypoint.php?mode=get&extra=abcdefghijklmnopqrstuvwxyz&nojs=true')
    + try:
    + match = 'CAPTCHA ID: [a-z]*'
    + captcha_cookie = re.search(match, r.text).group().split(': ')[1]
    + match = '<image src="data:image/png;base64,[A-Za-z0-9+/=]*">'
    + with open('captcha_image.png', 'wb') as f:
    + f.write(re.search(match, r.text).group().split(',')[1].strip('>').strip('"').decode('base64'))
    + webbrowser.open('captcha_image.png')
    + if py3:
    + captcha_text = input('Enter the captcha: ')
    + else:
    + captcha_text = raw_input('Enter the captcha: ')
    + os.remove('captcha_image.png')
    + data['captcha_cookie'] = captcha_cookie
    + data['captcha_text'] = captcha_text
    + except AttributeError:
    + print('Server error while fetching captcha')
    + pass
    +
    +
    +parser = argparse.ArgumentParser(description='Dump a folder to a thread')
    +parser.add_argument('-f', '--folder', help='Folder to upload images from', type=str, required=True)
    +parser.add_argument('-u', '--url', help='URL of thread', required=True)
    +parser.add_argument('-d', '--delay', help='Delay between posting', type=int, required=True)
    +parser.add_argument('-i', '--images', help='Number of images to post', type=int)
    +parser.add_argument('-n', '--name', help='Name to post with', type=str, default='')
    +parser.add_argument('-e', '--email', help='Email to post with', type=str, default='')
    +parser.add_argument('-p', '--progress', help='Post with dump progress? (default y)', choices=('y', 'n'), default='y')
    +parser.add_argument('-r', '--random', help='Post with random filenames? (default n)', choices=('y', 'n'), default='n')
    +parser.add_argument('-l', '--length', help='To be used with -r/--random. Maximum length of random filename (optional, default 15)', type=int, default=15)
    +args = vars(parser.parse_args())
    +# https://stackoverflow.com/questions/9234258/in-python-argparse-is-it-possible-to-have-paired-no-something-something-arg
    +
    +extensions = ['.jpg', '.png', '.gif']
    +def make_random_filename():
    + return ''.join(choice(ascii_letters + digits) for _ in range(randint(1, args['length']))) + choice(extensions)
    +
    +
    +delay = args['delay']
    +DIRECTORY = args['folder']
    +filelist = []
    +for file in os.listdir(DIRECTORY):
    + if os.path.splitext(file)[1].lower() in ('.jpg', '.jpeg', '.png', '.gif', '.webm', '.mp4'):
    + filelist.append(os.path.join(DIRECTORY, file))
    +# I stole this from stackoverflow somewhere, I can't find the link
    +
    +if len(args['url'].split('/')) == 6:
    + spliturl = args['url'].split('/')
    + if has_numbers(spliturl[5]) and '.html' in args['url']:
    + url = '{}//{}'.format(spliturl[0], spliturl[2])
    + board = spliturl[3]
    + thread = spliturl[5].split('.')[0]
    + else:
    + sys.exit('\nBad URL. --u/--url should be the URL of a thread.\nExample: https://8ch.net/b/res/1.html')
    +else:
    + sys.exit('\nBad URL. --u/--url should be the URL of a thread.\nExample: https://8ch.net/b/res/1.html')
    +boardindex = requests.get('{}/{}/index.html'.format(url, board))
    +
    +if args['images'] == None:
    + if is_installed('bs4') == True:
    + from bs4 import BeautifulSoup
    + soup = BeautifulSoup(boardindex.text)
    + script_tag = str(soup.find_all('script')[1])
    + print('-i/--images not specified. Defaulting to the maximum number of allowed images on this board.')
    + maxfiles = int(re.search('var max_images=[1-5]', script_tag).group(0).split('=')[1])
    + elif is_installed('bs4') == False:
    + sys.exit('Unable to automatically detect the maximum number of images per post, please specify -i/--images')
    +else:
    + if args['images'] >= 1 and args['images'] <= 5:
    + maxfiles = args['images']
    + else:
    + sys.exit('-i/--images must be between 1 and 5')
    +
    +filelist = natural_sort(filelist)
    +total = len(filelist)
    +chunked_list = list(chunks(filelist, maxfiles))
    +
    +r = requests.get('{}/settings.php?board={}'.format(url, board))
    +try:
    + j = json.loads(r.text)
    + if j['max_newlines'] != 0:
    + max_newlines = j['max_newlines']
    + else:
    + max_newlines = 100
    +except ValueError:
    + sys.exit('Server error while getting board settings')
    +
    +data = {
    + 'board': board,
    + 'thread': thread,
    + 'name': args['name'],
    + 'email': args['email'],
    + 'subject': '',
    + 'body': '',
    + 'embed': '',
    + 'dx': '',
    + 'dy': '',
    + 'dz': '',
    + 'password': 'ayylmao',
    + 'json_response': '1',
    + 'post': 'New Reply',
    +}
    +
    +headers = {
    + 'referer': '',
    + 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0',
    + 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    + 'accept-language': 'en-US,en;q=0.5',
    + 'cache-control': 'max-age=0',
    +}
    +
    +headers['referer'] = '{}/{}/'.format(url, board)
    +
    +progress = maxfiles
    +for chunk in range(len(chunked_list)):
    + number_of_files = len(chunked_list[chunk])
    + status = ''
    + while 'redirect' not in status:
    + for x in range(len(chunked_list[chunk])):
    + l = natural_sort(chunked_list[chunk])
    + files = []
    + if args['random'] == 'y':
    + for file in range(len(l)):
    + if file == 0:
    + files.append(['file', (make_random_filename(), open(l[file], 'rb'))])
    + else:
    + files.append(['file' + str(file), (make_random_filename(), open(l[file], 'rb'))])
    + else:
    + for file in range(len(l)):
    + if file == 0:
    + files.append(['file', open(l[file], 'rb')])
    + else:
    + files.append(['file' + str(file), open(l[file], 'rb')])
    + files = tuple(files)
    + newlines = '\n' * randint(1, max_newlines)
    + if progress > total:
    + progress = total
    + if args['progress'] == 'y':
    + data['body'] = '{}/{}{}'.format(progress, total, newlines)
    + else:
    + data['body'] = newlines
    + if j['captcha']['enabled'] == True:
    + fetch_captcha()
    + r = requests.post('{}/post.php'.format(url), data=data, headers=headers, files=files)
    + status_code = r.status_code
    + status = r.text
    + if status_code == 200:
    + print(status)
    + else:
    + print('{} server error'.format(status_code))
    + if 'Failed to resize image' and 'corrupt image' in status:
    + print('ONE OF THE FOLLOWING IMAGES ARE CORRUPT, AND AS A RESULT, THE FOLLOWING FILES WERE NOT UPLOADED:')
    + pprint(l)
    + status = 'redirect'
    + if 'already exists' in status:
    + status = 'redirect'
    + if 'Maximum file size' in status:
    + print('THE FOLLOWING FILE(S) WERE OVER THE FILE SIZE LIMIT AND WERE NOT POSTED:')
    + pprint(l)
    + print('Consider setting -i/--images to a lower number so your files fit under the limit')
    + status = 'redirect'
    + del files
    + print('{}/{} - Waiting {} seconds...').format(progress, total, delay)
    + sleep(delay)
    + progress += number_of_files
Something went wrong with that request. Please try again.