|
|
@ -4,6 +4,9 @@ import android.annotation.SuppressLint;
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.fox2code.mmm.R;
|
|
|
|
import com.fox2code.mmm.manager.ModuleInfo;
|
|
|
|
import com.fox2code.mmm.manager.ModuleInfo;
|
|
|
|
import com.fox2code.mmm.utils.Files;
|
|
|
|
import com.fox2code.mmm.utils.Files;
|
|
|
|
import com.fox2code.mmm.utils.Http;
|
|
|
|
import com.fox2code.mmm.utils.Http;
|
|
|
@ -27,6 +30,7 @@ import java.util.Map;
|
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.Objects;
|
|
|
|
|
|
|
|
|
|
|
|
public class RepoData {
|
|
|
|
public class RepoData {
|
|
|
|
|
|
|
|
private static final String TAG = "RepoData";
|
|
|
|
private final Object populateLock = new Object();
|
|
|
|
private final Object populateLock = new Object();
|
|
|
|
public final String url;
|
|
|
|
public final String url;
|
|
|
|
public final File cacheRoot;
|
|
|
|
public final File cacheRoot;
|
|
|
@ -36,7 +40,7 @@ public class RepoData {
|
|
|
|
public final HashMap<String, RepoModule> moduleHashMap;
|
|
|
|
public final HashMap<String, RepoModule> moduleHashMap;
|
|
|
|
public long lastUpdate;
|
|
|
|
public long lastUpdate;
|
|
|
|
public String name;
|
|
|
|
public String name;
|
|
|
|
private final Map<String, Long> specialTimes;
|
|
|
|
private final Map<String, SpecialData> specialData;
|
|
|
|
private long specialLastUpdate;
|
|
|
|
private long specialLastUpdate;
|
|
|
|
|
|
|
|
|
|
|
|
protected RepoData(String url, File cacheRoot, SharedPreferences cachedPreferences) {
|
|
|
|
protected RepoData(String url, File cacheRoot, SharedPreferences cachedPreferences) {
|
|
|
@ -51,7 +55,7 @@ public class RepoData {
|
|
|
|
this.special = special;
|
|
|
|
this.special = special;
|
|
|
|
this.moduleHashMap = new HashMap<>();
|
|
|
|
this.moduleHashMap = new HashMap<>();
|
|
|
|
this.name = this.url; // Set url as default name
|
|
|
|
this.name = this.url; // Set url as default name
|
|
|
|
this.specialTimes = special ? new HashMap<>() : Collections.emptyMap();
|
|
|
|
this.specialData = special ? new HashMap<>() : Collections.emptyMap();
|
|
|
|
if (!this.cacheRoot.isDirectory()) {
|
|
|
|
if (!this.cacheRoot.isDirectory()) {
|
|
|
|
this.cacheRoot.mkdirs();
|
|
|
|
this.cacheRoot.mkdirs();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -63,10 +67,13 @@ public class RepoData {
|
|
|
|
Files.read(this.metaDataCache), StandardCharsets.UTF_8));
|
|
|
|
Files.read(this.metaDataCache), StandardCharsets.UTF_8));
|
|
|
|
for (int i = 0; i < jsonArray.length(); i++) {
|
|
|
|
for (int i = 0; i < jsonArray.length(); i++) {
|
|
|
|
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
|
|
|
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
|
|
|
this.specialTimes.put(jsonObject.getString("name"),
|
|
|
|
this.specialData.put(
|
|
|
|
Objects.requireNonNull(ISO_OFFSET_DATE_TIME.parse(
|
|
|
|
jsonObject.getString("name"), new SpecialData(
|
|
|
|
jsonObject.getString("pushed_at"))).getTime());
|
|
|
|
Objects.requireNonNull(ISO_OFFSET_DATE_TIME.parse(
|
|
|
|
Log.d("RepoData", "Got " +
|
|
|
|
jsonObject.getString(
|
|
|
|
|
|
|
|
"pushed_at"))).getTime(),
|
|
|
|
|
|
|
|
jsonObject.optInt("stargazers_count")));
|
|
|
|
|
|
|
|
Log.d(TAG, "Got " +
|
|
|
|
jsonObject.getString("name") + " from local storage!");
|
|
|
|
jsonObject.getString("name") + " from local storage!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.specialLastUpdate = metaDataCacheSpecial.lastModified();
|
|
|
|
this.specialLastUpdate = metaDataCacheSpecial.lastModified();
|
|
|
@ -79,6 +86,10 @@ public class RepoData {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.metaDataCache.exists()) {
|
|
|
|
if (this.metaDataCache.exists()) {
|
|
|
|
|
|
|
|
this.lastUpdate = metaDataCache.lastModified();
|
|
|
|
|
|
|
|
if (this.lastUpdate > System.currentTimeMillis()) {
|
|
|
|
|
|
|
|
this.lastUpdate = 0; // Don't allow time travel
|
|
|
|
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
List<RepoModule> modules = this.populate(new JSONObject(
|
|
|
|
List<RepoModule> modules = this.populate(new JSONObject(
|
|
|
|
new String(Files.read(this.metaDataCache), StandardCharsets.UTF_8)));
|
|
|
|
new String(Files.read(this.metaDataCache), StandardCharsets.UTF_8)));
|
|
|
@ -108,7 +119,6 @@ public class RepoData {
|
|
|
|
for (RepoModule repoModule : this.moduleHashMap.values()) {
|
|
|
|
for (RepoModule repoModule : this.moduleHashMap.values()) {
|
|
|
|
repoModule.processed = false;
|
|
|
|
repoModule.processed = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Log.d("RepoData", "Data: " + this.specialTimes.toString());
|
|
|
|
|
|
|
|
JSONArray array = jsonObject.getJSONArray("modules");
|
|
|
|
JSONArray array = jsonObject.getJSONArray("modules");
|
|
|
|
int len = array.length();
|
|
|
|
int len = array.length();
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
@ -116,16 +126,15 @@ public class RepoData {
|
|
|
|
String moduleId = module.getString("id");
|
|
|
|
String moduleId = module.getString("id");
|
|
|
|
// Deny remote modules ids shorter than 3 chars long or that start with a digit
|
|
|
|
// Deny remote modules ids shorter than 3 chars long or that start with a digit
|
|
|
|
if (moduleId.length() < 3 || Character.isDigit(moduleId.charAt(0))) continue;
|
|
|
|
if (moduleId.length() < 3 || Character.isDigit(moduleId.charAt(0))) continue;
|
|
|
|
Long moduleLastUpdateSpecial = this.specialTimes.get(moduleId);
|
|
|
|
SpecialData moduleSpecialData = this.specialData.get(moduleId);
|
|
|
|
long moduleLastUpdate = module.getLong("last_update");
|
|
|
|
long moduleLastUpdate = module.getLong("last_update");
|
|
|
|
String moduleNotesUrl = module.getString("notes_url");
|
|
|
|
String moduleNotesUrl = module.getString("notes_url");
|
|
|
|
String modulePropsUrl = module.getString("prop_url");
|
|
|
|
String modulePropsUrl = module.getString("prop_url");
|
|
|
|
String moduleZipUrl = module.getString("zip_url");
|
|
|
|
String moduleZipUrl = module.getString("zip_url");
|
|
|
|
String moduleChecksum = module.optString("checksum");
|
|
|
|
String moduleChecksum = module.optString("checksum");
|
|
|
|
if (moduleLastUpdateSpecial != null) { // Fix last update time
|
|
|
|
String moduleStars = module.optString("stars");
|
|
|
|
Log.d("RepoData", "Data: " + moduleLastUpdate + " -> " +
|
|
|
|
if (moduleSpecialData != null) { // Fix last update time
|
|
|
|
moduleLastUpdateSpecial + " for " + moduleId);
|
|
|
|
moduleLastUpdate = Math.max(moduleLastUpdate, moduleSpecialData.time);
|
|
|
|
moduleLastUpdate = Math.max(moduleLastUpdate, moduleLastUpdateSpecial);
|
|
|
|
|
|
|
|
moduleNotesUrl = Http.updateLink(moduleNotesUrl);
|
|
|
|
moduleNotesUrl = Http.updateLink(moduleNotesUrl);
|
|
|
|
modulePropsUrl = Http.updateLink(modulePropsUrl);
|
|
|
|
modulePropsUrl = Http.updateLink(modulePropsUrl);
|
|
|
|
moduleZipUrl = Http.updateLink(moduleZipUrl);
|
|
|
|
moduleZipUrl = Http.updateLink(moduleZipUrl);
|
|
|
@ -152,6 +161,15 @@ public class RepoData {
|
|
|
|
repoModule.propUrl = modulePropsUrl;
|
|
|
|
repoModule.propUrl = modulePropsUrl;
|
|
|
|
repoModule.zipUrl = moduleZipUrl;
|
|
|
|
repoModule.zipUrl = moduleZipUrl;
|
|
|
|
repoModule.checksum = moduleChecksum;
|
|
|
|
repoModule.checksum = moduleChecksum;
|
|
|
|
|
|
|
|
if (moduleSpecialData != null) {
|
|
|
|
|
|
|
|
repoModule.qualityValue = moduleSpecialData.stars;
|
|
|
|
|
|
|
|
repoModule.qualityText = R.string.module_stars;
|
|
|
|
|
|
|
|
} else if (!moduleStars.isEmpty()) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
repoModule.qualityValue = Integer.parseInt(moduleStars);
|
|
|
|
|
|
|
|
repoModule.qualityText = R.string.module_stars;
|
|
|
|
|
|
|
|
} catch (NumberFormatException ignored) {}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Remove no longer existing modules
|
|
|
|
// Remove no longer existing modules
|
|
|
|
Iterator<RepoModule> moduleInfoIterator = this.moduleHashMap.values().iterator();
|
|
|
|
Iterator<RepoModule> moduleInfoIterator = this.moduleHashMap.values().iterator();
|
|
|
@ -184,6 +202,12 @@ public class RepoData {
|
|
|
|
if (moduleInfo.version == null) {
|
|
|
|
if (moduleInfo.version == null) {
|
|
|
|
moduleInfo.version = "v" + moduleInfo.versionCode;
|
|
|
|
moduleInfo.version = "v" + moduleInfo.versionCode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SpecialData moduleSpecialData =
|
|
|
|
|
|
|
|
this.specialData.get(repoModule.id);
|
|
|
|
|
|
|
|
if (moduleSpecialData != null) {
|
|
|
|
|
|
|
|
repoModule.qualityValue = moduleSpecialData.stars;
|
|
|
|
|
|
|
|
repoModule.qualityText = R.string.module_stars;
|
|
|
|
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
} catch (Exception ignored) {
|
|
|
|
} catch (Exception ignored) {
|
|
|
|
file.delete();
|
|
|
|
file.delete();
|
|
|
@ -200,20 +224,24 @@ public class RepoData {
|
|
|
|
public void updateSpecialTimes(boolean force) throws IOException, JSONException {
|
|
|
|
public void updateSpecialTimes(boolean force) throws IOException, JSONException {
|
|
|
|
if (!this.special) return;
|
|
|
|
if (!this.special) return;
|
|
|
|
synchronized (this.populateLock) {
|
|
|
|
synchronized (this.populateLock) {
|
|
|
|
if (this.specialLastUpdate == 0L ||
|
|
|
|
if (this.specialLastUpdate == 0L || (force && (this.specialData.isEmpty() ||
|
|
|
|
(force && this.specialLastUpdate < System.currentTimeMillis() - 60000L)) {
|
|
|
|
this.specialLastUpdate < System.currentTimeMillis() - 60000L))) {
|
|
|
|
File metaDataCacheSpecial = new File(cacheRoot, "modules_times.json");
|
|
|
|
File metaDataCacheSpecial = new File(cacheRoot, "modules_times.json");
|
|
|
|
this.specialTimes.clear();
|
|
|
|
this.specialData.clear();
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
|
|
|
|
// Requesting only 32 most recently pushed repos
|
|
|
|
byte[] data = Http.doHttpGet(
|
|
|
|
byte[] data = Http.doHttpGet(
|
|
|
|
"https://api.github.com/users/Magisk-Modules-Repo/repos",
|
|
|
|
"https://api.github.com/users/Magisk-Modules-Repo/" +
|
|
|
|
false);
|
|
|
|
"repos?sort=pushed&per_page=32", false);
|
|
|
|
JSONArray jsonArray = new JSONArray(new String(data, StandardCharsets.UTF_8));
|
|
|
|
JSONArray jsonArray = new JSONArray(new String(data, StandardCharsets.UTF_8));
|
|
|
|
for (int i = 0;i < jsonArray.length();i++) {
|
|
|
|
for (int i = 0;i < jsonArray.length();i++) {
|
|
|
|
JSONObject jsonObject = jsonArray.optJSONObject(i);
|
|
|
|
JSONObject jsonObject = jsonArray.optJSONObject(i);
|
|
|
|
this.specialTimes.put(jsonObject.getString("name"),
|
|
|
|
this.specialData.put(
|
|
|
|
Objects.requireNonNull(ISO_OFFSET_DATE_TIME.parse(
|
|
|
|
jsonObject.getString("name"), new SpecialData(
|
|
|
|
jsonObject.getString("pushed_at"))).getTime());
|
|
|
|
Objects.requireNonNull(ISO_OFFSET_DATE_TIME.parse(
|
|
|
|
|
|
|
|
jsonObject.getString(
|
|
|
|
|
|
|
|
"pushed_at"))).getTime(),
|
|
|
|
|
|
|
|
jsonObject.optInt("stargazers_count")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Files.write(metaDataCacheSpecial, data);
|
|
|
|
Files.write(metaDataCacheSpecial, data);
|
|
|
|
this.specialLastUpdate = System.currentTimeMillis();
|
|
|
|
this.specialLastUpdate = System.currentTimeMillis();
|
|
|
@ -229,4 +257,22 @@ public class RepoData {
|
|
|
|
this.name.equals(this.url) ?
|
|
|
|
this.name.equals(this.url) ?
|
|
|
|
fallback : this.name;
|
|
|
|
fallback : this.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class SpecialData {
|
|
|
|
|
|
|
|
SpecialData(long time, int stars) {
|
|
|
|
|
|
|
|
this.time = time; this.stars = stars;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final long time;
|
|
|
|
|
|
|
|
final int stars;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public String toString() {
|
|
|
|
|
|
|
|
return "SpecialData{" +
|
|
|
|
|
|
|
|
"time=" + time +
|
|
|
|
|
|
|
|
", stars=" + stars +
|
|
|
|
|
|
|
|
'}';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|