diff --git a/CHANGELOG.md b/CHANGELOG.md index f710531ed..1547f267a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. - [#1827] Replacing and bulk import of DefineVideoStream - Movie FLV export - writing simple onMetadata tag - [#1424], [#1473], [#1473], [#1852] Replacing sound streams (SoundStreamHead, SoundStreamBlock) +- Bulk import sounds and sound streams ### Fixed - [#1914] DropShadow filter diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 571b6e6f9..0a83d945f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -875,6 +875,10 @@ public final class Configuration { @ConfigurationCategory("ui") public static ConfigurationItem showImportMovieInfo = null; + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static ConfigurationItem showImportSoundInfo = null; + private enum OSId { WINDOWS, OSX, UNIX } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java index a53568020..bb425d820 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/SoundImporter.java @@ -21,9 +21,11 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.tags.DefineSoundTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag; import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.SoundImportException; import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; import com.jpexs.decompiler.flash.tags.base.SoundTag; @@ -38,11 +40,17 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +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.List; +import java.util.Locale; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.sound.sampled.AudioFormat; @@ -460,4 +468,96 @@ public class SoundImporter { } return false; } + + public int bulkImport(File soundDir, SWF swf, boolean printOut) { + + Map characters = swf.getCharacters(); + int soundCount = 0; + List extensions = Arrays.asList("mp3", "wav"); + File allFiles[] = soundDir.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; + } + }); + + + List soundTags = new ArrayList<>(); + for (int characterId : characters.keySet()) { + CharacterTag tag = characters.get(characterId); + if (tag instanceof DefineSoundTag) { + soundTags.add((DefineSoundTag) tag); + } + if (tag instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) tag; + for (Tag subTag : sprite.getTags()) { + if (subTag instanceof SoundStreamHeadTypeTag) { + soundTags.add((SoundStreamHeadTypeTag)subTag); + } + } + } + } + for (Tag tag:swf.getTags()) { + if (tag instanceof SoundStreamHeadTypeTag) { + soundTags.add((SoundStreamHeadTypeTag) tag); + } + } + + for (SoundTag tag : soundTags) { + int characterId = tag.getCharacterId(); + List existingFilesForSoundTag = new ArrayList<>(); + for (File f : allFiles) { + if (f.getName().startsWith("" + characterId + ".") || f.getName().startsWith("" + characterId + "_")) { + existingFilesForSoundTag.add(f); + } + } + existingFilesForSoundTag.sort(new Comparator() { + @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 (existingFilesForSoundTag.isEmpty()) { + continue; + } + + if (existingFilesForSoundTag.size() > 1) { + Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, "Multiple matching files for sound tag {0} exists, {1} selected", new Object[]{characterId, existingFilesForSoundTag.get(0).getName()}); + } + File sourceFile = existingFilesForSoundTag.get(0); + + try { + if (printOut) { + System.out.println("Importing character " + characterId + " from file " + sourceFile.getName()); + } + int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; + if (sourceFile.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".mp3")) { + soundFormat = SoundFormat.FORMAT_MP3; + } + try (FileInputStream fis = new FileInputStream(sourceFile)){ + importSound(tag,fis, soundFormat); + soundCount++; + } + } catch (IOException|SoundImportException ex) { + Logger.getLogger(ShapeImporter.class.getName()).log(Level.WARNING, "Cannot import sound " + characterId + " from file " + sourceFile.getName(), ex); + } + if (Thread.currentThread().isInterrupted()) { + break; + } + } + return soundCount; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java index 64137b79a..12ccfe4d5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/SoundTag.java @@ -58,4 +58,6 @@ public interface SoundTag extends TreeItem { public void setSoundCompression(int soundCompression); public void setSoundRate(int soundRate); + + public int getCharacterId(); } diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 2c947fe2f..3e188ef12 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -226,6 +226,7 @@ import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; import com.jpexs.decompiler.flash.tags.base.HasSeparateAlphaChannel; import com.jpexs.decompiler.flash.tags.base.RenderContext; import com.jpexs.decompiler.flash.tags.base.SoundImportException; +import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; import com.jpexs.decompiler.flash.tags.base.UnsupportedSamplingRateException; import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.helpers.SerializableImage; @@ -598,7 +599,11 @@ public class CommandLineArgumentParser { out.println(" ...imports movies to and saves the result to "); } - + if (filter == null || filter.equals("importsounds")) { + out.println(" " + (cnt++) + ") -importSounds "); + out.println(" ...imports sounds to and saves the result to "); + } + if (filter == null || filter.equals("importshapes")) { out.println(" " + (cnt++) + ") -importShapes [nofill] "); out.println(" ...imports shapes to and saves the result to "); @@ -1067,6 +1072,9 @@ public class CommandLineArgumentParser { } else if (command.equals("importmovies")) { parseImportMovies(args, charset); System.exit(0); + } else if (command.equals("importsounds")) { + parseImportSounds(args, charset); + System.exit(0); } else if (command.equals("importshapes")) { parseImportShapes(args, charset); System.exit(0); @@ -1483,7 +1491,7 @@ public class CommandLineArgumentParser { } return false; } - }, charset); + }, charset); } private static void parseSetInstanceMetadata(Stack args, String charset) { @@ -1692,7 +1700,7 @@ public class CommandLineArgumentParser { } return false; } - }, charset); + }, charset); } private static void parseRemoveInstanceMetadata(Stack args, String charset) { @@ -1820,7 +1828,7 @@ public class CommandLineArgumentParser { } return false; } - }, charset); + }, charset); } private static class Range { @@ -2732,7 +2740,7 @@ public class CommandLineArgumentParser { } } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); - } + } } private static void parseXml2Swf(Stack args, String charset) { @@ -2751,7 +2759,7 @@ public class CommandLineArgumentParser { } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } - + } private static void parseExtract(Stack args) { @@ -2836,7 +2844,7 @@ public class CommandLineArgumentParser { } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } - + } private static void parseMemorySearch(Stack args) { @@ -2921,7 +2929,7 @@ public class CommandLineArgumentParser { } else { System.err.println("Memory search is only available on Windows platform."); } - + } private static void parseRenameInvalidIdentifiers(Stack args) { @@ -3065,7 +3073,7 @@ public class CommandLineArgumentParser { int fframe = 0; final Graphics2D g = (Graphics2D) job.getGraphics(pf); - + SerializableImage image = new SerializableImage((int) w + 1, (int) h + 1, SerializableImage.TYPE_INT_ARGB_PRE) { private Graphics2D compositeGraphics; @@ -3103,7 +3111,7 @@ public class CommandLineArgumentParser { if (Thread.currentThread().isInterrupted()) { return; - } + } System.out.println("OK"); @@ -3169,16 +3177,56 @@ public class CommandLineArgumentParser { System.err.println("CharacterId should be integer"); badArguments("replace"); } - if (!swf.getCharacters().containsKey(characterId)) { + + SoundStreamHeadTypeTag soundStreamHead = null; + CharacterTag characterTag = null; + if (characterId == 0) { + //replacing soundstreamhead on main timeline + } else if (swf.getCharacters().containsKey(characterId)) { + characterTag = swf.getCharacter(characterId); + } else { System.err.println("CharacterId does not exist"); System.exit(1); } - CharacterTag characterTag = swf.getCharacter(characterId); String repFile = args.pop(); + byte[] data = Helper.readFile(repFile); String ext = Path.getExtension(repFile); - if (characterTag instanceof DefineBinaryDataTag) { + + int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; + if (".mp3".equals(ext)) { + soundFormat = SoundFormat.FORMAT_MP3; + } + + if ((characterTag == null || (characterTag instanceof DefineSpriteTag)) && (".wav".equals(ext) || ".mp3".equals(ext))) { + ReadOnlyTagList tags = (characterTag == null) ? swf.getTags() : ((DefineSpriteTag) characterTag).getTags(); + for (Tag t : tags) { + if (t instanceof SoundStreamHeadTypeTag) { + soundStreamHead = (SoundStreamHeadTypeTag) t; + break; + } + } + if (soundStreamHead == null) { + System.err.println((characterTag == null ? "Main timeline " : "DefineSprite(" + characterId + ")") + " does not contain any SoundStreamHead"); + System.exit(1); + } + boolean ok = false; + try { + ok = new SoundImporter().importSoundStream(soundStreamHead, new ByteArrayInputStream(data), soundFormat); + } catch (UnsupportedSamplingRateException usre) { + List supportedRatesStr = new ArrayList<>(); + for (int i : usre.getSupportedRates()) { + supportedRatesStr.add("" + i); + } + System.err.println("Import FAILED. Input file has unsupported sampling rate (" + usre.getSoundRate() + "). Supported rates for this sound format: " + String.join(", ", supportedRatesStr) + "."); + System.exit(2); + } + if (!ok) { + System.err.println("Import FAILED. Maybe unsuppoted media type? Only MP3 and uncompressed WAV are available."); + System.exit(1); + } + } else if (characterTag instanceof DefineBinaryDataTag) { DefineBinaryDataTag defineBinaryData = (DefineBinaryDataTag) characterTag; new BinaryDataImporter().importData(defineBinaryData, data); } else if (characterTag instanceof ImageTag) { @@ -3218,12 +3266,7 @@ public class CommandLineArgumentParser { } }).importText(textTag, new String(data, Utf8Helper.charset)); } else if (characterTag instanceof SoundTag) { - SoundTag st = (SoundTag) characterTag; - int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN; - if (repFile.toLowerCase(Locale.ENGLISH).endsWith(".mp3")) { - soundFormat = SoundFormat.FORMAT_MP3; - } - + SoundTag st = (SoundTag) characterTag; boolean ok = false; SoundImporter soundImporter = new SoundImporter(); try { @@ -3233,7 +3276,7 @@ public class CommandLineArgumentParser { for (int i : usre.getSupportedRates()) { supportedRatesStr.add("" + i); } - System.err.println("Import FAILED. Input file has unsupported sampling rate ("+usre.getSoundRate()+"). Supported rates for this sound format: "+String.join(", ", supportedRatesStr)+"."); + System.err.println("Import FAILED. Input file has unsupported sampling rate (" + usre.getSoundRate() + "). Supported rates for this sound format: " + String.join(", ", supportedRatesStr) + "."); System.exit(2); } catch (SoundImportException sie) { ok = false; @@ -3243,11 +3286,11 @@ public class CommandLineArgumentParser { System.exit(1); } } else if (characterTag instanceof DefineVideoStreamTag) { - DefineVideoStreamTag movie = (DefineVideoStreamTag)characterTag; + DefineVideoStreamTag movie = (DefineVideoStreamTag) characterTag; try { - new MovieImporter().importMovie(movie, data); + new MovieImporter().importMovie(movie, data); } catch (IOException iex) { - System.err.println("Import FAILED: "+iex.getMessage()); + System.err.println("Import FAILED: " + iex.getMessage()); System.exit(1); } } else { @@ -3317,7 +3360,7 @@ public class CommandLineArgumentParser { try { try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { swf.saveTo(fos); - } + } } catch (IOException e) { System.err.println("I/O error during writing"); System.exit(2); @@ -3824,7 +3867,7 @@ public class CommandLineArgumentParser { } ShapeImporter shapeImporter = new ShapeImporter(); int shapeCount = shapeImporter.bulkImport(shapesDir, swf, noFill, true); - + System.out.println("Writing outfile"); try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { swf.saveTo(fos); @@ -3835,7 +3878,7 @@ public class CommandLineArgumentParser { System.exit(2); } } - + private static void parseImportMovies(Stack args, String charset) { if (args.size() < 3) { badArguments("importmovies"); @@ -3860,7 +3903,7 @@ public class CommandLineArgumentParser { System.exit(1); } MovieImporter movieImporter = new MovieImporter(); - int movieCount = movieImporter.bulkImport(moviesDir, swf, true); + int movieCount = movieImporter.bulkImport(moviesDir, swf, true); System.out.println("Writing outfile"); try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { swf.saveTo(fos); @@ -3872,6 +3915,42 @@ public class CommandLineArgumentParser { } } + private static void parseImportSounds(Stack args, String charset) { + if (args.size() < 3) { + badArguments("importsounds"); + } + + 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 soundsDir = new File(Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME)); + if (soundsDir.exists()) { + System.out.println("Using the directory: " + soundsDir.getAbsolutePath()); + } else { + soundsDir = new File(selFile); + } + if (!soundsDir.exists()) { + System.err.println("Sounds directory does not exist: " + soundsDir.getAbsolutePath()); + System.exit(1); + } + SoundImporter soundImporter = new SoundImporter(); + int soundCount = soundImporter.bulkImport(soundsDir, swf, true); + System.out.println("Writing outfile"); + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { + swf.saveTo(fos); + } + System.out.println("" + soundCount + " sounds successfully imported"); + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during writing"); + System.exit(2); + } + } + private static void parseImportImages(Stack args, String charset) { if (args.size() < 3) { badArguments("importimages"); @@ -3896,7 +3975,7 @@ public class CommandLineArgumentParser { System.exit(1); } ImageImporter imageImporter = new ImageImporter(); - int imageCount = imageImporter.bulkImport(imagesDir, swf, true); + int imageCount = imageImporter.bulkImport(imagesDir, swf, true); System.out.println("Writing outfile"); try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(outFile))) { swf.saveTo(fos); @@ -4296,7 +4375,7 @@ public class CommandLineArgumentParser { } if (!found) { System.exit(1); - } + } } private static String doubleToString(double d) { @@ -4383,7 +4462,7 @@ public class CommandLineArgumentParser { } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); System.exit(1); - } + } } private static void parseDumpAS2(Stack args, String charset) { @@ -4483,7 +4562,7 @@ public class CommandLineArgumentParser { System.exit(3); } - System.out.println("Finished"); + System.out.println("Finished"); } private static void parseDumpAS3(Stack args, String charset) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index eae205afb..b72d9e96b 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -383,6 +383,16 @@ public abstract class MainFrameMenu implements MenuBuilder { mainFrame.getPanel().importMovie((SWF) openable); } + protected void importSoundsActionPerformed(ActionEvent evt) { + if (Main.isWorking()) { + return; + } + if (mainFrame.getPanel().checkEdited()) { + return; + } + mainFrame.getPanel().importSound((SWF) openable); + } + protected void importSymbolClassActionPerformed(ActionEvent evt) { if (Main.isWorking()) { return; @@ -1129,6 +1139,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addMenuItem("/file/import/importOther/importShapes", translate("menu.file.import.shape"), "importshape32", this::importShapesActionPerformed, PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/file/import/importOther/importShapesNoFill", translate("menu.file.import.shapeNoFill"), "importshape32", this::importShapesNoFillActionPerformed, PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/file/import/importOther/importMovies", translate("menu.file.import.movie"), "importmovie32", this::importMoviesActionPerformed, PRIORITY_MEDIUM, null, true, null, false); + addMenuItem("/file/import/importOther/importSounds", translate("menu.file.import.sound"), "importsound32", this::importSoundsActionPerformed, PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/file/import/importOther/importSymbolClass", translate("menu.file.import.symbolClass"), "importsymbolclass32", this::importSymbolClassActionPerformed, PRIORITY_MEDIUM, null, true, null, false); finishMenu("/file/import/importOther"); finishMenu("/file/import"); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index f9c1f0242..411d93544 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -3129,6 +3129,66 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se }.execute(); } } + + public void importSound(final SWF swf) { + ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importSounds2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportSoundInfo); + 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) { + + previewPanel.clear(); + + String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); + File soundsDir = new File(Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME)); + if (!soundsDir.exists()) { + soundsDir = new File(selFile); + } + final File fSoundsDir = soundsDir; + SoundImporter soundImporter = new SoundImporter(); + + final long timeBefore = System.currentTimeMillis(); + new CancellableWorker() { + + private int count = 0; + + @Override + public Void doInBackground() throws Exception { + try { + count = soundImporter.bulkImport(fSoundsDir, 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.sound.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); JFileChooser chooser = new JFileChooser(); diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importsound16.png b/src/com/jpexs/decompiler/flash/gui/graphics/importsound16.png new file mode 100644 index 000000000..4f2b6d23a Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importsound16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importsound32.png b/src/com/jpexs/decompiler/flash/gui/graphics/importsound32.png new file mode 100644 index 000000000..301afdea6 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importsound32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index d9043dbda..39234ef58 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -662,3 +662,6 @@ config.description.warningRenameIdentifiers = Show warning when turning on auto config.name.showImportMovieInfo = Show information before importing movies config.description.showImportMovieInfo = Displays some info about how importing movies works after clicking Import movies in the menu. + +config.name.showImportSoundInfo = Show information before importing sounds +config.description.showImportSoundInfo = Displays some info about how importing sounds works after clicking Import sounds in the menu. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 92741a336..43cef3066 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -652,3 +652,6 @@ config.description.warningRenameIdentifiers = Zobrazovat varov\u00e1n\u00ed b\u0 config.name.showImportMovieInfo = Zobrazit informaci p\u0159ed importem vide\u00ed config.description.showImportMovieInfo = Zobraz\u00ed n\u011bjak\u00e9 informace o tom jak import vide\u00ed funguje po kliku na import vide\u00ed v menu. + +config.name.showImportSoundInfo = Zobrazit informaci p\u0159ed importem zvuk\u016f +config.description.showImportSoundInfo = Zobraz\u00ed n\u011bjak\u00e9 informace o tom jak import zvuk\u016f funguje po kliku na import zvuk\u016f v menu. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index c1c51048a..c92268376 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1099,3 +1099,12 @@ message.info.importMovies2 = During importing movies, you need to select a FOLDE The best way to get the structure right is to export images in current SWF file first. import.movie.result = %count% movies imported. + +menu.file.import.sound = Import sounds + +message.info.importSounds2 = During importing sounds, you need to select a FOLDER.\r\n \ + Filenames inside the folder must match existing sounds in current selected SWF.\r\n \ + If there exist "sounds" folder inside, it is selected instead.\r\n \ + The best way to get the structure right is to export sounds in current SWF file first. + +import.sound.result = %count% sounds imported. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 0ae033f28..7c6c35b58 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1083,4 +1083,13 @@ message.info.importMovies2 = B\u011bhem importu vide\u00ed mus\u00edte vybrat SL 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. \ No newline at end of file +import.movie.result = %count% vide\u00ed importov\u00e1no. + +menu.file.import.sound = Importovat zvuky + +message.info.importSounds2 = B\u011bhem importu zvuk\u016f mus\u00edte vybrat SLO\u017dKU.\r\n \ + N\u00e1zvy soubor\u016f uvnit\u0159 mus\u00ed souhlasit s existuj\u00edc\u00edmi zvuky v pr\u00e1v\u011b vybran\u00e9m SWF.\r\n \ + Pokud je uvnit\u0159 slo\u017eka "sounds", 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 zvuky v aktu\u00e1ln\u00edm SWF souboru. + +import.sound.result = %count% zvuk\u016f importov\u00e1no. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index f3e35c753..ebccd43e4 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -173,6 +173,8 @@ public class TagTreeContextMenu extends JPopupMenu { private JMenuItem importMoviesMenuItem; + private JMenuItem importSoundsMenuItem; + private JMenuItem importSymbolClassMenuItem; private JMenuItem closeMenuItem; @@ -417,6 +419,11 @@ public class TagTreeContextMenu extends JPopupMenu { importMoviesMenuItem.addActionListener(this::importMoviesActionPerformed); importMoviesMenuItem.setIcon(View.getIcon("importmovie16")); add(importMoviesMenuItem); + + importSoundsMenuItem = new JMenuItem(mainPanel.translate("menu.file.import.sound")); + importSoundsMenuItem.addActionListener(this::importSoundsActionPerformed); + importSoundsMenuItem.setIcon(View.getIcon("importsound16")); + add(importSoundsMenuItem); importSymbolClassMenuItem = new JMenuItem(mainPanel.translate("menu.file.import.symbolClass")); importSymbolClassMenuItem.addActionListener(this::importSymbolClassActionPerformed); @@ -900,6 +907,7 @@ public class TagTreeContextMenu extends JPopupMenu { importShapesMenuItem.setVisible(false); importShapesNoFillMenuItem.setVisible(false); importMoviesMenuItem.setVisible(false); + importSoundsMenuItem.setVisible(false); importScriptsMenuItem.setVisible(false); importSymbolClassMenuItem.setVisible(false); importTextsMenuItem.setVisible(false); @@ -1119,6 +1127,7 @@ public class TagTreeContextMenu extends JPopupMenu { importShapesMenuItem.setVisible(true); importShapesNoFillMenuItem.setVisible(true); importMoviesMenuItem.setVisible(true); + importSoundsMenuItem.setVisible(true); importScriptsMenuItem.setVisible(true); importSymbolClassMenuItem.setVisible(true); importTextsMenuItem.setVisible(true); @@ -3271,6 +3280,11 @@ public class TagTreeContextMenu extends JPopupMenu { SWF swf = (SWF) getCurrentItem().getOpenable(); mainPanel.importMovie(swf); } + + public void importSoundsActionPerformed(ActionEvent evt) { + SWF swf = (SWF) getCurrentItem().getOpenable(); + mainPanel.importSound(swf); + } public void importSymbolClassActionPerformed(ActionEvent evt) { SWF swf = (SWF) getCurrentItem().getOpenable();