mirror of
https://github.com/hyzendust/Sharepoint-Downloader.git
synced 2026-06-30 20:32:20 +02:00
Enhance popup interface with cookie handling and warning for yt-dlp commands
This commit is contained in:
92
README.md
92
README.md
@@ -1,73 +1,87 @@
|
|||||||
# MTH Video Manifest Capture
|
# SharePoint Video Downloader
|
||||||
|
|
||||||
A Chrome extension that captures video manifest URLs (e.g., HLS `.m3u8`, MPEG-DASH `.mpd`, and SharePoint DASH manifests) from web pages, processes them, and generates FFmpeg and yt-dlp commands for downloading.
|
A Chrome/Edge extension that captures SharePoint/OneDrive Stream video URLs and generates ready-to-run yt-dlp and FFmpeg download commands.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
**MTH Video Manifest Capture** is designed to assist users in capturing and processing video streaming manifests, particularly for SharePoint, HLS, and DASH formats. The extension provides a user-friendly popup interface to view cleaned manifest URLs, select quality and format options, set custom filenames, and copy commands for FFmpeg and yt-dlp to download the video content.
|
**SharePoint Video Downloader** detects video manifests and stream URLs on SharePoint/OneDrive pages and generates download commands with the correct authentication flags. It supports both `--cookies-from-browser` (browser must be closed) and `--cookies cookies.txt` (browser can stay open) workflows.
|
||||||
|
|
||||||
This extension is built using Chrome's **Manifest V3**, ensuring modern security and performance standards.
|
Built using Chrome **Manifest V3**.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Captures video manifest URLs** (`.m3u8`, `.mpd`, and SharePoint `/transform/videomanifest` with `format=dash`).
|
- **Detects SharePoint stream URLs** — `/transform/videomanifest` (DASH/HLS), `mediap.svc.ms` proxy manifests, `oneDrive.transcode` segment endpoints, and direct `download.aspx` links.
|
||||||
- **Cleans URLs** by removing unnecessary parameters (e.g., after `format=dash`).
|
- **Per-tab URL capture** — stores up to 20 URLs per tab, deduplicated.
|
||||||
- **Generates customizable FFmpeg and yt-dlp commands** with options for quality (Best, 1080p, 720p, 480p) and format (MP4, MKV, TS).
|
- **Current Page shortcut** — one-click copy of a yt-dlp command using the active SharePoint tab URL (uses the built-in SharePoint extractor).
|
||||||
- **Allows custom output filenames** or uses a timestamp-based default (e.g., `video_YYYYMMDD_HHMMSS`).
|
- **Two cookie modes** — `--cookies-from-browser <browser>` and `--cookies cookies.txt`.
|
||||||
- **"Download Manifest" button** to open the cleaned manifest URL in a new tab or initiate a basic download of the manifest file.
|
- **Cookie lock warning** — shows a warning when Edge/Chrome/Brave is selected, since Chromium locks the cookie database while the browser is open.
|
||||||
- **Toggle buttons** to expand/collapse long URLs and commands for better readability.
|
- **Customizable output** — quality (Best, 1080p, 720p, 480p), format (MP4, MKV, TS), and custom filename.
|
||||||
- **Copy buttons** for FFmpeg and yt-dlp commands to easily paste into a terminal.
|
- **Copy buttons** for all commands.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Google Chrome or Chromium browser (**Manifest V3 compatible, version 88 or later**).
|
- **Edge or Chrome** (Manifest V3, version 88+).
|
||||||
- FFmpeg and yt-dlp installed on your system (**optional, for running the generated commands**).
|
- **yt-dlp** — `pip install yt-dlp` or download from [github.com/yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp).
|
||||||
|
- **FFmpeg** *(optional)* — [ffmpeg.org](https://ffmpeg.org/).
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
|
|
||||||
1. **Clone or Download the Repository**
|
1. **Clone or download the repository**
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/MiniduTH/Sharepoint-Downloader.git
|
git clone https://github.com/MiniduTH/Sharepoint-Downloader.git
|
||||||
```
|
```
|
||||||
Or download the ZIP file and extract it.
|
|
||||||
|
|
||||||
2. **Load the Extension in Chrome**
|
2. **Load the extension**
|
||||||
- Open Chrome and navigate to `chrome://extensions/`.
|
- Edge: `edge://extensions/` → Enable **Developer mode** → **Load unpacked** → select the folder.
|
||||||
- Enable **"Developer mode"** in the top-right corner.
|
- Chrome: `chrome://extensions/` → same steps.
|
||||||
- Click **"Load unpacked"** and select the `Sharepoint-Downloader` folder.
|
|
||||||
|
|
||||||
3. **Install Dependencies** *(optional, for using generated commands)*
|
|
||||||
- **FFmpeg:** Install via your package manager (e.g., `sudo apt install ffmpeg` on Ubuntu) or download from [ffmpeg.org](https://ffmpeg.org/).
|
|
||||||
- **yt-dlp:** Install via `pip install yt-dlp` or download from [yt-dlp.org](https://yt-dlp.org/).
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
1. **Open a Web Page with Video Manifests**
|
### Recommended: Current Page method
|
||||||
- Visit a website streaming video content (e.g., SharePoint, HLS, or DASH streams).
|
|
||||||
|
|
||||||
2. **Activate the Extension**
|
1. Open the SharePoint video page in your browser.
|
||||||
- Click the **"MTH Video Manifest Capture"** icon in the Chrome toolbar.
|
2. Click the extension icon.
|
||||||
|
3. In the **Current Page** card, click **Copy yt-dlp (cookies.txt)** (if Edge is open) or **Copy yt-dlp Command** (if you'll close the browser first).
|
||||||
|
4. Paste into a terminal and run.
|
||||||
|
|
||||||
3. **Capture Manifests**
|
### Cookie authentication — two options
|
||||||
- The extension automatically detects and captures video manifest URLs (`.m3u8`, `.mpd`, or SharePoint DASH manifests).
|
|
||||||
- The cleaned URL, FFmpeg command, and yt-dlp command will appear in the popup.
|
|
||||||
|
|
||||||
4. **Customize Options**
|
#### Option A: `--cookies-from-browser` (no extra setup, but browser must be closed)
|
||||||
- Use the dropdowns to select video quality (**Best, 1080p, 720p, 480p**) and format (**MP4, MKV, TS**).
|
|
||||||
- Enter a custom output filename, or leave it blank to use the timestamp-based default (e.g., `video_20250305_143022.mp4`).
|
|
||||||
|
|
||||||
5. **Copy Commands**
|
Chromium-based browsers (Edge, Chrome, Brave) **lock the cookie database while running**. You must close the browser before running the command.
|
||||||
- Click **"Copy FFmpeg"** or **"Copy yt-dlp"** to copy the respective commands to your clipboard.
|
|
||||||
- Paste the commands into a terminal to download the video using FFmpeg or yt-dlp.
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Close Edge/Chrome completely
|
||||||
|
# 2. Run:
|
||||||
|
yt-dlp --cookies-from-browser edge -f "bestvideo+bestaudio/best" --merge-output-format mp4 -o "lecture.mp4" "https://mysliit-my.sharepoint.com/..."
|
||||||
|
# 3. Reopen the browser
|
||||||
|
```
|
||||||
|
|
||||||
## Screenshots
|
Firefox does **not** lock its cookie database, so `--cookies-from-browser firefox` works while the browser is open.
|
||||||
|
|
||||||
_Screenshot of the popup interface showing captured manifest, commands, and options._
|
#### Option B: `--cookies cookies.txt` ✅ Confirmed working
|
||||||
|
|
||||||

|
Export cookies while the browser is open using the **[Get cookies.txt LOCALLY](https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)** extension, then run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yt-dlp --cookies cookies.txt -f "bestvideo+bestaudio/best" --merge-output-format mp4 -o "lecture.mp4" "https://mysliit-my.sharepoint.com/..."
|
||||||
|
```
|
||||||
|
|
||||||
|
**Steps to export cookies.txt:**
|
||||||
|
1. Install **Get cookies.txt LOCALLY** in Edge/Chrome.
|
||||||
|
2. Navigate to `mysliit-my.sharepoint.com` (or your SharePoint domain).
|
||||||
|
3. Click the extension icon → **Export** → save as `cookies.txt` in the same folder where you'll run yt-dlp.
|
||||||
|
4. Use the **Copy yt-dlp (cookies.txt)** button in this extension to get the command.
|
||||||
|
|
||||||
|
### Captured Stream URLs
|
||||||
|
|
||||||
|
The extension also intercepts manifest URLs as you play the video:
|
||||||
|
|
||||||
|
1. Play the video on SharePoint.
|
||||||
|
2. Open the extension popup — captured URLs appear in the **Captured Stream URLs** list.
|
||||||
|
3. Click a URL to generate FFmpeg and yt-dlp commands for it in the **Download Commands** card.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
17
popup.css
17
popup.css
@@ -27,6 +27,23 @@ body {
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warn {
|
||||||
|
margin: 6px 0 4px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
background: #fff3cd;
|
||||||
|
border: 1px solid #ffc107;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #664d03;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.warn code {
|
||||||
|
background: rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 1px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Buttons ─────────────────────────────────────────── */
|
/* ── Buttons ─────────────────────────────────────────── */
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
|
|||||||
33
popup.html
33
popup.html
@@ -22,6 +22,13 @@
|
|||||||
<button id="copyTabYtdlp" class="btn secondary small">
|
<button id="copyTabYtdlp" class="btn secondary small">
|
||||||
Copy yt-dlp Command
|
Copy yt-dlp Command
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
id="copyTabYtdlpCookies"
|
||||||
|
class="btn secondary small"
|
||||||
|
style="display: none"
|
||||||
|
>
|
||||||
|
Copy yt-dlp (cookies.txt)
|
||||||
|
</button>
|
||||||
<button id="copyTabUrl" class="btn toggle small">Copy URL</button>
|
<button id="copyTabUrl" class="btn toggle small">Copy URL</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,6 +44,16 @@
|
|||||||
<option value="firefox">Firefox</option>
|
<option value="firefox">Firefox</option>
|
||||||
<option value="brave">Brave</option>
|
<option value="brave">Brave</option>
|
||||||
</select>
|
</select>
|
||||||
|
<div id="cookieWarn" class="warn" style="display: none">
|
||||||
|
⚠ <strong>Close your browser first!</strong> Chromium-based
|
||||||
|
browsers lock the cookie DB while open — yt-dlp will fail to read
|
||||||
|
cookies. Close it, run the command, then reopen.<br />
|
||||||
|
<span
|
||||||
|
>Alternative: export cookies with
|
||||||
|
<em>Get cookies.txt LOCALLY</em> extension, save as
|
||||||
|
<code>cookies.txt</code>, then use the command below.</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label>Quality:</label>
|
<label>Quality:</label>
|
||||||
<select id="quality" class="select">
|
<select id="quality" class="select">
|
||||||
@@ -104,7 +121,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="manifest-section">
|
<div class="manifest-section">
|
||||||
<label>yt-dlp:</label>
|
<label>yt-dlp (browser cookies):</label>
|
||||||
<div class="text-container">
|
<div class="text-container">
|
||||||
<p id="ytdlpCommand" class="text">Select a captured URL above.</p>
|
<p id="ytdlpCommand" class="text">Select a captured URL above.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -112,6 +129,20 @@
|
|||||||
Copy yt-dlp
|
Copy yt-dlp
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="manifest-section"
|
||||||
|
id="ytdlpCookiesFileSection"
|
||||||
|
style="display: none"
|
||||||
|
>
|
||||||
|
<label>yt-dlp (cookies.txt file):</label>
|
||||||
|
<div class="text-container">
|
||||||
|
<p id="ytdlpCookiesFileCommand" class="text"></p>
|
||||||
|
</div>
|
||||||
|
<button id="copyYtdlpCookiesFileBtn" class="btn secondary small">
|
||||||
|
Copy yt-dlp (cookies.txt)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
75
popup.js
75
popup.js
@@ -1,6 +1,7 @@
|
|||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
const tabUrlDiv = document.getElementById("tabUrl");
|
const tabUrlDiv = document.getElementById("tabUrl");
|
||||||
const copyTabYtdlp = document.getElementById("copyTabYtdlp");
|
const copyTabYtdlp = document.getElementById("copyTabYtdlp");
|
||||||
|
const copyTabYtdlpCookies = document.getElementById("copyTabYtdlpCookies");
|
||||||
const copyTabUrl = document.getElementById("copyTabUrl");
|
const copyTabUrl = document.getElementById("copyTabUrl");
|
||||||
const browserSelect = document.getElementById("browser");
|
const browserSelect = document.getElementById("browser");
|
||||||
const qualitySelect = document.getElementById("quality");
|
const qualitySelect = document.getElementById("quality");
|
||||||
@@ -12,6 +13,16 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const ytdlpCommandDiv = document.getElementById("ytdlpCommand");
|
const ytdlpCommandDiv = document.getElementById("ytdlpCommand");
|
||||||
const copyFfmpegBtn = document.getElementById("copyFfmpegBtn");
|
const copyFfmpegBtn = document.getElementById("copyFfmpegBtn");
|
||||||
const copyYtdlpBtn = document.getElementById("copyYtdlpBtn");
|
const copyYtdlpBtn = document.getElementById("copyYtdlpBtn");
|
||||||
|
const ytdlpCookiesFileSection = document.getElementById(
|
||||||
|
"ytdlpCookiesFileSection",
|
||||||
|
);
|
||||||
|
const ytdlpCookiesFileCommandDiv = document.getElementById(
|
||||||
|
"ytdlpCookiesFileCommand",
|
||||||
|
);
|
||||||
|
const copyYtdlpCookiesFileBtn = document.getElementById(
|
||||||
|
"copyYtdlpCookiesFileBtn",
|
||||||
|
);
|
||||||
|
const cookieWarn = document.getElementById("cookieWarn");
|
||||||
const refreshBtn = document.getElementById("refresh");
|
const refreshBtn = document.getElementById("refresh");
|
||||||
const clearAllBtn = document.getElementById("clearAll");
|
const clearAllBtn = document.getElementById("clearAll");
|
||||||
|
|
||||||
@@ -40,6 +51,19 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
return browserSelect.value;
|
return browserSelect.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether the selected browser uses a locked Chromium cookie DB
|
||||||
|
function isChromiumBrowser() {
|
||||||
|
return ["edge", "chrome", "brave"].includes(browser());
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCookieWarning() {
|
||||||
|
const show = isChromiumBrowser();
|
||||||
|
cookieWarn.style.display = show ? "" : "none";
|
||||||
|
ytdlpCookiesFileSection.style.display =
|
||||||
|
show && selectedManifest ? "" : "none";
|
||||||
|
copyTabYtdlpCookies.style.display = show ? "" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
// ── Command generators ───────────────────────────────────
|
// ── Command generators ───────────────────────────────────
|
||||||
|
|
||||||
function ytdlpForPage(url) {
|
function ytdlpForPage(url) {
|
||||||
@@ -53,6 +77,17 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
return `yt-dlp --cookies-from-browser ${browser()} -f "${fSel}" --merge-output-format ${fmt} -o "${name}" "${url}"`;
|
return `yt-dlp --cookies-from-browser ${browser()} -f "${fSel}" --merge-output-format ${fmt} -o "${name}" "${url}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ytdlpCookiesFileForPage(url) {
|
||||||
|
const q = qualitySelect.value;
|
||||||
|
const fmt = formatSelect.value;
|
||||||
|
const name = outName();
|
||||||
|
let fSel =
|
||||||
|
q === "best"
|
||||||
|
? "bestvideo+bestaudio/best"
|
||||||
|
: `bestvideo[height<=?${q.replace("p", "")}]+bestaudio/best[height<=?${q.replace("p", "")}]`;
|
||||||
|
return `yt-dlp --cookies cookies.txt -f "${fSel}" --merge-output-format ${fmt} -o "${name}" "${url}"`;
|
||||||
|
}
|
||||||
|
|
||||||
function ytdlpForManifest(url) {
|
function ytdlpForManifest(url) {
|
||||||
const q = qualitySelect.value;
|
const q = qualitySelect.value;
|
||||||
const fmt = formatSelect.value;
|
const fmt = formatSelect.value;
|
||||||
@@ -64,6 +99,17 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
return `yt-dlp --cookies-from-browser ${browser()} -f "${fSel}" --merge-output-format ${fmt} -o "${name}" "${url}"`;
|
return `yt-dlp --cookies-from-browser ${browser()} -f "${fSel}" --merge-output-format ${fmt} -o "${name}" "${url}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ytdlpCookiesFileForManifest(url) {
|
||||||
|
const q = qualitySelect.value;
|
||||||
|
const fmt = formatSelect.value;
|
||||||
|
const name = outName();
|
||||||
|
let fSel =
|
||||||
|
q === "best"
|
||||||
|
? "bestvideo+bestaudio/best"
|
||||||
|
: `bestvideo[height<=?${q.replace("p", "")}]+bestaudio/best[height<=?${q.replace("p", "")}]`;
|
||||||
|
return `yt-dlp --cookies cookies.txt -f "${fSel}" --merge-output-format ${fmt} -o "${name}" "${url}"`;
|
||||||
|
}
|
||||||
|
|
||||||
function ffmpegForManifest(url, type) {
|
function ffmpegForManifest(url, type) {
|
||||||
const name = outName();
|
const name = outName();
|
||||||
const referer = currentTabUrl
|
const referer = currentTabUrl
|
||||||
@@ -110,6 +156,15 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
copyTabYtdlpCookies.addEventListener("click", () => {
|
||||||
|
if (currentTabUrl)
|
||||||
|
copyText(
|
||||||
|
ytdlpCookiesFileForPage(currentTabUrl),
|
||||||
|
copyTabYtdlpCookies,
|
||||||
|
"Copy yt-dlp (cookies.txt)",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
copyTabUrl.addEventListener("click", () => {
|
copyTabUrl.addEventListener("click", () => {
|
||||||
if (currentTabUrl) copyText(currentTabUrl, copyTabUrl, "Copy URL");
|
if (currentTabUrl) copyText(currentTabUrl, copyTabUrl, "Copy URL");
|
||||||
});
|
});
|
||||||
@@ -166,6 +221,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
selectedManifest.type,
|
selectedManifest.type,
|
||||||
);
|
);
|
||||||
ytdlpCommandDiv.textContent = ytdlpForManifest(selectedManifest.cleanedUrl);
|
ytdlpCommandDiv.textContent = ytdlpForManifest(selectedManifest.cleanedUrl);
|
||||||
|
ytdlpCookiesFileCommandDiv.textContent = ytdlpCookiesFileForManifest(
|
||||||
|
selectedManifest.cleanedUrl,
|
||||||
|
);
|
||||||
|
updateCookieWarning();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Buttons ──────────────────────────────────────────────
|
// ── Buttons ──────────────────────────────────────────────
|
||||||
@@ -192,10 +251,24 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
copyText(ytdlpCommandDiv.textContent, copyYtdlpBtn, "Copy yt-dlp");
|
copyText(ytdlpCommandDiv.textContent, copyYtdlpBtn, "Copy yt-dlp");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
copyYtdlpCookiesFileBtn.addEventListener("click", () => {
|
||||||
|
copyText(
|
||||||
|
ytdlpCookiesFileCommandDiv.textContent,
|
||||||
|
copyYtdlpCookiesFileBtn,
|
||||||
|
"Copy yt-dlp (cookies.txt)",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Recalculate commands when options change
|
// Recalculate commands when options change
|
||||||
[qualitySelect, formatSelect, filenameInput, browserSelect].forEach((el) => {
|
[qualitySelect, formatSelect, filenameInput, browserSelect].forEach((el) => {
|
||||||
el.addEventListener("change", updateCommands);
|
el.addEventListener("change", () => {
|
||||||
|
updateCommands();
|
||||||
|
updateCookieWarning();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Init cookie warning on load
|
||||||
|
updateCookieWarning();
|
||||||
|
|
||||||
// Live-listen for new manifests
|
// Live-listen for new manifests
|
||||||
chrome.runtime.onMessage.addListener((msg) => {
|
chrome.runtime.onMessage.addListener((msg) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user