@shaivpidadi/trends-js 1.0.0 → 1.0.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/README.md
CHANGED
|
@@ -46,8 +46,26 @@ const result = await GoogleTrendsApi.dailyTrends({
|
|
|
46
46
|
|
|
47
47
|
// Result structure:
|
|
48
48
|
// {
|
|
49
|
-
// allTrendingStories: Array
|
|
50
|
-
//
|
|
49
|
+
// allTrendingStories: Array<{
|
|
50
|
+
// title: string,
|
|
51
|
+
// traffic: string,
|
|
52
|
+
// image?: {
|
|
53
|
+
// newsUrl: string,
|
|
54
|
+
// source: string,
|
|
55
|
+
// imageUrl: string
|
|
56
|
+
// },
|
|
57
|
+
// articles: Array<{
|
|
58
|
+
// title: string,
|
|
59
|
+
// url: string,
|
|
60
|
+
// source: string,
|
|
61
|
+
// time: string,
|
|
62
|
+
// snippet: string
|
|
63
|
+
// }>,
|
|
64
|
+
// shareUrl: string,
|
|
65
|
+
// startTime: number, // Unix timestamp
|
|
66
|
+
// endTime?: number // Unix timestamp (optional)
|
|
67
|
+
// }>,
|
|
68
|
+
// summary: Array<...>
|
|
51
69
|
// }
|
|
52
70
|
```
|
|
53
71
|
|
|
@@ -63,8 +81,26 @@ const result = await GoogleTrendsApi.realTimeTrends({
|
|
|
63
81
|
|
|
64
82
|
// Result structure:
|
|
65
83
|
// {
|
|
66
|
-
// allTrendingStories: Array
|
|
67
|
-
//
|
|
84
|
+
// allTrendingStories: Array<{
|
|
85
|
+
// title: string,
|
|
86
|
+
// traffic: string,
|
|
87
|
+
// image?: {
|
|
88
|
+
// newsUrl: string,
|
|
89
|
+
// source: string,
|
|
90
|
+
// imageUrl: string
|
|
91
|
+
// },
|
|
92
|
+
// articles: Array<{
|
|
93
|
+
// title: string,
|
|
94
|
+
// url: string,
|
|
95
|
+
// source: string,
|
|
96
|
+
// time: string,
|
|
97
|
+
// snippet: string
|
|
98
|
+
// }>,
|
|
99
|
+
// shareUrl: string,
|
|
100
|
+
// startTime: number, // Unix timestamp
|
|
101
|
+
// endTime?: number // Unix timestamp (optional)
|
|
102
|
+
// }>,
|
|
103
|
+
// summary: Array<...>
|
|
68
104
|
// }
|
|
69
105
|
```
|
|
70
106
|
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractJsonFromResponse = void 0;
|
|
4
4
|
const GoogleTrendsError_js_1 = require("../errors/GoogleTrendsError.js");
|
|
5
|
-
// For future
|
|
5
|
+
// For future reference and update: from google trends page rpc call response,
|
|
6
6
|
// 0 "twitter down" The main trending search term.
|
|
7
|
-
// 1 null
|
|
7
|
+
// 1 null OR [newsUrl, source, imageUrl, [articles...]] Image/article data (often null in current API responses).
|
|
8
8
|
// 2 "US" Country code (where the trend is happening).
|
|
9
|
-
// 3 [1741599600] Unix timestamp
|
|
10
|
-
// 4 null
|
|
9
|
+
// 3 [1741599600] Unix timestamp array - first element is when the trend started.
|
|
10
|
+
// 4 null OR [1741602000] Unix timestamp array - trend end time (if available).
|
|
11
11
|
// 5 null Unused (reserved for future data).
|
|
12
12
|
// 6 500000 Search volume index (estimated search interest for the term).
|
|
13
13
|
// 7 null Unused (reserved for future data).
|
|
@@ -41,6 +41,48 @@ const extractJsonFromResponse = (text) => {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
exports.extractJsonFromResponse = extractJsonFromResponse;
|
|
44
|
+
const extractArticles = (item) => {
|
|
45
|
+
const imageData = item[1];
|
|
46
|
+
if (!imageData || !Array.isArray(imageData))
|
|
47
|
+
return [];
|
|
48
|
+
if (imageData.length <= 3)
|
|
49
|
+
return [];
|
|
50
|
+
const articlesArray = imageData[3];
|
|
51
|
+
if (!Array.isArray(articlesArray))
|
|
52
|
+
return [];
|
|
53
|
+
return articlesArray
|
|
54
|
+
.filter((article) => Array.isArray(article) && article.length >= 5)
|
|
55
|
+
.map((article) => ({
|
|
56
|
+
title: String(article[0] || ''),
|
|
57
|
+
url: String(article[1] || ''),
|
|
58
|
+
source: String(article[2] || ''),
|
|
59
|
+
time: String(article[3] || ''),
|
|
60
|
+
snippet: String(article[4] || ''),
|
|
61
|
+
}));
|
|
62
|
+
};
|
|
63
|
+
const extractTimestamp = (item, index) => {
|
|
64
|
+
const timeArray = item[index];
|
|
65
|
+
if (!Array.isArray(timeArray))
|
|
66
|
+
return undefined;
|
|
67
|
+
if (timeArray.length === 0)
|
|
68
|
+
return undefined;
|
|
69
|
+
const timestamp = timeArray[0];
|
|
70
|
+
if (typeof timestamp !== 'number')
|
|
71
|
+
return undefined;
|
|
72
|
+
return timestamp;
|
|
73
|
+
};
|
|
74
|
+
const extractImage = (item) => {
|
|
75
|
+
const imageData = item[1];
|
|
76
|
+
if (!imageData || !Array.isArray(imageData))
|
|
77
|
+
return undefined;
|
|
78
|
+
if (imageData.length < 3)
|
|
79
|
+
return undefined;
|
|
80
|
+
return {
|
|
81
|
+
newsUrl: String(imageData[0] || ''),
|
|
82
|
+
source: String(imageData[1] || ''),
|
|
83
|
+
imageUrl: String(imageData[2] || ''),
|
|
84
|
+
};
|
|
85
|
+
};
|
|
44
86
|
const updateResponseObject = (data) => {
|
|
45
87
|
if (!Array.isArray(data)) {
|
|
46
88
|
throw new GoogleTrendsError_js_1.ParseError('Invalid data format: expected array');
|
|
@@ -49,30 +91,26 @@ const updateResponseObject = (data) => {
|
|
|
49
91
|
const summary = [];
|
|
50
92
|
data.forEach((item) => {
|
|
51
93
|
if (Array.isArray(item)) {
|
|
94
|
+
const articles = extractArticles(item);
|
|
95
|
+
const startTime = extractTimestamp(item, 3) ?? 0;
|
|
96
|
+
const endTime = extractTimestamp(item, 4);
|
|
97
|
+
const image = extractImage(item);
|
|
52
98
|
const story = {
|
|
53
99
|
title: String(item[0] || ''),
|
|
54
100
|
traffic: String(item[6] || '0'),
|
|
55
|
-
articles:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
snippet: String(article[4] || '')
|
|
61
|
-
})) : [],
|
|
62
|
-
shareUrl: String(item[12] || '')
|
|
101
|
+
articles: articles,
|
|
102
|
+
shareUrl: String(item[12] || ''),
|
|
103
|
+
startTime,
|
|
104
|
+
...(endTime && { endTime }),
|
|
105
|
+
...(image && { image }),
|
|
63
106
|
};
|
|
64
|
-
if (item[1]) {
|
|
65
|
-
story.image = {
|
|
66
|
-
newsUrl: String(item[1][0] || ''),
|
|
67
|
-
source: String(item[1][1] || ''),
|
|
68
|
-
imageUrl: String(item[1][2] || '')
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
107
|
allTrendingStories.push(story);
|
|
72
108
|
summary.push({
|
|
73
109
|
title: story.title,
|
|
74
110
|
traffic: story.traffic,
|
|
75
|
-
articles: story.articles
|
|
111
|
+
articles: story.articles,
|
|
112
|
+
startTime,
|
|
113
|
+
...(endTime && { endTime }),
|
|
76
114
|
});
|
|
77
115
|
}
|
|
78
116
|
});
|
|
@@ -152,6 +152,10 @@ class GoogleTrendsApi {
|
|
|
152
152
|
}
|
|
153
153
|
//
|
|
154
154
|
async interestByRegion({ keyword, startTime = new Date('2004-01-01'), endTime = new Date(), geo = 'US', resolution = 'REGION', hl = 'en-US', timezone = new Date().getTimezoneOffset(), category = 0 }) {
|
|
155
|
+
const keywordValue = Array.isArray(keyword) ? keyword[0] : keyword;
|
|
156
|
+
if (!keywordValue || keywordValue.trim() === '') {
|
|
157
|
+
return { error: new GoogleTrendsError_js_1.InvalidRequestError('Keyword is required') };
|
|
158
|
+
}
|
|
155
159
|
const formatDate = (date) => {
|
|
156
160
|
return date.toISOString().split('T')[0];
|
|
157
161
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ParseError } from '../errors/GoogleTrendsError.js';
|
|
2
|
-
// For future
|
|
2
|
+
// For future reference and update: from google trends page rpc call response,
|
|
3
3
|
// 0 "twitter down" The main trending search term.
|
|
4
|
-
// 1 null
|
|
4
|
+
// 1 null OR [newsUrl, source, imageUrl, [articles...]] Image/article data (often null in current API responses).
|
|
5
5
|
// 2 "US" Country code (where the trend is happening).
|
|
6
|
-
// 3 [1741599600] Unix timestamp
|
|
7
|
-
// 4 null
|
|
6
|
+
// 3 [1741599600] Unix timestamp array - first element is when the trend started.
|
|
7
|
+
// 4 null OR [1741602000] Unix timestamp array - trend end time (if available).
|
|
8
8
|
// 5 null Unused (reserved for future data).
|
|
9
9
|
// 6 500000 Search volume index (estimated search interest for the term).
|
|
10
10
|
// 7 null Unused (reserved for future data).
|
|
@@ -37,6 +37,48 @@ export const extractJsonFromResponse = (text) => {
|
|
|
37
37
|
throw new ParseError('Failed to parse response');
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
|
+
const extractArticles = (item) => {
|
|
41
|
+
const imageData = item[1];
|
|
42
|
+
if (!imageData || !Array.isArray(imageData))
|
|
43
|
+
return [];
|
|
44
|
+
if (imageData.length <= 3)
|
|
45
|
+
return [];
|
|
46
|
+
const articlesArray = imageData[3];
|
|
47
|
+
if (!Array.isArray(articlesArray))
|
|
48
|
+
return [];
|
|
49
|
+
return articlesArray
|
|
50
|
+
.filter((article) => Array.isArray(article) && article.length >= 5)
|
|
51
|
+
.map((article) => ({
|
|
52
|
+
title: String(article[0] || ''),
|
|
53
|
+
url: String(article[1] || ''),
|
|
54
|
+
source: String(article[2] || ''),
|
|
55
|
+
time: String(article[3] || ''),
|
|
56
|
+
snippet: String(article[4] || ''),
|
|
57
|
+
}));
|
|
58
|
+
};
|
|
59
|
+
const extractTimestamp = (item, index) => {
|
|
60
|
+
const timeArray = item[index];
|
|
61
|
+
if (!Array.isArray(timeArray))
|
|
62
|
+
return undefined;
|
|
63
|
+
if (timeArray.length === 0)
|
|
64
|
+
return undefined;
|
|
65
|
+
const timestamp = timeArray[0];
|
|
66
|
+
if (typeof timestamp !== 'number')
|
|
67
|
+
return undefined;
|
|
68
|
+
return timestamp;
|
|
69
|
+
};
|
|
70
|
+
const extractImage = (item) => {
|
|
71
|
+
const imageData = item[1];
|
|
72
|
+
if (!imageData || !Array.isArray(imageData))
|
|
73
|
+
return undefined;
|
|
74
|
+
if (imageData.length < 3)
|
|
75
|
+
return undefined;
|
|
76
|
+
return {
|
|
77
|
+
newsUrl: String(imageData[0] || ''),
|
|
78
|
+
source: String(imageData[1] || ''),
|
|
79
|
+
imageUrl: String(imageData[2] || ''),
|
|
80
|
+
};
|
|
81
|
+
};
|
|
40
82
|
const updateResponseObject = (data) => {
|
|
41
83
|
if (!Array.isArray(data)) {
|
|
42
84
|
throw new ParseError('Invalid data format: expected array');
|
|
@@ -45,30 +87,26 @@ const updateResponseObject = (data) => {
|
|
|
45
87
|
const summary = [];
|
|
46
88
|
data.forEach((item) => {
|
|
47
89
|
if (Array.isArray(item)) {
|
|
90
|
+
const articles = extractArticles(item);
|
|
91
|
+
const startTime = extractTimestamp(item, 3) ?? 0;
|
|
92
|
+
const endTime = extractTimestamp(item, 4);
|
|
93
|
+
const image = extractImage(item);
|
|
48
94
|
const story = {
|
|
49
95
|
title: String(item[0] || ''),
|
|
50
96
|
traffic: String(item[6] || '0'),
|
|
51
|
-
articles:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
snippet: String(article[4] || '')
|
|
57
|
-
})) : [],
|
|
58
|
-
shareUrl: String(item[12] || '')
|
|
97
|
+
articles: articles,
|
|
98
|
+
shareUrl: String(item[12] || ''),
|
|
99
|
+
startTime,
|
|
100
|
+
...(endTime && { endTime }),
|
|
101
|
+
...(image && { image }),
|
|
59
102
|
};
|
|
60
|
-
if (item[1]) {
|
|
61
|
-
story.image = {
|
|
62
|
-
newsUrl: String(item[1][0] || ''),
|
|
63
|
-
source: String(item[1][1] || ''),
|
|
64
|
-
imageUrl: String(item[1][2] || '')
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
103
|
allTrendingStories.push(story);
|
|
68
104
|
summary.push({
|
|
69
105
|
title: story.title,
|
|
70
106
|
traffic: story.traffic,
|
|
71
|
-
articles: story.articles
|
|
107
|
+
articles: story.articles,
|
|
108
|
+
startTime,
|
|
109
|
+
...(endTime && { endTime }),
|
|
72
110
|
});
|
|
73
111
|
}
|
|
74
112
|
});
|
|
@@ -149,6 +149,10 @@ export class GoogleTrendsApi {
|
|
|
149
149
|
}
|
|
150
150
|
//
|
|
151
151
|
async interestByRegion({ keyword, startTime = new Date('2004-01-01'), endTime = new Date(), geo = 'US', resolution = 'REGION', hl = 'en-US', timezone = new Date().getTimezoneOffset(), category = 0 }) {
|
|
152
|
+
const keywordValue = Array.isArray(keyword) ? keyword[0] : keyword;
|
|
153
|
+
if (!keywordValue || keywordValue.trim() === '') {
|
|
154
|
+
return { error: new InvalidRequestError('Keyword is required') };
|
|
155
|
+
}
|
|
152
156
|
const formatDate = (date) => {
|
|
153
157
|
return date.toISOString().split('T')[0];
|
|
154
158
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaivpidadi/trends-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Google Trends API for Node.js",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/jest": "^29.5.0",
|
|
44
44
|
"@types/node": "^20.0.0",
|
|
45
|
-
"jest": "^29.
|
|
45
|
+
"jest": "^29.7.0",
|
|
46
46
|
"ts-jest": "^29.1.0",
|
|
47
47
|
"typescript": "^5.0.0"
|
|
48
48
|
}
|