How to get JavaFX media metadata without a listener
So I've been looking for this week and reading. Although each question is very similar, it seems that no one asks the same question as me (try reverse engineering. Other solutions are similar to what I want but fail)
Explains the caveman style: I'm trying to create lists using metadata
>I open multiple dialog boxes and select multiple MP3 > I put the file in an ArrayList < File > > I recycle the enhanced for circular file and extract metadata using media variables > metadata information (such as "artist") is an example I want to save in ArrayList
The problem is that the listener works only after the enhancement loop ends. ArrayList < string > has an object without anything
Here is an example:
ArrayList<String> al; String path; public void open(){ files=chooser.showOpenMultipleDialog(new Stage()); for( File f:files){ path=f.getPath(); Media media = new Media("file:/"+path.replace("\\","/").replace(" ","%20")); al= new ArrayList<String>(); media.getMetadata().addListener(new Mapchangelistener<String,Object>() { public void onChanged(Change<? extends String,? extends Object> change) { if (change.wasAdded()) { if (change.getKey().equals("artist")) { al.add((String) change.getValueAdded()); } } } }); }//close for loop //then i want to see the size of al like this system.out.println(al.size()); //then it returns 1 no matter how much file i selected //when i system out "al" i get an empty string
Solution
Another way to read media source metadata by adding listeners is to extract the information in the media player setOnReady(); This is an example part of the Java controller class
Public class uicontroller implements initializable{
@FXML private Label label; @FXML private ListView<String> lv; @FXML private AnchorPane root; @FXML private Button button; private ObservableList<String> ol= FXCollections.observableArrayList(); private List<File> selectedFiles; private final Object obj= new Object(); @Override public void initialize(URL url,ResourceBundle rb) { assert button != null : "fx:id=\"button\" was not injected: check your FXML file 'ui.fxml'."; assert label != null : "fx:id=\"label\" was not injected: check your FXML file 'ui.fxml'."; assert lv != null : "fx:id=\"lv\" was not injected: check your FXML file 'ui.fxml'."; assert root != null : "fx:id=\"root\" was not injected: check your FXML file 'ui.fxml'."; // initialize your logic here: all @FXML variables will have been injected lv.setItems(ol); } @FXML private void open(ActionEvent event) { FileChooser.ExtensionFilter extention= new FileChooser.ExtensionFilter("Music Files","*.mp3","*.m4a","*.aif","*.wav","*.m3u","*.m3u8"); FileChooser fc= new FileChooser(); fc.setInitialDirectory(new File(System.getenv("userprofile"))); fc.setTitle("Select File(s)"); fc.getExtensionFilters().add(extention); selectedFiles =fc.showOpenMultipleDialog(root.getScene().getWindow()); if(selectedFiles != null &&!selectedFiles.isEmpty()){ listFiles(); } } /** * Convert each fie selected to its URI */ private void listFiles(){ try { for (File file : selectedFiles) { readMetaData(file.toURI().toString()); synchronized(obj){ obj.wait(100); } } } catch (InterruptedException ex) { } System.gc(); } /** * Read a Media source Metadata * Note: Sometimes the was unable to extract the Metadata especially when * i have selected large number of files reasons i don't kNown why * @param mediaURI Media file URI */ private void readMetaData(String mediaURI){ final MediaPlayer mp= new MediaPlayer(new Media(mediaURI)); mp.setOnReady(new Runnable() { @Override public void run() { String artistName=(String) mp.getMedia().getMetadata().get("artist"); ol.add(artistName); synchronized(obj){//this is required since mp.setOnReady creates a new thread and our loopp in the main thread obj.notify();// the loop has to wait unitl we are able to get the media Metadata thats why use .wait() and .notify() to synce the two threads(main thread and MediaPlayer thread) } } }); }
}
Some of the changes made are to use observablelist to store artist names in metadata
You will find this in the code
synchronized(obj){ obj.wait(100); }
I did this because of mediaplayer Setonready () creates a new thread and loops in the main application thread The loop must wait a while to create another thread, and we can extract metadata, and Setonready() has a
synchronized(obj){ obj.notify; }
Wakes up the main thread so that the loop can move to the next item
I admit that this may not be the best solution to this problem, but anyone who has a better way to read JavaFX media metadata from the file list is welcome. The complete NetBeans project can be found here https://docs.google.com/file/d/0BxDEmOcXqnCLSTFHbTVFcGIzT1E/edit?usp=sharing
Plus uses JavaFX to create a small mediaplayer application that uses metadata https://docs.google.com/file/d/0BxDEmOcXqnCLR1Z0VGN4ZlJkbUU/edit?usp=sharing