Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@

public class MusicBrainzJSONReader {
private final JsonObject json;
private final String na = "n/a";

/*
* Creates a MusicBrainzJSONReader from a JSON string.
* @param json The JSON string.
* @throws IllegalArgumentException If the JSON is invalid.
*/
public MusicBrainzJSONReader(String json) throws IllegalArgumentException {
JsonObject tempJsonObject;
try {
Expand All @@ -30,33 +34,51 @@ public MusicBrainzJSONReader(String json) throws IllegalArgumentException {
this.json = tempJsonObject;
}

/**
* Parses a JSON array and creates a new array of the same type as the provided array.
*
* @param <T> The type of the array elements.
* @param key The JSON key to look for (e.g., "releases", "cdstubs").
* @param processor A functional interface to process each {@link JsonObject} in the JSON array
* and convert it into an object of type {@code T}.
* @param array An example array of type {@code T[]} used to determine the type of the output array.
* @return A new array of type {@code T[]} containing the processed elements from the JSON array.
* If the key does not exist or the JSON array is empty, an empty array is returned.
*/
@SuppressWarnings("unchecked")
private <T> T[] parseJsonArray(String key, JsonArrayProcessor<T> processor, T[] array) {
// Make sure the key exists in the JSON object
if (!json.has(key)) {
// Return an empty array if the JSON object does not have the key
array = (T[]) Array.newInstance(array.getClass().getComponentType(), 0);
return array;
}
// Make a JSON array using the provided key
JsonArray jsonArray = json.getAsJsonArray(key);
array = (T[]) Array.newInstance(array.getClass().getComponentType(), jsonArray.size());

// Process each JSON object in the array
for (int i = 0; i < jsonArray.size(); i++) {
JsonObject jsonObject = jsonArray.get(i).getAsJsonObject();
array[i] = processor.process(jsonObject);
array[i] = processor.process(jsonObject); // Uses provided processor to process the JSON object
}
return array;
}

/*
/**
* Gets releases from the JSON.
* @return An array of the releases.
*/
public MusicBrainzRelease[] getReleases() {
return parseJsonArray("releases", jsonObject -> {
// Get the title, date, track count, and id from the JSON object
// If the value does not exist in JSON, n/a will be returned
String title = jsonHasAndIsNotNull(jsonObject, "title") ? jsonObject.get("title").getAsString() : null;
String date = jsonHasAndIsNotNull(jsonObject, "date") ? jsonObject.get("date").getAsString() : null;
int trackCount = jsonHasAndIsNotNull(jsonObject, "track-count") ? jsonObject.get("track-count").getAsInt() : -1;
String id = jsonHasAndIsNotNull(jsonObject, "id") ? jsonObject.get("id").getAsString() : null;

// Get all artists as a String[]
JsonArray artistsArray = jsonObject.getAsJsonArray("artist-credit");
String[] artists = new String[artistsArray.size()];
for (int j = 0; j < artistsArray.size(); j++) {
Expand All @@ -69,34 +91,49 @@ public MusicBrainzRelease[] getReleases() {
}, new MusicBrainzRelease[0]);
}

/**
* Gets CD stubs from the JSON.
* @return An array of the CD stubs.
*/
public MusicBrainzCDStub[] getCDStubs() {
return parseJsonArray("cdstubs", jsonObject -> {
// Read the title, track count, and id from the JSON object
// Also applies n/a should the value not exist in JSON
String title = jsonHasAndIsNotNull(jsonObject, "title") ? jsonObject.get("title").getAsString() : null;
String id = jsonHasAndIsNotNull(jsonObject, "id") ? jsonObject.get("id").getAsString() : null;
int trackCount = jsonHasAndIsNotNull(jsonObject, "count") ? jsonObject.get("count").getAsInt() : -1;
String artist = jsonHasAndIsNotNull(jsonObject, "artist") ? jsonObject.get("artist").getAsString() : null;

// Keep in mind that CDStubs only have one artist
return new MusicBrainzCDStub(id, title, new String[] {artist}, trackCount);
}, new MusicBrainzCDStub[0]);
}

/*
/**
* Creates a table model from an array of items.
* @param items The array of items. Usually a MusicBrainzRelease, MusicBrainzCDStub, etc.
* @param columnNames The names of the columns.
* @param extractor The extractor that extracts the data from the item.
*/
private DefaultTableModel createTableModel(Object[] items, String[] columnNames, DataExtractor extractor) {
// Make sure that the array is not null or empty
if (items == null || items.length == 0) {
// If so, return an empty table model with column names
return new DefaultTableModel(new String[0][0], columnNames);
}
String[][] data = new String[items.length][columnNames.length];
// Use the extractor provided to extract the data from the item
for (int i = 0; i < items.length; i++) {
data[i] = extractor.extractData(items[i]);
}
return new DefaultTableModel(data, columnNames);
}

/**
* Gets the releases as a table model.
* @param releaseArray The array of releases.
* @return The table model.
*/
public DefaultTableModel getReleasesAsTableModel(MusicBrainzRelease[] releaseArray) {
String[] columnNames = {"Release Name", "Artist", "Track Count", "Date", ""};
return createTableModel(releaseArray, columnNames, item -> {
Expand All @@ -111,6 +148,11 @@ public DefaultTableModel getReleasesAsTableModel(MusicBrainzRelease[] releaseArr
});
}

/**
* Gets the CD stubs as a table model.
* @param cdStubArray The array of CD stubs.
* @return The table model.
*/
public DefaultTableModel getCDStubsAsTableModel(MusicBrainzCDStub[] cdStubArray) {
String[] columnNames = {"Disc Name", "Artist", "Track Count", ""};
return createTableModel(cdStubArray, columnNames, item -> {
Expand All @@ -124,22 +166,40 @@ public DefaultTableModel getCDStubsAsTableModel(MusicBrainzCDStub[] cdStubArray)
});
}

/**
* Functional interface for extracting data from an item.
*/
@FunctionalInterface
private interface DataExtractor {
String[] extractData(Object item);
}

/**
* Functional interface for processing a JSON object.
* @param <T> The type of the object to be processed.
*/
@FunctionalInterface
private interface JsonArrayProcessor<T> {
T process(JsonObject jsonObject);
}

/**
* Checks if a JSON object has a member and is not null.
* @param jsonObject The JSON object.
* @param memberName The member name to check for.
* @return True if the member exists and is not null, false otherwise.
*/
private boolean jsonHasAndIsNotNull(JsonObject jsonObject, String memberName) {
return jsonObject.has(memberName) && !jsonObject.get(memberName).isJsonNull();
}

/**
* Gets a value or returns "n/a" if the value is null.
* @param value The value to check.
* @return The value or "n/a" if the value is null.
*/
private String getOrDefault(String value) {
return value != null ? value : na;
return value != null ? value : "n/a";
}

@Override
Expand Down
60 changes: 51 additions & 9 deletions src/main/java/com/CDPrintable/ProgramWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.Objects;

public class ProgramWindow {
private final UserAgent userAgent;
private JLabel fullUserAgentLabel = new JLabel();

/**
* Creates a new ProgramWindow and sets up the GUI.
*/
public ProgramWindow() {
userAgent = new UserAgent("CDPrintable/" + Constants.VERSION, "example@example.com");

Expand All @@ -47,6 +51,11 @@ public ProgramWindow() {
// Set the frame to be visible
frame.setVisible(true);
}

/**
* Gets a JPanel for the table panel. This is a helper method.
* @return A JPanel with the table panel.
*/
private JPanel tablePanel() {
JPanel panel = new JPanel(new BorderLayout());

Expand All @@ -60,6 +69,11 @@ private JPanel tablePanel() {

return panel;
}

/**
* Gets a JPanel for the search panel. This is a helper method.
* @return A JPanel with the search panel.
*/
private JPanel searchPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
Expand All @@ -79,32 +93,37 @@ private JPanel searchPanel() {
// CD Search Panel set up
JPanel cdSearchPanel = new JPanel();
cdSearchPanel.setBorder(BorderFactory.createTitledBorder("Search"));

JTextField searchField = new JTextField(15);

JComboBox<String> searchTypeComboBox = new JComboBox<>(new String[] {"CDStub", "Artist", "Release"});

// Search button and event listener setup
JButton searchButton = new JButton("Search");
searchButton.addActionListener(e -> {
searchButton.addActionListener(_ -> {
if (searchTypeComboBox.getSelectedItem() == null) {
return;
}
if (searchTypeComboBox.getSelectedItem().equals("CDStub")) {
searchTable.setModel(getCDStubModel());
MusicBrainzJSONReader reader = sendRequest("cdstub", searchField.getText());


// Get CDStubs and set the table model
MusicBrainzCDStub[] cdStubs = reader.getCDStubs();
searchTable.setModel(reader.getCDStubsAsTableModel(cdStubs));
} else if (searchTypeComboBox.getSelectedItem().equals("Artist")) {
searchTable.setModel(getArtistModel());
searchTable.setModel(getArtistModel()); // Default model
} else if (searchTypeComboBox.getSelectedItem().equals("Release")) {
searchTable.setModel(getReleaseModel());
MusicBrainzJSONReader reader = sendRequest("release", searchField.getText());

// Get Releases and set the table model
MusicBrainzRelease[] releases = reader.getReleases();
searchTable.setModel(reader.getReleasesAsTableModel(releases));
} else {
// how does this even happen
JOptionPane.showMessageDialog(panel, "Please select a search type.");
}
});

cdSearchPanel.setLayout(new FlowLayout());
cdSearchPanel.add(searchTypeComboBox);
cdSearchPanel.add(searchField);
Expand All @@ -116,6 +135,12 @@ private JPanel searchPanel() {
return panel;
}

/**
* Sends a request to the MusicBrainz API.
* @param queryType The query type to send. E.g. "cdstub", "release", etc.
* @param query The query to send.
* @return a MusicBrainzJSONReader object with the response JSON already in it.
*/
private MusicBrainzJSONReader sendRequest(String queryType, String query) {
MusicBrainzRequest request = new MusicBrainzRequest(queryType, query);
WebRequest webRequest = new WebRequest(request, userAgent);
Expand All @@ -128,31 +153,47 @@ private MusicBrainzJSONReader sendRequest(String queryType, String query) {
There was a fatal error when sending the request. Please try again or submit an issue on GitHub.
Here are some things to try:
• Check your internet connection.
• Remove any special characters from your query.""");
• Remove any special characters from your query.""", "CDPrintable Severe Error", JOptionPane.ERROR_MESSAGE);
}

MusicBrainzJSONReader reader = new MusicBrainzJSONReader(response);
return reader;
return new MusicBrainzJSONReader(Objects.requireNonNullElse(response, ""));

}

/**
* Gets a default table model for CDStubs.
* @return A DefaultTableModel with the correct columns.
*/
private DefaultTableModel getCDStubModel() {
String[] columnNames = {"Disc Name", "Artist", "Track Count", ""};
String[][] data = {{"", "", "", ""}};
return new javax.swing.table.DefaultTableModel(data, columnNames);
}

/**
* Gets a default table model for Artists.
* @return A DefaultTableModel with the correct columns.
*/
private DefaultTableModel getArtistModel() {
String[] columnNames = {"Artist Name", "Date Organised", ""};
String[][] data = {{"", "", ""}};
return new javax.swing.table.DefaultTableModel(data, columnNames);
}

/**
* Gets a default table model for Releases.
* @return A DefaultTableModel with the correct columns.
*/
private DefaultTableModel getReleaseModel() {
String[] columnNames = {"Release Name", "Artist", "Track Count", "Date", ""};
String[][] data = {{"", "", "", ""}};
return new javax.swing.table.DefaultTableModel(data, columnNames);
}

/**
* Gets a JPanel for settings. This is another helper method.
* @return A JPanel with the settings window.
*/
private JPanel settingsPanel() {
JPanel panel = new JPanel(new GridLayout(1, 2));
GridBagConstraints gbc = new GridBagConstraints();
Expand All @@ -163,6 +204,7 @@ private JPanel settingsPanel() {
JPanel userAgentPanel = new JPanel(new BorderLayout());
userAgentPanel.setBorder(BorderFactory.createTitledBorder("User Agent"));

// Setup user agent text fields, labels, and document listeners
JLabel userAgentLabel = new JLabel("User Agent:");
JTextField userAgentField = new JTextField(15);
userAgentField.setText(userAgent.getUserAgent());
Expand All @@ -181,11 +223,11 @@ public void removeUpdate(DocumentEvent e) {
public void changedUpdate(DocumentEvent e) {} // Not used
});

// Set up the user agent field with labels and document listener.
JLabel userAgentEmailLabel = new JLabel("User Agent Email:");
JTextField userAgentEmailField = new JTextField(15);
userAgentEmailField.setText(userAgent.getUserAgentEmail());
userAgentEmailField.getDocument().addDocumentListener(new DocumentListener() {

@Override
public void insertUpdate(DocumentEvent e) {
userAgent.setUserAgentEmail(userAgentEmailField.getText(), fullUserAgentLabel);
Expand Down
Loading