Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more flexible sorting algorithm. #138

Open
wants to merge 1 commit into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/lib/formats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
exports.formats = {
5: ['flv', '240', 'mp3', 64, null],
6: ['flv', '270', 'mp3', 64, null],
13: ['3gp', 'N/A', 'aac', null, null],
17: ['3gp', '144', 'aac', 24, null],
18: ['mp4', '360', 'aac', 96, null],
22: ['mp4', '720', 'aac', 192, null],
34: ['flv', '360', 'aac', 128, null],
35: ['flv', '280', 'aac', 128, null],
36: ['3gp', '240', 'aac', 38, null],
37: ['mp4', '1080', 'aac', 192, null],
38: ['mp4', '3072', 'aac', 192, null],
43: ['webm', '360', 'ogg', 128, null],
44: ['webm', '480', 'ogg', 128, null],
45: ['webm', '720', 'ogg', 192, null],
46: ['webm', '1080', 'ogg', 192, null],
83: ['mp4', '240', 'aac', 96, null],
82: ['mp4', '360', 'aac', 96, null],
59: ['mp4', '480', 'aac', 128, null],
78: ['mp4', '480', 'aac', 128, null],
85: ['mp4', '520', 'aac', 152, null],
84: ['mp4', '720', 'aac', 192, null],
100: ['webm', '360', 'ogg', 128, null],
101: ['webm', '360', 'ogg', 192, null],
102: ['webm', '720', 'ogg', 192, null],
120: ['flv', '720', 'aac', 128, null],
139: ['m4a', '48', 'aac', 38, 'a'], //Audio-only
140: ['m4a', '128', 'aac', 128, 'a'], //Audio-only
141: ['m4a', '256', 'aac', 256, 'a'], //Audio-only
171: ['webm', '128', 'ogg', 128, 'a'], //Audio-only
172: ['webm', '256', 'ogg', 192, 'a'], //Audio-only
249: ['webm', "48", 'opus', 50, 'a'],
250: ['webm', "48", 'opus', 70, 'a'],
251: ['webm', "128", 'opus', 160, 'a'],
160: ['mp4', '144', null, null, 'v'], //Video-only
133: ['mp4', '240', null, null, 'v'], //Video-only
134: ['mp4', '360', null, null, 'v'], //Video-only
135: ['mp4', '480', null, null, 'v'], //Video-only
298: ['mp4', '720', null, null, 'v'], //Video-only (60fps)
136: ['mp4', '720', null, null, 'v'], //Video-only
299: ['mp4', '1080', null, null, 'v'], //Video-only (60fps)
137: ['mp4', '1080', null, null, 'v'], //Video-only
138: ['mp4', '2160', null, null, 'v'], //Video-only
266: ['mp4', '2160', null, null, 'v'], //Video-only
264: ['mp4', '1440', null, null, 'v'], //Video-only
278: ['webm', '144', null, null, 'v'], //Video-only
242: ['webm', '240', null, null, 'v'], //Video-only
243: ['webm', '360', null, null, 'v'], //Video-only
244: ['webm', '480', null, null, 'v'], //Video-only
245: ['webm', '480', null, null, 'v'], //Video-only
246: ['webm', '480', null, null, 'v'], //Video-only
302: ['webm', '720', null, null, 'v'], //Video-only (60fps)
247: ['webm', '720', null, null, 'v'], //Video-only
303: ['webm', '1080', null, null, 'v'], //Video-only (60fps)
248: ['webm', '1080', null, null, 'v'], //Video-only
313: ['webm', '2160', null, null, 'v'], //Video-only
272: ['webm', '2160', null, null, 'v'], //Video-only
271: ['webm', '1440', null, null, 'v'], //Video-only
308: ['webm', '1440', null, null, 'v'], //Video-only (60fps)
315: ['webm', '2160', null, null, 'v'], //Video-only (60fps)
};

148 changes: 148 additions & 0 deletions src/lib/sortformats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
var KNOWN = require('./formats').formats;


function to_object(previousValue,currentValue,currentIndex,array) {
previousValue[currentValue] = currentIndex;
return previousValue;
}

function build_set(index) {
var members = {'null':true};
for(var tag in KNOWN) {
members[KNOWN[tag][index]] = true;
}

return members;
}

function sanitize_order_strings(s,ss){
var list = s.split(',');
list = list.map(function(a){ return a.replace(/\W/g,'')}).filter(function(i) { return ss[i] || (ss['acending'] && !isNaN(i));});
return list.filter(function(item, pos) {item = (item === 'acending') ? 'decending' : item; return list.indexOf(item) == pos;});
}

