/*
* Copyright (C) 2013 Chen Hui <calmer91@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package master.flame.danmaku.danmaku.parser.android;
import android.graphics.Color;
import android.text.TextUtils;
import master.flame.danmaku.danmaku.model.AlphaValue;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.Duration;
import master.flame.danmaku.danmaku.model.IDisplayer;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
import master.flame.danmaku.danmaku.parser.DanmakuFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import java.io.IOException;
import java.util.Locale;
public class BiliDanmukuParser extends BaseDanmakuParser {
static {
System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
}
private float mDispScaleX;
private float mDispScaleY;
@Override
public Danmakus parse() {
if (mDataSource != null) {
AndroidFileSource source = (AndroidFileSource) mDataSource;
try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
XmlContentHandler contentHandler = new XmlContentHandler();
xmlReader.setContentHandler(contentHandler);
xmlReader.parse(new InputSource(source.data()));
return contentHandler.getResult();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public class XmlContentHandler extends DefaultHandler {
private static final String TRUE_STRING = "true";
public Danmakus result = null;
public BaseDanmaku item = null;
public boolean completed = false;
public int index = 0;
public Danmakus getResult() {
return result;
}
@Override
public void startDocument() throws SAXException {
result = new Danmakus();
}
@Override
public void endDocument() throws SAXException {
completed = true;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
String tagName = localName.length() != 0 ? localName : qName;
tagName = tagName.toLowerCase(Locale.getDefault()).trim();
if (tagName.equals("d")) {
// <d p="23.826000213623,1,25,16777215,1422201084,0,057075e9,757076900">我从未见过如此厚颜无耻之猴</d>
// 0:时间(弹幕出现时间)
// 1:类型(1从左至右滚动弹幕|6从右至左滚动弹幕|5顶端固定弹幕|4底端固定弹幕|7高级弹幕|8脚本弹幕)
// 2:字号
// 3:颜色
// 4:时间戳 ?
// 5:弹幕池id
// 6:用户hash
// 7:弹幕id
String pValue = attributes.getValue("p");
// parse p value to danmaku
String[] values = pValue.split(",");
if (values.length > 0) {
long time = (long) (Float.parseFloat(values[0]) * 1000); // 出现时间
int type = Integer.parseInt(values[1]); // 弹幕类型
float textSize = Float.parseFloat(values[2]); // 字体大小
int color = Integer.parseInt(values[3]) | 0xFF000000; // 颜色
// int poolType = Integer.parseInt(values[5]); // 弹幕池类型(忽略
item = DanmakuFactory.createDanmaku(type, mDisp);
if (item != null) {
item.time = time;
item.textSize = textSize * (mDispDensity - 0.6f);
item.textColor = color;
item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK;
}
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (item != null) {
if (item.duration != null) {
String tagName = localName.length() != 0 ? localName : qName;
if (tagName.equalsIgnoreCase("d")) {
item.setTimer(mTimer);
result.addItem(item);
}
}
item = null;
}
}
@Override
public void characters(char[] ch, int start, int length) {
if (item != null) {
DanmakuFactory.fillText(item, decodeXmlString(new String(ch, start, length)));
item.index = index++;
// initial specail danmaku data
String text = item.text.trim();
if (item.getType() == BaseDanmaku.TYPE_SPECIAL && text.startsWith("[")
&& text.endsWith("]")) {
//text = text.substring(1, text.length() - 1);
String[] textArr = null;//text.split(",", -1);
try {
JSONArray jsonArray = new JSONArray(text);
textArr = new String[jsonArray.length()];
for(int i=0;i<textArr.length;i++){
textArr[i] = jsonArray.getString(i);
}
} catch (JSONException e) {
e.printStackTrace();
}
if (textArr == null || textArr.length < 5) {
item = null;
return;
}
item.text = textArr[4];
float beginX = Float.parseFloat(textArr[0]);
float beginY = Float.parseFloat(textArr[1]);
float endX = beginX;
float endY = beginY;
String[] alphaArr = textArr[2].split("-");
int beginAlpha = (int) (AlphaValue.MAX * Float.parseFloat(alphaArr[0]));
int endAlpha = beginAlpha;
if (alphaArr.length > 1) {
endAlpha = (int) (AlphaValue.MAX * Float.parseFloat(alphaArr[1]));
}
long alphaDuraion = (long) (Float.parseFloat(textArr[3]) * 1000);
long translationDuration = alphaDuraion;
long translationStartDelay = 0;
float rotateY = 0, rotateZ = 0;
if (textArr.length >= 7) {
rotateZ = Float.parseFloat(textArr[5]);
rotateY = Float.parseFloat(textArr[6]);
}
if (textArr.length >= 11) {
endX = Float.parseFloat(textArr[7]);
endY = Float.parseFloat(textArr[8]);
if(!"".equals(textArr[9])){
translationDuration = Integer.parseInt(textArr[9]);
}
if(!"".equals(textArr[10])){
translationStartDelay = (long) (Float.parseFloat(textArr[10]));
}
}
item.duration = new Duration(alphaDuraion);
item.rotationZ = rotateZ;
item.rotationY = rotateY;
DanmakuFactory.fillTranslationData(item, beginX,
beginY, endX, endY, translationDuration, translationStartDelay, mDispScaleX, mDispScaleY);
DanmakuFactory.fillAlphaData(item, beginAlpha, endAlpha, alphaDuraion);
if (textArr.length >= 12) {
// 是否有描边
if (!TextUtils.isEmpty(textArr[11]) && TRUE_STRING.equals(textArr[11])) {
item.textShadowColor = Color.TRANSPARENT;
}
}
if (textArr.length >= 13) {
//TODO 字体 textArr[12]
}
if (textArr.length >= 14) {
//TODO 是否有加速
}
if (textArr.length >= 15) {
// 路径数据
if (!"".equals(textArr[14])) {
String motionPathString = textArr[14].substring(1);
String[] pointStrArray = motionPathString.split("L");
if (pointStrArray != null && pointStrArray.length > 0) {
float[][] points = new float[pointStrArray.length][2];
for (int i = 0; i < pointStrArray.length; i++) {
String[] pointArray = pointStrArray[i].split(",");
points[i][0] = Float.parseFloat(pointArray[0]);
points[i][1] = Float.parseFloat(pointArray[1]);
}
DanmakuFactory.fillLinePathData(item, points, mDispScaleX,
mDispScaleY);
}
}
}
}
}
}
private String decodeXmlString(String title) {
if (title.contains("&")) {
title = title.replace("&", "&");
}
if (title.contains(""")) {
title = title.replace(""", "\"");
}
if (title.contains(">")) {
title = title.replace(">", ">");
}
if (title.contains("<")) {
title = title.replace("<", "<");
}
return title;
}
}
@Override
public BaseDanmakuParser setDisplayer(IDisplayer disp) {
super.setDisplayer(disp);
mDispScaleX = mDispWidth / DanmakuFactory.BILI_PLAYER_WIDTH;
mDispScaleY = mDispHeight / DanmakuFactory.BILI_PLAYER_HEIGHT;
return this;
}
}