Reaperxxxx commited on
Commit
ff4da35
·
verified ·
1 Parent(s): 5e10416

Create server.js

Browse files
Files changed (1) hide show
  1. server.js +140 -0
server.js ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const axios = require('axios');
3
+ const cheerio = require('cheerio');
4
+ const stringSimilarity = require('string-similarity');
5
+
6
+ const app = express();
7
+ const PORT = 3000;
8
+ const baseURL = "https://www.tokyoinsider.com/anime/";
9
+
10
+ app.get('/anime/:name/:episode', async (req, res) => {
11
+ const animeName = decodeURIComponent(req.params.name).trim();
12
+ const episodeNumber = req.params.episode;
13
+ const firstLetter = animeName[0].toUpperCase();
14
+ const categoryURL = `${baseURL}${firstLetter}`;
15
+
16
+ console.log(`Fetching: ${categoryURL}`);
17
+
18
+ try {
19
+ let response = await axios.get(categoryURL);
20
+ let html = response.data;
21
+ let $ = cheerio.load(html);
22
+
23
+ let animeLinks = {};
24
+
25
+ $('a[href*="/anime/"]').each((i, link) => {
26
+ let title = $(link).text().trim();
27
+ let href = $(link).attr('href');
28
+
29
+ if (title && href) {
30
+ animeLinks[title] = `https://www.tokyoinsider.com${href}`;
31
+ }
32
+ });
33
+
34
+ if (Object.keys(animeLinks).length === 0) {
35
+ return res.status(404).json({ error: "No anime found." });
36
+ }
37
+
38
+ let bestMatch = findClosestMatch(animeName, Object.keys(animeLinks));
39
+
40
+ if (bestMatch) {
41
+ let episodeURL = `${animeLinks[bestMatch]}/episode/${episodeNumber}`;
42
+ console.log(`Anime Found: ${bestMatch}`);
43
+ console.log(`Episode URL: ${episodeURL}`);
44
+
45
+ let downloads = await getEpisodeDownloads(episodeURL);
46
+
47
+ if (downloads.length === 0) {
48
+ return res.status(404).json({ error: "No download links found." });
49
+ }
50
+
51
+ let categorizedDownloads = categorizeDownloads(downloads);
52
+
53
+ let responseObj = {
54
+ anime: bestMatch,
55
+ episode: episodeNumber,
56
+ episodeURL,
57
+ ...categorizedDownloads
58
+ };
59
+
60
+ return res.json(responseObj);
61
+ } else {
62
+ return res.status(404).json({ error: "No close match found." });
63
+ }
64
+ } catch (error) {
65
+ console.error("Error:", error.message);
66
+ return res.status(500).json({ error: "Server error." });
67
+ }
68
+ });
69
+
70
+ async function getEpisodeDownloads(episodeURL) {
71
+ console.log(`Fetching Episode Page: ${episodeURL}`);
72
+
73
+ try {
74
+ let response = await axios.get(episodeURL);
75
+ let html = response.data;
76
+ let $ = cheerio.load(html);
77
+
78
+ let downloads = [];
79
+
80
+ $('.c_h2, .c_h2b').each((i, div) => {
81
+ let linkElement = $(div).find('a[href*="media.tokyoinsider.com"]');
82
+ let infoElement = $(div).find('.finfo');
83
+
84
+ if (linkElement.length > 0 && infoElement.length > 0) {
85
+ let title = linkElement.text().trim();
86
+ let url = linkElement.attr('href');
87
+ let sizeText = infoElement.find('b').eq(0).text();
88
+ let downloadsCount = infoElement.find('b').eq(1).text();
89
+ let uploader = infoElement.find('b').eq(2).text();
90
+ let addedOn = infoElement.find('b').eq(3).text();
91
+
92
+ let size = parseSize(sizeText);
93
+
94
+ if (size > 0) {
95
+ downloads.push({ title, url, size, downloadsCount, uploader, addedOn });
96
+ }
97
+ }
98
+ });
99
+
100
+ return downloads;
101
+ } catch (error) {
102
+ console.error("Error fetching episode page:", error.message);
103
+ return [];
104
+ }
105
+ }
106
+
107
+ function categorizeDownloads(downloads) {
108
+ let resolutions = { "360p": null, "720p": null, "1080p": null };
109
+
110
+ downloads.forEach(d => {
111
+ if (d.size >= 25 && d.size < 100 && !resolutions["360p"]) {
112
+ resolutions["360p"] = d;
113
+ } else if (d.size >= 100 && d.size < 400 && !resolutions["720p"]) {
114
+ resolutions["720p"] = d;
115
+ } else if (d.size >= 400 && !resolutions["1080p"]) {
116
+ resolutions["1080p"] = d;
117
+ }
118
+ });
119
+
120
+ return resolutions;
121
+ }
122
+
123
+ function parseSize(sizeText) {
124
+ let size = parseFloat(sizeText);
125
+
126
+ if (sizeText.includes("GB")) {
127
+ size *= 1024;
128
+ }
129
+
130
+ return isNaN(size) ? 0 : size;
131
+ }
132
+
133
+ function findClosestMatch(query, animeList) {
134
+ let bestMatch = stringSimilarity.findBestMatch(query, animeList);
135
+ return bestMatch.bestMatch.rating > 0.5 ? bestMatch.bestMatch.target : null;
136
+ }
137
+
138
+ app.listen(PORT, () => {
139
+ console.log(`Server running on http://localhost:${PORT}`);
140
+ });