# JabberminorBot for reddit, on the subreddit /r/CynicalBrit.
# Created by Jabberminor, with source code help from AndrewNeo in the form of groompbot.
# Huge thanks to stephen_j and The1RGood for helping me out.
# The idea of this bot is post a comment to the video thread containing information about the video.
 
import sys
import time
import logging
import json
import praw
import gdata.youtube
import gdata.youtube.service
import thread

# YouTube functions
def getUserUploads(username):
    """Get YouTube uploads by username."""
    yt_service = gdata.youtube.service.YouTubeService()
    uri = "http://gdata.youtube.com/feeds/api/users/%s/uploads" % username
    return yt_service.GetYouTubeVideoFeed(uri + "?max-results=25&start-index=20")
 
def getVideoIdFromEntry(entry):
    """Get video ID from a YouTube entry."""
    return entry.id.text.split("/")[-1]
 
# Reddit functions
def getReddit(settings):
    """Get a reference to Reddit."""
    r = praw.Reddit(user_agent=settings["reddit_ua"])
    try:
        r.login(settings["reddit_username"], settings["reddit_password"])
    except:
        logging.exception("Error logging into Reddit.")
        exitApp()
    return r

def getSubreddit(settings, reddit):
    """Get the subreddit."""
    return reddit.get_subreddit(settings["reddit_subreddit"])
 
def submitContent(subreddit, title, link):
    """Submit a link to a subreddit."""
    logging.info("Submitting %s (%s)", (title, link))
    try:
        subreddit.submit(title, url=link)
    except praw.errors.APIException:
        logging.exception("Error on link submission.")
 
def getPastVideos(subreddit):
    """Get all YouTube videos posted in the past hour."""
    hour = subreddit.get_new(limit=25)
    for video in hour:
        if ("youtube" in video.url):
            yield video.url
 
# Main functions
def loadSettings():
    """Load settings from file."""
    try:
        settingsFile = open("TBsettings.json", "r")
    except IOError:
        logging.exception("Error opening TBsettings.json.")
        exitApp()
   
    settingStr = settingsFile.read()
    settingsFile.close()
 
    try:
        settings = json.loads(settingStr)
    except ValueError:
        logging.exception("Error parsing TBsettings.json.")
        exitApp()
   
    # Check integrity
    if (len(settings["reddit_username"]) == 0):
        logging.critical("Reddit username not set.")
        exitApp()
 
    if (len(settings["reddit_password"]) == 0):
        logging.critical("Reddit password not set.")
        exitApp()
 
    if (len(settings["reddit_subreddit"]) == 0):
        logging.critical("Subreddit not set.")
        exitApp()
 
    if (len(settings["reddit_ua"]) == 0):
        logging.critical("Reddit bot user agent not set.")
        exitApp()
 
    if (len(settings["youtube_account"]) == 0):
        logging.critical("YouTube account not set.")
        exitApp()
 
    settings["repost_protection"] = bool(settings["repost_protection"])
 
    # Get last upload position
    try:
        lastUploadFile = open("lastupload.txt", "r")
        lastUpload = lastUploadFile.read()
        lastUploadFile.close()
 
        settings["youtube_lastupload"] = lastUpload
    except IOError:
        logging.info("No last uploaded video found.")
        settings["youtube_lastupload"] = None
 
    return settings
 
def savePosition(position):
    """Write last position to file."""
    lastUploadFile = open("lastupload.txt", "w")
    lastUploadFile.write(position)
    lastUploadFile.close()

def commenter(url):
    url = url.split("?")[1].split("&")[0][2:]
    yt_service = gdata.youtube.service.YouTubeService()
    entry = yt_service.GetYouTubeVideoEntry(video_id=url)
    title = entry.media.title.text
    description = entry.media.description.text.replace("\n\n","\n\n>")
    publish_date = entry.published.text
    seconds = entry.media.duration.seconds
    duration = (str(int(seconds)//60) + " minutes, " + str(int(seconds)%60) + " seconds")
    
    return(("**YouTube channel:** [Total Biscuit](http://www.youtube.com/user/totalhalibut)" +
    "\n\n**Subscribe to channel:** [click here](http://www.youtube.com/subscription_center?add_user=totalhalibut)" +
    "\n\n**Video title:** %s" % title +
    "\n\n**Video published on:** %s" % publish_date +
    "\n\n**Subreddit of The Cynical Brit:** /r/cynicalbrit" +
    "\n\n**Duration:** %s" % duration +
    "\n\n**Description:**\n\n> %s" % description +
    "\n\n***This comment was written by a bot. Any issues, please message me.***")
    )

def containsAuthor(post):
    comments = post.comments
    for c in comments:
        # print c.author + " "
        if(c.author.name == u'Jabberminor'):
            # print "True\n"
            return True
    # print "False\n"    
    return False

def approveComments(sr):
    while True:
        queue = sr.get_mod_queue(limit=50)
        for comment in queue:
            if(comment.author.name == u'Jabberminor'):
                comment.approve()
        time.sleep(150)
     
def exitApp():
    sys.exit(1)
 
def runBot():
    """Start a run of the bot."""
    logging.info("Starting bot.")
    settings = loadSettings()
 
    logging.info("Getting YouTube videos.")
 
    # Download video list
    uploads = getUserUploads(settings["youtube_account"]).entry
    newestUpload = uploads[0]
 
    # Reverse from new to old, to old to new
    uploads.reverse()
   
    # Only get new uploads
    try:
        videoIdList = map(getVideoIdFromEntry, uploads)
        indexOfLastUpload = videoIdList.index(settings["youtube_lastupload"])
        uploads = uploads[indexOfLastUpload + 1:]
        if (len(uploads) == 0):
            logging.info("No new uploads since last run.")
            exitApp()
    except ValueError:
        # Ignore a failure if lastupload value isn't in list
        pass
 
    # Get reddit stuff
    logging.info("Logging into Reddit.")
    reddit = getReddit(settings)
    sr = getSubreddit(settings, reddit)
   
    # Save newest position
    logging.info("Saving position.")
    videoid = getVideoIdFromEntry(newestUpload)
    savePosition(videoid)

    # Post a comment
    var = 1
    while var > 0:
        var += 1
        data = sr.get_new()
        for post in data:
            if not containsAuthor(post):
                post.add_comment(commenter(post.url))
            else:
                break
   
    logging.info("Done!")
 
if __name__ == "__main__":
    max_time = int(60)
    start_time = time.time()  # remember when we started
    while (time.time() - start_time) < max_time:
        logging.basicConfig()
 
        try:
            runBot()
        except SystemExit:
            logging.info("Exit called.")
        except:
            logging.exception("Uncaught exception.")
 
    logging.shutdown()
