crextractor 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,31 +1,34 @@
1
1
  # Crextractor
2
2
 
3
- Utility for extracting credentials from the Crunchyroll Android app
3
+ Utility for extracting credentials from the Crunchyroll Android app (both TV and mobile versions).
4
+
5
+ The [credentials](https://github.com/vitalygashkov/crextractor/blob/main/credentials.tv.json) are [automatically](https://github.com/vitalygashkov/crextractor/actions/workflows/extract.yml) updated once a week (if there are any changes).
4
6
 
5
7
  ## Prerequisites
6
8
 
7
9
  - [Node.js](https://nodejs.org/en)
8
10
  - [jadx](https://github.com/skylot/jadx)
9
11
 
10
- ## Installation
12
+ ## Usage
13
+
14
+ ### Library
11
15
 
12
16
  ```bash
13
17
  npm i crextractor
14
18
  ```
15
19
 
16
- ## Usage
17
-
18
- ### Fetching already extracted secrets
20
+ #### Fetch ready credentials from this GitHub repository
19
21
 
20
22
  ```js
23
+ import { pull } from 'crextractor';
24
+
21
25
  async function main() {
22
- const url = 'https://raw.githubusercontent.com/vitalygashkov/crextractor/refs/heads/main/credentials.tv.json';
23
- const data = await fetch(url).then((response) => response.json());
26
+ const credentials = await pull('tv');
24
27
 
25
- // You can use the extracted secrets to obtain access tokens for Crunchyroll APIs
28
+ // You can use the extracted credentials to obtain access tokens for Crunchyroll APIs
26
29
  const response = await fetch('https://beta-api.crunchyroll.com/auth/v1/token', {
27
30
  headers: {
28
- Authorization: data.authorization,
31
+ Authorization: credentials.authorization, // Ready HTTP header in the format `Basic <encoded>`, can be used to access some Crunchyroll APIs
29
32
  'User-Agent': 'Crunchyroll/ANDROIDTV/3.42.1_22267 (Android 16; en-US; sdk_gphone64_x86_64)',
30
33
  // ...
31
34
  },
@@ -37,17 +40,23 @@ async function main() {
37
40
  }
38
41
  ```
39
42
 
40
- #### Library
43
+ #### Extract credentials from the latest APK using jadx
41
44
 
42
45
  ```js
43
46
  import { extract } from 'crextractor';
44
47
 
45
- const { id, secret, encoded, authorization } = await extract();
48
+ async function main() {
49
+ const { id, secret, encoded, authorization } = await extract();
50
+ // id - Crunchyroll app ID
51
+ // secret - Crunchyroll app secret
52
+ // encoded - Base64 encoded `id:secret` string
53
+ // authorization - ready HTTP header in the format `Basic <encoded>`, can be used to access some Crunchyroll APIs
46
54
 
47
- // Do something with the extracted secrets
55
+ // Do something with the extracted credentials
56
+ }
48
57
  ```
49
58
 
50
- #### Command-line interface
59
+ ### Command-line interface
51
60
 
52
61
  ```bash
53
62
  npx crextractor --target mobile --output ./credentials.mobile.json
package/bin/cli.js CHANGED
@@ -14,7 +14,7 @@ const args = parseArgs({
14
14
  },
15
15
  cleanup: {
16
16
  type: 'boolean',
17
- default: false,
17
+ default: true,
18
18
  },
19
19
  },
20
20
  });
package/crextractor.d.ts CHANGED
@@ -1,10 +1,24 @@
1
- export function extractSecrets(): Promise<{
1
+ export type CrunchyrollAppCredentials = {
2
2
  // Crunchyroll app ID
3
3
  id: string;
4
4
  // Crunchyroll app secret
5
5
  secret: string;
6
6
  // Base64 encoded `id:secret` string
7
7
  encoded: string;
8
- // HTTP header with Basic Authorization to access Crunchyroll mobile APIs
8
+ // Ready HTTP header in the format `Basic <encoded>`, can be used to access some Crunchyroll APIs
9
9
  authorization: string;
10
- }>;
10
+ };
11
+
12
+ /**
13
+ * Extract credentials from the Crunchyroll Android APK using jadx.
14
+ */
15
+ export function extract(options?: {
16
+ target?: 'mobile' | 'tv';
17
+ output?: string;
18
+ cleanup?: boolean;
19
+ }): Promise<CrunchyrollAppCredentials>;
20
+
21
+ /**
22
+ * Fetch ready credentials from the GitHub repository.
23
+ */
24
+ export function pull(options?: { target: 'mobile' | 'tv' }): Promise<CrunchyrollAppCredentials>;
package/crextractor.js CHANGED
@@ -1,16 +1,12 @@
1
1
  const { execSync } = require('node:child_process');
2
2
  const { join } = require('node:path');
3
3
  const { readdir, readFile, writeFile, rm } = require('node:fs/promises');
4
- const { download } = require('molnia');
5
4
  const { existsSync } = require('node:fs');
5
+ const { download } = require('molnia');
6
6
 
7
7
  const downloadMobileApk = async () => {
8
- const source = 'https://apkcombo.com/crunchyroll/com.crunchyroll.crunchyroid/download/apk';
9
- const page = await fetch(source);
10
- const html = await page.text();
11
- const route = '/r2' + html.split('/r2')[1]?.split('"')[0];
12
- const url = `https://apkcombo.com${route}`;
13
- const filepath = join(process.cwd(), 'crunchyroll.xapk');
8
+ const url = 'https://api.qqaoop.com/v11/apps/com.crunchyroll.crunchyroid/download?userId=1';
9
+ const filepath = join(process.cwd(), 'crunchyroll.apk');
14
10
  await download(url, {
15
11
  output: filepath,
16
12
  onError: (error) => console.error(error),
@@ -100,7 +96,7 @@ const parseVersion = async (decompiledDir) => {
100
96
  }
101
97
  };
102
98
 
103
- const extract = async ({ target, output, cleanup = false } = {}) => {
99
+ const extract = async ({ target = 'mobile', output, cleanup = false } = {}) => {
104
100
  console.log('Downloading APK...');
105
101
  const apkPath = target === 'tv' ? await downloadTvApk() : await downloadMobileApk();
106
102
 
@@ -132,4 +128,10 @@ const extract = async ({ target, output, cleanup = false } = {}) => {
132
128
  return { version, id, secret, encoded, authorization };
133
129
  };
134
130
 
135
- module.exports = { extract };
131
+ const pull = async ({ target = 'mobile' } = {}) => {
132
+ const url = `https://raw.githubusercontent.com/vitalygashkov/crextractor/refs/heads/main/credentials.${target}.json`;
133
+ const credentials = await fetch(url).then((response) => response.json());
134
+ return credentials;
135
+ };
136
+
137
+ module.exports = { extract, pull };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crextractor",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Utility for extracting credentials from the Crunchyroll Android app",
5
5
  "main": "crextractor.js",
6
6
  "bin": {
@@ -15,6 +15,8 @@
15
15
  "type": "commonjs",
16
16
  "scripts": {
17
17
  "start": "node bin/cli.js",
18
+ "extract:mobile": "node bin/cli.js --target mobile --output ./credentials.mobile.json",
19
+ "extract:tv": "node bin/cli.js --target tv --output ./credentials.tv.json",
18
20
  "test": "echo \"Error: no test specified\" && exit 1"
19
21
  },
20
22
  "keywords": [