const vaild_container = build_set(0);
const valid_video_resolution = {'acending':true, 'decending': true, 'null':true};
const valid_audio_codec = build_set(2);
const valid_audio_bitrate = valid_video_resolution;
const valid_stream = build_set(4);
const valid_property = {'container':true, 'stream':true, 'video_resolution':true, 'audio_bitrate':true, 'audio_codec':true, 'null':true };

var user_container_order = 'mp4,webm,3gp,flv,m4a' + ',null';
var user_stream_order = 'null,v,a' + ',null' ;
var user_audio_codec_order = 'aac,mp3,ogg,opus' + ',null';
var user_video_resolution_order = 'decending' + ',null';
var user_audio_bitrate_order = 'decending' + ',null';
var user_property_order = 'stream, video_resolution, audio_bitrate';


var audio_bitrate_order = sanitize_order_strings(user_audio_bitrate_order,valid_audio_bitrate).reduce(to_object,{'offset':3});
var container_order = sanitize_order_strings(user_container_order,vaild_container).reduce(to_object,{'offset':0});
var stream_order = sanitize_order_strings(user_stream_order,valid_stream).reduce(to_object,{'offset':4});
var audio_codec_order = sanitize_order_strings(user_audio_codec_order,valid_audio_codec).reduce(to_object,{'offset':2});
var video_resolution_order = sanitize_order_strings(user_video_resolution_order,valid_video_resolution).reduce(to_object,{'offset':1});


const map_properties = {'container':container_order, 'stream':stream_order, 'video_resolution':video_resolution_order, 'audio_bitrate':audio_bitrate_order, 'audio_codec':audio_codec_order};

var property_order = sanitize_order_strings(user_property_order,valid_property).reverse().map(function(e){return map_properties[e];});

function cardinal_compare(s) {
return function(a,b) {

var map_to_set = function(member) {
if (!(member in s)){
if (typeof(member) === 'number') {
var as_string = JSON.stringify(member);

if (!(as_string in s)) {
if ('acending' in s) {
return [member,s['acending']];
}else if ('decending' in s) {
return [member,s['decending']];
}else {
return ['null',0];
}

}else {
return [as_string,0];
}
}else {
return ['null',0];
}
}else {
return [member,0];
}
};


var t = map_to_set(a);
var na = t[0], a_in_range = t[1];
t = map_to_set(b);
var nb = t[0], b_in_range = t[1];


if(a_in_range && b_in_range) {
if('acending' in s) {
return na - nb;
}else {
return nb - na;
}
}

if(a_in_range && !b_in_range) {
return a_in_range - s[nb];
}

if(!a_in_range && b_in_range) {
return s[na] - b_in_range;
}

if(!a_in_range && !b_in_range) {
return s[na] - s[nb];
}

return 0;


}
}

function stableSort(arr, cmpFunc) {
//wrap the arr elements in wrapper objects, so we can associate them with their origional starting index position
var arrOfWrapper = arr.map(function(elem, idx){
return {elem: elem, idx: idx};
});

//sort the wrappers, breaking sorting ties by using their elements orig index position
arrOfWrapper.sort(function(wrapperA, wrapperB){
var cmpDiff = cmpFunc(wrapperA.elem, wrapperB.elem);
return cmpDiff === 0
? wrapperA.idx - wrapperB.idx
: cmpDiff;
});

//unwrap and return the elements
return arrOfWrapper.map(function(wrapper){
return wrapper.elem;
});
}

function sort_formats(formats,order) {

for(var i = 0; i < order.length; ++i) {

var f = cardinal_compare(order[i]);
if(order[i] === video_resolution_order) {
formats = stableSort(formats,function(a,b) { a = KNOWN[a.itag][order[i].offset]; b = KNOWN[b.itag][order[i].offset]; a = parseInt(a); b = parseInt(b); return f(a,b);});
}else{
formats = stableSort(formats,function(a,b) {a = KNOWN[a.itag][order[i].offset]; b = KNOWN[b.itag][order[i].offset]; return f(a,b);});
}

}

return formats;

}

exports.sortFormats = function(c) { return sort_formats(c,property_order);};
95 changes: 4 additions & 91 deletions src/lib/youtube.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var {Cc, Ci, Cu} = require('chrome'),
prefs = require('sdk/simple-prefs').prefs,
KNOWN = require('./formats').formats,
sortfunctions = require('./sortformats'),
self = require('sdk/self');
Cu.import('resource://gre/modules/Promise.jsm');

