[leanback] support cast

pull/123/head
FongMi 3 years ago
parent 96292ee01e
commit fd95160ba3
  1. 5
      app/build.gradle
  2. 432
      app/schemas/com.fongmi.android.tv.db.AppDatabase/21.json
  3. 29
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/HomeActivity.java
  4. 28
      app/src/main/java/com/fongmi/android/tv/bean/History.java
  5. 22
      app/src/main/java/com/fongmi/android/tv/server/Nano.java
  6. 18
      app/src/main/java/com/fongmi/android/tv/server/Server.java
  7. 3
      app/src/main/java/com/fongmi/android/tv/server/process/InputRequestProcess.java
  8. 8
      app/src/main/java/com/fongmi/android/tv/utils/Utils.java

@ -11,6 +11,11 @@ android {
minSdk 21
targetSdk 29
ndk { abiFilters "armeabi-v7a" }
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
productFlavors {

@ -0,0 +1,432 @@
{
"formatVersion": 1,
"database": {
"version": 21,
"identityHash": "0dd6fc8bd9e6415bed916c27d8febede",
"entities": [
{
"tableName": "Keep",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `siteName` TEXT, `vodName` TEXT, `vodPic` TEXT, `createTime` INTEGER NOT NULL, `type` INTEGER NOT NULL, `cid` INTEGER NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "siteName",
"columnName": "siteName",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "vodName",
"columnName": "vodName",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "vodPic",
"columnName": "vodPic",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "createTime",
"columnName": "createTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "cid",
"columnName": "cid",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Site",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `name` TEXT, `searchable` INTEGER, `filterable` INTEGER, `changeable` INTEGER, `activated` INTEGER NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "searchable",
"columnName": "searchable",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "filterable",
"columnName": "filterable",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "changeable",
"columnName": "changeable",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "activated",
"columnName": "activated",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Track",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `group` INTEGER NOT NULL, `track` INTEGER NOT NULL, `player` INTEGER NOT NULL, `key` TEXT, `name` TEXT, `selected` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "group",
"columnName": "group",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "track",
"columnName": "track",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "player",
"columnName": "player",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "selected",
"columnName": "selected",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_Track_key_player_type",
"unique": true,
"columnNames": [
"key",
"player",
"type"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Track_key_player_type` ON `${TABLE_NAME}` (`key`, `player`, `type`)"
}
],
"foreignKeys": []
},
{
"tableName": "Config",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `time` INTEGER NOT NULL, `url` TEXT, `json` TEXT, `name` TEXT, `home` TEXT, `parse` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "json",
"columnName": "json",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "home",
"columnName": "home",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "parse",
"columnName": "parse",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_Config_url_type",
"unique": true,
"columnNames": [
"url",
"type"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Config_url_type` ON `${TABLE_NAME}` (`url`, `type`)"
}
],
"foreignKeys": []
},
{
"tableName": "Device",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uuid` TEXT, `name` TEXT, `ip` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "ip",
"columnName": "ip",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_Device_uuid_name",
"unique": true,
"columnNames": [
"uuid",
"name"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Device_uuid_name` ON `${TABLE_NAME}` (`uuid`, `name`)"
}
],
"foreignKeys": []
},
{
"tableName": "History",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `vodPic` TEXT, `vodName` TEXT, `vodFlag` TEXT, `vodRemarks` TEXT, `episodeUrl` TEXT, `revSort` INTEGER NOT NULL, `revPlay` INTEGER NOT NULL, `createTime` INTEGER NOT NULL, `opening` INTEGER NOT NULL, `ending` INTEGER NOT NULL, `position` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `speed` REAL NOT NULL, `player` INTEGER NOT NULL, `scale` INTEGER NOT NULL, `cid` INTEGER NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "vodPic",
"columnName": "vodPic",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "vodName",
"columnName": "vodName",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "vodFlag",
"columnName": "vodFlag",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "vodRemarks",
"columnName": "vodRemarks",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "episodeUrl",
"columnName": "episodeUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "revSort",
"columnName": "revSort",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "revPlay",
"columnName": "revPlay",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "createTime",
"columnName": "createTime",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "opening",
"columnName": "opening",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ending",
"columnName": "ending",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "speed",
"columnName": "speed",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "player",
"columnName": "player",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "scale",
"columnName": "scale",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "cid",
"columnName": "cid",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0dd6fc8bd9e6415bed916c27d8febede')"
]
}
}

