|
|
|
|
@ -20,48 +20,58 @@ import com.github.catvod.net.OkHttp; |
|
|
|
|
import java.text.SimpleDateFormat; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.Date; |
|
|
|
|
import java.util.Iterator; |
|
|
|
|
import java.util.EnumMap; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Locale; |
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.TimeZone; |
|
|
|
|
import java.util.concurrent.Callable; |
|
|
|
|
import java.util.concurrent.ExecutorService; |
|
|
|
|
import java.util.concurrent.Executors; |
|
|
|
|
import java.util.concurrent.Future; |
|
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
|
|
|
|
|
|
public class LiveViewModel extends ViewModel { |
|
|
|
|
|
|
|
|
|
private static final int LIVE = 0; |
|
|
|
|
private static final int EPG = 1; |
|
|
|
|
private static final int URL = 2; |
|
|
|
|
private static final int XML = 3; |
|
|
|
|
private enum TaskType { |
|
|
|
|
|
|
|
|
|
LIVE(Constant.TIMEOUT_LIVE), |
|
|
|
|
EPG(Constant.TIMEOUT_EPG), |
|
|
|
|
XML(Constant.TIMEOUT_XML), |
|
|
|
|
URL(Constant.TIMEOUT_PARSE_LIVE); |
|
|
|
|
|
|
|
|
|
final long timeout; |
|
|
|
|
|
|
|
|
|
TaskType(long timeout) { |
|
|
|
|
this.timeout = timeout; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private final List<SimpleDateFormat> formatTime; |
|
|
|
|
private final Map<TaskType, Future<?>> futures; |
|
|
|
|
private final SimpleDateFormat formatDate; |
|
|
|
|
private final ExecutorService executor; |
|
|
|
|
|
|
|
|
|
public MutableLiveData<Channel> url; |
|
|
|
|
public MutableLiveData<Boolean> xml; |
|
|
|
|
public MutableLiveData<Live> live; |
|
|
|
|
public MutableLiveData<Epg> epg; |
|
|
|
|
|
|
|
|
|
private ExecutorService executor1; |
|
|
|
|
private ExecutorService executor2; |
|
|
|
|
private ExecutorService executor3; |
|
|
|
|
private ExecutorService executor4; |
|
|
|
|
public final MutableLiveData<Channel> url; |
|
|
|
|
public final MutableLiveData<Boolean> xml; |
|
|
|
|
public final MutableLiveData<Live> live; |
|
|
|
|
public final MutableLiveData<Epg> epg; |
|
|
|
|
|
|
|
|
|
public LiveViewModel() { |
|
|
|
|
this.live = new MutableLiveData<>(); |
|
|
|
|
this.epg = new MutableLiveData<>(); |
|
|
|
|
this.url = new MutableLiveData<>(); |
|
|
|
|
this.xml = new MutableLiveData<>(); |
|
|
|
|
this.url = new MutableLiveData<>(); |
|
|
|
|
this.formatTime = new ArrayList<>(); |
|
|
|
|
this.futures = new EnumMap<>(TaskType.class); |
|
|
|
|
this.executor = Executors.newFixedThreadPool(4); |
|
|
|
|
this.formatDate = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); |
|
|
|
|
this.formatTime.add(new SimpleDateFormat("yyyy-MM-ddHH:mm", Locale.getDefault())); |
|
|
|
|
this.formatTime.add(new SimpleDateFormat("yyyy-MM-ddHH:mm:ss", Locale.getDefault())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void getLive(Live item) { |
|
|
|
|
execute(LIVE, () -> { |
|
|
|
|
execute(TaskType.LIVE, () -> { |
|
|
|
|
LiveParser.start(item.recent()); |
|
|
|
|
setTimeZone(item); |
|
|
|
|
verify(item); |
|
|
|
|
@ -70,7 +80,7 @@ public class LiveViewModel extends ViewModel { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void getXml(Live item) { |
|
|
|
|
execute(XML, () -> { |
|
|
|
|
execute(TaskType.XML, () -> { |
|
|
|
|
boolean result = false; |
|
|
|
|
for (String url : item.getEpgXml()) if (parseXml(item, url)) result = true; |
|
|
|
|
return result; |
|
|
|
|
@ -88,14 +98,14 @@ public class LiveViewModel extends ViewModel { |
|
|
|
|
public void getEpg(Channel item) { |
|
|
|
|
String date = formatDate.format(new Date()); |
|
|
|
|
String url = item.getEpg().replace("{date}", date); |
|
|
|
|
execute(EPG, () -> { |
|
|
|
|
execute(TaskType.EPG, () -> { |
|
|
|
|
if (url.startsWith("http") && !item.getData().equal(date)) item.setData(Epg.objectFrom(OkHttp.string(url), item.getTvgId(), formatTime)); |
|
|
|
|
return item.getData().selected(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void getUrl(Channel item) { |
|
|
|
|
execute(URL, () -> { |
|
|
|
|
execute(TaskType.URL, () -> { |
|
|
|
|
item.setMsg(null); |
|
|
|
|
Source.get().stop(); |
|
|
|
|
item.setUrl(Source.get().fetch(item)); |
|
|
|
|
@ -104,7 +114,7 @@ public class LiveViewModel extends ViewModel { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void getUrl(Channel item, EpgData data) { |
|
|
|
|
execute(URL, () -> { |
|
|
|
|
execute(TaskType.URL, () -> { |
|
|
|
|
item.setMsg(null); |
|
|
|
|
Source.get().stop(); |
|
|
|
|
item.setUrl(item.getCatchup().format(Source.get().fetch(item), data)); |
|
|
|
|
@ -122,63 +132,43 @@ public class LiveViewModel extends ViewModel { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void verify(Live item) { |
|
|
|
|
Iterator<Group> iterator = item.getGroups().iterator(); |
|
|
|
|
while (iterator.hasNext()) if (iterator.next().isEmpty()) iterator.remove(); |
|
|
|
|
item.getGroups().removeIf(Group::isEmpty); |
|
|
|
|
if (item.getGroups().isEmpty() || item.getGroups().get(0).isKeep()) return; |
|
|
|
|
item.getGroups().add(0, Group.create(R.string.keep)); |
|
|
|
|
LiveConfig.get().setKeep(item.getGroups()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void execute(int type, Callable<?> callable) { |
|
|
|
|
switch (type) { |
|
|
|
|
case LIVE: |
|
|
|
|
if (executor1 != null) executor1.shutdownNow(); |
|
|
|
|
executor1 = Executors.newFixedThreadPool(2); |
|
|
|
|
executor1.execute(runnable(type, callable, executor1)); |
|
|
|
|
break; |
|
|
|
|
case EPG: |
|
|
|
|
if (executor2 != null) executor2.shutdownNow(); |
|
|
|
|
executor2 = Executors.newFixedThreadPool(2); |
|
|
|
|
executor2.execute(runnable(type, callable, executor2)); |
|
|
|
|
break; |
|
|
|
|
case URL: |
|
|
|
|
if (executor3 != null) executor3.shutdownNow(); |
|
|
|
|
executor3 = Executors.newFixedThreadPool(2); |
|
|
|
|
executor3.execute(runnable(type, callable, executor3)); |
|
|
|
|
break; |
|
|
|
|
case XML: |
|
|
|
|
if (executor4 != null) executor4.shutdownNow(); |
|
|
|
|
executor4 = Executors.newFixedThreadPool(2); |
|
|
|
|
executor4.execute(runnable(type, callable, executor4)); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private Runnable runnable(int type, Callable<?> callable, ExecutorService executor) { |
|
|
|
|
return () -> { |
|
|
|
|
private <T> void execute(TaskType type, Callable<T> callable) { |
|
|
|
|
Future<?> oldFuture = futures.get(type); |
|
|
|
|
if (oldFuture != null && !oldFuture.isDone()) oldFuture.cancel(true); |
|
|
|
|
final Future<T> newFuture = executor.submit(callable); |
|
|
|
|
futures.put(type, newFuture); |
|
|
|
|
executor.execute(() -> { |
|
|
|
|
try { |
|
|
|
|
if (Thread.interrupted()) return; |
|
|
|
|
if (type == EPG) epg.postValue((Epg) executor.submit(callable).get(Constant.TIMEOUT_EPG, TimeUnit.MILLISECONDS)); |
|
|
|
|
if (type == LIVE) live.postValue((Live) executor.submit(callable).get(Constant.TIMEOUT_LIVE, TimeUnit.MILLISECONDS)); |
|
|
|
|
if (type == XML) xml.postValue((Boolean) executor.submit(callable).get(Constant.TIMEOUT_XML, TimeUnit.MILLISECONDS)); |
|
|
|
|
if (type == URL) url.postValue((Channel) executor.submit(callable).get(Constant.TIMEOUT_PARSE_LIVE, TimeUnit.MILLISECONDS)); |
|
|
|
|
T result = newFuture.get(type.timeout, TimeUnit.MILLISECONDS); |
|
|
|
|
if (newFuture.isCancelled()) return; |
|
|
|
|
if (type == TaskType.EPG) epg.postValue((Epg) result); |
|
|
|
|
else if (type == TaskType.LIVE) live.postValue((Live) result); |
|
|
|
|
else if (type == TaskType.XML) xml.postValue((Boolean) result); |
|
|
|
|
else if (type == TaskType.URL) url.postValue((Channel) result); |
|
|
|
|
} catch (InterruptedException e) { |
|
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
|
} catch (Throwable e) { |
|
|
|
|
if (e instanceof InterruptedException || Thread.interrupted()) return; |
|
|
|
|
if (newFuture.isCancelled()) return; |
|
|
|
|
if (e.getCause() instanceof ExtractException) url.postValue(Channel.error(e.getCause().getMessage())); |
|
|
|
|
else if (type == URL) url.postValue(new Channel()); |
|
|
|
|
if (type == LIVE) live.postValue(new Live()); |
|
|
|
|
if (type == EPG) epg.postValue(new Epg()); |
|
|
|
|
if (type == XML) xml.postValue(false); |
|
|
|
|
else if (type == TaskType.URL) url.postValue(new Channel()); |
|
|
|
|
else if (type == TaskType.LIVE) live.postValue(new Live()); |
|
|
|
|
else if (type == TaskType.EPG) epg.postValue(new Epg()); |
|
|
|
|
else if (type == TaskType.XML) xml.postValue(false); |
|
|
|
|
e.printStackTrace(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
protected void onCleared() { |
|
|
|
|
if (executor1 != null) executor1.shutdownNow(); |
|
|
|
|
if (executor2 != null) executor2.shutdownNow(); |
|
|
|
|
if (executor3 != null) executor3.shutdownNow(); |
|
|
|
|
if (executor4 != null) executor4.shutdownNow(); |
|
|
|
|
super.onCleared(); |
|
|
|
|
for (Future<?> future : futures.values()) if (future != null) future.cancel(true); |
|
|
|
|
if (executor != null) executor.shutdownNow(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |