diff --git a/.gitignore b/.gitignore index a0a0091..4312a4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/index.ts .env .idea node_modules diff --git a/combineStream.ts b/combineStream.ts index 1e00a04..bc0a720 100644 --- a/combineStream.ts +++ b/combineStream.ts @@ -1,12 +1,12 @@ import fs from 'fs'; import ffmpeg from "fluent-ffmpeg"; -const combinedStreams = (dir, latestFile, feature) => { +const combinedStreams = (dir, latestFile, feature, numberOfFiles) => { return new Promise((resolve, reject) => { let files = [] - fs.readdirSync(`${dir}`).forEach(file => { - files.push(`${dir}/${file}`) - }); + for(let i = 0; i < numberOfFiles; i++) { + files.push(`${dir}/${i}.mp3`) + } const combiner = ffmpeg().on("error", err => { console.error("An error occurred: " + err.message); }) diff --git a/cypress/integration/getVideoUrls/getVideos.spec.js b/cypress/integration/getVideoUrls/getVideos.spec.js index 595829c..f081375 100644 --- a/cypress/integration/getVideoUrls/getVideos.spec.js +++ b/cypress/integration/getVideoUrls/getVideos.spec.js @@ -18,11 +18,10 @@ describe('Get Video', () => { }) it('get this ', () => { - const feature = 5; // const e = fs.readFileSync(`./curated-list/${feature}/1.txt`) // console.log(e.toString().split("\n")); - cy.readFile(`./curated-list/${feature}/1.txt`).then((fileUrl) => { + cy.readFile(`./curated-list/${Cypress.env('fileUpto')}/1.txt`).then((fileUrl) => { const c = fileUrl.split('\n') // read in file list and write next file name as file i.e. 1, 2, 3... etc. c.forEach((item) => { @@ -35,23 +34,14 @@ describe('Get Video', () => { console.log('below') console.log(updatedUrl.redirects.toString().split(' ')[1]); console.log('above') - cy.writeFile('./random-video-links/te.txt', updatedUrl.redirects.toString().split(' ')[1] + ',' + item.split(',')[1] + '\n', { flag: 'a+', timeout: 30000 }); + cy.writeFile(`./random-video-links/${Cypress.env('fileUpto')}/1.txt`, updatedUrl.redirects.toString().split(' ')[1] + ',' + item.split(',')[1] + '\n', { flag: 'a+', timeout: 120000 }); }) } }) - // cy.request({ - // url: fileUrl, - // method: 'GET' - // }).then((updatedUrl) => { - // console.log('below') - // console.log(updatedUrl.redirects.toString().split(' ')); - // console.log('above') - // cy.writeFile('./random-video-links/te.txt', updatedUrl.redirects.toString().split(' ')[1]); - // }) }) }) after(() => { // pass duration here. - cy.exec(`ts-node generateTemplates.ts ${Cypress.env('duration')}`) + cy.exec(`ts-node generateTemplates.ts ${Cypress.env('duration')}`, { timeout: 120000 }) }) }) diff --git a/enoughVideos.ts b/enoughVideos.ts index 4685210..6b6e291 100644 --- a/enoughVideos.ts +++ b/enoughVideos.ts @@ -4,22 +4,43 @@ import randomWords from "random-words"; const getRandomInt = (max) => { return Math.floor(Math.random() * max); } - +let listVids = []; const enoughVideos = async (listVideos, durationOfAudio) => { - let newList = listVideos; const t = await getVideo(randomWords()) - const duration = newList.reduce((currentValue, previousValue) => ({duration: currentValue.duration + previousValue.duration})); - if(duration.duration > durationOfAudio) { - if((duration.duration - durationOfAudio) < 40) { - return newList + if(listVideos) { + let newList = listVideos; + if(t !== undefined) { + listVids = [...listVideos, ...t]; + } else { + const y = await getVideo(randomWords()) + enoughVideos(y, durationOfAudio) + } + + + console.log(listVids) + const duration = listVids.reduce((currentValue, previousValue) => ({duration: currentValue?.duration + previousValue?.duration}), {duration: 0}); + console.log('below') + console.log(duration.duration) + console.log(durationOfAudio); + console.log('above') + + if(duration.duration > durationOfAudio) { + if((duration.duration - durationOfAudio) < 220) { + return listVids + } + listVids.pop(); + return enoughVideos(newList, durationOfAudio); } - newList.pop(); - return enoughVideos(newList, durationOfAudio); + const c = [t[getRandomInt(t.length)], ...newList] + listVids = [...listVideos, ...c]; + // this is where we can do a call to get more video. + return enoughVideos(c, durationOfAudio); + } else { + const t = await getVideo(randomWords()) + listVids = [...listVideos, ...t]; + enoughVideos(t, durationOfAudio); } - const c = [t[getRandomInt(t.length)], ...newList] - // this is where we can do a call to get more video. - return enoughVideos(c, durationOfAudio); } export default enoughVideos; diff --git a/generateTemplates.ts b/generateTemplates.ts index 56fcc6f..f53a8f1 100644 --- a/generateTemplates.ts +++ b/generateTemplates.ts @@ -15,13 +15,17 @@ class GenerateTemplates { return parseInt(process.argv.slice(2).toString(), 10); } + public getLinksFolder(): number { + return fs.readdirSync('./random-video-links').length; + } + public generateCompositionTemplate(){ const compositionTemplate = CompositionTemplateFile(this.getDuration()); fs.writeFileSync('./output-video-template/composition-files.tsx', compositionTemplate); } public generateVideoTemplate() { - const procesedVideoLinks = fs.readFileSync('./random-video-links/te.txt') + const procesedVideoLinks = fs.readFileSync(`./random-video-links/${this.getLinksFolder()}/1.txt`) let vidTemplates = []; procesedVideoLinks.toString().split('\n').forEach((line) => { diff --git a/generateTextFile.ts b/generateTextFile.ts index ba43947..4c3e760 100644 --- a/generateTextFile.ts +++ b/generateTextFile.ts @@ -5,7 +5,7 @@ export default class GenerateTextFile { public splitTextFile(): string[] { const str = fs.readFileSync(`./whole-story-text/${this.getLatestStory()}/1.txt`); - return this.yourSplit(10, str.toString().replace(/\'/g, '')) + return this.yourSplit(4, str.toString().replace(/\'/g, '')) } public getLatestStory(): number { diff --git a/getStory.ts b/getStory.ts index e991a66..b69597f 100644 --- a/getStory.ts +++ b/getStory.ts @@ -6,9 +6,13 @@ const getStory = async (directory, fileName, wholeStoryNumber) => { const post = await getPost('AmItheAsshole'); return new Promise((resolve, reject) => { const gtts = new gTTS(post['selftext'], 'en'); + console.log('below is file name') + console.log(fileName) + console.log(wholeStoryNumber) + console.log('above is file name') // we write each post to its own directory AND append to the same file // because gtts could be run on separate threads... so future proofing parallel processing speed. - fs.writeFileSync(`./story-text/${directory}/${fileName}.txt`, post['selftext'].replace(/\n/g, '')); + // fs.writeFileSync(`./story-text/${directory}/${fileName}.txt`, post['selftext'].replace(/\n/g, '')); fs.writeFileSync(`./whole-story-text/${wholeStoryNumber}/1.txt`, post['selftext'].replace(/\n/g, ''), {flag: 'a+'} ) gtts.save(`./stories/${directory}/${fileName}.mp3`, function (err, result) { if (err) { diff --git a/getVideo.ts b/getVideo.ts index d459d33..1835d6b 100644 --- a/getVideo.ts +++ b/getVideo.ts @@ -2,6 +2,7 @@ import axios from 'axios'; const getVideo = async (videoName) => { console.log('search term:::-', videoName); + // handle the undefined results here.. recursively poll until returning something. const req = await axios.get(`https://pixabay.com/api/videos/?key=21063902-7eaa7556445c3e0dd44c20488&q=${videoName}`) if (req.data.hits){ return req.data.hits diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..016fd5f --- /dev/null +++ b/index.ts @@ -0,0 +1,119 @@ +import randomWords from "random-words"; +import getVideo from "./getVideo"; +import organiseVideoByRating from "./organiseVideo"; +import enoughVideos from './enoughVideos'; +import getStory from './getStory'; +import fs from 'fs'; +import VideoTemplate from './template-writer/video-template-file'; +import TextTemplate from './template-writer/text-template-file'; +import getDuration from './getDuration'; +import combinedStreams from './combineStream'; +import CompositionTemplateFile from './template-writer/composition-template-file'; + +import GenerateTextFile from './generateTextFile'; + +const {exec} = require('child_process'); +const feature: number = fs.readdirSync('./stories').length; +async function loopStories() { + /** below **/ + let listOfVideos = [] + // // loop new stories + const fileName = Date.now(); + + + const numberOfPosts = 3; + + fs.mkdirSync(`./curated-list/${feature}`) + fs.mkdirSync(`./whole-story-text/${feature}`) + // console.log('number of posts, ', numberOfPosts) + fs.mkdirSync(`./combined/${feature}`) + fs.mkdirSync(`./stories/${feature}`) + fs.mkdirSync(`./random-video-links/${feature}`) + + for (let i = 0; i < numberOfPosts; i++) { + // + // // join into one file... so we can generate the text file. + await getStory(feature, i, feature) + } + + const latestFile = Date.now(); + await combinedStreams(`./stories/${feature}`, latestFile, feature, numberOfPosts) + // + // + // // used combined audio + const featureAudioFile = fs.readdirSync(`./combined/${feature}`); + // + // // should only have one feature audio track per folder. + // copy this to the src folder. + const audioFileDuration = await getDuration(`./combined/${feature}/${featureAudioFile[0]}`); + // + const videoList = await getVideo(randomWords()) + // + const organisedList = organiseVideoByRating(videoList); + listOfVideos.push(organisedList); + + console.log(audioFileDuration) + + // handle if list of video is shorter than audio length... + const curatedList = await enoughVideos(organisedList, audioFileDuration); + //console.log(curatedList) + const curatedListDuration = curatedList.reduce((currentValue, previousValue) => ({duration: currentValue.duration + previousValue.duration}), {duration: 0}); + console.log(`should be ${audioFileDuration} but is actually:: `, curatedListDuration); + + + + + fs.writeFileSync(`./curated-list/${feature}/1.txt`, ''); + curatedList.forEach((videoUrls) => { + if(videoUrls.videos.large.url){ + console.log(videoUrls.videos.large.url) + fs.appendFileSync(`./curated-list/${feature}/1.txt`, videoUrls.videos.large.url + ',' + videoUrls.duration + '\n'); + } + }) + + + + + // * fps substitude the 30 + exec(`node_modules/.bin/cypress run --env duration=${curatedListDuration.duration * 30},fileUpto=${feature}`) + + /** above is all good **/ + + + + /** above **/ + + + + /** NOTES BELOW **/ + // could potentially skip the step where we write it to file. + // - only if I can figure out how to pass the file paths as args into cypress... need to write those to file. + + + // currently we can get a reddit post, combined audio into one file, get video, of enough duration and get links to that video. + + //TOD + // have a script run cypress (after writing the intermediate video file links to file) + // have cypress write the finalized links to file. + // next we need to generate the file using remotion... bring that package into here. + // generate a video template file in remotion... looping through the list of videos. + // look into reading the text file in... and playing as part of the sequence (sync to the audio). + + + + /** NOTES ABOVE **/ + + + + +} + +loopStories(); + +// +// loopStories(); + + + + + diff --git a/template-writer/text-template-file.ts b/template-writer/text-template-file.ts index e392b2f..40f3958 100644 --- a/template-writer/text-template-file.ts +++ b/template-writer/text-template-file.ts @@ -34,14 +34,14 @@ const TextTemplate = (text: string[]) => { "paddingRight: 10,\n" + "transform:" + "`" + "scale(" + "$" + "{" + "spring" + "({\n" + "fps: 30,\n" + - "frame: -1* (" + `${z * 100}` + "- (frame - i * 5)),\n" + + "frame: -1* (" + `${z * 120}` + "- (frame - i * 5)),\n" + "config: {\n" + "damping: 100,\n" + "stiffness: 200,\n" + "mass: 0.5,\n" + "}\n" + "})})" + "`,\n" + - "marginBottom: 25,\n" + + "marginBottom: 85,\n" + "display: 'inline-block'\n" + "}}\n" + '>' + @@ -59,7 +59,7 @@ const TextTemplate = (text: string[]) => { "return " + "(\n" + "<>\n" + `${text.map((textLine, i) => { - return "" + + return "" + "{" + "val"+i + "(" + ")" + "}" + "\n" + "\n" }).join('')}\n` + diff --git a/template-writer/video-template-file.ts b/template-writer/video-template-file.ts index 123832a..d15459c 100644 --- a/template-writer/video-template-file.ts +++ b/template-writer/video-template-file.ts @@ -6,7 +6,7 @@ export interface VideoList { const VideoTemplate = (videoList: VideoList[], audioFilePath: string) => { return "import {AbsoluteFill} from 'remotion';\n" + - "import {Video} from 'remotion';\n" + + "import {Video, Audio} from 'remotion';\n" + "import TransitionSeries from 'remotion-transition-series';\n" + "import {TextRead} from './text';\n" + `import audio from '${audioFilePath}'\n` + @@ -20,7 +20,7 @@ const VideoTemplate = (videoList: VideoList[], audioFilePath: string) => { ${videoList.map((videoUrl: VideoList) => { return "" + '\n' + - "