Commit 6708ef77 authored by fallenstardust's avatar fallenstardust Committed by GitHub

Merge pull request #80 from zhuhongbozhuhongbo/webcrawler

add webcrawler to show ex-card
parents f58063a9 e8655f1a
......@@ -131,4 +131,6 @@ dependencies {
implementation 'de.hdodenhof:circleimageview:2.2.0'
//决斗助手
implementation 'com.github.feihuaduo:YGODuelAssistantLib:1.0'
// jsoup HTML parser library @ https://jsoup.org/
implementation 'org.jsoup:jsoup:1.15.3'
}
......@@ -145,6 +145,14 @@
<activity
android:name="cn.garymb.ygomobile.ui.activities.PermissionsActivity"
android:theme="@style/TranslucentTheme" />
<!-- android:screenOrientation="landscape"-->
<activity
android:name="cn.garymb.ygomobile.ex_card.ExCardActivity"
android:theme="@style/AppTheme.Mycard"
android:launchMode="singleTop"
/>
<!-- 为防止Service被系统回收,可以尝试通过提高服务的优先级解决,1000是最高优先级,数字越小,优先级越低 -->
<!--android:priority="1000"-->
<service
......
package cn.garymb.ygomobile.ex_card;
import android.os.Parcel;
import android.os.Parcelable;
public class ExCard implements Parcelable {
private String name;
private String imageUrl;
private String description;
public ExCard(String name, String imageUrl, String description) {
this.name = name;
this.imageUrl = imageUrl;
this.description = description;
}
protected ExCard(Parcel in) {
name = in.readString();
imageUrl = in.readString();
description = in.readString();
}
public static final Creator<ExCard> CREATOR = new Creator<ExCard>() {
@Override
public ExCard createFromParcel(Parcel in) {
return new ExCard(in);
}
@Override
public ExCard[] newArray(int size) {
return new ExCard[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeString(this.imageUrl);
dest.writeString(this.description);
}
}
package cn.garymb.ygomobile.ex_card;
import static cn.garymb.ygomobile.Constants.ASSET_SERVER_LIST;
import static cn.garymb.ygomobile.Constants.URL_YGO233_FILE;
import static cn.garymb.ygomobile.Constants.URL_YGO233_FILE_ALT;
import static cn.garymb.ygomobile.utils.DownloadUtil.TYPE_DOWNLOAD_EXCEPTION;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import cn.garymb.ygomobile.AppsSettings;
import cn.garymb.ygomobile.Constants;
import cn.garymb.ygomobile.bean.ServerInfo;
import cn.garymb.ygomobile.bean.ServerList;
import cn.garymb.ygomobile.lite.BuildConfig;
import cn.garymb.ygomobile.lite.R;
import cn.garymb.ygomobile.ui.activities.BaseActivity;
import cn.garymb.ygomobile.ui.activities.WebActivity;
import cn.garymb.ygomobile.ui.home.MainActivity;
import cn.garymb.ygomobile.ui.home.ServerListManager;
import cn.garymb.ygomobile.ui.plus.VUiKit;
import cn.garymb.ygomobile.utils.DownloadUtil;
import cn.garymb.ygomobile.utils.FileUtils;
import cn.garymb.ygomobile.utils.IOUtils;
import cn.garymb.ygomobile.utils.SharedPreferenceUtil;
import cn.garymb.ygomobile.utils.SystemUtils;
import cn.garymb.ygomobile.utils.UnzipUtils;
import cn.garymb.ygomobile.utils.XmlUtils;
import cn.garymb.ygomobile.utils.YGOUtil;
import ocgcore.DataManager;
public class ExCardActivity extends BaseActivity {
private View layoutView;
public static String dataVer;
private String mTitle;
private Button btn_download;
private List<ServerInfo> serverInfos;
private ServerInfo mServerInfo;
private File xmlFile;
private int FailedCount;
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case DownloadUtil.TYPE_DOWNLOAD_ING:
btn_download.setText(msg.arg1 + "%");
break;
case DownloadUtil.TYPE_DOWNLOAD_EXCEPTION:
++FailedCount;
if (FailedCount <= 2) {
Toast.makeText(getActivity(), R.string.Ask_to_Change_Other_Way, Toast.LENGTH_SHORT).show();
downloadfromWeb(URL_YGO233_FILE_ALT);
}
YGOUtil.show("error" + msg.obj);
break;
case UnzipUtils.ZIP_READY:
btn_download.setText(R.string.title_use_ex);
break;
case UnzipUtils.ZIP_UNZIP_OK:
if (!AppsSettings.get().isReadExpansions()) {
Intent startSetting = new Intent(getContext(), MainActivity.class);
startSetting.putExtra("flag", 4);
startActivity(startSetting);
Toast.makeText(getContext(), R.string.ypk_go_setting, Toast.LENGTH_LONG).show();
} else {
DataManager.get().load(true);
Toast.makeText(getContext(), R.string.ypk_installed, Toast.LENGTH_LONG).show();
}
String servername = "";
if (getPackageName().equals(BuildConfig.APPLICATION_ID))
servername = "23333先行服务器";
if (getPackageName().equals((BuildConfig.APPLICATION_ID) + ".KO"))
servername = "YGOPRO 사전 게시 중국서버";
if (getPackageName().equals((BuildConfig.APPLICATION_ID) + ".EN"))
servername = "Mercury23333 OCG/TCG Pre-release";
AddServer(servername, "s1.ygo233.com", 23333, "Knight of Hanoi");
btn_download.setVisibility(View.GONE);
SharedPreferenceUtil.setExpansionDataVer(WebActivity.dataVer);
break;
case UnzipUtils.ZIP_UNZIP_EXCEPTION:
Toast.makeText(getContext(), getString(R.string.install_failed_bcos) + msg.obj, Toast.LENGTH_SHORT).show();
break;
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("webCrawler", "ExCardActivity onCreate");
setContentView(R.layout.activity_ex_card);
/* show the recyclerView */
//get ex card data from intent
List<ExCard> exCards = this.getIntent()
.getParcelableArrayListExtra("exCards");
ExCardListAdapter exCardListAdapter = new ExCardListAdapter(R.layout.item_ex_card, exCards);
RecyclerView exCardListView = (RecyclerView) findViewById(R.id.list_ex_cards);
exCardListView.setLayoutManager(new LinearLayoutManager(this));
exCardListView.setAdapter(exCardListAdapter);
final Toolbar toolbar = $(R.id.toolbar);
setSupportActionBar(toolbar);
enableBackHome();
serverInfos = new ArrayList<>();
xmlFile = new File(this.getFilesDir(), Constants.SERVER_FILE);
initButton();
}
public void initButton() {
btn_download = $(R.id.web_btn_download_prerelease);
btn_download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downloadfromWeb(URL_YGO233_FILE);
}
});
}
public void AddServer(String name, String Addr, int port, String playerName) {
mServerInfo = new ServerInfo();
mServerInfo.setName(name);
mServerInfo.setServerAddr(Addr);
mServerInfo.setPort(port);
mServerInfo.setPlayerName(playerName);
VUiKit.defer().when(() -> {
ServerList assetList = ServerListManager.readList(this.getAssets().open(ASSET_SERVER_LIST));
ServerList fileList = xmlFile.exists() ? ServerListManager.readList(new FileInputStream(xmlFile)) : null;
if (fileList == null) {
return assetList;
}
if (fileList.getVercode() < assetList.getVercode()) {
xmlFile.delete();
return assetList;
}
return fileList;
}).done((list) -> {
if (list != null) {
serverInfos.clear();
serverInfos.addAll(list.getServerInfoList());
boolean hasServer = false;
for (int i = 0; i < list.getServerInfoList().size(); i++) {
if (mServerInfo.getPort() != serverInfos.get(i).getPort() && mServerInfo.getServerAddr() != serverInfos.get(i).getServerAddr()) {
continue;
} else {
hasServer = true;
break;
}
}
if (!hasServer && !serverInfos.contains(mServerInfo)) {
serverInfos.add(mServerInfo);
}
saveItems();
}
});
}
public void saveItems() {
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(xmlFile);
XmlUtils.get().saveXml(new ServerList(SystemUtils.getVersion(getContext()), serverInfos), outputStream);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.close(outputStream);
}
}
private void downloadfromWeb(String fileUrl) {
File file = new File(AppsSettings.get().getResourcePath() + "-preRlease.zip");
if (file.exists()) {
FileUtils.deleteFile(file);
}
DownloadUtil.get().download(fileUrl, file.getParent(), file.getName(), new DownloadUtil.OnDownloadListener() {
@Override
public void onDownloadSuccess(File file) {
Message message = new Message();
message.what = UnzipUtils.ZIP_READY;
try {
File ydks = new File(AppsSettings.get().getDeckDir());
File[] subYdks = ydks.listFiles();
for (File files : subYdks) {
if (files.getName().contains("-") && files.getName().contains(" new cards"))
files.delete();
}
UnzipUtils.upZipFile(file, AppsSettings.get().getResourcePath());
} catch (Exception e) {
message.what = UnzipUtils.ZIP_UNZIP_EXCEPTION;
} finally {
message.what = UnzipUtils.ZIP_UNZIP_OK;
}
handler.sendMessage(message);
}
@Override
public void onDownloading(int progress) {
Message message = new Message();
message.what = DownloadUtil.TYPE_DOWNLOAD_ING;
message.arg1 = progress;
handler.sendMessage(message);
}
@Override
public void onDownloadFailed(Exception e) {
//下载失败后删除下载的文件
FileUtils.deleteFile(file);
Message message = new Message();
message.what = TYPE_DOWNLOAD_EXCEPTION;
message.obj = e.toString();
handler.sendMessage(message);
}
});
}
}
package cn.garymb.ygomobile.ex_card;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import com.bumptech.glide.RequestBuilder;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import java.util.List;
import cn.garymb.ygomobile.lite.R;
import cn.garymb.ygomobile.loader.ImageLoader;
import cn.garymb.ygomobile.utils.glide.GlideCompat;
import cn.garymb.ygomobile.utils.glide.StringSignature;
public class ExCardListAdapter extends BaseQuickAdapter<ExCard, BaseViewHolder> {
private ImageLoader imageLoader;
public ExCardListAdapter(int layoutResId, List<ExCard> data) {
super(layoutResId, data);
//use the imageLoader to load image from url
imageLoader = new ImageLoader(true);
}
@Override
protected void convert(BaseViewHolder helper, ExCard item) {
helper.setText(R.id.ex_card_name, item.getName());
helper.setText(R.id.ex_card_description, item.getDescription());
ImageView imageview = helper.getView(R.id.ex_card_image);
//the function cn.garymb.ygomobile.loader.ImageLoader.bindT(...)
//cn.garymb.ygomobile.loader.ImageLoader.setDefaults(...)
//is a private function,so I copied the content of it to here
RequestBuilder<Drawable> resource = GlideCompat.with(imageview.getContext()).load(item.getImageUrl());
resource.placeholder(R.drawable.unknown);
resource.error(R.drawable.unknown);
resource.into(imageview);
}
}
......@@ -43,6 +43,10 @@ import com.tubb.smrv.SwipeMenuRecyclerView;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.FileInputStream;
......@@ -60,6 +64,8 @@ import cn.garymb.ygomobile.bean.Deck;
import cn.garymb.ygomobile.bean.ServerInfo;
import cn.garymb.ygomobile.bean.ServerList;
import cn.garymb.ygomobile.bean.events.ServerInfoEvent;
import cn.garymb.ygomobile.ex_card.ExCardActivity;
import cn.garymb.ygomobile.ex_card.ExCard;
import cn.garymb.ygomobile.lite.BuildConfig;
import cn.garymb.ygomobile.lite.R;
import cn.garymb.ygomobile.loader.ImageLoader;
......@@ -522,12 +528,12 @@ public class HomeFragment extends BaseFragemnt implements OnDuelAssistantListene
@Override
public void onSaveDeck(Uri uri, List<Integer> mainList, List<Integer> exList, List<Integer> sideList, boolean isCompleteDeck, String exception, int id) {
saveDeck(uri,mainList,exList,sideList,isCompleteDeck,exception);
saveDeck(uri, mainList, exList, sideList, isCompleteDeck, exception);
}
public void saveDeck(Uri uri, List<Integer> mainList, List<Integer> exList, List<Integer> sideList, boolean isCompleteDeck, String exception) {
if (!TextUtils.isEmpty(exception)){
YGOUtil.show("卡组解析失败,原因为:"+exception);
if (!TextUtils.isEmpty(exception)) {
YGOUtil.show("卡组解析失败,原因为:" + exception);
return;
}
DialogPlus dialog = new DialogPlus(getContext());
......@@ -696,12 +702,83 @@ public class HomeFragment extends BaseFragemnt implements OnDuelAssistantListene
YGOStarter.startGame(getActivity(), null, "-k", "-s");
break;
case R.id.action_download_ex:
String aurl = Constants.URL_YGO233_ADVANCE;
if (ll_new_notice.getVisibility() == View.VISIBLE) {
aurl = aurl + "#pre_update_title";
}
WebActivity.open(getContext(), getString(R.string.action_download_expansions), aurl);
ll_new_notice.setVisibility(View.GONE);
//using Web crawler to extract the information of pre card
final DialogPlus dialog_read_ex = DialogPlus.show(getContext(), null, getContext().getString(R.string.fetch_ex_card));
VUiKit.defer().when(() -> {
String aurl = Constants.URL_YGO233_ADVANCE;
//Connect to the website
Document document = Jsoup.connect(aurl).get();
Element pre_card_content = document.getElementById("pre_release_cards");
Element tbody = pre_card_content.getElementsByTag("tbody").get(0);
Elements cards = tbody.getElementsByTag("tr");
if (cards.size() > 300) {//Considering the efficiency of html parse, if the size of
// pre cards list is to large, return null directly.
return null;
}
ArrayList<ExCard> exCards = new ArrayList<>();
for (Element card : cards) {
Elements card_attributes = card.getElementsByTag("td");
String imageUrl = card_attributes.get(0).getElementsByTag("a").attr("href");
String name = card_attributes.get(1).text();
String description = card_attributes.get(2).text();
ExCard exCard = new ExCard(name, imageUrl, description);
exCards.add(exCard);
}
Log.i("webCrawler", exCards.toString());
if (exCards.isEmpty()) {
return null;
} else {
return exCards;
}
}).fail((e) -> {
//关闭异常
if (dialog_read_ex.isShowing()) {
try {
dialog_read_ex.dismiss();
} catch (Exception ex) {
}
}
//If the crawler process failed, open webActivity
String aurl = Constants.URL_YGO233_ADVANCE;
if (ll_new_notice.getVisibility() == View.VISIBLE) {
aurl = aurl + "#pre_update_title";
}
WebActivity.open(getContext(), getString(R.string.action_download_expansions), aurl);
ll_new_notice.setVisibility(View.GONE);
Log.i("webCrawler", "webCrawler fail");
}).done((tmp) -> {
if (tmp != null) {
Log.i("webCrawler", "webCrawler done");
Intent intent = new Intent(getActivity(), ExCardActivity.class);
//intent.putExtra("exCards", tmp);
intent.putParcelableArrayListExtra("exCards", tmp);
startActivity(intent);
} else {
//If the crawler process cannot return right ex-card data,
//open webActivity
String aurl = Constants.URL_YGO233_ADVANCE;
if (ll_new_notice.getVisibility() == View.VISIBLE) {
aurl = aurl + "#pre_update_title";
}
WebActivity.open(getContext(), getString(R.string.action_download_expansions), aurl);
ll_new_notice.setVisibility(View.GONE);
Log.i("webCrawler", "webCrawler cannot return ex-card data");
}
//关闭异常
if (dialog_read_ex.isShowing()) {
try {
dialog_read_ex.dismiss();
Log.i("webCrawler", "dialog close");
} catch (Exception ex) {
}
}
});
break;
case R.id.action_help: {
final DialogPlus dialog = new DialogPlus(getContext());
......@@ -733,7 +810,7 @@ public class HomeFragment extends BaseFragemnt implements OnDuelAssistantListene
case R.id.nav_webpage: {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(Constants.URL_DONATE));
Toast.makeText(getActivity(),R.string.donatefor, Toast.LENGTH_LONG).show();
Toast.makeText(getActivity(), R.string.donatefor, Toast.LENGTH_LONG).show();
startActivity(intent);
}
break;
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.tubb.smrv.SwipeMenuRecyclerView
android:id="@+id/list_ex_cards"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@android:color/transparent"
android:dividerHeight="4dp"
android:padding="5dp"
android:scrollbars="vertical" />
</LinearLayout>
<LinearLayout
android:id="@+id/web_btn_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal">
<Button
android:id="@+id/web_btn_download_prerelease"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/button_bg"
android:text="@string/Download"
/>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sml="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- set the layout_height in the linear layout to “wrap_content”
so it doesn’t only show one TextView per page.-->
<!-- <LinearLayout
android:layout_width="@dimen/card_width_middle"
android:layout_height="@dimen/card_height_middle">
</LinearLayout>-->
<ImageView
android:id="@+id/ex_card_image"
android:layout_width="@dimen/card_width_middle"
android:layout_height="@dimen/card_height_middle"
android:layout_centerInParent="true"
android:layout_gravity="center_vertical"
android:scaleType="fitXY"
android:paddingRight="10dp"
tools:src="@drawable/unknown" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<cn.garymb.ygomobile.ui.widget.AlwaysMarqueeTextView
android:id="@+id/ex_card_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:shadowColor="@color/black"
android:shadowDx="1"
android:shadowDy="2"
android:shadowRadius="2"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="@color/item_title"
android:textSize="18sp"
tools:text="Card Name" />
<TextView
android:id="@+id/ex_card_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:textSize="17sp" />
<View
android:id="@+id/view_bar"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="3dp"
android:background="@color/colorPrimaryDark" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
......@@ -38,6 +38,7 @@
<string name="quit_tip">앱을 종료하겠습니까?</string>
<string name="back_tip">뒤로가기 키를 한번 더 누르시면 앱이 종료됩니다</string>
<string name="string_help_text">현재 앱에 필요한 권한이 없습니다. \n설정 - 권한 - 필요한 권한 얻기를 터치하십시오.</string>
<string name="fetch_ex_card">선행카드 읽기</string>
<!-- settings -->
<string name="settings_about">정보</string>
<string name="settings_about_sub_about">정보</string>
......
......@@ -38,6 +38,7 @@
<string name="quit_tip">退出游戏?</string>
<string name="back_tip">请再按一次返回键退出</string>
<string name="string_help_text">当前应用缺少必要权限。\n请点击 设置-权限 打开所需权限。</string>
<string name="fetch_ex_card">读取先行卡</string>
<!-- settings -->
<string name="settings_about">关于</string>
<string name="settings_about_sub_about">关于</string>
......
......@@ -45,6 +45,7 @@
<string name="back_tip">Press back key again to exit.</string>
<string name="string_help_text">The current application lacks the necessary permissions. \n
please click Settings - permissions - open the required permissions.</string>
<string name="fetch_ex_card">Fetching ex-cards</string>
<!-- settings -->
<string name="settings_about">About</string>
<string name="settings_about_sub_about">About</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment