Skip to content
This repository has been archived by the owner on Jun 10, 2023. It is now read-only.

Commit

Permalink
0.3.0
Browse files Browse the repository at this point in the history
* Closes #8
  • Loading branch information
codyduong committed Mar 17, 2022
1 parent a6df322 commit bf81f02
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 461 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ results

[Documentation](https://codyduong.github.io/ytmusicapiJS/)

See the [Documentation for the Python 3 API](https://ytmusicapi.readthedocs.io/en/latest/usage.html) for reference.
The API does support usage in browsers, however you will have to use a proxy since YTmusic does not have CORS support.

## Contributing
The library is intended to keep features within the same scope of the original Python 3 library. This may/may not change at my discretion.
Expand Down
15 changes: 6 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codyduong/ytmusicapi",
"version": "0.3.0-rc1",
"version": "0.3.0",
"description": "Unofficial API for YouTube Music",
"main": "dist/index.js",
"browser": "dist/index.browser.js",
Expand All @@ -20,44 +20,41 @@
"author": "Cody Duong",
"license": "MIT",
"devDependencies": {
"@types/crypto-js": "^4.1.1",
"@types/jest": "^27.4.0",
"@types/node": "^17.0.18",
"@types/utf8": "^3.0.1",
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@typescript-eslint/parser": "^5.12.0",
"buffer": "^6.0.3",
"clean-jsdoc-theme": "^3.3.3",
"configparser": "^0.3.9",
"crypto-browserify": "^3.12.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^4.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.2.0",
"https-browserify": "^1.0.0",
"jest": "^27.5.1",
"jsdoc": "^3.6.10",
"path-browserify": "^1.0.1",
"prettier": "^2.4.1",
"prettier-eslint-cli": "^5.0.1",
"stream-browserify": "^3.0.0",
"stream-http": "^3.2.0",
"ts-jest": "^27.1.3",
"ts-loader": "^9.2.8",
"ts-node": "^10.5.0",
"typescript": "^4.6.2",
"url": "^0.11.0",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2"
},
"dependencies": {
"axios": "^0.26.0",
"browser-or-node": "^2.0.0",
"buffer": "^6.0.3",
"case-insensitive-object": "^0.1.3",
"crypto-js": "^4.1.1",
"i18next": "^21.6.13",
"path-browserify": "^1.0.1",
"prompt-sync": "^4.2.0",
"type-fest": "^2.12.0",
"url": "^0.11.0",
"utf8": "^3.0.0"
},
"files": [
Expand Down
25 changes: 25 additions & 0 deletions src/fallback/crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//A reimplemntation of createHash from Node crypto module.
//crypto-browserify does not work for webpack 5
import CryptoJS from 'crypto-js';

class Hash {
#value: ReturnType<typeof CryptoJS.algo.SHA1.create>;
constructor() {
this.#value = CryptoJS.algo.SHA1.create();
}
setValue(value: any): void {
this.#value = value;
}
update(string: string): void {
this.#value.update(string);
}
//Intentionally unused param
digest(_string: string): CryptoJS.lib.WordArray {
return this.#value.finalize();
}
}

//Intentionally unused param
export const createHash = (_string: string): any => {
return new Hash();
};
12 changes: 10 additions & 2 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { re, json, time, locale, SimpleCookie } from './pyLibraryMock';
import * as utf8 from 'utf8';
import * as constants from './constants';
import { createHash } from 'crypto';

import { createHash } from './fallback/crypto';
import type { Headers } from './types';

// @CODYDUONG TODO type better
Expand Down Expand Up @@ -152,3 +151,12 @@ export function sumTotalDuration(item: any): number {
)
);
}

//Removes any headers controlled by browser
export function clearUnsafeHeaders(o: Record<string, any>): void {
if (window) {
delete o['user-agent'];
delete o['accept-encoding'];
delete o['origin'];
}
}
34 changes: 0 additions & 34 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,6 @@ import { ExploreMixin } from './mixins/explore';
import { LibraryMixin } from './mixins/library';
import { PlaylistsMixin } from './mixins/playlists';
import { UploadsMixin } from './mixins/uploads';
import { isBrowser } from 'browser-or-node';

//We have to make sure the user has installed shims if using browser.
if (isBrowser) {
const requiredArray = [
'crypto-browserify',
'https-browserify',
'path-browserify',
'stream-browserify',
'stream-http',
'url',
'buffer',
];
const definedArray = [];
for (const [i, required] of requiredArray.entries()) {
definedArray[i] = !!require(required);
}
if (definedArray.length > 0) {
const missing = definedArray
.map((v, i) => (v === false ? `${requiredArray[i]}` : undefined))
.filter((x): x is string => !!x);
const install = missing.reduce((p, c) => `${p} ${c}`, '');
throw new Error(
`You are missing required browser dependencies.\n${missing.reduce(
(p, c) => `${p}, ${c}`,
''
)}\nInstall them now with:\n
npm install ${install}\n
OR\n
yarn add ${install}\n
`
);
}
}

/**
* Allows automated interactions with YouTube Music by emulating the YouTube web client's requests.
Expand Down
12 changes: 6 additions & 6 deletions src/mixins/browsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const BrowsingMixin = <TBase extends GConstructor<_YTMusic>>(
const body = { browseId: 'FEmusic_home' };
const response = await this._sendRequest(endpoint, body);
const results = nav(response, [...SINGLE_COLUMN_TAB, ...SECTION_LIST]);
let home = [...this.parser.parseHome(results)];
let home = [...this._parser.parseHome(results)];

const sectionList = nav(response, [
...SINGLE_COLUMN_TAB,
Expand All @@ -141,7 +141,7 @@ export const BrowsingMixin = <TBase extends GConstructor<_YTMusic>>(
const requestFunc = async (additionalParams: any): Promise<any> =>
await this._sendRequest(endpoint, body, additionalParams);
const parseFunc = (contents: any): any =>
this.parser.parseHome(contents);
this._parser.parseHome(contents);
home = [
...home,
...(await getContinuations(
Expand Down Expand Up @@ -441,7 +441,7 @@ export const BrowsingMixin = <TBase extends GConstructor<_YTMusic>>(
: null;
searchResults = [
...searchResults,
...this.parser.parseSearchResults(
...this._parser.parseSearchResults(
resultsMusicShelfContents,
type,
category
Expand All @@ -456,7 +456,7 @@ export const BrowsingMixin = <TBase extends GConstructor<_YTMusic>>(
await this._sendRequest(endpoint, body, additionalParams);

const parseFunc = (contents: any): Record<string, any> =>
this.parser.parseSearchResults(contents, type, category);
this._parser.parseSearchResults(contents, type, category);

searchResults = [
...searchResults,
Expand Down Expand Up @@ -636,7 +636,7 @@ export const BrowsingMixin = <TBase extends GConstructor<_YTMusic>>(
//@ts-expect-error: We're overriding the shape here
artist['songs']['results'] = parsePlaylistItems(musicShelf['contents']);
}
artist = { ...artist, ...this.parser.parseArtistContents(results) };
artist = { ...artist, ...this._parser.parseArtistContents(results) };
return artist;
}

Expand Down Expand Up @@ -718,7 +718,7 @@ export const BrowsingMixin = <TBase extends GConstructor<_YTMusic>>(
'musicVisualHeaderRenderer',
...TITLE_TEXT,
]) as string,
...this.parser.parseArtistContents(results),
...this._parser.parseArtistContents(results),
};
return user;
}
Expand Down
6 changes: 3 additions & 3 deletions src/mixins/uploads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ export const UploadsMixin = <TBase extends GConstructor<LibraryMixin>>(
supportedFiletypes.join(', ')
);
}
const headers: any = this.headers;
const headers: any = this._headers;
let uploadUrl = `https://upload.youtube.com/upload/usermusic/http?authuser=${headers['x-goog-authuser']}`;
const filesize = statSync(filepath).size;
const body = 'filename=' + utf8.encode(basename(filepath));
Expand All @@ -357,7 +357,7 @@ export const UploadsMixin = <TBase extends GConstructor<LibraryMixin>>(
headers['X-Goog-Upload-Protocol'] = 'resumable';
const response = await axios.post(uploadUrl, body, {
headers: headers,
proxy: this.proxies,
proxy: this._proxies,
});
headers['X-Goog-Upload-Command'] = 'upload, finalize';
headers['X-Goog-Upload-Offset'] = '0';
Expand All @@ -367,7 +367,7 @@ export const UploadsMixin = <TBase extends GConstructor<LibraryMixin>>(
const data = readFileSync(filepath);
const response2: any = await axios.post(uploadUrl, data, {
headers: headers,
proxy: this.proxies,
proxy: this._proxies,
});
if (response2.status == 200) {
return 'STATUS_SUCCEEDED';
Expand Down
Loading

0 comments on commit bf81f02

Please sign in to comment.