diff --git a/.travis.yml b/.travis.yml index 89c66b3..87e43bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,8 @@ android: components: - tools - platform-tools - - build-tools-26.0.1 - - android-26 + - build-tools-27.0.3 + - android-27 - extra-android-m2repository - extra-google-m2repository diff --git a/app/build.gradle b/app/build.gradle index 8c78b21..de77231 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,11 +1,11 @@ -apply plugin: 'com.android.application' +apply plugin: "com.android.application" android { compileSdkVersion 27 buildToolsVersion "27.0.3" lintOptions{ - disable 'MissingTranslation' + disable "MissingTranslation" abortOnError false } @@ -19,7 +19,7 @@ android { sourceSets { main { - assets.srcDirs = ['assets', 'src/main/assets', 'src/main/assets/'] + assets.srcDirs = ["assets", "src/main/assets", "src/main/assets/"] } } @@ -28,54 +28,54 @@ android { minifyEnabled true zipAlignEnabled true multiDexEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } release { minifyEnabled true zipAlignEnabled true multiDexEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } } dependencies { - provided fileTree(dir: 'libs', include: ['XposedBridgeApi-20150213.jar']) + compileOnly fileTree(dir: 'libs', include: ['XposedBridgeApi-20150213.jar']) - compile 'com.android.support:support-compat:27.1.0' - compile 'com.android.support:appcompat-v7:27.1.0' - compile 'com.android.support:recyclerview-v7:27.1.0' - compile 'com.android.support:design:27.1.0' - compile "com.android.support:preference-v7:27.1.0" - compile 'com.android.support:cardview-v7:27.1.0' + implementation 'com.android.support:support-compat:27.1.1' + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support:recyclerview-v7:27.1.1' + implementation 'com.android.support:design:27.1.1' + implementation "com.android.support:preference-v7:27.1.1" + implementation 'com.android.support:cardview-v7:27.1.1' - compile 'com.google.firebase:firebase-core:11.8.0' - compile 'com.google.firebase:firebase-crash:11.8.0' - compile 'com.google.android.gms:play-services-plus:11.8.0' - compile 'com.google.firebase:firebase-messaging:11.8.0' - compile 'com.github.HaarigerHarald:android-youtubeExtractor:v1.7.0' + implementation 'com.google.firebase:firebase-core:12.0.1' + implementation 'com.google.firebase:firebase-crash:12.0.1' + implementation 'com.google.android.gms:play-services-plus:12.0.1' + implementation 'com.google.firebase:firebase-messaging:12.0.1' + implementation 'com.github.HaarigerHarald:android-youtubeExtractor:v1.7.0' - compile 'com.afollestad.material-dialogs:core:0.9.6.0' - compile 'com.afollestad.material-dialogs:commons:0.9.6.0' - compile 'net.xpece.android:support-preference:2.1.1' - compile 'com.squareup.okhttp3:okhttp:3.9.0' - compile 'com.squareup.okio:okio:1.13.0' - compile 'me.zhanghai.android.materialprogressbar:library:1.4.2@aar' - compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar' - compile 'com.github.bluejamesbond:textjustify-android:2.1.6' - compile 'com.evernote:android-job:1.2.0' - testCompile 'junit:junit:4.12' + implementation 'com.afollestad.material-dialogs:core:0.9.6.0' + implementation 'com.afollestad.material-dialogs:commons:0.9.6.0' + implementation 'net.xpece.android:support-preference:2.1.1' + implementation 'com.squareup.okhttp3:okhttp:3.9.0' + implementation 'com.squareup.okio:okio:1.13.0' + implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2@aar' + implementation 'org.solovyev.android.views:linear-layout-manager:0.5@aar' + implementation 'com.github.bluejamesbond:textjustify-android:2.1.6' + implementation 'com.evernote:android-job:1.2.0' + testImplementation 'junit:junit:4.12' } -apply plugin: 'com.google.gms.google-services' +apply plugin: "com.google.gms.google-services" configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> def requested = details.requested - if (requested.group == 'com.android.support') { + if (requested.group == "com.android.support") { if (!requested.name.startsWith("multidex")) { - details.useVersion '27.1.0' + details.useVersion "27.1.1" } } } diff --git a/app/src/main/java/com/phantom/onetapfacebookmodule/FacebookHook.java b/app/src/main/java/com/phantom/onetapfacebookmodule/FacebookHook.java index cbae423..e14a8cb 100755 --- a/app/src/main/java/com/phantom/onetapfacebookmodule/FacebookHook.java +++ b/app/src/main/java/com/phantom/onetapfacebookmodule/FacebookHook.java @@ -34,7 +34,7 @@ public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) thr } final XC_MethodHook methodHook = new XC_MethodHook() { - protected void afterHookedMethod(XC_MethodHook.MethodHookParam hookParams) throws Throwable { + protected void afterHookedMethod(XC_MethodHook.MethodHookParam hookParams) { try { Uri uri = (Uri) hookParams.args[0]; ApplicationLogMaintainer.sendBroadcast(context, "Facebook Main URL : " + uri.toString()); diff --git a/app/src/main/java/com/phantom/onetapvideodownload/ApplicationLogMaintainer.java b/app/src/main/java/com/phantom/onetapvideodownload/ApplicationLogMaintainer.java index b5fb92d..836e824 100644 --- a/app/src/main/java/com/phantom/onetapvideodownload/ApplicationLogMaintainer.java +++ b/app/src/main/java/com/phantom/onetapvideodownload/ApplicationLogMaintainer.java @@ -84,6 +84,7 @@ void writeToLog(String message, boolean appendMode) { File logFile = new File(getLogFilePath()); if (!logFile.getParentFile().exists()) { + //noinspection ResultOfMethodCallIgnored logFile.getParentFile().mkdirs(); } diff --git a/app/src/main/java/com/phantom/onetapvideodownload/IpcService.java b/app/src/main/java/com/phantom/onetapvideodownload/IpcService.java index 3738fcc..2912016 100644 --- a/app/src/main/java/com/phantom/onetapvideodownload/IpcService.java +++ b/app/src/main/java/com/phantom/onetapvideodownload/IpcService.java @@ -1,5 +1,6 @@ package com.phantom.onetapvideodownload; +import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -14,7 +15,8 @@ import android.os.Handler; import android.os.IBinder; import android.support.v4.app.NotificationCompat; -import android.support.v4.app.NotificationManagerCompat; +import android.support.v4.app.ServiceCompat; +import android.support.v4.content.ContextCompat; import android.util.Log; import android.util.SparseArray; @@ -47,6 +49,8 @@ public class IpcService extends Service implements Invokable { public static final String EXTRA_PARAM_STRING = PACKAGE_NAME + ".extra.url"; public static final String EXTRA_PACKAGE_NAME = PACKAGE_NAME + ".extra.package_name"; + private static final String NOTIFICATION_CHANNEL_NAME = "One Tap Video Download"; + private Handler mHandler = new Handler(); private final IBinder mBinder = new LocalBinder(); private static final AtomicInteger notificationId = new AtomicInteger(); @@ -62,14 +66,14 @@ public static void startSaveUrlAction(Context context, String uri, String packag intent.setClassName(PACKAGE_NAME, CLASS_NAME); intent.putExtra(EXTRA_URL, uri); intent.putExtra(EXTRA_PACKAGE_NAME, packageName); - context.startService(intent); + ContextCompat.startForegroundService(context, intent); } public static void startSaveYoutubeVideoAction(Context context, String paramString) { Intent intent = new Intent(ACTION_SAVE_YOUTUBE_VIDEO); intent.setClassName(PACKAGE_NAME, CLASS_NAME); intent.putExtra(EXTRA_PARAM_STRING, paramString); - context.startService(intent); + ContextCompat.startForegroundService(context, intent); } public static void startInspectMediaUriAction(Context context, String uri, String packageName) { @@ -77,7 +81,23 @@ public static void startInspectMediaUriAction(Context context, String uri, Strin intent.setClassName(PACKAGE_NAME, CLASS_NAME); intent.putExtra(EXTRA_URL, uri); intent.putExtra(EXTRA_PACKAGE_NAME, packageName); - context.startService(intent); + ContextCompat.startForegroundService(context, intent); + } + + @Override + public void onCreate() { + super.onCreate(); + // On Oreo, we need a notification to show that the app is running in background + // Refer - https://stackoverflow.com/a/47654126 - for more information + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + startForeground(1024, new Notification()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE); } @Override @@ -85,10 +105,7 @@ public IBinder onBind(Intent intent) { return mBinder; } - public class LocalBinder extends Binder { - public IpcService getServiceInstance() { - return IpcService.this; - } + private class LocalBinder extends Binder { } @Override @@ -135,8 +152,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { } private void showNotification(String url, String title, long videoId) { - String notification_channel_id = "otvd_notification_channel"; - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, notification_channel_id); + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, PACKAGE_NAME); mBuilder.setSmallIcon(R.drawable.one_tap_small); mBuilder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.one_tap_large)); mBuilder.setContentTitle(title); @@ -146,7 +162,7 @@ private void showNotification(String url, String title, long videoId) { // 0 if vibration is disabled. long vibrationAmount = CheckPreferences.vibrationAmount(this); - mBuilder.setVibrate(new long[] {0, vibrationAmount}); + mBuilder.setVibrate(new long[]{0, vibrationAmount}); int currentApiVersion = android.os.Build.VERSION.SDK_INT; if (CheckPreferences.headsUpEnabled(this) && currentApiVersion >= Build.VERSION_CODES.JELLY_BEAN) { @@ -165,7 +181,7 @@ private void showNotification(String url, String title, long videoId) { instantDownloadIntent = ProxyDownloadManager.getActionBrowserDownload(this, videoId, title, CheckPreferences.getDownloadLocation(this)); } else if (VideoDatabase.VIDEO_TYPE_YOUTUBE == videoDatabase.getCategory(videoId)) { - YoutubeVideo video = (YoutubeVideo)videoDatabase.getVideo(videoId); + YoutubeVideo video = (YoutubeVideo) videoDatabase.getVideo(videoId); int itag = video.getBestVideoFormat().itag; instantDownloadIntent = ProxyDownloadManager.getActionYoutubeDownload(this, videoId, title, CheckPreferences.getDownloadLocation(this), itag); @@ -206,14 +222,13 @@ private void showNotification(String url, String title, long videoId) { mBuilder.setContentIntent(downloadPendingIntent); final NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + if (notificationmanager == null) { + return; + } final int id = possibleId; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - int importance = NotificationManager.IMPORTANCE_LOW; - CharSequence name = getString(R.string.otvd_channel); - NotificationChannel mChannel = new NotificationChannel(notification_channel_id, name, importance); - mChannel.setSound(null, null); - notificationmanager.createNotificationChannel(mChannel); + notificationmanager.createNotificationChannel(getNotificationChannel()); } notificationmanager.notify(id, mBuilder.build()); @@ -263,20 +278,28 @@ private void handleActionSaveYoutubeVideo(String paramString) { if (invalidId) { final NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + if (notificationmanager == null) { + return; + } + int possibleId = notificationId.getAndIncrement(); if (possibleId >= CheckPreferences.notificationCountAllowed(this)) { possibleId = 0; notificationId.set(possibleId); } final int id = possibleId; - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, PACKAGE_NAME); mBuilder.setSmallIcon(R.drawable.one_tap_small); + mBuilder.setChannelId(PACKAGE_NAME); mBuilder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.one_tap_large)); mBuilder.setContentTitle(getResources().getString(R.string.youtube_next_video_title)); mBuilder.setContentInfo(getResources().getString(R.string.youtube_next_video_summary)); mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(getResources().getString(R.string.youtube_next_video_summary))); mBuilder.setAutoCancel(true); mBuilder.setOnlyAlertOnce(false); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationmanager.createNotificationChannel(getNotificationChannel()); + } notificationmanager.notify(id, mBuilder.build()); return; } @@ -286,7 +309,7 @@ private void handleActionSaveYoutubeVideo(String paramString) { @Override public Integer invoke(Video video) { if (video != null) { - YoutubeVideo youtubeVideo = (YoutubeVideo)video; + YoutubeVideo youtubeVideo = (YoutubeVideo) video; youtubeVideo.setPackageName("com.google.android.youtube"); String bestFormatUrl = youtubeVideo.getBestVideoFormat().url; if (bestFormatUrl == null @@ -302,4 +325,10 @@ public Integer invoke(Video video) { } return 0; } + + @TargetApi(Build.VERSION_CODES.O) + private NotificationChannel getNotificationChannel() { + return new NotificationChannel(PACKAGE_NAME, NOTIFICATION_CHANNEL_NAME, + NotificationManager.IMPORTANCE_DEFAULT); + } } diff --git a/app/src/main/java/com/phantom/onetapvideodownload/ThemeManager.java b/app/src/main/java/com/phantom/onetapvideodownload/ThemeManager.java index 9501c93..71d4820 100644 --- a/app/src/main/java/com/phantom/onetapvideodownload/ThemeManager.java +++ b/app/src/main/java/com/phantom/onetapvideodownload/ThemeManager.java @@ -5,7 +5,6 @@ import android.content.Intent; import android.os.Build; import android.support.v4.content.ContextCompat; -import android.support.v4.content.IntentCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; @@ -30,7 +29,7 @@ public static void onThemeChanged(Activity activity) { activity.startActivity(intent); } - public static int getTheme(Context context) { + private static int getTheme(Context context) { if (CheckPreferences.getDarkThemeEnabled(context)) { return R.style.AppTheme_Dark; } else { @@ -38,7 +37,7 @@ public static int getTheme(Context context) { } } - public static int getPopupMenuTheme(Context context) { + private static int getPopupMenuTheme(Context context) { if (CheckPreferences.getDarkThemeEnabled(context)) { return R.style.AppTheme_ThemeOverlay_AppCompat_Dark; } else { @@ -70,7 +69,7 @@ public static int getLightBackgroundColor(Context context) { } } - public static int getPrimaryDarkColor(Context context) { + private static int getPrimaryDarkColor(Context context) { if (CheckPreferences.getDarkThemeEnabled(context)) { return ContextCompat.getColor(context, R.color.dark_background); } else { @@ -78,7 +77,7 @@ public static int getPrimaryDarkColor(Context context) { } } - public static int getNavigationBarColor(Context context) { + private static int getNavigationBarColor(Context context) { if (CheckPreferences.getDarkThemeEnabled(context)) { return ContextCompat.getColor(context, R.color.black); } else { diff --git a/app/src/main/java/com/phantom/onetapvideodownload/downloader/DownloadManager.java b/app/src/main/java/com/phantom/onetapvideodownload/downloader/DownloadManager.java index cf14485..a5ceb82 100644 --- a/app/src/main/java/com/phantom/onetapvideodownload/downloader/DownloadManager.java +++ b/app/src/main/java/com/phantom/onetapvideodownload/downloader/DownloadManager.java @@ -57,19 +57,19 @@ public class DownloadManager extends Service { private final Integer mNotificationId = 20; private final Long NOTIFICATION_UPDATE_WAIT_TIME = 2500L; private Thread mUiUpdateThread; + private static final String NOTIFICATION_CHANNEL_NAME = "One Tap Video Download"; @Override public void onCreate() { mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - String notification_channel_id = "otvd_notification_channel"; - mBuilder = new NotificationCompat.Builder(this, notification_channel_id); + String channelId = PACKAGE_NAME + "." + TAG; + mBuilder = new NotificationCompat.Builder(this, channelId); mBuilder.setOnlyAlertOnce(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - int importance = NotificationManager.IMPORTANCE_LOW; - CharSequence name = getString(R.string.otvd_channel); - NotificationChannel mChannel = new NotificationChannel(notification_channel_id, name, importance); - mChannel.setSound(null, null); - mNotifyManager.createNotificationChannel(mChannel); + NotificationChannel channel = new NotificationChannel(channelId, NOTIFICATION_CHANNEL_NAME, + NotificationManager.IMPORTANCE_LOW); + channel.setSound(null, null); + mNotifyManager.createNotificationChannel(channel); } DownloadDatabase downloadDatabase = DownloadDatabase.getDatabase(this); @@ -231,7 +231,8 @@ public boolean checkPermissionGranted(AppPermissions permission) { private void requestPermission(AppPermissions permission) { String title = "Storage permission required"; String description = "Please enable this permission and restart your download."; - NotificationCompat.Builder builder = new NotificationCompat.Builder(this); + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, + PACKAGE_NAME + "." + TAG); builder.setSmallIcon(R.drawable.one_tap_small); builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.one_tap_large)); builder.setContentTitle(title); diff --git a/app/src/main/java/com/phantom/onetapyoutubemodule/YoutubeMediaHook.java b/app/src/main/java/com/phantom/onetapyoutubemodule/YoutubeMediaHook.java index 73921c1..6018901 100644 --- a/app/src/main/java/com/phantom/onetapyoutubemodule/YoutubeMediaHook.java +++ b/app/src/main/java/com/phantom/onetapyoutubemodule/YoutubeMediaHook.java @@ -1,7 +1,7 @@ package com.phantom.onetapyoutubemodule; +import android.annotation.SuppressLint; import android.content.Context; -import android.support.v4.util.Pair; import com.phantom.onetapvideodownload.ApplicationLogMaintainer; import com.phantom.onetapvideodownload.IpcService; @@ -21,11 +21,12 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage; public class YoutubeMediaHook implements IXposedHookLoadPackage { - private static final String ONE_TAP_PACKAGE_NAME = "com.phantom.onetapvideodownload"; + // private static final String ONE_TAP_PACKAGE_NAME = "com.phantom.onetapvideodownload"; private static final String ONE_TAP_YOUTUBE_MODULE_PACKAGE_NAME = "com.phantom.onetapyoutubemodule"; private static final String PACKAGE_NAME = "com.google.android.youtube"; private static final String ORIGINAL_CLASS_NAME = "com.google.android.libraries.youtube.innertube.model.media.FormatStreamModel"; - private static final HashMap classNamesMap = new HashMap<>(); + @SuppressLint("UseSparseArrays") + private static final Map classNamesMap = new HashMap<>(); private static long lastVideoTime = System.currentTimeMillis(); public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { @@ -42,11 +43,11 @@ public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) thr File hookFile = new File(HookClassNamesFetcher.getHooksFilePath(context)); try { - if (!hookFile.exists()) { + if (!hookFile.exists()) { ApplicationLogMaintainer.sendBroadcast(context, "Hook file doesn't exist"); } - if (!Global.isFileReadable(hookFile)) { + if (!Global.isFileReadable(hookFile)) { ApplicationLogMaintainer.sendBroadcast(context, "Unable to open file for reading"); ApplicationLogMaintainer.sendBroadcast(context, hookFile.getAbsolutePath()); } @@ -69,7 +70,7 @@ public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) thr boolean isNotObfuscated = Global.isClassPresent(loader, ORIGINAL_CLASS_NAME); final XC_MethodHook methodHook = new XC_MethodHook() { - protected void afterHookedMethod(XC_MethodHook.MethodHookParam hookParams) throws Throwable { + protected void afterHookedMethod(XC_MethodHook.MethodHookParam hookParams) { long currentTime = System.currentTimeMillis(); if (currentTime - lastVideoTime < 1200L) { return; @@ -77,11 +78,13 @@ protected void afterHookedMethod(XC_MethodHook.MethodHookParam hookParams) throw if (!(hookParams.args[1] instanceof String)) { ApplicationLogMaintainer.sendBroadcast(context, "Non-string object found in the hooked method"); + ApplicationLogMaintainer.sendBroadcast(context, "Object is " + + hookParams.args[1]); return; } lastVideoTime = currentTime; - String paramString = (String)hookParams.args[1]; + String paramString = (String) hookParams.args[1]; ApplicationLogMaintainer.sendBroadcast(context, "Youtube Video Id : " + paramString); IpcService.startSaveYoutubeVideoAction(context, paramString); } diff --git a/build.gradle b/build.gradle index bff4701..31aa6b9 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { maven { url 'https://maven.google.com' } } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.0' classpath 'com.google.gms:google-services:3.2.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8c0fb64..f6b961f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f620830..9a4163a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sat Aug 12 22:40:11 IST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/gradlew b/gradlew index 91a7e26..cccdd3d 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec9973..e95643d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/youtube_hooks_updater_scripts/README.md b/youtube_hooks_updater_scripts/README.md new file mode 100644 index 0000000..3ecc62b --- /dev/null +++ b/youtube_hooks_updater_scripts/README.md @@ -0,0 +1,30 @@ +# Youtube hooks extractor + +Simple python scripts to extract hooks from the latest Youtube APK + +## Usage + +Use the `hooks_updater.py` to download the latest Youtube APK and extract hooks from it + +```sh +$ ./hooks_updater.py --help +Usage: hooks_updater.py [OPTIONS] + +Options: + --youtube-apk-url TEXT URL to download latest Youtube APKs + --dont-create-pr BOOLEAN Create a PR against master + --help Show this message and exit. +``` + +## Requirements + +- Python 2/3 +- Packages from `requirements.txt` +- [dex2jar](https://github.com/pxb1988/dex2jar) + - Expects a script called `dex2jar` in the `PATH` that would decompile the apk. + - The `d2j-dex2jar.sh` should do the trick but it needs to be named as `dex2jar`. +- [jd-core-java](https://github.com/nviennot/jd-core-java) + - Expects a script called `jd-core-java` in the `PATH` which would execute the `jd-core-java` + jar with the specified parameters. +- [hub](https://github.com/github/hub) should be present in the `PATH` + diff --git a/youtube_hooks_updater_scripts/hooks_extractor.py b/youtube_hooks_updater_scripts/hooks_extractor.py old mode 100755 new mode 100644 index 4292892..e61f5dc --- a/youtube_hooks_updater_scripts/hooks_extractor.py +++ b/youtube_hooks_updater_scripts/hooks_extractor.py @@ -1,26 +1,34 @@ -#!/usr/bin/python - -import subprocess +#!/usr/bin/env python +from __future__ import print_function import javalang +import os +import shutil +import subprocess + +DECOMPILED_DIRECTORY = 'decompiled' +JAR_NAME = 'youtube.jar' +REQUIRED_METHOD_PARAMETERS = ['Uri', 'String', 'long'] +APK_NAME = 'latest_youtube.apk' -DECOMPILED_DIRECTORY = "decompiled" -JAR_NAME = "youtube.jar" -REQUIRED_METHOD_PARAMETERS = ["Uri", "String", "long"] -APK_NAME = "latest_youtube.apk" def extractor(apk_url): - subprocess.call(['mkdir', "-p", DECOMPILED_DIRECTORY]) - subprocess.call(['wget', '-O', APK_NAME, apk_url], cwd=DECOMPILED_DIRECTORY) - subprocess.call(['dex2jar', "-f", "-o", JAR_NAME, APK_NAME], cwd=DECOMPILED_DIRECTORY) - subprocess.call(['jd-core-java', JAR_NAME, "."], cwd=DECOMPILED_DIRECTORY) - file_name = subprocess.check_output(['grep', "-irl", 'application/x-mpegURL";'], cwd=DECOMPILED_DIRECTORY) + os.mkdir(DECOMPILED_DIRECTORY) + subprocess.call(['wget', '-O', APK_NAME, apk_url], + cwd=DECOMPILED_DIRECTORY) + subprocess.call(['dex2jar', '-f', '-o', JAR_NAME, + APK_NAME], cwd=DECOMPILED_DIRECTORY) + subprocess.call(['jd-core-java', JAR_NAME, '.'], cwd=DECOMPILED_DIRECTORY) + file_name = subprocess.check_output( + ['grep', '-irl', 'application/x-mpegURL";', '.'], + cwd=DECOMPILED_DIRECTORY) file_name = file_name.strip() - java_source = subprocess.check_output(['cat', file_name], cwd=DECOMPILED_DIRECTORY) + with open(os.path.join(DECOMPILED_DIRECTORY, file_name), 'r') as _file: + java_source = _file.read() parse_tree = javalang.parse.parse(java_source) class_name = parse_tree.types[0].name - subprocess.call(['rm', '-rf', DECOMPILED_DIRECTORY]) + shutil.rmtree(DECOMPILED_DIRECTORY, ignore_errors=True) - print class_name + print(class_name) return class_name diff --git a/youtube_hooks_updater_scripts/hooks_updater.py b/youtube_hooks_updater_scripts/hooks_updater.py old mode 100644 new mode 100755 index 307b442..0a14b68 --- a/youtube_hooks_updater_scripts/hooks_updater.py +++ b/youtube_hooks_updater_scripts/hooks_updater.py @@ -1,24 +1,26 @@ -#!/usr/bin/python2 +#!/usr/bin/env python +from __future__ import print_function from bs4 import BeautifulSoup +import click from hooks_extractor import extractor import json +import os +from pipes import quote import requests import subprocess -import os import sys -from pipes import quote YOUTUBE_APK_URL = 'https://www.androidapksfree.com/apk/youtube-apk-latest-version-download/download/' HOOKS_DIRECTORY_PATH = 'app/src/main/assets' HOOKS_FILENAME = 'HookClassnames.json' -def addNewHookClassnames(): +def addNewHookClassnames(create_pr): app_details = apkDetailsFetcher() app_version = app_details['version'] - print "Latest Youtube version", app_version + print('Latest Youtube version', app_version) if isAlreadySupported(app_version): - print "Version already supported!" + print('Version already supported!') return direct_url = app_details['direct_url'] @@ -27,17 +29,22 @@ def addNewHookClassnames(): json_data = json.loads(getJsonString()) json_data['Youtube'][app_version] = class_name with open(getHookFilePath(), 'w') as f: - json.dump(json_data, f, sort_keys=True, indent=4, separators=(',', ':')) - print 'Updated HookClassnames.json for version : ', app_version + json.dump(json_data, f, sort_keys=True, + indent=4, separators=(',', ':')) + print('Updated HookClassnames.json for version : ', app_version) f.close() - createGitPullRequest(app_version) + if create_pr: + print('Creating Pull Request') + createGitPullRequest(app_version) + else: + print('Not creating Pull Request') def apkDetailsFetcher(): result = {} data = requests.get(YOUTUBE_APK_URL).text - soup = BeautifulSoup(data, "html.parser") + soup = BeautifulSoup(data, 'html.parser') links = soup.find_all('a') for link in links: @@ -59,7 +66,8 @@ def isAlreadySupported(version): def getHookFilePath(): script_path = os.path.dirname(os.path.abspath(__file__)) - hook_file_path = os.path.join(script_path, '..', HOOKS_DIRECTORY_PATH, HOOKS_FILENAME) + hook_file_path = os.path.join( + script_path, '..', HOOKS_DIRECTORY_PATH, HOOKS_FILENAME) return hook_file_path @@ -70,37 +78,53 @@ def getJsonString(): def directoryExists(directory_name): return os.path.isdir(directory_name) + def repoRootPath(): script_path = os.path.dirname(os.path.abspath(__file__)) repo_root_path = os.path.join(script_path, '..') return repo_root_path + def pullLatestChanges(): repo_root_path = repoRootPath() try: - subprocess.call(["git reset HEAD~100 --hard"], shell=True, cwd=repo_root_path) - subprocess.call(["git pull upstream master"], shell=True, cwd=repo_root_path) - subprocess.call(["git push origin master --force"], shell=True, cwd=repo_root_path) + subprocess.call(['git reset HEAD~100 --hard'], + shell=True, cwd=repo_root_path) + subprocess.call(['git pull upstream master'], + shell=True, cwd=repo_root_path) + subprocess.call(['git push origin master --force'], + shell=True, cwd=repo_root_path) except Exception as e: - print e + print(e) + def createGitPullRequest(version): repo_root_path = repoRootPath() comment = 'Added class names for Youtube version : {0}'.format(version) comment = quote(comment) try: - subprocess.call(["git add ."], shell=True, cwd=repo_root_path) - subprocess.call(['git commit --author="Automation Daemon " -m {0}'.format(comment)], - shell=True, cwd=repo_root_path) - subprocess.call(['git', 'push', 'origin', 'master'], cwd=repo_root_path) - subprocess.call(['hub', 'pull-request', '-m', comment, '-fb', 'Ashish-Bansal:master'], cwd=repo_root_path) + subprocess.call(['git', 'add', '.'], shell=True, cwd=repo_root_path) + subprocess.call(['git', 'commit', + '--author="Automation Daemon "', + '-m', comment], shell=True, cwd=repo_root_path) + subprocess.call(['git', 'push', 'origin', 'master'], + cwd=repo_root_path) + subprocess.call(['hub', 'pull-request', '-m', comment, + '-fb', 'Ashish-Bansal:master'], cwd=repo_root_path) except Exception as e: - print e - + print(e) -if __name__ == '__main__': - if len(sys.argv) > 1: - YOUTUBE_APK_URL = sys.argv[1] +@click.command() +@click.option('--youtube-apk-url', type=str, default=YOUTUBE_APK_URL, + help='URL to download latest Youtube APKs') +@click.option('--dont-create-pr', type=bool, default=False, + help='Create a PR against master') +def main(youtube_apk_url, create_pr): + YOUTUBE_APK_URL = youtube_apk_url pullLatestChanges() - addNewHookClassnames() + addNewHookClassnames(create_pr) + + +if __name__ == '__main__': + main() diff --git a/youtube_hooks_updater_scripts/requirements.txt b/youtube_hooks_updater_scripts/requirements.txt new file mode 100644 index 0000000..b610a75 --- /dev/null +++ b/youtube_hooks_updater_scripts/requirements.txt @@ -0,0 +1,4 @@ +click +bs4 +javalang +requests