@mathieuc/tradingview 3.4.0 → 3.4.1
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/.eslintrc.js +2 -0
- package/package.json +1 -1
- package/src/client.js +5 -1
- package/src/miscRequests.js +21 -12
- package/tests/09. AllErrors.js +39 -1
- package/tests/10. Authenticated.js +12 -6
package/.eslintrc.js
CHANGED
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -214,6 +214,7 @@ module.exports = class Client {
|
|
|
214
214
|
/**
|
|
215
215
|
* @typedef {Object} ClientOptions
|
|
216
216
|
* @prop {string} [token] User auth token (in 'sessionid' cookie)
|
|
217
|
+
* @prop {string} [signature] User auth token signature (in 'sessionid_sign' cookie)
|
|
217
218
|
* @prop {boolean} [DEBUG] Enable debug mode
|
|
218
219
|
* @prop {'data' | 'prodata' | 'widgetdata'} [server] Server type
|
|
219
220
|
*/
|
|
@@ -230,7 +231,10 @@ module.exports = class Client {
|
|
|
230
231
|
});
|
|
231
232
|
|
|
232
233
|
if (clientOptions.token) {
|
|
233
|
-
misc.getUser(
|
|
234
|
+
misc.getUser(
|
|
235
|
+
clientOptions.token,
|
|
236
|
+
clientOptions.signature ? clientOptions.signature : '',
|
|
237
|
+
).then((user) => {
|
|
234
238
|
this.#sendQueue.unshift(protocol.formatWSPacket({
|
|
235
239
|
m: 'set_auth_token',
|
|
236
240
|
p: [user.authToken],
|
package/src/miscRequests.js
CHANGED
|
@@ -375,8 +375,11 @@ module.exports = {
|
|
|
375
375
|
|
|
376
376
|
if (data.error) throw new Error(data.error);
|
|
377
377
|
|
|
378
|
-
const
|
|
379
|
-
const session = (
|
|
378
|
+
const sessionCookie = cookies.find((c) => c.includes('sessionid='));
|
|
379
|
+
const session = (sessionCookie.match(/sessionid=(.*?);/) ?? [])[1];
|
|
380
|
+
|
|
381
|
+
const signCookie = cookies.find((c) => c.includes('sessionid_sign='));
|
|
382
|
+
const signature = (signCookie.match(/sessionid_sign=(.*?);/) ?? [])[1];
|
|
380
383
|
|
|
381
384
|
return {
|
|
382
385
|
id: data.user.id,
|
|
@@ -388,6 +391,7 @@ module.exports = {
|
|
|
388
391
|
followers: data.user.followers,
|
|
389
392
|
notifications: data.user.notification_count,
|
|
390
393
|
session,
|
|
394
|
+
signature,
|
|
391
395
|
sessionHash: data.user.session_hash,
|
|
392
396
|
privateChannel: data.user.private_channel,
|
|
393
397
|
authToken: data.user.auth_token,
|
|
@@ -399,19 +403,20 @@ module.exports = {
|
|
|
399
403
|
* Get user from 'sessionid' cookie
|
|
400
404
|
* @function getUser
|
|
401
405
|
* @param {string} session User 'sessionid' cookie
|
|
406
|
+
* @param {string} [signature] User 'sessionid_sign' cookie
|
|
402
407
|
* @param {string} [location] Auth page location (For france: https://fr.tradingview.com/)
|
|
403
408
|
* @returns {Promise<User>} Token
|
|
404
409
|
*/
|
|
405
|
-
async getUser(session, location = 'https://www.tradingview.com/') {
|
|
410
|
+
async getUser(session, signature = '', location = 'https://www.tradingview.com/') {
|
|
406
411
|
return new Promise((cb, err) => {
|
|
407
412
|
https.get(location, {
|
|
408
|
-
headers: { cookie: `sessionid=${session}` },
|
|
413
|
+
headers: { cookie: `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}` },
|
|
409
414
|
}, (res) => {
|
|
410
415
|
let rs = '';
|
|
411
416
|
res.on('data', (d) => { rs += d; });
|
|
412
417
|
res.on('end', async () => {
|
|
413
418
|
if (res.headers.location && location !== res.headers.location) {
|
|
414
|
-
cb(await module.exports.getUser(session, res.headers.location));
|
|
419
|
+
cb(await module.exports.getUser(session, signature, res.headers.location));
|
|
415
420
|
return;
|
|
416
421
|
}
|
|
417
422
|
if (rs.includes('auth_token')) {
|
|
@@ -428,12 +433,13 @@ module.exports = {
|
|
|
428
433
|
user: parseFloat(/"notification_count":\{"following":[0-9]*,"user":([0-9]*)/.exec(rs)[1] || 0),
|
|
429
434
|
},
|
|
430
435
|
session,
|
|
436
|
+
signature,
|
|
431
437
|
sessionHash: /"session_hash":"(.*?)"/.exec(rs)[1],
|
|
432
438
|
privateChannel: /"private_channel":"(.*?)"/.exec(rs)[1],
|
|
433
439
|
authToken: /"auth_token":"(.*?)"/.exec(rs)[1],
|
|
434
440
|
joinDate: new Date(/"date_joined":"(.*?)"/.exec(rs)[1] || 0),
|
|
435
441
|
});
|
|
436
|
-
} else err(new Error('Wrong or expired sessionid'));
|
|
442
|
+
} else err(new Error('Wrong or expired sessionid/signature'));
|
|
437
443
|
});
|
|
438
444
|
|
|
439
445
|
res.on('error', err);
|
|
@@ -445,12 +451,13 @@ module.exports = {
|
|
|
445
451
|
* Get user's private indicators from a 'sessionid' cookie
|
|
446
452
|
* @function getPrivateIndicators
|
|
447
453
|
* @param {string} session User 'sessionid' cookie
|
|
454
|
+
* @param {string} [signature] User 'sessionid_sign' cookie
|
|
448
455
|
* @returns {Promise<SearchIndicatorResult[]>} Search results
|
|
449
456
|
*/
|
|
450
|
-
async getPrivateIndicators(session) {
|
|
457
|
+
async getPrivateIndicators(session, signature = '') {
|
|
451
458
|
return new Promise((cb, err) => {
|
|
452
459
|
https.get('https://pine-facade.tradingview.com/pine-facade/list?filter=saved', {
|
|
453
|
-
headers: { cookie: `sessionid=${session}` },
|
|
460
|
+
headers: { cookie: `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}` },
|
|
454
461
|
}, (res) => {
|
|
455
462
|
let rs = '';
|
|
456
463
|
res.on('data', (d) => { rs += d; });
|
|
@@ -499,18 +506,19 @@ module.exports = {
|
|
|
499
506
|
* Get a chart token from a layout ID and the user credentials if the layout is not public
|
|
500
507
|
* @function getChartToken
|
|
501
508
|
* @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
|
|
502
|
-
* @param {UserCredentials} [credentials] User credentials (id + session)
|
|
509
|
+
* @param {UserCredentials} [credentials] User credentials (id + session + [signature])
|
|
503
510
|
* @returns {Promise<string>} Token
|
|
504
511
|
*/
|
|
505
512
|
async getChartToken(layout, credentials = {}) {
|
|
506
513
|
const creds = credentials.id && credentials.session;
|
|
507
514
|
const userID = creds ? credentials.id : -1;
|
|
508
515
|
const session = creds ? credentials.session : null;
|
|
516
|
+
const signature = creds ? credentials.signature : null;
|
|
509
517
|
|
|
510
518
|
const { data } = await request({
|
|
511
519
|
host: 'www.tradingview.com',
|
|
512
520
|
path: `/chart-token/?image_url=${layout}&user_id=${userID}`,
|
|
513
|
-
headers: { cookie: session ? `sessionid=${session}` : '' },
|
|
521
|
+
headers: { cookie: session ? `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}` : '' },
|
|
514
522
|
});
|
|
515
523
|
|
|
516
524
|
if (!data.token) throw new Error('Wrong layout or credentials');
|
|
@@ -545,7 +553,7 @@ module.exports = {
|
|
|
545
553
|
* @function getDrawings
|
|
546
554
|
* @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
|
|
547
555
|
* @param {string | ''} [symbol] Market filter (Like: 'BINANCE:BTCEUR')
|
|
548
|
-
* @param {UserCredentials} [credentials] User credentials (id + session)
|
|
556
|
+
* @param {UserCredentials} [credentials] User credentials (id + session + [signature])
|
|
549
557
|
* @param {number} [chartID] Chart ID
|
|
550
558
|
* @returns {Promise<Drawing[]>} Drawings
|
|
551
559
|
*/
|
|
@@ -553,12 +561,13 @@ module.exports = {
|
|
|
553
561
|
const chartToken = await module.exports.getChartToken(layout, credentials);
|
|
554
562
|
const creds = credentials.id && credentials.session;
|
|
555
563
|
const session = creds ? credentials.session : null;
|
|
564
|
+
const signature = creds ? credentials.signature : null;
|
|
556
565
|
|
|
557
566
|
const { data } = await request({
|
|
558
567
|
host: 'charts-storage.tradingview.com',
|
|
559
568
|
path: `/charts-storage/layout/${layout}/sources?chart_id=${chartID
|
|
560
569
|
}&jwt=${chartToken}${symbol ? `&symbol=${symbol}` : ''}`,
|
|
561
|
-
headers: { cookie: session ? `sessionid=${session}` : '' },
|
|
570
|
+
headers: { cookie: session ? `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}` : '' },
|
|
562
571
|
});
|
|
563
572
|
|
|
564
573
|
if (!data.payload) throw new Error('Wrong layout, user credentials, or chart id.');
|
package/tests/09. AllErrors.js
CHANGED
|
@@ -135,10 +135,48 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
135
135
|
next();
|
|
136
136
|
});
|
|
137
137
|
},
|
|
138
|
+
|
|
139
|
+
async (next) => { /* Testing "Wrong or expired sessionid/signature" using getUser method */
|
|
140
|
+
log('Testing "Wrong or expired sessionid/signature" error using getUser method:');
|
|
141
|
+
|
|
142
|
+
if (!process.env.SESSION) {
|
|
143
|
+
warn('=> Skipping test because no sessionid/signature was provided');
|
|
144
|
+
next();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
await TradingView.getUser(process.env.SESSION);
|
|
150
|
+
err('=> User found !');
|
|
151
|
+
} catch (error) {
|
|
152
|
+
success('=> User not found:', error);
|
|
153
|
+
next();
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
async (next) => { /* Testing "Wrong or expired sessionid/signature" using client */
|
|
158
|
+
log('Testing "Wrong or expired sessionid/signature" error using client:');
|
|
159
|
+
|
|
160
|
+
if (!process.env.SESSION) {
|
|
161
|
+
warn('=> Skipping test because no sessionid/signature was provided');
|
|
162
|
+
next();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
log('Creating a new client...');
|
|
167
|
+
const client2 = new TradingView.Client({
|
|
168
|
+
token: process.env.SESSION,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
client2.onError((...error) => {
|
|
172
|
+
success('=> Client error:', error);
|
|
173
|
+
client2.end();
|
|
174
|
+
next();
|
|
175
|
+
});
|
|
176
|
+
},
|
|
138
177
|
];
|
|
139
178
|
|
|
140
179
|
(async () => {
|
|
141
|
-
// eslint-disable-next-line no-restricted-syntax, no-await-in-loop
|
|
142
180
|
for (const t of tests) await new Promise(t);
|
|
143
181
|
success(`Crashtests ${tests.length}/${tests.length} done !`);
|
|
144
182
|
cb();
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
/* eslint-disable no-restricted-syntax */
|
|
2
|
-
/* eslint-disable no-await-in-loop */
|
|
3
1
|
const TradingView = require('../main');
|
|
4
2
|
|
|
5
|
-
const wait = (ms) => new Promise((
|
|
3
|
+
const wait = (ms) => new Promise((cb) => { setTimeout(cb, ms); });
|
|
6
4
|
|
|
7
5
|
module.exports = async (log, success, warn, err, cb) => {
|
|
6
|
+
if (!process.env.SESSION || !process.env.SIGNATURE) {
|
|
7
|
+
warn('No sessionid/signature was provided');
|
|
8
|
+
cb();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
log('Getting user info');
|
|
9
13
|
|
|
10
|
-
const userInfos = await TradingView.getUser(process.env.SESSION);
|
|
14
|
+
const userInfos = await TradingView.getUser(process.env.SESSION, process.env.SIGNATURE);
|
|
11
15
|
if (userInfos && userInfos.id) {
|
|
12
16
|
success('User info:', {
|
|
13
17
|
id: userInfos.id,
|
|
@@ -24,8 +28,8 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
24
28
|
await wait(1000);
|
|
25
29
|
|
|
26
30
|
log('Getting user indicators');
|
|
27
|
-
|
|
28
31
|
const userIndicators = await TradingView.getPrivateIndicators(process.env.SESSION);
|
|
32
|
+
|
|
29
33
|
if (userIndicators) {
|
|
30
34
|
if (userIndicators.length === 0) warn('No private indicator found');
|
|
31
35
|
else success('User indicators:', userIndicators.map((i) => i.name));
|
|
@@ -36,7 +40,9 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
36
40
|
log('Creating logged client');
|
|
37
41
|
const client = new TradingView.Client({
|
|
38
42
|
token: process.env.SESSION,
|
|
43
|
+
signature: process.env.SIGNATURE,
|
|
39
44
|
});
|
|
45
|
+
|
|
40
46
|
client.onError((...error) => {
|
|
41
47
|
err('Client error', error);
|
|
42
48
|
});
|
|
@@ -76,7 +82,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
76
82
|
await wait(1000);
|
|
77
83
|
|
|
78
84
|
log('Loading indicators...');
|
|
79
|
-
|
|
80
85
|
for (const indic of userIndicators) {
|
|
81
86
|
const privateIndic = await indic.get();
|
|
82
87
|
log(`[${indic.name}] Loading indicator...`);
|
|
@@ -92,4 +97,5 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
92
97
|
await check(indic.id);
|
|
93
98
|
});
|
|
94
99
|
}
|
|
100
|
+
log('Indicators loaded !');
|
|
95
101
|
};
|