Added ffmpeg progress bar via fluent-ffmpeg and progress libs (#57)
* Add fluent-ffmpeg back and cross-platform progress bar * Repo clean up Move ts files to src, build and output js files to build folder * Do not print messages when exit code is 0 this is triggered by signal events Co-authored-by: kylon <kylonux@gmail.com>
This commit is contained in:
parent
d489b02d03
commit
9faa0c4846
10 changed files with 118 additions and 201 deletions
216
package-lock.json
generated
216
package-lock.json
generated
|
@ -30,44 +30,6 @@
|
|||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@sidneys/cli-progress": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@sidneys/cli-progress/-/cli-progress-2.2.0.tgz",
|
||||
"integrity": "sha512-JMIiVpZpDhH0HgHEpM4HH3SxE0OkwzOaCqpm3GxuHHG3bIsEju6pcvrA6FyANI6Tbt991hZnH/flJX+DNNmmwA==",
|
||||
"requires": {
|
||||
"colors": "^1.3.2",
|
||||
"string-width": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sindresorhus/jimp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/jimp/-/jimp-0.3.0.tgz",
|
||||
|
@ -108,6 +70,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@types/cli-progress": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.4.2.tgz",
|
||||
"integrity": "sha512-9Rlk664JggbgDLDMCM/8HziTh6ZU2IBLVS2/Kkh3T/TNVlpWlwgLrFl7kDyQBOlX1pofPM05ZKG/GyuULJ0FfA==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/color-name": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
|
@ -340,11 +310,6 @@
|
|||
"execa": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"app-root-path": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz",
|
||||
"integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA=="
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
|
@ -360,6 +325,11 @@
|
|||
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
|
||||
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
|
||||
},
|
||||
"async-limiter": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
|
||||
|
@ -518,6 +488,15 @@
|
|||
"restore-cursor": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"cli-progress": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.7.0.tgz",
|
||||
"integrity": "sha512-xo2HeQ3vNyAO2oYF5xfrk5YM6jzaDNEbeJRLAQir6QlH54g4f6AXW+fLyJ/f12gcTaCbJznsOdQcr/yusp/Kjg==",
|
||||
"requires": {
|
||||
"colors": "^1.1.2",
|
||||
"string-width": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"cli-width": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
|
||||
|
@ -613,14 +592,6 @@
|
|||
"object-keys": "^1.0.12"
|
||||
}
|
||||
},
|
||||
"define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
|
||||
"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
|
||||
"requires": {
|
||||
"is-descriptor": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
|
@ -646,11 +617,6 @@
|
|||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"ellipsize": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ellipsize/-/ellipsize-0.1.0.tgz",
|
||||
"integrity": "sha1-nUNoLUS5GtFuvYQmisEDFwplU/g="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
|
@ -965,52 +931,6 @@
|
|||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"ffmpeg-progressbar-cli": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ffmpeg-progressbar-cli/-/ffmpeg-progressbar-cli-1.5.0.tgz",
|
||||
"integrity": "sha512-0oEomm2If0xN8Cop4eVL+6OSPAhSs4V+89xdRBztGj+tqrBGp6fBhBK+OzN5Epi+1NuSgTxDQzFno1SioUp4ZQ==",
|
||||
"requires": {
|
||||
"@sidneys/cli-progress": "^2.2.0",
|
||||
"app-root-path": "^2.1.0",
|
||||
"chalk": "^2.4.1",
|
||||
"ellipsize": "^0.1.0",
|
||||
"ini": "^1.3.5",
|
||||
"moment": "^2.22.2",
|
||||
"moment-duration-format": "^2.2.2",
|
||||
"string-width": "^2.1.1",
|
||||
"which": "^1.3.1",
|
||||
"window-size": "^1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"figures": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||
|
@ -1097,6 +1017,15 @@
|
|||
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
|
||||
"dev": true
|
||||
},
|
||||
"fluent-ffmpeg": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz",
|
||||
"integrity": "sha1-yVLeIkD4EuvaCqgAbXd27irPfXQ=",
|
||||
"requires": {
|
||||
"async": ">=0.2.9",
|
||||
"which": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||
|
@ -1294,11 +1223,6 @@
|
|||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz",
|
||||
|
@ -1347,14 +1271,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"is-accessor-descriptor": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
|
||||
"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
|
||||
"requires": {
|
||||
"kind-of": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"is-admin": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-admin/-/is-admin-3.0.0.tgz",
|
||||
|
@ -1372,41 +1288,18 @@
|
|||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"is-callable": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
|
||||
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"is-data-descriptor": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
|
||||
"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
|
||||
"requires": {
|
||||
"kind-of": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"is-date-object": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
|
||||
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
|
||||
"dev": true
|
||||
},
|
||||
"is-descriptor": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
|
||||
"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
|
||||
"requires": {
|
||||
"is-accessor-descriptor": "^1.0.0",
|
||||
"is-data-descriptor": "^1.0.0",
|
||||
"kind-of": "^6.0.2"
|
||||
}
|
||||
},
|
||||
"is-elevated": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-elevated/-/is-elevated-3.0.0.tgz",
|
||||
|
@ -1491,6 +1384,11 @@
|
|||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||
},
|
||||
"iso8601-duration": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/iso8601-duration/-/iso8601-duration-1.2.0.tgz",
|
||||
"integrity": "sha512-ErTBd++b17E8nmWII1K1uZtBgD1E8RjyvwmxlCjPHNqHMD7gmcMHOw0E8Ro/6+QT4PhHRSnnMo7bxa1vFPkwhg=="
|
||||
},
|
||||
"iterm2-version": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/iterm2-version/-/iterm2-version-4.2.0.tgz",
|
||||
|
@ -1542,11 +1440,6 @@
|
|||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz",
|
||||
"integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk="
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
|
||||
},
|
||||
"levn": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||
|
@ -1888,16 +1781,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.24.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
|
||||
},
|
||||
"moment-duration-format": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/moment-duration-format/-/moment-duration-format-2.3.2.tgz",
|
||||
"integrity": "sha512-cBMXjSW+fjOb4tyaVHuaVE/A5TqkukDWiOfxxAjY+PEqmmBQlLwn+8OzwPiG3brouXKY5Un4pBjAeB6UToXHaQ=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
|
@ -2755,33 +2638,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"window-size": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz",
|
||||
"integrity": "sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA==",
|
||||
"requires": {
|
||||
"define-property": "^1.0.0",
|
||||
"is-number": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-number": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
|
||||
"requires": {
|
||||
"kind-of": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"build": "echo Transpiling TypeScript to JavaScript... & node node_modules/typescript/bin/tsc --listEmittedFiles",
|
||||
"run": "node ./destreamer.js",
|
||||
"start": "npm run -s build & npm run -s run",
|
||||
"test": "mocha"
|
||||
"test": "mocha build/test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "snobu",
|
||||
|
@ -28,12 +28,15 @@
|
|||
"tmp": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/cli-progress": "^3.4.2",
|
||||
"@types/fluent-ffmpeg": "^2.1.14",
|
||||
"@types/jwt-decode": "^2.2.1",
|
||||
"axios": "^0.19.2",
|
||||
"cli-progress": "^3.7.0",
|
||||
"colors": "^1.4.0",
|
||||
"ffmpeg-progressbar-cli": "^1.5.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"is-elevated": "^3.0.0",
|
||||
"iso8601-duration": "^1.2.0",
|
||||
"jwt-decode": "^2.2.0",
|
||||
"puppeteer": "^2.1.1",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Metadata, Session } from './Types';
|
||||
|
||||
import { parse } from 'iso8601-duration';
|
||||
import axios from 'axios';
|
||||
|
||||
function publishedDateToString(date: string) {
|
||||
|
@ -10,10 +11,21 @@ function publishedDateToString(date: string) {
|
|||
return day+'-'+month+'-'+dateJs.getFullYear();
|
||||
}
|
||||
|
||||
function durationToTotalChuncks(duration: string) {
|
||||
const durationObj = parse(duration);
|
||||
const hrs = durationObj['hours'] ?? 0;
|
||||
const mins = durationObj['minutes'] ?? 0;
|
||||
const secs = Math.ceil(durationObj['seconds'] ?? 0);
|
||||
|
||||
return hrs * 1000 + mins * 100 + secs;
|
||||
}
|
||||
|
||||
|
||||
export async function getVideoMetadata(videoGuids: string[], session: Session, verbose: boolean): Promise<Metadata[]> {
|
||||
let metadata: Metadata[] = [];
|
||||
let title: string;
|
||||
let date: string;
|
||||
let duration: number;
|
||||
let playbackUrl: string;
|
||||
let posterImage: string;
|
||||
|
||||
|
@ -38,9 +50,11 @@ export async function getVideoMetadata(videoGuids: string[], session: Session, v
|
|||
|
||||
posterImage = response.data['posterImage']['medium']['url'];
|
||||
date = publishedDateToString(response.data['publishedDate']);
|
||||
duration = durationToTotalChuncks(response.data.media['duration']);
|
||||
|
||||
metadata.push({
|
||||
date: date,
|
||||
duration: duration,
|
||||
title: title,
|
||||
playbackUrl: playbackUrl,
|
||||
posterImage: posterImage
|
||||
|
@ -48,4 +62,4 @@ export async function getVideoMetadata(videoGuids: string[], session: Session, v
|
|||
}));
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ export type Session = {
|
|||
|
||||
export type Metadata = {
|
||||
date: string;
|
||||
duration: number;
|
||||
title: string;
|
||||
playbackUrl: string;
|
||||
posterImage: string;
|
|
@ -1,4 +1,4 @@
|
|||
import { sleep, parseVideoUrls, checkRequirements, makeUniqueTitle } from './utils';
|
||||
import { sleep, parseVideoUrls, checkRequirements, makeUniqueTitle, ffmpegTimemarkToChunk } from './utils';
|
||||
import { TokenCache } from './TokenCache';
|
||||
import { getVideoMetadata } from './Metadata';
|
||||
import { Metadata, Session, Errors } from './Types';
|
||||
|
@ -6,13 +6,13 @@ import { drawThumbnail } from './Thumbnail';
|
|||
|
||||
import isElevated from 'is-elevated';
|
||||
import puppeteer from 'puppeteer';
|
||||
import { execSync } from 'child_process';
|
||||
import colors from 'colors';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import yargs from 'yargs';
|
||||
import sanitize from 'sanitize-filename';
|
||||
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import cliProgress from 'cli-progress';
|
||||
|
||||
let tokenCache = new TokenCache();
|
||||
|
||||
|
@ -65,9 +65,7 @@ async function init() {
|
|||
});
|
||||
|
||||
process.on('exit', (code) => {
|
||||
if (code === 0)
|
||||
console.log(colors.bgGreen('\n\nDestreamer finished successfully! \n'))
|
||||
else if (code in Errors)
|
||||
if (code in Errors)
|
||||
console.error(colors.bgRed(`\n\nError: ${Errors[code]} \n`))
|
||||
else
|
||||
console.error(colors.bgRed(`\n\nUnknown exit code ${code} \n`))
|
||||
|
@ -182,6 +180,14 @@ function extractVideoGuid(videoUrls: string[]): string[] {
|
|||
|
||||
async function downloadVideo(videoUrls: string[], outputDirectory: string, session: Session) {
|
||||
const videoGuids = extractVideoGuid(videoUrls);
|
||||
const pbar = new cliProgress.SingleBar({
|
||||
barCompleteChar: '\u2588',
|
||||
barIncompleteChar: '\u2591',
|
||||
format: 'progress [{bar}] {percentage}% {speed}Kbps {eta_formatted}',
|
||||
barsize: Math.floor(process.stdout.columns / 3),
|
||||
stopOnComplete: true,
|
||||
etaBuffer: 20
|
||||
});
|
||||
|
||||
console.log('Fetching metadata...');
|
||||
|
||||
|
@ -204,27 +210,52 @@ async function downloadVideo(videoUrls: string[], outputDirectory: string, sessi
|
|||
|
||||
video.title = makeUniqueTitle(sanitize(video.title) + ' - ' + video.date, argv.outputDirectory);
|
||||
|
||||
const outputPath = outputDirectory + path.sep + video.title + '.mp4';
|
||||
|
||||
// Very experimental inline thumbnail rendering
|
||||
if (!argv.noThumbnails)
|
||||
await drawThumbnail(video.posterImage, session.AccessToken);
|
||||
|
||||
console.info('Spawning ffmpeg with access token and HLS URL. This may take a few seconds...\n');
|
||||
|
||||
const outputPath = outputDirectory + path.sep + video.title + '.mp4';
|
||||
ffmpeg()
|
||||
.input(video.playbackUrl)
|
||||
.inputOption([
|
||||
// Never remove those "useless" escapes or ffmpeg will not
|
||||
// pick up the header correctly
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
'-headers', `Authorization:\ Bearer\ ${session.AccessToken}`,
|
||||
])
|
||||
.format('mp4')
|
||||
.saveToFile(outputPath)
|
||||
.on('codecData', data => {
|
||||
console.log(`Input is ${data.video} with ${data.audio} audio.\n`);
|
||||
|
||||
// We probably need a way to be deterministic about
|
||||
// how we locate that ffmpeg-bar wrapper, npx maybe?
|
||||
// Do not remove those "useless" escapes or ffmpeg will
|
||||
// not pick up the header correctly.
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
let cmd = `node_modules/.bin/ffmpeg-bar -headers "Authorization:\ Bearer\ ${session.AccessToken}" -i "${video.playbackUrl}" -y "${outputPath}"`;
|
||||
execSync(cmd, {stdio: 'inherit'});
|
||||
console.info(`Download finished: ${outputPath}`);
|
||||
pbar.start(video.duration, 0, {
|
||||
speed: '0'
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
pbar.stop();
|
||||
});
|
||||
})
|
||||
.on('progress', progress => {
|
||||
const currentChuncks = ffmpegTimemarkToChunk(progress.timemark);
|
||||
|
||||
pbar.update(currentChuncks, {
|
||||
speed: progress.currentKbps
|
||||
});
|
||||
})
|
||||
.on('error', err => {
|
||||
pbar.stop();
|
||||
console.log(`ffmpeg returned an error: ${err.message}`);
|
||||
})
|
||||
.on('end', () => {
|
||||
console.log(colors.green(`\nDownload finished: ${outputPath}`));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function main() {
|
||||
checkRequirements() ?? process.exit(22);
|
||||
await init();
|
|
@ -71,3 +71,13 @@ export function makeUniqueTitle(title: string, outDir: string) {
|
|||
|
||||
return ntitle;
|
||||
}
|
||||
|
||||
|
||||
export function ffmpegTimemarkToChunk(timemark: string) {
|
||||
const timeVals: string[] = timemark.split(':');
|
||||
const hrs = parseInt(timeVals[0]);
|
||||
const mins = parseInt(timeVals[1]);
|
||||
const secs = parseInt(timeVals[2]);
|
||||
|
||||
return hrs * 1000 + mins * 100 + secs;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { parseVideoUrls } from '../utils';
|
||||
import { parseVideoUrls } from '../src/utils';
|
||||
import puppeteer from 'puppeteer';
|
||||
import assert from 'assert';
|
||||
import tmp from 'tmp';
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"rootDirs": ["./src", "./test"],
|
||||
"outDir": "./build",
|
||||
"target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
|
|
Loading…
Reference in a new issue