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

Commit

Permalink
Add more tests and fix any failing.
Browse files Browse the repository at this point in the history
  • Loading branch information
codyduong committed Mar 15, 2022
1 parent 9899ebc commit 4439338
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 131 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ tests/test.cfg
headers_auth.json
dist
yarn-error.log
coverage
coverage
TEST_setup.json
19 changes: 10 additions & 9 deletions src/mixins/uploads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ export const UploadsMixin = <TBase extends GConstructor<LibraryMixin>>(
filepath: string
): Promise<'STATUS_SUCCEEDED' | Record<string, any>> {
this._checkAuth();
if (existsSync(filepath)) {
if (!existsSync(filepath)) {
throw new Error('The provided file does not exist.');
}
const supportedFiletypes = ['mp3', 'm4a', 'wma', 'flac', 'ogg'];
Expand All @@ -345,33 +345,34 @@ export const UploadsMixin = <TBase extends GConstructor<LibraryMixin>>(
supportedFiletypes.join(', ')
);
}
const headers: Record<string, 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));
headers.pop('content-encoding', null);
delete headers['content-encoding'];
headers['content-type'] =
'application/x-www-form-urlencoded;charset=utf-8';
headers['X-Goog-Upload-Command'] = 'start';
headers['X-Goog-Upload-Header-Content-Length'] = String(filesize);
headers['X-Goog-Upload-Header-Content-Length'] = filesize;
headers['X-Goog-Upload-Protocol'] = 'resumable';
const response = await axios.post(uploadUrl, body, {
headers: headers,
proxy: this.proxies,
});
headers['X-Goog-Upload-Command'] = 'upload, finalize';
headers['X-Goog-Upload-Offset'] = '0';
uploadUrl = response.headers['X-Goog-Upload-URL'];
uploadUrl =
response.headers['X-Goog-Upload-URL'] ??
response.headers['x-goog-upload-url'];
const data = readFileSync(filepath);
const response2: any = axios.post(uploadUrl, data, {
const response2: any = await axios.post(uploadUrl, data, {
headers: headers,
proxy: this.proxies,
});

if (response2.status_code == 200) {
if (response2.status == 200) {
return 'STATUS_SUCCEEDED';
} else {
return response;
return response2;
}
}

Expand Down
67 changes: 8 additions & 59 deletions src/mixins/uploads.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,20 @@ import {
getLibraryAlbumsReturn,
getLibraryArtistsReturn,
Order as _Order,
Rating,
} from './library.types';
import { thumbnails } from './browsing.types';
import { parseAlbumHeaderReturn } from '../parsers/albums.types';
import { parseUploadedItemsReturn } from '../parsers/uploads';

export type Order = _Order;
export type uploadsOptions = {
limit: number;
order: Order;
limit?: number;
order?: Order;
};

/**
* getLibraryUploadSongs
*/
export type getLibraryUploadSongsReturn = {
entityId: string;
videoId: string;
artists: {
name: string;
id: string;
}[];
title: string;
album: string;
likeStatus: Rating;
thumbnails: thumbnails;
}[];
export type getLibraryUploadSongsReturn = parseUploadedItemsReturn[];
export type getLibraryUploadAlbumsReturn = getLibraryAlbumsReturn;
export type getLibraryUploadArtistsReturn = getLibraryArtistsReturn;
export type getLibraryUploadArtistReturn = {
entityId: string;
videoId: string;
title: string;
artists: {
name: string;
id: string;
}[];
album: {
name: string;
id: string;
} | null;
likeStatus: Rating;
thumbnails: thumbnails;
}[];
export type getLibraryUploadAlbumReturn = {
title: string;
type: string;
thumbnails: thumbnails;
trackCount: number;
duration: string;
duration_seconds: number;
audioPlaylistId: string;
tracks: {
entityId: string;
videoId: string;
title: string;
duration: string;
duration_seconds: number;
artists: null | {
name: string;
id: string;
};
album: null | {
name: string;
id: string;
};
likeStatus: Rating;
thumbnails: thumbnails;
}[];
export type getLibraryUploadArtistReturn = parseUploadedItemsReturn[];
export type getLibraryUploadAlbumReturn = parseAlbumHeaderReturn & {
tracks: parseUploadedItemsReturn[];
};
26 changes: 23 additions & 3 deletions src/parsers/uploads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,31 @@ import {
THUMBNAILS,
} from '.';
import { parseDuration } from '../helpers';
import { parseSongAlbum, parseSongArtists } from './songs';
import { Rating } from '../mixins/library.types';
import { thumbnails } from '../types';
import {
parseSongAlbum,
parseSongAlbumReturn,
parseSongArtists,
parseSongArtistsReturn,
} from './songs';
import { getFixedColumnItem, getItemText, nav } from './utils';

export function parseUploadedItems(results: any): Array<any> {
const songs = [];
export type parseUploadedItemsReturn = {
entityId: string;
videoId: string;
title: string | null;
duration: string;
duration_seconds: number;
artists: parseSongArtistsReturn;
album: parseSongAlbumReturn;
likeStatus: Rating;
thumbnails: thumbnails;
};
export function parseUploadedItems(
results: any
): Array<parseUploadedItemsReturn> {
const songs: parseUploadedItemsReturn[] = [];
for (const result of results) {
const data = result[MRLIR];
if (!data['menu']) {
Expand Down
18 changes: 0 additions & 18 deletions src/parsers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,24 +381,6 @@ export function findObjectByKey<T extends Array<Record<string, any>>>(
return null;
}

//Ditto
export function findObjectsByKey<T extends Array<Record<string, any>>>(
objectList: T,
key: string,
nested: null
): any {
const objects = [];
for (let item of objectList) {
if (nested) {
item = item[nested];
}
if (key in item) {
objects.push(item);
}
}
return objects;
}

export function getDotSeperatorIndex(runs: Record<string, any>[]): number {
let index = runs.length;
// cheap workaround rather than deep equality
Expand Down
34 changes: 28 additions & 6 deletions src/pyLibraryMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,35 @@ export const locale = {
},
};

export const CaseInsensitiveObject = <T extends Record<string, any>>(
export const CaseInsensitiveObject = <T extends Record<string | symbol, any>>(
object: T
): T => ({
...(Object.fromEntries(
Object.entries(object).map(([k, v]) => [k.toLowerCase(), v])
) as T),
});
): T => {
const lowercaseObject = {
...(Object.fromEntries(
Object.entries(object).map(([k, v]) => [k.toLowerCase(), v])
) as T),
};
const proxy = new Proxy(lowercaseObject, {
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
get(obj, prop, receiver) {
const newProp = typeof prop == 'string' ? prop.toLowerCase() : prop;
return Reflect.get(obj, newProp, receiver);
},
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
set(
obj: { [index: string | symbol]: any },
prop,
value,
_receiver
): boolean {
const newProp = typeof prop == 'string' ? prop.toLowerCase() : prop;
obj[newProp] = value;
return true;
},
});

return proxy;
};

export class SimpleCookie {
'__Secure-3PAPISID': any;
Expand Down
51 changes: 31 additions & 20 deletions src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import * as fs from 'fs';
const _path = __filename;

export function setup(filepath: any, headersRaw: string): string {
let contents = [];
const contents = [];
let userHeaders: Record<string, any> = {};
if (!headersRaw) {
const eof =
// eslint-disable-next-line prettier/prettier
Expand All @@ -30,39 +31,47 @@ export function setup(filepath: any, headersRaw: string): string {
}
contents.push(line);
}
} else {
contents = headersRaw.split('\n');
}
let userHeaders: Record<string, any> = {};
try {
for (const content of contents) {
const header = content?.split(': ') ?? [];
if (header.length == 1 || header[0] == ':') {
// nothing was split or chromium headers
continue;
try {
for (const content of contents) {
const header = content?.split(': ') ?? [];
if (header.length == 1 || header[0] == ':') {
// nothing was split or chromium headers
continue;
}
userHeaders[header[0].toLowerCase()] = header.slice(1).join(': ');
}
userHeaders[header[0].toLowerCase()] = header.slice(1).join(': ');
} catch (e) {
throw new Error(
'Error parsing your input, please try again. Full error: ' + String(e)
);
}
} catch (e) {
throw new Error(
'Error parsing your input, please try again. Full error: ' + String(e)
);
}

userHeaders = json.load(headersRaw);
for (const key of Object.keys(userHeaders)) {
userHeaders[key.toLowerCase()] = userHeaders[key];
}
const missing_headers = ['cookie', 'x-goog-authuser'].filter(
(reqKey) => !(reqKey in userHeaders)
);
if (missing_headers) {
if (missing_headers.length > 0) {
throw new Error(
`The following entries are missing in your headers: ${missing_headers.join(
', '
)}\n
Please try a different request (such as /browse) and make sure you are logged in.`
);
}
const ignore_headers = ['host', 'content-length', 'accept-encoding'];
const ignore_headers = [
'host',
'content-length',
'accept-encoding',
'Host',
'Content-Length',
'Accept-Encoding',
];
for (const i of ignore_headers) {
userHeaders.delete(i);
delete userHeaders[i];
}

const initHeaders = helpers.initializeHeaders();
Expand All @@ -77,7 +86,9 @@ export function setup(filepath: any, headersRaw: string): string {
indent: 4,
}),
(err: any) => {
throw new Error(String(err));
if (err) {
throw new Error(String(err));
}
}
);
}
Expand Down
1 change: 0 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export type Headers = {
'content-type': string;
'content-encoding': string;
origin: string;

'x-origin'?: string;
'x-goog-visitor-id'?: string;
authorization?: string;
Expand Down
25 changes: 17 additions & 8 deletions src/ytmusic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ export class _YTMusic {
)}\nYTMusicAPI will still work, but some functions such as search or get_artist may not work. See https://github.com/codyduong/ytmusicapiJS/tree/main/src/locales for more details.`
);
}
(async (): Promise<void> => {
if (i18next.isInitialized && i18next.language != language) {
throw new Error(
'Multiple instances of YTMusic are not supported with different languages, please use changeLangauge instance function instead!'
);
} else {
if (i18next.isInitialized && i18next.language != language) {
throw new Error(
'Multiple instances of YTMusic are not supported with different languages, please use changeLangauge instance function instead!'
);
} else {
(async (): Promise<void> => {
await i18next.init({
lng: language ?? 'en',
//debug: true,
Expand All @@ -133,8 +133,9 @@ export class _YTMusic {
zh_CN,
},
});
}
})();
})();
}

this.parser = new Parser();

if (user) {
Expand Down Expand Up @@ -200,6 +201,14 @@ export class _YTMusic {
return response.data;
}

checkAuth(): this | null {
if (!this.#auth) {
return null;
} else {
return this;
}
}

_checkAuth(): void {
if (!this.#auth) {
throw new Error(
Expand Down
Binary file added tests/empty.mp3
Binary file not shown.
Loading

0 comments on commit 4439338

Please sign in to comment.