2023-07-15 07:30:36 +00:00
|
|
|
|
|
|
|
const getSortValue = function(value) {
|
|
|
|
var sortValue = value;
|
|
|
|
function trim(value) {
|
|
|
|
return value.replace(/^\W+(?=\w)/, '');
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
isEmpty(value)
|
|
|
|
|| isNull(value)
|
|
|
|
|| isUndefined(value)
|
|
|
|
) {
|
|
|
|
sortValue = null;
|
|
|
|
} else if (isString(value)) {
|
|
|
|
// make lowercase and remove leading non-word characters
|
|
|
|
sortValue = trim(value.toLowerCase());
|
|
|
|
// move leading articles to the end
|
|
|
|
// and remove leading non-word characters
|
|
|
|
['a', 'an', 'the'].forEach(function(article) {
|
|
|
|
if (new RegExp('^' + article + ' ').test(sortValue)) {
|
|
|
|
sortValue = trim(sortValue.slice(article.length + 1))
|
|
|
|
+ ', ' + sortValue.slice(0, article.length);
|
|
|
|
return false; // break
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// remove thousand separators and pad numbers
|
|
|
|
sortValue = sortValue.replace(/(\d),(?=(\d{3}))/g, '$1')
|
|
|
|
.replace(/\d+/g, function(match) {
|
|
|
|
return match.padStart(64, '0')
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return sortValue;
|
|
|
|
};
|
|
|
|
|
|
|
|
const sortByKey = function(array, by) {
|
|
|
|
return array.sort(function(a, b) {
|
|
|
|
var aValue, bValue, index = 0, key, ret = 0;
|
|
|
|
while (ret == 0 && index < by.length) {
|
|
|
|
key = by[index].key;
|
|
|
|
aValue = getSortValue(a[key])
|
|
|
|
bValue = getSortValue(b[key])
|
|
|
|
if ((aValue === null) != (bValue === null)) {
|
|
|
|
ret = aValue === null ? 1 : -1;
|
|
|
|
} else if (aValue < bValue) {
|
|
|
|
ret = by[index].operator == '+' ? -1 : 1;
|
|
|
|
} else if (aValue > bValue) {
|
|
|
|
ret = by[index].operator == '+' ? 1 : -1;
|
|
|
|
} else {
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
async function sortClips(edit, sort) {
|
|
|
|
var key = sort.key, index;
|
|
|
|
if (key == 'position') {
|
|
|
|
key = 'in';
|
|
|
|
}
|
|
|
|
if ([
|
|
|
|
'id', 'index', 'in', 'out', 'duration',
|
|
|
|
'title', 'director', 'year', 'videoRatio'
|
|
|
|
].indexOf(key) > -1) {
|
|
|
|
sortBy(sort);
|
|
|
|
index = 0;
|
|
|
|
edit.clips.forEach(function(clip) {
|
|
|
|
clip.sort = index++;
|
|
|
|
if (sort.operator == '-') {
|
|
|
|
clip.sort = -clip.sort;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
var response = await pandoraAPI('sortClips', {
|
|
|
|
edit: edit.id,
|
|
|
|
sort: [sort]
|
|
|
|
})
|
|
|
|
edit.clips.forEach(function(clip) {
|
|
|
|
clip.sort = response.data.clips.indexOf(clip.id);
|
|
|
|
if (sort.operator == '-') {
|
|
|
|
clip.sort = -clip.sort;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
sortBy({
|
|
|
|
key: 'sort',
|
|
|
|
operator: '+'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function sortBy(key) {
|
|
|
|
edit.clips = sortByKey(edit.clips, [key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function loadEdit(id, args) {
|
|
|
|
var data = window.data = {}
|
|
|
|
data.id = id
|
|
|
|
data.site = pandora.hostname
|
|
|
|
|
|
|
|
var response = await pandoraAPI('getEdit', {
|
|
|
|
id: data.id,
|
|
|
|
keys: [
|
|
|
|
]
|
|
|
|
})
|
|
|
|
if (response.status.code != 200) {
|
|
|
|
return {
|
|
|
|
site: data.site,
|
|
|
|
error: response.status
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data.edit = response['data']
|
|
|
|
if (data.edit.status !== 'public') {
|
|
|
|
return {
|
|
|
|
site: data.site,
|
|
|
|
error: {
|
|
|
|
code: 403,
|
|
|
|
text: 'permission denied'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data.layers = {}
|
|
|
|
data.videos = []
|
|
|
|
|
|
|
|
if (args.sort) {
|
|
|
|
await sortClips(data.edit, args.sort)
|
|
|
|
}
|
|
|
|
|
|
|
|
data.edit.duration = 0;
|
|
|
|
data.edit.clips.forEach(function(clip) {
|
|
|
|
clip.position = data.edit.duration;
|
|
|
|
data.edit.duration += clip.duration;
|
|
|
|
});
|
|
|
|
|
|
|
|
data.edit.clips.forEach(clip => {
|
|
|
|
var start = clip['in'] || 0, end = clip.out, position = 0;
|
|
|
|
clip.durations.forEach((duration, idx) => {
|
|
|
|
if (!duration) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (position + duration <= start || position > end) {
|
|
|
|
// pass
|
|
|
|
} else {
|
|
|
|
var video = {}
|
|
|
|
var oshash = clip.streams[idx]
|
|
|
|
video.src = getVideoURL(clip.item, 480, idx+1, '', oshash)
|
|
|
|
/*
|
|
|
|
if (clip['in'] && clip.out) {
|
|
|
|
video.src += `#t=${clip['in']},${clip.out}`
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
if (isNumber(clip.volume)) {
|
|
|
|
video.volume = clip.volume;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
position <= start
|
|
|
|
&& position + duration > start
|
|
|
|
) {
|
|
|
|
video['in'] = start - position;
|
|
|
|
}
|
|
|
|
if (position + duration >= end) {
|
|
|
|
video.out = end - position;
|
|
|
|
}
|
|
|
|
if (video['in'] && video.out) {
|
|
|
|
video.duration = video.out - video['in']
|
|
|
|
} else if (video.out) {
|
|
|
|
video.duration = video.out;
|
|
|
|
} else if (!isUndefined(video['in'])) {
|
|
|
|
video.duration = duration - video['in'];
|
|
|
|
video.out = duration;
|
|
|
|
} else {
|
|
|
|
video.duration = duration;
|
|
|
|
video['in'] = 0;
|
|
|
|
video.out = video.duration;
|
|
|
|
}
|
|
|
|
data.videos.push(video)
|
|
|
|
}
|
|
|
|
position += duration
|
|
|
|
})
|
|
|
|
Object.keys(clip.layers).forEach(layer => {
|
|
|
|
clip.layers[layer].forEach(annotation => {
|
|
|
|
if (args.users && !args.users.includes(annotation.user)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (args.layers && !args.layers.includes(layer)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var a = {...annotation}
|
|
|
|
a['id'] = clip['id'] + '/' + a['id'];
|
|
|
|
a['in'] = Math.max(
|
|
|
|
clip['position'],
|
|
|
|
a['in'] - clip['in'] + clip['position']
|
|
|
|
);
|
|
|
|
a.out = Math.min(
|
|
|
|
clip['position'] + clip['duration'],
|
|
|
|
a.out - clip['in'] + clip['position']
|
|
|
|
);
|
2023-08-23 12:16:52 +00:00
|
|
|
data.layers[layer] = data.layers[layer] || []
|
2023-07-15 07:30:36 +00:00
|
|
|
data.layers[layer].push(a)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2023-12-09 13:20:59 +00:00
|
|
|
if (data.layers[pandora.subtitleLayer]) {
|
|
|
|
var previous;
|
|
|
|
data.layers[pandora.subtitleLayer].forEach(annotation => {
|
|
|
|
if (previous) {
|
|
|
|
previous.out = annotation['in']
|
|
|
|
}
|
|
|
|
previous = annotation
|
|
|
|
})
|
|
|
|
}
|
2023-07-15 07:30:36 +00:00
|
|
|
var value = []
|
|
|
|
pandora.layerKeys.forEach(layer => {
|
|
|
|
if (!data.layers[layer]) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var html = []
|
|
|
|
var layerData = getObjectById(pandora.site.layers, layer)
|
|
|
|
html.push(`<h3>
|
|
|
|
<span class="icon">${icon.down}</span>
|
|
|
|
${layerData.title}
|
|
|
|
</h3>`)
|
|
|
|
data.layers[layer].forEach(annotation => {
|
|
|
|
html.push(`
|
|
|
|
<div class="annotation ${layerData.type}" data-in="${annotation.in}" data-out="${annotation.out}">
|
|
|
|
${annotation.value}
|
|
|
|
</div>
|
|
|
|
`)
|
|
|
|
})
|
2023-12-09 13:20:59 +00:00
|
|
|
var layerClass = ""
|
|
|
|
if (layerData.isSubtitles) {
|
|
|
|
layerClass = " is-subtitles"
|
|
|
|
}
|
|
|
|
value.push('<div class="layer'+layerClass+'">' + html.join('\n') + '</div>')
|
2023-07-15 07:30:36 +00:00
|
|
|
})
|
|
|
|
data.value = value.join('\n')
|
|
|
|
|
|
|
|
data.title = data.edit.name
|
|
|
|
data.byline = data.edit.description
|
|
|
|
data.link = `${pandora.proto}://${data.site}/edits/${data.edit.id}`
|
2024-02-06 11:24:27 +00:00
|
|
|
const poster = data.edit.posterFrames[0]
|
2024-02-06 11:22:35 +00:00
|
|
|
if (poster) {
|
|
|
|
data.poster = `${pandora.proto}://${data.site}/${poster.item}/480p${poster.position}.jpg`
|
|
|
|
} else {
|
|
|
|
data.poster = data.videos[0].src.split('/48')[0] + `/480p${data.videos[0].in}.jpg`
|
|
|
|
}
|
2023-07-15 07:30:36 +00:00
|
|
|
data.aspectratio = data.edit.clips[0].videoRatio
|
|
|
|
data.duration = data.edit.duration
|
|
|
|
return data
|
|
|
|
|
|
|
|
}
|