![]() * Added Chromium caching of identity provider cookies * Moved token expiry check in standalone method * Created refreshSession function * Session is now refreshed if the token expires * Linting fixes * Removed debug console.log() * Added CC support * Created function to prompt user for download parameters (interactive mode) * Fix data folder for puppeteer * Fixed multiple session error * Fix token expire time * Moved session refreshing to a more sensible place * Changed Metadata name to Video (to better reflect the data structure) * Complete CLI refactoring * Removed useless sleep function * Added outDir check from CLI * Complete input parsing refactoring (both inline and file) * Fixed and improved tests to work with the new input parsing * Moved and improved output path generation to videoUtils * Main code refactoring, added outpath to video type * Minor changes in spacing and type definition style * Updated readme after code refactoring * Fix if inputFile doesn't start with url on line 1 * Minor naming change * Use module 'winston' for logging * Created logge, changed all console.log and similar to use the logger * Added verbose logging, changed posterUrl property name on Video type * Moved GUID extraction to input parsing * Added support for group links * Fixed test after last input parsing update * Removed debug proces.exit() * Changed from desc to asc order for group videos * Updated test to reflect GUIDs output after parsing * Added couple of comments and restyled some imports * More readable verbose GUIDs logging * Removed unused errors * Temporary fix for timeout not working in ApiClient * Explicit class member accessibility * Defined array naming schema to be Array<T> * Defined type/interface schema to be type only * A LOT of type definitions |
||
---|---|---|
.github | ||
.vscode | ||
assets | ||
scripts | ||
src | ||
test | ||
.eslintrc.json | ||
.gitignore | ||
CONTRIBUTING.md | ||
destreamer.cmd | ||
destreamer.ps1 | ||
destreamer.sh | ||
LICENSE | ||
package-lock.json | ||
package.json | ||
README.md | ||
tsconfig.json |
(Alternative artwork proposals are welcome! Submit one through an Issue.)
Saves Microsoft Stream videos for offline enjoyment
v2.0 Release, codename Hammer of DawnTM
This release would not have been possible without the code and time contributed by two distinguished developers: @lukaarma and @kylon. Thank you!
Politecnico di Milano students may want to use this fork over at https://github.com/SamanFekri/destreamer which is a specialized implementation of this project with automatic logon.
Another specialized implementation (for University of Pisa this time) is available at https://github.com/Guray00/destreamer-unipi.
Outstanding bugs
- We couldn't yet find an elegant way to refresh the access token, so you'll need to perform an interactive logon every hour or so. We're still at the drawing board on this one.
What's new
- Major code refactoring
- Dramatically improved error handling
- We now have a token cache so we can reuse access tokens. This really means that within one hour you need to perform the interactive browser login only once.
- We removed the dependency on
youtube-dl
- Getting to the HLS URL is dramatically more reliable as we dropped parsing the DOM for the video element in favor of calling the Microsoft Stream API
- Fixed a major 2FA bug that would sometimes cause a timeout in our code
- Fixed a wide variety of other bugs, maybe introduced a few new ones :)
Disclaimer
Hopefully this doesn't break the end user agreement for Microsoft Stream. Since we're simply saving the HLS stream to disk as if we were a browser, this does not abuse the streaming endpoints. However i take no responsibility if either Microsoft or your Office 365 admins request a chat with you in a small white room.
Prereqs
- Node.js: You'll need Node.js version 8.0 or higher. A GitHub Action runs tests on all major Node versions on every commit. One caveat for Node 8, if you get a
Parse Error
withcode: HPE_HEADER_OVERFLOW
you're out of luck and you'll need to upgrade to Node 10+. - npm: usually comes with Node.js, type
npm
in your terminal to check for its presence - ffmpeg: a recent version (year 2019 or above), in
$PATH
or in the same directory as this README file (project root). - git: one or more npm dependencies require git.
Destreamer takes a honeybadger approach towards the OS it's running on. We've successfully tested it on Windows, macOS and Linux.
Limits and limitations
Make sure you use the right script (.sh
, .ps1
or .cmd
) and escape char (if using line breaks) for your shell.
PowerShell uses a backtick [ ` ] and cmd.exe uses a caret [ ^ ].
Note that destreamer won't run in an elevated (Administrator/root) shell. Running inside Cygwin/MinGW/MSYS may also fail, please use cmd.exe or PowerShell if you're on Windows.
WSL (Windows Subsystem for Linux) is not supported as it can't easily pop up a browser window. It may work by installing an X Window server (like Xming) and exporting the default display to it (export DISPLAY=:0
) before running destreamer. See this issue for more on WSL v1 and v2.
How to build
To build destreamer clone this repository, install dependencies and run the build script -
$ git clone https://github.com/snobu/destreamer
$ cd destreamer
$ npm install
$ npm run build
Usage
$ ./destreamer.sh
Options:
--help Show help [boolean]
--version Show version number [boolean]
--username, -u The username used to log into Microsoft Stream (enabling this will fill in the email field for
you) [string]
--videoUrls, -i List of video urls [array]
--inputFile, -f Path to text file containing URLs and optionally outDirs. See the README for more on outDirs.
[string]
--outputDirectory, -o The directory where destreamer will save your downloads [string] [default: "videos"]
--keepLoginCookies, -k Let Chromium cache identity provider cookies so you can use "Remember me" during login
[boolean] [default: false]
--noExperiments, -x Do not attempt to render video thumbnails in the console [boolean] [default: false]
--simulate, -s Disable video download and print metadata information to the console[boolean] [default: false]
--verbose, -v Print additional information to the console (use this before opening an issue on GitHub)
[boolean] [default: false]
--closedCaptions, --cc Check if closed captions are aviable and let the user choose which one to download (will not
ask if only one aviable) [boolean] [default: false]
--noCleanup, --nc Do not delete the downloaded video file when an FFmpeg error occurs [boolean] [default: false]
--vcodec Re-encode video track. Specify FFmpeg codec (e.g. libx265) or set to "none" to disable video.
[string] [default: "copy"]
--acodec Re-encode audio track. Specify FFmpeg codec (e.g. libopus) or set to "none" to disable audio.
[string] [default: "copy"]
--format Output container format (mkv, mp4, mov, anything that FFmpeg supports)
[string] [default: "mkv"]
--skip Skip download if file already exists [boolean] [default: false]
-
Passing
--username
is optional. It's there to make logging in faster (the username field will be populated automatically on the login form). -
You can use an absolute path for
-o
(output directory), for example/mnt/videos
. -
We default to
.mkv
for the output container. If you prefer something else (likemp4
), pass--format mp4
.
Download a video -
$ ./destreamer.sh -i "https://web.microsoftstream.com/video/VIDEO-1"
Download a video and re-encode with HEVC (libx265) -
$ ./destreamer.sh -i "https://web.microsoftstream.com/video/VIDEO-1" --vcodec libx265
Download a video and speed up the interactive login by automagically filling in the username -
$ ./destreamer.sh -u user@example.com -i "https://web.microsoftstream.com/video/VIDEO-1"
Download a video to a custom path -
$ ./destreamer.sh -i "https://web.microsoftstream.com/video/VIDEO-1" -o /Users/hacker/Downloads
Download two or more videos -
$ ./destreamer.sh -i "https://web.microsoftstream.com/video/VIDEO-1" \
"https://web.microsoftstream.com/video/VIDEO-2"
Download many videos but read URLs from a file -
$ ./destreamer.sh -f list.txt
Input file
You can create a .txt
file containing your video URLs, one video per line. The text file can have any name, followed by the .txt
extension.
Additionally you can have destreamer download each video in the input list to a separate directory.
These optional lines must start with white space(s).
Usage -
https://web.microsoftstream.com/video/xxxxxxxx-aaaa-xxxx-xxxx-xxxxxxxxxxxx
-dir=videos/lessons/week1
https://web.microsoftstream.com/video/xxxxxxxx-aaaa-xxxx-xxxx-xxxxxxxxxxxx
-dir=videos/lessons/week2"
Expected output
Windows Terminal -
iTerm2 on a Mac -
By default, downloads are saved under videos/
unless specified by -o
(output directory).
Contributing
Contributions are welcome. Open an issue first before sending in a pull request. All pull requests require at least one code review before they are merged to master.
Found a bug?
Please open an issue and we'll look into it.