Skip to content
This repository has been archived by the owner on Jan 10, 2020. It is now read-only.

Commit

Permalink
Merge pull request #103 from NewSpring/sermon-audio
Browse files Browse the repository at this point in the history
Sermon audio
  • Loading branch information
johnthepink committed Aug 3, 2016
2 parents 8bd20ef + c01aab0 commit e5eae04
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 6 deletions.
9 changes: 4 additions & 5 deletions global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,6 @@ declare module "truncate" {
export default function(string: string, length: number): string;
}

declare module "connect-datadog" {
export default function(opts: any): any;
}


declare module "raven" {
export interface IOptions {
extra?: Object;
Expand Down Expand Up @@ -153,3 +148,7 @@ declare module "datadog-metrics" {
let client: DDog;
export default client;
}

declare module "mp3-duration" {
export default function(filename: string, callback: any);
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"moment": "^2.13.0",
"mongoose": "^4.5.8",
"morgan": "^1.7.0",
"mp3-duration": "^1.0.10",
"mssql-geoparser": "0.0.1",
"mysql": "^2.10.2",
"newrelic": "^1.25.0",
Expand Down
18 changes: 18 additions & 0 deletions src/expression-engine/models/content/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,30 @@ export default {
description: "primary",
}];
},
// deprecated
tracks: ({ entry_id, tracks, exp_channel }, _, { models }) => {
if (!tracks) return [];

const position = Number(exp_channel.exp_channel_fields.tracks.split("_").pop());
return models.File.getFilesFromContent(entry_id, tracks, position);
},
audio: ({ entry_id, audio, tracks, exp_channel }, _, { models }) => {
if (!audio && !tracks) return Promise.all([]);
const getAllFiles = [];

if (audio) {
const audioPosition = Number(exp_channel.exp_channel_fields.audio.split("_").pop());
getAllFiles.push(models.File.getFilesFromContent(entry_id, audio, audioPosition));
}

if (tracks) {
const trackPosition = Number(exp_channel.exp_channel_fields.tracks.split("_").pop());
getAllFiles.push(models.File.getFilesFromContent(entry_id, tracks, trackPosition));
}

return Promise.all(getAllFiles)
.then(data => flatten(data));
},
},

ContentMeta: {
Expand Down
3 changes: 3 additions & 0 deletions src/expression-engine/models/content/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ type ContentData {
tags: [String] # XXX create global tag type
colors: [ContentColor]
images: [File]

# deprecated (use audio field)
tracks: [File]
audio: [File]
scripture: [ContentScripture]
}

Expand Down
49 changes: 48 additions & 1 deletion src/expression-engine/models/files/model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { merge } from "lodash";
import { get as httpGet } from "http";
import { existsSync, mkdirSync, createWriteStream, unlink } from "fs";
import mp3Duration from "mp3-duration";

import { Cache, defaultCache } from "../../../util/cache";

Expand Down Expand Up @@ -95,6 +98,49 @@ export class File extends EE {
}
}

private addDuration(file: any): Promise<any> {
return new Promise((resolve, reject) => {
const fileName = file.exp_assets_file.file_name;
if (fileName.slice(fileName.length - 3) !== "mp3") return resolve(file);

const duration = file.exp_matrix_datum && this.fuzzyMatchKey(file.exp_matrix_datum, "duration");
if (duration) {
file.duration = duration;
return resolve(file);
}

// create ./tmp/audio directory
if (!existsSync("./tmp")) mkdirSync("./tmp");
if (!existsSync("./tmp/audio")) mkdirSync("./tmp/audio");

// if no duration, try to calcuate it
const url = `http:${this.generateFileName(file.exp_assets_file).s3}`;
const tmpFileName = `./tmp/audio/${file.exp_assets_file.file_name}`;
const tmpFile = createWriteStream(tmpFileName);
httpGet(url, (response) => {
response.pipe(tmpFile);
tmpFile.on("finish", () => {
tmpFile.close();
mp3Duration(tmpFileName, (err, calcDuration) => {
const seconds = Math.round(calcDuration % 60);
const minutes = Math.round(calcDuration / 60);
const paddedSeconds = seconds < 10 ? `0${seconds}` : seconds;

// check first in case multiple requests come in before cache
if (existsSync(tmpFileName)) unlink(tmpFileName);
file.duration = `${minutes}:${paddedSeconds}`;
return resolve(file);
});
});
}).on("error", (error) => {
console.log(error.message); // tslint:disable-line
unlink(tmpFileName);
file.duration = null;
return reject(file);
});
});
}

