mirror of
https://github.com/hyzendust/Sharepoint-Downloader.git
synced 2026-06-30 20:32:20 +02:00
171 lines
4.9 KiB
JavaScript
171 lines
4.9 KiB
JavaScript
console.log("Background script loaded");
|
|
|
|
// Classify and clean a URL, returning { cleanedUrl, type, label } or null
|
|
function classifyUrl(url) {
|
|
try {
|
|
const u = new URL(url);
|
|
const path = u.pathname.toLowerCase();
|
|
const host = u.hostname.toLowerCase();
|
|
|
|
// 1. SharePoint videomanifest (DASH / HLS / smooth)
|
|
if (path.includes("/transform/videomanifest")) {
|
|
let type = "dash";
|
|
if (url.includes("format=hls")) type = "hls";
|
|
return { cleanedUrl: url, type, label: "Video Manifest" };
|
|
}
|
|
|
|
// 2. Media proxy service (mediap.svc.ms) — actual stream chunks/manifests
|
|
if (host.includes("mediap.svc.ms")) {
|
|
if (path.endsWith(".m3u8") || url.includes(".m3u8")) {
|
|
return {
|
|
cleanedUrl: url.split("?")[0],
|
|
type: "hls",
|
|
label: "HLS Manifest (mediap)",
|
|
};
|
|
}
|
|
if (path.endsWith(".mpd") || url.includes(".mpd")) {
|
|
return {
|
|
cleanedUrl: url.split("?")[0],
|
|
type: "dash",
|
|
label: "DASH Manifest (mediap)",
|
|
};
|
|
}
|
|
// Catch-all for other mediap requests that look like manifests
|
|
if (path.includes("manifest") || path.includes("Manifest")) {
|
|
return {
|
|
cleanedUrl: url,
|
|
type: "dash",
|
|
label: "Stream Manifest (mediap)",
|
|
};
|
|
}
|
|
return null; // Ignore individual segment fetches
|
|
}
|
|
|
|
// 3. Standalone .m3u8 / .mpd files
|
|
if (path.endsWith(".m3u8") || path.match(/\.m3u8($|\?)/)) {
|
|
return {
|
|
cleanedUrl: url.split("?")[0],
|
|
type: "hls",
|
|
label: "HLS Manifest",
|
|
};
|
|
}
|
|
if (path.endsWith(".mpd") || path.match(/\.mpd($|\?)/)) {
|
|
return {
|
|
cleanedUrl: url.split("?")[0],
|
|
type: "dash",
|
|
label: "DASH Manifest",
|
|
};
|
|
}
|
|
|
|
// 4. SharePoint direct-download links
|
|
if (host.includes("sharepoint.com") && path.includes("download.aspx")) {
|
|
return { cleanedUrl: url, type: "direct", label: "Direct Download" };
|
|
}
|
|
|
|
// 5. SharePoint OneDrive transcode API segments (mid-playback encrypted segments)
|
|
// Strip per-segment params so all segments of the same video deduplicate to one entry.
|
|
if (
|
|
host.includes("sharepoint.com") &&
|
|
path.includes("/onedrive.transcode")
|
|
) {
|
|
const u2 = new URL(url);
|
|
// Keep only identity/auth params; drop segment-specific ones
|
|
const dropParams = new Set([
|
|
"part",
|
|
"track",
|
|
"quality",
|
|
"segmentTime",
|
|
"wsd",
|
|
"ppd",
|
|
"ppst",
|
|
"headerOffset",
|
|
"headerSize",
|
|
"correlationid",
|
|
"psi",
|
|
"ccat",
|
|
"PlaybackSessionData",
|
|
]);
|
|
for (const k of dropParams) u2.searchParams.delete(k);
|
|
return {
|
|
cleanedUrl: u2.toString(),
|
|
type: "direct",
|
|
label: "SP Transcode (use Current Page tab for yt-dlp)",
|
|
};
|
|
}
|
|
|
|
return null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
chrome.webRequest.onBeforeRequest.addListener(
|
|
(details) => {
|
|
try {
|
|
const result = classifyUrl(details.url);
|
|
if (!result) return;
|
|
|
|
const manifestData = {
|
|
originalUrl: details.url,
|
|
cleanedUrl: result.cleanedUrl,
|
|
type: result.type,
|
|
label: result.label,
|
|
timestamp: Date.now(),
|
|
tabId: details.tabId,
|
|
};
|
|
|
|
// Store per-tab list (keep last 20 per tab)
|
|
const storageKey = `manifests_${details.tabId}`;
|
|
chrome.storage.local.get(storageKey, (stored) => {
|
|
const list = stored[storageKey] || [];
|
|
// Avoid duplicates by cleanedUrl
|
|
if (!list.some((m) => m.cleanedUrl === manifestData.cleanedUrl)) {
|
|
list.push(manifestData);
|
|
if (list.length > 20) list.shift();
|
|
chrome.storage.local.set({ [storageKey]: list });
|
|
}
|
|
});
|
|
|
|
// Also keep a global "lastManifest" for backward compat
|
|
chrome.storage.local.set({ lastManifest: manifestData });
|
|
|
|
chrome.runtime.sendMessage(
|
|
{ type: "manifestDetected", data: manifestData },
|
|
() => {
|
|
if (chrome.runtime.lastError) {
|
|
/* popup closed, ignore */
|
|
}
|
|
},
|
|
);
|
|
} catch (error) {
|
|
console.error("Error in webRequest listener:", error);
|
|
}
|
|
},
|
|
{ urls: ["<all_urls>"] },
|
|
);
|
|
|
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
if (message.type === "getManifests") {
|
|
const tabId = message.tabId;
|
|
const storageKey = `manifests_${tabId}`;
|
|
chrome.storage.local.get([storageKey, "lastManifest"], (result) => {
|
|
if (chrome.runtime.lastError) {
|
|
sendResponse({ manifests: [], lastManifest: null });
|
|
} else {
|
|
sendResponse({
|
|
manifests: result[storageKey] || [],
|
|
lastManifest: result.lastManifest || null,
|
|
});
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
if (message.type === "clearManifests") {
|
|
const tabId = message.tabId;
|
|
chrome.storage.local.remove(`manifests_${tabId}`, () => {
|
|
sendResponse({ ok: true });
|
|
});
|
|
return true;
|
|
}
|
|
});
|