Skip to content

Commit

Permalink
Working on support of tags from exportExt.pdb files
Browse files Browse the repository at this point in the history
  • Loading branch information
brunchboy committed Sep 1, 2024
1 parent 7c3cf9e commit bccbaae
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 6 deletions.
33 changes: 32 additions & 1 deletion src/main/java/org/deepsymmetry/cratedigger/DatabaseExt.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package org.deepsymmetry.cratedigger;

import org.apiguardian.api.API;
import org.deepsymmetry.cratedigger.pdb.RekordboxPdb;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.util.*;

/**
* <p>Parses rekordbox database {@code exportExt.pdb} files, providing access to the information they contain.</p>
Expand Down Expand Up @@ -38,9 +40,38 @@ public class DatabaseExt implements Closeable {
@API(status = API.Status.EXPERIMENTAL)
public DatabaseExt(File sourceFile) throws IOException {
databaseUtil = new DatabaseUtil(sourceFile, true);
// TODO: Gather and index the tag information.
final Map<Long, RekordboxPdb.TagRow> mutableTagIndex = new HashMap<>();
final SortedMap<String, SortedSet<Long>> mutableTagNameIndex = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

databaseUtil.indexRows(RekordboxPdb.PageTypeExt.TAGS, row -> {
// We found a tag; index it by its ID.
RekordboxPdb.TagRow tagRow = (RekordboxPdb.TagRow)row;
final long id = tagRow.id();
mutableTagIndex.put(id, tagRow);
// ALso index the tags by name.
final String title = Database.getText(tagRow.name());
databaseUtil.addToSecondaryIndex(mutableTagNameIndex, title, tagRow.id());
});
tagIndex = Collections.unmodifiableMap(mutableTagIndex);
logger.info("Indexed {} Tags.", tagIndex.size());
tagNameIndex = databaseUtil.freezeSecondaryIndex(mutableTagNameIndex);

// TODO: Gather and index the track tag information.
}

/**
* A map from tag ID to the actual tag object.
*/
@API(status = API.Status.EXPERIMENTAL)
public final Map<Long, RekordboxPdb.TagRow> tagIndex;

/**
* A sorted map from tag names to the IDs of tags with that name.
*/
@API(status = API.Status.EXPERIMENTAL)
public final SortedMap<String, SortedSet<Long>> tagNameIndex;


/**
* Close the file underlying the parsed database. This needs to be called if you want to be able
* to unmount the media on which that file resides, but once it is done, you can no longer access
Expand Down
62 changes: 57 additions & 5 deletions src/main/java/org/deepsymmetry/cratedigger/DatabaseUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,18 @@ interface RowHandler {
}

/**
* Parse and index all the rows found in a particular table. This method performs a scan of the
* specified table, passing all rows that are encountered to an interface that knows what to do
* with them.
* Parse and index all the rows found in a particular {@code export.pdb} table. This method performs a scan of the
* specified table, passing all rows that are encountered to an interface that knows what to do with them.
*
* @param type the type of table to be scanned and parsed
* @param type the type of table present in export.pdb files to be scanned and parsed
* @param handler the code that knows how to index that kind of row
*
* @throws IllegalStateException if there is more than (or less than) one table of that type in the file
*/
void indexRows(RekordboxPdb.PageType type, DatabaseUtil.RowHandler handler) {
if (isExportExt) {
throw new IllegalStateException("Calling indexRows() with a non-ext page type can never succeed for an exportExt.pdb file");
}
boolean done = false;
for (RekordboxPdb.Table table : pdb.tables()) {
if (table.type() == type) {
Expand All @@ -107,7 +109,57 @@ void indexRows(RekordboxPdb.PageType type, DatabaseUtil.RowHandler handler) {
for (RekordboxPdb.RowRef rowRef : rowGroup.rows()) {
if (rowRef.present()) {
// We found a row, pass it to the handler to be indexed appropriately.
handler.rowFound(isExportExt? rowRef.bodyExt() : rowRef.body());
handler.rowFound(rowRef.body());
}
}
}
}

// Was this the final page in the table? If so, stop, otherwise, move on to the next page.
if (currentRef.index() == lastIndex) {
moreLeft = false;
} else {
currentRef = page.nextPage();
}
} while (moreLeft);
done = true;
}
}

if (!done) throw new IllegalStateException("No table found of type " + type);
}

/**
* Parse and index all the rows found in a particular {@code exportExt.pdb} table. This method performs a scan of the
* specified table, passing all rows that are encountered to an interface that knows what to do with them.
*
* @param type the type of table present in exportExt.pdb files to be scanned and parsed
* @param handler the code that knows how to index that kind of row
*
* @throws IllegalStateException if there is more than (or less than) one table of that type in the file
*/
void indexRows(RekordboxPdb.PageTypeExt type, DatabaseUtil.RowHandler handler) {
if (!isExportExt) {
throw new IllegalStateException("Calling indexRows() with an ext page type can never succeed for an export.pdb file");
}
boolean done = false;
for (RekordboxPdb.Table table : pdb.tables()) {
if (table.typeExt() == type) {
if (done) throw new IllegalStateException("More than one table found with type " + type);
final long lastIndex = table.lastPage().index(); // This is how we know when to stop.
RekordboxPdb.PageRef currentRef = table.firstPage();
boolean moreLeft = true;
do {
// logger.info("Indexing page " + currentRef.index());
final RekordboxPdb.Page page = currentRef.body();

// Process only ordinary data pages.
if (page.isDataPage()) {
for (RekordboxPdb.RowGroup rowGroup : page.rowGroups()) {
for (RekordboxPdb.RowRef rowRef : rowGroup.rows()) {
if (rowRef.present()) {
// We found a row, pass it to the handler to be indexed appropriately.
handler.rowFound(rowRef.bodyExt());
}
}
}
Expand Down

0 comments on commit bccbaae

Please sign in to comment.