public async getFilesFromContent(
entry_id: number, name: string = "Hero Image", field_id: number
): Promise<any> { // replace with FileType
Expand Down Expand Up @@ -138,12 +184,13 @@ export class File extends EE {
],
})
.then(data => data.map(x => x.exp_assets_selection))
.then(data => (Promise.all(data.map(file => ( this.addDuration(file) )))))
.then(data => data.map(x => (merge(
{
file_id: x.file_id,
fileLabel: x.exp_matrix_col && x.exp_matrix_col.col_label,
title: x.exp_matrix_datum && this.fuzzyMatchKey(x.exp_matrix_datum, "title"),
duration: x.exp_matrix_datum && this.fuzzyMatchKey(x.exp_matrix_datum, "duration"),
duration: x.duration,
},
this.generateFileName(x.exp_assets_file)
))))
Expand Down
98 changes: 98 additions & 0 deletions test/expression-engine/models/content/resolver.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,101 @@ test("`ContentScripture` returns book and passage", t => {
t.deepEqual(book, sampleData.contentScripture.book);
t.deepEqual(passage, sampleData.contentScripture.passage);
});

// XXX test all of this resolver

test("`ContentData` returns blank array if no audio or tracks", async (t) => {
const { ContentData } = Resolver;
const mockData = {
entry_id: "testId",
audio: null,
tracks: null,
exp_channel: {},
};
const models = {};

await ContentData.audio(mockData, null, { models });
});

test("`ContentData` fetches audio files if audio", async (t) => {
const { ContentData } = Resolver;
const mockData = {
entry_id: "testId",
audio: "audio.mp3",
tracks: null,
exp_channel: {
exp_channel_fields: {
audio: "test_field_123",
},
},
};
const models = {
File: {
getFilesFromContent: (entry_id, audio, audioPosition) => {
t.is(entry_id, mockData.entry_id);
t.is(audio, mockData.audio);
t.is(audioPosition, Number(mockData.exp_channel.exp_channel_fields.audio.split("_").pop()));
},
},
};

await ContentData.audio(mockData, null, { models });
});

test("`ContentData` fetches tracks files if tracks", async (t) => {
const { ContentData } = Resolver;
const mockData = {
entry_id: "testId",
audio: null,
tracks: "audio.mp3",
exp_channel: {
exp_channel_fields: {
tracks: "test_field_789",
},
},
};
const models = {
File: {
getFilesFromContent: (entry_id, tracks, trackPosition) => {
t.is(entry_id, mockData.entry_id);
t.is(tracks, mockData.tracks);
t.is(trackPosition, Number(mockData.exp_channel.exp_channel_fields.tracks.split("_").pop()));
},
},
};

await ContentData.audio(mockData, null, { models });
});

test("`ContentData` fetches audio and tracks files if both", async (t) => {
const { ContentData } = Resolver;
const mockData = {
entry_id: "testId",
audio: "audio.mp3",
tracks: "track.mp3",
exp_channel: {
exp_channel_fields: {
audio: "test_field_123",
tracks: "test_field_789",
},
},
};
let count = 0;
const models = {
File: {
getFilesFromContent: (entry_id, thing, thingPosition) => {
count++;
t.is(entry_id, mockData.entry_id);
t.true([mockData.audio, mockData.tracks].indexOf(thing) > -1);
const splitField = thing === mockData.audio ?
Number(mockData.exp_channel.exp_channel_fields.audio.split("_").pop()) :
Number(mockData.exp_channel.exp_channel_fields.tracks.split("_").pop())
;
t.is(thingPosition, splitField);
},
},
};

await ContentData.audio(mockData, null, { models });
t.is(count, 2);
});

0 comments on commit e5eae04

Please sign in to comment.