Warning: session_start(): open(/var/lib/php/sessions/sess_g4nt8ek2pjk43d4e7ig70bjmf3, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
!7
sclass VidFile {
File file;
double length = -1;
transient float[] profile;
transient L ranges;
S id() { ret md5FromFilePathSizeAndDate(file); }
File audioFile() { ret prepareCacheProgramFile("preview-" + id() + ".wav"); }
}
module AJCBatch > DynObjectTable {
S outputFile;
int volumeThresholdPercent = 15;
S minSilence = "0.2", leadIn = "0.2", leadOut = "0.2";
transient double profileSamplingInterval = 0.05; // 50 ms
transient int audioWindowSize = iround(profileSamplingInterval*16000);
S originalLength, cutLength;
transient ReliableSingleThread rstScan = dm_rst(this, r scan);
visualize {
JComponent sup = super.visualize();
ret centerAndSouthWithMargins(
jHandleMultiFileDrop(vf> onFileDrop,
withCenteredTitle("Input videos (you can drag&drop files here):",
withRightAlignedButtons(sup,
tableDependentButton(table, "Remove selected", r removeSelected)
))),
vstackWithSpacing(
centeredLine(withLabel("Total input duration:", dm_boldLabel('originalLength))),
dm_ajc_parametersSection(),
centeredLine(withLabel("Total output duration (est.):", dm_boldLabel('cutLength))),
withLabel("Output video:", filePathInputWithBrowseButton(dm_textField('outputFile))),
rightAlignedLine(fontSizePlus(3, jbutton("Make video", rThread makeVideo)))
));
}
void onFileDrop(L files) enter {
print("Have file drop");
Set haveFiles = collectAsSet file(data());
addAll(map(listMinusSet(files, haveFiles), f -> nu VidFile(file := f)));
}
start {
itemToMap = func(VidFile v) -> Map {
litorderedmap(
"Video" := fileName(v.file),
"Folder" := dirPath(v.file),
"Duration" := !fileExists(v.file) ? "File not found"
: v.length < 0 ? "[calculating]" : formatMinuteAndSeconds(iceil(v.length))
)
};
rstScan.trigger();
dm_watchFields(allNonStaticNonTransientFields(AJCParameters), r recut);
}
void recut {
for (VidFile v : clonedList())
v.ranges = null;
rstScan.trigger();
}
void scan {
bool change;
double lenIn = 0, lenOut = 0;
for (VidFile v : clonedList()) pcall {
if (v.ranges == null || v.length < 0 && fileExists(v.file)) {
File audio = v.audioFile();
if (fileLength(audio) == 0) {
print("Extracting audio from " + v.file);
ffmpeg_toMonoAudio_16k(v.file, audio); // TODO: temp file for safety?
v.profile = null;
}
if (v.profile == null)
v.profile = decodeWAVToMonoSamples_floatVolumeProfile(audio, audioWindowSize);
v.length = l(v.profile)*profileSamplingInterval;
v.ranges = ajc_findSpeechPartsFromVolumeProfile(v.profile,
shallowCloneToClass AJCParameters(module()));
set change;
}
lenIn += v.length;
lenOut += totalLengthOfDoubleRanges(v.ranges);
}
setField(originalLength := formatMinuteAndSeconds(iceil(lenIn));
setField(cutLength := formatMinuteAndSeconds(iceil(lenOut));
if (change) fireDataChanged();
}
void makeVideo {
temp dm_tempDisableAllButtons();
while (rstScan.running()) sleep(10);
if (emptyAfterTrim(outputFile)) ret with infoBox("Need output file path");
File out = newFile(trim(outputFile));
L l = clonedList();
if (empty(l)) ret with infoBox("No input files");
if (fileExists(out) && !confirmOKCancel("Overwrite " + fileName(out) + "?")) ret;
L files = collect file(l);
LL ranges = collect ranges(l);
temp tempInfoBox_noHide("Splicing video...");
backtickToConsole(ffmpegCmd() + " -y " + ffmpeg_argsForSplice_usingFile(files, out, ranges));
if (fileExists(out))
infoBox("Done splicing video!" + fileInfo(out));
else
infoBox("Something went wrong...");
}
}