diff --git a/src/dash.js b/src/dash.js
index 01a34809..cb57b1d6 100644
--- a/src/dash.js
+++ b/src/dash.js
@@ -37,7 +37,9 @@ function generateDash(dashInfo)
function _addAdaptationSet(streamsArr)
{
- const mimeInfo = _getMimeInfo(streamsArr[0].mimeType);
+ /* We just need it for adaptation type,
+ * so any stream will do */
+ const { mimeInfo } = streamsArr[0];
const adaptArr = [
`contentType="${mimeInfo.content}"`,
@@ -93,11 +95,9 @@ function _addAdaptationSet(streamsArr)
function _getStreamRepresentation(stream)
{
- const mimeInfo = _getMimeInfo(stream.mimeType);
-
const repOptsArr = [
`id="${stream.itag}"`,
- `codecs="${mimeInfo.codecs}"`,
+ `codecs="${stream.mimeInfo.codecs}"`,
`bandwidth="${stream.bitrate}"`,
];
@@ -120,13 +120,8 @@ function _getStreamRepresentation(stream)
repArr.push(` `);
}
- const encodedURL = Misc.encodeHTML(stream.url)
- .replace('?', '/')
- .replace(/&/g, '/')
- .replace(/=/g, '/');
-
repArr.push(
- ` ${encodedURL}`
+ ` ${stream.url}`
);
if(stream.indexRange) {
@@ -152,22 +147,6 @@ function _getStreamRepresentation(stream)
return repArr.join('\n');
}
-function _getMimeInfo(mimeType)
-{
- const mimeArr = mimeType.split(';');
-
- let codecs = mimeArr.find(info => info.includes('codecs')).split('=')[1];
- codecs = codecs.substring(1, codecs.length - 1);
-
- const mimeInfo = {
- content: mimeArr[0].split('/')[0],
- type: mimeArr[0],
- codecs,
- };
-
- return mimeInfo;
-}
-
function _getPar(width, height)
{
const gcd = _getGCD(width, height);
diff --git a/src/youtube.js b/src/youtube.js
index afc34a5d..c84b2010 100644
--- a/src/youtube.js
+++ b/src/youtube.js
@@ -357,27 +357,75 @@ var YouTubeClient = GObject.registerClass({
)
return null;
- /* TODO: Options in prefs to set preferred video formats for adaptive streaming */
- const videoStream = info.streamingData.adaptiveFormats.find(stream => {
- return (stream.mimeType.startsWith('video/mp4') && stream.quality === 'hd1080');
- });
- const audioStream = info.streamingData.adaptiveFormats.find(stream => {
- return (stream.mimeType.startsWith('audio/mp4'));
- });
+ /* TODO: Options in prefs to set preferred video formats and adaptive streaming */
+ const isAdaptiveEnabled = false;
+ const allowedFormats = {
+ video: [
+ 133,
+ 134,
+ 135,
+ 136,
+ 137,
+ 298,
+ 299,
+ ],
+ audio: [
+ 140,
+ ]
+ };
- if(!videoStream || !audioStream)
- return null;
+ const filteredStreams = {
+ video: [],
+ audio: [],
+ };
+
+ for(let fmt of ['video', 'audio']) {
+ debug(`filtering ${fmt} streams`);
+ let index = allowedFormats[fmt].length;
+
+ while(index--) {
+ const itag = allowedFormats[fmt][index];
+ const foundStream = info.streamingData.adaptiveFormats.find(stream => (stream.itag == itag));
+ if(foundStream) {
+ /* Parse and convert mimeType string into object */
+ foundStream.mimeInfo = this._getMimeInfo(foundStream.mimeType);
+
+ /* Sanity check */
+ if(!foundStream.mimeInfo || foundStream.mimeInfo.content !== fmt) {
+ debug(new Error(`mimeType parsing failed on stream: ${itag}`));
+ continue;
+ }
+
+ /* Sort from worst to best */
+ filteredStreams[fmt].unshift(foundStream);
+ debug(`added ${fmt} itag: ${foundStream.itag}`);
+
+ if(!isAdaptiveEnabled)
+ break;
+ }
+ }
+ if(!filteredStreams[fmt].length) {
+ debug(`dash info ${fmt} streams list is empty`);
+ return null;
+ }
+ }
debug('following redirects');
- for(let stream of [videoStream, audioStream]) {
- debug(`initial URL: ${stream.url}`);
+ for(let fmtArr of Object.values(filteredStreams)) {
+ for(let stream of fmtArr) {
+ debug(`initial URL: ${stream.url}`);
- const result = await this._downloadDataPromise(stream.url, 'HEAD').catch(debug);
- if(!result) return null;
+ const result = await this._downloadDataPromise(stream.url, 'HEAD').catch(debug);
+ if(!result) return null;
- stream.url = result.uri;
- debug(`resolved URL: ${stream.url}`);
+ stream.url = Misc.encodeHTML(result.uri)
+ .replace('?', '/')
+ .replace(/&/g, '/')
+ .replace(/=/g, '/');
+
+ debug(`resolved URL: ${stream.url}`);
+ }
}
debug('all redirects resolved');
@@ -385,8 +433,8 @@ var YouTubeClient = GObject.registerClass({
return {
duration: info.videoDetails.lengthSeconds,
adaptations: [
- [videoStream],
- [audioStream],
+ filteredStreams.video,
+ filteredStreams.audio,
]
};
}
@@ -527,6 +575,26 @@ var YouTubeClient = GObject.registerClass({
return reduced;
}
+ _getMimeInfo(mimeType)
+ {
+ debug(`parsing mimeType: ${mimeType}`);
+
+ const mimeArr = mimeType.split(';');
+
+ let codecs = mimeArr.find(info => info.includes('codecs')).split('=')[1];
+ codecs = codecs.substring(1, codecs.length - 1);
+
+ const mimeInfo = {
+ content: mimeArr[0].split('/')[0],
+ type: mimeArr[0],
+ codecs,
+ };
+
+ debug(`parsed mimeType: ${JSON.stringify(mimeInfo)}`);
+
+ return mimeInfo;
+ }
+
_getPlayerInfoPromise(videoId)
{
const data = this._getPlayerPostData(videoId);