├── LICENSE ├── Procfile ├── README.md ├── app.py ├── memeGenerator.py └── requirements.txt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Rasesh Shetty 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn --bind 0.0.0.0:$PORT app:app -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reddit Meme API 2 | JSON API for a random meme scraped from reddit. 3 | 4 | API Link : [https://reddit-meme-api.herokuapp.com/](https://reddit-meme-api.herokuapp.com/) 5 | 6 | **Example Response:** 7 | 8 | ```jsonc 9 | { 10 | 11 | "code": 200, 12 | "post_link": "https://redd.it/kadq22", 13 | "subreddit": "AdviceAnimals", 14 | "title": "The struggle is real during these trying times.", 15 | "url": "https://i.redd.it/di9suwomhc461.jpg", 16 | "ups": 22471, 17 | "author": "bobbydigital_ftw", 18 | "spoilers_enabled": true, 19 | "nsfw": false, 20 | "image_previews": [ 21 | "https://preview.redd.it/di9suwomhc461.jpg?width=108&crop=smart&auto=webp&s=8c033387866f4a2ff608abf3f8cce8507518866c", 22 | "https://preview.redd.it/di9suwomhc461.jpg?width=216&crop=smart&auto=webp&s=85ea6bc35101b9fd76bbbd1c17a1df3889e21e62", 23 | "https://preview.redd.it/di9suwomhc461.jpg?width=320&crop=smart&auto=webp&s=263b77afd27714f155a94f15578b042f968cc688" 24 | ] 25 | 26 | } 27 | ``` 28 | > Note: While using the API always confirm that the response for `"code"` is 200, else there is some error!!! 29 | 30 | ## Custom Endpoints 31 | 32 | ### Specify count (MAX 200) 33 | 34 | In order to get multiple memes in a single request specify the count with the following endpoint. 35 | 36 | Endpoint: [/{count}](https://reddit-meme-api.herokuapp.com/2) 37 | 38 | Example: [https://reddit-meme-api.herokuapp.com/2](https://reddit-meme-api.herokuapp.com/2) 39 | 40 | Response: 41 | 42 | ```jsonc 43 | { 44 | 45 | "code": 200, 46 | "count": 2, 47 | "memes": [ 48 | { 49 | "post_link": "https://redd.it/kgvsku", 50 | "subreddit": "MemeEconomy", 51 | "title": "Easy Investment", 52 | "url": "https://i.redd.it/9xsdu34x0d661.jpg", 53 | "ups": 7439, 54 | "author": "KingEmperio", 55 | "spoilers_enabled": true, 56 | "nsfw": false, 57 | "image_previews": [ 58 | "https://preview.redd.it/9xsdu34x0d661.jpg?width=108&crop=smart&auto=webp&s=f24bfe89b3946b4c9fe8d37d475582067953cafd", 59 | "https://preview.redd.it/9xsdu34x0d661.jpg?width=216&crop=smart&auto=webp&s=ce659a23b9983ac821b0a0a2bfe4fb2243750e08", 60 | "https://preview.redd.it/9xsdu34x0d661.jpg?width=320&crop=smart&auto=webp&s=c3bfb292653ab689cc0b9ce6b20371e320fc7020", 61 | "https://preview.redd.it/9xsdu34x0d661.jpg?width=640&crop=smart&auto=webp&s=96d04ad834466addf1a9482a17a6a1d92e5f86dd", 62 | "https://preview.redd.it/9xsdu34x0d661.jpg?width=960&crop=smart&auto=webp&s=e0d74c2cf387326927838cd777b54eee7eb83462", 63 | "https://preview.redd.it/9xsdu34x0d661.jpg?width=1080&crop=smart&auto=webp&s=b3dea7a7fc38dbfd2764a8d08af0fdf449e6e3d8" 64 | ] 65 | }, 66 | { 67 | "post_link": "https://redd.it/kgfk5v", 68 | "subreddit": "MemeEconomy", 69 | "title": "How much is this meme template worth?", 70 | "url": "https://i.redd.it/2j5r9myud7661.jpg", 71 | "ups": 127, 72 | "author": "ABC0012300", 73 | "spoilers_enabled": true, 74 | "nsfw": false, 75 | "image_previews": [ 76 | "https://preview.redd.it/2j5r9myud7661.jpg?width=108&crop=smart&auto=webp&s=879677b7b53b9612b35d04b7182edae85e778599", 77 | "https://preview.redd.it/2j5r9myud7661.jpg?width=216&crop=smart&auto=webp&s=f933ed1d55d0effbd196afd52cb2e755e683a9c1", 78 | "https://preview.redd.it/2j5r9myud7661.jpg?width=320&crop=smart&auto=webp&s=e921fb4b46920bc72efba8a477ced020a8c16c49" 79 | ] 80 | } 81 | ] 82 | 83 | } 84 | ``` 85 | > Not all memes have image preview so it is suggested to use the `"url"` endpoint's result 86 | 87 | ### Specify Subreddit 88 | 89 | By default the API grabs a random meme from '_memes_', '_dankmemes_', '_AdviceAnimals_','_MemeEconomy_','__me_irl__', 90 | '_ComedyCemetery_' and '_terriblefacebookmemes_'subreddits. To provide your own custom subreddit use the following endpoint. 91 | 92 | Endpoint: [/{subreddit}](https://reddit-meme-api.herokuapp.com/wholesomememes) 93 | 94 | Example: [https://reddit-meme-api.herokuapp.com/wholesomememes](https://reddit-meme-api.herokuapp.com/wholesomememes) 95 | 96 | Response: 97 | 98 | ```json 99 | { 100 | "code": 200, 101 | "post_link": "https://redd.it/kgx7gq", 102 | "subreddit": "wholesomememes", 103 | "title": "Good looking cookiea", 104 | "url": "https://i.redd.it/hn2axo0zed661.jpg", 105 | "ups": 36563, 106 | "author": "the_mean_guy_is_here", 107 | "spoilers_enabled": true, 108 | "nsfw": false, 109 | "image_previews": [ 110 | "https://preview.redd.it/hn2axo0zed661.jpg?width=108&crop=smart&auto=webp&s=e3cf46f9200d4d9ad71ea4e8a12741b1c83aa7a9", 111 | "https://preview.redd.it/hn2axo0zed661.jpg?width=216&crop=smart&auto=webp&s=acee023286903da15e977b2cc62346529dec359b", 112 | "https://preview.redd.it/hn2axo0zed661.jpg?width=320&crop=smart&auto=webp&s=b7e9973afcb785a821b8dfd9f2e20763465653a1", 113 | "https://preview.redd.it/hn2axo0zed661.jpg?width=640&crop=smart&auto=webp&s=695d53f60ae2e7bb353a85a26997175904c8fbe6" 114 | ] 115 | }, 116 | ``` 117 | 118 | ### Specify Subreddit Count (MAX 200) 119 | 120 | In order to get a custom number of memes from a specific subreddit provide the name of the subreddit and the count in the following endpoint. 121 | 122 | Endpoint: [/{subreddit}/{count}](https://reddit-meme-api.herokuapp.com/wholesomememes/2/) 123 | 124 | Example: [https://reddit-meme-api.herokuapp.com/wholesomememes/2](https://reddit-meme-api.herokuapp.com/wholesomememes/2/) 125 | 126 | Response: 127 | 128 | ```json 129 | { 130 | 131 | "code": 200, 132 | "count": 2, 133 | "memes": [ 134 | { 135 | "post_link": "https://redd.it/kgx7gq", 136 | "subreddit": "wholesomememes", 137 | "title": "Good looking cookiea", 138 | "url": "https://i.redd.it/hn2axo0zed661.jpg", 139 | "ups": 36563, 140 | "author": "the_mean_guy_is_here", 141 | "spoilers_enabled": true, 142 | "nsfw": false, 143 | "image_previews": [ 144 | "https://preview.redd.it/hn2axo0zed661.jpg?width=108&crop=smart&auto=webp&s=e3cf46f9200d4d9ad71ea4e8a12741b1c83aa7a9", 145 | "https://preview.redd.it/hn2axo0zed661.jpg?width=216&crop=smart&auto=webp&s=acee023286903da15e977b2cc62346529dec359b", 146 | "https://preview.redd.it/hn2axo0zed661.jpg?width=320&crop=smart&auto=webp&s=b7e9973afcb785a821b8dfd9f2e20763465653a1", 147 | "https://preview.redd.it/hn2axo0zed661.jpg?width=640&crop=smart&auto=webp&s=695d53f60ae2e7bb353a85a26997175904c8fbe6" 148 | ] 149 | }, 150 | { 151 | "post_link": "https://redd.it/kh1svx", 152 | "subreddit": "wholesomememes", 153 | "title": "yes yes yes", 154 | "url": "https://i.redd.it/upypw6gtke661.jpg", 155 | "ups": 1945, 156 | "author": "patrickpotato07", 157 | "spoilers_enabled": true, 158 | "nsfw": false, 159 | "image_previews": [ 160 | "https://preview.redd.it/upypw6gtke661.jpg?width=108&crop=smart&auto=webp&s=fea3a1b77bf574dd42d9c890c56e4b99f27f3002", 161 | "https://preview.redd.it/upypw6gtke661.jpg?width=216&crop=smart&auto=webp&s=6d79463760e9a53be595dd95fe249390c574a03f", 162 | "https://preview.redd.it/upypw6gtke661.jpg?width=320&crop=smart&auto=webp&s=8738d682e8059ec5ef0cb1cecf980888cfdb33f2", 163 | "https://preview.redd.it/upypw6gtke661.jpg?width=640&crop=smart&auto=webp&s=70a37d8e5d9f9020942f2f85f30cb393f4e59f4f" 164 | ] 165 | } 166 | ] 167 | 168 | } 169 | ``` 170 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | from memeGenerator import ScrapMemes 3 | 4 | # Making a flask app 5 | app = Flask(__name__) 6 | # setting flask jsonify to not sort dictionary keys while returning as API 7 | app.config['JSON_SORT_KEYS'] = False 8 | 9 | 10 | # Random Meme Generator 11 | @app.route('/') 12 | def meme_api(): 13 | result = ScrapMemes() 14 | return jsonify(result) 15 | 16 | # Numbered Meme Generator 17 | @app.route('//') 18 | def meme_api_no(num): 19 | result = ScrapMemes(num=num) 20 | return jsonify(result) 21 | 22 | # Topic wise Meme Generator 23 | @app.route('//') 24 | def meme_api_topic(topic): 25 | result = ScrapMemes(topic=topic) 26 | return jsonify(result) 27 | 28 | # Topicwise and numbered meme generator 29 | @app.route('///') 30 | def meme_api_topic_and_no(topic, num): 31 | result = ScrapMemes(topic=topic, num=num) 32 | return jsonify(result) 33 | 34 | 35 | if __name__ == "__main__": 36 | # running the flask app in threaded mode 37 | # to allow handling more requests at once 38 | app.run(threaded=True) 39 | -------------------------------------------------------------------------------- /memeGenerator.py: -------------------------------------------------------------------------------- 1 | import praw 2 | from random import choice 3 | import os 4 | 5 | reddit = praw.Reddit(client_id=os.getenv("CLIENT_ID"), 6 | client_secret=os.getenv("CLIENT_SECRET"), 7 | user_agent=os.getenv("USER_AGENT") 8 | ) 9 | 10 | TOPICS = [ # Default Topics When No Topic is given!! 11 | "dankmemes", 12 | "memes", 13 | "AdviceAnimals", 14 | "MemeEconomy", 15 | "me_irl", 16 | "ComedyCemetery", 17 | "terriblefacebookmemes" 18 | ] 19 | 20 | 21 | def ScrapMemes(topic=0, num=1): 22 | ''' 23 | topic: The Name Of Subreddit to search for memes.. If default will choose random topic from the TOPICS list 24 | 25 | Each subreddit has five different ways of organizing the topics created by redditors: .hot, .new, .controversial, .top, and .gilded. You can also use .search("SEARCH_KEYWORDS") to get only results matching an engine search. 26 | ''' 27 | try: 28 | if num <= 0: 29 | return { 30 | "code": 400, 31 | "message": "Enter a positive Number less than 200" 32 | } 33 | result = {} 34 | num = num % 200 35 | if topic == 0: 36 | topic = choice(TOPICS) 37 | if num == 1: 38 | subreddit = reddit.subreddit(topic) 39 | meme = subreddit.random() 40 | try: 41 | _ = meme.preview 42 | result = { 43 | "code":200, 44 | "post_link": meme.shortlink, 45 | "subreddit": topic, 46 | "title": meme.title, 47 | "url": meme.url, 48 | "ups": meme.ups, 49 | "author": meme.author.name, 50 | "spoilers_enabled": subreddit.spoilers_enabled, 51 | "nsfw": subreddit.over18, 52 | "image_previews": [i["url"] for i in meme.preview.get("images")[0].get("resolutions")] 53 | } 54 | except Exception as e: 55 | result = { 56 | 57 | "post_link": meme.shortlink, 58 | "subreddit": topic, 59 | "title": meme.title, 60 | "url": meme.url, 61 | "ups": meme.ups, 62 | "author": meme.author.name, 63 | "spoilers_enabled": subreddit.spoilers_enabled, 64 | "nsfw": subreddit.over18, 65 | "image_previews": ["No Preview Found For This Meme.. Sorry For That"] 66 | } 67 | else: 68 | subreddit = reddit.subreddit(topic) 69 | submissions = subreddit.random_rising(limit=num) 70 | result = { 71 | "code": 200, 72 | "count": num, 73 | "memes": [] 74 | } 75 | for meme in submissions: 76 | try: 77 | _ = meme.preview 78 | item = { 79 | 80 | "post_link": meme.shortlink, 81 | "subreddit": topic, 82 | "title": meme.title, 83 | "url": meme.url, 84 | "ups": meme.ups, 85 | "author": meme.author.name, 86 | "spoilers_enabled": subreddit.spoilers_enabled, 87 | "nsfw": subreddit.over18, 88 | "image_previews": [i["url"] for i in meme.preview.get("images")[0].get("resolutions")] 89 | } 90 | except Exception as e: 91 | item = { 92 | 93 | "post_link": meme.shortlink, 94 | "subreddit": topic, 95 | "title": meme.title, 96 | "url": meme.url, 97 | "ups": meme.ups, 98 | "author": meme.author.name, 99 | "spoilers_enabled": subreddit.spoilers_enabled, 100 | "nsfw": subreddit.over18, 101 | "image_previews": ["No Preview Found For This Meme.. Sorry For That"] 102 | } 103 | result.get("memes").append(item) 104 | return result 105 | 106 | except Exception as e: 107 | return { 108 | "code": 400, 109 | "message": str(type(e))+str(e), 110 | "help": "Subreddit Doesn't Exist, Check if u spelled it correctly.." 111 | } 112 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2020.12.5 2 | chardet==4.0.0 3 | click==7.1.2 4 | Flask==1.1.2 5 | gunicorn==20.0.4 6 | idna==2.10 7 | itsdangerous==1.1.0 8 | Jinja2==2.11.2 9 | MarkupSafe==1.1.1 10 | praw==7.1.0 11 | prawcore==1.5.0 12 | requests==2.25.1 13 | six==1.15.0 14 | update-checker==0.18.0 15 | urllib3==1.26.2 16 | websocket-client==0.57.0 17 | Werkzeug==1.0.1 18 | --------------------------------------------------------------------------------