opensubtitles-api
Version:
opensubtitles.org api wrapper
140 lines (118 loc) • 4.89 kB
JavaScript
const fs = require('fs')
const crypto = require('crypto')
const zlib = require('zlib')
module.exports = new class LibHash {
// opens the file, gzip the content and base64 encode it
computeSubContent(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) return reject(err)
zlib.deflate(data, (err, buffer) => {
if (err) return reject(err)
resolve(buffer.toString('base64'))
})
})
})
}
// get md5 of a file
computeMD5(path) {
return new Promise((resolve, reject) => {
let hash = crypto.createHash('md5')
fs.createReadStream(path)
.on('data', data => hash.update(data, 'utf8'))
.on('end', () => resolve(hash.digest('hex'))) // md5 checksum
.on('error', reject)
})
}
computeHash(path) {
// based on node-opensubtitles-api, under MIT - Copyright (c) 2015 ka2er
return new Promise((resolve, reject) => {
// get file size, first 64kb, last 64kb and summup everything
let chunk_size = 65536 //64 * 1024
let buf_start = Buffer.alloc(chunk_size * 2)
let buf_end = Buffer.alloc(chunk_size * 2)
let file_size = 0
let checksum
let array_checksum = Array()
const checksumReady = checksum_part => {
array_checksum.push(checksum_part)
if (array_checksum.length === 3) {
checksum = this.sumHex64bits(array_checksum[0], array_checksum[1])
checksum = this.sumHex64bits(checksum, array_checksum[2])
checksum = checksum.substr(-16)
resolve({
moviehash: this.padLeft(checksum, '0', 16),
moviebytesize: file_size.toString()
})
}
}
fs.stat(path, (err, stat) => {
if (err) return reject(err)
file_size = stat.size
checksumReady(file_size.toString(16))
fs.open(path, 'r', (err, fd) => {
if (err) return reject(err)
fs.read(fd, buf_start, 0, chunk_size * 2, 0, (er1, bytesRead, buf1) => {
fs.read(fd, buf_end, 0, chunk_size * 2, file_size - chunk_size, (er2, bytesRead, buf2) => {
fs.close(fd, er3 => {
if (er1 || er2) return reject(er1 || er2) //er3 is not breaking
checksumReady(this.checksumBuffer(buf1, 16))
checksumReady(this.checksumBuffer(buf2, 16))
})
})
})
})
})
})
}
// read 64 bits from buffer starting at offset as LITTLE ENDIAN hex
read64LE(buffer, offset) {
const ret_64_be = buffer.toString('hex', offset * 8, ((offset + 1) * 8))
const array = Array()
for (let i = 0; i < 8; i++) {
array.push(ret_64_be.substr(i * 2, 2))
}
array.reverse()
return array.join('')
}
// compute checksum of the buffer splitting by chunk of lengths bits
checksumBuffer(buf, length) {
let checksum = 0
let checksum_hex = 0
for (let i = 0; i < (buf.length / length); i++) {
checksum_hex = this.read64LE(buf, i)
checksum = this.sumHex64bits(checksum.toString(), checksum_hex).substr(-16)
}
return checksum
}
// calculate hex sum between 2 64bits hex numbers
sumHex64bits(n1, n2) {
if (n1.length < 16) n1 = this.padLeft(n1, '0', 16)
if (n2.length < 16) n2 = this.padLeft(n2, '0', 16)
// 1st 32 bits
let n1_0 = n1.substr(0, 8)
let n2_0 = n2.substr(0, 8)
let i_0 = parseInt(n1_0, 16) + parseInt(n2_0, 16)
// 2nd 32 bits
let n1_1 = n1.substr(8, 8)
let n2_1 = n2.substr(8, 8)
let i_1 = parseInt(n1_1, 16) + parseInt(n2_1, 16)
// back to hex
let h_1 = i_1.toString(16)
let i_1_over = 0
if (h_1.length > 8) {
i_1_over = parseInt(h_1.substr(0, h_1.length - 8), 16)
} else {
h_1 = this.padLeft(h_1, '0', 8)
}
let h_0 = (i_1_over + i_0).toString(16)
return h_0 + h_1.substr(-8)
}
// pad left with c up to length characters
padLeft(str, c, length) {
while (str.length < length) {
str = c.toString() + str
}
return str
}
}