Expand Down Expand Up @@ -97,68 +99,7 @@ var tagInfo = (function () {

/* Converting video tag to video codec information */
var formatDictionary = (function () {
const KNOWN = {
5: ['flv', '240', 'mp3', 64, null],
6: ['flv', '270', 'mp3', 64, null],
13: ['3gp', 'N/A', 'aac', null, null],
17: ['3gp', '144', 'aac', 24, null],
18: ['mp4', '360', 'aac', 96, null],
22: ['mp4', '720', 'aac', 192, null],
34: ['flv', '360', 'aac', 128, null],
35: ['flv', '280', 'aac', 128, null],
36: ['3gp', '240', 'aac', 38, null],
37: ['mp4', '1080', 'aac', 192, null],
38: ['mp4', '3072', 'aac', 192, null],
43: ['webm', '360', 'ogg', 128, null],
44: ['webm', '480', 'ogg', 128, null],
45: ['webm', '720', 'ogg', 192, null],
46: ['webm', '1080', 'ogg', 192, null],
83: ['mp4', '240', 'aac', 96, null],
82: ['mp4', '360', 'aac', 96, null],
59: ['mp4', '480', 'aac', 128, null],
78: ['mp4', '480', 'aac', 128, null],
85: ['mp4', '520', 'aac', 152, null],
84: ['mp4', '720', 'aac', 192, null],
100: ['webm', '360', 'ogg', 128, null],
101: ['webm', '360', 'ogg', 192, null],
102: ['webm', '720', 'ogg', 192, null],
120: ['flv', '720', 'aac', 128, null],
139: ['m4a', '48', 'aac', 38, 'a'], //Audio-only
140: ['m4a', '128', 'aac', 128, 'a'], //Audio-only
141: ['m4a', '256', 'aac', 256, 'a'], //Audio-only
171: ['webm', '128', 'ogg', 128, 'a'], //Audio-only
172: ['webm', '256', 'ogg', 192, 'a'], //Audio-only
249: ['webm', "48", 'opus', 50, 'a'],
250: ['webm', "48", 'opus', 70, 'a'],
251: ['webm', "128", 'opus', 160, 'a'],
160: ['mp4', '144', null, null, 'v'], //Video-only
133: ['mp4', '240', null, null, 'v'], //Video-only
134: ['mp4', '360', null, null, 'v'], //Video-only
135: ['mp4', '480', null, null, 'v'], //Video-only
298: ['mp4', '720', null, null, 'v'], //Video-only (60fps)
136: ['mp4', '720', null, null, 'v'], //Video-only
299: ['mp4', '1080', null, null, 'v'], //Video-only (60fps)
137: ['mp4', '1080', null, null, 'v'], //Video-only
138: ['mp4', '2160', null, null, 'v'], //Video-only
266: ['mp4', '2160', null, null, 'v'], //Video-only
264: ['mp4', '1440', null, null, 'v'], //Video-only
278: ['webm', '144', null, null, 'v'], //Video-only
242: ['webm', '240', null, null, 'v'], //Video-only
243: ['webm', '360', null, null, 'v'], //Video-only
244: ['webm', '480', null, null, 'v'], //Video-only
245: ['webm', '480', null, null, 'v'], //Video-only
246: ['webm', '480', null, null, 'v'], //Video-only
302: ['webm', '720', null, null, 'v'], //Video-only (60fps)
247: ['webm', '720', null, null, 'v'], //Video-only
303: ['webm', '1080', null, null, 'v'], //Video-only (60fps)
248: ['webm', '1080', null, null, 'v'], //Video-only
313: ['webm', '2160', null, null, 'v'], //Video-only
272: ['webm', '2160', null, null, 'v'], //Video-only
271: ['webm', '1440', null, null, 'v'], //Video-only
308: ['webm', '1440', null, null, 'v'], //Video-only (60fps)
315: ['webm', '2160', null, null, 'v'], //Video-only (60fps)
}
return function (obj) {
return function (obj) {
var itag = obj.itag;
if (!KNOWN[itag]) {
return;
Expand Down Expand Up @@ -670,35 +611,7 @@ function findOtherItags (info) {

/* Sorting audio-only and video-only formats */
function sortFormats (info) {
info.formats = info.formats.sort(function (a, b) {
var aaIndex = a.dash == 'a',
baIndex = b.dash == 'a',
avIndex = a.dash == 'v',
bvIndex = b.dash == 'v';

if (aaIndex && baIndex) {
return b.audioBitrate - a.audioBitrate;
}
if (avIndex && bvIndex) {
var tmp = parseInt(b.resolution) - parseInt(a.resolution);
if (tmp === 0) {
tmp = parseInt(a.bitrate) - parseInt(b.bitrate);
}
return tmp;
}
if (aaIndex && bvIndex) {
return 1;
}
if (avIndex && baIndex) {
return -1;
}
if (!aaIndex && !avIndex && (baIndex || bvIndex)) {
return -1;
}
if (!baIndex && !bvIndex && (aaIndex || avIndex)) {
return 1;
}
});
info.formats = sortfunctions.sortFormats(info.formats);

return info;
}
Expand Down