Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Harry260 committed May 16, 2022
0 parents commit 06d5b1f
Show file tree
Hide file tree
Showing 13 changed files with 3,664 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
7 changes: 7 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2022 Harry Tom

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.
96 changes: 96 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Memes Api

<h1 align="center">
<br>
<a href="https://bobthebot.netlify.app/">
<img src="./public/images/icon.png" alt="Bob The Bot" width="200">
</a>
<br>
<a href="https://instagram.com/dragshorts/">Memable API</a><br>
</h1>

<h4 align="center">
Memable is a Meme Explorer website (im working on) and this is a prototype of the API i created for it. It is powered by Rddit!<a href="https://instagram.com/dragshorts/">here</a>
</h4>

<h4 align="center">
<img src="./public/images/Reddit-Logo.png" alt="Bob The Bot" width="200">
</h4>

<hr>

## Table of content

- [Usage](#usage)
- [Endpoints](#endpoints)
- [Deploy](#deploy)
- [Support](#show-your-support)

<br>

## Usage

### Clone the repo

```bat
git clone https://github.com/harry260/meme-api
```

#### Install dependencies

```bat
npm install
```

### Run the server

```bat
npm start
```

<br>

## Endpoints

### `/memes`

```
/memes?subreddits=<subreddit1>,<subreddit>:<last_post_id>&filter=<filter>&max=<max>
```

| Parameter | Description | Example |
| ---------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| subreddits | Comma separated list of subreddits. Use colon to separate if you need to set last post id | subreddits=wholesomememes:`lastIdLOL`,memes,dankmemes |
| filter | Add filter (`hot`\|`top`\|`new`\|`controversial` \| `raising`) | filter=hot |
| max | Maximum number of memes from each subreddit. Doesn't mean the exact count. | max=50 |

````
#### Example request & response
```bat
/memes?subreddits=memes,dankmemes:uc569x,wholesomememes&filter=hot&max=69
````

<a href="./example-response.json">

| Example response |
| ---------------- |

</a>
<br>

## Deploy

You can deploy this to either Vercel or Railway or any other hosting service.

[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/JEAO4v?referralCode=Xot9yF)

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fharry260%2Fmeme-api&project-name=memeable-api&repo-name=meme-api-repo)

## Show your support

Show your support by 🌟 Starring this repo or buy me a coffee!
<br><br>
<a href="https://www.buymeacoffee.com/harrytom" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a><br>
<br>
Empty file added example-response.json
Empty file.
70 changes: 70 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import express from "express";
import getParameterObj from "./lib/utils.js";
import Memes from "./lib/memes.js";
import Reddit from "./lib/reddit.js";
import cors from "cors";
import packageJSON from "./package.json" assert { type: "json" };

const app = express();
const port = process.env.PORT || 4000;

app.use(
cors({
origin: "*",
})
);

app.use("/favicon.ico", express.static("public/images/icon.png"));

app.get(
"/memes",
(req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET");
res.setHeader(
"Access-Control-Allow-Headers",
"X-Requested-With,content-type"
);
res.setHeader("Access-Control-Allow-Credentials", true);

var subreddits = req.query.subreddits;
var max = req.query.max;
var filter = req.query.filter;
var send = false;
var parameters = getParameterObj(subreddits, max, filter);
var meme = new Memes(parameters);

meme.getMultipleSubreddits((data) => {
if (send) return;
send = true;
res.status(200).send(data);
}, parameters.lastIDs);
},
cors()
);

app.get("/reddit/u/:user", (req, res) => {
if (req.params.user) {
var user = req.params.user;

Reddit.getUserInfo(user).then((data) => {
res.send({ success: true, data: data });
});
} else {
res.send({
success: false,
error: "No user specified!",
});
}
});

app.get("/", (req, res) => {
var repoUrl = packageJSON.repository.url.startsWith("git+")
? packageJSON.repository.url.slice(4)
: packageJSON.repository.url;
res.redirect(repoUrl);
});

app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
189 changes: 189 additions & 0 deletions lib/memes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import axios from "axios";
import Reddit from "./reddit.js";

class Memes {
constructor(config = {}) {
// Create an array of one element if parameter is passed as string
if (typeof config.subreddits === "string") {
config.subreddits = [config.subreddits];
}

// Set maxiuum memes
this.max = config.max ?? 10;

var availableFilters = ["top", "hot", "new", "controversial", "rising"];

this.filter = availableFilters.includes(config.filter)
? config.filter
: false;

// Set the subreddit
this.subreddits = config.subreddits ?? [
"memes",
"dankmemes",
"wholesomememes",
];
}

getMultipleSubreddits(callback, lastIds = {}) {
var subreddits = this.subreddits;
var result = {};

console.log("Fetching data from subreddits: ", subreddits);
subreddits.forEach((subreddit, index) => {
var last = lastIds[subreddit] ?? false;
var processedRedditcount = index + 1;

this.getSubreddit(
subreddit,
(data) => {
result[subreddit] = data;
if (processedRedditcount === subreddits.length) {
var finalResult = {
success: true,
data: result,
properties: {
subreddits: subreddits,
max: this.max,
filter: this.filter,
},
};

this._callback(callback, finalResult);
}
},
last
);
});
}

getSubreddit(subreddit, callback, lastid) {
var memes = [];
var url = this._getApiUrl(subreddit, lastid);

this._fetchData(url, (result) => {
var data = result.data;
var processeMemeCount = 0;

if (result.success) {
data.map((meme) => {
processeMemeCount++;
meme = meme.data;

if (!meme.url.endsWith(".jpg")) {
return;
}
var memeResult = {
id: meme.id,
title: meme.title,
url: meme.url,
subreddit: meme.subreddit,
ups: meme.ups,
downs: meme.downs,
score: meme.score,
created: meme.created,
NSFW: meme.over_18,
spoiler: meme.spoiler,
permalink: meme.permalink,
};

Reddit.getUserInfo(meme.author).then((authorResult) => {
authorResult = authorResult.data;
var sr = authorResult.subreddit || {};

var name = sr.title;
var profile = sr.icon_img;
var id = authorResult.name;
var description =
sr.public_description ?? "I love reddit!";

memeResult.author = {
name,
profile,
id,
description,
};

memes.push(memeResult);
if (processeMemeCount === data.length) {
this._callback(callback, memes);
}
});
});
}
});
}

_getAuthorInfo(author, callback) {
this._fetchData(
`https://www.reddit.com/user/${author}/about.json`,
(result) => {
if (result.error === 404) {
this._callback(callback, {
success: false,
error: "User not found!",
});
} else {
this._callback(callback, {
success: true,
data: result.data,
});
}
}
);
}

_fetchData(url, cb) {
axios
.get(url)
.then((response) => {
const data = response.data.data.children;
if (data.length === 0) {
cb({
success: false,
data: "No such subreddit, or it may be private!",
});
} else {
cb({
success: true,
data: data,
});
}
})
.catch((error) => console.log(error));
}

_callback(e, t) {
var data = t ?? {};
const cb = e ?? false;
if (typeof cb === "function") {
cb(data);
}
}

_getApiUrl(subreddit, lId) {
var filter = this.filter;

if (subreddit) {
var params = {};

if (lId) {
params.after = lId;
}
params.limit = this.max;

const sp = new URLSearchParams(params);

var url = `https://www.reddit.com/r/${subreddit}${
filter ? `/${filter}` : ""
}.json?${sp}`;

console.log("Fetching data from URL: ", url);
return url;
} else {
return `https://www.reddit.com/r/memes.json?${this.max}`;
}
}
}

export default Memes;
29 changes: 29 additions & 0 deletions lib/reddit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import axios from "axios";

const Reddit = {
getUserInfo: (username) => {
if (username === "[deleted]") {
var deletedInfo = {
data: {
subreddit: {
title: "Deleted User",
icon_img: "https://www.redditstatic.com/icon.png",
public_description: "This user has been deleted.",
},
name: "[deleted]",
},
};

return new Promise(function (resolve, reject) {
resolve(deletedInfo);
});
}

var url = `https://www.reddit.com/user/${username}/about.json`;
return axios.get(url).then((response) => {
return response.data;
});
},
};

export default Reddit;
Loading

0 comments on commit 06d5b1f

Please sign in to comment.