frostpv 1.0.8 → 1.0.10
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/index.js +73 -25
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -58,7 +58,13 @@ const videoPlatforms = [
|
|
|
58
58
|
"https://twitter.com",
|
|
59
59
|
"https://www.twitter.com",
|
|
60
60
|
"https://vm.tiktok.com/",
|
|
61
|
-
"https://vt.tiktok.com/"
|
|
61
|
+
"https://vt.tiktok.com/",
|
|
62
|
+
"https://www.youtube.com",
|
|
63
|
+
"https://youtube.com",
|
|
64
|
+
"https://youtu.be",
|
|
65
|
+
"https://m.youtube.com",
|
|
66
|
+
"https://www.youtube.com/watch?"
|
|
67
|
+
|
|
62
68
|
];
|
|
63
69
|
|
|
64
70
|
// Blacklist links
|
|
@@ -1145,41 +1151,83 @@ async function downloadSmartVideo(url, config) {
|
|
|
1145
1151
|
try {
|
|
1146
1152
|
const data = await youtube(url);
|
|
1147
1153
|
// Try to find the video URL in the response
|
|
1148
|
-
// Common patterns: data.url, data.mp4, data.link, or direct string
|
|
1149
1154
|
|
|
1150
1155
|
if (!data) throw new Error("No data returned from youtube downloader");
|
|
1151
1156
|
|
|
1152
|
-
//
|
|
1153
|
-
const
|
|
1154
|
-
|
|
1155
|
-
|
|
1157
|
+
// Helper to check if a value looks like a video URL
|
|
1158
|
+
const isVideoUrl = (val) => typeof val === 'string' && val.startsWith('http') && !val.includes('.mp3');
|
|
1159
|
+
|
|
1160
|
+
let bestUrl = null;
|
|
1161
|
+
let bestScore = -1;
|
|
1162
|
+
|
|
1163
|
+
// Function to score keys based on quality
|
|
1164
|
+
const getScore = (key) => {
|
|
1165
|
+
const k = key.toLowerCase();
|
|
1166
|
+
if (k.includes('1080')) return 100;
|
|
1167
|
+
if (k.includes('720')) return 80;
|
|
1168
|
+
if (k.includes('480')) return 60;
|
|
1169
|
+
if (k.includes('hd')) return 90;
|
|
1170
|
+
if (k.includes('sd')) return 50;
|
|
1171
|
+
if (k.includes('360')) return 40;
|
|
1172
|
+
if (k.includes('mp4')) return 30;
|
|
1173
|
+
if (k.includes('video')) return 20;
|
|
1174
|
+
return 10;
|
|
1175
|
+
};
|
|
1156
1176
|
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1177
|
+
// Recursive function to gather all candidates
|
|
1178
|
+
const gatherCandidates = (obj) => {
|
|
1179
|
+
if (!obj) return;
|
|
1180
|
+
|
|
1181
|
+
if (typeof obj === 'object') {
|
|
1182
|
+
for (const key in obj) {
|
|
1183
|
+
const val = obj[key];
|
|
1184
|
+
if (isVideoUrl(val)) {
|
|
1185
|
+
const score = getScore(key);
|
|
1186
|
+
if (score > bestScore) {
|
|
1187
|
+
bestScore = score;
|
|
1188
|
+
bestUrl = val;
|
|
1189
|
+
}
|
|
1190
|
+
} else if (typeof val === 'object') {
|
|
1191
|
+
// Check if this object represents a format (e.g. { quality: '720p', url: '...' })
|
|
1192
|
+
if (val.url && isVideoUrl(val.url)) {
|
|
1193
|
+
let score = getScore(key); // Score from key name
|
|
1194
|
+
if (val.quality || val.resolution) {
|
|
1195
|
+
score = Math.max(score, getScore(String(val.quality || val.resolution)));
|
|
1196
|
+
}
|
|
1197
|
+
if (score > bestScore) {
|
|
1198
|
+
bestScore = score;
|
|
1199
|
+
bestUrl = val.url;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
// Recurse
|
|
1203
|
+
gatherCandidates(val);
|
|
1204
|
+
}
|
|
1161
1205
|
}
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1206
|
+
}
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
gatherCandidates(data);
|
|
1210
|
+
|
|
1211
|
+
// If no scored candidate found, try direct simple extraction with priority keys
|
|
1212
|
+
if (!bestUrl) {
|
|
1213
|
+
const priorities = ['mp4', 'url', 'link', 'download', 'video'];
|
|
1214
|
+
const findSimple = (obj) => {
|
|
1215
|
+
if (!obj) return null;
|
|
1165
1216
|
for (const key of priorities) {
|
|
1166
|
-
if (obj[key])
|
|
1167
|
-
const found = findVideoUrl(obj[key]);
|
|
1168
|
-
if (found) return found;
|
|
1169
|
-
}
|
|
1217
|
+
if (obj[key] && isVideoUrl(obj[key])) return obj[key];
|
|
1170
1218
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
const found = findVideoUrl(obj[key]);
|
|
1219
|
+
for (const key in obj) {
|
|
1220
|
+
if (typeof obj[key] === 'object') {
|
|
1221
|
+
const found = findSimple(obj[key]);
|
|
1175
1222
|
if (found) return found;
|
|
1176
1223
|
}
|
|
1177
1224
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1225
|
+
return null;
|
|
1226
|
+
};
|
|
1227
|
+
bestUrl = findSimple(data);
|
|
1228
|
+
}
|
|
1181
1229
|
|
|
1182
|
-
videoUrl =
|
|
1230
|
+
videoUrl = bestUrl;
|
|
1183
1231
|
|
|
1184
1232
|
if (!videoUrl) {
|
|
1185
1233
|
console.log('YouTube data dump:', JSON.stringify(data, null, 2)); // Debug log since we can't test
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frostpv",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "downloads",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"license": "ISC",
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"axios": "1.12.0",
|
|
16
|
-
"btch-downloader": "6.0.
|
|
16
|
+
"btch-downloader": "6.0.23",
|
|
17
17
|
"btch-downloader-old": "npm:btch-downloader@4.0.15",
|
|
18
18
|
"express": "^5.1.0",
|
|
19
19
|
"ffmpeg-ffprobe-static": "^6.1.1-rc.5",
|