mirror of
https://github.com/snobu/destreamer.git
synced 2026-01-21 23:42:16 +00:00
Major code refactoring (#164)
* Added Chromium caching of identity provider cookies * Moved token expiry check in standalone method * Created refreshSession function * Session is now refreshed if the token expires * Linting fixes * Removed debug console.log() * Added CC support * Created function to prompt user for download parameters (interactive mode) * Fix data folder for puppeteer * Fixed multiple session error * Fix token expire time * Moved session refreshing to a more sensible place * Changed Metadata name to Video (to better reflect the data structure) * Complete CLI refactoring * Removed useless sleep function * Added outDir check from CLI * Complete input parsing refactoring (both inline and file) * Fixed and improved tests to work with the new input parsing * Moved and improved output path generation to videoUtils * Main code refactoring, added outpath to video type * Minor changes in spacing and type definition style * Updated readme after code refactoring * Fix if inputFile doesn't start with url on line 1 * Minor naming change * Use module 'winston' for logging * Created logge, changed all console.log and similar to use the logger * Added verbose logging, changed posterUrl property name on Video type * Moved GUID extraction to input parsing * Added support for group links * Fixed test after last input parsing update * Removed debug proces.exit() * Changed from desc to asc order for group videos * Updated test to reflect GUIDs output after parsing * Added couple of comments and restyled some imports * More readable verbose GUIDs logging * Removed unused errors * Temporary fix for timeout not working in ApiClient * Explicit class member accessibility * Defined array naming schema to be Array<T> * Defined type/interface schema to be type only * A LOT of type definitions
This commit is contained in:
@@ -1,56 +1,104 @@
|
||||
import * as fs from 'fs';
|
||||
import { chromeCacheFolder } from './destreamer';
|
||||
import { ERROR_CODE } from './Errors';
|
||||
import { logger } from './Logger';
|
||||
import { getPuppeteerChromiumPath } from './PuppeteerHelper';
|
||||
import { Session } from './Types';
|
||||
import { bgGreen, bgYellow, green } from 'colors';
|
||||
|
||||
import fs from 'fs';
|
||||
import jwtDecode from 'jwt-decode';
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
|
||||
export class TokenCache {
|
||||
private tokenCacheFile: string = '.token_cache';
|
||||
private tokenCacheFile = '.token_cache';
|
||||
|
||||
public Read(): Session | null {
|
||||
let j = null;
|
||||
if (!fs.existsSync(this.tokenCacheFile)) {
|
||||
console.warn(bgYellow.black(`${this.tokenCacheFile} not found.\n`));
|
||||
logger.warn(`${this.tokenCacheFile} not found. \n`);
|
||||
|
||||
return null;
|
||||
}
|
||||
let f = fs.readFileSync(this.tokenCacheFile, 'utf8');
|
||||
j = JSON.parse(f);
|
||||
|
||||
interface Jwt {
|
||||
let session: Session = JSON.parse(fs.readFileSync(this.tokenCacheFile, 'utf8'));
|
||||
|
||||
type Jwt = {
|
||||
[key: string]: any
|
||||
}
|
||||
const decodedJwt: Jwt = jwtDecode(session.AccessToken);
|
||||
|
||||
const decodedJwt: Jwt = jwtDecode(j.AccessToken);
|
||||
let now: number = Math.floor(Date.now() / 1000);
|
||||
let exp: number = decodedJwt['exp'];
|
||||
let timeLeft: number = exp - now;
|
||||
|
||||
let now = Math.floor(Date.now() / 1000);
|
||||
let exp = decodedJwt['exp'];
|
||||
let timeLeft = exp - now;
|
||||
|
||||
let timeLeftInMinutes = Math.floor(timeLeft / 60);
|
||||
if (timeLeft < 120) {
|
||||
console.warn(bgYellow.black('\nAccess token has expired.'));
|
||||
logger.warn('Access token has expired! \n');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
console.info(bgGreen.black(`\nAccess token still good for ${timeLeftInMinutes} minutes.\n`));
|
||||
|
||||
let session: Session = {
|
||||
AccessToken: j.AccessToken,
|
||||
ApiGatewayUri: j.ApiGatewayUri,
|
||||
ApiGatewayVersion: j.ApiGatewayVersion
|
||||
};
|
||||
logger.info(`Access token still good for ${Math.floor(timeLeft / 60)} minutes.\n`.green);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public Write(session: Session): void {
|
||||
let s = JSON.stringify(session, null, 4);
|
||||
let s: string = JSON.stringify(session, null, 4);
|
||||
fs.writeFile('.token_cache', s, (err: any) => {
|
||||
if (err) {
|
||||
return console.error(err);
|
||||
return logger.error(err);
|
||||
}
|
||||
console.info(green('Fresh access token dropped into .token_cache'));
|
||||
logger.info('Fresh access token dropped into .token_cachen \n'.green);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function refreshSession(): Promise<Session> {
|
||||
const url = 'https://web.microsoftstream.com';
|
||||
|
||||
const browser: puppeteer.Browser = await puppeteer.launch({
|
||||
executablePath: getPuppeteerChromiumPath(),
|
||||
headless: false, // NEVER TRUE OR IT DOES NOT WORK
|
||||
userDataDir: chromeCacheFolder,
|
||||
args: [
|
||||
'--disable-dev-shm-usage',
|
||||
'--fast-start',
|
||||
'--no-sandbox'
|
||||
]
|
||||
});
|
||||
|
||||
const page: puppeteer.Page = (await browser.pages())[0];
|
||||
await page.goto(url, { waitUntil: 'load' });
|
||||
|
||||
await browser.waitForTarget((target: puppeteer.Target) => target.url().includes(url), { timeout: 30000 });
|
||||
|
||||
let session: Session | null = null;
|
||||
let tries = 1;
|
||||
|
||||
while (!session) {
|
||||
try {
|
||||
let sessionInfo: any;
|
||||
session = await page.evaluate(
|
||||
() => {
|
||||
return {
|
||||
AccessToken: sessionInfo.AccessToken,
|
||||
ApiGatewayUri: sessionInfo.ApiGatewayUri,
|
||||
ApiGatewayVersion: sessionInfo.ApiGatewayVersion
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
if (tries > 5) {
|
||||
process.exit(ERROR_CODE.NO_SESSION_INFO);
|
||||
}
|
||||
|
||||
session = null;
|
||||
tries++;
|
||||
await page.waitFor(3000);
|
||||
}
|
||||
}
|
||||
browser.close();
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user