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

Share Audio #389

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
53 changes: 53 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@ffmpeg/ffmpeg": "^0.12.1",
"@ffmpeg/util": "^0.12.0",
"@sveltejs/adapter-static": "^2",
"@sveltejs/kit": "^1",
"@tailwindcss/typography": "^0.5.2",
Expand Down Expand Up @@ -60,6 +62,6 @@
"vite": "^4"
},
"volta": {
"node": "16.17.0"
"node": "18.17.0"
}
}
63 changes: 63 additions & 0 deletions src/lib/data/audio-convert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { FFmpeg } from '@ffmpeg/ffmpeg';
import type { FileData } from '@ffmpeg/ffmpeg/dist/esm/types';
import { toBlobURL, fetchFile } from '@ffmpeg/util';

//
//-y -i /data/user/0/com.example.app.scripture/cache/B01___01_Matthew_____ENGWEBN2DA.mp3
//-map_metadata 0 -ss 00:00:20.120 -to 00:00:28.960
//-map 0:a -acodec copy -write_xing 0
// "/storage/emulated/0/Android/data/com.example.app.scripture/files/WEB Gospels/Matthew_1_3.mp3"

let ffmpeg: FFmpeg = null;
let loaded = false;
export async function loadFFmpeg() {
if (!ffmpeg) {
const baseURL = 'https://unpkg.com/@ffmpeg/[email protected]/dist/umd';
ffmpeg = new FFmpeg();
ffmpeg.on('log', ({ message }) => {
console.log(message);
});
// toBlobURL is used to bypass CORS issue, urls with the same
// domain can be used directly.
await ffmpeg.load({
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm')
});
loaded = true;
}
}

export async function convert(
inputPath: string,
timingStart: string,
timingEnd: string,
output: string
): Promise<FileData> {
if (!loaded) {
await loadFFmpeg();
}

const input = 'input.' + inputPath.split('.').pop();
await ffmpeg.writeFile(input, await fetchFile(inputPath));
await ffmpeg.exec([
'-i',
input,
'-map_metadata',
'0',
'-ss',
timingStart,
'-to',
timingEnd,
'-map',
'0:a',
'-acodec',
'copy',
'-write_xing',
'0',
output
]);
const data = await ffmpeg.readFile(output);
await ffmpeg.deleteFile(input);
await ffmpeg.deleteFile(output);
return data;
}
83 changes: 83 additions & 0 deletions src/lib/data/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,86 @@ export function seekToVerse(verseClicked) {
//forces highlighting change
updateTime();
}

// This algorithm is based on the Android code in
// AudioVideoFileManager::getExtractAudioProcessingTask
export function getTimingForVerseRange(verseRange: string) {
const timing = currentAudioPlayer.timing;

if (timing && timing.length > 0) {
// Ensure the final timing has its end time set properly
const lastTiming = timing[timing.length - 1];
if (lastTiming.endtime - lastTiming.starttime < 0.01) {
lastTiming.endtime = currentAudioPlayer.audio.duration;
}
}

let timing1 = null;
let timing2 = null;

const vs = verseRange.split('-');
if (vs.length === 1) {
const verse = vs[0];
timing1 = timing.find((t) => t.tag.includes(verse));
timing2 = timing1;
}
const startVerse = verseRange.split('-')[0];
const endVerse = verseRange.split('-')[1];
const startTiming = timing.find((t) => t.tag.includes(startVerse));
const endTiming = timing.find((t) => t.tag.includes(endVerse));
return {
start: startTiming,
end: endTiming
};
}

function getTimingForVerse(timings: Array<any>, verse: string) {
const result = [];
for (let i = 0; i < timings.length; i++) {
if (!isTimingForVerseRange(timings[i])) {
// This timing is for a single verse or phrases in a verse
// e.g. "4" - return timings 4a, 4b, 4c.
if (getVerseForTiming(timings[i]) === verse) {
result.push(timings[i]);
}
} else {
}
}
}

function getVerseForTiming(timing: any) {
function extractNumericalPart(inputString) {
let numericalPart = '';
let index = 0;

// Skip non-numerical characters at the beginning of the string
while (index < inputString.length && isNaN(parseInt(inputString[index]))) {
index++;
}

// Extract numerical characters until a non-numerical character is encountered
while (index < inputString.length && !isNaN(parseInt(inputString[index]))) {
numericalPart += inputString[index];
index++;
}

// Return the numerical part or null if no numerical part is found
return numericalPart.length > 0 ? numericalPart : null;
}

return extractNumericalPart(timing.tag);
}

function isVerseNumberInVerseRange(verse: string, verseRange: string) {
const vs = verseRange.split('-');
if (vs.length === 1) {
return verse === vs[0];
}
const startVerse = vs[0];
const endVerse = vs[1];
return verse >= startVerse && verse <= endVerse;
}

function isTimingForVerseRange(timing: any) {
return timing.tag && timing.tag.includes('-');
}