Browse Source

A bit of code reformating and add an option to regenerate the .crpersistant file in case it become corrupted and Crunchy try to redownload everything.

Godzil 6 years ago
parent
commit
7f668c0cbe
6 changed files with 109 additions and 45 deletions
  1. 3 1
      package-lock.json
  2. 1 1
      package.json
  3. 6 2
      src/batch.ts
  4. 14 1
      src/episode.ts
  5. 1 0
      src/interface/IConfig.d.ts
  6. 84 40
      src/my_request.ts

+ 3 - 1
package-lock.json

@@ -7,7 +7,8 @@
     "@types/bluebird": {
       "version": "3.5.20",
       "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.20.tgz",
-      "integrity": "sha512-Wk41MVdF+cHBfVXj/ufUHJeO3BlIQr1McbHZANErMykaCWeDSZbH5erGjNBw2/3UlRdSxZbLfSuQTzFmPOYFsA=="
+      "integrity": "sha512-Wk41MVdF+cHBfVXj/ufUHJeO3BlIQr1McbHZANErMykaCWeDSZbH5erGjNBw2/3UlRdSxZbLfSuQTzFmPOYFsA==",
+      "dev": true
     },
     "@types/caseless": {
       "version": "0.12.1",
@@ -57,6 +58,7 @@
       "version": "4.1.41",
       "resolved": "https://registry.npmjs.org/@types/request-promise/-/request-promise-4.1.41.tgz",
       "integrity": "sha512-qlx6COxSTdSFHY9oX9v2zL1I05hgz5lwqYiXa2SFL2nDxAiG5KK8rnllLBH7k6OqzS3Ck0bWbxlGVdrZhS6oNw==",
+      "dev": true,
       "requires": {
         "@types/bluebird": "3.5.20",
         "@types/request": "2.47.0"

+ 1 - 1
package.json

@@ -34,10 +34,10 @@
   },
   "devDependencies": {
     "@types/bluebird": "^3.5.20",
-    "@types/request-promise": "^4.1.41",
     "@types/cheerio": "^0.22.7",
     "@types/mkdirp": "^0.5.2",
     "@types/request": "^2.47.0",
+    "@types/request-promise": "^4.1.41",
     "@types/xml2js": "^0.4.2",
     "tsconfig-lint": "^0.12.0",
     "tslint": "^5.9.1",

+ 6 - 2
src/batch.ts

@@ -6,7 +6,8 @@ import log = require('./log');
 import series from './series';
 
 /* correspondances between resolution and value CR excpect */
-const resol_table: { [id: string]: IResolData; } = {
+const resol_table: { [id: string]: IResolData; } =
+{
     360:  {quality: '60', format: '106'},
     480:  {quality: '61', format: '106'},
     720:  {quality: '62', format: '106'},
@@ -28,7 +29,9 @@ export default function(args: string[], done: (err?: Error) => void)
     {
       config.video_format = resol_table[config.resolution].format;
       config.video_quality = resol_table[config.resolution].quality;
-    } catch (e) {
+    }
+    catch (e)
+    {
       log.warn(`Invalid resolution ${config.resolution}p. Setting to 1080p`);
       config.video_format = resol_table['1080'].format;
       config.video_quality = resol_table['1080'].quality;
@@ -178,5 +181,6 @@ function parse(args: string[]): IConfigLine
     .option('-n, --filename <s>', 'The name override.')
     .option('-t, --tag <s>', 'The subgroup. (Default: CrunchyRoll)')
     .option('-r, --resolution <s>', 'The video resolution. (Default: 1080 (360, 480, 720, 1080))')
+    .option('-g, --rebuildcrp', 'Rebuild the crpersistant file.')
     .parse(args);
 }

+ 14 - 1
src/episode.ts

@@ -57,7 +57,8 @@ function fileExist(path: string)
   {
     fs.statSync(path);
     return true;
-  } catch (e)
+  }
+  catch (e)
   {
     return false;
   }
@@ -82,6 +83,13 @@ function download(config: IConfig, page: IEpisodePage, player: IEpisodePlayer, d
   if (fileExist(filePath + '.mkv'))
   {
     let count = 0;
+
+    if (config.rebuildcrp)
+    {
+      log.warn('Adding \'' + fileName + '\' to the DB...');
+      return done(null, false);
+    }
+
     log.warn('File \'' + fileName + '\' already exist...');
 
     do
@@ -94,6 +102,11 @@ function download(config: IConfig, page: IEpisodePage, player: IEpisodePlayer, d
     log.warn('Renaming to \'' + fileName + '\'...');
   }
 
+  if (config.rebuildcrp)
+  {
+    return done(null, true);
+  }
+
   mkdirp(path.dirname(filePath), (errM: Error) =>
   {
     if (errM)

+ 1 - 0
src/interface/IConfig.d.ts

@@ -17,4 +17,5 @@ interface IConfig {
   resolution?: string;
   video_format?: string;
   video_quality?: string;
+  rebuildcrp?: boolean;
 }

+ 84 - 40
src/my_request.ts

@@ -13,28 +13,34 @@ const cloudscraper = require('cloudscraper');
 let isAuthenticated = false;
 let isPremium = false;
 
-const defaultHeaders: request.Headers = {
+const defaultHeaders: request.Headers = 
+{
   'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
   'Connection': 'keep-alive',
   'Referer': 'https://www.crunchyroll.com/login',
 };
 
-function generateDeviceId(): string {
-	let id = '';
-	const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+function generateDeviceId(): string 
+{
+  let id = '';
+  const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 
-	for (let i = 0; i < 32; i++) {
-		id += possible.charAt(Math.floor(Math.random() * possible.length));
-	}
+  for (let i = 0; i < 32; i++) 
+  {
+      id += possible.charAt(Math.floor(Math.random() * possible.length));
+  }
 
-	return id;
+  return id;
 }
 
-function startSession(): Promise<string> {
-  return rp({
+function startSession(): Promise<string> 
+{
+  return rp(
+  {
     method: 'GET',
     url: 'https://api.crunchyroll.com/start_session.0.json',
-    qs: {
+    qs: 
+    {
       device_id: generateDeviceId(),
       device_type: 'com.crunchyroll.iphone',
       access_token: 'QWjz212GspMHH9h',
@@ -43,16 +49,20 @@ function startSession(): Promise<string> {
     },
     json: true,
   })
-  .then((response: any) => {
+  .then((response: any) => 
+  {
     return response.data.session_id;
   });
 }
 
-function login(sessionId: string, user: string, pass: string): Promise<any> {
-  return rp({
+function login(sessionId: string, user: string, pass: string): Promise<any>
+{
+  return rp(
+  {
     method: 'POST',
     url: 'https://api.crunchyroll.com/login.0.json',
-    form: {
+    form: 
+    {
       account: user,
       password: pass,
       session_id: sessionId,
@@ -60,7 +70,8 @@ function login(sessionId: string, user: string, pass: string): Promise<any> {
     },
     json: true,
   })
-  .then((response) => {
+  .then((response) =>
+  {
     if (response.error) throw new Error('Login failed: ' + response.message);
     return response.data;
   });
@@ -71,13 +82,17 @@ function login(sessionId: string, user: string, pass: string): Promise<any> {
 /**
  * Performs a GET request for the resource.
  */
-export function get(config: IConfig, options: string|request.Options, done: (err: Error, result?: string) => void) {
-  authenticate(config, (err) => {
-    if (err) {
+export function get(config: IConfig, options: string|request.Options, done: (err: Error, result?: string) => void)
+{
+  authenticate(config, (err) =>
+  {
+    if (err)
+    {
       return done(err);
     }
 
-    cloudscraper.request(modify(options, 'GET'), (error: Error, response: any, body: any) => {
+    cloudscraper.request(modify(options, 'GET'), (error: Error, response: any, body: any) =>
+    {
       if (error) return done(error);
       done(null, typeof body === 'string' ? body : String(body));
     });
@@ -87,14 +102,21 @@ export function get(config: IConfig, options: string|request.Options, done: (err
 /**
  * Performs a POST request for the resource.
  */
-export function post(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void) {
-  authenticate(config, (err) => {
-    if (err) {
+export function post(config: IConfig, options: request.Options, done: (err: Error, result?: string) => void)
+{
+  authenticate(config, (err) =>
+  {
+    if (err)
+    {
         return done(err);
     }
 
-    cloudscraper.request(modify(options, 'POST'), (error: Error, response: any, body: any) => {
-      if (error) return done(error);
+    cloudscraper.request(modify(options, 'POST'), (error: Error, response: any, body: any) =>
+    {
+      if (error)
+      {
+         return done(error);
+      }
       done(null, typeof body === 'string' ? body : String(body));
     });
   });
@@ -103,30 +125,39 @@ export function post(config: IConfig, options: request.Options, done: (err: Erro
 /**
  * Authenticates using the configured pass and user.
  */
-function authenticate(config: IConfig, done: (err: Error) => void) {
-  if (isAuthenticated || !config.pass || !config.user) {
+function authenticate(config: IConfig, done: (err: Error) => void)
+{
+  if (isAuthenticated || !config.pass || !config.user)
+  {
       return done(null);
   }
 
   startSession()
-  .then((sessionId: string) => {
+  .then((sessionId: string) =>
+  {
     defaultHeaders.Cookie = `sess_id=${sessionId}; c_locale=enUS`;
     return login(sessionId, config.user, config.pass);
   })
-  .then((userData) => {
+  .then((userData) =>
+  {
     /**
      * The page return with a meta based redirection, as we wan't to check that everything is fine, reload
      * the main page. A bit convoluted, but more sure.
      */
-    const options = {
+    const options =
+    {
       headers: defaultHeaders,
       jar: true,
       url: 'http://www.crunchyroll.com/',
       method: 'GET',
     };
 
-    cloudscraper.request(options, (err: Error, rep: string, body: string) => {
-      if (err) return done(err);
+    cloudscraper.request(options, (err: Error, rep: string, body: string) =>
+    {
+      if (err)
+      {
+         return done(err);
+      }
 
       const $ = cheerio.load(body);
 
@@ -134,24 +165,31 @@ function authenticate(config: IConfig, done: (err: Error) => void) {
       const regexps = /ga\('set', 'dimension[5-8]', '([^']*)'\);/g;
       const dims = regexps.exec($('script').text());
 
-      for (let i = 1; i < 5; i++) {
-        if ((dims[i] !== undefined) && (dims[i] !== '') && (dims[i] !== 'not-registered')) {
+      for (let i = 1; i < 5; i++)
+      {
+        if ((dims[i] !== undefined) && (dims[i] !== '') && (dims[i] !== 'not-registered'))
+        {
             isAuthenticated = true;
         }
 
-        if ((dims[i] === 'premium') || (dims[i] === 'premiumplus')) {
+        if ((dims[i] === 'premium') || (dims[i] === 'premiumplus'))
+        {
             isPremium = true;
         }
       }
 
-      if (isAuthenticated === false) {
+      if (isAuthenticated === false)
+      {
         const error = $('ul.message, li.error').text();
         return done(new Error('Authentication failed: ' + error));
       }
 
-      if (isPremium === false) {
+      if (isPremium === false)
+      {
           log.warn('Do not use this app without a premium account.');
-      } else {
+      }
+      else
+      {
           log.info('You have a premium account! Good!');
       }
       done(null);
@@ -165,11 +203,17 @@ function authenticate(config: IConfig, done: (err: Error) => void) {
  */
 function modify(options: string|request.Options, reqMethod: string): request.Options
 {
-  if (typeof options !== 'string') {
+  if (typeof options !== 'string')
+  {
     options.jar = true;
     options.headers = defaultHeaders;
     options.method = reqMethod;
     return options;
   }
-  return { jar: true, headers: defaultHeaders, url: options.toString(), method: reqMethod };
+  return { 
+    jar: true, 
+    headers: defaultHeaders, 
+    url: options.toString(), 
+    method: reqMethod 
+  };
 }