Import bookmarks and identities from the TeamSpeak 3 client
The official client keeps what a myTeamSpeak account synchronises as protobuf Item_Data blobs in the ProtobufItems table of settings.db. Decode them, adopt them on first run when we have no identity yet, and offer a re-import from Manage Bookmarks and Identities. The settings.db reader moves from contacts to a new teamspeak package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,9 @@ package com.ts3client.ui;
|
||||
import com.ts3client.config.Bookmark;
|
||||
import com.ts3client.config.Bookmarks;
|
||||
import com.ts3client.config.IdentityStore;
|
||||
import com.ts3client.config.Settings;
|
||||
import com.ts3client.teamspeak.TeamSpeakImporter;
|
||||
import com.ts3client.teamspeak.TeamSpeakSettingsDb;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
@@ -26,6 +29,7 @@ import java.awt.Frame;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -36,6 +40,8 @@ import java.util.function.Consumer;
|
||||
public final class BookmarksDialog extends JDialog {
|
||||
|
||||
private final Bookmarks bookmarks;
|
||||
private final IdentityStore identities;
|
||||
private final Settings settings;
|
||||
private final Consumer<Bookmark> onConnect;
|
||||
private final Runnable onChanged;
|
||||
private final DefaultListModel<Bookmark> listModel = new DefaultListModel<>();
|
||||
@@ -56,10 +62,12 @@ public final class BookmarksDialog extends JDialog {
|
||||
/** Bookmark the form currently shows, so edits can be flushed back into it. */
|
||||
private Bookmark editing;
|
||||
|
||||
public BookmarksDialog(Frame owner, Bookmarks bookmarks, IdentityStore identities,
|
||||
public BookmarksDialog(Frame owner, Bookmarks bookmarks, IdentityStore identities, Settings settings,
|
||||
Consumer<Bookmark> onConnect, Runnable onChanged) {
|
||||
super(owner, "Manage Bookmarks", true);
|
||||
this.bookmarks = bookmarks;
|
||||
this.identities = identities;
|
||||
this.settings = settings;
|
||||
this.onConnect = onConnect;
|
||||
this.onChanged = onChanged;
|
||||
this.identity = new IdentityChooser(identities, true, "");
|
||||
@@ -151,17 +159,23 @@ public final class BookmarksDialog extends JDialog {
|
||||
buttons.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8));
|
||||
addButton(buttons, "Add", this::addBookmark);
|
||||
addButton(buttons, "Remove", this::removeSelected);
|
||||
if (TeamSpeakSettingsDb.locate() != null) {
|
||||
addButton(buttons, "Import from TeamSpeak 3…", this::importFromTeamSpeak)
|
||||
.setToolTipText("Add the bookmarks of the TeamSpeak 3 client installed on this computer, "
|
||||
+ "along with the identities they connect with");
|
||||
}
|
||||
buttons.add(Box.createHorizontalGlue());
|
||||
addButton(buttons, "Connect", this::connectSelected);
|
||||
addButton(buttons, "Close", this::closeDialog);
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private void addButton(JPanel panel, String text, Runnable action) {
|
||||
private JButton addButton(JPanel panel, String text, Runnable action) {
|
||||
JButton b = new JButton(text);
|
||||
b.addActionListener(e -> action.run());
|
||||
panel.add(b);
|
||||
panel.add(Box.createHorizontalStrut(4));
|
||||
return b;
|
||||
}
|
||||
|
||||
// ---- Form <-> model ----
|
||||
@@ -228,6 +242,26 @@ public final class BookmarksDialog extends JDialog {
|
||||
persist();
|
||||
}
|
||||
|
||||
private void importFromTeamSpeak() {
|
||||
File db = TeamSpeakSettingsDb.locate();
|
||||
if (db == null) return;
|
||||
commit();
|
||||
try {
|
||||
TeamSpeakImporter.Result result = new TeamSpeakImporter(identities, bookmarks, settings).importBookmarks(db);
|
||||
identity.reload();
|
||||
reload();
|
||||
if (result.bookmarksAdded() > 0) list.setSelectedIndex(listModel.size() - result.bookmarksAdded());
|
||||
persist();
|
||||
JOptionPane.showMessageDialog(this, result.bookmarks() + " bookmark(s) read from " + db
|
||||
+ "\n" + result.bookmarksAdded() + " new, " + result.bookmarksKnown() + " already present; "
|
||||
+ result.identitiesAdded() + " identit" + (result.identitiesAdded() == 1 ? "y" : "ies") + " imported.",
|
||||
"Import from TeamSpeak 3", JOptionPane.INFORMATION_MESSAGE);
|
||||
} catch (Exception e) {
|
||||
JOptionPane.showMessageDialog(this, "Could not read " + db + ":\n" + e.getMessage(),
|
||||
"Import from TeamSpeak 3", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private void connectSelected() {
|
||||
commit();
|
||||
Bookmark b = list.getSelectedValue();
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.ts3client.contacts.Contact;
|
||||
import com.ts3client.contacts.ContactStore;
|
||||
import com.ts3client.contacts.ContactType;
|
||||
import com.ts3client.contacts.NicknameDisplay;
|
||||
import com.ts3client.contacts.TeamSpeakSettingsDb;
|
||||
import com.ts3client.teamspeak.TeamSpeakSettingsDb;
|
||||
import com.ts3client.text.TsLink;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.ts3client.config.Bookmarks;
|
||||
import com.ts3client.config.IdentityEntry;
|
||||
import com.ts3client.config.IdentityStore;
|
||||
import com.ts3client.config.Settings;
|
||||
import com.ts3client.teamspeak.TeamSpeakImporter;
|
||||
import com.ts3client.teamspeak.TeamSpeakSettingsDb;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
@@ -79,6 +81,9 @@ public final class IdentitiesDialog extends JDialog {
|
||||
buttons.setBorder(BorderFactory.createEmptyBorder(8, 0, 8, 8));
|
||||
addButton(buttons, "New…", this::newIdentity);
|
||||
addButton(buttons, "Import…", this::importIdentity);
|
||||
if (TeamSpeakSettingsDb.locate() != null) {
|
||||
addButton(buttons, "Import from TeamSpeak 3…", this::importFromTeamSpeak);
|
||||
}
|
||||
addButton(buttons, "Export…", this::exportSelected);
|
||||
addButton(buttons, "Rename…", this::renameSelected);
|
||||
addButton(buttons, "Set as default", this::setSelectedDefault);
|
||||
@@ -209,6 +214,21 @@ public final class IdentitiesDialog extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private void importFromTeamSpeak() {
|
||||
File db = TeamSpeakSettingsDb.locate();
|
||||
if (db == null) return;
|
||||
try {
|
||||
TeamSpeakImporter.Result result = new TeamSpeakImporter(identities, bookmarks, settings).importIdentities(db);
|
||||
reload();
|
||||
JOptionPane.showMessageDialog(this, result.identities() + " identit" + (result.identities() == 1 ? "y" : "ies")
|
||||
+ " read from " + db + "\n" + result.identitiesAdded() + " new, "
|
||||
+ result.identitiesKnown() + " already present.",
|
||||
"Import from TeamSpeak 3", JOptionPane.INFORMATION_MESSAGE);
|
||||
} catch (Exception e) {
|
||||
error("Could not read " + db, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void exportSelected() {
|
||||
IdentityEntry e = list.getSelectedValue();
|
||||
if (e == null) return;
|
||||
|
||||
@@ -23,9 +23,7 @@ final class IdentityChooser extends JComboBox<Object> {
|
||||
IdentityChooser(IdentityStore identities, boolean allowDefault, String selectedId) {
|
||||
this.identities = identities;
|
||||
this.allowDefault = allowDefault;
|
||||
if (allowDefault) addItem(USE_DEFAULT);
|
||||
for (IdentityEntry e : identities.all()) addItem(e);
|
||||
|
||||
reload();
|
||||
setSelectedIdentityId(selectedId);
|
||||
|
||||
setRenderer(new DefaultListCellRenderer() {
|
||||
@@ -40,6 +38,15 @@ final class IdentityChooser extends JComboBox<Object> {
|
||||
});
|
||||
}
|
||||
|
||||
/** Re-reads the store's identities, keeping the selection where it still exists. */
|
||||
void reload() {
|
||||
String selected = getSelectedIdentityId();
|
||||
removeAllItems();
|
||||
if (allowDefault) addItem(USE_DEFAULT);
|
||||
for (IdentityEntry e : identities.all()) addItem(e);
|
||||
setSelectedIdentityId(selected);
|
||||
}
|
||||
|
||||
/** Selected identity id, or an empty string when the default is to be used. */
|
||||
String getSelectedIdentityId() {
|
||||
Object v = getSelectedItem();
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.ts3client.config.Bookmark;
|
||||
import com.ts3client.config.Bookmarks;
|
||||
import com.ts3client.config.IdentityStore;
|
||||
import com.ts3client.config.Settings;
|
||||
import com.ts3client.teamspeak.TeamSpeakImporter;
|
||||
import com.ts3client.contacts.ContactStore;
|
||||
import com.ts3client.net.ChannelNode;
|
||||
import com.ts3client.sound.SoundNotifier;
|
||||
@@ -85,6 +86,7 @@ public final class MainFrame extends JFrame implements ServerTabPane.Listener {
|
||||
super("TS3J — TeamSpeak 3 Java Client");
|
||||
this.settings = settings;
|
||||
this.identities = IdentityStore.load(settings);
|
||||
new TeamSpeakImporter(identities, bookmarks, settings).seedIfFresh();
|
||||
this.sounds = new SoundNotifier(settings);
|
||||
this.soundPlayer = audio.createSoundPlayer(settings);
|
||||
this.sounds.setPlayer(soundPlayer);
|
||||
@@ -235,7 +237,7 @@ public final class MainFrame extends JFrame implements ServerTabPane.Listener {
|
||||
|
||||
@Override
|
||||
public void onManageBookmarks() {
|
||||
new BookmarksDialog(MainFrame.this, bookmarks, identities,
|
||||
new BookmarksDialog(MainFrame.this, bookmarks, identities, settings,
|
||||
MainFrame.this::connectToBookmark, menuBar::rebuildBookmarks).setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user