Context Action beaTlet
Many of the things we want to do with songs we only want to do with the currently selected songs. So what's the code for manipulating those songs?
Easy. It's pretty much a regular BaseAction that fetches the currently selected AudioSong ids, looks up the actual song objects and then does something with them. To demonstrate how it's done, we're going to show a simple action that resets the ReplayGain values for the selected songs:
from javax.swing import Action
from com.tagtraum.core.app import AbsoluteActionLocation
from com.tagtraum.core.app import ActionLocation
from com.tagtraum.beatunes.action import BaseAction
from com.tagtraum.beatunes.action import BeaTunesUIRegion
from com.tagtraum.beatunes.songtable import SongPropertyChangeListener
# Needed for Java array creation
from jarray import array
class ResetReplayGain(BaseAction):
def getId(self):
return "Jython.ResetReplayGain"
def init(self):
self.putValue(Action.NAME, "Reset ReplayGain")
# Install the action in both the Tools menu and the context
# menu of the main table.
def getActionLocations(self):
# Java array creation via array([], type)
return array([
AbsoluteActionLocation(BeaTunesUIRegion.TOOL_MENU, AbsoluteActionLocation.LAST),
AbsoluteActionLocation(BeaTunesUIRegion.SONG_CONTEXT_MENU, AbsoluteActionLocation.LAST)
], ActionLocation)
def actionPerformed(self, actionEvent):
# get ids for the selected songs
ids = self.getSelectedSongIds()
for id in ids:
# obtain the AudioSong object
# special cast to java.lang.Long necessary!!
song = self.getApplication().getMediaLibrary().getSong(id)
# register a SongPropertyChangeListener, so that
# any changes are displayed right away.
song.addPropertyChangeListener(
SongPropertyChangeListener(self.getApplication().getMainWindow().getSongTable().getTable(), id)
)
# do something with the object.
# don't forget that you are on the EDT!
# so whatever you do here, should be quick.
# if not, start a new thread for your work.
song.setAlbumReplayGain(None, False)
song.setTrackReplayGain(None, True)
import javax.swing.*
import java.awt.event.ActionEvent
import com.tagtraum.audiokern.*
import com.tagtraum.core.app.*
import com.tagtraum.beatunes.action.*
import com.tagtraum.beatunes.songtable.SongPropertyChangeListener
class ResetReplayGain extends BaseAction {
def String getId() {
"Groovy.ResetReplayGain"
}
def void init() {
putValue(Action.NAME, "Reset ReplayGain")
}
/**
* Install the action in both the Tools menu and the context
* menu of the main table.
*/
def ActionLocation[] getActionLocations() {
[new AbsoluteActionLocation(BeaTunesUIRegion.TOOL_MENU, AbsoluteActionLocation.LAST),
new AbsoluteActionLocation(BeaTunesUIRegion.SONG_CONTEXT_MENU, AbsoluteActionLocation.LAST)]
}
def void actionPerformed(ActionEvent actionEvent) {
// get ids for the selected songs
long[] ids = getSelectedSongIds()
for (long id : ids) {
// obtain the AudioSong object
AudioSong song = getApplication().getMediaLibrary().getSong(id)
// register a SongPropertyChangeListener, so that
// any changes are displayed right away.
song.addPropertyChangeListener(new SongPropertyChangeListener(getApplication().getMainWindow().getSongTable().getTable(), id))
// do something with the object.
// don't forget that you are on the EDT!
// so whatever you do here, should be quick.
// if not, start a new thread for your work.
song.setAlbumReplayGain(null, false)
song.setTrackReplayGain(null, true)
}
}
}
require 'java'
java_import javax.swing.Action
java_import com.tagtraum.core.app.ActionLocation
java_import com.tagtraum.core.app.AbsoluteActionLocation
java_import com.tagtraum.beatunes.action.BeaTunesUIRegion
java_import com.tagtraum.beatunes.action.BaseAction
java_import com.tagtraum.beatunes.songtable.SongPropertyChangeListener
class ResetReplayGain < BaseAction
def getId
"JRuby.ResetReplayGain"
end
def init()
putValue(Action.NAME, "Reset ReplayGain")
end
# Install the action in both the Tools menu and the context
# menu of the main table.
def getActionLocations()
# "to_java()" converts the Ruby array into a Java array of the given type
[
AbsoluteActionLocation.new(BeaTunesUIRegion::TOOL_MENU, AbsoluteActionLocation::LAST),
AbsoluteActionLocation.new(BeaTunesUIRegion::SONG_CONTEXT_MENU, AbsoluteActionLocation::LAST)
].to_java(ActionLocation)
end
def actionPerformed(actionEvent)
# get ids for the selected songs
ids = getSelectedSongIds()
for id in ids
# obtain the AudioSong object
# special cast to java.lang.Long necessary!!
song = getApplication().getMediaLibrary().getSong(id.to_java(java.lang.Long))
# register a SongPropertyChangeListener, so that
# any changes are displayed right away.
song.addPropertyChangeListener(
SongPropertyChangeListener.new(getApplication().getMainWindow().getSongTable().getTable(), id)
)
# do something with the object.
# don't forget that you are on the EDT!
# so whatever you do here, should be quick.
# if not, start a new thread for your work.
song.setAlbumReplayGain(nil, false)
song.setTrackReplayGain(nil, true)
end
end
end
/*
* These type vars basically act as imports for Java classes.
*/
var Action = Java.type("javax.swing.Action");
var ActionLocations = Java.type("com.tagtraum.core.app.ActionLocation[]");
var AbsoluteActionLocation = Java.type("com.tagtraum.core.app.AbsoluteActionLocation");
var BeaTunesUIRegion = Java.type("com.tagtraum.beatunes.action.BeaTunesUIRegion");
var BaseAction = Java.type("com.tagtraum.beatunes.action.BaseAction");
var SongPropertyChangeListener = Java.type("com.tagtraum.beatunes.songtable.SongPropertyChangeListener");
// BaseAction is an abstract class.
// This allows us to subclass it with "new".
// The resulting subclass instance is stored in the "beatlet" variable.
var beatlet = new BaseAction() {
/*
* Unique id.
*/
getId: function() {
return "Javascript.ResetReplayGain";
},
/*
* Is called by beaTunes as part of the lifecycle after instantiation.
* At this point all other plugins are instantiated and registered.
* We use this to set the menu item's (i.e. the action's) name.
*/
init: function() {
beatletSuper.putValue(Action.NAME, "Reset ReplayGain");
},
/*
* Define, where in the UI the Action should appear.
* You can define multiple locations in an array. Here, we
* request to be the last item in the Tool and the Context menu.
* Note, that we use the Nashorn extension "Java.to", to
* create a Java array.
*/
getActionLocations: function() {
return Java.to(
[
new AbsoluteActionLocation(BeaTunesUIRegion.TOOL_MENU, AbsoluteActionLocation.LAST),
new AbsoluteActionLocation(BeaTunesUIRegion.SONG_CONTEXT_MENU, AbsoluteActionLocation.LAST),
], ActionLocations
);
},
/*
* React to a click on the menu item.
*/
actionPerformed: function(actionEvent) {
// get ids for the selected songs (this is an array of type long)
var ids = beatletSuper.getSelectedSongIds()
for (var i=0; i<ids.length; i++) {
// obtain the AudioSong object
var song = beatletSuper.getApplication().getMediaLibrary().getSong(ids[i]);
// register a SongPropertyChangeListener, so that
// any changes are displayed right away.
song.addPropertyChangeListener(new SongPropertyChangeListener(beatletSuper.getApplication().getMainWindow().getSongTable().getTable(), ids[i]));
// do something with the object.
// don't forget that you are on the EDT!
// so whatever you do here, should be quick.
// if not, start a new thread for your work.
song.setAlbumReplayGain(null, false);
song.setTrackReplayGain(null, true);
}
}
}
// Find super class of beatlet, so that we can call methods on it
// in the "actionPerformed" function.
var beatletSuper = Java.super(beatlet);
// Put "beatlet" into the last line, so that it is returned
// to beaTunes when this script is eval'd.
beatlet;
Other beaTlet samples:
- Getting Started
- Library Batch Action
- Playlist Exporter
- Song Analysis Task
- beaTlet Plugin Descriptor
- Song Context View
- Song Property Analyzer
All sample beaTlets are also on
GitHub
.