├── .gitignore ├── LICENSE ├── MiniVK ├── .gitignore ├── .idea │ ├── .gitignore │ ├── .name │ ├── compiler.xml │ ├── gradle.xml │ └── misc.xml ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ ├── release │ │ ├── app-release.apk1 │ │ └── output-metadata.json │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── monobogdan │ │ │ └── minivk │ │ │ ├── BitmapCache.java │ │ │ ├── PersistStorage.java │ │ │ ├── Preferences.java │ │ │ ├── api │ │ │ ├── VK.java │ │ │ └── VKDataSet.java │ │ │ ├── service │ │ │ ├── AudioDownloader.java │ │ │ └── PollService.java │ │ │ └── ui │ │ │ ├── AuthActivity.java │ │ │ ├── ChatActivity.java │ │ │ ├── DialogsActivity.java │ │ │ ├── MainMenu.java │ │ │ ├── MusicActivity.java │ │ │ ├── UIUtils.java │ │ │ ├── UserPopupWindow.java │ │ │ └── VKActivity.java │ │ └── res │ │ ├── drawable │ │ ├── chat.png │ │ ├── divider.xml │ │ ├── download.png │ │ ├── headphone.png │ │ ├── menu_item.png │ │ ├── music.png │ │ ├── search.png │ │ └── vk.png │ │ ├── layout │ │ ├── activity_audio.xml │ │ ├── activity_auth.xml │ │ ├── activity_chat.xml │ │ ├── activity_main.xml │ │ ├── dialog_search.xml │ │ ├── frag_audio.xml │ │ ├── frag_dialog.xml │ │ ├── frag_menu.xml │ │ ├── frag_message.xml │ │ ├── overlay_menu.xml │ │ ├── popup_profile.xml │ │ └── test.xml │ │ └── values │ │ ├── strings.xml │ │ └── theme.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── MiniVKv2 ├── .gitignore ├── .idea │ ├── .gitignore │ ├── .name │ ├── compiler.xml │ ├── gradle.xml │ ├── misc.xml │ └── render.experimental.xml ├── app │ ├── .gitignore │ ├── build.gradle │ ├── jackson-annotations-2.11.1.jar │ ├── jackson-core-2.11.1.jar │ ├── jackson-databind-2.11.1.jar │ └── proguard-rules.pro ├── build.gradle ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── README.md ├── TinyYT ├── .gitignore ├── .idea │ ├── .gitignore │ ├── .name │ ├── compiler.xml │ ├── gradle.xml │ └── misc.xml ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ ├── release │ │ ├── app-release.apk1 │ │ └── output-metadata.json │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── monobogdan │ │ │ └── miniyt │ │ │ ├── backend │ │ │ ├── History.java │ │ │ ├── VideoDownloader.java │ │ │ └── YTAPI.java │ │ │ ├── ui │ │ │ └── MainActivity.java │ │ │ └── utils │ │ │ └── SSLFucker.java │ │ └── res │ │ ├── drawable │ │ ├── history.png │ │ ├── search.png │ │ ├── star.png │ │ ├── trending.png │ │ └── youtube.png │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_video.xml │ │ ├── frag_tab.xml │ │ └── frag_video.xml │ │ ├── values │ │ └── strings.xml │ │ └── xml │ │ └── network_security_config.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── release └── output-metadata.json └── vkrelay ├── apirelay.php └── audiorelay.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /MiniVK/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /MiniVK/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /MiniVK/.idea/.name: -------------------------------------------------------------------------------- 1 | MiniVK -------------------------------------------------------------------------------- /MiniVK/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MiniVK/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /MiniVK/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /MiniVK/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /MiniVK/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | namespace 'com.monobogdan.minivk' 7 | compileSdk 8 8 | buildToolsVersion '17.0.0' 9 | 10 | defaultConfig { 11 | applicationId "com.monobogdan.minivk" 12 | minSdk 3 13 | //noinspection ExpiredTargetSdkVersion 14 | targetSdk 3 15 | versionCode 11 16 | versionName "1.01" 17 | } 18 | 19 | buildTypes { 20 | debug { 21 | zipAlignEnabled false 22 | } 23 | release { 24 | minifyEnabled false 25 | 26 | } 27 | } 28 | compileOptions { 29 | sourceCompatibility JavaVersion.VERSION_1_8 30 | targetCompatibility JavaVersion.VERSION_1_8 31 | } 32 | } 33 | 34 | dependencies { 35 | 36 | } -------------------------------------------------------------------------------- /MiniVK/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /MiniVK/app/release/app-release.apk1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/monobogdan/selfeco/9d4cd71ae0f524f9bc41394197a167cb4bdd5d08/MiniVK/app/release/app-release.apk1 -------------------------------------------------------------------------------- /MiniVK/app/release/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "com.monobogdan.minivk", 8 | "variantName": "release", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "attributes": [], 14 | "versionCode": 1, 15 | "versionName": "1.0", 16 | "outputFile": "app-release.apk" 17 | } 18 | ], 19 | "elementType": "File" 20 | } -------------------------------------------------------------------------------- /MiniVK/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /MiniVK/app/src/main/java/com/monobogdan/minivk/BitmapCache.java: -------------------------------------------------------------------------------- 1 | package com.monobogdan.minivk; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.net.Uri; 8 | import android.util.Log; 9 | 10 | import java.io.BufferedInputStream; 11 | import java.io.BufferedReader; 12 | import java.io.File; 13 | import java.io.FileOutputStream; 14 | import java.io.InputStream; 15 | import java.io.InputStreamReader; 16 | import java.net.URL; 17 | import java.util.HashMap; 18 | import java.util.WeakHashMap; 19 | import java.util.concurrent.Executor; 20 | import java.util.concurrent.ExecutorService; 21 | import java.util.concurrent.Executors; 22 | 23 | import javax.net.ssl.HttpsURLConnection; 24 | 25 | public class BitmapCache { 26 | 27 | class LifetimedBitmap 28 | { 29 | Bitmap bitmap; 30 | int lifeTime; 31 | } 32 | 33 | private static ExecutorService threadPool; 34 | private static HashMap cache; 35 | 36 | public static interface CacheCallback 37 | { 38 | void success(Bitmap bitmap); 39 | } 40 | 41 | static 42 | { 43 | cache = new HashMap<>(); 44 | threadPool = Executors.newSingleThreadExecutor(); 45 | } 46 | 47 | public static byte[] downloadBinary(Uri uri) 48 | { 49 | try 50 | { 51 | HttpsURLConnection conn = (HttpsURLConnection) new URL(uri.toString()).openConnection(); 52 | conn.setDoInput(true); 53 | conn.setRequestMethod("GET"); 54 | conn.connect(); 55 | 56 | BufferedInputStream stream = new BufferedInputStream(conn.getInputStream()); 57 | byte[] ret = new byte[conn.getContentLength()]; 58 | 59 | int ptr = 0; 60 | while(ptr < ret.length) 61 | ptr += stream.read(ret, ptr, ret.length - ptr); 62 | 63 | return ret; 64 | } 65 | catch (Exception e) 66 | { 67 | e.printStackTrace(); 68 | 69 | return null; 70 | } 71 | } 72 | 73 | public static void getBitmapFromCache(Context ctx, Uri uri, CacheCallback cb) 74 | { 75 | File cacheDir = ctx.getCacheDir(); 76 | File absPath = new File(cacheDir.getAbsolutePath() + "/" + new File(uri.toString()).getName()); 77 | 78 | if(absPath.exists()) { 79 | threadPool.submit(new Runnable() { 80 | @Override 81 | public void run() { 82 | Bitmap bmp = null; 83 | 84 | if(cache.containsKey(absPath.getName())) { 85 | bmp = cache.get(absPath.getName()); 86 | } 87 | else 88 | { 89 | bmp = BitmapFactory.decodeFile(absPath.getAbsolutePath()); 90 | cache.put(absPath.getName(), bmp); 91 | } 92 | 93 | cb.success(bmp); 94 | } 95 | }); 96 | } 97 | else 98 | { 99 | threadPool.submit(new Runnable() { 100 | @Override 101 | public void run() { 102 | byte[] data = downloadBinary(uri); 103 | 104 | if(data != null) 105 | { 106 | try { 107 | FileOutputStream strm = new FileOutputStream(absPath.getAbsolutePath()); 108 | strm.write(data); 109 | strm.close(); 110 | 111 | cb.success(BitmapFactory.decodeByteArray(data, 0, data.length)); 112 | } 113 | catch(Exception e) 114 | { 115 | e.printStackTrace(); 116 | } 117 | } 118 | } 119 | }); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /MiniVK/app/src/main/java/com/monobogdan/minivk/PersistStorage.java: -------------------------------------------------------------------------------- 1 | package com.monobogdan.minivk; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import org.json.JSONObject; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.File; 10 | import java.io.FileInputStream; 11 | import java.io.FileOutputStream; 12 | import java.io.InputStreamReader; 13 | import java.io.OutputStreamWriter; 14 | 15 | public class PersistStorage { 16 | private static PersistStorage appInstance; 17 | 18 | private final int PERSIST_VERSION = 100; 19 | private final String TAG = "PersistStorage"; 20 | private final String FILENAME = "/minivk.obj"; 21 | 22 | public String apiToken; 23 | public String secret; 24 | public String uid; 25 | public String audioToken; 26 | 27 | public static PersistStorage getAppInstance() { 28 | if(appInstance == null) 29 | appInstance = new PersistStorage(); 30 | 31 | return appInstance; 32 | } 33 | 34 | private PersistStorage() 35 | { 36 | 37 | } 38 | 39 | public boolean isAuthorized() 40 | { 41 | return apiToken != null && apiToken.length() > 0; 42 | } 43 | 44 | public void load(Context context) 45 | { 46 | File file = new File(context.getFilesDir().getAbsolutePath() + FILENAME); 47 | 48 | try { 49 | BufferedReader strm = new BufferedReader(new InputStreamReader(new FileInputStream(file))); 50 | String json = ""; 51 | 52 | while(strm.ready()) 53 | json += strm.readLine(); 54 | strm.close(); 55 | 56 | JSONObject obj = new JSONObject(json); 57 | apiToken = obj.getString("apiToken"); 58 | uid = obj.getString("uid"); 59 | secret = obj.getString("secret"); 60 | audioToken = obj.getString("audioToken"); 61 | } 62 | catch(Exception e) 63 | { 64 | Log.i(TAG, "save: Failed to load PersistStorage"); 65 | } 66 | } 67 | 68 | public void save(Context context) 69 | { 70 | File file = new File(context.getFilesDir().getAbsolutePath() + FILENAME); 71 | 72 | try { 73 | OutputStreamWriter strm = new OutputStreamWriter(new FileOutputStream(file)); 74 | 75 | JSONObject obj = new JSONObject(); 76 | obj.put("version", PERSIST_VERSION); 77 | obj.put("apiToken", apiToken); 78 | obj.put("uid", uid); 79 | obj.put("secret", secret); 80 | obj.put("audioToken", audioToken); 81 | 82 | strm.write(obj.toString()); 83 | strm.close(); 84 | } 85 | catch(Exception e) 86 | { 87 | Log.i(TAG, "save: Failed to save PersistStorage"); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /MiniVK/app/src/main/java/com/monobogdan/minivk/Preferences.java: -------------------------------------------------------------------------------- 1 | package com.monobogdan.minivk; 2 | 3 | import android.os.Bundle; 4 | import android.preference.PreferenceActivity; 5 | 6 | public class Preferences extends PreferenceActivity { 7 | @Override 8 | protected void onCreate(Bundle savedInstanceState) { 9 | super.onCreate(savedInstanceState); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MiniVK/app/src/main/java/com/monobogdan/minivk/api/VK.java: -------------------------------------------------------------------------------- 1 | package com.monobogdan.minivk.api; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.net.ConnectivityManager; 6 | import android.util.Log; 7 | import android.view.inputmethod.InputMethodManager; 8 | 9 | import com.monobogdan.minivk.PersistStorage; 10 | 11 | import org.apache.http.util.EncodingUtils; 12 | import org.json.JSONException; 13 | import org.json.JSONObject; 14 | 15 | import java.io.BufferedReader; 16 | import java.io.InputStreamReader; 17 | import java.io.OutputStreamWriter; 18 | import java.net.HttpURLConnection; 19 | import java.net.URL; 20 | import java.net.URLEncoder; 21 | import java.security.MessageDigest; 22 | import java.util.Random; 23 | import java.util.concurrent.ExecutorService; 24 | import java.util.concurrent.Executors; 25 | import java.util.concurrent.atomic.AtomicBoolean; 26 | 27 | import javax.net.ssl.HostnameVerifier; 28 | import javax.net.ssl.HttpsURLConnection; 29 | import javax.net.ssl.SSLSession; 30 | 31 | public class VK { 32 | 33 | private final String apiUrl = "http://90.156.209.92/apirelay.php"; 34 | private final String audioUrl = "http://90.156.209.92/audiorelay.php"; 35 | private final String version = "5.131"; 36 | 37 | private final String APP_ID = "2274003"; 38 | private final String APP_SECRET = "hHbZxrka2uZ6jB1inYsH"; 39 | 40 | private Context context; 41 | private ExecutorService threadPool; 42 | private AtomicBoolean jobInProgress; 43 | 44 | final int THREAD_COUNT = 3; 45 | 46 | public interface VKResult 47 | { 48 | void success(JSONObject json); 49 | void failed(String reason); 50 | } 51 | 52 | public interface AuthResult 53 | { 54 | void success(); 55 | void error(String desc); 56 | } 57 | 58 | private ConnectivityManager conMan; 59 | 60 | public VK(Context context) 61 | { 62 | this.context = context; 63 | threadPool = Executors.newSingleThreadExecutor(); 64 | 65 | jobInProgress = new AtomicBoolean(); 66 | 67 | HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 68 | @Override 69 | public boolean verify(String s, SSLSession sslSession) { 70 | return true; 71 | } 72 | }); 73 | } 74 | 75 | public boolean isJobInProgress() { 76 | return jobInProgress.get(); 77 | } 78 | 79 | public void beginDirectAuthFlow(String login, String password, AuthResult auth, Activity thiz) 80 | { 81 | String fmt = String.format("https://oauth.vk.com/token?grant_type=password&validate_token=true&client_id=%s&client_secret=%s&username=%s&password=%s", 82 | APP_ID, APP_SECRET, URLEncoder.encode(login), URLEncoder.encode(password)); 83 | 84 | directRequest(fmt, new VKResult() { 85 | @Override 86 | public void success(JSONObject json) { 87 | try { 88 | if (json.has("access_token")) { 89 | // Grant us access as official app 90 | PersistStorage.getAppInstance().apiToken = json.getString("access_token"); 91 | 92 | auth.success(); 93 | } 94 | else 95 | auth.error(json.getString("error_description")); 96 | } 97 | catch (JSONException e) 98 | { 99 | auth.error(e.getLocalizedMessage()); 100 | } 101 | } 102 | 103 | @Override 104 | public void failed(String reason) { 105 | auth.error(reason); 106 | } 107 | }, thiz); 108 | } 109 | 110 | private String genericRequest(String request) 111 | { 112 | try { 113 | HttpURLConnection conn = (HttpURLConnection) new URL(request).openConnection(); 114 | conn.setDoInput(true); 115 | conn.setDoOutput(true); 116 | conn.setRequestProperty("Content-Type", "text/plain"); 117 | //conn.setRequestMethod("POST"); 118 | 119 | BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); 120 | String response = ""; 121 | while (reader.ready()) 122 | response += reader.readLine(); 123 | 124 | return response; 125 | } 126 | catch (Exception e) 127 | { 128 | e.printStackTrace(); 129 | 130 | return ""; 131 | } 132 | } 133 | 134 | private void directRequest(String url, VKResult handler, Activity thiz) 135 | { 136 | jobInProgress.set(true); 137 | threadPool.submit(new Runnable() { 138 | @Override 139 | public void run() { 140 | try { 141 | HttpURLConnection conn = (HttpURLConnection) new URL(apiUrl).openConnection(); 142 | conn.setDoInput(true); 143 | conn.setDoOutput(true); 144 | conn.setRequestMethod("POST"); 145 | conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)"); 146 | conn.connect(); 147 | 148 | OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream()); 149 | writer.write(url); 150 | writer.close(); 151 | 152 | BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); 153 | String response = ""; 154 | String line = ""; 155 | while ((line = reader.readLine()) != null) 156 | response += line; 157 | 158 | String finalResponse = response; 159 | Log.i("", "run: " + finalResponse); 160 | JSONObject obj = new JSONObject(finalResponse); 161 | 162 | if(thiz != null) 163 | thiz.runOnUiThread(new Runnable() { 164 | @Override 165 | public void run() { 166 | handler.success(obj); 167 | } 168 | }); 169 | else 170 | handler.success(obj); 171 | } 172 | catch (Exception e) 173 | { 174 | e.printStackTrace(); 175 | handler.failed(e.getLocalizedMessage()); 176 | } 177 | 178 | jobInProgress.set(false); 179 | } 180 | }); 181 | } 182 | 183 | public void audioRequest(String request, VKResult handler, Activity thiz) 184 | { 185 | threadPool.submit(new Runnable() { 186 | @Override 187 | public void run() { 188 | String result = genericRequest(audioUrl + "?" + request); 189 | 190 | try 191 | { 192 | handler.success(new JSONObject(result)); 193 | } 194 | catch (JSONException e) 195 | { 196 | e.printStackTrace(); 197 | handler.failed("Failed to parse JSON"); 198 | } 199 | } 200 | }); 201 | } 202 | 203 | public void request(String request, VKResult handler, Activity thiz) 204 | { 205 | request = "/method/" + request + "access_token=" + PersistStorage.getAppInstance().apiToken + "&v=" + version; 206 | 207 | try { 208 | /*MessageDigest md5 = MessageDigest.getInstance("md5"); 209 | byte[] digest = md5.digest(EncodingUtils.getAsciiBytes( request + PersistStorage.getAppInstance().secret)); 210 | String sig = ""; 211 | 212 | for(byte b : digest) 213 | { 214 | if(b == 0) 215 | break; 216 | 217 | sig += String.format("%x", b); 218 | }*/ 219 | 220 | //Log.i("TAG", "md5: " + sig); 221 | //Log.i("TAG", "request: " + request + PersistStorage.getAppInstance().secret); 222 | directRequest("https://api.vk.com" + request, handler, thiz); 223 | } 224 | catch (Exception e) 225 | { 226 | e.printStackTrace(); 227 | } 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /MiniVK/app/src/main/java/com/monobogdan/minivk/api/VKDataSet.java: -------------------------------------------------------------------------------- 1 | package com.monobogdan.minivk.api; 2 | 3 | import android.text.format.DateUtils; 4 | 5 | import org.json.JSONArray; 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | 9 | import java.io.File; 10 | import java.text.DateFormat; 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.Comparator; 14 | import java.util.Date; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | public class VKDataSet { 19 | 20 | public static final class Dialog 21 | { 22 | public int id; 23 | public String avatar; 24 | public String name; 25 | public String lastMessage; 26 | public String date; 27 | public int inRead; 28 | 29 | public int lastMessageDate; 30 | } 31 | 32 | public static final class Message 33 | { 34 | public int sender; 35 | public String avatarName; 36 | public String senderReadable; 37 | public String text; 38 | public long date; 39 | public String dateFormatted; 40 | public boolean isRead; 41 | 42 | public boolean hasVoiceAttachment; 43 | public String voiceUrl; 44 | 45 | public boolean hasAttachments; 46 | public ArrayList attachments; // Pictures are meant to be here 47 | } 48 | 49 | public static final class User 50 | { 51 | public String name; 52 | public int id; 53 | public String avatarUrl; 54 | public boolean isOnline; 55 | } 56 | 57 | public static final class Audio 58 | { 59 | public String contentId; // Used also for caching 60 | public String artist; 61 | public String title; 62 | public String duration; 63 | } 64 | 65 | private static Map getUsersFromResponse(JSONArray resp) throws JSONException 66 | { 67 | Map ret = new HashMap<>(); 68 | 69 | for(int i = 0; i < resp.length(); i++) 70 | { 71 | JSONObject profile = resp.getJSONObject(i); 72 | User user = new User(); 73 | 74 | user.id = profile.getInt("id"); 75 | user.avatarUrl = profile.getString("photo_100"); 76 | user.isOnline = profile.getInt("online") == 1; 77 | user.name = profile.getString("first_name") + " " + profile.get("last_name"); 78 | 79 | ret.put(user.id, user); 80 | } 81 | 82 | return ret; 83 | } 84 | 85 | private static String formatDate(long date) 86 | { 87 | if(DateUtils.isToday(date)) { 88 | return DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date(date * 1000)); 89 | } 90 | else 91 | { 92 | return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date(date * 1000)); 93 | } 94 | } 95 | 96 | public static ArrayList fetchMessages(JSONObject obj) 97 | { 98 | try 99 | { 100 | obj = obj.getJSONObject("response"); 101 | JSONArray dialogs = obj.getJSONArray("items"); 102 | 103 | ArrayList ret = new ArrayList<>(); 104 | Map users = getUsersFromResponse(obj.getJSONArray("profiles")); 105 | 106 | for(int i = 0; i < dialogs.length(); i++) 107 | { 108 | JSONObject jmsg = dialogs.getJSONObject(i); 109 | Message message = new Message(); 110 | 111 | message.date = jmsg.getLong("date"); 112 | message.dateFormatted = formatDate(message.date); 113 | message.text = jmsg.getString("text"); 114 | message.sender = jmsg.getInt("from_id"); 115 | message.senderReadable = users.get(message.sender).name; 116 | message.avatarName = new File(users.get(message.sender).avatarUrl).getName(); 117 | 118 | JSONArray attachments = jmsg.getJSONArray("attachments"); 119 | 120 | if(attachments.length() == 1 && attachments.getJSONObject(0).getString("type").equals("audio_message")) 121 | { 122 | message.hasVoiceAttachment = true; 123 | message.voiceUrl = attachments.getJSONObject(0).getJSONObject("audio_message").getString("link_mp3"); 124 | } 125 | else 126 | { 127 | message.hasAttachments = attachments.length() > 0; 128 | message.attachments = new ArrayList<>(); 129 | 130 | for(int j = 0; j < attachments.length(); j++) 131 | { 132 | JSONObject at = attachments.getJSONObject(j); 133 | 134 | if(at.getString("type").equals("photo")) { 135 | JSONArray sizes = at.getJSONObject("photo").getJSONArray("sizes"); 136 | message.attachments.add(sizes.getJSONObject(sizes.length() - 1).getString("url")); 137 | } 138 | } 139 | } 140 | 141 | ret.add(message); 142 | } 143 | 144 | return ret; 145 | } 146 | catch (JSONException e) 147 | { 148 | e.printStackTrace(); 149 | 150 | return new ArrayList<>(); 151 | } 152 | } 153 | 154 | public static ArrayList fetchDialogs(JSONObject obj) 155 | { 156 | try { 157 | obj = obj.getJSONObject("response"); 158 | JSONArray dialogs = obj.getJSONArray("items"); 159 | Map users = getUsersFromResponse(obj.getJSONArray("profiles")); 160 | 161 | ArrayList ret = new ArrayList<>(); 162 | 163 | for(int i = 0; i < dialogs.length(); i++) 164 | { 165 | JSONObject jdlg = dialogs.getJSONObject(i).getJSONObject("conversation"); 166 | Dialog dialog = new Dialog(); 167 | 168 | // Get peer info 169 | JSONObject peer = jdlg.getJSONObject("peer"); 170 | 171 | if(peer.getString("type").equals("group")) 172 | continue; 173 | 174 | dialog.name = "Unknown"; 175 | dialog.id = peer.getInt("id"); 176 | 177 | if(peer.getString("type").equals("chat")) 178 | { 179 | dialog.name = jdlg.getJSONObject("chat_settings").getString("title"); 180 | } 181 | else 182 | { 183 | dialog.name = users.get(dialog.id).name; 184 | dialog.avatar = users.get(dialog.id).avatarUrl; 185 | } 186 | 187 | dialog.lastMessageDate = dialogs.getJSONObject(i).getJSONObject("last_message").getInt("date"); 188 | dialog.lastMessage = dialogs.getJSONObject(i).getJSONObject("last_message").getString("text"); 189 | dialog.inRead = jdlg.getInt("in_read"); 190 | 191 | ret.add(dialog); 192 | } 193 | 194 | Collections.sort(ret, new Comparator() { 195 | 196 | @Override 197 | public int compare(Dialog o1, Dialog o2) { 198 | return o1.lastMessageDate > o2.lastMessageDate ? -1 : (o1.lastMessageDate < o2.lastMessageDate ? 1 : 0); 199 | } 200 | }); 201 | 202 | return ret; 203 | } 204 | catch (JSONException e) 205 | { 206 | e.printStackTrace(); 207 | 208 | return new ArrayList<>(); 209 | } 210 | } 211 | 212 | public static ArrayList