|
1 |
| -const fs = require('fs'); |
2 | 1 | const express = require('express');
|
3 | 2 | const multer = require('multer');
|
4 |
| -const bencode = require('bencode'); |
5 |
| -const crypto = require('crypto'); |
6 | 3 | const db = require('./../db');
|
7 |
| -const validator = require('./validator'); |
8 | 4 |
|
9 | 5 | const app = express.Router();
|
10 | 6 |
|
11 |
| -/** |
12 |
| - * Saves torrent file to disk |
13 |
| - * |
14 |
| - * Saves torrent to the path defined in the .env file. |
15 |
| - * Also adds a path property to the torrent Object |
16 |
| - * |
17 |
| - * @param torrent - torrent object |
18 |
| - * @return {Promise<Object>} torrent object with path attached |
19 |
| - */ |
20 |
| -const saveToDisk = async (torrent) => { |
21 |
| - const now = new Date(); |
22 |
| - const month = now.getMonth() + 1; |
23 |
| - const year = now.getFullYear(); |
24 |
| - const path = `${process.env.TORRENT_DIR}${year}/${month}/${ |
25 |
| - torrent.hash |
26 |
| - }.torrent`; |
27 |
| - |
28 |
| - await fs.promises.writeFile(path, Buffer.from(torrent.buffer)); |
29 |
| - torrent.path = path; |
30 |
| - return torrent; |
31 |
| -}; |
32 |
| - |
33 | 7 | const storage = multer.memoryStorage();
|
34 |
| - |
35 | 8 | const upload = multer({ storage });
|
36 | 9 |
|
37 |
| -const hashTorrent = (torrentBuffer) => { |
38 |
| - const hash = crypto.createHash('sha256'); |
39 |
| - const code = `${process.env.SECRET}${torrentBuffer.toString( |
40 |
| - 'utf8' |
41 |
| - )}${Math.floor(new Date().getTime() / 1000).toString()}`; |
42 |
| - hash.update(code); |
43 |
| - return hash.digest('hex'); |
44 |
| -}; |
45 |
| - |
46 |
| -/** |
47 |
| - * Processes a torrent |
48 |
| - * |
49 |
| - * Removes trackers from torrent |
50 |
| - * Adds fileList and hash fields to the torrent |
51 |
| - * |
52 |
| - * @param torrent - torrent object |
53 |
| - * @return {Object} torrent object with buffer and hash attached |
54 |
| - */ |
55 |
| -const processTorrent = (torrent) => { |
56 |
| - const decodedTorrent = bencode.decode(torrent.buffer); |
57 |
| - delete decodedTorrent.announce; |
58 |
| - |
59 |
| - torrent.fileList = []; |
60 |
| - torrent.totalFileSize = decodedTorrent.info.files.reduce((total, file) => { |
61 |
| - torrent.fileList.push({ fileName: file.path, fileSize: file.length }); |
62 |
| - total += file.length; |
63 |
| - return total; |
64 |
| - }, 0); |
65 |
| - |
66 |
| - torrent.buffer = bencode.encode(decodedTorrent); |
67 |
| - torrent.hash = hashTorrent(torrent.buffer); |
68 |
| - |
69 |
| - return torrent; |
70 |
| -}; |
71 |
| - |
72 | 10 | const torrentUpload = upload.fields([{ name: 'torrent', maxCount: 1 }]);
|
73 |
| - |
74 | 11 | app.post('/upload', torrentUpload, async (req, res) => {
|
75 | 12 | const release = JSON.parse(req.body.release);
|
76 |
| - const client = await db.pool.connect(); |
77 |
| - |
78 |
| - if (release.torrentType === 'music') { |
79 |
| - const musicReleaseTypes = (await db.getMusicReleaseTypes()).rows; |
80 |
| - const musicQualities = (await db.getMusicQualities()).rows; |
81 |
| - try { |
82 |
| - await validator.validateMusic({ |
83 |
| - release, |
84 |
| - musicReleaseTypes, |
85 |
| - musicQualities |
| 13 | + const torrentFile = req.files.torrent[0]; |
| 14 | + |
| 15 | + try { |
| 16 | + if (release.torrentType === 'music') { |
| 17 | + const { |
| 18 | + torrentId, |
| 19 | + musicId, |
| 20 | + musicReleaseId |
| 21 | + } = await db.createMusicRelease(release, torrentFile); |
| 22 | + return res.json({ |
| 23 | + torrentId, |
| 24 | + musicId, |
| 25 | + musicReleaseId |
86 | 26 | });
|
87 |
| - |
88 |
| - // valid if doesn't throw |
89 |
| - await Promise.all(release.artists.map(validator.validateArtist)); |
90 |
| - |
91 |
| - await db.beginTransaction(client); |
92 |
| - |
93 |
| - let musicId = release.music; |
94 |
| - // insert music if necessary |
95 |
| - if (release.music instanceof Object) { |
96 |
| - // music comes with at least 1 associated artist |
97 |
| - // insert the artist(s) if they are not ids |
98 |
| - const artistsToInsert = release.artists.filter((artist) => |
99 |
| - Object.prototype.hasOwnProperty.call(artist, 'name') |
100 |
| - ); |
101 |
| - const artistIds = release.artists.filter((artist) => |
102 |
| - Object.prototype.hasOwnProperty.call(artist, 'id') |
103 |
| - ); |
104 |
| - const insertedArtists = await db.insertArtists(artistsToInsert, client); |
105 |
| - const artistsToLink = [...artistIds, ...insertedArtists]; |
106 |
| - |
107 |
| - // insert music and assign it to musicId to be used to create the music_release |
108 |
| - const insertMusicRes = await db.insertMusic( |
109 |
| - { |
110 |
| - music: release.music, |
111 |
| - artistsToLink |
112 |
| - }, |
113 |
| - client |
114 |
| - ); |
115 |
| - musicId = insertMusicRes.rows[0].id; |
116 |
| - } |
117 |
| - |
118 |
| - const processedTorrent = processTorrent(req.files.torrent[0]); |
119 |
| - |
120 |
| - // insert torrent |
121 |
| - const torrentRes = await db.insertTorrent( |
122 |
| - { |
123 |
| - fileSize: processedTorrent.totalFileSize, |
124 |
| - originalFileName: processedTorrent.originalname, |
125 |
| - filePath: '/', |
126 |
| - files: processedTorrent.fileList, |
127 |
| - uploaderId: '01D91F1JSSW4X5DNKSVPD2J3EM' |
128 |
| - }, |
129 |
| - client |
130 |
| - ); |
131 |
| - |
132 |
| - const torrentId = torrentRes.rows[0].id; |
133 |
| - |
134 |
| - // insert music release |
135 |
| - await db.insertMusicRelease( |
136 |
| - { musicId, releaseInfo: release.info, torrentId }, |
137 |
| - client |
| 27 | + } |
| 28 | + if (release.torrentType === 'movie') { |
| 29 | + const { |
| 30 | + torrentId, |
| 31 | + movieId, |
| 32 | + videoReleaseId |
| 33 | + } = await db.createMovieRelease(release, torrentFile); |
| 34 | + |
| 35 | + return res.json({ |
| 36 | + torrentId, |
| 37 | + movieId, |
| 38 | + videoReleaseId |
| 39 | + }); |
| 40 | + } |
| 41 | + if (release.torrentType === 'tv') { |
| 42 | + const { torrentId, tvId, videoReleaseId } = await db.createTVRelease( |
| 43 | + release, |
| 44 | + torrentFile |
138 | 45 | );
|
139 | 46 |
|
140 |
| - await db.commitTransaction(client); |
141 |
| - } catch (e) { |
142 |
| - await db.rollbackTransaction(client); |
143 |
| - console.log(e); |
144 |
| - return res.status(400).json({ |
145 |
| - error: e |
| 47 | + return res.json({ |
| 48 | + torrentId, |
| 49 | + tvId, |
| 50 | + videoReleaseId |
146 | 51 | });
|
147 |
| - } finally { |
148 |
| - client.release(); |
149 | 52 | }
|
150 |
| - } else if (release.torrentType === 'movie') { |
151 |
| - try { |
152 |
| - await validator.validateMovie({ |
153 |
| - release |
| 53 | + if (release.torrentType === 'anime') { |
| 54 | + const { |
| 55 | + torrentId, |
| 56 | + animeId, |
| 57 | + videoReleaseId |
| 58 | + } = await db.createAnimeRelease(release, torrentFile); |
| 59 | + |
| 60 | + return res.json({ |
| 61 | + torrentId, |
| 62 | + animeId, |
| 63 | + videoReleaseId |
154 | 64 | });
|
155 |
| - |
156 |
| - await db.beginTransaction(client); |
157 |
| - |
158 |
| - let movieId = release.movie; |
159 |
| - if (release.movie instanceof Object) { |
160 |
| - const movieRes = await db.insertMovie( |
161 |
| - { |
162 |
| - name: release.movie.name, |
163 |
| - description: release.movie.description, |
164 |
| - year: release.movie.year |
165 |
| - }, |
166 |
| - client |
167 |
| - ); |
168 |
| - |
169 |
| - movieId = movieRes.rows[0].id; |
170 |
| - } |
171 |
| - |
172 |
| - const processedTorrent = processTorrent(req.files.torrent[0]); |
173 |
| - |
174 |
| - // insert torrent |
175 |
| - const torrentRes = await db.insertTorrent( |
176 |
| - { |
177 |
| - fileSize: processedTorrent.totalFileSize, |
178 |
| - originalFileName: processedTorrent.originalname, |
179 |
| - filePath: '/', |
180 |
| - files: processedTorrent.fileList, |
181 |
| - uploaderId: '01D91F1JSSW4X5DNKSVPD2J3EM' |
182 |
| - }, |
183 |
| - client |
| 65 | + } |
| 66 | + if (release.torrentType === 'software') { |
| 67 | + const { torrentId, softwareId } = await db.createSoftwareRelease( |
| 68 | + release, |
| 69 | + torrentFile |
184 | 70 | );
|
185 | 71 |
|
186 |
| - const torrentId = torrentRes.rows[0].id; |
187 |
| - |
188 |
| - await db.insertVideoRelease( |
189 |
| - { |
190 |
| - videoId: movieId, |
191 |
| - quality: release.info.quality, |
192 |
| - title: release.info.title, |
193 |
| - description: release.info.description, |
194 |
| - torrentId |
195 |
| - }, |
196 |
| - client |
| 72 | + return res.json({ |
| 73 | + torrentId, |
| 74 | + softwareId |
| 75 | + }); |
| 76 | + } |
| 77 | + if (release.torrentType === 'video-game') { |
| 78 | + const { torrentId, videoGameId } = await db.createVideoGameRelease( |
| 79 | + release, |
| 80 | + torrentFile |
197 | 81 | );
|
198 | 82 |
|
199 |
| - await db.commitTransaction(client); |
200 |
| - } catch (e) { |
201 |
| - await db.rollbackTransaction(client); |
202 |
| - console.log(e); |
203 |
| - return res.status(400).json({ |
204 |
| - error: e |
| 83 | + return res.json({ |
| 84 | + torrentId, |
| 85 | + videoGameId |
205 | 86 | });
|
206 |
| - } finally { |
207 |
| - client.release(); |
208 | 87 | }
|
209 |
| - } else if (release.torrentType === 'tv') { |
210 |
| - } else if (release.torrentType === 'anime') { |
211 |
| - } else if ( |
212 |
| - release.torrentType === 'software' || |
213 |
| - release.torrentType === 'video-game' |
214 |
| - ) { |
215 |
| - } else { |
216 | 88 | return res.sendStatus(400);
|
| 89 | + } catch (e) { |
| 90 | + return res.status(500).json({ |
| 91 | + error: e |
| 92 | + }); |
217 | 93 | }
|
218 |
| - res.sendStatus(200); |
219 | 94 | });
|
220 | 95 |
|
221 | 96 | module.exports = app;
|
0 commit comments