Turn audio into a shareable video. forked from nypublicradio/audiogram

index.js 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Dependencies
  2. var express = require("express"),
  3. compression = require("compression"),
  4. path = require("path"),
  5. multer = require("multer"),
  6. uuid = require("uuid"),
  7. mkdirp = require("mkdirp");
  8. // Routes and middleware
  9. var logger = require("../lib/logger/"),
  10. render = require("./render.js"),
  11. status = require("./status.js"),
  12. fonts = require("./fonts.js"),
  13. errorHandlers = require("./error.js");
  14. // Settings
  15. var serverSettings = require("../lib/settings/");
  16. var fs = require("fs"),
  17. bodyParser = require("body-parser");
  18. var app = express();
  19. var jsonParser = bodyParser.json();
  20. // var urlencodedParser = bodyParser.urlencoded({ extended: false });
  21. app.use(compression());
  22. app.use(logger.morgan());
  23. const uid = uuid.v1();
  24. // Options for where to store uploaded audio and max size
  25. var fileOptions = {
  26. storage: multer.diskStorage({
  27. destination: function(req, file, cb) {
  28. var dir = path.join(serverSettings.workingDirectory, uid);
  29. mkdirp(dir, function(err) {
  30. return cb(err, dir);
  31. });
  32. },
  33. filename: function(req, file, cb) {
  34. cb(null, file.fieldname);
  35. }
  36. })
  37. };
  38. var newThemeFileOptions = {
  39. storage: multer.diskStorage({
  40. destination: function(req, file, cb) {
  41. var dir = path.join(serverSettings.themeStoragePath);
  42. mkdirp(dir, function(err) {
  43. return cb(err, dir);
  44. });
  45. },
  46. filename: function(req, file, cb) {
  47. cb(null, file.originalname);
  48. }
  49. })
  50. };
  51. if (serverSettings.maxUploadSize) {
  52. fileOptions.limits = {
  53. fileSize: +serverSettings.maxUploadSize
  54. };
  55. newThemeFileOptions.limits = {
  56. fileSize: +serverSettings.maxUploadSize
  57. };
  58. }
  59. // On submission, check upload, validate input, and start generating a video
  60. const mt = multer(fileOptions).fields([{name: 'audio'}, {name: 'subtitle'}]);
  61. app.post("/submit/", [mt, render.validate, render.route]);
  62. // Upload new theme
  63. app.post("/theme/upload/", [multer(newThemeFileOptions).single("newTheme"), function (req, res) {
  64. var themesFile = path.join(serverSettings.settingsPath, "themes.json");
  65. fs.readFile(themesFile, "utf8", function readFileCallback(err, data) {
  66. if (err) {
  67. console.log('err', err);
  68. res.send(JSON.stringify({status: 500, error: err}));
  69. } else {
  70. var caption = req.body.newCaption;
  71. var themes = JSON.parse(data);
  72. themes[caption] = {
  73. "backgroundImage": req.file.filename
  74. };
  75. var jt = JSON.stringify(themes);
  76. fs.writeFile(themesFile, jt, "utf8", function (err) {
  77. if (err) {
  78. console.log(err);
  79. res.send(JSON.stringify({status: 500, error: err}));
  80. }
  81. res.send(JSON.stringify({status: 200, success: "success"}));
  82. });
  83. }
  84. });
  85. }]);
  86. // Delete theme
  87. app.post("/theme/delete/", jsonParser, function (req, res) {
  88. var themesFile = path.join(serverSettings.settingsPath, "themes.json");
  89. fs.readFile(themesFile, "utf8", function readFileCallback(err, data) {
  90. if (err) {
  91. console.log('err', err);
  92. res.send(JSON.stringify({status: 500, error: err}));
  93. } else {
  94. var theme = req.body.theme;
  95. var themes = JSON.parse(data);
  96. if (themes[theme]) {
  97. var background = themes[theme]["backgroundImage"];
  98. if (background) {
  99. var asset = path.join(serverSettings.themeStoragePath, background);
  100. try {
  101. fs.unlink(asset, function(err) {
  102. if (err) {
  103. console.log('err', error);
  104. res.send(JSON.stringify({status: 500, error: err}));
  105. }
  106. delete themes[theme];
  107. var jt = JSON.stringify(themes);
  108. fs.writeFile(themesFile, jt, "utf8", function (err) {
  109. if (err) {
  110. console.log(err);
  111. res.send(JSON.stringify({status: 500, error: err}));
  112. }
  113. res.send(JSON.stringify({status: 200, success: "success"}));
  114. });
  115. });
  116. } catch (err) {
  117. console.log(err);
  118. res.send(JSON.stringify({status: 500, error: err}));
  119. }
  120. }
  121. }
  122. }
  123. });
  124. });
  125. // Save theme
  126. app.post("/theme/save/", jsonParser, function (req, res) {
  127. var themesFile = path.join(serverSettings.settingsPath, "themes.json");
  128. fs.readFile(themesFile, "utf8", function readFileCallback(err, data) {
  129. if (err) {
  130. console.log('err', err);
  131. res.send(JSON.stringify({status: 500, error: err}));
  132. } else {
  133. var theme = req.body.theme;
  134. var themes = JSON.parse(data);
  135. themes[theme.name] = theme;
  136. var jt = JSON.stringify(themes);
  137. fs.writeFile(themesFile, jt, "utf8", function (err) {
  138. if (err) {
  139. console.log(err);
  140. res.send(JSON.stringify({status: 500, error: err}));
  141. }
  142. res.send(JSON.stringify({status: 200, success: "success"}));
  143. });
  144. }
  145. });
  146. });
  147. // Theme editor
  148. app.use("/theme/", express.static(path.join(__dirname, "..", "editor/theme.html")));
  149. // If not using S3, serve videos locally
  150. if (!serverSettings.s3Bucket) {
  151. app.use("/video/", express.static(path.join(serverSettings.storagePath, "video")));
  152. }
  153. // Serve custom fonts
  154. app.get("/fonts/fonts.css", fonts.css);
  155. app.get("/fonts/fonts.js", fonts.js);
  156. if (serverSettings.fonts) {
  157. app.get("/fonts/:font", fonts.font);
  158. }
  159. // Check the status of a current video
  160. app.get("/status/:id/", status);
  161. // Serve background images and themes JSON statically
  162. app.use("/settings/", function(req, res, next) {
  163. // Limit to themes.json and bg images
  164. if (req.url.match(/^\/?themes.json$/i) || req.url.match(/^\/?backgrounds\/[^/]+$/i)) {
  165. return next();
  166. }
  167. return res.status(404).send("Cannot GET " + path.join("/settings", req.url));
  168. }, express.static(path.join(__dirname, "..", "settings")));
  169. // Serve editor files statically
  170. app.use(express.static(path.join(__dirname, "..", "editor")));
  171. app.use(errorHandlers);
  172. module.exports = app;