#automated nzb downloader based on gamespot ratings using rss feed and api from newzbin.com
#this script is designed to download game nzb files from newzbin.com (requires registration and payment)
#created by binhex
#ver 1.0
#problems/features
import urllib
import httplib
import xml.dom.minidom
import re
import time
import os
import traceback
import logging
import socket
import fileinput
import subprocess
#put your own folder names below as specified in sabnzbd+
watch_dir="H:\\Downloads\\Usenet\\SABnzbd\\Watched\\"
nzb_dir="H:\\Downloads\\Usenet\\SABnzbd\\NZBs\\"
completed_dir="H:\\Downloads\\Usenet\\SABnzbd\\Completed\\"
#put your own folder and filenames below to specify location of log files
mainlog="F:\\Scripts\\Logs\\Errors\\newzbin_autodl_games_main.log"
tracelog="F:\\Scripts\\Logs\\Errors\\newzbin_autodl_games_traceback.log"
cachelog="F:\\Scripts\\Logs\\Output\\newzbin_autodl_games_cache" + time.strftime("_%m%y") + ".log"
#put your own notification message process below for error logging
notifylog="cmd /c msg console /TIME:43200 Newzbin Games Script Error, Check Logs"
#send failure messages to log file
main_logger = logging.getLogger('myapp1')
main_handler = logging.FileHandler(mainlog)
main_formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
main_handler.setFormatter(main_formatter)
main_logger.addHandler(main_handler)
main_logger.setLevel(logging.INFO)
#sets timeout period for urlretrieve (in seconds)
socket.setdefaulttimeout(240)
#newzbin account details
newzbin_username="yourusername"
newzbin_password="yourpassword"
#newzbin rss feed for "Saved Searches"
newzbin_com_feed="https://www.newzbin.com/search/therestofyourrssfeed"
#define platform search for gamerankings
#gamerankings_platform="site=pc" #pc platform
gamerankings_platform="site=xbox360" #xbox360 platform
#gamerankings_platform="site=wii" #wii platform
#gamerankings_platform="site=ds" #ds platform
#define release time period search for gamerankings
gamerankings_released="&year=0" #anytime release
#gamerankings_released="&year=1" #in the past release
#gamerankings_released="&year=2" #last month release
#gamerankings_released="&year=3" #last 3 months release
#gamerankings_released="&year=4" #last 6 months release
#gamerankings_released="&year=5" #last year release
#define minimum number of reviews search for gamerankings
#gamerankings_reviews="&numrev=0" #0+ reviews
#gamerankings_reviews="&numrev=1" #1+ reviews
#gamerankings_reviews="&numrev=2" #5+ reviews
gamerankings_reviews="&numrev=3" #10+ reviews
#gamerankings_reviews="&numrev=4" #20+ reviews
#gamerankings search page
gamerankings_search_url="http://www.gamerankings.com/browse.html?" + gamerankings_platform + "&cat=0" + gamerankings_released + gamerankings_reviews + "&sort=0&letter=&search="
#check for internet connectivity
pingtest = "ping www.google.co.uk"
process = subprocess.Popen(pingtest, shell=True, stdout=subprocess.PIPE)
process.wait()
if process.returncode == 0:
##############
# os filters #
##############
try:
def isInWatched(check_watched_folder):
#this is set to download only if the nzb file doesn't exist in the watch folder (watch_dir)
if os.path.exists(watch_dir + check_watched_folder + ".nzb"):
return 0
else:
return 1
def isInNZB(check_nzb_folder):
#this is set to download only if the nzb file doesn't exist in the nzb folder (nzb_dir)
if os.path.exists(nzb_dir + check_nzb_folder + ".nzb.gz"):
return 0
else:
return 1
def isCompleted(check_completed_folder):
#this is set to download only if the game doesn't exist in the completed folder (completed_dir)
if os.path.exists(completed_dir + check_completed_folder):
return 0
else:
return 1
except:
print("Error: OS Filter Error")
main_logger.error("OS Filter Error")
traceback.print_exc(file=open(tracelog,"a"))
os.system(notifylog)
########################
# gamerankings filters #
########################
try:
def isGoodRatings(check_ratings):
#this is set to download games with a min rating 85% (gamerankings)
if re.compile("<b>8[5-9]\.[0-9][0-9]\%</b>|<b>9[0-9]\.[0-9][0-9]\%</b>").search(check_ratings):
return 1
else:
return 0
def isGoodTitle(check_title):
#this is set to ignore gamerankings filters for games with certain titles
if re.compile("Good Game", re.IGNORECASE).search(check_title):
return 1
else:
return 0
def isGoodMatch(check_match):
#this is set to check that release title and gamerankings search result match
gamerankings_search_result_title = re.compile("/xbox360/[0-9]+.*\>.*\</a\>").search(check_match)
if gamerankings_search_result_title is not None:
if re.search(newzbin_game_title + "\</a\>", gamerankings_search_result_title.group()):
return 1
else:
return 0
def isBadSearch(check_search):
#this is set to search for no title match found on gamerankings
if re.compile("No results were found for your search", re.IGNORECASE).search(check_search):
return 0
else:
return 1
except:
print("Error: Gamerankings Filter Error")
main_logger.error("Gamerankings Filter Error")
traceback.print_exc(file=open(tracelog,"a"))
os.system(notifylog)
try:
def download(download_nzb):
print("------------------------------")
print("Status: Downloading Game.....")
print("Release Game Title: " + newzbin_game_title)
print("NZB Filename: " + newzbin_game_title_strip)
print("")
#the following code uses the newzbin api
headers = {
'User-Agent': 'grabnzb.py',
}
conn = httplib.HTTPSConnection('v3.newzbin.com')
postdata = { 'username': newzbin_username, 'password': newzbin_password, 'reportid': report_id }
postdata = urllib.urlencode(postdata)
headers['Content-type'] = 'application/x-www-form-urlencoded'
fetchurl = '/api/dnzb/'
conn.request('POST', fetchurl, postdata, headers)
response = conn.getresponse()
rcode = response.getheader('X-DNZB-RCode')
if re.compile("200", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) OK, NZB content follows")
data = response.read()
#save response to nzb file
nzbfile=file(watch_dir + newzbin_game_title_strip + ".nzb","a")
nzbfile.write(data + "\n")
nzbfile.close()
elif re.compile("400", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) Bad Request, please supply all parameters")
elif re.compile("401", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) Unauthorised, check username/password?")
elif re.compile("402", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) Payment Required, not Premium")
elif re.compile("404", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) Not Found, data doesn't exist? ")
elif re.compile("450", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) Try Later, wait 60 seconds for counter to reset")
time.sleep(60)
conn.request('POST', fetchurl, postdata, headers)
response = conn.getresponse()
data = response.read()
#save response to nzb file
nzbfile=file(watch_dir + newzbin_game_title_strip + ".nzb","a")
nzbfile.write(data + "\n")
nzbfile.close()
elif re.compile("500", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) Internal Server Error, please report to Administrator")
elif re.compile("503", re.IGNORECASE).search(rcode):
print("Debug: (Newzbin API) Service Unavailable, site is currently down")
#read response back from newzbin (debug)
#rcode = response.getheader('X-DNZB-RCode')
#print("Debug: Newzbin API Return Code: " + rcode)
#rtext = response.getheader('X-DNZB-RText')
#print("Debug: Newzbin API Resturn Code Text: " + rtext)
#report_name = response.getheader('X-DNZB-Name')
#print("Debug: Newzbin API Returned Report: " + report_name)
#report_cat = response.getheader('X-DNZB-Category')
#print("Debug: Newzbin API Returned Category: " + report_cat)
#report_extlink = response.getheader('X-DNZB-MoreInfo')
#print("Debug: Newzbin API Returned External Link: " + report_extlink)
except:
print("Error: Download Of NZB Failed")
main_logger.error("Download Of Game " + newzbin_game_title_strip + " Failed")
traceback.print_exc(file=open(tracelog,"a"))
os.system(notifylog)
#this retries the deletion of partial nzb downloads
removeRetryCount = 0
while removeRetryCount < 5:
#sleep and retry to delete partial nzb download 5 times with 30 sec gap
try:
os.remove(watch_dir + newzbin_game_title_strip + ".nzb")
break
except:
removeRetryCount += 1
time.sleep(30)
else:
print("Error: Deletion Of Partial NZB Failed")
main_logger.error("Deletion Of NZB " + newzbin_game_title_strip + " Failed")
traceback.print_exc(file=open(tracelog,"a"))
os.system(notifylog)
#this reads the content of the rss feed from newzbin.com
rssfeedRetryCount = 0
while rssfeedRetryCount < 5:
#sleep and retry to read the content of the rss feed from newzbin.com 5 times with 2 min gap
try:
dom=xml.dom.minidom.parse(urllib.urlopen(newzbin_com_feed))
break
except:
rssfeedRetryCount += 1
time.sleep(120)
else:
print("Error: RSS Feed Error")
main_logger.error("RSS Feed Error")
traceback.print_exc(file=open(tracelog,"a"))
os.system(notifylog)
#this breaks down the rss feed page into tag sections
for node in dom.getElementsByTagName("item"):
newzbin_game_title = node.getElementsByTagName("title")[0].childNodes[0].data
#remove unwanted characters from newzbin title
newzbin_game_title = re.sub("\(.*\)+$|\[.*\]$","" ,newzbin_game_title)
newzbin_game_title = re.sub("\s+$","" ,newzbin_game_title)
newzbin_game_title = re.sub("40K","40,000" ,newzbin_game_title)
#remove/replace illegal characters from newzbin title (used for nzb filename)
newzbin_game_title_strip = re.sub("\:","" ,newzbin_game_title)
newzbin_game_title_strip = re.sub("\*","" ,newzbin_game_title_strip)
newzbin_game_title_strip = re.sub("\"","" ,newzbin_game_title_strip)
newzbin_game_title_strip = re.sub("/"," " ,newzbin_game_title_strip)
newzbin_game_title_strip = re.sub("\\\\"," " ,newzbin_game_title_strip)
newzbin_game_title_strip = re.sub("\?","" ,newzbin_game_title_strip)
newzbin_game_title_strip = re.sub("\|","" ,newzbin_game_title_strip)
newzbin_game_title_strip = re.sub("\<","" ,newzbin_game_title_strip)
newzbin_game_title_strip = re.sub("\>","" ,newzbin_game_title_strip)
#replaces spaces with + used for searching gamerankings
gamerankings_search_title = re.sub(" ","+" ,newzbin_game_title)
#create cache of game titles and check cachefile, skip if match found
cachefile=file(cachelog, "a")
cachefile.close()
cachefile=file(cachelog,"r")
cacheread=cachefile.readlines()
cachefile.close()
if newzbin_game_title_strip + "\n" not in cacheread:
#write game title to cachelog
cachefile=file(cachelog,"a")
cachefile.write(newzbin_game_title_strip + "\n")
cachefile.close()
gamerankings_search_result = gamerankings_search_url + gamerankings_search_title
try:
sock = urllib.urlopen(gamerankings_search_result)
gamerankings_search_result_page = sock.read()
sock.close()
except:
print("Error: RSS Feed Tag Error")
main_logger.error("RSS Feed Tag Error")
traceback.print_exc(file=open(tracelog,"a"))
os.system(notifylog)
try:
#######################
# check filter values #
#######################
if (isInWatched(newzbin_game_title_strip) == 1):
VisInWatched = 1
else:
VisInWatched = 0
if ((isInWatched(newzbin_game_title_strip) == 1) and (isInNZB(newzbin_game_title_strip) == 1) and (isCompleted(newzbin_game_title_strip) == 1) and (isGoodMatch(gamerankings_search_result_page) == 1) and (isBadSearch(gamerankings_search_result_page) == 1)) and ((isGoodRatings(gamerankings_search_result_page) == 1) or (isGoodTitle(newzbin_game_title_strip) == 1)):
report_id = node.getElementsByTagName("report:id")[0].childNodes[0].data
download(report_id)
else:
print("---------------------------")
print("Status: Skipping Game.....")
print("Release Game Title: " + newzbin_game_title)
print("NZB Filename: " + newzbin_game_title_strip)
print("")
except:
print("Error: Filter Value Check Error")
main_logger.error("Filter Value Check Error")
traceback.print_exc(file=open(tracelog,"a"))
os.system(notifylog)
#############
# Debugging #
#############
#file system checks
if (isCompleted(newzbin_game_title_strip) == 0):
print("Debug: (File System Check) Game Exists In Completed Folder")
if (VisInWatched == 0):
print("Debug: (File System Check) NZB Exists In Watch Folder")
if (isInNZB(newzbin_game_title_strip) == 0):
print("Debug: (File System Check) NZB Exists In NZB Folder")
#gamerankings website checks
if (isBadSearch(gamerankings_search_result_page) == 0):
print("Debug: (Gamerankings Website Check) No Results For Game Title")
elif (isGoodMatch(gamerankings_search_result_page) == 0):
print("Debug: (Gamerankings Website Check) Search Result NOT Equal To Release Title")
elif (isGoodTitle(newzbin_game_title_strip) == 1):
print("Debug: (Gamerankings Website Check) Title Is In Exempt List")
elif (isGoodRatings(gamerankings_search_result_page) == 0):
print("Debug: (Gamerankings Website Check) Rating Below Threshold")
else:
print("ping failed")