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

json subtitles to srt format #33

Merged
merged 2 commits into from
Jul 26, 2024
Merged
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
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = {
env: {
es2021: true,
node: true,
jest: true,
},
extends: ["eslint:recommended", "prettier"],
plugins: ["prettier"],
Expand Down
20 changes: 20 additions & 0 deletions __tests__/utils/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { jsonToSrt } from "../../src/utils/utils.js";

describe("utils", () => {
it("conver YandexSubtitles json to srt", () => {
const jsonYS = [
{ text: "Привет", startMs: 2222.0, durationMs: 3610.0 },
{ text: "мир", startMs: 26050.0, durationMs: 970.0 },
];

const expectedSRT = `1
00:00:02,222 --> 00:00:05,832
Привет

2
00:00:26,050 --> 00:00:27,020
мир`;

expect(jsonToSrt(jsonYS)).toBe(expectedSRT);
});
});
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"lint": "npx eslint .",
"lint-fix": "npx eslint . --fix",
"format": "prettier --write --ignore-unknown \"src/**/*.{js,ts,json}\"",
"prepare": "husky"
"prepare": "husky",
"test": "jest"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -44,10 +45,14 @@
"uuid": "^10.0.0"
},
"devDependencies": {
"@babel/core": "^7.24.9",
"@babel/preset-env": "^7.24.8",
"babel-jest": "^29.7.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"husky": "^9.0.11",
"jest": "^29.7.0",
"prettier": "^3.3.2"
}
}
22 changes: 20 additions & 2 deletions src/download.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import fs from "fs";
import { Writable } from "stream";
import axios from "axios";
import { jsonToSrt } from "./utils/utils.js";

function calcPercents(current, max) {
return ((current / max) * 100).toFixed(1);
Expand All @@ -9,7 +11,7 @@ export default async function downloadFile(url, outputPath, subtask, videoId) {
if (!url) {
throw new Error("Invalid download link");
}

const IS_NEED_CONVERT = outputPath.endsWith(".srt");
const writer = fs.createWriteStream(outputPath);
const { data, headers } = await axios({
method: "get",
Expand All @@ -31,7 +33,23 @@ export default async function downloadFile(url, outputPath, subtask, videoId) {
// console.log(calcPercents(downloadedLength, totalLength))
});

data.pipe(writer);
if (IS_NEED_CONVERT) {
let dataBuffer = "";
const writableStream = new Writable({
write(chunk, encoding, callback) {
dataBuffer += chunk.toString();
callback();
},
});
data.pipe(writableStream);
data.on("end", () => {
const jsonData = JSON.parse(dataBuffer);
writer.write(jsonToSrt(jsonData["subtitles"]));
writer.end();
});
} else {
data.pipe(writer);
}

return new Promise((resolve, reject) => {
writer.on("finish", resolve);
Expand Down
10 changes: 6 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ const argv = parseArgs(process.argv.slice(2));
const ARG_LINKS = argv._;
const OUTPUT_DIR = argv.output;
const OUTPUT_FILE = argv["output-file"];
const IS_SUBS_REQ = argv.subs || argv.subtitles;
const IS_SUBS_FORMAT_SRT = argv["subs-srt"] || argv["subtitles-srt"];
const RESPONSE_SUBTITLES_FORMAT = IS_SUBS_FORMAT_SRT ? "srt" : "json";
const IS_SUBS_REQ = argv.subs || argv.subtitles || IS_SUBS_FORMAT_SRT;
const ARG_HELP = argv.help || argv.h;
const ARG_VERSION = argv.version || argv.v;
const PROXY_STRING = argv.proxy;
Expand Down Expand Up @@ -398,12 +400,12 @@ async function main() {

const taskSubTitle = `(ID: ${videoId})`;
const filename = OUTPUT_FILE
? OUTPUT_FILE.endsWith(".json")
? OUTPUT_FILE.endsWith(`.${RESPONSE_SUBTITLES_FORMAT}`)
? OUTPUT_FILE
: `${OUTPUT_FILE}.json`
: `${OUTPUT_FILE}.${RESPONSE_SUBTITLES_FORMAT}`
: `${subOnReqLang.language}---${clearFileName(
videoId,
)}---${uuidv4()}.json`;
)}---${uuidv4()}.${RESPONSE_SUBTITLES_FORMAT}`;
await downloadFile(
subOnReqLang.url,
`${OUTPUT_DIR}/${filename}`,
Expand Down
23 changes: 22 additions & 1 deletion src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,25 @@ function clearFileName(name) {
return name.replace(/[^\w.-]/g, "");
}

export { clearFileName };
function convertToSrtTimeFormat(ms) {
const date = new Date(ms);
const hours = String(date.getUTCHours()).padStart(2, "0");
const minutes = String(date.getUTCMinutes()).padStart(2, "0");
const seconds = String(date.getUTCSeconds()).padStart(2, "0");
const milliseconds = String(date.getUTCMilliseconds()).padStart(3, "0");
return `${hours}:${minutes}:${seconds},${milliseconds}`;
}

function jsonToSrt(subtitles) {
return subtitles
.map((s, index) => {
const { text, startMs, durationMs } = s;
const startTime = convertToSrtTimeFormat(startMs);
const endTime = convertToSrtTimeFormat(startMs + durationMs);
return `${index + 1}\n${startTime} --> ${endTime}\n${text}\n`;
})
.join("\n")
.trim();
}

export { clearFileName, jsonToSrt };