diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png new file mode 100644 index 0000000..ae4910e Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ diff --git a/app/src/main/java/me/harshithgoka/youtubedl/Extractor.java b/app/src/main/java/me/harshithgoka/youtubedl/Extractor.java index 3453371..e3711ac 100644 --- a/app/src/main/java/me/harshithgoka/youtubedl/Extractor.java +++ b/app/src/main/java/me/harshithgoka/youtubedl/Extractor.java @@ -200,6 +200,9 @@ public VideoInfo getFormats(String you_url) { String response; String video_id = ""; String thumbnail_url = ""; + String length = ""; + String view_count = ""; + String author = ""; JSONObject ret = new JSONObject(); try { @@ -209,11 +212,17 @@ public VideoInfo getFormats(String you_url) { Pattern ytcond_end = Pattern.compile(";[ ]*ytplayer\\.load"); String json = ytcond_end.split(ytconf.split(response)[1])[0]; JSONObject ytconfig = new JSONObject(json); - ret.put ("data", ytconfig); + ret.put("data", ytconfig); ret.put("status", true); - String fmts = ytconfig.getJSONObject("args").getString("url_encoded_fmt_stream_map") + "," + ytconfig.getJSONObject("args").getString("adaptive_fmts"); - String title = ytconfig.getJSONObject("args").optString("title", "videoplayback"); + JSONObject args = ytconfig.getJSONObject("args"); + String fmts = args.getString("url_encoded_fmt_stream_map") + "," + ytconfig.getJSONObject("args").getString("adaptive_fmts"); + String title = args.optString("title", "videoplayback"); + video_id = args.getString("video_id"); + length = args.getString("length_seconds"); + view_count = args.getString("view_count"); + author = args.getString("author"); + String[] fmts_enc = fmts.split(","); List formats = new ArrayList<>(); @@ -242,7 +251,7 @@ else if (params.contains("s")) { Pattern playerType = Pattern.compile("(html5player-([^/]+?)(?:/html5player(?:-new)?)?\\.js)|((?:www|player)-([^/]+)(?:/[a-z]{2}_[A-Z]{2})?/base\\.js)"); m = playerType.matcher(player_url); if (!m.find()) { - Log.d("ERR","Couldn't find Player URL"); + Log.d("ERR", "Couldn't find Player URL"); Log.d("ERR", response); } @@ -262,7 +271,7 @@ else if (params.contains("s")) { f.url = url; - for (String param: params) { + for (String param : params) { if (param.equals("itag")) { f.setItag(Integer.parseInt(query_pairs.get(param))); } @@ -279,10 +288,16 @@ else if (params.contains("s")) { formats.add(f); } - VideoInfo videoInfo = new VideoInfo(video_id, thumbnail_url, formats); + VideoInfo videoInfo = new VideoInfo(video_id, title, length, view_count, author, thumbnail_url, formats); return videoInfo; - + } catch (IllegalStateException e) { + try { + ret.put("message", e.toString()); + } catch (JSONException e1) { + e1.printStackTrace(); + } + Log.d("Err", e.toString()); } catch (IOException e) { try { ret.put("message", e.toString()); diff --git a/app/src/main/java/me/harshithgoka/youtubedl/MainActivity.java b/app/src/main/java/me/harshithgoka/youtubedl/MainActivity.java index 7f1e52d..db6108f 100644 --- a/app/src/main/java/me/harshithgoka/youtubedl/MainActivity.java +++ b/app/src/main/java/me/harshithgoka/youtubedl/MainActivity.java @@ -16,8 +16,8 @@ import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.text.method.ScrollingMovementMethod; +import android.util.Log; import android.view.View; -import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; @@ -54,9 +54,13 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe Pattern youtubeUrlPattern; - RecyclerView recyclerView; - FormatAdapter adapter; - LinearLayoutManager linearLayoutManager; + RecyclerView formatsRecyclerView; + FormatAdapter formatAdapter; + LinearLayoutManager formatLinearLayoutManager; + + RecyclerView viRecyclerView; + VideoInfoAdapter viAdapter; + LinearLayoutManager viLinearLayoutManager; BottomSheetBehavior bottomSheetBehavior; List progressBars; @@ -64,6 +68,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe SharedPreferences mPrefs; ArrayList history; + TextView videoTitle; + + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { @@ -115,24 +122,19 @@ protected void onCreate(Bundle savedInstanceState) { youtubeUrlPattern = Pattern.compile(extractor._VALID_URL); + // Formats Holder Bottom Sheet bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottom_sheet)); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - recyclerView = findViewById(R.id.recycler_view); - adapter = new FormatAdapter(getApplicationContext(), formats); - recyclerView.setAdapter(adapter); - linearLayoutManager = new LinearLayoutManager(getApplicationContext()); - recyclerView.setLayoutManager(linearLayoutManager); - - BottomAppBar bar = (BottomAppBar) findViewById(R.id.bar); - bar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // Handle the navigation click by showing a BottomDrawer etc. - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - } - }); + videoTitle = findViewById(R.id.video_title); + // Formats + formatsRecyclerView = findViewById(R.id.recycler_view); + formatAdapter = new FormatAdapter(getApplicationContext(), formats); + formatsRecyclerView.setAdapter(formatAdapter); + formatLinearLayoutManager = new LinearLayoutManager(getApplicationContext()); + formatsRecyclerView.setLayoutManager(formatLinearLayoutManager); + // History Get Content mPrefs = getPreferences(MODE_PRIVATE); Gson gson = new Gson(); String json = mPrefs.getString(HISTORY, ""); @@ -143,6 +145,23 @@ public void onClick(View v) { history = new ArrayList<>(); } + // History + viRecyclerView = findViewById(R.id.historyRecyclerView); + viAdapter = new VideoInfoAdapter(this, history); + viRecyclerView.setAdapter(viAdapter); + viLinearLayoutManager = new LinearLayoutManager(getApplicationContext()); + viRecyclerView.setLayoutManager(viLinearLayoutManager); + + + BottomAppBar bar = (BottomAppBar) findViewById(R.id.bar); + bar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Handle the navigation click by showing a BottomDrawer etc. + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); + } + }); + // ATTENTION: This was auto-generated to handle app links. Intent appLinkIntent = getIntent(); String appLinkAction = appLinkIntent.getAction(); @@ -241,6 +260,16 @@ public void hideLoading() { } } + void loadVideoInfo(VideoInfo videoInfo) { + Log.d("II", "Loading videoInfo"); + formats.clear(); + formatAdapter.notifyItemRangeRemoved(0, videoInfo.formats.size()); + formats.addAll(videoInfo.formats); + formatAdapter.notifyItemRangeInserted(0, videoInfo.formats.size()); + videoTitle.setText(videoInfo.title); + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); + } + @Override public void onClick(View v) { switch (v.getId()){ @@ -279,12 +308,12 @@ protected VideoInfo doInBackground(String... strings) { protected void onPostExecute(VideoInfo videoInfo) { hideLoading(); if (videoInfo != null) { + List formats = videoInfo.formats; - history.add(0, videoInfo); if (formats.size() > 0) { - MainActivity.this.formats.clear(); - MainActivity.this.formats.addAll(formats); - MainActivity.this.adapter.notifyDataSetChanged(); + history.add(0, videoInfo); + viAdapter.notifyItemInserted(0); + loadVideoInfo(videoInfo); String finalurl = formats.get(0).url; println(finalurl); diff --git a/app/src/main/java/me/harshithgoka/youtubedl/VideoInfo.java b/app/src/main/java/me/harshithgoka/youtubedl/VideoInfo.java index f143acf..c89f9cc 100644 --- a/app/src/main/java/me/harshithgoka/youtubedl/VideoInfo.java +++ b/app/src/main/java/me/harshithgoka/youtubedl/VideoInfo.java @@ -5,16 +5,44 @@ import java.util.ArrayList; import java.util.List; +import java.util.Locale; public class VideoInfo { public String video_id; public String thumbnail_url; + public String title; + public String author; + public int length; + public int view_count; public List formats; - VideoInfo(String id, String thumbnail_url, List formats) { + + VideoInfo(String id, String title, String length, String view_count, String author, String thumbnail_url, List formats) { this.video_id = id; + this.title = title; + this.author = author; + try { + this.view_count = Integer.parseInt(view_count); + } + catch (Exception e) { + // do nothing + this.view_count = -1; + } + + try { + this.length = Integer.parseInt(length); + } + catch (Exception e) { + // do nothing + this.length = -1; + } + this.thumbnail_url = thumbnail_url; this.formats = new ArrayList<>(); this.formats.addAll(formats); } + + public String getUrl() { + return String.format(Locale.UK, "https://www.youtube.com/watch?v=%s", video_id); + } } diff --git a/app/src/main/java/me/harshithgoka/youtubedl/VideoInfoAdapter.java b/app/src/main/java/me/harshithgoka/youtubedl/VideoInfoAdapter.java new file mode 100644 index 0000000..aba1fe0 --- /dev/null +++ b/app/src/main/java/me/harshithgoka/youtubedl/VideoInfoAdapter.java @@ -0,0 +1,93 @@ +package me.harshithgoka.youtubedl; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.net.Uri; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.List; +import java.util.Locale; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class VideoInfoAdapter extends RecyclerView.Adapter { + + List videoInfos; + Context context; + + VideoInfoAdapter(Context context, List videoInfos) { + this.context = context; + this.videoInfos = videoInfos; + } + + @NonNull + @Override + public VideoInfoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.video_info_item, parent, false); + + return new VideoInfoViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull VideoInfoViewHolder holder, int position) { + VideoInfo videoInfo = videoInfos.get(position); + holder.title.setText(videoInfo.title); + holder.videoId.setText(videoInfo.video_id); + holder.author.setText(videoInfo.author); + } + + @Override + public int getItemCount() { + if (videoInfos != null) + return videoInfos.size(); + else + return 0; + } + + class VideoInfoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + TextView title, videoId, author; + View copyLink; + public VideoInfoViewHolder(@NonNull View itemView) { + super(itemView); + title = itemView.findViewById(R.id.video_title); + videoId = itemView.findViewById(R.id.videoId); + copyLink = itemView.findViewById(R.id.copyLink); + author = itemView.findViewById(R.id.author); + copyLink.setOnClickListener(this); + itemView.setOnClickListener(this); + } + + void copyUrl (VideoInfo videoInfo) { + String url = videoInfo.getUrl(); + + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + assert clipboard != null; + ClipData clip = ClipData.newRawUri("DownloadURL", Uri.parse(url)); + clipboard.setPrimaryClip(clip); + + Toast.makeText(context, String.format(Locale.UK, "Copied Link: %s", url), Toast.LENGTH_SHORT).show(); + } + + @Override + public void onClick(View v) { + int pos = getAdapterPosition(); + VideoInfo videoInfo = videoInfos.get(pos); + + switch (v.getId()) { + case R.id.copyLink: + copyUrl(videoInfo); + break; + case R.id.videoInfo: + ((MainActivity) context).loadVideoInfo(videoInfo); + break; + } + } + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 8f026a9..9be60c1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,8 +11,7 @@ android:layout_height="match_parent"> + android:layout_height="match_parent"> @@ -68,14 +67,28 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textInputLayout" /> + + @@ -111,4 +124,5 @@ + diff --git a/app/src/main/res/layout/formats_layout.xml b/app/src/main/res/layout/formats_layout.xml index c3a57c2..94d25d7 100644 --- a/app/src/main/res/layout/formats_layout.xml +++ b/app/src/main/res/layout/formats_layout.xml @@ -7,6 +7,8 @@ style="@style/Widget.MaterialComponents.CardView" android:layout_width="match_parent" android:layout_height="match_parent" + android:translationZ="0dp" + android:elevation="0dp" app:behavior_hideable="true" app:behavior_peekHeight="300dp" @@ -35,13 +37,25 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + app:layout_constraintTop_toBottomOf="@+id/video_title" /> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index bbd3e02..036d09b 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index bbd3e02..036d09b 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index a2f5908..ba10e65 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..feb2ad1 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index 1b52399..ba10e65 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index ff10afd..1d63034 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..b2e16e5 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index 115a4c7..1d63034 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index dcd3cd8..0b54702 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..abb0d2e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index 459ca60..0b54702 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 8ca12fe..f3711c6 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..e376e19 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index 8e19b41..f3711c6 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index b824ebd..d61c029 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..e46b344 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index 4c19a13..d61c029 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 5154225..4111f87 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,8 +1,8 @@ - #6202ee + #1de9b6 #6000dd - #FF4081 + #42a5f5 #FFFFFF #000000 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index a46457f..17fcc5e 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,5 +2,5 @@ 180dp 16dp 16dp - 24dp + 28dp diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..c5d5899 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 545b9c6..6989c3e 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ -