Skip to content

Commit

Permalink
youtube: add support for OAuth2 tokens (#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
wukko authored Jun 8, 2024
2 parents 7fb2e6d + a84d0dd commit a434de0
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 6 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
"scripts": {
"start": "node src/cobalt",
"setup": "node src/modules/setup",
"test": "node src/test/test",
"test": "node src/util/test",
"build": "node src/modules/buildStatic",
"testFilenames": "node src/test/testFilenamePresets"
"token:youtube": "node src/util/generate-youtube-tokens"
},
"repository": {
"type": "git",
Expand Down
47 changes: 44 additions & 3 deletions src/modules/processing/services/youtube.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Innertube, Session } from 'youtubei.js';
import { env } from '../../config.js';
import { cleanString } from '../../sub/utils.js';
import { fetch } from 'undici'
import { getCookie } from '../cookie/manager.js'
import { getCookie, updateCookieValues } from '../cookie/manager.js'

const ytBase = Innertube.create().catch(e => e);

Expand All @@ -24,6 +24,26 @@ const codecMatch = {
}
}

const transformSessionData = (cookie) => {
if (!cookie)
return;

const values = cookie.values();
const REQUIRED_VALUES = [
'access_token', 'refresh_token',
'client_id', 'client_secret',
'expires'
];

if (REQUIRED_VALUES.some(x => typeof values[x] !== 'string')) {
return;
}
return {
...values,
expires: new Date(values.expires),
};
}

const cloneInnertube = async (customFetch) => {
const innertube = await ytBase;
if (innertube instanceof Error) {
Expand All @@ -36,11 +56,32 @@ const cloneInnertube = async (customFetch) => {
innertube.session.api_version,
innertube.session.account_index,
innertube.session.player,
getCookie('youtube')?.toString(),
undefined,
customFetch ?? innertube.session.http.fetch,
innertube.session.cache
);

const cookie = getCookie('youtube_oauth');
const oauthData = transformSessionData(cookie);

if (!session.logged_in && oauthData) {
await session.oauth.init(oauthData);
session.logged_in = true;
}

if (session.logged_in) {
await session.oauth.refreshIfRequired();
const oldExpiry = new Date(cookie.values().expires);
const newExpiry = session.oauth.credentials.expires;

if (oldExpiry.getTime() !== newExpiry.getTime()) {
updateCookieValues(cookie, {
...session.oauth.credentials,
expires: session.oauth.credentials.expires.toISOString()
});
}
}

const yt = new Innertube(session);
return yt;
}
Expand All @@ -62,7 +103,7 @@ export default async function(o) {
}

try {
info = await yt.getBasicInfo(o.id, 'IOS');
info = await yt.getBasicInfo(o.id, yt.session.logged_in ? 'ANDROID' : 'IOS');
} catch(e) {
if (e?.message === 'This video is unavailable') {
return { error: 'ErrorCouldntFetch' };
Expand Down
38 changes: 38 additions & 0 deletions src/util/generate-youtube-tokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Innertube } from 'youtubei.js';
import { Red } from '../modules/sub/consoleText.js'

const bail = (...msg) => {
console.error(...msg);
throw new Error(msg);
};

const tube = await Innertube.create();

tube.session.once(
'auth-pending',
({ verification_url, user_code }) => {
console.log(`${Red('[!]')} The token generated by this script is sensitive and you should not share it with anyone!`);
console.log(` By using this token, you are risking your Google account getting terminated.`);
console.log(` You should ${Red('NOT')} use your personal account!`);
console.log();
console.log(`Open ${verification_url} in a browser and enter ${user_code} when asked for the code.`);
}
);

tube.session.once('auth-error', (err) => bail('An error occurred:', err));
tube.session.once('auth', ({ status, credentials, ...rest }) => {
if (status !== 'SUCCESS') {
bail('something went wrong', rest);
}

console.log(
'add this cookie to the youtube_oauth array in your cookies file:',
JSON.stringify(
Object.entries(credentials)
.map(([k, v]) => `${k}=${v instanceof Date ? v.toISOString() : v}`)
.join('; ')
)
);
});

await tube.session.signIn();
2 changes: 1 addition & 1 deletion src/test/test.js → src/util/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { normalizeRequest } from "../modules/processing/request.js";
import { env } from "../modules/config.js";

env.apiURL = 'http://localhost:9000'
let tests = loadJSON('./src/test/tests.json');
let tests = loadJSON('./src/util/tests.json');

let noTest = [];
let failed = [];
Expand Down
File renamed without changes.
File renamed without changes.

0 comments on commit a434de0

Please sign in to comment.