Revision b6f0d860
Added by dsorber over 12 years ago
| software/bashquote/bashquote | ||
|---|---|---|
|
#!/usr/bin/env python
|
||
|
|
||
|
import cPickle
|
||
|
import os
|
||
|
import random
|
||
|
import sys
|
||
|
|
||
|
BQ_DIR = '/Users/dsorber/.bashquote'
|
||
|
BQ_CACHE = '/Users/dsorber/.bashquote/bq_cache'
|
||
|
|
||
|
def main():
|
||
|
|
||
|
# Create the cache file, or open it if it already exists
|
||
|
if not os.path.exists(BQ_CACHE):
|
||
|
print 'bashquote cache does not exist!'
|
||
|
sys.exit()
|
||
|
else :
|
||
|
cache = open(BQ_CACHE, 'r')
|
||
|
quotes = cPickle.load(cache)
|
||
|
cache.close()
|
||
|
|
||
|
# Choose a random quote from the list
|
||
|
num_quotes = len(quotes)
|
||
|
if num_quotes == 1:
|
||
|
# Repopulate the list manually if there is only one quote remaining
|
||
|
print 'Low on quotes, grabbing some more...',
|
||
|
os.system('bashquote_populate')
|
||
|
print 'Done'
|
||
|
index = random.randint(0, num_quotes - 1)
|
||
|
quote = quotes.pop(index)
|
||
|
|
||
|
# Print it out
|
||
|
print 'bashquote #%s ------ %s' % (quote[0], quote[1])
|
||
|
print quote[2]
|
||
|
|
||
|
# Re-store the remaining quotes and exit
|
||
|
cache = open(BQ_CACHE, 'w')
|
||
|
cPickle.dump(quotes, cache, -1)
|
||
|
cache.close()
|
||
|
sys.exit()
|
||
|
|
||
|
if __name__=="__main__":
|
||
|
main()
|
||
| software/bashquote/bashquote_populate | ||
|---|---|---|
|
#!/usr/bin/env python
|
||
|
|
||
|
import cPickle
|
||
|
import os
|
||
|
import re
|
||
|
import sys
|
||
|
import urllib
|
||
|
|
||
|
BQ_DIR = '/Users/dsorber/.bashquote'
|
||
|
BQ_CACHE = '/Users/dsorber/.bashquote/bq_cache'
|
||
|
|
||
|
def main():
|
||
|
|
||
|
# Create a list to hold the quotes
|
||
|
quotes = []
|
||
|
|
||
|
# Create the bashquote directory if it does not exist
|
||
|
if not os.path.exists(BQ_DIR):
|
||
|
print 'Creating bashquote directory...',
|
||
|
os.mkdir(BQ_DIR)
|
||
|
print 'Done'
|
||
|
|
||
|
# Create the cache file, or open it if it already exists
|
||
|
if not os.path.exists(BQ_CACHE):
|
||
|
print 'Creating bashquote cache...',
|
||
|
cache = open(BQ_CACHE, 'w')
|
||
|
cache.close()
|
||
|
print 'Done'
|
||
|
else:
|
||
|
cache = open(BQ_CACHE, 'r')
|
||
|
quotes = cPickle.load(cache)
|
||
|
cache.close()
|
||
|
|
||
|
|
||
|
# Only grab fresh quotes if there are less than 50 in the cache
|
||
|
if not len(quotes) < 50:
|
||
|
print 'plenty left'
|
||
|
sys.exit()
|
||
|
|
||
|
# Goto to the random >0 bash quotes page
|
||
|
listpage = urllib.urlopen("http://www.bash.org/?random1")
|
||
|
listpagetext = listpage.read()
|
||
|
|
||
|
quote_regex = '<p class="quote".+<b>#(\d+)</b>.+</a>\((\d+)\)<a .+<p class="qt">([\s\S]+?)</p>'
|
||
|
|
||
|
quotes = []
|
||
|
for quote_match in re.finditer(quote_regex, listpagetext):
|
||
|
quotes.append((quote_match.group(1),
|
||
|
quote_match.group(2),
|
||
|
unhtmlify(quote_match.group(3))))
|
||
|
|
||
|
# Store the list of quotes in the cache file, using the highest protocol
|
||
|
cache = open(BQ_CACHE, 'w')
|
||
|
cPickle.dump(quotes, cache, -1)
|
||
|
cache.close()
|
||
|
sys.exit()
|
||
|
|
||
|
|
||
|
def unhtmlify(quote):
|
||
|
# Filter out that HTML bullshit
|
||
|
return quote.replace("<", "<").replace("\'<", "<")\
|
||
|
.replace(">", ">").replace(""", "\"")\
|
||
|
.replace(" ", " ").replace("\\'", "'")\
|
||
|
.replace("\\x92", "'").replace("<br />\\r\\n', '", "\n")\
|
||
|
.replace("<br />\\r\\n\", '", "\n").replace("&", "&")\
|
||
|
.replace("<br />\\r\\n', \"", "\n")\
|
||
|
.replace("<br />\\r\\n\", \"", "\n").replace("<br />", "")
|
||
|
|
||
|
|
||
|
if __name__=="__main__":
|
||
|
main()
|
||
| software/image_grabber/grabber.py | ||
|---|---|---|
|
from multiprocessing import Process
|
||
|
from multiprocessing import Queue
|
||
|
import multiprocessing
|
||
|
import os
|
||
|
import re
|
||
|
import sys
|
||
|
import time
|
||
|
import urllib2
|
||
|
|
||
|
# --- DESCRIPTION ---
|
||
|
# A script for circumventing the image "protection" from http://celebforum.to/
|
||
|
# specifically for imagevenue.com links (will also support imagebam in the future)
|
||
|
#
|
||
|
# USAGE:
|
||
|
# python grabber.py <html source of gallery>
|
||
|
|
||
|
|
||
|
# http://img184.imagevenue.com/loc663/th_74708_0005_blood_orange_dress05_123_663lo.jpg
|
||
|
# http://img184.imagevenue.com/img.php?loc=loc663&image=74708_0005_blood_orange_dress05_123_663lo.jpg
|
||
|
IMAGEVENUE_PAGE_RE = r'"http://(img\d{3})\.imagevenue\.com/(loc\d{3})/(.+?\.jpg)"'
|
||
|
IMAGEVENUE_SRC_RE = r'<img id="thepic" .+? SRC="(.+?)"'
|
||
|
|
||
|
IMAGEBAM_PAGE_RE = r'"http://thumbnails\d+\.imagebam\.com/\d+/(.+?\.jpg)"'
|
||
|
IMAGEBAM_SRC_RE = r'<img .+? onclick="scale\(this\);" src="(.+?\.jpg)"'
|
||
|
|
||
|
# Location where the images should be saved
|
||
|
IMAGE_SAVE_PATH = 'images'
|
||
|
|
||
|
|
||
|
class ImageVenueProcessor(Process):
|
||
|
|
||
|
def __init__(self, input_file_name, image_src_queue):
|
||
|
Process.__init__(self)
|
||
|
self.input_file_name = input_file_name
|
||
|
self.image_src_queue = image_src_queue
|
||
|
self.running = False
|
||
|
|
||
|
def run(self):
|
||
|
self.running = True
|
||
|
|
||
|
# Iterate over the input source file and look for all thumbnail image matches
|
||
|
matches = []
|
||
|
with open(self.input_file_name, 'r') as input_file:
|
||
|
for line in input_file:
|
||
|
line_matches = re.findall(IMAGEVENUE_PAGE_RE, line)
|
||
|
for line_match in line_matches:
|
||
|
matches.append(line_match)
|
||
|
|
||
|
# Iterate over each match and build the correct image page URL
|
||
|
# Major thanks to http://vintage-erotica-forum.com/showthread.php?p=694632
|
||
|
# for explaining the secret sauce!
|
||
|
total = len(matches)
|
||
|
for idx, match in enumerate(matches):
|
||
|
server = 'http://{:s}.imagevenue.com/'.format(match[0])
|
||
|
image_name = match[2][3:]
|
||
|
image_loc = 'img.php?loc={:s}&image={:s}'.format(match[1], image_name)
|
||
|
link = '{:s}{:s}'.format(server, image_loc)
|
||
|
|
||
|
# Open the image page and download the source HTML
|
||
|
response = urllib2.urlopen(link)
|
||
|
html = response.read()
|
||
|
|
||
|
# Iterate over the source HTML looking for the image source link
|
||
|
for line in html.split('\n'):
|
||
|
img = re.search(IMAGEVENUE_SRC_RE, line)
|
||
|
if img:
|
||
|
location = '{:s}{:s}'.format(server, img.group(1))
|
||
|
print '{:3d} of {:3d} - {:s}'.format(idx + 1, total, location)
|
||
|
self.image_src_queue.put(location)
|
||
|
|
||
|
self.running = False
|
||
|
|
||
|
class ImageBamProcessor(Process):
|
||
|
|
||
|
def __init__(self, input_file_name, image_src_queue):
|
||
|
Process.__init__(self)
|
||
|
self.input_file_name = input_file_name
|
||
|
self.image_src_queue = image_src_queue
|
||
|
self.running = False
|
||
|
|
||
|
def run(self):
|
||
|
self.running = True
|
||
|
|
||
|
# Iterate over the input source file and look for all thumbnail image matches
|
||
|
matches = []
|
||
|
with open(self.input_file_name, 'r') as input_file:
|
||
|
for line in input_file:
|
||
|
line_matches = re.findall(IMAGEBAM_PAGE_RE, line)
|
||
|
for line_match in line_matches:
|
||
|
matches.append(line_match)
|
||
|
|
||
|
# Iterate over each match and build the correct image page URL
|
||
|
# Thanks to http://board.jdownloader.org/showthread.php?t=26255
|
||
|
total = len(matches)
|
||
|
for idx, match in enumerate(matches):
|
||
|
image_name = match
|
||
|
server = 'http://www.imagebam.com/image/'
|
||
|
link = '{:s}{:s}'.format(server, image_name)
|
||
|
|
||
|
# Open image page and download the source HTML
|
||
|
response = urllib2.urlopen(link)
|
||
|
html = response.read()
|
||
|
|
||
|
# Iterate over the source HTML looking for the image source link
|
||
|
for line in html.split('\n'):
|
||
|
img_match = re.search(IMAGEBAM_SRC_RE, line)
|
||
|
if img_match:
|
||
|
location = img_match.group(1)
|
||
|
print '{:3d} of {:3d} - {:s}'.format(idx + 1, total, location)
|
||
|
self.image_src_queue.put(location)
|
||
|
|
||
|
self.running = False
|
||
|
|
||
|
class Downloader(Process):
|
||
|
|
||
|
def __init__(self, image_src_queue):
|
||
|
Process.__init__(self)
|
||
|
self.image_src_queue = image_src_queue
|
||
|
|
||
|
def run(self):
|
||
|
|
||
|
while True:
|
||
|
image_path = self.image_src_queue.get()
|
||
|
image_name = image_path.rsplit('/', 1)[1]
|
||
|
|
||
|
print 'Downloading "{:s}"...'.format(image_path),
|
||
|
|
||
|
# Check if the image has already been downloaded before
|
||
|
# attempting to download it
|
||
|
contents = os.listdir(IMAGE_SAVE_PATH)
|
||
|
if image_name not in os.listdir(IMAGE_SAVE_PATH):
|
||
|
|
||
|
# Download the freakin image!
|
||
|
try:
|
||
|
response = urllib2.urlopen(image_path, timeout=4)
|
||
|
data = response.read()
|
||
|
except:
|
||
|
# print 'Unable to download: {:s}'.format(location)
|
||
|
print 'ERROR'
|
||
|
continue
|
||
|
|
||
|
# Save the image to the desired location
|
||
|
with open(os.path.join(IMAGE_SAVE_PATH, image_name), 'wb') as new_image:
|
||
|
new_image.write(data)
|
||
|
|
||
|
print 'DONE'
|
||
|
|
||
|
else:
|
||
|
print 'SKIPPED'
|
||
|
|
||
|
def main():
|
||
|
|
||
|
if len(sys.argv) < 2:
|
||
|
print 'Not enough arguments specified!'
|
||
|
return -1
|
||
|
|
||
|
# Create the image source queue that the "Processing" objects will produce
|
||
|
# to and the "Downloader" objects will consume from
|
||
|
image_src_queue = Queue(2048)
|
||
|
|
||
|
# Based on the number of cores in the system determine how many
|
||
|
# Downloader worker objects should be created
|
||
|
num_workers = max(1, multiprocessing.cpu_count() - 2)
|
||
|
|
||
|
# Create the Downloader worker objects
|
||
|
dl_workers = []
|
||
|
for ctr in xrange(num_workers):
|
||
|
dl_worker = Downloader(image_src_queue)
|
||
|
dl_worker.start()
|
||
|
dl_workers.append(dl_worker)
|
||
|
|
||
|
# Create the ImageBam Processsor
|
||
|
ib_proc = ImageBamProcessor(sys.argv[1], image_src_queue)
|
||
|
ib_proc.start()
|
||
|
|
||
|
# Create the ImageVenue Processor
|
||
|
iv_proc = ImageVenueProcessor(sys.argv[1], image_src_queue)
|
||
|
iv_proc.start()
|
||
|
|
||
|
# Wait for the Processor objects to complete
|
||
|
ib_proc.join()
|
||
|
iv_proc.join()
|
||
|
|
||
|
# Wait until the image source queue is empty, then kill all the
|
||
|
# Downloader workers
|
||
|
while True:
|
||
|
if image_src_queue.empty():
|
||
|
# Wait 3 seconds to allow any downloads to finish
|
||
|
time.sleep(3)
|
||
|
for dl_worker in dl_workers:
|
||
|
dl_worker.terminate()
|
||
|
break
|
||
|
|
||
|
print '\n\n'
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/keypress counter/keypress_counter.c | ||
|---|---|---|
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdint.h>
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <dirent.h>
|
||
|
#include <linux/input.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/select.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <termios.h>
|
||
|
#include <signal.h>
|
||
|
|
||
|
|
||
|
void perror_exit(char *error)
|
||
|
{
|
||
|
perror(error);
|
||
|
printf("\nexiting...(%d)\n", 9);
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
uint32_t counter;
|
||
|
struct input_event ev[64];
|
||
|
int fd, rd, value;
|
||
|
int size = sizeof(struct input_event);
|
||
|
char name[256] = "Unknown";
|
||
|
char *device = NULL;
|
||
|
|
||
|
FILE *out_file;
|
||
|
|
||
|
// Make sure the user is root
|
||
|
if ((getuid ()) != 0)
|
||
|
{
|
||
|
printf ("\nYou must be root to display keypress counts.\n\n");
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
// Setup check
|
||
|
if (argv[1] == NULL)
|
||
|
{
|
||
|
printf("Please specify (on the command line) the path to the dev event interface device\n");
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
if (argc > 1)
|
||
|
{
|
||
|
device = argv[1];
|
||
|
}
|
||
|
|
||
|
if (argc > 2)
|
||
|
{
|
||
|
out_file = fopen(argv[2], "w");
|
||
|
if (out_file == NULL)
|
||
|
{
|
||
|
printf("Unable to open file %s", argv[2]);
|
||
|
exit(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Open specified device
|
||
|
if ((fd = open (device, O_RDONLY)) == -1)
|
||
|
{
|
||
|
printf("%s is not a vaild device.\n", device);
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
// Print device name
|
||
|
//ioctl (fd, EVIOCGNAME(sizeof(name)), name);
|
||
|
//printf ("Reading From : %s (%s)\n", device, name);
|
||
|
|
||
|
// Main loop, read
|
||
|
counter = 0;
|
||
|
while(1)
|
||
|
{
|
||
|
if ((rd = read(fd, ev, size * 64)) < size)
|
||
|
{
|
||
|
perror_exit("read()");
|
||
|
}
|
||
|
|
||
|
value = ev[0].value;
|
||
|
|
||
|
// Only read the key press event
|
||
|
if (value != ' ' && ev[1].value == 1 && ev[1].type == 1)
|
||
|
{
|
||
|
counter++;
|
||
|
|
||
|
// If a filename was given, output to that file
|
||
|
if (argc > 2)
|
||
|
{
|
||
|
// Seek to beginning of file, output and flush to file
|
||
|
fseek(out_file, 0, SEEK_SET);
|
||
|
fprintf(out_file, "%10u", counter);
|
||
|
fflush(out_file);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Otherwise print to stdout
|
||
|
// Print count, fixed width of 10 spaces, over of the same line
|
||
|
printf("\r%10u", counter);
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
|
||
|
// Check for (hopefully rare) overflow condition
|
||
|
if (counter == UINT32_MAX)
|
||
|
{
|
||
|
printf("\nGADZOOKS BATMAN!!! You overflowed a 32 bit unsigned integer with all your keystrokes!\n\n");
|
||
|
counter = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose(out_file);
|
||
|
return 0;
|
||
|
}
|
||
| software/keypress counter/keypress_wrapper.sh | ||
|---|---|---|
|
#!/bin/bash
|
||
|
#
|
||
|
# Keypress counter wrapper
|
||
|
#
|
||
|
./keypress_counter /dev/input/by-path/platform-i8042-serio-0-event-kbd /home/dsorber/Desktop/keypress_count.txt &
|
||
|
KC_PID=$!
|
||
|
echo $KC_PID
|
||
|
sleep 30s
|
||
|
echo "`date +%F` `cat /home/dsorber/Desktop/keypress_count.txt`" >> keypress_totals.txt
|
||
|
kill -15 `echo $KC_PID`
|
||
|
|
||
|
./keypress_counter /dev/input/by-path/platform-i8042-serio-0-event-kbd /home/dsorber/Desktop/keypress_count.txt &
|
||
|
KC_PID=$!
|
||
|
echo $KC_PID
|
||
|
sleep 30s
|
||
|
echo "`date +%F` `cat /home/dsorber/Desktop/keypress_count.txt`" >> keypress_totals.txt
|
||
|
kill -15 `echo $KC_PID`
|
||
|
|
||
|
./keypress_counter /dev/input/by-path/platform-i8042-serio-0-event-kbd /home/dsorber/Desktop/keypress_count.txt &
|
||
|
KC_PID=$!
|
||
|
echo $KC_PID
|
||
|
sleep 30s
|
||
|
echo "`date +%F` `cat /home/dsorber/Desktop/keypress_count.txt`" >> keypress_totals.txt
|
||
|
kill -15 `echo $KC_PID`
|
||
| software/misc/popcount_alg.py | ||
|---|---|---|
|
import sys
|
||
|
|
||
|
def popcount(i):
|
||
|
i = i - ((i >> 1) & 0x55555555)
|
||
|
i = (i & 0x33333333) + ((i >> 2) & 0x33333333)
|
||
|
return ((((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) & 0xFFFFFFFF) >> 24
|
||
|
|
||
|
def main():
|
||
|
print 'Popcount Algorithm Overview\n'
|
||
|
|
||
|
#i = i - ((i >> 1) & 0x55555555);
|
||
|
#i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
|
||
|
#return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
|
||
|
|
||
|
uint = raw_input('Enter a 32 bit unsigned number> ')
|
||
|
if uint.startswith('0x'):
|
||
|
uint = int(uint, 16) & 0xFFFFFFFF
|
||
|
else:
|
||
|
uint = int(uint) & 0xFFFFFFFF
|
||
|
print
|
||
|
|
||
|
#i = i - ((i >> 1) & 0x55555555);
|
||
|
print 'Step 0: Input number: {:>10d} -- hex: 0x{:08X}'.format(uint, uint)
|
||
|
op_step1 = (uint >> 1)
|
||
|
print 'Step 1: (i >> 1): {:>10d} -- hex: 0x{:08X}'.format(op_step1, op_step1)
|
||
|
op_step2 = op_step1 & 0x55555555
|
||
|
print 'Step 2: ((i >> 1) & 0x55555555): {:>10d} -- hex: 0x{:08X}'.format(op_step2, op_step2)
|
||
|
op_step3 = uint - op_step2
|
||
|
print 'Step 3: i - ((i >> 1) & 0x55555555): {:>10d} -- hex: 0x{:08X}'.format(op_step3, op_step3)
|
||
|
print
|
||
|
|
||
|
#i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
|
||
|
op_step4 = op_step3 & 0x33333333
|
||
|
print 'Step 4: (i & 0x33333333): {:>10d} -- hex: 0x{:08X}'.format(op_step4, op_step4)
|
||
|
op_step5 = op_step3 >> 2
|
||
|
print 'Step 5: (i >> 2): {:>10d} -- hex: 0x{:08X}'.format(op_step5, op_step5)
|
||
|
op_step6 = op_step5 & 0x33333333
|
||
|
print 'Step 6: ((i >> 2) & 0x33333333): {:>10d} -- hex: 0x{:08X}'.format(op_step6, op_step6)
|
||
|
op_step7 = op_step4 + op_step6
|
||
|
print 'Step 7: (i & 0x33333333) + ((i >> 2) & 0x33333333): {:>10d} -- hex: 0x{:08X}'.format(op_step7, op_step7)
|
||
|
print
|
||
|
|
||
|
#ans = (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24
|
||
|
op_step8 = op_step7 >> 4
|
||
|
print 'Step 8: (i >> 4): {:>10d} -- hex: 0x{:08X}'.format(op_step8, op_step8)
|
||
|
op_step9 = op_step7 + op_step8
|
||
|
print 'Step 9: (i + (i >> 4)): {:>10d} -- hex: 0x{:08X}'.format(op_step9, op_step9)
|
||
|
op_step10 = op_step9 & 0x0F0F0F0F
|
||
|
print 'Step 10: ((i + (i >> 4)) & 0x0F0F0F0F): {:>10d} -- hex: 0x{:08X}'.format(op_step10, op_step10)
|
||
|
op_step11 = (op_step10 * 0x01010101) & 0xFFFFFFFF
|
||
|
print 'Step 11: (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101): {:>10d} -- hex: 0x{:08X}'.format(op_step11, op_step11)
|
||
|
op_step12 = op_step11 >> 24
|
||
|
print 'Step 12: (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24: {:>10d} -- hex: 0x{:08X}'.format(op_step12, op_step12)
|
||
|
print
|
||
|
print 'Popcount: {:d}'.format(popcount(uint))
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/misc/unbruce.py | ||
|---|---|---|
|
import os
|
||
|
import sys
|
||
|
|
||
|
def main():
|
||
|
|
||
|
for file in os.listdir(sys.argv[1]):
|
||
|
if file.startswith('www-bruce-juice-com-') or \
|
||
|
file.startswith('www-bruce-juice-com_'):
|
||
|
print '%s ---> %s' % (file, file[20:])
|
||
|
os.rename(file, file[20:])
|
||
|
elif file.startswith('www-bangtidy-net-') or \
|
||
|
file.startswith('www-bangtidy-net_'):
|
||
|
print '%s ---> %s' % (file, file[17:])
|
||
|
os.rename(file, file[17:])
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/renamer/renamer.py | ||
|---|---|---|
|
import os
|
||
|
import re
|
||
|
import sys
|
||
|
|
||
|
def main():
|
||
|
|
||
|
if len(sys.argv) < 3:
|
||
|
print 'Not enough arguments specified!'
|
||
|
return
|
||
|
|
||
|
show_name = sys.argv[1]
|
||
|
directory = sys.argv[2]
|
||
|
|
||
|
show_name = show_name.replace(' ', '\.')
|
||
|
|
||
|
for filename in os.listdir(directory):
|
||
|
m = re.match("^(%s)\.S(\d+)E(\d+)\.(.*)\.(\w{3})$" % show_name, filename, re.IGNORECASE)
|
||
|
if m:
|
||
|
new_name = '%s - S%sE%s.%s' % (show_name.replace('\.', ' '),
|
||
|
m.group(2), m.group(3), m.group(5).lower())
|
||
|
|
||
|
print '%s --- MATCH: %s' % (filename, new_name)
|
||
|
os.rename(os.path.join(directory, filename),
|
||
|
os.path.join(directory, new_name))
|
||
|
else:
|
||
|
print filename
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/similar images/build_index.py | ||
|---|---|---|
|
#!/opt/local/bin/python2.7
|
||
|
import bz2
|
||
|
import cPickle
|
||
|
import imghdr
|
||
|
import os
|
||
|
import sys
|
||
|
|
||
|
import pHash
|
||
|
|
||
|
from image import Image
|
||
|
|
||
|
# Build index
|
||
|
# TODO: write more schtuff here
|
||
|
|
||
|
def main():
|
||
|
|
||
|
image_list = []
|
||
|
|
||
|
# Make sure at least one command line argument was provided
|
||
|
if len(sys.argv) < 2:
|
||
|
print 'Usage: build_index.py <path>'
|
||
|
return -1;
|
||
|
|
||
|
# Print out the path we're walking
|
||
|
path = sys.argv[1]
|
||
|
print 'Building image index from path: {:s}\n'.format(path)
|
||
|
|
||
|
# Walk the root path and count all images
|
||
|
img_counter = 0
|
||
|
for root, dirs, files in os.walk(path):
|
||
|
for file in files:
|
||
|
img_path = os.path.join(root, file)
|
||
|
# Check the make sure the file is a JPEG
|
||
|
if not imghdr.what(img_path) == 'jpeg':
|
||
|
continue
|
||
|
img_counter += 1
|
||
|
print 'Done counting, {:d} images total.'.format(img_counter)
|
||
|
|
||
|
# Walk the root path
|
||
|
ctr = 0
|
||
|
for root, dirs, files in os.walk(path):
|
||
|
for file in files:
|
||
|
img_path = os.path.join(root, file)
|
||
|
# Check the make sure the file is a JPEG
|
||
|
if not imghdr.what(img_path) == 'jpeg':
|
||
|
continue
|
||
|
ctr += 1
|
||
|
percent_done = int((float(ctr) / img_counter) * 100)
|
||
|
print '{:3d}% -- {:s}'.format(percent_done, img_path)
|
||
|
img_obj = Image(img_path)
|
||
|
# print '{:s} -> {:016X}'.format(img_path, img_obj.hash)
|
||
|
image_list.append(img_obj)
|
||
|
|
||
|
# Write index as a bzip2'd file to save space
|
||
|
index_file = bz2.BZ2File('images_index.bz2', 'w')
|
||
|
cPickle.dump(image_list, index_file)
|
||
|
index_file.close()
|
||
|
|
||
|
print '\nIndex file images_index.bz2 created. Done.'
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/similar images/build_index_faster.py | ||
|---|---|---|
|
#!/opt/local/bin/python2.7
|
||
|
import bz2
|
||
|
import cPickle
|
||
|
import imghdr
|
||
|
import math
|
||
|
import multiprocessing
|
||
|
import os
|
||
|
import Queue
|
||
|
import random
|
||
|
import sys
|
||
|
|
||
|
import pHash
|
||
|
|
||
|
from image import Image
|
||
|
|
||
|
NUM_WORKERS = 7
|
||
|
|
||
|
# Build index
|
||
|
# TODO: write more schtuff here
|
||
|
|
||
|
class IndexWorker(multiprocessing.Process):
|
||
|
|
||
|
def __init__(self, file_list, queue):
|
||
|
multiprocessing.Process.__init__(self)
|
||
|
self.file_list = file_list
|
||
|
self.queue = queue
|
||
|
|
||
|
def run(self):
|
||
|
|
||
|
list_size = len(self.file_list)
|
||
|
ctr = 0
|
||
|
for file_path in self.file_list:
|
||
|
ctr += 1
|
||
|
percent_done = int((float(ctr) / list_size) * 100)
|
||
|
# We can only index jpegs right now
|
||
|
if not imghdr.what(file_path) == 'jpeg':
|
||
|
continue
|
||
|
print '{:d} -- {:3d}% -- {:s}'.format(self.pid, percent_done,
|
||
|
file_path)
|
||
|
image_obj = Image(file_path)
|
||
|
|
||
|
self.queue.put(image_obj, True)
|
||
|
|
||
|
|
||
|
|
||
|
def main():
|
||
|
|
||
|
# Make sure at least one command line argument was provided
|
||
|
if len(sys.argv) < 2:
|
||
|
print 'Usage: build_index_faster.py <path>'
|
||
|
return -1;
|
||
|
|
||
|
# Print out the path we're walking
|
||
|
path = sys.argv[1]
|
||
|
print 'Building image index from path: {:s}\n'.format(path)
|
||
|
|
||
|
master_file_list = []
|
||
|
image_index = []
|
||
|
|
||
|
# Walk the root path and create a list of all files in the root path
|
||
|
for root, dirs, files in os.walk(path):
|
||
|
for file in files:
|
||
|
master_file_list.append(os.path.join(root, file))
|
||
|
|
||
|
random.shuffle(master_file_list)
|
||
|
|
||
|
print 'Done counting, {:d} files total.'.format(len(master_file_list))
|
||
|
|
||
|
workers = []
|
||
|
queue = multiprocessing.Queue(64)
|
||
|
|
||
|
def chunker(seq, size):
|
||
|
return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
|
||
|
|
||
|
chunk_size = int(math.ceil(len(master_file_list) / NUM_WORKERS))
|
||
|
|
||
|
# Create worker processes
|
||
|
for work_chunk in chunker(master_file_list, chunk_size):
|
||
|
workers.append(IndexWorker(work_chunk, queue))
|
||
|
|
||
|
# Start workers
|
||
|
for worker in workers:
|
||
|
worker.start()
|
||
|
|
||
|
print 'Waiting for workers to complete'
|
||
|
|
||
|
# Loop until all workers are finished
|
||
|
while any([w.is_alive() for w in workers]):
|
||
|
try:
|
||
|
image_obj = queue.get(True, 2)
|
||
|
image_index.append(image_obj)
|
||
|
except Queue.Empty:
|
||
|
print 'Queue was empty'
|
||
|
continue
|
||
|
|
||
|
print 'Workers are complete: {:d} images found'.format(len(image_index))
|
||
|
|
||
|
# Write index as a bzip2'd file to save space
|
||
|
index_file = bz2.BZ2File('images_index.bz2', 'w')
|
||
|
cPickle.dump(image_index, index_file)
|
||
|
index_file.close()
|
||
|
|
||
|
print '\nIndex file images_index.bz2 created. Done.'
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/similar images/find_duplicates_simple.py | ||
|---|---|---|
|
#!/opt/local/bin/python2.7
|
||
|
from collections import defaultdict
|
||
|
import imghdr
|
||
|
import os
|
||
|
import sys
|
||
|
|
||
|
import pHash
|
||
|
|
||
|
# Find Duplicates Simple
|
||
|
# Attempt to find images by looking for exact hash collisions.
|
||
|
# This method is not very sophisticated and does not work all
|
||
|
# that well.
|
||
|
|
||
|
def main():
|
||
|
|
||
|
img_map = defaultdict(list)
|
||
|
|
||
|
# Make sure at least one command line argument was provided
|
||
|
if len(sys.argv) < 2:
|
||
|
print 'Usage: find_duplicate_simple <path>'
|
||
|
return -1;
|
||
|
|
||
|
# Print out the path we're walking
|
||
|
path = sys.argv[1]
|
||
|
print 'Step 1: Walk path: {:s}\n'.format(path)
|
||
|
|
||
|
# Walk the root path
|
||
|
for root, dirs, files in os.walk(path):
|
||
|
for file in files:
|
||
|
img_path = os.path.join(root, file)
|
||
|
# Check the make sure the file is an actual image
|
||
|
if not imghdr.what(img_path):
|
||
|
continue
|
||
|
img_hash = pHash.imagehash(img_path)
|
||
|
print '{:s} -> {:016X}'.format(img_path, img_hash)
|
||
|
img_map[img_hash].append(img_path)
|
||
|
|
||
|
|
||
|
print '\n\nStep 2: find duplicates\n'
|
||
|
|
||
|
# Now look through the image hash dictionary for matches
|
||
|
for img_hash, files in img_map.items():
|
||
|
if len(files) > 2:
|
||
|
print '{:016X}'.format(img_hash)
|
||
|
for file_path in files:
|
||
|
print '\t{:s}'.format(file_path)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/similar images/find_similar.py | ||
|---|---|---|
|
#!/opt/local/bin/python2.7
|
||
|
import bz2
|
||
|
from collections import defaultdict
|
||
|
import cPickle
|
||
|
import imghdr
|
||
|
import os
|
||
|
import sys
|
||
|
|
||
|
import pHash
|
||
|
|
||
|
from image import Image
|
||
|
|
||
|
HAMMING_THRESHOLD = 10
|
||
|
CORRELATION_THRESHOLD = 70.0
|
||
|
|
||
|
# Find duplicates by looking over index
|
||
|
# write some description
|
||
|
|
||
|
def find_similar(total_done, index, image):
|
||
|
index_length = len(index)
|
||
|
image_digest = image.make_digest()
|
||
|
|
||
|
# Search the index
|
||
|
ctr = 0
|
||
|
for index_image in index:
|
||
|
ctr += 1
|
||
|
percent_done = int((float(ctr) / index_length) * 100)
|
||
|
sys.stdout.write('\r\tTotal: {:3d}% --- This image: {:3d}%'.format(total_done, percent_done))
|
||
|
sys.stdout.flush()
|
||
|
# Original might be in index, skip it
|
||
|
if image.hash == index_image.hash and image.path == index_image.path:
|
||
|
continue
|
||
|
|
||
|
# Hamming distance hash compare
|
||
|
hamming_distance = pHash.hamming_distance(image.hash, index_image.hash)
|
||
|
|
||
|
# Cross correlation compare
|
||
|
correlation = pHash.crosscorr(image_digest, index_image.make_digest())[1]
|
||
|
|
||
|
# Determine if comparison criteria are within the thresholds
|
||
|
if hamming_distance <= HAMMING_THRESHOLD or \
|
||
|
correlation >= CORRELATION_THRESHOLD:
|
||
|
sys.stdout.write('\r\t--- SIMILAR IMAGE FOUND --- \n')
|
||
|
print '\tHamming distance: {:d}'.format(hamming_distance)
|
||
|
print '\tCross correlation: {:f}'.format(correlation)
|
||
|
print '\tImage path: {:s}\n'.format(index_image.path)
|
||
|
print
|
||
|
|
||
|
|
||
|
def main():
|
||
|
|
||
|
# Make sure at least one command line argument was provided
|
||
|
if len(sys.argv) < 3:
|
||
|
print 'Usage: find_similar.py <image dir root path> <index path>'
|
||
|
return -1;
|
||
|
|
||
|
# Print out the path we're walking
|
||
|
root_path = sys.argv[1]
|
||
|
index_path = sys.argv[2]
|
||
|
|
||
|
# Load image index
|
||
|
index_file = bz2.BZ2File(index_path, 'r')
|
||
|
image_index = cPickle.load(index_file)
|
||
|
index_file.close()
|
||
|
|
||
|
print 'Looking for similar images from from path: {:s}'.format(root_path)
|
||
|
|
||
|
# Walk the root path and count all images
|
||
|
# (is there a better way to do this?)
|
||
|
image_counter = 0
|
||
|
for root, dirs, files in os.walk(root_path):
|
||
|
for file in files:
|
||
|
image_path = os.path.join(root, file)
|
||
|
# Check the make sure the file is a JPEG
|
||
|
if not imghdr.what(image_path) == 'jpeg':
|
||
|
continue
|
||
|
image_counter += 1
|
||
|
print 'Done counting, {:d} images total.'.format(image_counter)
|
||
|
|
||
|
# Walk the root path
|
||
|
ctr = 0
|
||
|
for root, dirs, files in os.walk(root_path):
|
||
|
for file in files:
|
||
|
image_path = os.path.join(root, file)
|
||
|
# Check the make sure the file is a JPEG
|
||
|
if not imghdr.what(image_path) == 'jpeg':
|
||
|
continue
|
||
|
ctr += 1
|
||
|
percent_done = int((float(ctr) / image_counter) * 100)
|
||
|
print '\n\nLooking for similar -- {:s}'.format(image_path)
|
||
|
image_obj = Image(image_path)
|
||
|
# Find similar images by searching the index
|
||
|
find_similar(percent_done, image_index, image_obj)
|
||
|
|
||
|
print '\nDone.'
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
| software/similar images/image.py | ||
|---|---|---|
|
import copy
|
||
|
|
||
|
import pHash
|
||
|
|
||
|
class Image(object):
|
||
|
|
||
|
def __init__(self, path, hash=None, coefficients=None):
|
||
|
self.path = path
|
||
|
|
||
|
if not hash:
|
||
|
self.hash = pHash.imagehash(self.path)
|
||
|
else:
|
||
|
self.hash = hash
|
||
|
|
||
|
if not coefficients:
|
||
|
self.coefficients = copy.copy(pHash.image_digest(self.path, 1.0, 1.0, 180).coeffs)
|
||
|
else:
|
||
|
self.coefficients = coefficients
|
||
|
|
||
|
def make_digest(self):
|
||
|
digest = pHash.Digest()
|
||
|
digest.coeffs = copy.copy(self.coefficients)
|
||
|
digest.size = len(self.coefficients)
|
||
|
return digest
|
||
|
|
||
|
def __repr__(self):
|
||
|
print 'Image: {:s}'.format(self.path)
|
||
|
print '\tHash: {:016X}'.format(self.hash)
|
||
|
print '\tDigest coefficients: {:s}'.format(str(self.coefficients))
|
||
| software/similar images/test.py | ||
|---|---|---|
|
import sys
|
||
|
|
||
|
import pHash
|
||
|
|
||
|
def main():
|
||
|
hash1 = pHash.imagehash(sys.argv[1])
|
||
|
hash2 = pHash.imagehash(sys.argv[2])
|
||
|
|
||
|
print 'Image 1: {:X}'.format(hash1)
|
||
|
print 'Image 2: {:X}'.format(hash2)
|
||
|
print 'Distance {:d}'.format(pHash.hamming_distance(hash2, hash1))
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|
||
Whoops I need to use the move command so that git keeps track of where things have gone.