@ -20,12 +20,14 @@ import com.fongmi.android.tv.Updater;
import com.fongmi.android.tv.api.ApiConfig;
import com.fongmi.android.tv.api.LiveConfig;
import com.fongmi.android.tv.api.WallConfig;
import com.fongmi.android.tv.bean.Config;
import com.fongmi.android.tv.bean.Func;
import com.fongmi.android.tv.bean.History;
import com.fongmi.android.tv.bean.Result;
import com.fongmi.android.tv.bean.Site;
import com.fongmi.android.tv.bean.Vod;
import com.fongmi.android.tv.databinding.ActivityHomeBinding;
import com.fongmi.android.tv.event.CastEvent;
import com.fongmi.android.tv.event.RefreshEvent;
import com.fongmi.android.tv.event.ServerEvent;
import com.fongmi.android.tv.model.SiteViewModel;
@ -310,6 +312,33 @@ public class HomeActivity extends BaseActivity implements CustomTitleView.Listen
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onCastEvent(CastEvent event) {
if (ApiConfig.getUrl().equals(event.getUrl())) {
History history = History.objectFrom(event.getHistory());
history.setCid(ApiConfig.getCid());
onItemClick(history.update());
} else {
ApiConfig.get().clear().config(Config.find(event.getUrl(), 0)).load(getCallback(event));
}
}
private Callback getCallback(CastEvent event) {
return new Callback() {
@Override
public void success() {
RefreshEvent.history();
RefreshEvent.video();
onCastEvent(event);
}
@Override
public void error(int resId) {
Notify.show(resId);
}
};
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (Utils.isMenuKey(event)) showDialog();

@ -7,6 +7,8 @@ import androidx.room.PrimaryKey;
import com.fongmi.android.tv.R;
import com.fongmi.android.tv.api.ApiConfig;
import com.fongmi.android.tv.db.AppDatabase;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.util.List;
@ -15,24 +17,45 @@ public class History {
@NonNull
@PrimaryKey
@SerializedName("key")
private String key;
@SerializedName("vodPic")
private String vodPic;
@SerializedName("vodName")
private String vodName;
@SerializedName("vodFlag")
private String vodFlag;
@SerializedName("vodRemarks")
private String vodRemarks;
@SerializedName("episodeUrl")
private String episodeUrl;
@SerializedName("revSort")
private boolean revSort;
@SerializedName("revPlay")
private boolean revPlay;
@SerializedName("createTime")
private long createTime;
@SerializedName("opening")
private long opening;
@SerializedName("ending")
private long ending;
@SerializedName("position")
private long position;
@SerializedName("duration")
private long duration;
@SerializedName("speed")
private float speed;
@SerializedName("player")
private int player;
@SerializedName("scale")
private int scale;
@SerializedName("cid")
private int cid;
public static History objectFrom(String str) {
return new Gson().fromJson(str, History.class);
}
public History() {
this.speed = 1;
this.scale = -1;
@ -228,8 +251,13 @@ public class History {
public void update(long position, long duration) {
setPosition(position);
setDuration(duration);
update();
}
public History update() {
checkMerge(AppDatabase.get().getHistoryDao().findByName(ApiConfig.getCid(), getVodName()));
AppDatabase.get().getHistoryDao().insertOrUpdate(this);
return this;
}
public History delete() {

@ -2,6 +2,7 @@ package com.fongmi.android.tv.server;
import com.fongmi.android.tv.R;
import com.fongmi.android.tv.api.ApiConfig;
import com.fongmi.android.tv.bean.Device;
import com.fongmi.android.tv.server.process.InputRequestProcess;
import com.fongmi.android.tv.server.process.RawRequestProcess;
import com.fongmi.android.tv.server.process.RequestProcess;
@ -71,6 +72,7 @@ public class Nano extends NanoHTTPD {
case GET:
if (url.startsWith("/file")) return doFile(url);
else if (url.startsWith("/proxy")) return doProxy(session.getParms());
else if (url.startsWith("/device")) return createPlainTextResponse(NanoHTTPD.Response.Status.OK, Device.get().toString());
break;
case POST:
if (url.startsWith("/upload")) return doUpload(session.getParms(), files);
@ -99,9 +101,9 @@ public class Nano extends NanoHTTPD {
String path = url.substring(6);
File file = FileUtil.getRootFile(path);
if (file.isFile()) return newChunkedResponse(Response.Status.OK, "application/octet-stream", new FileInputStream(file));
else return newFixedLengthResponse(Response.Status.OK, MIME_PLAINTEXT, listFiles(file));
else return createPlainTextResponse(Response.Status.OK, listFiles(file));
} catch (Exception e) {
return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, e.getMessage());
return createPlainTextResponse(Response.Status.INTERNAL_ERROR, e.getMessage());
}
}
@ -110,7 +112,7 @@ public class Nano extends NanoHTTPD {
Object[] rs = ApiConfig.get().proxyLocal(params);
return newChunkedResponse(Response.Status.lookup((Integer) rs[0]), (String) rs[1], (InputStream) rs[2]);
} catch (Exception e) {
return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "500");
return createPlainTextResponse(Response.Status.INTERNAL_ERROR, "500");
}
}
@ -122,20 +124,20 @@ public class Nano extends NanoHTTPD {
if (fn.toLowerCase().endsWith(".zip")) FileUtil.unzip(temp, FileUtil.getRootPath() + File.separator + path);
else FileUtil.copy(temp, FileUtil.getRootFile(path + File.separator + fn));
}
return newFixedLengthResponse(Response.Status.OK, MIME_PLAINTEXT, "OK");
return createPlainTextResponse(Response.Status.OK, "OK");
}
private Response doNewFolder(Map<String, String> params) {
String path = params.get("path");
String name = params.get("name");
FileUtil.getRootFile(path + File.separator + name).mkdirs();
return newFixedLengthResponse(Response.Status.OK, MIME_PLAINTEXT, "OK");
return createPlainTextResponse(Response.Status.OK, "OK");
}
private Response doDelFolder(Map<String, String> params) {
String path = params.get("path");
FileUtil.clearDir(FileUtil.getRootFile(path));
return newFixedLengthResponse(Response.Status.OK, MIME_PLAINTEXT, "OK");
return createPlainTextResponse(Response.Status.OK, "OK");
}
private String getParent(File root) {
@ -175,10 +177,12 @@ public class Nano extends NanoHTTPD {
public interface Listener {
void onSearch(String text);
void onSearch(String word);
void onPush(String text);
void onPush(String url);
void onApi(String text);
void onApi(String url);
void onCast(String url, String history);
}
}

@ -5,6 +5,7 @@ import android.net.wifi.WifiManager;
import android.text.format.Formatter;
import com.fongmi.android.tv.App;
import com.fongmi.android.tv.event.CastEvent;
import com.fongmi.android.tv.event.ServerEvent;
import java.net.Inet4Address;
@ -86,17 +87,22 @@ public class Server implements Nano.Listener {
}
@Override
public void onSearch(String text) {
if (text.length() > 0) ServerEvent.search(text);
public void onSearch(String word) {
if (word.length() > 0) ServerEvent.search(word);
}
@Override
public void onPush(String text) {
if (text.length() > 0) ServerEvent.push(text);
public void onPush(String url) {
if (url.length() > 0) ServerEvent.push(url);
}
@Override
public void onApi(String text) {
if (text.length() > 0) ServerEvent.api(text);
public void onApi(String url) {
if (url.length() > 0) ServerEvent.api(url);
}
@Override
public void onCast(String url, String history) {
CastEvent.post(url, history);
}
}

@ -33,6 +33,9 @@ public class InputRequestProcess implements RequestProcess {
case "api":
nano.getListener().onApi(params.get("url").trim());
break;
case "cast":
nano.getListener().onCast(params.get("url").trim(), params.get("history").trim());
break;
}
return Nano.createPlainTextResponse(NanoHTTPD.Response.Status.OK, "ok");
}

@ -144,10 +144,16 @@ public class Utils {
}
}
public static String getUUID() {
public static String getDeviceId() {
return Settings.Secure.getString(App.get().getContentResolver(), Settings.Secure.ANDROID_ID);
}
public static String getDeviceName() {
String model = Build.MODEL;
String manufacturer = Build.MANUFACTURER;
return model.startsWith(manufacturer) ? model : manufacturer + " " + model;
}
public static String getBase64(String ext) {
return Base64.encodeToString(ext.getBytes(), Base64.DEFAULT | Base64.NO_WRAP);
}

Loading…
Cancel
Save