/**
*
*/
package com.dotcool.reader.dao;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.dotcool.R;
import com.dotcool.reader.AlternativeLanguageInfo;
import com.dotcool.reader.Constants;
import com.dotcool.reader.LNReaderApplication;
import com.dotcool.reader.UIHelper;
import com.dotcool.reader.callback.CallbackEventData;
import com.dotcool.reader.callback.ICallbackNotifier;
import com.dotcool.reader.helper.BakaReaderException;
import com.dotcool.reader.helper.DBHelper;
import com.dotcool.reader.helper.Util;
import com.dotcool.reader.helper.db.BookModelHelper;
import com.dotcool.reader.helper.db.BookmarkModelHelper;
import com.dotcool.reader.helper.db.ImageModelHelper;
import com.dotcool.reader.helper.db.NovelCollectionModelHelper;
import com.dotcool.reader.helper.db.NovelContentModelHelper;
import com.dotcool.reader.helper.db.PageModelHelper;
import com.dotcool.reader.helper.db.UpdateInfoModelHelper;
import com.dotcool.reader.model.BookModel;
import com.dotcool.reader.model.BookmarkModel;
import com.dotcool.reader.model.ImageModel;
import com.dotcool.reader.model.NovelCollectionModel;
import com.dotcool.reader.model.NovelContentModel;
import com.dotcool.reader.model.PageModel;
import com.dotcool.reader.model.UpdateInfoModel;
import com.dotcool.reader.parser.BakaTsukiParser;
import com.dotcool.reader.parser.BakaTsukiParserAlternative;
import com.dotcool.reader.parser.CommonParser;
import com.dotcool.reader.task.DownloadFileTask;
import com.dotcool.util.AppUtil;
/**
* @author Nandaka
*
*/
public class NovelsDao {
private static final String TAG = NovelsDao.class.toString();
private static DBHelper dbh;
private static Context context;
private static NovelsDao instance;
private static Object lock = new Object();
public static NovelsDao getInstance(Context applicationContext) {
synchronized (lock) {
if (instance == null) {
instance = new NovelsDao(applicationContext);
context = applicationContext;
}
}
return instance;
}
public static NovelsDao getInstance() {
synchronized (lock) {
if (instance == null) {
try {
instance = new NovelsDao(LNReaderApplication.getInstance().getApplicationContext());
} catch (Exception ex) {
Log.e(TAG, "Failed to get context for NovelsDao", ex);
// throw new BakaReaderException("NovelsDao is not Initialized!", BakaReaderException.NULL_NOVELDAO,
// ex);
throw new NullPointerException("NovelsDao is not Initialized!");
}
}
}
return instance;
}
private NovelsDao(Context context) {
if (dbh == null) {
dbh = new DBHelper(context);
}
}
public DBHelper getDBHelper() {
if (dbh == null) {
dbh = new DBHelper(context);
}
return dbh;
}
public void deleteDB() {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
try {
dbh.deletePagesDB(db);
} finally {
db.close();
}
}
}
public String copyDB(boolean makeBackup) throws IOException {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
String filePath;
try {
filePath = dbh.copyDB(db, context, makeBackup);
} finally {
db.close();
}
return filePath;
}
}
public ArrayList<PageModel> getNovels(ICallbackNotifier notifier, boolean alphOrder,String api) throws Exception {
ArrayList<PageModel> list = null;
PageModel page = null;
SQLiteDatabase db = null;
// check if main page exist
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
if(api.equals("/api/leixin/cat/1")){
page = PageModelHelper.getHistoryPage(db);
}else if(api.equals("/api/leixin/cat/3")){
page = PageModelHelper.getKehuanPage(db);
}else if(api.equals("/api/leixin/cat/7")){
page = PageModelHelper.getXuanhuanPage(db);
}else if(api.equals("/api/leixin/cat/10")){
page = PageModelHelper.getQitaPage(db);
}else if(api.equals("/api/book/update/11")){
page = PageModelHelper.getUpdatePage(db);
}else if(api.equals("/api/book/update/12")){
page = PageModelHelper.getMoodPage(db);
}else {
page = PageModelHelper.getMainPage(db);
}
} finally {
db.close();
}
}
if (page == null) {
Log.d(TAG, "No Main_Page data!");
list = getNovelsFromInternet(notifier,api);
} else {
// get from db
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
list = dbh.getAllNovels(db, alphOrder);// dbh.selectAllByColumn(db,
// DBHelper.COLUMN_TYPE,
// PageModel.TYPE_NOVEL);
} finally {
db.close();
}
}
Log.d(TAG, "Found: " + list.size());
}
return list;
}
public ArrayList<PageModel> getNovelsFromInternet(ICallbackNotifier notifier,String api) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new BakaReaderException("没有网络,请稍后...", BakaReaderException.NO_NETWORK_CONNECTIFITY);
if (notifier != null) {
notifier.onCallback(new CallbackEventData("正在加载列表请稍后..."));
}
// get last updated main page revision from internet
PageModel mainPage = new PageModel();
if(api.equals("/api/leixin/cat/1")){
mainPage.setPage("Category:history");
mainPage.setTitle(LNReaderApplication.getInstance().getResources().getString(R.string.str_xuanhuan));
}else if(api.equals("/api/leixin/cat/3")){
mainPage.setPage("Category:kehuan");
mainPage.setTitle(LNReaderApplication.getInstance().getResources().getString(R.string.str_xuanhuan));
}else if(api.equals("/api/leixin/cat/7")){
mainPage.setPage("Category:xuanhuan");
mainPage.setTitle(LNReaderApplication.getInstance().getResources().getString(R.string.str_xuanhuan));
}else if(api.equals("/api/leixin/cat/10")){
mainPage.setPage("Category:qita");
mainPage.setTitle(LNReaderApplication.getInstance().getResources().getString(R.string.str_xuanhuan));
}else if(api.equals("/api/book/update/11")){
mainPage.setPage("Category:update");
mainPage.setTitle(LNReaderApplication.getInstance().getResources().getString(R.string.light_novels));
}else if(api.equals("/api/book/mood/12")){
mainPage.setPage("Category:mood");
mainPage.setTitle(LNReaderApplication.getInstance().getResources().getString(R.string.originals));
}
mainPage.setLanguage(Constants.LANG_ENGLISH);
mainPage = getPageModel(mainPage, notifier);
mainPage.setType(PageModel.TYPE_OTHER);
mainPage.setParent("");
ArrayList<PageModel> list = null;
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
try {
// db.beginTransaction();
mainPage = PageModelHelper.insertOrUpdatePageModel(db, mainPage, false);
Log.d(TAG, "Updated Main_Page");
// now get the novel list
list = new ArrayList<PageModel>();
String url = UIHelper.getBaseUrl(LNReaderApplication.getInstance().getApplicationContext()) + api;
Log.d(TAG, "--"+url);
int retry = 0;
while (retry < getRetry()) {
try {
Response response = Jsoup.connect(url).timeout(getTimeout(retry)).execute();
//Document doc = response.parse();
String result =response.body();
//String result = AppUtil.getContent(url);
Log.d(TAG, "Found from internet: "+ result + " Novels");
list = BakaTsukiParser.ParseNovelList(result);
Log.d(TAG, "Found from internet: " + list.size() + " Novels");
// saved to db and get saved value
list = PageModelHelper.insertAllNovel(db, list);
// db.setTransactionSuccessful();
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Found: " + list.size() + " novels."));
}
break;
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Retrying: Main_Page (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "Retrying: Main_Page (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
} finally {
// db.endTransaction();
db.close();
}
}
return list;
}
public ArrayList<PageModel> getWatchedNovel() {
ArrayList<PageModel> watchedNovel = null;
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
try {
// watchedNovel = dbh.selectAllByColumn(db,
// DBHelper.COLUMN_IS_WATCHED + " = ? and ("
// + DBHelper.COLUMN_PARENT + " = ? or "
// + DBHelper.COLUMN_PARENT + " = ? )"
// , new String[] { "1", "Main_Page", "Category:Teasers" }
// , DBHelper.COLUMN_TITLE );
watchedNovel = dbh.getAllWatchedNovel(db, true);
} finally {
db.close();
}
}
return watchedNovel;
}
public ArrayList<PageModel> getTeaser(ICallbackNotifier notifier, boolean alphOrder) throws Exception {
SQLiteDatabase db = null;
PageModel page = null;
ArrayList<PageModel> list = null;
// check if main page exist
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
page = PageModelHelper.getTeaserPage(db);
} finally {
db.close();
}
}
if (page == null) {
return getTeaserFromInternet(notifier);
} else {
// get from db
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
list = dbh.getAllTeaser(db, alphOrder);
} finally {
db.close();
}
}
Log.d(TAG, "Found: " + list.size());
}
return list;
}
public ArrayList<PageModel> getTeaserFromInternet(ICallbackNotifier notifier) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new BakaReaderException("No Network Connectifity", BakaReaderException.NO_NETWORK_CONNECTIFITY);
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Downloading Teaser Novels list..."));
}
// parse Category:Teasers information
PageModel teaserPage = new PageModel();
teaserPage.setPage("Category:Teasers");
teaserPage.setLanguage(Constants.LANG_ENGLISH);
teaserPage.setTitle("Teasers");
teaserPage = getPageModel(teaserPage, notifier);
teaserPage.setType(PageModel.TYPE_OTHER);
// update page model
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
teaserPage = PageModelHelper.insertOrUpdatePageModel(db, teaserPage, true);
Log.d(TAG, "Updated Category:Teasers");
}
// get teaser list
ArrayList<PageModel> list = null;
String url = UIHelper.getBaseUrl(LNReaderApplication.getInstance().getApplicationContext()) + "/project/index.php?title=Category:Teasers";
int retry = 0;
while (retry < getRetry()) {
try {
Response response = Jsoup.connect(url).timeout(getTimeout(retry)).execute();
String doc = response.body();
list = BakaTsukiParser.ParseTeaserList(doc);
Log.d(TAG, "Found from internet: " + list.size() + " Teaser");
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Found: " + list.size() + " teaser."));
}
break;
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Retrying: Category:Teasers (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "Retrying: Category:Teasers (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
// save teaser list
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
for (PageModel pageModel : list) {
pageModel = PageModelHelper.insertOrUpdatePageModel(db, pageModel, true);
Log.d(TAG, "Updated teaser: " + pageModel.getPage());
}
}
return list;
}
// Originals, copied from teaser
public ArrayList<PageModel> getOriginal(ICallbackNotifier notifier, boolean alphOrder) throws Exception {
SQLiteDatabase db = null;
PageModel page = null;
ArrayList<PageModel> list = null;
// check if main page exist
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
page = PageModelHelper.getOriginalPage(db);
} finally {
db.close();
}
}
if (page == null) {
return getOriginalFromInternet(notifier);
} else {
// get from db
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
list = dbh.getAllOriginal(db, alphOrder);
} finally {
db.close();
}
}
Log.d(TAG, "Found: " + list.size());
}
return list;
}
public ArrayList<PageModel> getOriginalFromInternet(ICallbackNotifier notifier) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new Exception("No Network Connectifity");
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Downloading Original Novels list..."));
}
// parse Category:Teasers information
PageModel teaserPage = new PageModel();
teaserPage.setPage("Category:Original");
teaserPage.setLanguage(Constants.LANG_ENGLISH);
teaserPage.setTitle("Original Novels");
teaserPage = getPageModel(teaserPage, notifier);
teaserPage.setType(PageModel.TYPE_OTHER);
// update page model
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
teaserPage = PageModelHelper.insertOrUpdatePageModel(db, teaserPage, true);
Log.d(TAG, "Updated Category:Original");
}
// get teaser list
ArrayList<PageModel> list = null;
String url = UIHelper.getBaseUrl(LNReaderApplication.getInstance().getApplicationContext()) + "/project/index.php?title=Category:Original";
int retry = 0;
while (retry < getRetry()) {
try {
Response response = Jsoup.connect(url).timeout(getTimeout(retry)).execute();
String doc = response.body();
list = BakaTsukiParser.ParseOriginalList(doc);
Log.d(TAG, "Found from internet: " + list.size() + " Teaser");
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Found: " + list.size() + " original."));
}
break;
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Retrying: Category:Original (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "Retrying: Category:Original (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
// save original list
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
for (PageModel pageModel : list) {
pageModel = PageModelHelper.insertOrUpdatePageModel(db, pageModel, true);
Log.d(TAG, "Updated original: " + pageModel.getPage());
}
}
return list;
}
// Alternative Language, copied from Original
public ArrayList<PageModel> getAlternative(ICallbackNotifier notifier, boolean alphOrder, String language) throws Exception {
SQLiteDatabase db = null;
PageModel page = null;
ArrayList<PageModel> list = null;
// check if main page exist
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
page = PageModelHelper.getAlternativePage(db, language);
} finally {
db.close();
}
}
if (page == null) {
return getAlternativeFromInternet(notifier, language);
} else {
// get from db
synchronized (dbh) {
try {
db = dbh.getReadableDatabase();
list = dbh.getAllAlternative(db, alphOrder, language);
} finally {
db.close();
}
}
Log.d(TAG, "Found: " + list.size());
}
return list;
}
public ArrayList<PageModel> getAlternativeFromInternet(ICallbackNotifier notifier, String language) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new BakaReaderException("No Network Connectifity", BakaReaderException.NO_NETWORK_CONNECTIFITY);
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Downloading " + language + " Novels list..."));
}
// parse information
PageModel teaserPage = new PageModel();
if (language != null) {
teaserPage.setPage(AlternativeLanguageInfo.getAlternativeLanguageInfo().get(language).getCategoryInfo());
teaserPage.setTitle(language + " Novels");
teaserPage.setLanguage(language);
}
teaserPage = getPageModel(teaserPage, notifier);
teaserPage.setType(PageModel.TYPE_NOVEL);
// update page model
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
teaserPage = PageModelHelper.insertOrUpdatePageModel(db, teaserPage, true);
Log.d(TAG, "Updated " + language);
}
// get alternative list
ArrayList<PageModel> list = null;
String url = null;
if (language != null)
url = UIHelper.getBaseUrl(LNReaderApplication.getInstance().getApplicationContext()) + "/project/index.php?title=" + AlternativeLanguageInfo.getAlternativeLanguageInfo().get(language).getCategoryInfo();
int retry = 0;
while (retry < getRetry()) {
try {
Response response = Jsoup.connect(url).timeout(getTimeout(retry)).execute();
Document doc = response.parse();
list = BakaTsukiParserAlternative.ParseAlternativeList(doc, language);
Log.d(TAG, "Found from internet: " + list.size() + " " + language + " Novel");
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Found: " + list.size() + " " + language + " ."));
}
break;
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Retrying: " + language + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "Retrying: " + language + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
// save teaser list
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
for (PageModel pageModel : list) {
pageModel = PageModelHelper.insertOrUpdatePageModel(db, pageModel, true);
Log.d(TAG, "Updated " + language + " novel: " + pageModel.getPage());
}
}
return list;
}
/**
* Get page model from db. If autoDownload = true, get the pageModel from
* internet if not exists.
*
* @param page
* @param notifier
* @param autoDownload
* @return
* @throws Exception
*/
public PageModel getPageModel(PageModel page, ICallbackNotifier notifier, boolean autoDownload) throws Exception {
PageModel pageModel = null;
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
try {
pageModel = PageModelHelper.getPageModel(db, page.getPage());
} finally {
db.close();
}
}
if (pageModel == null && autoDownload) {
pageModel = getPageModelFromInternet(page, notifier);
}
return pageModel;
}
/**
* Get page model from db. Get the pageModel from internet if not exists.
*
* @param page
* @param notifier
* @return
* @throws Exception
*/
public PageModel getPageModel(PageModel page, ICallbackNotifier notifier) throws Exception {
return getPageModel(page, notifier, true);
}
/**
* Return pageModel, null if not exist.
*
* @param page
* @param notifier
* @return
* @throws Exception
*/
public PageModel getExistingPageModel(PageModel page, ICallbackNotifier notifier) throws Exception {
PageModel pageModel = null;
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
try {
pageModel = PageModelHelper.getPageModel(db, page.getPage());
} finally {
db.close();
}
}
return pageModel;
}
public PageModel getPageModelFromInternet(PageModel page, ICallbackNotifier notifier) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new BakaReaderException("没有网络连接", BakaReaderException.NO_NETWORK_CONNECTIFITY);
Log.d(TAG, "PageModel = " + page.getPage());
int retry = 0;
while (retry < getRetry()) {
try {
if (notifier != null) {
notifier.onCallback(new CallbackEventData("正在加载 " + " 请稍后"));
}
String encodedTitle = Util.UrlEncode(page.getPage());
String fullUrl = "http://www.baka-tsuki.org/project/api.php?action=query&prop=info&format=xml&redirects=yes&titles=" + encodedTitle;
Response response = Jsoup.connect(fullUrl).timeout(getTimeout(retry)).execute();
PageModel pageModel = null;
String lang = page.getLanguage();
if (lang != null)
pageModel = CommonParser.parsePageAPI(page, response.parse(), fullUrl);
pageModel.setFinishedRead(page.isFinishedRead());
pageModel.setWatched(page.isWatched());
synchronized (dbh) {
// save to db and get saved value
SQLiteDatabase db = dbh.getWritableDatabase();
try {
pageModel = PageModelHelper.insertOrUpdatePageModel(db, pageModel, false);
} finally {
db.close();
}
}
return pageModel;
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("重新尝试: " + page.getPage() + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "重新尝试: " + page.getPage() + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
return null;
}
public PageModel updatePageModel(PageModel page) {
PageModel pageModel = null;
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
try {
pageModel = PageModelHelper.insertOrUpdatePageModel(db, page, false);
} finally {
db.close();
}
}
return pageModel;
}
/*
* NovelCollectionModel
*/
public NovelCollectionModel getNovelDetails(PageModel page, ICallbackNotifier notifier) throws Exception {
NovelCollectionModel novel = null;
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
try {
novel = NovelCollectionModelHelper.getNovelDetails(db, page.getPage());
} finally {
db.close();
}
}
if (novel == null) {
novel = getNovelDetailsFromInternet(page, notifier);
}
return novel;
}
public NovelCollectionModel getNovelDetailsFromInternet(PageModel page, ICallbackNotifier notifier) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new BakaReaderException("没有网络连接", BakaReaderException.NO_NETWORK_CONNECTIFITY);
Log.d(TAG, "Getting Novel Details from internet: " + page.getPage());
NovelCollectionModel novel = null;
int retry = 0;
while (retry < getRetry()) {
try {
if (notifier != null) {
notifier.onCallback(new CallbackEventData("正在加载小说详细信息: " + page.getPage()));
}
//String encodedTitle = Util.UrlEncode();
String fullUrl = UIHelper.getBaseUrl(LNReaderApplication.getInstance().getApplicationContext()) + "/api/article/" + page.getId()+"/1";
Response response = Jsoup.connect(fullUrl).timeout(getTimeout(retry)).execute();
String doc = response.body();
/*
* Add your section of alternative language here, create own
* parser for each language for modularity reason
*/
if (!page.getLanguage().equals(Constants.LANG_ENGLISH))
novel = BakaTsukiParserAlternative.ParseNovelDetails(doc, page);
else
novel = BakaTsukiParser.ParseNovelDetails(doc, page);
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("重新尝试: " + page.getPage() + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "重新尝试: " + page.getPage() + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
// Novel details' Page Model
if (novel != null) {
page = updateNovelDetailsPageModel(page, notifier, novel);
synchronized (dbh) {
// insert to DB and get saved value
SQLiteDatabase db = dbh.getWritableDatabase();
try {
db.beginTransaction();
novel = NovelCollectionModelHelper.insertNovelDetails(db, novel);
db.setTransactionSuccessful();
//db.endTransaction();
} finally {
db.endTransaction();
db.close();
}
}
// update info for each chapters
if (notifier != null) {
notifier.onCallback(new CallbackEventData("获取章节信息: " + page.getPage()));
}
Log.d(TAG, "Cover size: " + novel.getFlattedChapterList().size());
ArrayList<PageModel> chapters = getUpdateInfo(novel.getFlattedChapterList(), notifier);
for (PageModel pageModel : chapters) {
pageModel = updatePageModel(pageModel);
}
// download cover image
Log.d(TAG, "Cover imgurl: " + page.getImgurl());
novel.setCoverUrl(new URL(Constants.BASE_IMAGE_URL+ page.getImgurl()));
if (novel.getCoverUrl() != null) {
if (notifier != null) {
notifier.onCallback(new CallbackEventData("获取封面图片."));
}
DownloadFileTask task = new DownloadFileTask(notifier);
ImageModel image = task.downloadImage(novel.getCoverUrl());
// TODO: need to save to db?
Log.d(TAG, "Cover Image: " + image.toString());
novel.setCover(image.getDedepath());
synchronized (dbh) {
// insert to DB and get saved value
SQLiteDatabase db = dbh.getWritableDatabase();
try {
db.beginTransaction();
NovelCollectionModelHelper.insertNovelDetailsImg(db, novel);
db.setTransactionSuccessful();
//db.endTransaction();
} finally {
db.endTransaction();
db.close();
}
}
}
Log.d(TAG, "Complete getting Novel Details from internet: " + page.getPage());
break;
}
}
return novel;
}
public PageModel updateNovelDetailsPageModel(PageModel page, ICallbackNotifier notifier, NovelCollectionModel novel) throws Exception {
// comment out because have teaser now...
// page.setParent("Main_Page"); // insurance
// get the last update time from internet
if (notifier != null) {
notifier.onCallback(new CallbackEventData("获取小说信息: " + page.getPage()));
}
/*PageModel novelPageTemp = getPageModelFromInternet(page, notifier);
if (novelPageTemp != null) {
page.setLastUpdate(novelPageTemp.getLastUpdate());
page.setLastCheck(new Date());
novel.setLastUpdate(novelPageTemp.getLastUpdate());
novel.setLastCheck(new Date());
} else {
page.setLastUpdate(new Date(0));
page.setLastCheck(new Date());
novel.setLastUpdate(new Date(0));
novel.setLastCheck(new Date());
}*/
// save the changes
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
try {
page = PageModelHelper.insertOrUpdatePageModel(db, page, true);
} finally {
db.close();
}
}
return page;
}
public PageModel getUpdateInfo(PageModel pageModel, ICallbackNotifier notifier) throws Exception {
ArrayList<PageModel> pageModels = new ArrayList<PageModel>();
pageModels.add(pageModel);
pageModels = getUpdateInfo(pageModels, notifier);
return pageModels.get(0);
}
/***
* Bulk update page info through wiki API - LastUpdateInfo. - Redirected. -
* Missing flag.
*
* @param pageModels
* @param notifier
* @return
* @throws Exception
*/
public ArrayList<PageModel> getUpdateInfo(ArrayList<PageModel> pageModels, ICallbackNotifier notifier) throws Exception {
ArrayList<PageModel> resultPageModel = new ArrayList<PageModel>();
ArrayList<PageModel> noInfoPageModel = new ArrayList<PageModel>();
ArrayList<PageModel> externalPageModel = new ArrayList<PageModel>();
String baseUrl = UIHelper.getBaseUrl(LNReaderApplication.getInstance().getApplicationContext()) + "/project/api.php?action=query&prop=info&format=xml&redirects=yes&titles=";
int i = 0;
int retry = 0;
while (i < pageModels.size()) {
int apiPageCount = 1;
ArrayList<PageModel> checkedPageModel = new ArrayList<PageModel>();
String titles = "";
while (i < pageModels.size() && apiPageCount < 50) {
if (pageModels.get(i).isExternal()) {
pageModels.get(i).setMissing(false);
externalPageModel.add(pageModels.get(i));
++i;
continue;
}
if (pageModels.get(i).isMissing() || pageModels.get(i).getPage().endsWith("&action=edit&redlink=1")) {
pageModels.get(i).setMissing(true);
noInfoPageModel.add(pageModels.get(i));
++i;
continue;
}
if (titles.length() + pageModels.get(i).getPage().length() < 2000) {
titles += "|" + Util.UrlEncode(pageModels.get(i).getPage());
checkedPageModel.add(pageModels.get(i));
++i;
++apiPageCount;
} else {
break;
}
}
// request the page
while (retry < getRetry()) {
try {
// Log.d(TAG, "Trying to get: " + baseUrl + titles);
String url = baseUrl + titles;
Response response = Jsoup.connect(url).timeout(getTimeout(retry)).execute();
Document doc = response.parse();
ArrayList<PageModel> updatedPageModels = CommonParser.parsePageAPI(checkedPageModel, doc, url);
resultPageModel.addAll(updatedPageModels);
break;
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Retrying: Get Pages Info (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "Retrying: Get Pages Info (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
}
for (PageModel page : externalPageModel) {
getExternalUpdateInfo(page);
}
resultPageModel.addAll(noInfoPageModel);
resultPageModel.addAll(externalPageModel);
return resultPageModel;
}
public void getExternalUpdateInfo(PageModel page) {
int retry;
Map<String, String> headers = null;
// Date: Wed, 13 Nov 2013 13:08:35 GMT
DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss z", Locale.US);
retry = 0;
while (retry < getRetry()) {
try {
headers = Jsoup.connect(page.getPage()).timeout(getTimeout(retry)).maxBodySize(1).execute().headers();
break;
} catch (Exception e) {
Log.e(TAG, "Error when getting updated date for: " + page.getPage(), e);
++retry;
}
}
if (headers != null) {
String dateStr = null;
if (headers.containsKey("Last-Modified")) {
dateStr = headers.get("Last-Modified");
}
else if (headers.containsKey("Date")) {
dateStr = headers.get("Date");
}
if (!Util.isStringNullOrEmpty(dateStr)) {
try {
Log.d(TAG, "External Novel last update: " + dateStr);
page.setLastUpdate(df.parse(dateStr));
} catch (Exception e) {
Log.e(TAG, "Failed to parse date for: " + page.getPage(), e);
}
}
}
page.setLastCheck(new Date());
}
public void deleteBooks(BookModel bookDel) {
synchronized (dbh) {
// get from db
SQLiteDatabase db = dbh.getReadableDatabase();
try {
BookModel tempBook = BookModelHelper.getBookModel(db, bookDel.getId());
if (tempBook != null) {
ArrayList<PageModel> chapters = tempBook.getChapterCollection();
for (PageModel chapter : chapters) {
NovelContentModelHelper.deleteNovelContent(db, chapter);
}
BookModelHelper.deleteBookModel(db, tempBook);
}
} finally {
db.close();
}
}
}
public void deletePage(PageModel page) {
synchronized (dbh) {
// get from db
SQLiteDatabase db = dbh.getReadableDatabase();
try {
PageModel tempPage = PageModelHelper.getPageModel(db, page.getId());
if (tempPage != null) {
PageModelHelper.deletePageModel(db, tempPage);
}
} finally {
db.close();
}
}
}
public ArrayList<PageModel> getChapterCollection(String page, String title, BookModel book) {
synchronized (dbh) {
// get from db
SQLiteDatabase db = dbh.getReadableDatabase();
try {
return NovelCollectionModelHelper.getChapterCollection(db, page + Constants.NOVEL_BOOK_DIVIDER + title, book);
} finally {
db.close();
}
}
}
public ArrayList<PageModel> getAllContentPageModel() {
ArrayList<PageModel> result = null;
synchronized (dbh) {
// get from db
SQLiteDatabase db = dbh.getReadableDatabase();
try {
result = PageModelHelper.getAllContentPageModel(db);
} finally {
db.close();
}
}
return result;
}
/*
* NovelContentModel
*/
public NovelContentModel getNovelContent(BookModel page, boolean download, ICallbackNotifier notifier) throws Exception {
NovelContentModel content = null;
synchronized (dbh) {
// get from db
SQLiteDatabase db = dbh.getReadableDatabase();
try {
content = NovelContentModelHelper.getNovelContent(db, page.getPage());
} finally {
db.close();
}
}
// get from Internet;
if (download && content == null) {
Log.d("getNovelContent", "Get from Internet: " + page.getPage());
content = getNovelContentFromInternet(page, notifier);
}
Log.d("getNovelContent", "Text: " + content.getContent());
return content;
}
public NovelContentModel getNovelContentFromInternet(BookModel page, ICallbackNotifier notifier) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new BakaReaderException("没有网络连接", BakaReaderException.NO_NETWORK_CONNECTIFITY);
String oldTitle = page.getTitle();
NovelContentModel content = new NovelContentModel();
int retry = 0;
String doc = null;
while (retry < getRetry()) {
try {
String encodedUrl = Constants.BASE_URL + "/api/article/"+page.getBookId()+"/ch/"+page.getChapter();
Response response = Jsoup.connect(encodedUrl).timeout(getTimeout(retry)).execute();
doc = response.body();
content = BakaTsukiParser.ParseNovelContent(doc, page);
content.setUpdatingFromInternet(true);
break;
} catch (EOFException eof) {
++retry;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Retrying: " + page.getPage() + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "Retrying: " + page.getPage() + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
/*if (doc != null) {
// download all attached images
DownloadFileTask task = new DownloadFileTask(notifier);
for (ImageModel image : content.getImages()) {
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Start downloading: " + image.getUrl()));
}
image = task.downloadImage(image.getUrl());
// TODO: need to save image to db? mostly thumbnail only
}
// download linked big images
boolean isDownloadBigImage = PreferenceManager.getDefaultSharedPreferences(LNReaderApplication.getInstance()).getBoolean(Constants.PREF_DOWLOAD_BIG_IMAGE, false);
if (isDownloadBigImage) {
Document imageDoc = Jsoup.parse(content.getContent());
ArrayList<String> images = CommonParser.parseImagesFromContentPage(imageDoc);
for (String imageUrl : images) {
// ImageModel bigImage = getImageModelFromInternet(image, notifier);
ImageModel bigImage = new ImageModel();
bigImage.setBigImage(true);
bigImage.setName(imageUrl);
bigImage.setReferer(imageUrl);
bigImage = getImageModel(bigImage, notifier);
}
}
// get last updated info
PageModel contentPageModelTemp = getPageModelFromInternet(content.getPageModel(), notifier);
if (contentPageModelTemp != null) {
// overwrite the old title
content.getPageModel().setTitle(oldTitle);
// syncronize the date
content.getPageModel().setLastUpdate(contentPageModelTemp.getLastUpdate());
content.getPageModel().setLastCheck(new Date());
content.setLastUpdate(contentPageModelTemp.getLastUpdate());
content.setLastCheck(new Date());
}
// page model will be also saved in insertNovelContent()
synchronized (dbh) {
// save to DB, and get the saved value
SQLiteDatabase db = dbh.getWritableDatabase();
try {
// TODO: somehow using transaction cause problem...
db.beginTransaction();
content = NovelContentModelHelper.insertNovelContent(db, content);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
db.close();
}
}
}*/
return content;
}
public NovelContentModel updateNovelContent(NovelContentModel content) throws Exception {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
try {
content = NovelContentModelHelper.insertNovelContent(db, content);
} finally {
db.close();
}
}
return content;
}
public boolean deleteNovelContent(PageModel ref) {
boolean result = false;
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
try {
result = NovelContentModelHelper.deleteNovelContent(db, ref);
} finally {
db.close();
}
}
return result;
}
/*
* ImageModel
*/
/**
* Get image from db, if not exist will try to download from internet
*
* @param image
* @param notifier
* @return
* @throws Exception
*/
public ImageModel getImageModel(ImageModel image, ICallbackNotifier notifier) throws Exception {
if (image == null || image.getName() == null)
throw new BakaReaderException("Empty Image!", BakaReaderException.EMPTY_IMAGE);
ImageModel imageTemp = null;
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
try {
imageTemp = ImageModelHelper.getImage(db, image);
if (imageTemp == null) {
if (image.getReferer() == null)
image.setReferer(image.getName());
Log.d(TAG, "Image not found, might need to check by referer: " + image.getName() + ", referer: " + image.getReferer());
imageTemp = ImageModelHelper.getImageByReferer(db, image);
}
} finally {
db.close();
}
}
boolean downloadBigImage = false;
if (imageTemp == null) {
Log.i(TAG, "Image not found in DB, getting data from internet: " + image.getName());
downloadBigImage = true;
} else if (!new File(imageTemp.getPath()).exists()) {
try{
Log.i(TAG, "Image found in DB, but doesn't exist in path: " + imageTemp.getPath()
+"\nAttempting URLDecoding method with default charset:"+java.nio.charset.Charset.defaultCharset().displayName());
if(!new File(java.net.URLDecoder.decode(imageTemp.getPath(), java.nio.charset.Charset.defaultCharset().displayName())).exists()){
Log.i(TAG, "Image found in DB, but doesn't exist in URL decoded path: " + java.net.URLDecoder.decode(imageTemp.getPath(), java.nio.charset.Charset.defaultCharset().displayName()));
downloadBigImage = true;
} //else Log.i(TAG, "Image found in DB with URL decoded path: " + java.net.URLDecoder.decode(imageTemp.getPath(), java.nio.charset.Charset.defaultCharset().displayName()));
}catch(Exception e){
Log.i(TAG, "Image found in DB, but path string seems to be broken: " + imageTemp.getPath()
+ " Charset:" + java.nio.charset.Charset.defaultCharset().displayName());
downloadBigImage = true;
}
}
if (downloadBigImage) {
Log.d(TAG, "Downloading big image from internet: " + image.getName());
imageTemp = getImageModelFromInternet(image, notifier);
}
return imageTemp;
}
/**
* Get image from internet from File:xxx
*
* @param page
* @param notifier
* @return
* @throws Exception
*/
public ImageModel getImageModelFromInternet(ImageModel image, ICallbackNotifier notifier) throws Exception {
if (!LNReaderApplication.getInstance().isOnline())
throw new BakaReaderException("No Network Connectifity", BakaReaderException.NO_NETWORK_CONNECTIFITY);
String url = image.getName();
if (!url.startsWith("http"))
url = UIHelper.getBaseUrl(LNReaderApplication.getInstance().getApplicationContext()) + url;
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Parsing File Page: " + url));
}
int retry = 0;
while (retry < getRetry()) {
try {
Response response = Jsoup.connect(url).timeout(getTimeout(retry)).execute();
Document doc = response.parse();
// only return the full image url
image = CommonParser.parseImagePage(doc);
DownloadFileTask downloader = new DownloadFileTask(notifier);
image = downloader.downloadImage(image.getUrl());
image.setReferer(url);
image = insertImage(image);
break;
} catch (EOFException eof) {
if (notifier != null) {
notifier.onCallback(new CallbackEventData("Retrying: " + url + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage()));
}
++retry;
if (retry > getRetry())
throw eof;
} catch (IOException eof) {
++retry;
String message = "Retrying: " + url + " (" + retry + " of " + getRetry() + ")\n" + eof.getMessage();
if (notifier != null) {
notifier.onCallback(new CallbackEventData(message));
}
Log.d(TAG, message, eof);
if (retry > getRetry())
throw eof;
}
}
return image;
}
public ImageModel insertImage(ImageModel image) {
synchronized (dbh) {
// save to db and get the saved value
SQLiteDatabase db = dbh.getWritableDatabase();
try {
image = ImageModelHelper.insertImage(db, image);
} finally {
db.close();
}
}
return image;
}
public ArrayList<ImageModel> getAllImages() {
ArrayList<ImageModel> result;
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
result = ImageModelHelper.getAllImages(db);
}
return result;
}
public ArrayList<PageModel> doSearch(String searchStr, boolean isNovelOnly, ArrayList<String> languageList) {
if (searchStr == null || searchStr.length() < 3)
return null;
ArrayList<PageModel> result;
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
result = dbh.doSearch(db, searchStr, isNovelOnly, languageList);
}
return result;
}
public boolean deleteNovel(PageModel novel) {
boolean result = false;
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
result = NovelCollectionModelHelper.deleteNovel(db, novel);
}
return result;
}
public ArrayList<BookmarkModel> getBookmarks(PageModel novel) {
ArrayList<BookmarkModel> bookmarks = new ArrayList<BookmarkModel>();
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
bookmarks = BookmarkModelHelper.getBookmarks(db, novel);
}
return bookmarks;
}
public int addBookmark(BookmarkModel bookmark) {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
return BookmarkModelHelper.insertBookmark(db, bookmark);
}
}
public int deleteBookmark(BookmarkModel bookmark) {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
return BookmarkModelHelper.deleteBookmark(db, bookmark);
}
}
public ArrayList<BookmarkModel> getAllBookmarks(boolean isOrderByDate) {
ArrayList<BookmarkModel> bookmarks = new ArrayList<BookmarkModel>();
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
bookmarks = BookmarkModelHelper.getAllBookmarks(db, isOrderByDate);
}
return bookmarks;
}
public boolean isContentUpdated(PageModel page) {
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
return dbh.isContentUpdated(db, page);
}
}
public int isNovelUpdated(PageModel page) {
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
return dbh.isNovelUpdated(db, page);
}
}
public ArrayList<UpdateInfoModel> getAllUpdateHistory() {
synchronized (dbh) {
SQLiteDatabase db = dbh.getReadableDatabase();
return UpdateInfoModelHelper.getAllUpdateHistory(db);
}
}
public void deleteAllUpdateHistory() {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
UpdateInfoModelHelper.deleteAllUpdateHistory(db);
}
}
public void deleteUpdateHistory(UpdateInfoModel updateInfo) {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
UpdateInfoModelHelper.deleteUpdateHistory(db, updateInfo);
}
}
public void insertUpdateHistory(UpdateInfoModel update) {
synchronized (dbh) {
SQLiteDatabase db = dbh.getWritableDatabase();
UpdateInfoModelHelper.insertUpdateHistory(db, update);
}
}
public void deleteChapterCache(PageModel chapter) {
deleteNovelContent(chapter);
// Set isDownloaded to false
chapter.setDownloaded(false);
updatePageModel(chapter);
}
public void deleteBookCache(BookModel bookDel) {
for (PageModel p : bookDel.getChapterCollection()) {
deleteChapterCache(p);
}
}
private int getRetry() {
return UIHelper.getIntFromPreferences(Constants.PREF_RETRY, 3);
}
private int getTimeout(int retry) {
boolean increaseRetry = PreferenceManager.getDefaultSharedPreferences(LNReaderApplication.getInstance().getApplicationContext()).getBoolean(Constants.PREF_INCREASE_RETRY, false);
int timeout = UIHelper.getIntFromPreferences(Constants.PREF_TIMEOUT, 60) * 1000;
if (increaseRetry) {
timeout = timeout * (retry + 1);
}
return timeout;
}
// public void temp() {
// synchronized (dbh) {
// SQLiteDatabase db = dbh.getWritableDatabase();
// db.execSQL("DROP TABLE IF EXISTS " + dbh.TABLE_NOVEL_BOOKMARK);
// db.execSQL(dbh.DATABASE_CREATE_NOVEL_BOOKMARK);
// }
// }
}