AcFunDanmakuParser與DanmakuFlameMaster自定義解析器
阿新 • • 發佈:2018-12-29
bilibili刪掉了DanmakuFlameMaster原始碼裡的AcFunDanmakuParser,之前官方(包括目前網上各種教程裡的AcFunDanmakuParser)也已經不適用,而官方給我們的BiliDanmukuParser不支援json,因此我重寫了一個支援json的AcFunDanmakuParser,支援的json格式為A站預設的json格式
[{"c":"0,16777215,1,25,196050,1364468342","m":"彈幕彈幕彈幕"},{"c":"3.619,16777215,1,25,196050,1364468347","m":"彈幕彈幕彈幕彈幕彈幕彈幕"}] 引數:{"c": "播放時間,顏色,模式,字號,uid,傳送時間", "m": "彈幕內容"} 其中uid和傳送時間可以自定義,由自己判斷是否需要改變彈幕樣式
import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.graphics.Color; import master.flame.danmaku.danmaku.model.BaseDanmaku; import master.flame.danmaku.danmaku.model.android.Danmakus; import master.flame.danmaku.danmaku.parser.BaseDanmakuParser; import master.flame.danmaku.danmaku.parser.android.JSONSource; public class AcFunDanmakuParser extends BaseDanmakuParser { @Override public Danmakus parse() { if (mDataSource != null && mDataSource instanceof JSONSource) { JSONSource jsonSource = (JSONSource) mDataSource; return doParse(jsonSource.data()); } return new Danmakus(); } /** * @param danmakuListData 彈幕資料 * 傳入的陣列內包含普通彈幕,會員彈幕,鎖定彈幕。 * @return 轉換後的Danmakus */ private Danmakus doParse(JSONArray danmakuListData) { Danmakus danmakus = new Danmakus(); if (danmakuListData == null || danmakuListData.length() == 0) { return danmakus; } danmakus = _parse(danmakuListData, danmakus); return danmakus; } private Danmakus _parse(JSONArray jsonArray, Danmakus danmakus) { if (danmakus == null) { danmakus = new Danmakus(); } if (jsonArray == null || jsonArray.length() == 0) { return danmakus; } for (int i = 0; i < jsonArray.length(); i++) { try { JSONObject obj = jsonArray.getJSONObject(i); String c = obj.getString("c"); String[] values = c.split(","); if (values.length > 0) { int type = Integer.parseInt(values[2]); // 彈幕型別 if (type == 7) // FIXME : hard code // TODO : parse advance danmaku json continue; long time = (long) (Float.parseFloat(values[0]) * 1000); // 出現時間 int color = Integer.parseInt(values[1]) | 0xFF000000; // 顏色 float textSize = Float.parseFloat(values[3]); // 字型大小 BaseDanmaku item = mContext.mDanmakuFactory.createDanmaku(type, mContext); if (item != null) { item.setTime(time); item.textSize = textSize * (mDispDensity - 0.6f); item.textColor = color; item.textShadowColor = color <= Color.BLACK ? Color.WHITE : Color.BLACK; item.index = i; item.flags = mContext.mGlobalFlagValues; item.setTimer(mTimer); item.text = obj.getString("m"); danmakus.addItem(item); } } } catch (JSONException e) { } catch (NumberFormatException e) { } } return danmakus; } }
使用的時候可以這樣用(參考官方的demo):
private BaseDanmakuParser createParser(InputStream stream) { if (stream == null) { return new BaseDanmakuParser() { @Override protected Danmakus parse() { return new Danmakus(); } }; } ILoader loader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_ACFUN); try { loader.load(stream); } catch (IllegalDataException e) { e.printStackTrace(); } BaseDanmakuParser parser = new AcFunDanmakuParser(); IDataSource<?> dataSource = loader.getDataSource(); parser.load(dataSource); return parser; }
其實也不難理解,從JSONArray裡解析出彈幕的內容,顏色,時間,顏色等屬性,然後填充進BaseDanmaku裡面,再把BaseDanmaku新增進Danmakus裡,最後把Danmakus返回回去就行,JSONArray相信大家都懂得,知道這點之後,其實我們也沒必要嚴格遵循官方的格式了。
甚至我們可以重寫BaseDanmakuParser、ILoader、IDataSource這三個類,來實現我們自己的Parser,這裡我寫一個JsonParser供大家參考
import android.graphics.Color;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.videoplayertest.bean.DanmakuBean;
import java.io.Reader;
import java.util.List;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.parser.BaseDanmakuParser;
public class JsonParser extends BaseDanmakuParser {
@Override
protected Danmakus parse() {
Danmakus danmakus = new Danmakus();
if(mDataSource != null && mDataSource instanceof JsonSource){
JsonSource source = (JsonSource) this.mDataSource;
return doParse(source.data());
}
return danmakus;
}
private Danmakus doParse(Reader json) {
Danmakus danmakus = new Danmakus();
//在這裡解析json,填充進BaseDanmaku裡
Gson gson = new Gson();
List<DanmakuBean> beans = gson.fromJson(json, new TypeToken<List<DanmakuBean>>() {
}.getType());
if(beans != null && beans.size()>0){
int size = beans.size();
for (int i = 0 ; i < size ; i++){
DanmakuBean bean = beans.get(i);
int type = bean.getType();
if (type == 7)
continue;
BaseDanmaku item = mContext.mDanmakuFactory.createDanmaku(type, mContext);
item.flags = mContext.mGlobalFlagValues;
item.textSize = bean.getTextSize() * (mDispDensity - 0.6f);
item.textColor = bean.getTextColor();
item.textShadowColor = bean.getTextColor() <= Color.BLACK ? Color.WHITE : Color.BLACK;
item.setTime((long) (bean.getTime()*1000));
item.setTimer(mTimer);
item.text = bean.getText();
item.index = i;
danmakus.addItem(item);
}
}
return danmakus;
}
}
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import master.flame.danmaku.danmaku.loader.ILoader;
import master.flame.danmaku.danmaku.loader.IllegalDataException;
public class JsonLoader implements ILoader {
private static volatile JsonLoader instance;
private JsonSource source;
public static ILoader instance() {
if(instance == null){
synchronized (JsonLoader.class){
if(instance == null)
instance = new JsonLoader();
}
}
return instance;
}
@Override
public JsonSource getDataSource() {
return source;
}
@Override
public void load(String uri) throws IllegalDataException {
load(new StringReader(uri));
}
@Override
public void load(InputStream in) throws IllegalDataException {
InputStreamReader reader = new InputStreamReader(in);
load(reader);
}
public void load(Reader reader) throws IllegalDataException {
source = new JsonSource(reader);
}
}
import java.io.Reader;
import master.flame.danmaku.danmaku.parser.IDataSource;
/**
* 考慮到彈幕資料可能較多,為避免String溢位,這裡建議使用reader代替String
* Gson可以直接使用reader,而且Reader方便在String和InputStream之間轉換
*/
public class JsonSource implements IDataSource<Reader> {
Reader reader;
public JsonSource(Reader reader) {
this.reader = reader;
}
@Override
public Reader data() {
return reader;
}
@Override
public void release() {
reader = null;
}
}
使用的時候把InputStream 傳進JsonLoader即可
private BaseDanmakuParser createParser(InputStream stream) {
ILoader loader = JsonLoader.instance();
try {
loader.load(stream);
} catch (IllegalDataException e) {
e.printStackTrace();
}
JsonParser parser = new JsonParser();
IDataSource<?> dataSource = loader.getDataSource();
parser.load(dataSource);
return parser;
}
我自定義的json格式為:
[{"millis":0,"text":"彈幕111111","textColor":-65536,"textSize":20.0,"time":0.6,"type":1,"userId":0},{"millis":0,"text":"彈幕111111","textColor":-16776961,"textSize":20.0,"time":0.6,"type":1,"userId":0}]
DanmakuBean為該json的實體類