Skip to content
This repository was archived by the owner on Jul 16, 2022. It is now read-only.
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
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ Very simple dictionary search application supporting;
- EPWING ebz compression (.ebz)
- LingvoDSL (.dsl)
- LingvoDSL dz compression (.dsl.dz)
- MDict(*1) (.mdx)
- MDict (.mdx, .mdd)
- StarDict (.ifo .dict)
- StarDict (.dict.dz)
- PDIC/Unicode (PDIC format v6.00, 6.10) (.DIC)

(*1) MDict support is _Experimental_ status that supports text only

![Application image](https://raw.githubusercontent.com/eb4j/ebviewer/main/docs/img/screen_image.png)

## Install
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ dependencies {
implementation("com.github.takawitter:trie4j:0.9.8")

// for mdict
implementation("io.github.eb4j:mdict4j:0.1.4")
implementation("io.github.eb4j:mdict4j:0.2.0")
implementation("org.jsoup:jsoup:1.14.3")

// for video replay
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public void loadDictionaries(final File dictionaryDirectory) {
for (File f : listFiles) {
try {
loadDictionary(f);
} catch (Exception ignore) {
} catch (Exception e) {
LOG.warn("get exception when loading", e);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/io/github/eb4j/ebview/dictionary/MDict.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.github.eb4j.ebview.dictionary;

import io.github.eb4j.ebview.data.IDictionary;
import io.github.eb4j.ebview.dictionary.mdict.MDX;
import io.github.eb4j.ebview.dictionary.mdict.MDictDictionaryImpl;
import io.github.eb4j.mdict.MDException;

import java.io.File;
Expand All @@ -19,7 +19,7 @@ public class MDict implements IDictionaryFactory {
* @return Whether or not the file is supported
*/
@Override
public boolean isSupportedFile(File file) {
public boolean isSupportedFile(final File file) {
return file.getPath().endsWith(".MDX") || file.getPath().endsWith(".mdx");
}

Expand All @@ -30,9 +30,9 @@ public boolean isSupportedFile(File file) {
* @return An IDictionary file that can read articles from the file
*/
@Override
public Set<IDictionary> loadDict(File file) throws MDException, IOException {
public Set<IDictionary> loadDict(final File file) throws MDException, IOException {
Set<IDictionary> result = new HashSet<>();
result.add(new MDX(file));
result.add(new MDictDictionaryImpl(file));
return result;
}
}
83 changes: 0 additions & 83 deletions src/main/java/io/github/eb4j/ebview/dictionary/mdict/MDX.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package io.github.eb4j.ebview.dictionary.mdict;

import io.github.eb4j.ebview.data.DictionaryEntry;
import io.github.eb4j.ebview.data.IDictionary;
import io.github.eb4j.ebview.utils.ImageUtils;
import io.github.eb4j.mdict.MDException;
import io.github.eb4j.mdict.MDictDictionary;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.safety.Safelist;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class MDictDictionaryImpl implements IDictionary {

private final MDictDictionary mdictionary;
private final MDictDictionary mData;

public MDictDictionaryImpl(final File mdxFile) throws MDException, IOException {
String mdxPath = mdxFile.getPath();
mdictionary = MDictDictionary.loadDicitonary(mdxPath);
if (mdictionary.getMdxVersion().equals("2.0")) {
mData = MDictDictionary.loadDictionaryData(mdxPath);
} else {
mData = null;
}
}

@Override
public String getDictionaryName() {
return mdictionary.getTitle();
}

/**
* Read article's text.
*
* @param word The word to look up in the dictionary
* @return List of entries. May be empty, but cannot be null.
*/
@Override
public List<DictionaryEntry> readArticles(final String word) throws Exception {
List<DictionaryEntry> result = new ArrayList<>();
for (Map.Entry<String, Object> entry: mdictionary.getEntries(word)) {
addEntry(result, entry);
}
return result;
}

/**
* Read article's text. Matching is predictive, so e.g. supplying "term"
* will return articles for "term", "terminology", "termite", etc. The
* default implementation simply calls {@link #readArticles(String)} for
* backwards compatibility.
*
* @param word The word to look up in the dictionary
* @return List of entries. May be empty, but cannot be null.
*/
@Override
public List<DictionaryEntry> readArticlesPredictive(final String word) throws Exception {
List<DictionaryEntry> result = new ArrayList<>();
for (Map.Entry<String, Object> entry: mdictionary.getEntriesPredictive(word)) {
addEntry(result, entry);
}
return result;
}

private void addEntry(final List<DictionaryEntry> result, final Map.Entry<String, Object> entry)
throws MDException {
if (entry.getValue() instanceof Long) {
result.add(new DictionaryEntry(entry.getKey(),
retrieveDataAndUpdateLink(cleaHtmlArticle(mdictionary.getText((Long) entry.getValue()))),
getDictionaryName()));
} else {
Long[] values = (Long[]) entry.getValue();
for (int i = 0; i < values.length; i++) {
result.add(new DictionaryEntry(entry.getKey(),
retrieveDataAndUpdateLink(cleaHtmlArticle(mdictionary.getText(values[i]))),
getDictionaryName()));
}
}
}

private String cleaHtmlArticle(final String mdictHtmlText) {
Safelist whitelist = new Safelist();
whitelist.addTags("b", "br");
whitelist.addAttributes("font", "color", "face");
whitelist.addAttributes("img", "src");
whitelist.addAttributes("a", "href");
return Jsoup.clean(mdictHtmlText, whitelist);
}

private String retrieveDataAndUpdateLink(final String mdictHtmlText) {
Document document = Jsoup.parse(mdictHtmlText);
// Support embeded image
try {
Elements elements = document.select("img[src]");
for (Element element: elements) {
String linkUrl = element.attr("src");
if (linkUrl.startsWith("file://pic/")) {
String targetKey = linkUrl.substring(6);
byte[] rawData = getRawData(targetKey);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("data:image/png;base64,");
stringBuffer.append(ImageUtils.convertImage2Base64("png", rawData));
element.attr("src", stringBuffer.toString());
}
}
} catch (MDException | IOException e) {
e.printStackTrace();
}
// Support sound
try {
Elements elements = document.select("a[href]");
for (Element element: elements) {
String linkUrl = element.attr("href");
if (linkUrl.startsWith("sound://audio/")) {
String targetKey = linkUrl.substring(7);
byte[] rawData = getRawData(targetKey);
File tmpAudioFile = File.createTempFile("ebviewer", ".mp3");
tmpAudioFile.deleteOnExit();
try (FileOutputStream outputStream = new FileOutputStream(tmpAudioFile)) {
outputStream.write(rawData);
}
element.attr("href", "file://" + tmpAudioFile.toPath());
}
}
} catch (IOException | MDException e) {
e.printStackTrace();
}
return document.outerHtml();
}

private byte[] getRawData(final String targetKey) throws MDException {
byte[] result = null;
for (Map.Entry<String, Object> entry: mData.getEntries(targetKey)) {
if (entry.getKey().equals(targetKey)) {
Object value = entry.getValue();
if (value instanceof Long) {
result = mData.getData((Long) value);
break;
}
}
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.eb4j.ebview.gui;

import io.github.eb4j.ebview.gui.dialogs.MoviePlay;
import uk.co.caprica.vlcj.player.component.AudioPlayerComponent;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
Expand All @@ -17,6 +18,8 @@
public class LinkActionListener implements HyperlinkListener {

private static final String[] MOVIE_EXTS = {".mpg", ".MPG", ".ogv", ".mp4", ".mov"};
private static final String[] SOUND_EXTS = {".wav", ".WAV"};
private static final String[] MUSIC_EXTS = {".mp3", ".MP3"};

private static boolean hasExt(final String path, final String[] extrn) {
return Arrays.stream(extrn).anyMatch(entry -> path.endsWith(entry));
Expand Down Expand Up @@ -55,11 +58,14 @@ public void hyperlinkUpdate(final HyperlinkEvent hyperlinkEvent) {
if (url.getProtocol().equals("file")) {
try {
String path = url.getPath();
if (path.endsWith(".wav") || path.endsWith(".WAV")) {
if (hasExt(path, SOUND_EXTS)) {
playSound(new File(url.toURI()));
} else if (hasExt(path, MOVIE_EXTS)) {
MoviePlay player = new MoviePlay(354, 280);
player.play(path);
} else if (hasExt(path, MUSIC_EXTS)) {
AudioPlayerComponent audioPlayerComponent = new AudioPlayerComponent();
audioPlayerComponent.mediaPlayer().media().play(path);
}
} catch (URISyntaxException e) {
e.printStackTrace();
Expand Down