/*** Copyright (c) 2012-2013 Samuele Rini This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses *** https://github.com/dentex/ytdownloader/ https://sourceforge.net/projects/ytdownloader/ *** Different Licenses and Credits where noted in code comments. */ package dentex.youtube.downloader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.bugsense.trace.BugSenseHandler; import com.matsuhiro.android.download.DownloadTask; import com.matsuhiro.android.download.DownloadTaskListener; import com.matsuhiro.android.download.Maps; import dentex.youtube.downloader.menu.AboutActivity; import dentex.youtube.downloader.menu.DonateActivity; import dentex.youtube.downloader.menu.TutorialsActivity; import dentex.youtube.downloader.utils.FetchUrl; import dentex.youtube.downloader.utils.Json; import dentex.youtube.downloader.utils.PopUps; import dentex.youtube.downloader.utils.RhinoRunner; import dentex.youtube.downloader.utils.Utils; public class ShareActivity extends Activity { private ProgressBar progressBar1; private ProgressBar progressBarD; private ProgressBar progressBarL; //private ProgressBar filesizeProgressBar; private static final String DEBUG_TAG = "ShareActivity"; private TextView tv; private TextView noVideoInfo; private ListView lv; private ArrayAdapter<String> aA; List<String> links = new ArrayList<String>(); List<String> codecs = new ArrayList<String>(); List<String> qualities = new ArrayList<String>(); List<String> stereo = new ArrayList<String>(); List<String> sizes = new ArrayList<String>(); List<String> itags = new ArrayList<String>(); List<String> listEntries = new ArrayList<String>(); private String titleRaw; private String basename; private int pos; private File path; private String validatedLink; private String vFilename = ""; public static Uri videoUri; private int icon; private CheckBox showAgain1; private CheckBox showAgain2; private TextView userFilename; private boolean sshInfoCheckboxEnabled; private boolean generalInfoCheckboxEnabled; private boolean fileRenameEnabled; private File chooserFolder; private AsyncDownload asyncDownload; //private AsyncSizeQuery asyncSizeQuery; private AsyncSizesFiller asyncSizesFiller; private boolean isAsyncDownloadRunning = false; private boolean isAsyncSizesFillerRunning = false; //private String videoFileSize; private AlertDialog helpDialog; //private AlertDialog waitBox; //private AlertDialog.Builder waitBuilder; private AlertDialog.Builder helpBuilder; private Bitmap img; private ImageView imgView; private String videoId; public static Context sShare; //private boolean showSizesInVideoList; //private boolean showSingleSize; ContextThemeWrapper boxThemeContextWrapper = new ContextThemeWrapper(this, R.style.BoxTheme); private int count; private String[] decryptionArray = null; private String jslink; private String decryptionRule; private String decryptionFunction; protected String ytid; private DownloadTaskListener dtl; private boolean autoModeEnabled = false; private boolean restartModeEnabled = false; private String extraId; //public String[] lv_arr; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); BugSenseHandler.leaveBreadcrumb("ShareActivity_onCreate"); sShare = getBaseContext(); // Theme init Utils.themeInit(this); setContentView(R.layout.activity_share); //showSizesInVideoList = YTD.settings.getBoolean("show_size_list", false); // Language init Utils.langInit(this); // loading views from the layout xml tv = (TextView) findViewById(R.id.textView1); noVideoInfo = (TextView) findViewById(R.id.share_activity_info); progressBarD = (ProgressBar) findViewById(R.id.progressBarD); progressBarL = (ProgressBar) findViewById(R.id.progressBarL); String theme = YTD.settings.getString("choose_theme", "D"); if (theme.equals("D")) { progressBar1 = progressBarD; progressBarL.setVisibility(View.GONE); } else { progressBar1 = progressBarL; progressBarD.setVisibility(View.GONE); } imgView = (ImageView)findViewById(R.id.imgview); lv = (ListView) findViewById(R.id.list); // YTD update initialization updateInit(); // Get intent, action and MIME type Intent intent = getIntent(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { BugSenseHandler.leaveBreadcrumb("Intent.ACTION_SEND"); if ("text/plain".equals(type)) { try { handleSendText(intent, action); Utils.logger("d", "handling ACTION_SEND", DEBUG_TAG); } catch (IOException e) { Log.e(DEBUG_TAG, "Error: " + e.getMessage(), e); } } } if (Intent.ACTION_VIEW.equals(action)) { BugSenseHandler.leaveBreadcrumb("Intent.ACTION_VIEW"); if (intent.hasCategory("AUTO")) { autoModeEnabled = true; extraId = intent.getStringExtra("id"); pos = intent.getIntExtra("position", 0); vFilename = intent.getStringExtra("filename"); Utils.logger("i", "Auto Mode Enabled:" + "\n -> id: " + extraId + "\n -> position: " + pos + "\n -> filename: " + vFilename, DEBUG_TAG); } else if (intent.hasCategory("RESTART")) { restartModeEnabled = true; extraId = intent.getStringExtra("id"); Utils.logger("i", "Restart Mode Enabled:" + "\n -> id: " + extraId, DEBUG_TAG); } try { handleSendText(intent, action); Utils.logger("d", "handling ACTION_VIEW", DEBUG_TAG); } catch (IOException e) { Log.e(DEBUG_TAG, "Error: " + e.getMessage(), e); } } } public static Context getContext() { return sShare; } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_share, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); if (!autoModeEnabled) { switch(item.getItemId()){ case R.id.menu_donate: startActivity(new Intent(this, DonateActivity.class)); return true; case R.id.menu_settings: startActivity(new Intent(this, SettingsActivity.class)); return true; case R.id.menu_about: startActivity(new Intent(this, AboutActivity.class)); return true; case R.id.menu_dashboard: launchDashboardActivity(); return true; case R.id.menu_tutorials: startActivity(new Intent(this, TutorialsActivity.class)); return true; default: return super.onOptionsItemSelected(item); } } else { return super.onOptionsItemSelected(item); } } private void launchDashboardActivity() { Intent dashboardIntent = new Intent(this, DashboardActivity.class); dashboardIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(dashboardIntent); } /*@Override protected void onStart() { super.onStart(); Utils.logger("v", "_onStart", DEBUG_TAG); } @Override protected void onRestart() { super.onRestart(); Utils.logger("v", "_onRestart"); } @Override public void onPause() { super.onPause(); Utils.logger("v", "_onPause"); } @Override protected void onStop() { super.onStop(); Utils.logger("v", "_onStop", DEBUG_TAG); }*/ @Override public void onBackPressed() { Utils.logger("v", "_onBackPressed", DEBUG_TAG); super.onBackPressed(); // To cancel the AsyncDownload AsyncSizesFiller tasks only on back button pressed (not when switching to other activities) if (isAsyncDownloadRunning) { Utils.logger("v", "canceling asyncDownload", DEBUG_TAG); asyncDownload.cancel(true); } if (isAsyncSizesFillerRunning) { Utils.logger("v", "canceling asyncSizesFiller", DEBUG_TAG); asyncSizesFiller.cancel(true); } } void handleSendText(Intent intent, String action) throws IOException { ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected()) { String sharedText = null; if (action.equals(Intent.ACTION_SEND)) { sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); } else if (action.equals(Intent.ACTION_VIEW)) { sharedText = intent.getDataString(); } if (sharedText != null) { if (linkValidator(sharedText) == "bad_link") { badOrNullLinkAlert(); } else if (sharedText != null) { showGeneralInfoTutorial(); asyncDownload = new AsyncDownload(); asyncDownload.execute(validatedLink); } } else { badOrNullLinkAlert(); } } else { progressBar1.setVisibility(View.GONE); tv.setVisibility(View.GONE); noVideoInfo.setText(getString(R.string.no_net)); noVideoInfo.setVisibility(View.VISIBLE); PopUps.showPopUp(getString(R.string.no_net), getString(R.string.no_net_dialog_msg), "alert", this); Button retry = (Button) findViewById(R.id.share_activity_retry_button); retry.setVisibility(View.VISIBLE); retry.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Utils.reload(ShareActivity.this); } }); } } public void badOrNullLinkAlert() { BugSenseHandler.leaveBreadcrumb("badOrNullLinkAlert"); progressBar1.setVisibility(View.GONE); PopUps.showPopUp(getString(R.string.error), getString(R.string.bad_link_dialog_msg), "alert", this); tv.setVisibility(View.GONE); noVideoInfo.setText(getString(R.string.bad_link)); noVideoInfo.setVisibility(View.VISIBLE); } private void showGeneralInfoTutorial() { generalInfoCheckboxEnabled = YTD.settings.getBoolean("general_info", true); if (generalInfoCheckboxEnabled == true) { AlertDialog.Builder adb = new AlertDialog.Builder(boxThemeContextWrapper); LayoutInflater adbInflater = LayoutInflater.from(ShareActivity.this); View generalInfo = adbInflater.inflate(R.layout.dialog_general_info, null); showAgain1 = (CheckBox) generalInfo.findViewById(R.id.showAgain1); showAgain1.setChecked(true); adb.setView(generalInfo); adb.setTitle(getString(R.string.tutorial_title)); adb.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (!showAgain1.isChecked()) { YTD.settings.edit().putBoolean("general_info", false).commit(); sshInfoCheckboxEnabled = YTD.settings.getBoolean("general_info", true); Utils.logger("v", "generalInfoCheckboxEnabled: " + generalInfoCheckboxEnabled, DEBUG_TAG); } } }); if (! ((Activity) this).isFinishing()) { adb.show(); } } } private String linkValidator(String sharedText) { Pattern pattern = Pattern.compile("(http://|https://).*(v=.{11}).*"); Matcher matcher = pattern.matcher(sharedText); if (matcher.find()) { validatedLink = matcher.group(1) + "www.youtube.com/watch?" + matcher.group(2); videoId = matcher.group(2).replace("v=", ""); return validatedLink; } return "bad_link"; } public void assignPath() { boolean Location = YTD.settings.getBoolean("swap_location", false); if (Location == false) { String location = YTD.settings.getString("standard_location", "Downloads"); Utils.logger("d", "location: " + location, DEBUG_TAG); if (location.equals("DCIM") == true) { path = YTD.dir_DCIM; } if (location.equals("Movies") == true) { path = YTD.dir_Movies; } if (location.equals("Downloads") == true) { path = YTD.dir_Downloads; } } else { String cs = YTD.settings.getString("CHOOSER_FOLDER", ""); chooserFolder = new File(cs); if (chooserFolder.exists()) { Utils.logger("d", "chooserFolder: " + chooserFolder, DEBUG_TAG); path = chooserFolder; } else { path = YTD.dir_Downloads; Utils.logger("w", "chooserFolder not found, falling back to Download path", DEBUG_TAG); } } if (!path.exists()) { if (new File(path.getAbsolutePath()).mkdirs()) { Utils.logger("w", "destination path not found, creating it now", DEBUG_TAG); } else { Log.e(DEBUG_TAG, "Something really bad happened with the download destination..."); } } Utils.logger("d", "path: " + path, DEBUG_TAG); } private class AsyncDownload extends AsyncTask<String, Integer, String> { protected void onPreExecute() { isAsyncDownloadRunning = true; tv.setText(R.string.loading); progressBar1.setIndeterminate(true); progressBar1.setVisibility(View.VISIBLE); } protected String doInBackground(String... urls) { try { Utils.logger("d", "doInBackground...", DEBUG_TAG); assignBitmapToVideoListThumbnail(generateThumbUrls()); FetchUrl fu = new FetchUrl(); return urlBlockMatchAndDecode(fu.doFetch(urls[0])); } catch (Exception e) { Log.e(DEBUG_TAG, "downloadUrl: " + e.getMessage()); BugSenseHandler.sendExceptionMessage(DEBUG_TAG + "-> downloadUrl: ", e.getMessage(), e); return "e"; } } public void doProgress(int value){ publishProgress(value); } protected void onProgressUpdate(Integer... values) { progressBar1.setProgress(values[0]); } @Override protected void onPostExecute(String result) { progressBar1.setVisibility(View.GONE); if (YTD.settings.getBoolean("show_thumb", false) && !((result == null || result.equals("e")) || (result != null && result.equals("login_required")) || (result != null && result.equals("rtmpe")) ) ) { imgView.setImageBitmap(img); } isAsyncDownloadRunning = false; if (result == null || result.equals("e") && !autoModeEnabled) { BugSenseHandler.leaveBreadcrumb("invalid_url"); //tv.setText(getString(R.string.invalid_url_short)); //PopUps.showPopUp(getString(R.string.error), getString(R.string.invalid_url), "alert", ShareActivity.this); //titleRaw = getString(R.string.invalid_response); noVideosMsgs("alert", getString(R.string.invalid_url)); } //lv_arr = listEntries.toArray(new String[0]); if (result != null && result.equals("login_required") && !autoModeEnabled) { BugSenseHandler.leaveBreadcrumb("login_required"); noVideosMsgs("info", getString(R.string.login_required)); } if (result != null && result.equals("rtmpe")) { BugSenseHandler.leaveBreadcrumb("encrypted_streams"); listEntries.clear(); noVideosMsgs("info", getString(R.string.encrypted_streams)); } aA = new ShareListAdapter(listEntries, ShareActivity.this); if (autoModeEnabled) { BugSenseHandler.leaveBreadcrumb("autoModeEnabled"); assignPath(); try { callDownloadManager(links.get(pos), pos, vFilename); } catch (IndexOutOfBoundsException e) { Toast.makeText(ShareActivity.this, getString(R.string.video_list_error_toast), Toast.LENGTH_SHORT).show(); launchDashboardActivity(); } } else { lv.setAdapter(aA); //if (YTD.settings.getBoolean("show_size_list", false)) { asyncSizesFiller = new AsyncSizesFiller(); asyncSizesFiller.execute(links.toArray(new String[0])); //} } Utils.logger("d", "LISTview done with " + aA.getCount() + " items.", DEBUG_TAG); tv.setText(titleRaw); lv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //Utils.logger("i", "Selected link: " + links.get(pos), DEBUG_TAG); BugSenseHandler.leaveBreadcrumb("ShareActivity_onItemClick"); assignPath(); pos = position; //pos = 45; // to test IndexOutOfBound Exception... vFilename = composeVideoFilename(); helpBuilder = new AlertDialog.Builder(boxThemeContextWrapper); helpBuilder.setIcon(android.R.drawable.ic_dialog_info); helpBuilder.setTitle(getString(R.string.list_click_dialog_title)); /*if (showSizesInVideoList) { showSingleSize = true; } else { showSingleSize = YTD.settings.getBoolean("show_size", false); }*/ boolean showSize = false; try { if (sizes.get(pos).equals("")) { /*if (showSingleSize) { showSize = true; asyncSizeQuery = new AsyncSizeQuery(); asyncSizeQuery.execute(links.get(position)); } else {*/ helpBuilder.setMessage(titleRaw + getString(R.string.codec) + " " + codecs.get(pos) + getString(R.string.quality) + " " + qualities.get(pos) + stereo.get(pos)); //} } else { helpBuilder.setMessage(titleRaw + getString(R.string.codec) + " " + codecs.get(pos) + getString(R.string.quality) + " " + qualities.get(pos) + stereo.get(pos) + getString(R.string.size) + " " + sizes.get(pos).replace(" - ", "")); } } catch (IndexOutOfBoundsException e) { Toast.makeText(ShareActivity.this, getString(R.string.video_list_error_toast), Toast.LENGTH_SHORT).show(); } helpBuilder.setPositiveButton(getString(R.string.list_click_download_local), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { try { fileRenameEnabled = YTD.settings.getBoolean("enable_rename", false); if (fileRenameEnabled == true) { AlertDialog.Builder adb = new AlertDialog.Builder(boxThemeContextWrapper); LayoutInflater adbInflater = LayoutInflater.from(ShareActivity.this); View inputFilename = adbInflater.inflate(R.layout.dialog_input_filename, null); userFilename = (TextView) inputFilename.findViewById(R.id.input_filename); userFilename.setText(basename); adb.setView(inputFilename); adb.setTitle(getString(R.string.rename_dialog_title)); adb.setMessage(getString(R.string.rename_dialog_msg)); adb.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { basename = userFilename.getText().toString(); vFilename = composeVideoFilename(); callDownloadManager(links.get(pos), pos, vFilename); } }); adb.setNegativeButton(getString(R.string.dialogs_negative), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // cancel } }); if (! ((Activity) ShareActivity.this).isFinishing()) { adb.show(); } } else { //vFilename = composeVideoFilename(); callDownloadManager(links.get(pos), pos, vFilename); } } catch (IndexOutOfBoundsException e) { Toast.makeText(ShareActivity.this, getString(R.string.video_list_error_toast), Toast.LENGTH_SHORT).show(); } } }); // show central button for SSH send if enabled in prefs if (!YTD.settings.getBoolean("ssh_to_longpress_menu", false)) { helpBuilder.setNeutralButton(getString(R.string.list_click_download_ssh), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { sendViaSsh(); } }); } helpBuilder.setNegativeButton(getString(R.string.dialogs_negative), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //Toast.makeText(ShareActivity.this, "Download canceled...", Toast.LENGTH_SHORT).show(); } }); //if (!showSingleSize || (showSizesInVideoList && showSingleSize)) { if (!showSize) { helpDialog = helpBuilder.create(); if (! ((Activity) ShareActivity.this).isFinishing()) { helpDialog.show(); } } } }); lv.setLongClickable(true); lv.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) { BugSenseHandler.leaveBreadcrumb("ShareActivity_onItemLongClick"); pos = position; vFilename = composeVideoFilename(); AlertDialog.Builder builder = new AlertDialog.Builder(boxThemeContextWrapper); if (!YTD.settings.getBoolean("ssh_to_longpress_menu", false)) { builder.setTitle(R.string.long_click_title).setItems(R.array.long_click_entries, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: // copy copy(position); break; case 1: // share share(position, vFilename); } } }); } else { builder.setTitle(R.string.long_click_title).setItems(R.array.long_click_entries2, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //vFilename = composeVideoFilename(); switch (which) { case 0: // copy copy(position); break; case 1: // share share(position, vFilename); break; case 2: // SSH sendViaSsh(); } } }); } builder.create(); if (! ((Activity) ShareActivity.this).isFinishing()) { builder.show(); } return true; } }); } private void noVideosMsgs(String type, String cause) { BugSenseHandler.leaveBreadcrumb("noVideosMsgs"); PopUps.showPopUp(getString(R.string.no_video_available), cause, type, ShareActivity.this); tv.setVisibility(View.GONE); noVideoInfo.setVisibility(View.VISIBLE); } private void share(final int position, String filename) { BugSenseHandler.leaveBreadcrumb("ShareActivity_share"); Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, filename); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, links.get(position)); startActivity(Intent.createChooser(sharingIntent, "Share YouTube link:")); } private void copy(final int position) { BugSenseHandler.leaveBreadcrumb("ShareActivity_copy"); ClipData cmd = ClipData.newPlainText("simple text", links.get(position)); ClipboardManager cb = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); cb.setPrimaryClip(cmd); } private boolean useQualitySuffix() { boolean enabled = YTD.settings.getBoolean("enable_q_suffix", true); return enabled; } private String composeVideoFilename() { String composedName; if (useQualitySuffix()) { boolean showRes = YTD.settings.getBoolean("show_resolutions", false); if (showRes) { composedName = basename + "_" + itags.get(pos).replace("/", "-") + stereo.get(pos) + "." + codecs.get(pos); } else { composedName = basename + "_" + qualities.get(pos) + stereo.get(pos) + "." + codecs.get(pos); } } else { composedName = basename + stereo.get(pos) + "." + codecs.get(pos); } Utils.logger("d", "videoFilename: " + composedName, DEBUG_TAG); return composedName; } private void callConnectBot() { BugSenseHandler.leaveBreadcrumb("callConnectBot"); Context context = getApplicationContext(); PackageManager pm = context.getPackageManager(); final String connectBotFlavour = YTD.settings.getString("connectbot_flavour", "org.connectbot"); String connectBotFlavourPlain = "ConnectBot"; if (connectBotFlavour.equals("sk.vx.connectbot")) connectBotFlavourPlain = "VX " + connectBotFlavourPlain; if (connectBotFlavour.equals("org.woltage.irssiconnectbot")) connectBotFlavourPlain = "Irssi " + connectBotFlavourPlain; Intent appStartIntent = pm.getLaunchIntentForPackage(connectBotFlavour); if (null != appStartIntent) { Utils.logger("d", "appStartIntent: " + appStartIntent, DEBUG_TAG); context.startActivity(appStartIntent); } else { AlertDialog.Builder cb = new AlertDialog.Builder(boxThemeContextWrapper); cb.setTitle(getString(R.string.callConnectBot_dialog_title, connectBotFlavourPlain)); cb.setMessage(getString(R.string.callConnectBot_dialog_msg)); icon = android.R.drawable.ic_dialog_alert; cb.setIcon(icon); cb.setPositiveButton(getString(R.string.callConnectBot_dialog_positive), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("market://details?id=" + connectBotFlavour)); try { startActivity(intent); } catch (ActivityNotFoundException exception){ PopUps.showPopUp(getString(R.string.no_market), getString(R.string.no_net_dialog_msg), "alert", ShareActivity.this); } } }); cb.setNegativeButton(getString(R.string.dialogs_negative), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // cancel } }); AlertDialog helpDialog = cb.create(); if (! ((Activity) ShareActivity.this).isFinishing()) { helpDialog.show(); } } } private void sendViaSsh() { BugSenseHandler.leaveBreadcrumb("sendViaSsh"); try { String wgetCmd; Boolean shortSshCmdEnabled = YTD.settings.getBoolean("enable_connectbot_short_cmd", false); if (shortSshCmdEnabled) { wgetCmd = "wget -e \"convert-links=off\" --keep-session-cookies --save-cookies /dev/null --no-check-certificate \'" + links.get(pos) + "\' -O " + vFilename; } else { wgetCmd = "REQ=`wget -q -e \"convert-links=off\" --keep-session-cookies --save-cookies /dev/null --no-check-certificate \'" + validatedLink + "\' -O-` && urlblock=`echo $REQ | grep -oE \'url_encoded_fmt_stream_map\": \".*\' | sed -e \'s/\", \".*//\'" + " -e \'s/url_encoded_fmt_stream_map\": \"//\'` && urlarray=( `echo $urlblock | sed \'s/,/\\n\\n/g\'` ) && N=" + pos + " && block=`echo \"${urlarray[$N]}\" | sed -e \'s/%3A/:/g\' -e \'s/%2F/\\//g\' -e \'s/%3F/\\?/g\' -e \'s/%3D/\\=/g\'" + " -e \'s/%252C/%2C/g\' -e \'s/%26/\\&/g\' -e \'s/%253A/\\:/g\' -e \'s/\", \"/\"-\"/\' -e \'s/sig=/signature=/\'" + " -e \'s/x-flv/flv/\' -e \'s/\\\\\\u0026/\\&/g\'` && url=`echo $block | grep -oE \'http://.*\' | sed -e \'s/&type=.*//\'" + " -e \'s/&signature=.*//\' -e \'s/&quality=.*//\' -e \'s/&fallback_host=.*//\'` && sig=`echo $block | " + "grep -oE \'signature=.{81}\'` && downloadurl=`echo $url\\&$sig | sed \'s/&itag=[0-9][0-9]&signature/\\&signature/\'` && " + "wget -e \"convert-links=off\" --keep-session-cookies --save-cookies /dev/null --tries=5 --timeout=45 --no-check-certificate " + "\"$downloadurl\" -O " + vFilename; } Utils.logger("d", "wgetCmd: " + wgetCmd, DEBUG_TAG); ClipData cmd = ClipData.newPlainText("simple text", wgetCmd); ClipboardManager cb = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); cb.setPrimaryClip(cmd); sshInfoCheckboxEnabled = YTD.settings.getBoolean("ssh_info", true); if (sshInfoCheckboxEnabled == true) { AlertDialog.Builder adb = new AlertDialog.Builder(boxThemeContextWrapper); LayoutInflater adbInflater = LayoutInflater.from(ShareActivity.this); View showAgain = adbInflater.inflate(R.layout.dialog_show_again_checkbox, null); showAgain2 = (CheckBox) showAgain.findViewById(R.id.showAgain2); showAgain2.setChecked(true); adb.setView(showAgain); adb.setTitle(getString(R.string.ssh_info_tutorial_title)); adb.setMessage(getString(R.string.ssh_info_tutorial_msg)); adb.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (!showAgain2.isChecked()) { YTD.settings.edit().putBoolean("ssh_info", false).apply(); Utils.logger("d", "sshInfoCheckboxEnabled: " + false, DEBUG_TAG); } callConnectBot(); } }); if (! ((Activity) ShareActivity.this).isFinishing()) { adb.show(); } } else { callConnectBot(); } } catch (IndexOutOfBoundsException e) { Toast.makeText(ShareActivity.this, getString(R.string.video_list_error_toast), Toast.LENGTH_SHORT).show(); } } } private void callDownloadManager(final String link, final int position, final String nameOfVideo) { BugSenseHandler.leaveBreadcrumb("callDownloadManager"); final String aExt = findAudioCodec(); dtl = new DownloadTaskListener() { @Override public void preDownload(DownloadTask task) { long ID = task.getDownloadId(); Utils.logger("d", "__preDownload on ID: " + ID, DEBUG_TAG); Maps.mNetworkSpeedMap.put(ID, (long) 0); Json.addEntryToJsonFile( sShare, String.valueOf(ID), YTD.JSON_DATA_TYPE_V, videoId, pos, YTD.JSON_DATA_STATUS_IN_PROGRESS, path.getAbsolutePath(), nameOfVideo, basename, aExt, "-", false); writeThumbToDisk(); if (!autoModeEnabled) YTD.sequence.add(ID); YTD.NotificationHelper(); } @Override public void updateProcess(DownloadTask task) { // nothing to do } @Override public void finishDownload(DownloadTask task) { long ID = task.getDownloadId(); String nameOfVideo = task.getDownloadedFileName(); Utils.logger("d", "__finishDownload on ID: " + ID, DEBUG_TAG); Utils.scanMedia(getApplicationContext(), new String[] { path.getPath() + File.separator + nameOfVideo }, new String[] {"video/*"}); long downloadTotalSize = Maps.mTotalSizeMap.get(ID); String size = String.valueOf(Utils.MakeSizeHumanReadable(downloadTotalSize, false)); Json.addEntryToJsonFile( sShare, String.valueOf(ID), YTD.JSON_DATA_TYPE_V, videoId, pos, YTD.JSON_DATA_STATUS_COMPLETED, path.getPath(), nameOfVideo, basename, aExt, size, false); if (DashboardActivity.isDashboardRunning) DashboardActivity.refreshlist(DashboardActivity.sDashboard); YTD.removeIdUpdateNotification(ID); YTD.videoinfo.edit().remove(String.valueOf(ID) + "_link").commit(); //YTD.videoinfo.edit().remove(String.valueOf(ID) + "_position").commit(); Maps.removeFromAllMaps(ID); } @Override public void errorDownload(DownloadTask task, Throwable error) { long ID = task.getDownloadId(); String nameOfVideo = task.getDownloadedFileName(); Utils.logger("w", "__errorDownload on ID: " + ID, DEBUG_TAG); Toast.makeText(sShare, nameOfVideo + ": " + getString(R.string.download_failed), Toast.LENGTH_LONG).show(); String status; String size; if (error != null && error.getMessage().equals("http error code: 403")) { status = YTD.JSON_DATA_STATUS_FAILED; size = "-"; } else { status = YTD.JSON_DATA_STATUS_PAUSED; try { Long bytes_downloaded = Maps.mDownloadSizeMap.get(ID); Long bytes_total = Maps.mTotalSizeMap.get(ID); String progress = String.valueOf(Maps.mDownloadPercentMap.get(ID)); String readableBytesDownloaded = Utils.MakeSizeHumanReadable(bytes_downloaded, false); String readableBytesTotal = Utils.MakeSizeHumanReadable(bytes_total, false); String progressRatio = readableBytesDownloaded + "/" + readableBytesTotal; size = progressRatio + " (" + progress + "%)"; } catch (NullPointerException e) { Utils.logger("w", "errorDownload: NPE @ DM Maps", DEBUG_TAG); size = "-"; } } Json.addEntryToJsonFile( sShare, String.valueOf(ID), YTD.JSON_DATA_TYPE_V, videoId, pos, status, path.getPath(), nameOfVideo, basename, aExt, size, false); if (DashboardActivity.isDashboardRunning) DashboardActivity.refreshlist(DashboardActivity.sDashboard); YTD.removeIdUpdateNotification(ID); } }; //TODO File dest = new File(path, vFilename); File destTemp = new File(path, vFilename + DownloadTask.TEMP_SUFFIX); String previousJson = Json.readJsonDashboardFile(sShare); boolean blockDashboardLaunch = false; if (dest.exists() || (destTemp.exists() && previousJson.contains(dest.getName())) && !autoModeEnabled && !restartModeEnabled) { blockDashboardLaunch = true; PopUps.showPopUp(getString(R.string.long_press_warning_title), getString(R.string.menu_import_double), "info", ShareActivity.this); } else { long id = 0; if (autoModeEnabled || restartModeEnabled) { id = Long.parseLong(extraId); } else { id = System.currentTimeMillis(); } try { DownloadTask dt = new DownloadTask(this, id, link, vFilename, path.getPath(), dtl, false); YTD.videoinfo.edit().putString(String.valueOf(id) + "_link", link).apply(); //YTD.videoinfo.edit().putInt(String.valueOf(id) + "_position", position).apply(); Maps.dtMap.put(id, dt); dt.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } catch (MalformedURLException e) { Log.e(DEBUG_TAG, "unable to start Download Manager -> " + e.getMessage()); } } if (autoModeEnabled && !blockDashboardLaunch) { launchDashboardActivity(); } } private String findAudioCodec() { String aExt = null; if (codecs.get(pos).equals("webm")) aExt = ".ogg"; if (codecs.get(pos).equals("mp4")) aExt = ".aac"; if (codecs.get(pos).equals("flv") && qualities.get(pos).equals("small")) aExt = ".mp3"; if (codecs.get(pos).equals("flv") && qualities.get(pos).equals("medium")) aExt = ".aac"; if (codecs.get(pos).equals("flv") && qualities.get(pos).equals("large")) aExt = ".aac"; if (codecs.get(pos).equals("3gpp")) aExt = ".aac"; return aExt; } private String urlBlockMatchAndDecode(String content) { if (asyncDownload.isCancelled()) { Utils.logger("d", "asyncDownload cancelled @ urlBlockMatchAndDecode begin", DEBUG_TAG); return "Cancelled!"; } Pattern rtmpePattern = Pattern.compile("rtmpe=yes|conn=rtmpe"); Matcher rtmpeMatcher = rtmpePattern.matcher(content); if (rtmpeMatcher.find()) { return "rtmpe"; } findVideoFilenameBase(content); findJs(content); Pattern loginPattern = Pattern.compile("restrictions:age"); Matcher loginMatcher = loginPattern.matcher(content); if (loginMatcher.find()) { return "login_required"; } Pattern streamsPattern = Pattern.compile("url_encoded_fmt_stream_map\\\": \\\"(.*?)\\\""); Matcher streamsMatcher = streamsPattern.matcher(content); if (streamsMatcher.find()) { Pattern blockPattern = Pattern.compile(","); Matcher blockMatcher = blockPattern.matcher(streamsMatcher.group(1)); if (blockMatcher.find() && !asyncDownload.isCancelled()) { String[] CQS = streamsMatcher.group(1).split(blockPattern.toString()); count = (CQS.length-1); Utils.logger("d", "number of entries found: " + count, DEBUG_TAG); int index = 0; progressBar1.setIndeterminate(false); decryptionArray = null; while ((index+1) < CQS.length) { try { CQS[index] = URLDecoder.decode(CQS[index], "UTF-8"); } catch (UnsupportedEncodingException e) { Log.e(DEBUG_TAG, e.getMessage()); } asyncDownload.doProgress((int) ((index / (float) count) * 100)); Utils.logger("v", "block " + index + ": " + CQS[index], DEBUG_TAG); codecMatcher(CQS[index], index); qualityMatcher(CQS[index], index); stereoMatcher(CQS[index], index); resolutionMatcher(CQS[index], index); linkComposer(CQS[index], index); index++; } listEntriesBuilder(); } else { Utils.logger("d", "asyncDownload cancelled @ 'findCodecAndQualityAndLinks' match", DEBUG_TAG); } return "ok"; } else { return "e"; } } private class AsyncSizesFiller extends AsyncTask<String, String, Void> { protected void onPreExecute() { isAsyncSizesFillerRunning = true; } @Override protected Void doInBackground(String... urls) { for (int i = 0; i < urls.length; i++) { if (!this.isCancelled()) { String size = getVideoFileSize(urls[i]); if (size.equals("-")) { Utils.logger("w", "trying getVideoFileSize 2nd time", DEBUG_TAG); size = getVideoFileSize(urls[i]); } Utils.logger("d", "index: " + i + ", size: " + size, DEBUG_TAG); publishProgress(String.valueOf(i), size); } } return null; } protected void onProgressUpdate(String... i) { Integer index = Integer.valueOf(i[0]); String newValue = i[1]; sizes.remove(index); sizes.add(index, " - " + newValue); listEntries.clear(); listEntriesBuilder(); aA.notifyDataSetChanged(); } @Override protected void onPostExecute(Void unused) { Utils.logger("v", "AsyncSizesFiller # onPostExecute", DEBUG_TAG); isAsyncSizesFillerRunning = false; } } private void findVideoFilenameBase(String content) { Pattern titlePattern = Pattern.compile("<title>(.*?)</title>"); Matcher titleMatcher = titlePattern.matcher(content); if (titleMatcher.find()) { titleRaw = titleMatcher.group().replaceAll("(<| - YouTube</)title>", ""); titleRaw = android.text.Html.fromHtml(titleRaw).toString(); basename = titleRaw.replaceAll("\\W", "_"); } else { basename = "Youtube Video"; } Utils.logger("d", "findVideoFilenameBase: " + basename, DEBUG_TAG); } private void listEntriesBuilder() { Iterator<String> codecsIter = codecs.iterator(); Iterator<String> qualitiesIter = qualities.iterator(); Iterator<String> stereoIter = stereo.iterator(); Iterator<String> sizesIter = sizes.iterator(); Iterator<String> itagsIter = itags.iterator(); //boolean showSize = YTD.settings.getBoolean("show_size_list", false); boolean showRes = YTD.settings.getBoolean("show_resolutions", false); while (codecsIter.hasNext()) { /*String size; if (showSize) { size = sizesIter.next(); } else { size = ""; }*/ try { String size = sizesIter.next(); String res; if (showRes) { res = itagsIter.next(); } else { res = qualitiesIter.next(); } listEntries.add(codecsIter.next().toUpperCase(Locale.ENGLISH).replace("WEBM", "WebM") + " - " + res + stereoIter.next() + size); } catch (NoSuchElementException e) { listEntries.add("//"); } } } private void linkComposer(String block, int i) { Pattern urlPattern = Pattern.compile("url=(.+?)\\\\u0026"); Matcher urlMatcher = urlPattern.matcher(block); String url = null; if (urlMatcher.find()) { url = urlMatcher.group(1); } else { Pattern urlPattern2 = Pattern.compile("url=(.+?)$"); Matcher urlMatcher2 = urlPattern2.matcher(block); if (urlMatcher2.find()) { url = urlMatcher2.group(1); } else { Log.e(DEBUG_TAG, "url: " + url); } } String sig = null; Pattern sigPattern = Pattern.compile("sig=(.+?)\\\\u0026"); Matcher sigMatcher = sigPattern.matcher(block); if (sigMatcher.find()) { sig = "signature=" + sigMatcher.group(1); Utils.logger("d", "non-ecrypted signature found on step 1", DEBUG_TAG); } else { Pattern sigPattern2 = Pattern.compile("sig=(.+?)$"); Matcher sigMatcher2 = sigPattern2.matcher(block); if (sigMatcher2.find()) { sig = "signature=" + sigMatcher2.group(1); Utils.logger("d", "non-ecrypted signature found on step 2", DEBUG_TAG); } else { Pattern sigPattern3 = Pattern.compile("sig=([[0-9][A-Z]]{39,40}\\.[[0-9][A-Z]]{39,40})"); Matcher sigMatcher3 = sigPattern3.matcher(block); if (sigMatcher3.find()) { sig = "signature=" + sigMatcher3.group(1); Utils.logger("d", "non-ecrypted signature found on step 3", DEBUG_TAG); } else { Pattern sigPattern4 = Pattern.compile("^s=(.+?)\\\\u0026"); Matcher sigMatcher4 = sigPattern4.matcher(block); if (sigMatcher4.find()) { Utils.logger("d", "encrypted signature found on step 1; length is " + sigMatcher4.group(1).length(), DEBUG_TAG); sig = "signature=" + decryptExpSig(sigMatcher4.group(1)); } else { Pattern sigPattern5 = Pattern.compile("\\\\u0026s=(.+?)\\\\u0026"); Matcher sigMatcher5 = sigPattern5.matcher(block); if (sigMatcher5.find()) { Utils.logger("d", "encrypted signature found on step 2; length is " + sigMatcher5.group(1).length(), DEBUG_TAG); sig = "signature=" + decryptExpSig(sigMatcher5.group(1)); } else { Pattern sigPattern6 = Pattern.compile("\\\\u0026s=(.+?)$"); Matcher sigMatcher6 = sigPattern6.matcher(block); if (sigMatcher6.find()) { Utils.logger("d", "encrypted signature found on step 3; length is " + sigMatcher6.group(1).length(), DEBUG_TAG); sig = "signature=" + decryptExpSig(sigMatcher6.group(1)); } else { Log.e(DEBUG_TAG, "sig: " + sig); } } } } } } Utils.logger("v", "url " + i + ": " + url, DEBUG_TAG); Utils.logger("v", "sig " + i + ": " + sig, DEBUG_TAG); String composedLink = url + "&" + sig; links.add(composedLink); //Utils.logger("i", composedLink); /*if (YTD.settings.getBoolean("show_size_list", false) && !asyncDownload.isCancelled()) { String size = getVideoFileSize(composedLink); sizes.add(size); Utils.logger("d", "size " + i + ": " + size, DEBUG_TAG); }*/ sizes.add(""); } private String decryptExpSig(String sig) { FetchUrl fu = new FetchUrl(); if (decryptionArray == null) { decryptionRule = null; String jsCode = fu.doFetch(jslink); String findSignatureCode = "function isInteger(n) {" + " return (typeof n==='number' && n%1==0);" + "}" + "function findSignatureCode(sourceCode) {" + " var functionNameMatches=sourceCode.match(/\\.signature\\s*=\\s*(\\w+)\\(\\w+\\)/);" + " var functionName=(functionNameMatches)?functionNameMatches[1]:null;" + " " + " var regCode=new RegExp('function '+functionName+" + " '\\\\s*\\\\(\\\\w+\\\\)\\\\s*{\\\\w+=\\\\w+\\\\.split\\\\(\"\"\\\\);(.+);return \\\\w+\\\\.join');" + " var functionCodeMatches=sourceCode.match(regCode);" + " var functionCode=(functionCodeMatches)?functionCodeMatches[1]:null;" + " " + " var regSlice=new RegExp('slice\\\\s*\\\\(\\\\s*(.+)\\\\s*\\\\)');" + " var regSwap=new RegExp('\\\\w+\\\\s*\\\\(\\\\s*\\\\w+\\\\s*,\\\\s*([0-9]+)\\\\s*\\\\)');" + " var regInline=new RegExp('\\\\w+\\\\[0\\\\]\\\\s*=\\\\s*\\\\w+\\\\[([0-9]+)\\\\s*%\\\\s*\\\\w+\\\\.length\\\\]');" + " var functionCodePieces = functionCode.split(';');" + " var decodeArray=[], signatureLength=81;" + " for (var i=0; i<functionCodePieces.length; i++) {" + " functionCodePieces[i]=functionCodePieces[i].trim();" + " if (functionCodePieces[i].length==0) {" + " } else if (functionCodePieces[i].indexOf('slice') >= 0) {" + " var sliceMatches=functionCodePieces[i].match(regSlice);" + " var slice=(sliceMatches)?sliceMatches[1]:null;" + " slice=parseInt(slice, 10);" + " if (isInteger(slice)){ " + " decodeArray.push(-slice);" + " signatureLength+=slice;" + " } " + " } else if (functionCodePieces[i].indexOf('reverse') >= 0) {" + " decodeArray.push(0);" + " } else if (functionCodePieces[i].indexOf('[0]') >= 0) {" + " if (i+2<functionCodePieces.length && functionCodePieces[i+1].indexOf('.length') >= 0 &&" + "functionCodePieces[i+1].indexOf('[0]') >= 0) {" + " var inlineMatches=functionCodePieces[i+1].match(regInline);" + " var inline=(inlineMatches)?inlineMatches[1]:null;" + " inline=parseInt(inline, 10);" + " decodeArray.push(inline);" + " i+=2;" + " } " + " } else if (functionCodePieces[i].indexOf(',') >= 0) {" + " var swapMatches=functionCodePieces[i].match(regSwap);" + " var swap=(swapMatches)?swapMatches[1]:null;" + " swap=parseInt(swap, 10);" + " if (isInteger(swap)){" + " decodeArray.push(swap);" + " } " + " }" + " }" + " return decodeArray;" + "}"; decryptionArray = RhinoRunner.obtainDecryptionArray(jsCode, findSignatureCode); decryptionFunction = "function decryptSignature(a){ a=a.split(\"\"); "; for (int i = 0; i < decryptionArray.length; i++) { //Utils.logger("i", "decryptionArray: " + decryptionArray[i], DEBUG_TAG); if (i == 0) { decryptionRule = decryptionArray[i]; } else { decryptionRule = decryptionRule + "," + decryptionArray[i]; } int rule = Integer.parseInt(decryptionArray[i]); if (rule == 0) decryptionFunction = decryptionFunction + "a=a.reverse(); "; if (rule < 0) decryptionFunction = decryptionFunction + "a=a.slice("+ -rule +"); "; if (rule > 0) decryptionFunction = decryptionFunction + "a=swap(a,"+ rule +"); "; } decryptionFunction = decryptionFunction + "return a.join(\"\")} function swap(a,b){ var c=a[0]; a[0]=a[b%a.length]; a[b]=c; return a };"; Utils.logger("i", "decryptionRule (lenght is " + decryptionArray.length + "): " + decryptionRule, DEBUG_TAG); Utils.logger("i", "decryptionFunction: " + decryptionFunction, DEBUG_TAG); } String signature = RhinoRunner.decipher(sig, decryptionFunction); /*if (signature == sig || signature.isEmpty() || signature == null) { String decryptSignatureLinkAtSf = "http://sourceforge.net/projects/ytdownloader/files/utils/decryptSignature/download"; Utils.logger("w", "signature empty, null or not deciphered" + "\n -> falling back on JS function from " + decryptSignatureLinkAtSf, DEBUG_TAG); String decryptFunction2 = fu.doFetch(decryptSignatureLinkAtSf); signature = RhinoRunner.decipher2(sig, decryptionRule, decryptFunction2); }*/ return signature; } private void findJs(String content) { Pattern jsPattern = Pattern.compile("\"js\":\\s*\"([^\"]+)\""); Matcher jsMatcher = jsPattern.matcher(content); if (jsMatcher.find()) { jslink = jsMatcher.group(1).replaceAll("\\\\", ""); } else { jslink = "NOT_FOUND"; } Utils.logger("v", "jslink: " + jslink, DEBUG_TAG); } /*private class AsyncSizeQuery extends AsyncTask<String, Void, String> { protected void onPreExecute() { waitBuilder = new AlertDialog.Builder(boxThemeContextWrapper); LayoutInflater adbInflater = LayoutInflater.from(ShareActivity.this); View barView = adbInflater.inflate(R.layout.wait_for_filesize, null); filesizeProgressBar = (ProgressBar) barView.findViewById(R.id.filesizeProgressBar); filesizeProgressBar.setVisibility(View.VISIBLE); waitBuilder.setView(barView); waitBuilder.setIcon(android.R.drawable.ic_dialog_info); waitBuilder.setTitle(R.string.wait); waitBuilder.setMessage(titleRaw + getString(R.string.codec) + " " + codecs.get(pos) + getString(R.string.quality) + " " + qualities.get(pos) + stereo.get(pos));*/ /* * next two listener from StackOverflow: * http://stackoverflow.com/questions/7801971/android-how-to-override-onbackpressed-in-alertdialog * * Q & A1: http://stackoverflow.com/users/964589/pooks * A2: http://stackoverflow.com/users/2104941/lettings-mall (modified) */ // this handles the BACK button only /*waitBuilder.setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey (DialogInterface dialog, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled()) { dialog.cancel(); Utils.logger("v", "canceling asyncSizeQuery", DEBUG_TAG); asyncSizeQuery.cancel(true); return true; } return false; } });*/ // this handles both the BACK button and the click OUTSIDE the dialog /*waitBuilder.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { dialog.cancel(); Utils.logger("v", "canceling asyncSizeQuery", DEBUG_TAG); asyncSizeQuery.cancel(true); } }); waitBox = waitBuilder.create(); if (! ((Activity) ShareActivity.this).isFinishing()) { waitBox.show(); } } protected String doInBackground(String... urls) { // params comes from the execute() call: params[0] is the url. return getVideoFileSize(urls[0]); } @Override protected void onPostExecute(String result) { filesizeProgressBar.setVisibility(View.GONE); if (! ((Activity) ShareActivity.this).isFinishing()) { waitBox.dismiss(); } videoFileSize = result; Utils.logger("d", "size " + pos + ": " + result, DEBUG_TAG); helpBuilder.setMessage(titleRaw + getString(R.string.codec) + " " + codecs.get(pos) + getString(R.string.quality) + " " + qualities.get(pos) + stereo.get(pos) + getString(R.string.size) + " " + videoFileSize); helpDialog = helpBuilder.create(); if (! ((Activity) ShareActivity.this).isFinishing()) { helpDialog.show(); } } }*/ private String getVideoFileSize(String link) { try { final URL url = new URL(link); URLConnection ucon = url.openConnection(); ucon.connect(); int file_size = ucon.getContentLength(); return Utils.MakeSizeHumanReadable(file_size, false); } catch(IOException e) { return "-"; } } private void codecMatcher(String current, int i) { Pattern codecPattern = Pattern.compile("(webm|mp4|flv|3gpp)"); Matcher codecMatcher = codecPattern.matcher(current); if (codecMatcher.find()) { codecs.add(codecMatcher.group()); } else { codecs.add("NoMatch"); } //Utils.logger("d", "index: " + i + ", Codec: " + codecs.get(i), DEBUG_TAG); } private void qualityMatcher(String current, int i) { Pattern qualityPattern = Pattern.compile("(highres|hd1080|hd720|large|medium|small)"); Matcher qualityMatcher = qualityPattern.matcher(current); if (qualityMatcher.find()) { qualities.add(qualityMatcher.group().replace("highres", "Original")); } else { qualities.add("NoMatch"); } //Utils.logger("d", "index: " + i + ", Quality: " + qualities.get(i), DEBUG_TAG); } private void stereoMatcher(String current, int i) { Pattern qualityPattern = Pattern.compile("stereo3d=1"); Matcher qualityMatcher = qualityPattern.matcher(current); if (qualityMatcher.find()) { stereo.add(qualityMatcher.group().replace("stereo3d=1", "_3D")); } else { stereo.add(""); } //Utils.logger("d", "index: " + i + ", Quality: " + qualities.get(i), DEBUG_TAG); } private void resolutionMatcher(String current, int i) { String res = "-"; Pattern itagPattern = Pattern.compile("itag=([0-9]{1,3})\\\\u0026"); Matcher itagMatcher = itagPattern.matcher(current); if (itagMatcher.find()) { res = findItag(itagMatcher, res); } else { Pattern itagPattern2 = Pattern.compile("itag=([0-9]{1,3})$"); Matcher itagMatcher2 = itagPattern2.matcher(current); if (itagMatcher2.find()) { res = findItag(itagMatcher2, res); } } itags.add(res); Utils.logger("d", "index: " + i + ", itag: " + itags.get(i), DEBUG_TAG); } private String findItag(Matcher itagMatcher, String res) { String itag = itagMatcher.group(1); if (itag != null) { try { switch (Integer.parseInt(itag)) { case 5: res = "240p"; break; case 6: res = "270p"; break; case 17: res = "144p"; break; case 18: res = "270p/360p"; break; case 22: res = "720p"; break; case 34: res = "360p"; break; case 35: res = "480p"; break; case 36: res = "240p"; break; case 37: res = "1080p"; break; case 38: res = "Original"; break; case 43: res = "360p"; break; case 44: res = "480p"; break; case 45: res = "720p"; break; case 46: res = "1080p"; break; case 82: res = "360p"; break; case 83: res = "240p"; break; case 84: res = "720p"; break; case 85: res = "520p"; break; case 100: res = "360p"; break; case 101: res = "360p"; break; case 102: res = "720p"; break; } } catch (NumberFormatException e) { Log.e(DEBUG_TAG, "resolutionMatcher --> " + e.getMessage()); } } return res; } /*private String generateThumbUrl() { // link example "http://i2.ytimg.com/vi/8wr-uQX1Grw/mqdefault.jpg" Random random = new Random(); int num = random.nextInt(4 - 1) + 1; String url = "http://i" + num + ".ytimg.com/vi/" + videoId + "/mqdefault.jpg"; Utils.logger("d", "thumbnail url: " + url, DEBUG_TAG); return url; }*/ private String[] generateThumbUrls() { String url1 = "http://i1.ytimg.com/vi/" + videoId + "/mqdefault.jpg"; String url2 = "http://i2.ytimg.com/vi/" + videoId + "/mqdefault.jpg"; String url3 = "http://i3.ytimg.com/vi/" + videoId + "/mqdefault.jpg"; String url4 = "http://i4.ytimg.com/vi/" + videoId + "/mqdefault.jpg"; String[] urls = { url1, url2, url3, url4 }; return urls; } private Bitmap downloadThumbnail(String fileUrl) { InputStream is = null; URL myFileUrl = null; try { myFileUrl = new URL(fileUrl); HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection(); conn.setDoInput(true); conn.connect(); is = conn.getInputStream(); return BitmapFactory.decodeStream(is); } catch (IOException e) { Log.e(DEBUG_TAG, "IOException @ " + e.getMessage()); return null; } } private void assignBitmapToVideoListThumbnail(String[] url) { Bitmap bm0 = downloadThumbnail(url[0]); if (bm0 != null) { img = bm0; Utils.logger("d", "assigning bitmap from url[0]: " + url[0], DEBUG_TAG); } else { Bitmap bm1 = downloadThumbnail(url[1]); if (bm1 != null) { img = bm1; Utils.logger("d", "assigning bitmap from url[1]: " + url[1], DEBUG_TAG); } else { Bitmap bm2 = downloadThumbnail(url[2]); if (bm2 != null) { img = bm2; Utils.logger("d", "assigning bitmap from url[2]: " + url[2], DEBUG_TAG); } else { Bitmap bm3 = downloadThumbnail(url[3]); if (bm3 != null) { img = bm3; Utils.logger("d", "assigning bitmap from url[3]: " + url[3], DEBUG_TAG); } else { Log.e(DEBUG_TAG, "\nFalling back on asset's placeholder"); InputStream assIs = null; AssetManager assMan = getAssets(); try { assIs = assMan.open("placeholder.png"); } catch (IOException e1) { Log.e(DEBUG_TAG, "downloadThumbnail -> " + e1.getMessage()); } img = BitmapFactory.decodeStream(assIs); } } } } } private void writeThumbToDisk() { File thumbFile = new File(sShare.getDir(YTD.THUMBS_FOLDER, 0), videoId + ".png"); //if (!thumbFile.exists()) { try { FileOutputStream os = new FileOutputStream(thumbFile); img.compress(Bitmap.CompressFormat.PNG, 50, os); } catch (FileNotFoundException e) { Log.e(DEBUG_TAG, "writeThumbToDisk -> " + e.getMessage()); } //} } private void updateInit() { int prefSig = YTD.settings.getInt("APP_SIGNATURE", 0); Utils.logger("d", "prefSig: " + prefSig, DEBUG_TAG); if (prefSig == SettingsActivity.SettingsFragment.YTD_SIG_HASH) { Utils.logger("d", "YTD signature in PREFS: update check possile", DEBUG_TAG); if (YTD.settings.getBoolean("autoupdate", false)) { Utils.logger("i", "autoupdate enabled", DEBUG_TAG); SettingsActivity.SettingsFragment.autoUpdate(ShareActivity.this); } } else { Utils.logger("d", "different or null YTD signature. Update check cancelled.", DEBUG_TAG); } } }