request.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. 'use strict';
  2. import request = require('request');
  3. import cheerio = require('cheerio');
  4. import log = require('./log');
  5. var isAuthenticated = false;
  6. var isPremium = false;
  7. var defaultHeaders: request.Headers = {
  8. 'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
  9. 'Connection': 'keep-alive'
  10. };
  11. /**
  12. * Performs a GET request for the resource.
  13. */
  14. export function get(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
  15. authenticate(config, err => {
  16. if (err) return done(err);
  17. request.get(modify(options), (err: Error, response: any, body: any) => {
  18. if (err) return done(err);
  19. done(null, typeof body === 'string' ? body : String(body));
  20. });
  21. });
  22. }
  23. /**
  24. * Performs a POST request for the resource.
  25. */
  26. export function post(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
  27. authenticate(config, err => {
  28. if (err) return done(err);
  29. request.post(modify(options), (err: Error, response: any, body: any) => {
  30. if (err) return done(err);
  31. done(null, typeof body === 'string' ? body : String(body));
  32. });
  33. });
  34. }
  35. /**
  36. * Authenticates using the configured pass and user.
  37. */
  38. function authenticate(config: IConfig, done: (err: Error) => void) {
  39. if (isAuthenticated || !config.pass || !config.user) return done(null);
  40. /* Bypass the login page and send a login request directly */
  41. var options =
  42. {
  43. headers: defaultHeaders,
  44. jar: true,
  45. gzip: false,
  46. url: 'https://www.crunchyroll.com/?a=formhandler&formname=RpcApiUser_Login&name=' + config.user + '&password=' + config.pass
  47. };
  48. request(options, (err: Error, rep: string, body: string) =>
  49. {
  50. if (err) return done(err);
  51. /* The page return with a meta based redirection, as we wan't to check that everything is fine, reload
  52. * the main page. A bit convoluted, but more sure.
  53. */
  54. var options =
  55. {
  56. headers: defaultHeaders,
  57. jar: true,
  58. url: 'http://www.crunchyroll.com/'
  59. };
  60. request(options, (err: Error, rep: string, body: string) =>
  61. {
  62. if (err) return done(err);
  63. var $ = cheerio.load(body);
  64. /* Check if auth worked */
  65. var regexps = /ga\(\'set\', \'dimension[5-8]\', \'([^']*)\'\);/g;
  66. var dims = regexps.exec($('script').text());
  67. for (var i = 1; i < 5; i++)
  68. {
  69. if ((dims[i] !== undefined) && (dims[i] !== '') && (dims[i] !== 'not-registered')) { isAuthenticated = true; }
  70. if ((dims[i] === 'premium') || (dims[i] === 'premiumplus')) { isPremium = true; }
  71. }
  72. if (isAuthenticated === false)
  73. {
  74. var error = $('ul.message, li.error').text();
  75. return done(new Error('Authentication failed: ' + error));
  76. }
  77. if (isPremium === false) { log.warn('Do not use this app without a premium account.'); }
  78. else { log.info('You have a premium account! Good!'); }
  79. done(null);
  80. });
  81. });
  82. }
  83. /**
  84. * Modifies the options to use the authenticated cookie jar.
  85. */
  86. function modify(options: string|request.Options): request.Options {
  87. if (typeof options !== 'string') {
  88. options.jar = true;
  89. options.headers = defaultHeaders;
  90. return options;
  91. }
  92. return {jar: true, headers: defaultHeaders, url: options.toString()};
  93. }