Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Backend API URL
# For local dev (Android emulator uses 10.0.2.2 to reach host localhost)
API_BASE_URL=http://10.0.2.2:3002

# For production, use your deployed backend:
# API_BASE_URL=https://your-backend.cloudfunctions.net
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,11 @@ yarn-error.log
#misc
.vscode/
.env
# /android/app/google-services.json
!.env.example
/android/app/google-services.json
.prettierrc.js

# Orphaned/generated files
go.mod
debug.log
bugreport-*.zip
27 changes: 18 additions & 9 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,32 +95,34 @@ packagingOptions {
keyPassword 'android'
}
release {
storeFile file('my-key.keystore')
storePassword 'samspotifydown'
keyAlias 'final-version-1'
keyPassword 'samspotifydown'
storeFile file(findProperty('MYAPP_RELEASE_STORE_FILE') ?: 'my-key.keystore')
storePassword findProperty('MYAPP_RELEASE_STORE_PASSWORD') ?: ''
keyAlias findProperty('MYAPP_RELEASE_KEY_ALIAS') ?: ''
keyPassword findProperty('MYAPP_RELEASE_KEY_PASSWORD') ?: ''
}
}
buildTypes {
debug {
signingConfig signingConfigs.release
applicationIdSuffix ".debug"
resValue "string", "reactNativeCodePush_androidDeploymentKey", 'TCMtmuQ4X68FcUqFUVqUlMTytsjroPIVcF4vwB'
signingConfig signingConfigs.debug
resValue "string", "reactNativeCodePush_androidDeploymentKey", findProperty('CODEPUSH_DEBUG_KEY') ?: ''
resValue "string", "CodePushDeploymentKey", findProperty('CODEPUSH_DEBUG_KEY') ?: ''

}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
resValue "string", "reactNativeCodePush_androidDeploymentKey", '3PZGCl14jxeBTJU3yT6U-8HNZJQ6CjxlOWQ5T'
resValue "string", "reactNativeCodePush_androidDeploymentKey", findProperty('CODEPUSH_RELEASE_KEY') ?: ''
resValue "string", "CodePushDeploymentKey", findProperty('CODEPUSH_RELEASE_KEY') ?: ''
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"

}
releaseStaging {
initWith release
applicationIdSuffix ".releasestaging"
resValue "string", "reactNativeCodePush_androidDeploymentKey", 'TCMtmuQ4X68FcUqFUVqUlMTytsjroPIVcF4vwB'
resValue "string", "reactNativeCodePush_androidDeploymentKey", findProperty('CODEPUSH_STAGING_KEY') ?: ''
resValue "string", "CodePushDeploymentKey", findProperty('CODEPUSH_STAGING_KEY') ?: ''
// Note: It's a good idea to provide matchingFallbacks for the new buildType you create to prevent build issues
// Add the following line if not already there
matchingFallbacks = ['release']
Expand Down Expand Up @@ -180,6 +182,13 @@ dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
implementation("com.squareup.okhttp3:okhttp:4.9.1")
implementation("com.squareup.okhttp3:okhttp-urlconnection:4.9.1")
implementation('com.github.TeamNewPipe:NewPipeExtractor:v0.26.0') {
exclude group: 'com.github.spotbugs', module: 'spotbugs-annotations'
exclude group: 'org.mozilla', module: 'rhino'
}
// yt-dlp for unthrottled downloading (handles n-param deobfuscation)
implementation("io.github.junkfood02.youtubedl-android:library:0.18.1")
implementation("io.github.junkfood02.youtubedl-android:ffmpeg:0.18.1")


debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
Expand Down
5 changes: 3 additions & 2 deletions android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
</application>
</manifest>
4 changes: 2 additions & 2 deletions android/app/src/debug/google-services.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"client_info": {
"mobilesdk_app_id": "1:714569810554:android:2590bf076e41e011f331c3",
"android_client_info": {
"package_name": "com.sam.downify.debug"
"package_name": "com.sam.downify"
}
},
"oauth_client": [
Expand All @@ -36,4 +36,4 @@
}
],
"configuration_version": "1"
}
}
3 changes: 2 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:allowBackup="false"
android:extractNativeLibs="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">

Expand All @@ -23,7 +24,7 @@
android:windowSoftInputMode="adjustPan"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:exported="false"
android:exported="true"

>
<intent-filter>
Expand Down
26 changes: 24 additions & 2 deletions android/app/src/main/java/com/sam/downify/MainApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
import androidx.multidex.MultiDexApplication;
import com.microsoft.codepush.react.CodePush;
import com.rnfs.RNFSPackage;
import com.facebook.react.PackageList;
import com.sam.downify.newpipe.YouTubeExtractorPackage;
import com.sam.downify.newpipe.DownloaderImpl;
import org.schabi.newpipe.extractor.NewPipe;
import com.yausername.youtubedl_android.YoutubeDL;
import com.yausername.ffmpeg.FFmpeg;


public class MainApplication extends MultiDexApplication implements ReactApplication {
Expand All @@ -34,6 +40,7 @@ protected List<ReactPackage> getPackages() {
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// packages.add(new RNFSPackage());
packages.add(new YouTubeExtractorPackage());
return packages;
}

Expand Down Expand Up @@ -62,7 +69,22 @@ public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}


@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
try {
NewPipe.init(DownloaderImpl.getInstance());
} catch (Exception e) {
e.printStackTrace();
}
// Initialize yt-dlp for unthrottled YouTube downloads
try {
YoutubeDL.getInstance().init(this);
FFmpeg.getInstance().init(this);
} catch (Exception e) {
e.printStackTrace();
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.sam.downify.newpipe;

import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.downloader.Request;
import org.schabi.newpipe.extractor.downloader.Response;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;

public final class DownloaderImpl extends Downloader {
private static DownloaderImpl instance;
private final OkHttpClient client;

private DownloaderImpl() {
this.client = new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.build();
}

public static DownloaderImpl getInstance() {
if (instance == null) {
instance = new DownloaderImpl();
}
return instance;
}

public OkHttpClient getClient() {
return client;
}

@Override
public Response execute(Request request) throws IOException, ReCaptchaException {
final String httpMethod = request.httpMethod();
final String url = request.url();
final Map<String, List<String>> headers = request.headers();
final byte[] dataToSend = request.dataToSend();

okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder()
.method(httpMethod, dataToSend == null ? null :
RequestBody.create(dataToSend))
.url(url);

for (Map.Entry<String, List<String>> header : headers.entrySet()) {
for (String value : header.getValue()) {
requestBuilder.addHeader(header.getKey(), value);
}
}

okhttp3.Response response = client.newCall(requestBuilder.build()).execute();

if (response.code() == 429) {
response.close();
throw new ReCaptchaException("reCaptcha Challenge requested", url);
}

final ResponseBody body = response.body();
String responseBody = body == null ? "" : body.string();

return new Response(
response.code(),
response.message(),
response.headers().toMultimap(),
responseBody,
response.request().url().toString()
);
}
}
Loading