Final Cut Proで出力できる.fcpxmlファイルから、タイトル情報を読み取り、YouTubeに入力できる.srt形式に変換するスクリプトです。動作はブラウザのJavaScriptのみで行われますので、データがサーバにアップされることはありません。
下のテキストエリアに.fcpxmlファイルをドロップ
まずFCPXのファイルから「XMLを書き出す」。
fcpxmlバージョン1.10から.fcpxmlファイルは.fcpxmldの「パッケージの内容を表示」内にあるようです。
ここに.fcpxmlファイルをドロップ
code
xml内のtitleタグから時間を算出してだけなので、改造も比較的簡単かと思います。
window.onload = function () {
document.querySelectorAll('.drop').forEach(function (target) {
target.addEventListener('dragover', handleDragOver, false)
target.addEventListener('drop', handleFileSelect, false)
})
function handleFileSelect(evt) {
evt.stopPropagation()
evt.preventDefault()
let files = evt.dataTransfer.files
let load = files[0]
if (load !== undefined) {
let reader = new FileReader()
reader.onload = function (evt) {
let text = evt.target.result
let out = extract(text)
document.getElementById('out').value = out
let filename = load.name.match(/([^/]+)\./)[1]
save(`${filename}.srt`, out)
};
reader.readAsText(load)
}
}
function extract(input) {
const parser = new DOMParser();
let xmlData = parser.parseFromString(input, 'text/xml');
let titles = xmlData.querySelectorAll('title')
let counter = 0, out = ''
for (title of titles) {
counter++
let parent = title.parentNode
let parentOffset = parent.getAttribute('offset')
let parentStart = parent.getAttribute('start')
let name = title.getAttribute('name')
let offset = title.getAttribute('offset')
let duration = title.getAttribute('duration')
let startTime = getTime(parentOffset) + getTime(offset) - getTime(parentStart)
let endTime = startTime + getTime(duration)
let body = ''
let texts = title.querySelectorAll('text')
for (text of texts) {
let styles = text.querySelectorAll('text-style')
for (style of styles) {
body += style.textContent.replace(/\r?\n/g, '')
}
}
if (body ==='') body = name
out += counter + '\n'
out += toHmsMs(startTime) + ' --> ' + toHmsMs(endTime) + '\n'
out += body + '\n'
out += '\n'
}
return out
}
function getTime(input) {
let sec = 0
if (input) {
if (input.indexOf('/') === -1) {
sec = Number(input.match(/(\d+)s/)[1])
} else {
let match = input.match(/(\d+)\/(\d+)s/)
sec = match[1] / match[2]
}
}
return sec
}
function toHmsMs(t) {
let decimal = 0
if (t > 0) {
decimal = t - Math.floor(t)
}
t = Math.floor(t)
let h = t / 3600 | 0
let m = t % 3600 / 60 | 0
let s = t % 60 | 0
return `${zp(h)}:${zp(m)}:${zp(s)},${zp(Math.round(decimal * 1000), 3)}`
function zp(num, length = 2) {
return ('0000000000' + num).slice(-length);
}
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function save(filename, text) {
let blob = new Blob([text], { type: 'text/plain' })
let a = document.getElementById('down')
a.href = window.URL.createObjectURL(blob)
a.textContent = 'Download'
a.download = filename
//a.click()
}
}