/*
* Copyright (c) 2008, 2009, 2010 Denis Tulskiy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
*/
package com.tulskiy.musique.gui;
import com.tulskiy.musique.audio.player.Player;
import com.tulskiy.musique.audio.player.PlayerEvent;
import com.tulskiy.musique.audio.player.PlayerListener;
import com.tulskiy.musique.playlist.Track;
import com.tulskiy.musique.system.Application;
import com.tulskiy.musique.system.configuration.Configuration;
import com.tulskiy.musique.util.Util;
import javax.swing.*;
import javax.swing.plaf.basic.BasicTextPaneUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Scanner;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Author: Denis Tulskiy
* Date: Jul 20, 2010
*/
public class LyricsPanel extends JPanel {
private static Application app = Application.getInstance();
private static Configuration config = app.getConfiguration();
private Logger logger = Logger.getLogger(getClass().getName());
private final File lyricsDir = new File(app.CONFIG_HOME, "lyrics");
private final Timer timer;
private Search search;
public LyricsPanel() {
setLayout(new BorderLayout());
final JTextPane textPane = new TextPane();
final Player player = app.getPlayer();
timer = new Timer(200, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Track track = player.getTrack();
try {
textPane.setText("");
StyledDocument doc = textPane.getStyledDocument();
doc.insertString(doc.getLength(), track.getTrackData().getArtist() + "\n", textPane.getStyle("artist"));
doc.insertString(doc.getLength(), track.getTrackData().getTitle() + "\n\n", textPane.getStyle("title"));
} catch (BadLocationException e1) {
e1.printStackTrace();
}
if (search != null && !search.isDone())
search.cancel(true);
search = new Search(textPane, track);
search.execute();
timer.stop();
}
});
player.addListener(new PlayerListener() {
@Override
public void onEvent(PlayerEvent e) {
switch (e.getEventCode()) {
case FILE_OPENED:
timer.restart();
}
}
});
add(new JScrollPane(textPane), BorderLayout.CENTER);
}
class TextPane extends JTextPane {
public final Style artistStyle;
public final Style titleStyle;
public TextPane() {
super();
Style style = getStyle("default");
StyleConstants.setAlignment(style, StyleConstants.ALIGN_CENTER);
artistStyle = addStyle("artist", null);
titleStyle = addStyle("title", null);
setEditable(false);
setOpaque(true);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
updateUI();
}
@Override
public void updateUI() {
super.updateUI();
Color oldSelectionColor = getSelectionColor();
setUI(new BasicTextPaneUI());
Color background = config.getColor("gui.color.background", null);
if (background != null) {
setBackground(background);
} else {
setBackground(Color.white);
}
Color text = config.getColor("gui.color.text", null);
if (text != null)
setForeground(text);
else
setForeground(null);
Color selection = config.getColor("gui.color.selection", null);
if (selection != null) {
setSelectionColor(selection);
} else {
setSelectionColor(oldSelectionColor);
}
setSelectedTextColor(Util.getContrastColor(getSelectionColor()));
Font font = config.getFont("gui.font.default", null);
if (font != null) {
setFont(font);
if (artistStyle != null)
StyleConstants.setFontSize(artistStyle, font.getSize() + 4);
if (titleStyle != null)
StyleConstants.setFontSize(titleStyle, font.getSize() + 2);
} else if (getParent() != null) {
setFont(getParent().getFont());
}
}
}
class Search extends SwingWorker<String, Object> {
private final JTextPane textPane;
private Track track;
Search(JTextPane textPane, Track track) {
this.textPane = textPane;
this.track = track;
}
@Override
protected String doInBackground() throws Exception {
String artist = track.getTrackData().getArtist();
String title = track.getTrackData().getTitle();
if (track != null && !Util.isEmpty(artist) && !Util.isEmpty(title)) {
try {
Scanner fi;
File file = new File(lyricsDir, artist + " - " + title + ".txt");
StringBuilder result = new StringBuilder();
if (file.exists()) {
logger.fine("Loading lyrics from file: " + file.getName());
fi = new Scanner(file);
while (fi.hasNextLine())
result.append(fi.nextLine()).append("\n");
} else if (config.getBoolean("lyrics.searchOnline", true)) {
searchLyrics(artist, title, result);
String text = result.toString().trim();
if (text.length() > 0) {
//noinspection ResultOfMethodCallIgnored
lyricsDir.mkdirs();
PrintWriter writer = new PrintWriter(file);
writer.print(text);
writer.close();
}
}
return result.toString();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void done() {
try {
String result = get();
if (result != null) {
textPane.setText("");
StyledDocument doc = textPane.getStyledDocument();
doc.insertString(doc.getLength(), track.getTrackData().getArtist() + "\n", textPane.getStyle("artist"));
doc.insertString(doc.getLength(), track.getTrackData().getTitle() + "\n\n", textPane.getStyle("title"));
doc.insertString(doc.getLength(), Util.htmlToString(result), null);
textPane.setCaretPosition(0);
}
} catch (Exception ignored) {
}
}
// private void searchLyrics(String artist, String title, StringBuilder sb) throws IOException {
// Scanner fi;
// URL search = new URL(searchURL +
// "artist=" + URLEncoder.encode(artist, "utf8") +
// "&title=" + URLEncoder.encode(title, "utf8"));
// logger.fine("Searching for lyrics at url: " + URLDecoder.decode(search.toString(), "utf8"));
// URLConnection conn = search.openConnection();
// fi = new Scanner(conn.getInputStream(), "utf-8");
// while (fi.hasNextLine()) {
// String s = fi.nextLine();
// if (s.startsWith("<div id=\"lyrics\">")) {
// while (!(s = fi.nextLine()).equals("</div>")) {
// sb.append(Util.htmlToString(s)).append("\n");
// }
// }
// }
// }
private void searchLyrics(String artist, String title, StringBuilder sb) throws IOException {
try {
// String search = "http://lyrics.wikia.com/Special:Search?search=";
// search += URLEncoder.encode(artist, "utf-8");
// search += "+";
// search += URLEncoder.encode(title, "utf-8");
//
// URL searchURL = new URL(search);
// Scanner scan = new Scanner(searchURL.openStream());
// StringBuilder content = new StringBuilder();
// while (scan.hasNextLine())
// content.append(scan.nextLine());
//
// Matcher matcher = Pattern.compile("http://lyrics.wikia.com/wiki/[^\"]*").matcher(content);
// if (!matcher.find()) {
// return;
// }
String search = "http://lyrics.wikia.com/";
artist = Util.capitalize(artist, "_");
title = Util.capitalize(title, "_");
search += URLEncoder.encode(artist, "utf-8");
search += ":";
search += URLEncoder.encode(title, "utf-8");
URL url = new URL(search);
InputStream is = url.openStream();
Scanner fi = new Scanner(is);
while (fi.hasNextLine()) {
String s = fi.nextLine();
if (s.startsWith("<div class='lyricbox'")) {
int index = s.lastIndexOf("</div>");
if (index > 0 && s.length() > 6)
s = s.substring(index);
s = s.replaceAll("<br />", "\n");
s = s.replaceAll("(<!--)|(<.*?>)", "");
Matcher m = Pattern.compile("(\\d+);").matcher(s);
m.reset();
StringBuffer buffer = new StringBuffer();
while (m.find()) {
String group = m.group(1);
char ch = (char) Integer.valueOf(group).shortValue();
m.appendReplacement(buffer, String.valueOf(ch));
}
m.appendTail(buffer);
sb.append(buffer);
}
}
fi.close();
} catch (IOException e) {
// e.printStackTrace();
}
}
}
}