diff --git a/.env b/.env
index 354ceca..21b9916 100644
--- a/.env
+++ b/.env
@@ -1,5 +1,4 @@
GITEA_TOKEN=7921aa22187b39125d29399d26f527ba26a2fb5b
-
GEMINI_API_KEY=AIzaSyDWOgyAJqscuPU6iSpS6gxupWBm4soNw5o
-telegram_bot_token:8593525164:AAGCX9B_RJGN35_F7tSB72rEZhS_4Zpcszs
-chat_id:692714536
+TELEGRAM_BOT_TOKEN=8593525164:AAGCX9B_RJGN35_F7tSB72rEZhS_4Zpcszs
+TELEGRAM_CHAT_ID=692714536
diff --git a/app/build.gradle b/app/build.gradle
index 1edb999..891d2d5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "com.streamplayer"
minSdk 21
targetSdk 33
- versionCode 93000
- versionName "9.3.0"
+ versionCode 93100
+ versionName "9.3.1"
buildConfigField "String", "DEVICE_REGISTRY_URL", '"http://194.163.191.200:4000"'
}
diff --git a/app/src/main/java/com/streamplayer/MainActivity.java b/app/src/main/java/com/streamplayer/MainActivity.java
index d6214b6..f214b56 100644
--- a/app/src/main/java/com/streamplayer/MainActivity.java
+++ b/app/src/main/java/com/streamplayer/MainActivity.java
@@ -1,6 +1,9 @@
package com.streamplayer;
import android.app.AlertDialog;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -329,7 +332,24 @@ public class MainActivity extends AppCompatActivity {
.setCancelable(false)
.setPositiveButton(R.string.device_blocked_close,
(dialog, which) -> finish())
- .show();
+ .create();
+ if (!TextUtils.isEmpty(tokenPart)) {
+ blockedDialog.setButton(AlertDialog.BUTTON_NEUTRAL,
+ getString(R.string.device_blocked_copy_token),
+ (dialog, which) -> copyTokenToClipboard(tokenPart));
+ }
+ blockedDialog.show();
+ }
+
+ private void copyTokenToClipboard(String tokenPart) {
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipboard == null) {
+ Toast.makeText(this, R.string.device_blocked_copy_error, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ ClipData data = ClipData.newPlainText("token", tokenPart);
+ clipboard.setPrimaryClip(data);
+ Toast.makeText(this, R.string.device_blocked_copy_success, Toast.LENGTH_SHORT).show();
}
private int getSpanCount() {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 56d49b0..b314f37 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -41,5 +41,8 @@
Sin motivo especificado.
Comparte este código con el administrador para solicitar acceso: %1$s
Salir
+ Copiar código
+ Código copiado al portapapeles
+ No se pudo copiar el código
No se pudo registrar el dispositivo (%1$s)
diff --git a/dashboard/data/devices.json b/dashboard/data/devices.json
index 2bd66b3..8bd2041 100644
--- a/dashboard/data/devices.json
+++ b/dashboard/data/devices.json
@@ -6,13 +6,13 @@
"model": "SM-S928B",
"manufacturer": "Samsung",
"osVersion": "16 (API 36)",
- "appVersionName": "9.2.0",
- "appVersionCode": 92000,
+ "appVersionName": "9.3.0",
+ "appVersionCode": 93000,
"firstSeen": "2025-11-23T20:53:43.615Z",
- "lastSeen": "2025-11-23T21:09:04.607Z",
+ "lastSeen": "2025-11-23T21:12:30.345Z",
"blocked": false,
"notes": "no pagó",
- "installs": 8,
+ "installs": 9,
"blockedAt": "2025-11-23T20:54:05.413Z",
"ip": "181.23.253.20",
"country": "AR",
diff --git a/dashboard/node_modules/.package-lock.json b/dashboard/node_modules/.package-lock.json
index 8ce28ee..21cd5e9 100644
--- a/dashboard/node_modules/.package-lock.json
+++ b/dashboard/node_modules/.package-lock.json
@@ -393,6 +393,18 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
+ "node_modules/dotenv": {
+ "version": "16.6.1",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
+ "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json
index d98c3ca..3c0e5a5 100644
--- a/dashboard/package-lock.json
+++ b/dashboard/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"axios": "^1.6.7",
"cors": "^2.8.5",
+ "dotenv": "^16.4.5",
"express": "^4.18.2",
"geoip-lite": "^1.4.6",
"morgan": "^1.10.0",
@@ -409,6 +410,18 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
+ "node_modules/dotenv": {
+ "version": "16.6.1",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
+ "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
diff --git a/dashboard/package.json b/dashboard/package.json
index 09b7a17..60e5549 100644
--- a/dashboard/package.json
+++ b/dashboard/package.json
@@ -11,6 +11,7 @@
"license": "MIT",
"dependencies": {
"axios": "^1.6.7",
+ "dotenv": "^16.4.5",
"cors": "^2.8.5",
"express": "^4.18.2",
"geoip-lite": "^1.4.6",
diff --git a/dashboard/server.js b/dashboard/server.js
index d48ccf6..be1f95d 100644
--- a/dashboard/server.js
+++ b/dashboard/server.js
@@ -7,6 +7,14 @@ const crypto = require('crypto');
const axios = require('axios');
const requestIp = require('request-ip');
const geoip = require('geoip-lite');
+const dotenv = require('dotenv');
+
+const envPath = path.resolve(__dirname, '..', '.env');
+if (fs.existsSync(envPath)) {
+ dotenv.config({ path: envPath });
+} else {
+ dotenv.config();
+}
const app = express();
const PORT = process.env.PORT || 4000;
diff --git a/update-manifest.json b/update-manifest.json
index d6872ff..f1de133 100644
--- a/update-manifest.json
+++ b/update-manifest.json
@@ -1,10 +1,10 @@
{
- "versionCode": 92000,
- "versionName": "9.2.0",
+ "versionCode": 93000,
+ "versionName": "9.3.0",
"minSupportedVersionCode": 91000,
"forceUpdate": false,
- "downloadUrl": "https://gitea.cbcren.online/renato97/app/releases/download/v9.2.0/StreamPlayer-v9.2.0.apk",
- "fileName": "StreamPlayer-v9.2.0.apk",
- "sizeBytes": 5940764,
- "notes": "StreamPlayer v9.2.0\n\nMejoras en esta versión:\n\n- Interfaz de usuario optimizada para mayor claridad\n- Diálogos de actualización más intuitivos\n- Mejora general en la experiencia de uso\n- Mayor estabilidad y rendimiento\n- Correcciones de errores menores\n\nEsta actualización mejora la usabilidad y mantiene todas las funcionalidades de seguridad y gestión de dispositivos."
+ "downloadUrl": "https://gitea.cbcren.online/renato97/app/releases/download/v9.3.0/StreamPlayer-v9.3.0.apk",
+ "fileName": "StreamPlayer-v9.3.0.apk",
+ "sizeBytes": 5941443,
+ "notes": "StreamPlayer v9.3.0\n\nMejoras importantes en esta versión:\n\n- Sistema de seguridad mejorado con verificación avanzada\n- Nuevas herramientas de administración y control\n- Mejoras en la gestión de dispositivos\n- Interfaz de usuario optimizada\n- Mayor rendimiento y estabilidad\n- Correcciones de seguridad mejoradas\n- Sistema de notificaciones más eficiente\n\nEsta actualización fortalece la seguridad y mejora la experiencia general de uso manteniendo todas las funcionalidades existentes."
}