-
-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathfb_videoDownloader.js
161 lines (145 loc) · 4.81 KB
/
fb_videoDownloader.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
export default {
icon: '<i class="fa-solid fa-video fa-lg"></i>',
name: {
en: "Download fb video/reel/watch from url",
vi: "Tải video/reel/watch fb từ url",
},
description: {
en: "Download facebook video/reel/watch",
vi: "Tải facebook video/reel/watch",
},
whiteList: ["https://*.facebook.com/*"],
popupScript: {
onClick: async function () {
const { getCurrentTab, showLoading } = await import("./helpers/utils.js");
let tab = await getCurrentTab();
let url = prompt("Nhập link video/reel/watch:", tab.url);
let videoId = shared.extractFbVideoIdFromUrl(url);
if (!videoId) {
alert(
"Link không đúng định dạng, không tìm thấy video/reel/watch id trong link."
);
return;
}
let { closeLoading, setLoadingText } = showLoading("Đang lấy token...");
try {
let dtsg = await shared.getDtsg();
setLoadingText("Đang get link video...");
let link = await shared.getLinkFbVideo(videoId, dtsg);
if (link) window.open(link);
else throw Error("Không tìm thấy link");
} catch (e) {
alert("ERROR: " + e);
} finally {
closeLoading();
}
},
},
};
export const shared = {
extractFbVideoIdFromUrl: function (url) {
return url.match(/\/(?:videos|reel|watch)(?:\/?)(?:\?v=)?(\d+)/)?.[1];
},
getDtsg: async function () {
const { runScriptInCurrentTab } = await import("./helpers/utils.js");
return await runScriptInCurrentTab(() => {
return require("DTSGInitialData").token;
});
},
stringifyVariables: function (d, e) {
let f = [],
a;
for (a in d)
if (d.hasOwnProperty(a)) {
let g = e ? e + "[" + a + "]" : a,
b = d[a];
f.push(
null !== b && "object" == typeof b
? shared.stringifyVariables(b, g)
: encodeURIComponent(g) + "=" + encodeURIComponent(b)
);
}
return f.join("&");
},
getLinkFbVideo: async function (videoId, dtsg) {
try {
return await shared.getLinkFbVideo2(videoId, dtsg);
} catch (e) {
return await shared.getLinkFbVideo1(videoId, dtsg);
}
},
// Original source code: https://gist.github.com/monokaijs/270e29620c46cabec1caca8c3746729d
// POST FB: https://www.facebook.com/groups/j2team.community/posts/1880294815635963/
// Cần thêm rule trong rule.jsons để hàm này có thể chạy trong extension context
getLinkFbVideo1: async function (videoId, dtsg) {
function fetchGraphQl(doc_id, variables) {
return fetch("https://www.facebook.com/api/graphql/", {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
},
body: shared.stringifyVariables({
doc_id: doc_id,
variables: JSON.stringify(variables),
fb_dtsg: dtsg,
server_timestamps: !0,
}),
});
}
let res = await fetchGraphQl("5279476072161634", {
UFI2CommentsProvider_commentsKey: "CometTahoeSidePaneQuery",
caller: "CHANNEL_VIEW_FROM_PAGE_TIMELINE",
displayCommentsContextEnableComment: null,
displayCommentsContextIsAdPreview: null,
displayCommentsContextIsAggregatedShare: null,
displayCommentsContextIsStorySet: null,
displayCommentsFeedbackContext: null,
feedbackSource: 41,
feedLocation: "TAHOE",
focusCommentID: null,
privacySelectorRenderLocation: "COMET_STREAM",
renderLocation: "video_channel",
scale: 1,
streamChainingSection: !1,
useDefaultActor: !1,
videoChainingContext: null,
videoID: videoId,
});
let text = await res.text();
let a = JSON.parse(text.split("\n")[0]),
link = a.data.video.playable_url_quality_hd || a.data.video.playable_url;
return link;
},
// DYL extension: faster
getLinkFbVideo2: async function (videoId, dtsg) {
let res = await fetch(
"https://www.facebook.com/video/video_data_async/?video_id=" + videoId,
{
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: shared.stringifyVariables({
__a: "1",
fb_dtsg: dtsg,
}),
}
);
let text = await res.text();
console.log(text);
text = text.replace("for (;;);", "");
let json = JSON.parse(text);
const { hd_src, hd_src_no_ratelimit, sd_src, sd_src_no_ratelimit } =
json?.payload || {};
return hd_src_no_ratelimit || hd_src || sd_src_no_ratelimit || sd_src;
},
// DYL extension: use access token
getLinkFbVideo3: async function (videoId, access_token) {
let res = await fetch(
"https://graph.facebook.com/v8.0/" +
videoId +
"?fields=source&access_token=" +
access_token
);
let json = await res.json();
return json.source;
},
};