diff options
| author | jwansek <eddie.atten.ea29@gmail.com> | 2019-01-07 20:03:02 +0000 | 
|---|---|---|
| committer | jwansek <eddie.atten.ea29@gmail.com> | 2019-01-07 20:03:02 +0000 | 
| commit | cdecedef83a73ab8d1011f22e1549d6013897c13 (patch) | |
| tree | 1fba64a306e196ce96e04a30b9cd64f2353933de | |
| download | SmallYTChannelBot-cdecedef83a73ab8d1011f22e1549d6013897c13.tar.gz SmallYTChannelBot-cdecedef83a73ab8d1011f22e1549d6013897c13.zip | |
added YouTube API features
| -rw-r--r-- | .gitignore | 108 | ||||
| -rw-r--r-- | LICENSE | 21 | ||||
| -rw-r--r-- | SmallYTChannelBotSubmissions.py | 315 | ||||
| -rw-r--r-- | archive_posts.py | 25 | ||||
| -rw-r--r-- | database.py | 95 | ||||
| -rw-r--r-- | onceaday.py | 9 | ||||
| -rw-r--r-- | runprog.py | 23 | ||||
| -rw-r--r-- | test_ytapi.py | 69 | ||||
| -rw-r--r-- | ytapi.py | 90 | 
9 files changed, 755 insertions, 0 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b220d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,108 @@ +login.py +graph.png + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.vs/ +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +#  Usually these files are written by a python script from a template +#  before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 jwansek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/SmallYTChannelBotSubmissions.py b/SmallYTChannelBotSubmissions.py new file mode 100644 index 0000000..110baa5 --- /dev/null +++ b/SmallYTChannelBotSubmissions.py @@ -0,0 +1,315 @@ +from mpl_toolkits.axes_grid1 import host_subplot +import mpl_toolkits.axisartist as AA +from imgurpython import ImgurClient +import matplotlib.pyplot as plt +from operator import itemgetter +from database import Database +import matplotlib +import datetime +import ytapi +import login +import time +import praw +import re +import os + +reddit = login.REDDIT + +subreddit = reddit.subreddit("SmallYTChannel") +#subreddit = reddit.subreddit("jwnskanzkwktest") + +db = Database() + +def get_time(): +    #this is not the correct way to do this but I don't care +    return str(datetime.datetime.now().time())[:8] + +def get_lambda_from_flair(s): +    result = re.search("\[(.*)\]", s) +    if result is not None and "λ" in result.group(1): +        return result.group(1) +    else: +        return "" + +def update_users_flair(comment): +    username = str(comment.author) +    flairscore = get_lambda_from_flair(str(comment.author_flair_text)) +    flairtext = comment.author_flair_text +    if flairtext is None: +        flairtext = "" +    else: +        flairtext = str(flairtext.replace("[%s] " % flairscore, "")) +    if username in [str(i) for i in subreddit.moderator()] + ["AutoModerator"]: +        newflair = "[∞λ] %s" % (flairtext) +    else: +        actualscore = db.get_lambda(username)[0] +        newflair = "[%iλ] %s" % (actualscore, flairtext) +    subreddit.flair.set(redditor = username, text = newflair) + +def get_mods(): +    return [str(i) for i in subreddit.moderator()] + ["AutoModerator"] + +def _make_graph(data): +    fig = plt.figure() +     +    lambdaCount = [i[1] for i in data] +    helpGiven = [i[2] for i in data] +    uniqueUsers = [i[3] for i in data] +    date = [datetime.datetime.strptime(i[4], "%Y-%m-%d") for i in data] + +    fig, ax1 = plt.subplots() +    ax1.plot(date, lambdaCount, label = "Total λ given", color = "r") +    ax1.set_ylabel("Total λ / help given") + +    ax1.plot(date, helpGiven, label = "Times help given", color = "g") +     +    ax2 = ax1.twinx() +    ax2.plot(date, uniqueUsers, label = "Unique users") +    ax2.set_ylabel("No. Unique Users") + +    ax1.legend() +    ax2.legend(loc = 4) +    fig.autofmt_xdate() + +    filepath = "graph.png" +    fig.savefig(filepath) +    return filepath + +def _update_tables(scores, data): +    content = "" +    date = str(datetime.date.today()) +    mods = get_mods() +    imagepath = _make_graph(data) +    imageurl = _upload_image(imagepath, date) +    bylambda = [i for i in sorted(scores, key = itemgetter(1), reverse = True) if i[0] not in mods][:10] +    byhelps = sorted(scores, key = itemgetter(2), reverse = True)[:10] + +    subreddit.stylesheet.upload("wikigraph", imagepath) + +    content += "\n\n##/r/SmallYTChannel lambda tables: %s" % date + +    content += "\n\n###By lambda:" +    content += "\n\nUsername|Lambda|Help given\n:--|:--|:--" +    for line in bylambda: +        content += "\n/u/%s|%i|%i" % (line[0], line[1], line[2]) + +    content += "\n\n###By Help given:" +    content += "\n\nUsername|Lambda|Help given\n:--|:--|:--" +    for line in byhelps: +        λ = str(line[1]) +        if line[0] in mods: +            λ = "∞" +        content += "\n/u/%s|%s|%i" % (line[0], λ, line[2]) + +    content += "\n\n##Statistics from %s:\n\n\n\nTotal λ given|Useful advice given|Unique users\n:--|:--|:--\n%i|%i|%i" % (date, data[-1][1], data[-1][2], data[-1][3]) +     +    reddit.subreddit("u_SmallYTChannelBot").submit("/r/SmallYTChannel Statistics: %s" % date, url = imageurl).reply(content).mod.distinguish(sticky = True) + +    subreddit.wiki["lambdatables"].edit(content, reason = "Update: %s" % date) +    subreddit.wiki[date].edit(content, reason = "Update: %s" % date) + +    currentdata = subreddit.wiki["index"].content_md +    currentdata += "\n\n* [%s](/r/SmallYTChannel/wiki/%s)" % (date, date) + +    subreddit.wiki["index"].edit(currentdata, reason = "Update: %s" % date) + +def _upload_image(path, date): +    client = login.IMGUR + +    config = { +		'album': None, +		'name':  'SmallYTChannelBot Statistics graph: %s' % date, +		'title': 'SmallYTChannelBot Statistics graph: %s' % date, +		'description': 'SmallYTChannelBot Statistics graph: %s' % date +    } + +    image = client.upload_from_path(path, config = config) + +    return "https://i.imgur.com/%s.png" % image["id"] + +def every_day(): +    db.update_stats() +    _update_tables(db.get_scores(), db.get_stats()) + +def main(): +    tail = "\n\n\n ^/u/SmallYTChannelBot ^*made* ^*by* ^/u/jwnskanzkwk. ^*PM* ^*for* ^*bug* ^*reports.* ^*For* ^*more* ^*information,* ^*read* ^*the* ^[FAQ.](https://www.reddit.com/user/SmallYTChannelBot/comments/a4u7qj/smallytchannelbot_faq/)" + +    comment_stream = subreddit.stream.comments(pause_after=-1) +    submission_stream = subreddit.stream.submissions(pause_after=-1) +    while True: +        try: +            for comment in comment_stream: +                if comment is None: +                    break +                if not db.id_in_blacklist(comment.id): +                    db.add_to_blacklist(comment.id) + +                    if "!mylambda" in comment.body.lower() and str(comment.author) != "SmallYTChannelBot": +                        author = str(comment.author) +                        λ, links = db.get_lambda(author) +                        if author in get_mods(): +                            text = "/u/%s is a moderator, and therefore has ∞λ." % author +                        else: +                            if λ == 0: +                                text = "/u/%s has 0λ." % author +                            else: +                                text = "/u/%s has %iλ, from helping the following posts:" % (author, λ) +                                count = 0 +                                for link in links: +                                    if "www.reddit.com" not in link: +                                        link = "https://www.reddit.com" + link + +                                    #set a max limit on the number of times this will iterate to stop it +                                    #breaking because of Reddit's character limit. +                                    count += 1 +                                    text += "\n\n- [%s](%s)" % (reddit.submission(url = link).title, link) +                                    if count > 20:  #experminent with this number +                                        text += "\n\n[%i more...]" % len(links) - count +                                        break + +                        reply = comment.reply(text + tail) +                        reply.mod.distinguish(sticky = False) +                        update_users_flair(comment) + + +                    if "!givelambda" in comment.body.lower() and str(comment.author) != "SmallYTChannelBot": +                        submission = comment.submission +                        parentauthour = str(comment.parent().author) +                        op = str(comment.author) +                        if op == parentauthour: +                            text = "You cannot give yourself λ." +                        elif parentauthour == "SmallYTChannelBot": +                            text = "Please only give lambda to humans." +                        elif str(comment.author) in get_mods(): +                            text = "The moderator /u/%s has given /u/%s 1λ. /u/%s now has %iλ." % (str(comment.author), parentauthour, parentauthour, db.get_lambda(parentauthour)[0] + 1) +                            db.give_lambda(parentauthour, submission.permalink)  +                        elif op != str(submission.author): +                            text = "Only the OP can give λ." +                        elif db.user_given_lambda(parentauthour, str(submission.permalink)): +                            text = "You have already given /u/%s λ for this submission. Why not give λ to another user instead?" % parentauthour +                        else: +                            print("[%s] '/u/%s' has given '/u/%s' lambda!" % (get_time(), op, parentauthour)) +                            text = "You have given /u/%s 1λ. /u/%s now has %iλ" % (parentauthour, parentauthour, db.get_lambda(parentauthour)[0] + 1) +                            +                            if not db.link_in_db(submission.permalink) or not db.link_in_db(submission.permalink.replace("https://www.reddit.com", "")): +                                db.give_lambda(parentauthour, submission.permalink, op) +                                print("The OP has received lambda too!") +                            else: +                                db.give_lambda(parentauthour, submission.permalink) +                         +                        update_users_flair(comment) +                        update_users_flair(comment.parent()) +                        reply = comment.reply(text + tail) +                        reply.mod.distinguish() + +                if comment.body[:11] == "!takelambda" and str(comment.author) in get_mods(): +                    try: +                        splitted = comment.body.split() +                        user = splitted[1].replace("/u/", "") +                        toremove = int(splitted[2]) +                        reason = " ".join(splitted[3:]) +                         +                        text = "/u/%s has had %iλ taken away from them for the reason '%s'. /u/%s now has %iλ" % (user, toremove, reason, user, db.get_lambda(user)[0] - toremove) +                        db.change_lambda(user, -toremove) +                    except Exception as e: +                        print("[ERROR while removing λ] %s" % e) +                        text = r"An error was encountered. Please use the syntax `!takelambda [user] [how much to remove {integer}] [reason]`" +                        reply = comment.reply(text + tail) +                        reply.mod.distinguish() +                        continue + +                    update_users_flair(comment.parent()) +                    reply = comment.reply(text + tail) +                    reply.mod.distinguish() + +       +            for submission in submission_stream: +                if submission is None: +                    break +                if not db.id_in_blacklist(submission.id): +                    db.add_to_blacklist(submission.id)                          +                    print("[%s] There has been a new submission: '%s', with flair '%s'" % (get_time(), submission.title, submission.link_flair_text)) + +                    if str(submission.author) not in get_mods(): +                        score = db.get_lambda(str(submission.author))[0] +                        if submission.link_flair_text in ["Discussion", "Meta", "Collab"]: +                            if "youtube.com" in str(submission.url) or "youtu.be" in str(submission.url): +                                text = "Your post has been removed because it has the wrong flair. [Discussion], [Meta] and [Collab] flairs are only for text submissions." +                                submission.mod.remove() +                            else: +                                text = "Your post is a discussion, meta or collab post so it costs 0λ." +                        else: +                            if score < 3: +                                text = """Thank you for submitting to /r/SmallYTChannel. Unfortunally, you submission has been removed since you do not have enough λ. You need +                                3λ to post. You currently have %iλ. For more information, read the [FAQ](https://www.reddit.com/user/SmallYTChannelBot/comments/a4u7qj/smallytchannelbot_faq/)""" % score +                                submission.mod.remove() +                            else: +                                text = """Thank you for submitting to /r/SmallYTChannel. You have spent 3λ to submit here, making your current balance %iλ. +                                /u/%s, please comment `!givelambda` to the most helpful advice you are given. You +                                will be rewarded 1λ if you do so.  For more information, read the [FAQ](https://www.reddit.com/user/SmallYTChannelBot/comments/a4u7qj/smallytchannelbot_faq/)""" % (score - 3, str(submission.author)) +                                db.change_lambda(str(submission.author), -3) + +                                ytid = ytapi.get_videoId_from_url(submission.url) +                                if "/" not in ytid: +                                    ytdata = ytapi.get_video_data(ytid) + +                                    text += """ +\n\n\n##Video data: + +Field|Data +:-|:- +Title|%s +Thumbnail|[Link](%s) +Views|%s +Length|%s +Likes/Dislikes|%s/%s +Comments|%s +Description|%s + +##Channel Data: + +Field|Data +:-|:- +Name|%s +Thumbnail|[Link](%s) +Subscribers|%s +Videos|%s +Views|%s +                                    """ % ( +                                        ytdata["title"], +                                        ytdata["thumbnail"], +                                        ytdata["views"], +                                        ytdata["length"], +                                        ytdata["likes"], +                                        ytdata["dislikes"], +                                        ytdata["comments"], +                                        ytdata["description"], +                                        ytdata["channel"], +                                        ytdata["channelThumb"], +                                        ytdata["subscribers"], +                                        ytdata["videos"], +                                        ytdata["channelViews"] +                                    ) + +                                    curflair = submission.link_flair_text +                                    if str(curflair) != "None": +                                        submission.mod.flair(" %s | %s | :youtube: %s" % (curflair, ytdata["length"], ytdata["channel"])) +                                    else:     +                                        submission.mod.flair("%s | :youtube: %s" % (ytdata["length"], ytdata["channel"])) + +                        update_users_flair(submission) +                        reply = submission.reply(text + tail) +                        reply.mod.distinguish(sticky = True) + +        except Exception as e: +            print("[ERROR]\t%s" % e) +            continue + +if __name__ == "__main__": +    #file = open("pid.txt", "w") +    #file.write(str(os.getpid())) +    #file.close() + +    print("\n####################\n[%s] RESTARTED\n####################\n" % get_time()) +    main() + diff --git a/archive_posts.py b/archive_posts.py new file mode 100644 index 0000000..a68feaf --- /dev/null +++ b/archive_posts.py @@ -0,0 +1,25 @@ +import praw +import database +import login + +reddit = login.REDDIT + +subreddit = reddit.subreddit("jwnskanzkwktest") +db = database.Database() + +comment_stream = subreddit.stream.comments(pause_after=-1) +submission_stream = subreddit.stream.submissions(pause_after=-1) +while True: +    for comment in comment_stream: +        if comment is None: +            break +        if not db.id_in_blacklist(comment.id): +            print("archived: ", comment.id) +            db.add_to_blacklist(comment.id) + +    for submission in submission_stream: +        if submission is None: +            break +        if not db.id_in_blacklist(submission.id): +            print("archived: ", submission.id) +            db.add_to_blacklist(submission.id)
\ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..26b8e43 --- /dev/null +++ b/database.py @@ -0,0 +1,95 @@ +import sqlite3 + +class Database: +    def __init__(self):    +        self.connection = sqlite3.connect("SmallYTChannelDatabase.db") +        self.cursor = self.connection.cursor() + +    def change_lambda(self, user, changeby): +        #this will make it go negative. You must check this operation is allowed. +        self.cursor.execute("UPDATE users SET lambda = ((SELECT lambda FROM users WHERE user_name = ?) + ?) WHERE user_name = ?;", (user, changeby, user)) +        self.connection.commit() + +    def give_lambda(self, user, link, op = None): +        def give(user, link = None): +            #check if the user has an entry in the database +            self.cursor.execute("SELECT userID FROM users WHERE user_name = ?;", (user, )) +            try: +                id_ = self.cursor.fetchone()[0] +            except TypeError: +                #the user isn't in the database +                self.cursor.execute("INSERT INTO users (user_name, lambda) VALUES (?, 1);", (user, )) +                self.connection.commit() +                if link is not None: +                    self.cursor.execute("INSERT INTO lambdas (userID, permalink) VALUES ((SELECT userID FROM users WHERE user_name = ?), ?);", (user, link)) +            else: +                #update their lambda and add to lambdas +                self.change_lambda(user, 1) +                if link is not None: +                    self.cursor.execute("INSERT INTO lambdas (userID, permalink) VALUES (?, ?);", (id_, link)) +         +            self.connection.commit() + +        #give one lambda to both the user and the OP +        give(user, link) +        if op is not None: +            give(op) + +    def get_lambda(self, user): +        self.cursor.execute("SELECT lambda FROM users WHERE user_name = ?", (user, )) +        try: +            lambda_ = self.cursor.fetchone()[0] +        except TypeError: +            #the user isn't in the database, and therefore has no lambda  +            return 0, [] +        else: +            self.cursor.execute("SELECT permalink FROM lambdas WHERE userID = (SELECT userID FROM users WHERE user_name = ?);", (user, )) +            links = [i[0] for i in self.cursor.fetchall()] + +            return lambda_, links + +    def link_in_db(self, link): +        self.cursor.execute("SELECT permalink FROM lambdas;") +        try: +            links = [i[0] for i in self.cursor.fetchall()] +        except TypeError: +            links = [] + +        return link in links + +    def add_to_blacklist(self, id): +        self.cursor.execute("INSERT INTO blacklist (prawID) VALUES (?);", (id, )) +        self.connection.commit() + +    def id_in_blacklist(self, id): +        self.cursor.execute("SELECT prawID FROM blacklist;") +        try: +            ids = [i[0] for i in self.cursor.fetchall()] +        except TypeError: +            ids = [] + +        return id in ids + +    def get_scores(self): +        self.cursor.execute("SELECT users.user_name, users.lambda, COUNT(users.user_name) FROM lambdas INNER JOIN users ON users.userID = lambdas.userID GROUP BY users.user_name;") +        return self.cursor.fetchall() + +    def update_stats(self): +        query = """INSERT INTO stats (lambdaCount, helpGiven, uniqueUsers, date) VALUES ( +        (SELECT SUM(lambda) FROM users), +        (SELECT COUNT(lambdaID) FROM lambdas), +        (SELECT COUNT(user_name) FROM users), +        (SELECT strftime('%Y-%m-%d')));""" + +        self.cursor.execute(query) +        self.connection.commit() + +    def get_stats(self): +        self.cursor.execute("SELECT * FROM stats;") +        return self.cursor.fetchall() + +    def user_given_lambda(self, user, permalink): +        links = self.get_lambda(user)[1] +        return permalink in links or permalink.replace("https://www.reddit.com", "") in links + +         diff --git a/onceaday.py b/onceaday.py new file mode 100644 index 0000000..a84b0d9 --- /dev/null +++ b/onceaday.py @@ -0,0 +1,9 @@ +import SmallYTChannelBotSubmissions +from time import sleep + +SECONDS_IN_DAY = 25 * 60 * 60 + +while True: +    SmallYTChannelBotSubmissions.every_day() +    print("Called @ %s" % SmallYTChannelBotSubmissions.get_time) +    sleep(SECONDS_IN_DAY) diff --git a/runprog.py b/runprog.py new file mode 100644 index 0000000..a564678 --- /dev/null +++ b/runprog.py @@ -0,0 +1,23 @@ +from time import sleep +import subprocess +import multiprocessing + +def thread_(): +    subprocess.run(["python3", "SmallYTChannelBotSubmissions.py"]) + +while True: +    thread = multiprocessing.Process(target = thread_, args = ()) +    thread.start() + +    sleep(60 * 60 * 2) + +    #print("closing...") +    #file = open("pid.txt", "r") +    #pid = file.readlines()[0] +    #file.close() + +    #subprocess.run(["kill", pid]) +    thread.terminate() + +    #print("killed ", pid) + diff --git a/test_ytapi.py b/test_ytapi.py new file mode 100644 index 0000000..44f439f --- /dev/null +++ b/test_ytapi.py @@ -0,0 +1,69 @@ +import praw +import database +import login +import ytapi + +reddit = login.REDDIT + +subreddit = reddit.subreddit("jwnskanzkwktest") + +tail = "\n\n\n ^/u/SmallYTChannelBot ^*made* ^*by* ^/u/jwnskanzkwk. ^*PM* ^*for* ^*bug* ^*reports.* ^*For* ^*more* ^*information,* ^*read* ^*the* ^[FAQ.](https://www.reddit.com/user/SmallYTChannelBot/comments/a4u7qj/smallytchannelbot_faq/)" + +submission_stream = subreddit.stream.submissions(pause_after=-1) +while True: + +    for submission in submission_stream: +        if submission is not None: + +            text = "Thank you for submitting..." +            ytid = ytapi.get_videoId_from_url(submission.url) +            if "/" not in ytid: +                ytdata = ytapi.get_video_data(ytid) + +                text += """ +\n\n\n##Video data: + +Field|Data +:-|:- +Title|%s +Thumbnail|[Link](%s) +Views|%s +Length|%s +Likes/Dislikes|%s/%s +Comments|%s +Description|%s + +##Channel Data: + +Field|Data +:-|:- +Name|%s +Thumbnail|[Link](%s) +Subscribers|%s +Videos|%s +Views|%s + +                """ % ( +                    ytdata["title"], +                    ytdata["thumbnail"], +                    ytdata["views"], +                    ytdata["length"], +                    ytdata["likes"], +                    ytdata["dislikes"], +                    ytdata["comments"], +                    ytdata["description"], +                    ytdata["channel"], +                    ytdata["channelThumb"], +                    ytdata["subscribers"], +                    ytdata["videos"], +                    ytdata["channelViews"] +                ) + +                curflair = submission.link_flair_text +                if str(curflair) != "None": +                    submission.mod.flair(" %s | %s | :youtube: %s" % (curflair, ytdata["length"], ytdata["channel"])) +                else:     +                    submission.mod.flair("%s | :youtube: %s" % (ytdata["length"], ytdata["channel"])) + +                reply = submission.reply(text + tail) +                reply.mod.distinguish(sticky = True) diff --git a/ytapi.py b/ytapi.py new file mode 100644 index 0000000..b472b7e --- /dev/null +++ b/ytapi.py @@ -0,0 +1,90 @@ +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError +import js2py + +ERROR_DICT =  { +        "title": "ERROR Video deleted?", +        "description": "ERROR Video deleted?", +        "channel": "ERROR Video deleted?", +        "subscribers": "ERROR Video deleted?", +        "videos": "ERROR Video deleted?", +        "channelViews": "ERROR Video deleted?", +        "channelThumb": "ERROR Video deleted?", +        "thumbnail": "ERROR Video deleted?", +        "length": "ERROR Video deleted?", +        "views": "ERROR Video deleted?", +        "likes": "ERROR Video deleted?", +        "dislikes": "ERROR Video deleted?", +        "comments": "ERROR Video deleted?" +    } + +# Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps +# tab of +#   https://cloud.google.com/console +# Please ensure that you have enabled the YouTube Data API for your project. +DEVELOPER_KEY = 'AIzaSyBQsuU5GgCTZdFi7cBmPQHWZwIa545zLUE' +YOUTUBE_API_SERVICE_NAME = 'youtube' +YOUTUBE_API_VERSION = 'v3' + +#run JavaScript because I don't understand regular expressions so we can copy this bad boy from Stack Overflow +get_videoId_from_url = js2py.eval_js(r"""function $(url){ +                            var re = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube(?:-nocookie)?\.com\S*?[^\w\s-])([\w-]{11})(?=[^\w-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig; +                            return url.replace(re, '$1'); +                        }""") + +def _yt_time_to_norm(time): +    if time == "ERROR Video deleted?": +        return time + +    time = time.replace("M", ":")[2:].replace("S", "") + +    s = time.split(":") +    if len(s) > 1: +        if len(s[1]) < 2: +            time = s[0] + ":" + s[1] + "0" + +    return time + +#this would be better as a class but I can't be bothered so dictionary it is +def get_video_data(videoId): +    youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY) + + +    #youTubeData = youtube.videos().list(part = "snippet", id = videoId).execute()["items"][0]["snippet"] + +    #return {"title": youTubeData["title"], "description": youTubeData["description"], "tags": youTubeData["tags"]} + +    try: +        youTubeData = youtube.videos().list(part = "snippet,contentDetails,statistics", id = videoId).execute()["items"][0] +    except IndexError: +        return ERROR_DICT + +    snippet = youTubeData["snippet"] +    length = youTubeData["contentDetails"]["duration"] +    stats = youTubeData["statistics"] +    channelId = snippet["channelId"] + +    channelData = youtube.channels().list(part = 'snippet,statistics', id = channelId).execute()["items"][0] + +    return { +        "title": snippet["title"], +        "description": snippet["description"].replace("\n", "⤶"), +        "channel": channelData["snippet"]["title"], +        "subscribers": channelData["statistics"]["subscriberCount"], +        "videos": channelData["statistics"]["videoCount"], +        "channelViews": channelData["statistics"]["viewCount"], +        "channelThumb": channelData["snippet"]["thumbnails"]["high"]["url"], +        "thumbnail": snippet["thumbnails"]["high"]["url"], +        "length": _yt_time_to_norm(length), +        "views": stats["viewCount"], +        "likes": stats["likeCount"], +        "dislikes": stats["dislikeCount"], +        "comments": stats["commentCount"] +    } + + +if __name__ == '__main__': +    try: +        print(get_channel_data("https://www.youtube.com/watch?v=XPpAkggrdaU&feature=youtu.be")) +    except HttpError as e: +        print('An HTTP error %d occurred:\n%s' % (e.resp.status, e.content))
\ No newline at end of file | 
