Bulk import movies

This commit is contained in:
Jindra Petřík
2022-12-26 09:31:10 +01:00
parent 9ca27d48be
commit dacd9195ef
5 changed files with 196 additions and 9 deletions

View File

@@ -26,30 +26,101 @@ import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.VideoFrameTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
import com.jpexs.decompiler.flash.timeline.Timelined;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.Reference;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class MovieImporter {
public void importMovie(DefineVideoStreamTag movie, InputStream fis) throws IOException {
public int bulkImport(File moviesDir, SWF swf, boolean printOut) {
Map<Integer, CharacterTag> characters = swf.getCharacters();
int movieCount = 0;
List<String> extensions = Arrays.asList("flv");
File allFiles[] = moviesDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
String nameLower = name.toLowerCase();
for (String ext : extensions) {
if (nameLower.endsWith("." + ext)) {
return true;
}
}
return false;
}
});
for (int characterId : characters.keySet()) {
CharacterTag tag = characters.get(characterId);
if (tag instanceof DefineVideoStreamTag) {
DefineVideoStreamTag movieTag = (DefineVideoStreamTag) tag;
List<File> existingFilesForMovieTag = new ArrayList<>();
for (File f : allFiles) {
if (f.getName().startsWith("" + characterId + ".") || f.getName().startsWith("" + characterId + "_")) {
existingFilesForMovieTag.add(f);
}
}
existingFilesForMovieTag.sort(new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
String ext1 = o1.getName().substring(o1.getName().lastIndexOf(".") + 1);
String ext2 = o2.getName().substring(o2.getName().lastIndexOf(".") + 1);
int ret = extensions.indexOf(ext1) - extensions.indexOf(ext2);
if (ret == 0) {
return o1.getName().compareTo(o2.getName());
}
return ret;
}
});
if (existingFilesForMovieTag.isEmpty()) {
continue;
}
if (existingFilesForMovieTag.size() > 1) {
Logger.getLogger(MovieImporter.class.getName()).log(Level.WARNING, "Multiple matching files for movie tag {0} exists, {1} selected", new Object[]{characterId, existingFilesForMovieTag.get(0).getName()});
}
File sourceFile = existingFilesForMovieTag.get(0);
try {
if (printOut) {
System.out.println("Importing character " + characterId + " from file " + sourceFile.getName());
}
importMovie(movieTag, Helper.readFile(sourceFile.getAbsolutePath()));
movieCount++;
} catch (IOException ex) {
Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, "Cannot import movie " + characterId + " from file " + sourceFile.getName(), ex);
}
if (Thread.currentThread().isInterrupted()) {
break;
}
}
}
return movieCount;
}
public void importMovie(DefineVideoStreamTag movie, byte[] data) throws IOException {
List<FLVTAG> videoTags = new ArrayList<>();
FLVInputStream flvIs = new FLVInputStream(fis);
FLVInputStream flvIs = new FLVInputStream(new ByteArrayInputStream(data));
Reference<Boolean> audioPresent = new Reference<>(false);
Reference<Boolean> videoPresent = new Reference<>(false);
flvIs.readHeader(audioPresent, videoPresent);

View File

@@ -592,6 +592,12 @@ public class CommandLineArgumentParser {
out.println(" ...imports Symbol-Class mapping to <infile> and saves the result to <outfile>");
}
if (filter == null || filter.equals("importmovies")) {
out.println(" " + (cnt++) + ") -importMovies <infile> <outfile> <moviesfolder>");
out.println(" ...imports movies to <infile> and saves the result to <outfile>");
}
if (filter == null || filter.equals("importshapes")) {
out.println(" " + (cnt++) + ") -importShapes <infile> <outfile> [nofill] <shapesfolder>");
out.println(" ...imports shapes to <infile> and saves the result to <outfile>");
@@ -1031,6 +1037,8 @@ public class CommandLineArgumentParser {
parseDoc(args);
} else if (command.equals("importsymbolclass")) {
parseImportSymbolClass(args, charset);
} else if (command.equals("importmovies")) {
parseImportMovies(args, charset);
} else if (command.equals("importshapes")) {
parseImportShapes(args, charset);
} else if (command.equals("importimages")) {
@@ -3215,7 +3223,7 @@ public class CommandLineArgumentParser {
} else if (characterTag instanceof DefineVideoStreamTag) {
DefineVideoStreamTag movie = (DefineVideoStreamTag)characterTag;
try {
new MovieImporter().importMovie(movie, new ByteArrayInputStream(data));
new MovieImporter().importMovie(movie, data);
} catch (IOException iex) {
System.err.println("Import FAILED: "+iex.getMessage());
System.exit(1);
@@ -3805,6 +3813,42 @@ public class CommandLineArgumentParser {
System.exit(2);
}
}
private static void parseImportMovies(Stack<String> args, String charset) {
if (args.size() < 3) {
badArguments("importmovies");
}
File inFile = new File(args.pop());
File outFile = new File(args.pop());
try (StdInAwareFileInputStream is = new StdInAwareFileInputStream(inFile)) {
SWF swf = new SWF(is, Configuration.parallelSpeedUp.get(), charset);
System.out.println("Source file opened");
String selFile = args.pop();
File moviesDir = new File(Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME));
if (moviesDir.exists()) {
System.out.println("Using the directory: " + moviesDir.getAbsolutePath());
} else {
moviesDir = new File(selFile);
}
if (!moviesDir.exists()) {
System.err.println("Movies directory does not exist: " + moviesDir.getAbsolutePath());
System.exit(1);
}
MovieImporter movieImporter = new MovieImporter();
int movieCount = movieImporter.bulkImport(moviesDir, swf, true);
System.out.println("Writing outfile");
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) {
swf.saveTo(fos);
}
System.out.println("" + movieCount + " movies successfully imported");
} catch (IOException | InterruptedException e) {
System.err.println("I/O error during writing");
System.exit(2);
}
}
private static void parseImportImages(Stack<String> args, String charset) {
if (args.size() < 3) {

View File

@@ -3067,7 +3067,60 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
public void importMovie(final SWF swf) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importMovies2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportShapeInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
File moviesDir = new File(Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME));
if (!moviesDir.exists()) {
moviesDir = new File(selFile);
}
final File fMoviesDir = moviesDir;
MovieImporter movieImporter = new MovieImporter();
final long timeBefore = System.currentTimeMillis();
new CancellableWorker<Void>() {
private int count = 0;
@Override
public Void doInBackground() throws Exception {
try {
count = movieImporter.bulkImport(fMoviesDir, swf, false);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during import", ex);
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
}
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.importing") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
final long timeMs = timeAfter - timeBefore;
View.execInEventDispatch(() -> {
refreshTree(swf);
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
ViewMessages.showMessageDialog(MainPanel.this, translate("import.movie.result").replace("%count%", Integer.toString(count)));
if (count != 0) {
reload(true);
}
});
}
}.execute();
}
}
public void importShape(final SWF swf, boolean noFill) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importShapes2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportShapeInfo);
@@ -4105,8 +4158,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
previewPanel.clear();
DefineVideoStreamTag movie = (DefineVideoStreamTag) item;
File selfile = Helper.fixDialogFile(selectedFile);
try (FileInputStream fis = new FileInputStream(selfile)) {
new MovieImporter().importMovie(movie, fis);
try {
new MovieImporter().importMovie(movie, Helper.readFile(selfile.getAbsolutePath()));
refreshTree();
} catch (IOException ex) {
ViewMessages.showMessageDialog(MainPanel.this, translate("error.movie.invalid") + ": "+ex.getMessage(), translate("error"), JOptionPane.ERROR_MESSAGE);

View File

@@ -1091,4 +1091,11 @@ error.sound.rate = The input sound has unsupported sampling rate: %saplingRate%.
filter.movies = Supported movie formats (%extensions%)
error.movie.invalid = Invalid movie.
menu.file.import.movie = Import movies
menu.file.import.movie = Import movies
message.info.importMovies2 = During importing movies, you need to select a FOLDER.\r\n \
Filenames inside the folder must match existing movies in current selected SWF.\r\n \
If there exist "movies" folder inside, it is selected instead.\r\n \
The best way to get the structure right is to export images in current SWF file first.
import.movie.result = %count% movies imported.

View File

@@ -1071,4 +1071,16 @@ status.editing.autosave = Jste v EDITA\u010cN\u00cdM re\u017eimu. Prove\u010fte
error.sound.rate = Vstupn\u00ed zvuk m\u00e1 nepodporovanou vzorkovac\u00ed frekvenci: %saplingRate%.\r\n\
P\u0159ed importem je t\u0159eba zvuk zkonvertovat n\u011bjak\u00fdm editorem zvuku\r\n\
do jedn\u00e9 z podporovan\u00fdch frekvenc\u00ed (%supportedRates%).
do jedn\u00e9 z podporovan\u00fdch frekvenc\u00ed (%supportedRates%).
filter.movies = Podporovan\u00e9 form\u00e1ty videa (%extensions%)
error.movie.invalid = Neplatn\u00e9 video.
menu.file.import.movie = Importovat videa
message.info.importMovies2 = B\u011bhem importu vide\u00ed mus\u00edte vybrat SLO\u017dKU.\r\n \
N\u00e1zvy soubor\u016f uvnit\u0159 mus\u00ed souhlasit s existuj\u00edc\u00edmi videi v pr\u00e1v\u011b vybran\u00e9m SWF.\r\n \
Pokud je uvnit\u0159 slo\u017eka "movies", pak je vybr\u00e1na m\u00edsto n\u00ed.\r\n \
Nejlep\u0161\u00ed zp\u016fsob jak m\u00edt tuto strukturu spr\u00e1vn\u011b je nejprve exportovat videa v aktu\u00e1ln\u00edm SWF souboru.
import.movie.result = %count% vide\u00ed importov\u00e1no.