Skip to content

Commit 26fbdac

Browse files
committed
.
1 parent 896a7d7 commit 26fbdac

7 files changed

Lines changed: 632 additions & 2 deletions

File tree

TMessagesProj/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,18 @@
364364
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
365365
</intent-filter>
366366
</activity>
367+
<activity
368+
android:name="org.telegram.ui.LastFmCallbackActivity"
369+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
370+
android:hardwareAccelerated="@bool/useHardwareAcceleration"
371+
android:exported="true">
372+
<intent-filter>
373+
<action android:name="android.intent.action.VIEW" />
374+
<category android:name="android.intent.category.DEFAULT" />
375+
<category android:name="android.intent.category.BROWSABLE" />
376+
<data android:scheme="tg" android:host="lastfm_callback" />
377+
</intent-filter>
378+
</activity>
367379
<!-- <activity-->
368380
<!-- android:name="org.telegram.ui.FeedWidgetConfigActivity"-->
369381
<!-- android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"-->

TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ public class BuildVars {
3333
public static String HUAWEI_STORE_URL = "https://appgallery.huawei.com/app/C101184875";
3434
public static String GOOGLE_AUTH_CLIENT_ID = "760348033671-81kmi3pi84p11ub8hp9a1funsv0rn2p9.apps.googleusercontent.com";
3535

36+
// Last.fm API constants
37+
public static String LASTFM_API_KEY = "YOUR_LASTFM_API_KEY";
38+
public static String LASTFM_API_SECRET = "YOUR_LASTFM_API_SECRET";
39+
public static String LASTFM_API_URL = "https://ws.audioscrobbler.com/2.0/";
3640

3741
// You can use this flag to disable Google Play Billing (If you're making fork and want it to be in Google Play)
3842
public static boolean IS_BILLING_UNAVAILABLE = false;
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
package org.telegram.messenger;
2+
3+
import android.content.Context;
4+
import android.content.SharedPreferences;
5+
6+
import java.security.MessageDigest;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
import java.util.TreeMap;
10+
11+
public class LastFmHelper {
12+
13+
private static LastFmHelper instance;
14+
private SharedPreferences prefs;
15+
16+
public static LastFmHelper getInstance() {
17+
if (instance == null) {
18+
instance = new LastFmHelper();
19+
}
20+
return instance;
21+
}
22+
23+
private LastFmHelper() {
24+
if (ApplicationLoader.applicationContext != null) {
25+
prefs = ApplicationLoader.applicationContext.getSharedPreferences("lastfm", Context.MODE_PRIVATE);
26+
}
27+
}
28+
29+
public boolean isLoggedIn() {
30+
return prefs != null && prefs.getBoolean("logged_in", false);
31+
}
32+
33+
public String getUsername() {
34+
return prefs != null ? prefs.getString("username", "") : "";
35+
}
36+
37+
public void logout() {
38+
if (prefs != null) {
39+
prefs.edit().clear().apply();
40+
}
41+
}
42+
43+
public void login(String username, String password, LoginCallback callback) {
44+
Utilities.globalQueue.postRunnable(() -> {
45+
try {
46+
// Шаг 1: Получаем токен
47+
String token = getToken();
48+
if (token == null) {
49+
AndroidUtilities.runOnUIThread(() -> callback.onError("Failed to get token"));
50+
return;
51+
}
52+
53+
// Шаг 2: Получаем сессию
54+
String sessionKey = getSession(username, password, token);
55+
if (sessionKey != null) {
56+
prefs.edit()
57+
.putBoolean("logged_in", true)
58+
.putString("username", username)
59+
.putString("session_key", sessionKey)
60+
.apply();
61+
AndroidUtilities.runOnUIThread(() -> callback.onSuccess());
62+
} else {
63+
AndroidUtilities.runOnUIThread(() -> callback.onError("Invalid credentials"));
64+
}
65+
} catch (Exception e) {
66+
FileLog.e(e);
67+
AndroidUtilities.runOnUIThread(() -> callback.onError(e.getMessage()));
68+
}
69+
});
70+
}
71+
72+
public interface LoginCallback {
73+
void onSuccess();
74+
void onError(String error);
75+
}
76+
77+
public void scrobbleTrack(String artist, String track, String album, long timestamp) {
78+
if (!isLoggedIn() || artist == null || track == null) {
79+
return;
80+
}
81+
82+
Map<String, String> params = new HashMap<>();
83+
params.put("method", "track.scrobble");
84+
params.put("api_key", BuildVars.LASTFM_API_KEY);
85+
params.put("artist", artist);
86+
params.put("track", track);
87+
if (album != null) {
88+
params.put("album", album);
89+
}
90+
params.put("timestamp", String.valueOf(timestamp));
91+
params.put("sk", getSessionKey());
92+
params.put("api_sig", generateApiSignature(params));
93+
94+
// Отправляем запрос в фоновом потоке
95+
Utilities.globalQueue.postRunnable(() -> {
96+
try {
97+
sendPostRequestVoid(params);
98+
if (BuildVars.LOGS_ENABLED) {
99+
FileLog.d("Last.fm scrobbled: " + artist + " - " + track);
100+
}
101+
} catch (Exception e) {
102+
FileLog.e(e);
103+
}
104+
});
105+
}
106+
107+
public void updateNowPlaying(String artist, String track, String album) {
108+
if (!isLoggedIn() || artist == null || track == null) {
109+
return;
110+
}
111+
112+
Map<String, String> params = new HashMap<>();
113+
params.put("method", "track.updateNowPlaying");
114+
params.put("api_key", BuildVars.LASTFM_API_KEY);
115+
params.put("artist", artist);
116+
params.put("track", track);
117+
if (album != null) {
118+
params.put("album", album);
119+
}
120+
params.put("sk", getSessionKey());
121+
params.put("api_sig", generateApiSignature(params));
122+
123+
// Отправляем запрос в фоновом потоке
124+
Utilities.globalQueue.postRunnable(() -> {
125+
try {
126+
sendPostRequestVoid(params);
127+
if (BuildVars.LOGS_ENABLED) {
128+
FileLog.d("Last.fm now playing: " + artist + " - " + track);
129+
}
130+
} catch (Exception e) {
131+
FileLog.e(e);
132+
}
133+
});
134+
}
135+
136+
private String getSessionKey() {
137+
return prefs != null ? prefs.getString("session_key", "") : "";
138+
}
139+
140+
public String generateApiSignature(Map<String, String> params) {
141+
TreeMap<String, String> sortedParams = new TreeMap<>(params);
142+
StringBuilder signature = new StringBuilder();
143+
144+
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
145+
signature.append(entry.getKey()).append(entry.getValue());
146+
}
147+
signature.append(BuildVars.LASTFM_API_SECRET);
148+
149+
return md5(signature.toString());
150+
}
151+
152+
private String md5(String input) {
153+
try {
154+
MessageDigest md = MessageDigest.getInstance("MD5");
155+
byte[] messageDigest = md.digest(input.getBytes());
156+
StringBuilder hexString = new StringBuilder();
157+
for (byte b : messageDigest) {
158+
String hex = Integer.toHexString(0xff & b);
159+
if (hex.length() == 1) {
160+
hexString.append('0');
161+
}
162+
hexString.append(hex);
163+
}
164+
return hexString.toString();
165+
} catch (Exception e) {
166+
return "";
167+
}
168+
}
169+
170+
private String getToken() {
171+
try {
172+
Map<String, String> params = new HashMap<>();
173+
params.put("method", "auth.getToken");
174+
params.put("api_key", BuildVars.LASTFM_API_KEY);
175+
params.put("api_sig", generateApiSignature(params));
176+
177+
String response = sendGetRequest(params);
178+
// Парсим XML ответ для получения токена
179+
// Упрощенная реализация - в реальном проекте нужен XML парсер
180+
if (response != null && response.contains("<token>")) {
181+
int start = response.indexOf("<token>") + 7;
182+
int end = response.indexOf("</token>");
183+
if (start > 6 && end > start) {
184+
return response.substring(start, end);
185+
}
186+
}
187+
} catch (Exception e) {
188+
FileLog.e(e);
189+
}
190+
return null;
191+
}
192+
193+
private String getSession(String username, String password, String token) {
194+
try {
195+
Map<String, String> params = new HashMap<>();
196+
params.put("method", "auth.getMobileSession");
197+
params.put("api_key", BuildVars.LASTFM_API_KEY);
198+
params.put("username", username);
199+
params.put("password", password);
200+
params.put("api_sig", generateApiSignature(params));
201+
202+
String response = sendPostRequest(params);
203+
// Парсим XML ответ для получения ключа сессии
204+
if (response != null && response.contains("<key>")) {
205+
int start = response.indexOf("<key>") + 5;
206+
int end = response.indexOf("</key>");
207+
if (start > 4 && end > start) {
208+
return response.substring(start, end);
209+
}
210+
}
211+
} catch (Exception e) {
212+
FileLog.e(e);
213+
}
214+
return null;
215+
}
216+
217+
private String sendGetRequest(Map<String, String> params) {
218+
try {
219+
StringBuilder urlBuilder = new StringBuilder(BuildVars.LASTFM_API_URL + "?");
220+
for (Map.Entry<String, String> entry : params.entrySet()) {
221+
if (urlBuilder.length() > BuildVars.LASTFM_API_URL.length() + 1) {
222+
urlBuilder.append('&');
223+
}
224+
urlBuilder.append(java.net.URLEncoder.encode(entry.getKey(), "UTF-8"));
225+
urlBuilder.append('=');
226+
urlBuilder.append(java.net.URLEncoder.encode(entry.getValue(), "UTF-8"));
227+
}
228+
229+
java.net.URL url = new java.net.URL(urlBuilder.toString());
230+
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
231+
connection.setRequestMethod("GET");
232+
233+
int responseCode = connection.getResponseCode();
234+
if (responseCode == 200) {
235+
java.io.BufferedReader reader = new java.io.BufferedReader(
236+
new java.io.InputStreamReader(connection.getInputStream()));
237+
StringBuilder response = new StringBuilder();
238+
String line;
239+
while ((line = reader.readLine()) != null) {
240+
response.append(line);
241+
}
242+
reader.close();
243+
connection.disconnect();
244+
return response.toString();
245+
}
246+
connection.disconnect();
247+
} catch (Exception e) {
248+
FileLog.e(e);
249+
}
250+
return null;
251+
}
252+
253+
private String sendPostRequest(Map<String, String> params) {
254+
try {
255+
java.net.URL url = new java.net.URL(BuildVars.LASTFM_API_URL);
256+
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
257+
connection.setRequestMethod("POST");
258+
connection.setDoOutput(true);
259+
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
260+
261+
StringBuilder postData = new StringBuilder();
262+
for (Map.Entry<String, String> entry : params.entrySet()) {
263+
if (postData.length() != 0) {
264+
postData.append('&');
265+
}
266+
postData.append(java.net.URLEncoder.encode(entry.getKey(), "UTF-8"));
267+
postData.append('=');
268+
postData.append(java.net.URLEncoder.encode(entry.getValue(), "UTF-8"));
269+
}
270+
271+
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
272+
connection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
273+
connection.getOutputStream().write(postDataBytes);
274+
275+
int responseCode = connection.getResponseCode();
276+
if (responseCode == 200) {
277+
java.io.BufferedReader reader = new java.io.BufferedReader(
278+
new java.io.InputStreamReader(connection.getInputStream()));
279+
StringBuilder response = new StringBuilder();
280+
String line;
281+
while ((line = reader.readLine()) != null) {
282+
response.append(line);
283+
}
284+
reader.close();
285+
connection.disconnect();
286+
return response.toString();
287+
}
288+
289+
if (BuildVars.LOGS_ENABLED) {
290+
FileLog.d("Last.fm API response code: " + responseCode);
291+
}
292+
293+
connection.disconnect();
294+
} catch (Exception e) {
295+
FileLog.e(e);
296+
}
297+
return null;
298+
}
299+
300+
private void sendPostRequestVoid(Map<String, String> params) {
301+
try {
302+
java.net.URL url = new java.net.URL(BuildVars.LASTFM_API_URL);
303+
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
304+
connection.setRequestMethod("POST");
305+
connection.setDoOutput(true);
306+
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
307+
308+
StringBuilder postData = new StringBuilder();
309+
for (Map.Entry<String, String> entry : params.entrySet()) {
310+
if (postData.length() != 0) {
311+
postData.append('&');
312+
}
313+
postData.append(java.net.URLEncoder.encode(entry.getKey(), "UTF-8"));
314+
postData.append('=');
315+
postData.append(java.net.URLEncoder.encode(entry.getValue(), "UTF-8"));
316+
}
317+
318+
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
319+
connection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
320+
connection.getOutputStream().write(postDataBytes);
321+
322+
int responseCode = connection.getResponseCode();
323+
if (BuildVars.LOGS_ENABLED) {
324+
FileLog.d("Last.fm API response code: " + responseCode);
325+
}
326+
327+
connection.disconnect();
328+
} catch (Exception e) {
329+
FileLog.e(e);
330+
}
331+
}
332+
}

TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3804,6 +3804,18 @@ public void onStateChanged(boolean playWhenReady, int playbackState) {
38043804
if (playbackState == ExoPlayer.STATE_ENDED || (playbackState == ExoPlayer.STATE_IDLE || playbackState == ExoPlayer.STATE_BUFFERING) && playWhenReady && messageObject.audioProgress >= 0.999f) {
38053805
messageObject.audioProgress = 1f;
38063806
NotificationCenter.getInstance(messageObject.currentAccount).postNotificationName(NotificationCenter.messagePlayingProgressDidChanged, messageObject.getId(), 0);
3807+
3808+
if (messageObject.isMusic() && messageObject.getDuration() > 30) {
3809+
String artist = messageObject.getMusicAuthor();
3810+
String track = messageObject.getMusicTitle();
3811+
String album = null;
3812+
if (audioInfo != null && !TextUtils.isEmpty(audioInfo.getAlbum())) {
3813+
album = audioInfo.getAlbum();
3814+
}
3815+
long timestamp = System.currentTimeMillis() / 1000;
3816+
LastFmHelper.getInstance().scrobbleTrack(artist, track, album, timestamp);
3817+
}
3818+
38073819
final boolean restored = restoreMusicPlaylistState();
38083820
if (!restored) {
38093821
if (!playlist.isEmpty() && (playlist.size() > 1 || !messageObject.isVoice())) {
@@ -3963,6 +3975,16 @@ public boolean needUpdate() {
39633975
}
39643976
startProgressTimer(playingMessageObject);
39653977
NotificationCenter.getInstance(messageObject.currentAccount).postNotificationName(NotificationCenter.messagePlayingDidStart, messageObject, oldMessageObject);
3978+
3979+
if (messageObject.isMusic()) {
3980+
String artist = messageObject.getMusicAuthor();
3981+
String track = messageObject.getMusicTitle();
3982+
String album = null;
3983+
if (audioInfo != null && !TextUtils.isEmpty(audioInfo.getAlbum())) {
3984+
album = audioInfo.getAlbum();
3985+
}
3986+
LastFmHelper.getInstance().updateNowPlaying(artist, track, album);
3987+
}
39663988

39673989
if (videoPlayer != null) {
39683990
try {

0 commit comments

Comments
 (0)