forked from 0x2620/pandora
chrome only show the first 100 enties in a folder, use more nested folders and move existing files into folders
This commit is contained in:
parent
8ef5d6908b
commit
b92f0c1bd0
1 changed files with 219 additions and 107 deletions
326
static/js/fs.js
326
static/js/fs.js
|
@ -16,8 +16,39 @@ pandora.fs = (function() {
|
||||||
that.fs = fs;
|
that.fs = fs;
|
||||||
that.fs.root.createReader().readEntries(function(results) {
|
that.fs.root.createReader().readEntries(function(results) {
|
||||||
results.forEach(function(entry) {
|
results.forEach(function(entry) {
|
||||||
if (entry.isFile && !Ox.startsWith(entry.name, 'partial::')) {
|
if (entry.isFile) {
|
||||||
that.local[entry.name] = entry.toURL();
|
if (Ox.startsWith(entry.name, 'partial::')) {
|
||||||
|
fileEntry.remove(function() {});
|
||||||
|
} else {
|
||||||
|
var name = entry.name.split('::'),
|
||||||
|
filename = Ox.last(name),
|
||||||
|
foldername = name[0] + "::" + filename.split('p')[0];
|
||||||
|
var key = foldername[0] + '/' + foldername;
|
||||||
|
createTree(key, function(folder) {
|
||||||
|
entry.moveTo(folder, filename, function(e) {
|
||||||
|
var name = folder.name + '/' + e.name;
|
||||||
|
that.local[name] = e.toURL();
|
||||||
|
that.storeBlob(new Blob(['ok']), key + '/done', function() {});
|
||||||
|
}, function() {
|
||||||
|
Ox.print('error moving', filename);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (entry.isDirectory) {
|
||||||
|
entry.createReader().readEntries(function(prefixes) {
|
||||||
|
prefixes.forEach(function(prefix) {
|
||||||
|
prefix.isDirectory && prefix.createReader().readEntries(function(contents) {
|
||||||
|
if (contents.filter(function(e) { return e.name == 'done'}).length) {
|
||||||
|
contents.forEach(function(e) {
|
||||||
|
if (e.name != 'done') {
|
||||||
|
var name = prefix.name + '/' + e.name;
|
||||||
|
that.local[name] = e.toURL();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -26,71 +57,80 @@ pandora.fs = (function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function cacheVideo(id, callback) {
|
function createTree(folder, callback, root) {
|
||||||
active = true;
|
var parts = folder.split('/');
|
||||||
pandora.api.get({id: id, keys: ['parts']}, function(result) {
|
root = root || that.fs.root;
|
||||||
var parts = result.data.parts, sizes = [];
|
root.getDirectory(parts.shift(), {create: true}, function(folder) {
|
||||||
downloadPart(0);
|
if (parts.length) {
|
||||||
|
createTree(parts.join('/'), callback, folder);
|
||||||
|
} else {
|
||||||
|
callback(folder);
|
||||||
|
}
|
||||||
|
}, function(error) {
|
||||||
|
Ox.Log('FS', 'error', error);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function downloadPart(part) {
|
function cacheVideo(id, callback) {
|
||||||
if (that.getVideoURL(id, pandora.user.ui.videoResolution, part + 1)) {
|
var key = id[0] + '/' + id + '::' + pandora.user.ui.videoResolution;
|
||||||
done();
|
active = true;
|
||||||
} else {
|
createTree(key, function(folder) {
|
||||||
that.downloadVideoURL(id, pandora.user.ui.videoResolution, part + 1, false, function(result) {
|
pandora.api.get({id: id, keys: ['parts']}, function(result) {
|
||||||
result.progress = 1/parts * (part + result.progress);
|
var parts = result.data.parts, sizes = [];
|
||||||
if (!that.downloads[id]) {
|
downloadPart(0);
|
||||||
result.cancel && result.cancel();
|
|
||||||
return;
|
function downloadPart(part) {
|
||||||
}
|
var partName = key + '/' + pandora.user.ui.videoResolution
|
||||||
that.downloads[id].progress = result.progress;
|
+ 'p' + (part + 1) + '.' + pandora.user.videoFormat,
|
||||||
if (result.cancel) {
|
url = that.getVideoURL(id, pandora.user.ui.videoResolution, part + 1);
|
||||||
that.downloads[id].cancel = result.cancel;
|
if (url) {
|
||||||
}
|
done({url: url});
|
||||||
if (result.total) {
|
|
||||||
sizes[part] = result.total;
|
|
||||||
that.downloads[id].size = Ox.sum(sizes);
|
|
||||||
}
|
|
||||||
if (result.url) {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
callback && callback(result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function done() {
|
|
||||||
if (part + 1 == parts) {
|
|
||||||
renamePart(0);
|
|
||||||
} else {
|
} else {
|
||||||
setTimeout(function() {
|
that.downloadVideoURL(id, pandora.user.ui.videoResolution, part + 1, false, function(result) {
|
||||||
downloadPart(part + 1);
|
result.progress = 1/parts * (part + result.progress);
|
||||||
|
if (!that.downloads[id]) {
|
||||||
|
result.cancel && result.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
that.downloads[id].progress = result.progress;
|
||||||
|
if (result.cancel) {
|
||||||
|
that.downloads[id].cancel = result.cancel;
|
||||||
|
}
|
||||||
|
if (result.total) {
|
||||||
|
sizes[part] = result.total;
|
||||||
|
that.downloads[id].size = Ox.sum(sizes);
|
||||||
|
}
|
||||||
|
if (result.url) {
|
||||||
|
done(result);
|
||||||
|
} else {
|
||||||
|
callback && callback(result);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
function done(result) {
|
||||||
function renamePart(i) {
|
that.local[partName] = result.url;
|
||||||
var name = that.getVideoName(id, pandora.user.ui.videoResolution, i + 1),
|
if (part + 1 == parts) {
|
||||||
partialName = 'partial::' + name;
|
//fixme
|
||||||
renameFile(partialName, name, function(fileEntry) {
|
that.storeBlob(new Blob(['ok']), key + '/done', function() {
|
||||||
if (fileEntry) {
|
delete that.downloads[id];
|
||||||
Ox.Log('FS', 'renamed file', partialName, 'to', name);
|
active = false;
|
||||||
that.local[name] = fileEntry.toURL();
|
callback && callback(result);
|
||||||
|
if (queue.length) {
|
||||||
|
var next = queue.shift();
|
||||||
|
setTimeout(function() {
|
||||||
|
cacheVideo(next[0], next[1]);
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
Ox.print('rename failed', name);
|
setTimeout(function() {
|
||||||
callback && callback({progress: -1, error: 'rename failed'});
|
downloadPart(part + 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (i + 1 == parts) {
|
}
|
||||||
delete that.downloads[id];
|
|
||||||
active = false;
|
|
||||||
if (queue.length) {
|
|
||||||
var next = queue.shift();
|
|
||||||
setTimeout(function() {
|
|
||||||
cacheVideo(next[0], next[1]);
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
renamePart(i + 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +148,7 @@ pandora.fs = (function() {
|
||||||
|
|
||||||
that.cacheVideo = function(id, callback) {
|
that.cacheVideo = function(id, callback) {
|
||||||
if (that.getVideoURL(id, pandora.user.ui.videoResolution, 1) || that.downloads[id]) {
|
if (that.getVideoURL(id, pandora.user.ui.videoResolution, 1) || that.downloads[id]) {
|
||||||
callback({progress: 1});
|
callback && callback({progress: 1});
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
that.downloads = that.downloads || {};
|
that.downloads = that.downloads || {};
|
||||||
|
@ -131,38 +171,53 @@ pandora.fs = (function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
that.getVideoName = function(id, resolution, part, track) {
|
that.getVideoName = function(id, resolution, part, track) {
|
||||||
return pandora.getVideoURLName(id, resolution, part, track).replace('/', '::');
|
return pandora.getVideoURLName(id, resolution, part, track).replace(id + '\/', id + '::' + resolution + '/');
|
||||||
};
|
};
|
||||||
|
|
||||||
that.removeVideo = function(id, callback) {
|
that.removeVideo = function(id, callback) {
|
||||||
if (that.downloads && that.downloads[id] && that.downloads[id].cancel) {
|
if (that.downloads && that.downloads[id] && that.downloads[id].cancel) {
|
||||||
that.downloads[id].cancel();
|
that.downloads[id].cancel();
|
||||||
delete that.downloads[id];
|
delete that.downloads[id];
|
||||||
} else {
|
}
|
||||||
pandora.api.get({id: id, keys: ['parts']}, function(result) {
|
// remove legacy files too
|
||||||
var count = result.data.parts * pandora.site.video.resolutions.length, done = 0;
|
pandora.api.get({id: id, keys: ['parts']}, function(result) {
|
||||||
Ox.range(result.data.parts).forEach(function(part) {
|
var count = result.data.parts * pandora.site.video.resolutions.length, done = 0;
|
||||||
pandora.site.video.resolutions.forEach(function(resolution) {
|
Ox.range(result.data.parts).forEach(function(part) {
|
||||||
var name = that.getVideoName(id, resolution, part + 1);
|
pandora.site.video.resolutions.forEach(function(resolution) {
|
||||||
that.fs.root.getFile(name, {create: false}, function(fileEntry) {
|
var name = pandora.getVideoURLName(id, resolution, part + 1).replace('/', '::');
|
||||||
// remove existing file
|
that.fs.root.getFile(name, {create: false}, function(fileEntry) {
|
||||||
fileEntry.remove(function(e) {
|
// remove existing file
|
||||||
if (that.local[name]) {
|
fileEntry.remove(function(e) {
|
||||||
delete that.local[name];
|
if (that.local[name]) {
|
||||||
}
|
delete that.local[name];
|
||||||
});
|
}
|
||||||
++done == count && callback();
|
|
||||||
}, function() { // file not found
|
|
||||||
++done == count && callback();
|
|
||||||
});
|
|
||||||
// remove partial file too
|
|
||||||
that.fs.root.getFile('partial::' + name, {create: false}, function(fileEntry) {
|
|
||||||
fileEntry.remove(function(e) {});
|
|
||||||
});
|
});
|
||||||
|
}, function() { // file not found
|
||||||
|
});
|
||||||
|
// remove partial file too
|
||||||
|
that.fs.root.getFile('partial::' + name, {create: false}, function(fileEntry) {
|
||||||
|
fileEntry.remove(function(e) {});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
Ox.parallelForEach(pandora.site.video.resolutions,
|
||||||
|
function(resolution, i, resolutions, cb) {
|
||||||
|
var key = id + '::' + resolution;
|
||||||
|
that.fs.root.getDirectory(key[0] + '/' + key, {create: false}, function(dir) {
|
||||||
|
dir.removeRecursively(cb, cb);
|
||||||
|
Object.keys(that.local).forEach(function(name) {
|
||||||
|
if (Ox.startsWith(name, key)) {
|
||||||
|
delete that.local[name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cb();
|
||||||
|
}, function() {
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}, function() {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
that.storeBlob = function(blob, name, callback, append) {
|
that.storeBlob = function(blob, name, callback, append) {
|
||||||
|
@ -208,14 +263,13 @@ pandora.fs = (function() {
|
||||||
//fixme: would be nice to download videos from subdomains,
|
//fixme: would be nice to download videos from subdomains,
|
||||||
// currently throws a cross domain error
|
// currently throws a cross domain error
|
||||||
var name = that.getVideoName(id, resolution, part, track),
|
var name = that.getVideoName(id, resolution, part, track),
|
||||||
partialName = 'partial::' + name,
|
|
||||||
url = '/' + pandora.getVideoURLName(id, resolution, part, track),
|
url = '/' + pandora.getVideoURLName(id, resolution, part, track),
|
||||||
blobSize = 5*1024*1024, total;
|
blobSize = 5*1024*1024, total;
|
||||||
Ox.Log('FS', 'start downloading', url);
|
Ox.Log('FS', 'start downloading', url);
|
||||||
getSize(url, function(size) {
|
getSize(url, function(size) {
|
||||||
Ox.Log('FS', 'HEAD', url, size);
|
Ox.Log('FS', 'HEAD', url, size);
|
||||||
total = size;
|
total = size;
|
||||||
that.fs.root.getFile(partialName, {create: false}, function(fileEntry) {
|
that.fs.root.getFile(name, {create: false}, function(fileEntry) {
|
||||||
fileEntry.getMetadata(function(meta) {
|
fileEntry.getMetadata(function(meta) {
|
||||||
if (meta.size >= total) {
|
if (meta.size >= total) {
|
||||||
Ox.Log('FS', 'file exists, done', meta.size, total);
|
Ox.Log('FS', 'file exists, done', meta.size, total);
|
||||||
|
@ -277,7 +331,6 @@ pandora.fs = (function() {
|
||||||
var progress = (event.loaded + offset) / total;
|
var progress = (event.loaded + offset) / total;
|
||||||
callback({
|
callback({
|
||||||
progress: progress,
|
progress: progress,
|
||||||
request: xhr,
|
|
||||||
total: total,
|
total: total,
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
xhr.abort();
|
xhr.abort();
|
||||||
|
@ -295,7 +348,7 @@ pandora.fs = (function() {
|
||||||
xhr.addEventListener('load', function() {
|
xhr.addEventListener('load', function() {
|
||||||
var blob = xhr.response;
|
var blob = xhr.response;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
that.storeBlob(blob, partialName, function(response) {
|
that.storeBlob(blob, name[0] + '/' + name, function(response) {
|
||||||
if (offset + blob.size < total) {
|
if (offset + blob.size < total) {
|
||||||
partialDownload(offset + blob.size);
|
partialDownload(offset + blob.size);
|
||||||
} else {
|
} else {
|
||||||
|
@ -327,30 +380,76 @@ pandora.fs = (function() {
|
||||||
that.getVideos = function(callback) {
|
that.getVideos = function(callback) {
|
||||||
var files = {};
|
var files = {};
|
||||||
that.fs.root.createReader().readEntries(function(results) {
|
that.fs.root.createReader().readEntries(function(results) {
|
||||||
var n = 0;
|
|
||||||
if (results.length) {
|
if (results.length) {
|
||||||
results.forEach(function(fileEntry) {
|
Ox.parallelForEach(results, function(fileEntry, i, entries, next_entry) {
|
||||||
if (Ox.startsWith(fileEntry.name, 'partial::')) {
|
if (fileEntry.isFile) {
|
||||||
++n == results.length && callback(Ox.values(files).concat(Ox.values(that.downloads)));
|
if (Ox.startsWith(fileEntry.name, 'partial::')) {
|
||||||
} else {
|
next_entry();
|
||||||
fileEntry.getMetadata(function(meta) {
|
} else {
|
||||||
var item = fileEntry.name.split('::')[0],
|
fileEntry.getMetadata(function(meta) {
|
||||||
resolution = parseInt(fileEntry.name.split('::')[1].split('p')[0]),
|
var item = fileEntry.name.split('::')[0],
|
||||||
part = parseInt(fileEntry.name.split('::')[1].split('p')[1].split('.')[0]),
|
resolution = parseInt(fileEntry.name.split('::')[1].split('p')[0]),
|
||||||
key = item + '::' + resolution;
|
part = parseInt(fileEntry.name.split('::')[1].split('p')[1].split('.')[0]),
|
||||||
if (!(that.downloads && that.downloads[item])) {
|
key = item + '::' + resolution;
|
||||||
files[key] = Ox.extend(files[key] || {}, {
|
if (!(that.downloads && that.downloads[item])) {
|
||||||
added: meta.modificationTime,
|
files[key] = Ox.extend(files[key] || {}, {
|
||||||
id: item + '::' + resolution,
|
added: meta.modificationTime,
|
||||||
item: item,
|
id: item + '::' + resolution,
|
||||||
progress: 1,
|
item: item,
|
||||||
resolution: resolution,
|
progress: 1,
|
||||||
size: files[key] ? files[key].size + meta.size: meta.size
|
resolution: resolution,
|
||||||
});
|
size: files[key] ? files[key].size + meta.size: meta.size
|
||||||
|
});
|
||||||
|
}
|
||||||
|
next_entry();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (fileEntry.isDirectory) {
|
||||||
|
fileEntry.createReader().readEntries(function(prefixes) {
|
||||||
|
if (prefixes.length) {
|
||||||
|
Ox.parallelForEach(prefixes, function(prefix, i, prefixes, callback) {
|
||||||
|
prefix.createReader().readEntries(function(contents) {
|
||||||
|
if (contents.filter(function(f) { return f.name == 'done' }).length) {
|
||||||
|
Ox.parallelMap(contents,
|
||||||
|
function(e, i, col, callback) {
|
||||||
|
e.getMetadata(function(meta) {
|
||||||
|
callback(meta);
|
||||||
|
});
|
||||||
|
}, function(meta) {
|
||||||
|
var item = prefix.name.split('::')[0],
|
||||||
|
resolution = parseInt(prefix.name.split('::')[1]),
|
||||||
|
key = item + '::' + resolution;
|
||||||
|
if (!(that.downloads && that.downloads[item])) {
|
||||||
|
files[key] = Ox.extend(files[key] || {}, {
|
||||||
|
added: Ox.min(meta.map(function(m) {
|
||||||
|
return m.modificationTime;
|
||||||
|
})),
|
||||||
|
id: item + '::' + resolution,
|
||||||
|
item: item,
|
||||||
|
progress: 1,
|
||||||
|
resolution: resolution,
|
||||||
|
size: Ox.sum(meta.map(function(m) {
|
||||||
|
return m.size;
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, next_entry);
|
||||||
|
} else {
|
||||||
|
next_entry();
|
||||||
}
|
}
|
||||||
++n == results.length && callback(Ox.values(files).concat(Ox.values(that.downloads)));
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
next_entry();
|
||||||
}
|
}
|
||||||
|
}, function() {
|
||||||
|
callback(Ox.values(files).concat(Ox.values(that.downloads)));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
callback(Ox.values(that.downloads));
|
callback(Ox.values(that.downloads));
|
||||||
|
@ -363,5 +462,18 @@ pandora.fs = (function() {
|
||||||
return that.local[name];
|
return that.local[name];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
that._tree = function(root) {
|
||||||
|
root = root || that.fs.root;
|
||||||
|
root.createReader().readEntries(function(results) {
|
||||||
|
results.forEach(function(entry) {
|
||||||
|
if (entry.isFile) {
|
||||||
|
Ox.print(entry.fullPath);
|
||||||
|
} else {
|
||||||
|
that._tree(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return that;
|
return that;
|
||||||
}());
|
}());
|
||||||
|
|
Loading…
Reference in a new issue