mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-11-04 09:13:00 +00:00 
			
		
		
		
	added autio streaming & jumped to version 0.4.0
This commit is contained in:
		@@ -6,6 +6,7 @@ import android.content.DialogInterface;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.preference.Preference;
 | 
			
		||||
import android.preference.PreferenceManager;
 | 
			
		||||
import android.support.v4.view.MenuItemCompat;
 | 
			
		||||
@@ -50,6 +51,7 @@ public class ActionBarHandler {
 | 
			
		||||
    private String webisteUrl = "";
 | 
			
		||||
    private AppCompatActivity activity;
 | 
			
		||||
    private VideoInfo.VideoStream[] videoStreams = null;
 | 
			
		||||
    private VideoInfo.AudioStream audioStream = null;
 | 
			
		||||
    private int selectedStream = -1;
 | 
			
		||||
    private String videoTitle = "";
 | 
			
		||||
 | 
			
		||||
@@ -75,18 +77,18 @@ public class ActionBarHandler {
 | 
			
		||||
        activity.getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setStreams(VideoInfo.VideoStream[] streams) {
 | 
			
		||||
        this.videoStreams = streams;
 | 
			
		||||
    public void setStreams(VideoInfo.VideoStream[] videoStreams, VideoInfo.AudioStream[] audioStreams) {
 | 
			
		||||
        this.videoStreams = videoStreams;
 | 
			
		||||
        selectedStream = 0;
 | 
			
		||||
        String[] itemArray = new String[streams.length];
 | 
			
		||||
        String[] itemArray = new String[videoStreams.length];
 | 
			
		||||
        String defaultResolution = defaultPreferences
 | 
			
		||||
                .getString(context.getString(R.string.defaultResolutionPreference),
 | 
			
		||||
                        context.getString(R.string.defaultResolutionListItem));
 | 
			
		||||
        int defaultResolutionPos = 0;
 | 
			
		||||
 | 
			
		||||
        for(int i = 0; i < streams.length; i++) {
 | 
			
		||||
            itemArray[i] = streams[i].format + " " + streams[i].resolution;
 | 
			
		||||
            if(defaultResolution.equals(streams[i].resolution)) {
 | 
			
		||||
        for(int i = 0; i < videoStreams.length; i++) {
 | 
			
		||||
            itemArray[i] = VideoInfo.getNameById(videoStreams[i].format) + " " + videoStreams[i].resolution;
 | 
			
		||||
            if(defaultResolution.equals(videoStreams[i].resolution)) {
 | 
			
		||||
                defaultResolutionPos = i;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -99,6 +101,27 @@ public class ActionBarHandler {
 | 
			
		||||
                    ,new ForamatItemSelectListener());
 | 
			
		||||
            ab.setSelectedNavigationItem(defaultResolutionPos);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // set audioStream
 | 
			
		||||
        audioStream = null;
 | 
			
		||||
        String preferedFormat = PreferenceManager.getDefaultSharedPreferences(context)
 | 
			
		||||
                .getString(context.getString(R.string.defaultAudioFormatPreference), "webm");
 | 
			
		||||
        if(preferedFormat.equals("webm")) {
 | 
			
		||||
            for(VideoInfo.AudioStream s : audioStreams) {
 | 
			
		||||
                if(s.format == VideoInfo.I_WEBMA) {
 | 
			
		||||
                    audioStream = s;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else if(preferedFormat.equals("m4a")){
 | 
			
		||||
            for(VideoInfo.AudioStream s : audioStreams) {
 | 
			
		||||
                Log.d(TAG, VideoInfo.getMimeById(s.format) + " : " + Integer.toString(s.bandWidth));
 | 
			
		||||
                if(s.format == VideoInfo.I_M4A &&
 | 
			
		||||
                        (audioStream == null || audioStream.bandWidth > s.bandWidth)) {
 | 
			
		||||
                    audioStream = s;
 | 
			
		||||
                    Log.d(TAG, "last choosen");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void selectFormatItem(int i) {
 | 
			
		||||
@@ -159,6 +182,9 @@ public class ActionBarHandler {
 | 
			
		||||
            case R.id.action_play_with_kodi:
 | 
			
		||||
                playWithKodi();
 | 
			
		||||
                break;
 | 
			
		||||
            case R.id.menu_item_play_audio:
 | 
			
		||||
                playAudio();
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                Log.e(TAG, "Menu Item not known");
 | 
			
		||||
        }
 | 
			
		||||
@@ -179,7 +205,7 @@ public class ActionBarHandler {
 | 
			
		||||
                try {
 | 
			
		||||
                    intent.setAction(Intent.ACTION_VIEW);
 | 
			
		||||
                    intent.setDataAndType(Uri.parse(videoStreams[selectedStream].url),
 | 
			
		||||
                            "video/" + videoStreams[selectedStream].format);
 | 
			
		||||
                            VideoInfo.getMimeById(videoStreams[selectedStream].format));
 | 
			
		||||
                    context.startActivity(intent);      // HERE !!!
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    e.printStackTrace();
 | 
			
		||||
@@ -216,29 +242,17 @@ public class ActionBarHandler {
 | 
			
		||||
    public void downloadVideo() {
 | 
			
		||||
        Log.d(TAG, "bla");
 | 
			
		||||
        if(!videoTitle.isEmpty()) {
 | 
			
		||||
            String suffix = "";
 | 
			
		||||
            switch (videoStreams[selectedStream].format) {
 | 
			
		||||
                case VideoInfo.F_WEBM:
 | 
			
		||||
                    suffix = ".webm";
 | 
			
		||||
                    break;
 | 
			
		||||
                case VideoInfo.F_MPEG_4:
 | 
			
		||||
                    suffix = ".mp4";
 | 
			
		||||
                    break;
 | 
			
		||||
                case VideoInfo.F_3GPP:
 | 
			
		||||
                    suffix = ".3gp";
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
 | 
			
		||||
            DownloadManager.Request request = new DownloadManager.Request(
 | 
			
		||||
                    Uri.parse(videoStreams[selectedStream].url));
 | 
			
		||||
            request.setDestinationUri(Uri.fromFile(new File(
 | 
			
		||||
                            defaultPreferences.getString("download_path_preference", "/storage/emulated/0/NewPipe")
 | 
			
		||||
                            + "/" + videoTitle + suffix)));
 | 
			
		||||
            try {
 | 
			
		||||
                dm.enqueue(request);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                e.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
            String videoSuffix = "." + VideoInfo.getSuffixById(videoStreams[selectedStream].format);
 | 
			
		||||
            String audioSuffix = "." + VideoInfo.getSuffixById(audioStream.format);
 | 
			
		||||
            Bundle args = new Bundle();
 | 
			
		||||
            args.putString(DownloadDialog.FILE_SUFFIX_VIDEO, videoSuffix);
 | 
			
		||||
            args.putString(DownloadDialog.FILE_SUFFIX_AUDIO, audioSuffix);
 | 
			
		||||
            args.putString(DownloadDialog.TITLE, videoTitle);
 | 
			
		||||
            args.putString(DownloadDialog.VIDEO_URL, videoStreams[selectedStream].url);
 | 
			
		||||
            args.putString(DownloadDialog.AUDIO_URL, audioStream.url);
 | 
			
		||||
            DownloadDialog downloadDialog = new DownloadDialog();
 | 
			
		||||
            downloadDialog.setArguments(args);
 | 
			
		||||
            downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -282,4 +296,34 @@ public class ActionBarHandler {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void playAudio() {
 | 
			
		||||
        Intent intent = new Intent();
 | 
			
		||||
        try {
 | 
			
		||||
            intent.setAction(Intent.ACTION_VIEW);
 | 
			
		||||
            intent.setDataAndType(Uri.parse(audioStream.url),
 | 
			
		||||
                    VideoInfo.getMimeById(audioStream.format));
 | 
			
		||||
            context.startActivity(intent);      // HERE !!!
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
 | 
			
		||||
            builder.setMessage(R.string.noPlayerFound)
 | 
			
		||||
                    .setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() {
 | 
			
		||||
                        @Override
 | 
			
		||||
                        public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
                            Intent intent = new Intent();
 | 
			
		||||
                            intent.setAction(Intent.ACTION_VIEW);
 | 
			
		||||
                            intent.setData(Uri.parse(context.getString(R.string.fdroidVLCurl)));
 | 
			
		||||
                            context.startActivity(intent);
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
 | 
			
		||||
                        @Override
 | 
			
		||||
                        public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
                            Log.i(TAG, "You unlocked a secret unicorn.");
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
            builder.create().show();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								app/src/main/java/org/schabi/newpipe/DownloadDialog.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								app/src/main/java/org/schabi/newpipe/DownloadDialog.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
package org.schabi.newpipe;
 | 
			
		||||
 | 
			
		||||
import android.app.Dialog;
 | 
			
		||||
import android.app.DownloadManager;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.DialogInterface;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.preference.PreferenceManager;
 | 
			
		||||
import android.support.v4.app.DialogFragment;
 | 
			
		||||
import android.support.v7.app.AlertDialog;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by Christian Schabesberger on 21.09.15.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
 | 
			
		||||
 * DownloadDialog.java is part of NewPipe.
 | 
			
		||||
 *
 | 
			
		||||
 * NewPipe 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.
 | 
			
		||||
 *
 | 
			
		||||
 * NewPipe 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 NewPipe.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
public class DownloadDialog extends DialogFragment {
 | 
			
		||||
    private static final String TAG = DialogFragment.class.getName();
 | 
			
		||||
 | 
			
		||||
    public static final String TITLE = "name";
 | 
			
		||||
    public static final String FILE_SUFFIX_AUDIO = "file_suffix_audio";
 | 
			
		||||
    public static final String FILE_SUFFIX_VIDEO = "file_suffix_video";
 | 
			
		||||
    public static final String AUDIO_URL = "audio_url";
 | 
			
		||||
    public static final String VIDEO_URL = "video_url";
 | 
			
		||||
    Bundle arguments;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Dialog onCreateDialog(Bundle savedInstanceState) {
 | 
			
		||||
        arguments = getArguments();
 | 
			
		||||
        super.onCreateDialog(savedInstanceState);
 | 
			
		||||
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 | 
			
		||||
        builder.setTitle(R.string.downloadDialogTitle)
 | 
			
		||||
                .setItems(R.array.downloadOptions, new DialogInterface.OnClickListener() {
 | 
			
		||||
                    @Override
 | 
			
		||||
                    public void onClick(DialogInterface dialog, int which) {
 | 
			
		||||
                        Context context = getActivity();
 | 
			
		||||
                        SharedPreferences defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context);
 | 
			
		||||
                        String suffix = "";
 | 
			
		||||
                        String title = arguments.getString(TITLE);
 | 
			
		||||
                        String url = "";
 | 
			
		||||
                        switch(which) {
 | 
			
		||||
                            case 0:     // Video
 | 
			
		||||
                                suffix = arguments.getString(FILE_SUFFIX_VIDEO);
 | 
			
		||||
                                url = arguments.getString(VIDEO_URL);
 | 
			
		||||
                                break;
 | 
			
		||||
                            case 1:
 | 
			
		||||
                                suffix = arguments.getString(FILE_SUFFIX_AUDIO);
 | 
			
		||||
                                url = arguments.getString(AUDIO_URL);
 | 
			
		||||
                                break;
 | 
			
		||||
                            default:
 | 
			
		||||
                                Log.d(TAG, "lolz");
 | 
			
		||||
                        }
 | 
			
		||||
                        DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
 | 
			
		||||
                        DownloadManager.Request request = new DownloadManager.Request(
 | 
			
		||||
                                Uri.parse(url));
 | 
			
		||||
                        request.setDestinationUri(Uri.fromFile(new File(
 | 
			
		||||
                                defaultPreferences.getString("download_path_preference", "/storage/emulated/0/NewPipe")
 | 
			
		||||
                                        + "/" + title + suffix)));
 | 
			
		||||
                        try {
 | 
			
		||||
                            dm.enqueue(request);
 | 
			
		||||
                        } catch (Exception e) {
 | 
			
		||||
                            e.printStackTrace();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
        return builder.create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -21,35 +21,104 @@ package org.schabi.newpipe;
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import android.graphics.Bitmap;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
import java.util.Vector;
 | 
			
		||||
 | 
			
		||||
public class VideoInfo {
 | 
			
		||||
 | 
			
		||||
    private static final String TAG = VideoInfo.class.toString();
 | 
			
		||||
 | 
			
		||||
    // format identifier
 | 
			
		||||
    public static final int I_MPEG_4 = 0x0;
 | 
			
		||||
    public static final int I_3GPP = 0x1;
 | 
			
		||||
    public static final int I_WEBM = 0x2;
 | 
			
		||||
    public static final int I_M4A = 0x3;
 | 
			
		||||
    public static final int I_WEBMA = 0x4;
 | 
			
		||||
 | 
			
		||||
    // format name
 | 
			
		||||
    public static final String F_MPEG_4 = "MPEG-4";
 | 
			
		||||
    public static final String F_3GPP = "3GPP";
 | 
			
		||||
    public static final String F_WEBM = "WebM";
 | 
			
		||||
    public static final String F_M4A = "m4a";
 | 
			
		||||
    public static final String F_WEBMA = "WebM";
 | 
			
		||||
 | 
			
		||||
    // file suffix
 | 
			
		||||
    public static final String C_MPEG_4 = "mp4";
 | 
			
		||||
    public static final String C_3GPP = "3gp";
 | 
			
		||||
    public static final String C_WEBM = "webm";
 | 
			
		||||
    public static final String C_M4A = "m4a";
 | 
			
		||||
    public static final String C_WEBMA = "webm";
 | 
			
		||||
 | 
			
		||||
    // mimeType
 | 
			
		||||
    public static final String M_MPEG_4 = "video/mp4";
 | 
			
		||||
    public static final String M_3GPP = "video/3gpp";
 | 
			
		||||
    public static final String M_WEBM = "video/webm";
 | 
			
		||||
    public static final String M_M4A = "audio/mp4";
 | 
			
		||||
    public static final String M_WEBMA = "audio/webm";
 | 
			
		||||
 | 
			
		||||
    public static final int VIDEO_AVAILABLE = 0x00;
 | 
			
		||||
    public static final int VIDEO_UNAVAILABLE = 0x01;
 | 
			
		||||
    public static final int VIDEO_UNAVAILABLE_GEMA = 0x02;
 | 
			
		||||
 | 
			
		||||
    public static String getNameById(int id) {
 | 
			
		||||
        switch(id) {
 | 
			
		||||
            case I_MPEG_4: return F_MPEG_4;
 | 
			
		||||
            case I_3GPP: return F_3GPP;
 | 
			
		||||
            case I_WEBM: return F_WEBM;
 | 
			
		||||
            case I_M4A: return F_M4A;
 | 
			
		||||
            case I_WEBMA: return F_WEBMA;
 | 
			
		||||
            default: Log.e(TAG, "format not known: " +
 | 
			
		||||
                    Integer.toString(id) + "call the programmer he messed it up.");
 | 
			
		||||
        }
 | 
			
		||||
        return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getSuffixById(int id) {
 | 
			
		||||
        switch(id) {
 | 
			
		||||
            case I_MPEG_4: return C_MPEG_4;
 | 
			
		||||
            case I_3GPP: return C_3GPP;
 | 
			
		||||
            case I_WEBM: return C_WEBM;
 | 
			
		||||
            case I_M4A: return C_M4A;
 | 
			
		||||
            case I_WEBMA: return C_WEBMA;
 | 
			
		||||
            default: Log.e(TAG, "format not known: " +
 | 
			
		||||
                    Integer.toString(id) + "call the programmer he messed it up.");
 | 
			
		||||
        }
 | 
			
		||||
        return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getMimeById(int id) {
 | 
			
		||||
        switch(id) {
 | 
			
		||||
            case I_MPEG_4: return M_MPEG_4;
 | 
			
		||||
            case I_3GPP: return M_3GPP;
 | 
			
		||||
            case I_WEBM: return M_WEBM;
 | 
			
		||||
            case I_M4A: return M_M4A;
 | 
			
		||||
            case I_WEBMA: return M_WEBMA;
 | 
			
		||||
            default: Log.e(TAG, "format not known: " +
 | 
			
		||||
                    Integer.toString(id) + "call the programmer he messed it up.");
 | 
			
		||||
        }
 | 
			
		||||
        return "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class VideoStream {
 | 
			
		||||
        public VideoStream(String url, String format, String res) {
 | 
			
		||||
        public VideoStream(String url, int format, String res) {
 | 
			
		||||
            this.url = url; this.format = format; resolution = res;
 | 
			
		||||
        }
 | 
			
		||||
        public String url = "";     //url of the stream
 | 
			
		||||
        public String format = "";
 | 
			
		||||
        public int format = -1;
 | 
			
		||||
        public String resolution = "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class AudioStream {
 | 
			
		||||
        public AudioStream(String url, String format) {
 | 
			
		||||
        public AudioStream(String url, int format, int bandWidth, int samplingRate) {
 | 
			
		||||
            this.url = url; this.format = format;
 | 
			
		||||
            this.bandWidth = bandWidth; this.samplingRate = samplingRate;
 | 
			
		||||
        }
 | 
			
		||||
        public String url = "";
 | 
			
		||||
        public String format = "";
 | 
			
		||||
        public int format = -1;
 | 
			
		||||
        public int bandWidth = -1;
 | 
			
		||||
        public int samplingRate = -1;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String id = "";
 | 
			
		||||
 
 | 
			
		||||
@@ -205,7 +205,7 @@ public class VideoItemDetailFragment extends Fragment {
 | 
			
		||||
                    for (int i = 0; i < streamList.length; i++) {
 | 
			
		||||
                        streamList[i] = streamsToUse.get(i);
 | 
			
		||||
                    }
 | 
			
		||||
                    ActionBarHandler.getHandler().setStreams(streamList);
 | 
			
		||||
                    ActionBarHandler.getHandler().setStreams(streamList, info.audioStreams);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
                case VideoInfo.VIDEO_UNAVAILABLE_GEMA:
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,9 @@ import org.schabi.newpipe.Extractor;
 | 
			
		||||
import org.schabi.newpipe.VideoInfo;
 | 
			
		||||
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.util.Xml;
 | 
			
		||||
 | 
			
		||||
import java.io.StringReader;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
@@ -22,6 +24,7 @@ import org.mozilla.javascript.Context;
 | 
			
		||||
import org.mozilla.javascript.Function;
 | 
			
		||||
import org.mozilla.javascript.ScriptableObject;
 | 
			
		||||
import org.schabi.newpipe.VideoInfoItem;
 | 
			
		||||
import org.xmlpull.v1.XmlPullParser;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by Christian Schabesberger on 06.08.15.
 | 
			
		||||
@@ -53,22 +56,22 @@ public class YoutubeExtractor implements Extractor {
 | 
			
		||||
    // How ever if you are heading for a list showing all itag formats lock at
 | 
			
		||||
    // https://github.com/rg3/youtube-dl/issues/1687
 | 
			
		||||
 | 
			
		||||
    public static String resolveFormat(int itag) {
 | 
			
		||||
    public static int resolveFormat(int itag) {
 | 
			
		||||
        switch(itag) {
 | 
			
		||||
            // video
 | 
			
		||||
            case 17: return VideoInfo.F_3GPP;
 | 
			
		||||
            case 18: return VideoInfo.F_MPEG_4;
 | 
			
		||||
            case 22: return VideoInfo.F_MPEG_4;
 | 
			
		||||
            case 36: return VideoInfo.F_3GPP;
 | 
			
		||||
            case 37: return VideoInfo.F_MPEG_4;
 | 
			
		||||
            case 38: return VideoInfo.F_MPEG_4;
 | 
			
		||||
            case 43: return VideoInfo.F_WEBM;
 | 
			
		||||
            case 44: return VideoInfo.F_WEBM;
 | 
			
		||||
            case 45: return VideoInfo.F_WEBM;
 | 
			
		||||
            case 46: return VideoInfo.F_WEBM;
 | 
			
		||||
            case 17: return VideoInfo.I_3GPP;
 | 
			
		||||
            case 18: return VideoInfo.I_MPEG_4;
 | 
			
		||||
            case 22: return VideoInfo.I_MPEG_4;
 | 
			
		||||
            case 36: return VideoInfo.I_3GPP;
 | 
			
		||||
            case 37: return VideoInfo.I_MPEG_4;
 | 
			
		||||
            case 38: return VideoInfo.I_MPEG_4;
 | 
			
		||||
            case 43: return VideoInfo.I_WEBM;
 | 
			
		||||
            case 44: return VideoInfo.I_WEBM;
 | 
			
		||||
            case 45: return VideoInfo.I_WEBM;
 | 
			
		||||
            case 46: return VideoInfo.I_WEBM;
 | 
			
		||||
            default:
 | 
			
		||||
                //Log.i(TAG, "Itag " + Integer.toString(itag) + " not known or not supported.");
 | 
			
		||||
                return null;
 | 
			
		||||
                return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -153,6 +156,7 @@ public class YoutubeExtractor implements Extractor {
 | 
			
		||||
        //-------------------------------------
 | 
			
		||||
        JSONObject playerArgs = null;
 | 
			
		||||
        JSONObject ytAssets = null;
 | 
			
		||||
        String dashManifest = "";
 | 
			
		||||
        {
 | 
			
		||||
            Pattern p = Pattern.compile("ytplayer.config\\s*=\\s*(\\{.*?\\});");
 | 
			
		||||
            Matcher m = p.matcher(site);
 | 
			
		||||
@@ -180,10 +184,20 @@ public class YoutubeExtractor implements Extractor {
 | 
			
		||||
            videoInfo.duration = playerArgs.getInt("length_seconds");
 | 
			
		||||
            videoInfo.average_rating = playerArgs.getString("avg_rating");
 | 
			
		||||
            // View Count will be extracted from html
 | 
			
		||||
            //videoInfo.view_count = playerArgs.getString("view_count");
 | 
			
		||||
            dashManifest = playerArgs.getString("dashmpd");
 | 
			
		||||
            String playerUrl = ytAssets.getString("js");
 | 
			
		||||
            if(playerUrl.startsWith("//")) {
 | 
			
		||||
                playerUrl = "https:" + playerUrl;
 | 
			
		||||
            }
 | 
			
		||||
            if(decryptoinCode.isEmpty()) {
 | 
			
		||||
                decryptoinCode = loadDecryptioinCode(playerUrl);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // extract audio
 | 
			
		||||
            videoInfo.audioStreams = parseDashManifest(dashManifest, decryptoinCode);
 | 
			
		||||
 | 
			
		||||
            //------------------------------------
 | 
			
		||||
            // extract stream url
 | 
			
		||||
            // extract video stream url
 | 
			
		||||
            //------------------------------------
 | 
			
		||||
            String encoded_url_map = playerArgs.getString("url_encoded_fmt_stream_map");
 | 
			
		||||
            Vector<VideoInfo.VideoStream> videoStreams = new Vector<>();
 | 
			
		||||
@@ -199,17 +213,13 @@ public class YoutubeExtractor implements Extractor {
 | 
			
		||||
 | 
			
		||||
                // if video has a signature: decrypt it and add it to the url
 | 
			
		||||
                if(tags.get("s") != null) {
 | 
			
		||||
                    String playerUrl = ytAssets.getString("js");
 | 
			
		||||
                    if(playerUrl.startsWith("//")) {
 | 
			
		||||
                        playerUrl = "https:" + playerUrl;
 | 
			
		||||
                    }
 | 
			
		||||
                    if(decryptoinCode.isEmpty()) {
 | 
			
		||||
                        decryptoinCode = loadDecryptioinCode(playerUrl);
 | 
			
		||||
                    }
 | 
			
		||||
                    streamUrl = streamUrl + "&signature=" + decriptSignature(tags.get("s"), decryptoinCode);
 | 
			
		||||
                    streamUrl = streamUrl + "&signature=" + decryptSignature(tags.get("s"), decryptoinCode);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if(resolveFormat(itag) != null) {
 | 
			
		||||
                if(resolveFormat(itag) != -1) {
 | 
			
		||||
                    videoStreams.add(new VideoInfo.VideoStream(
 | 
			
		||||
                            streamUrl,
 | 
			
		||||
                            resolveFormat(itag),
 | 
			
		||||
@@ -309,6 +319,81 @@ public class YoutubeExtractor implements Extractor {
 | 
			
		||||
        return videoInfo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private VideoInfo.AudioStream[] parseDashManifest(String dashManifest, String decryptoinCode) {
 | 
			
		||||
        if(!dashManifest.contains("/signature/")) {
 | 
			
		||||
            String encryptedSig = "";
 | 
			
		||||
            String decryptedSig = "";
 | 
			
		||||
            try {
 | 
			
		||||
                Pattern p = Pattern.compile("/s/([a-fA-F0-9\\.]+)");
 | 
			
		||||
                Matcher m = p.matcher(dashManifest);
 | 
			
		||||
                m.find();
 | 
			
		||||
                encryptedSig = m.group(1);
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                e.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
            decryptedSig = decryptSignature(encryptedSig, decryptoinCode);
 | 
			
		||||
            dashManifest = dashManifest.replace("/s/" + encryptedSig, "/signature/" + decryptedSig);
 | 
			
		||||
        }
 | 
			
		||||
        String dashDoc = Downloader.download(dashManifest);
 | 
			
		||||
        Vector<VideoInfo.AudioStream> audioStreams = new Vector<>();
 | 
			
		||||
        try {
 | 
			
		||||
            XmlPullParser parser = Xml.newPullParser();
 | 
			
		||||
            parser.setInput(new StringReader(dashDoc));
 | 
			
		||||
            int eventType = parser.getEventType();
 | 
			
		||||
            String tagName = "";
 | 
			
		||||
            String currentMimeType = "";
 | 
			
		||||
            int currentBandwidth = -1;
 | 
			
		||||
            int currentSamplingRate = -1;
 | 
			
		||||
            boolean currentTagIsBaseUrl = false;
 | 
			
		||||
            while(eventType != XmlPullParser.END_DOCUMENT) {
 | 
			
		||||
                switch(eventType) {
 | 
			
		||||
                    case XmlPullParser.START_TAG:
 | 
			
		||||
                        tagName = parser.getName();
 | 
			
		||||
                        if(tagName.equals("AdaptationSet")) {
 | 
			
		||||
                            currentMimeType = parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, "mimeType");
 | 
			
		||||
                        } else if(tagName.equals("Representation") && currentMimeType.contains("audio")) {
 | 
			
		||||
                            currentBandwidth = Integer.parseInt(
 | 
			
		||||
                                    parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, "bandwidth"));
 | 
			
		||||
                            currentSamplingRate = Integer.parseInt(
 | 
			
		||||
                                    parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, "audioSamplingRate"));
 | 
			
		||||
                        } else if(tagName.equals("BaseURL")) {
 | 
			
		||||
                            currentTagIsBaseUrl = true;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    case XmlPullParser.TEXT:
 | 
			
		||||
                        if(currentTagIsBaseUrl &&
 | 
			
		||||
                                (currentMimeType.contains("audio"))) {
 | 
			
		||||
                            int format = -1;
 | 
			
		||||
                            if(currentMimeType.equals(VideoInfo.M_WEBMA)) {
 | 
			
		||||
                                format = VideoInfo.I_WEBMA;
 | 
			
		||||
                            } else if(currentMimeType.equals(VideoInfo.M_M4A)) {
 | 
			
		||||
                                format = VideoInfo.I_M4A;
 | 
			
		||||
                            }
 | 
			
		||||
                            audioStreams.add(new VideoInfo.AudioStream(parser.getText(),
 | 
			
		||||
                                     format, currentBandwidth, currentSamplingRate));
 | 
			
		||||
                        }
 | 
			
		||||
                    case XmlPullParser.END_TAG:
 | 
			
		||||
                        if(tagName.equals("AdaptationSet")) {
 | 
			
		||||
                            currentMimeType = "";
 | 
			
		||||
                        } else if(tagName.equals("BaseURL")) {
 | 
			
		||||
                            currentTagIsBaseUrl = false;
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    default:
 | 
			
		||||
                }
 | 
			
		||||
                eventType = parser.next();
 | 
			
		||||
            }
 | 
			
		||||
        } catch(Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        VideoInfo.AudioStream[] output = new VideoInfo.AudioStream[audioStreams.size()];
 | 
			
		||||
        for(int i = 0; i < output.length; i++) {
 | 
			
		||||
            output[i] = audioStreams.get(i);
 | 
			
		||||
        }
 | 
			
		||||
        return output;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private VideoInfoItem extractVideoInfoItem(Element li) {
 | 
			
		||||
        VideoInfoItem info = new VideoInfoItem();
 | 
			
		||||
        info.webpage_url = li.select("a[class*=\"content-link\"]").first()
 | 
			
		||||
@@ -395,7 +480,7 @@ public class YoutubeExtractor implements Extractor {
 | 
			
		||||
        return decryptionCode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String decriptSignature(String encryptedSig, String decryptoinCode) {
 | 
			
		||||
    private String decryptSignature(String encryptedSig, String decryptoinCode) {
 | 
			
		||||
        Context context = Context.enter();
 | 
			
		||||
        context.setOptimizationLevel(-1);
 | 
			
		||||
        Object result = null;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable/ic_headset_black.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable/ic_headset_black.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 786 B  | 
@@ -3,14 +3,24 @@
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto">
 | 
			
		||||
    <item android:id="@+id/menu_item_play"
 | 
			
		||||
        android:title="@string/play"
 | 
			
		||||
        app:showAsAction="always"
 | 
			
		||||
        app:showAsAction="ifRoom"
 | 
			
		||||
        android:icon="@drawable/ic_play_arrow_black"/>
 | 
			
		||||
 | 
			
		||||
    <item android:id="@+id/menu_item_play_audio"
 | 
			
		||||
        android:title="@string/playAudio"
 | 
			
		||||
        app:showAsAction="always"
 | 
			
		||||
        android:icon="@drawable/ic_headset_black" />
 | 
			
		||||
 | 
			
		||||
    <item android:id="@+id/menu_item_share"
 | 
			
		||||
        android:title="@string/share"
 | 
			
		||||
        app:showAsAction="ifRoom"
 | 
			
		||||
        android:icon="@drawable/ic_share_black"/>
 | 
			
		||||
 | 
			
		||||
    <item android:id="@+id/action_play_with_kodi"
 | 
			
		||||
        android:title="@string/playWithKodiTitle"
 | 
			
		||||
        app:showAsAction="ifRoom"
 | 
			
		||||
        android:icon="@drawable/ic_cast_black"/>
 | 
			
		||||
 | 
			
		||||
    <item android:id="@+id/menu_item_openInBrowser"
 | 
			
		||||
        app:showAsAction="never"
 | 
			
		||||
        android:title="@string/open_in_browser" />
 | 
			
		||||
@@ -23,8 +33,5 @@
 | 
			
		||||
        app:showAsAction="never"
 | 
			
		||||
        android:title="@string/settings"/>
 | 
			
		||||
 | 
			
		||||
    <item android:id="@+id/action_play_with_kodi"
 | 
			
		||||
        android:title="@string/playWithKodiTitle"
 | 
			
		||||
        app:showAsAction="ifRoom"
 | 
			
		||||
        android:icon="@drawable/ic_cast_black"/>
 | 
			
		||||
 | 
			
		||||
</menu>
 | 
			
		||||
@@ -36,4 +36,13 @@
 | 
			
		||||
    <string name="showPlayWithKodiTitle">Zeige \"Mit Kodi abspielen\" Option</string>
 | 
			
		||||
    <string name="showPlayWithKodiSummary">Zeigt eine Option an, über die man Videos mit dem Kodi Mediacenter abspielen kann.</string>
 | 
			
		||||
    <string name="leftHandLayoutTitle">Linkshänder freundliches Layout.</string>
 | 
			
		||||
    <string name="playAudio">Audio</string>
 | 
			
		||||
    <string name="defaultAudioFormatTitle">Bevorzugtes Audio Format</string>
 | 
			
		||||
    <string name="webMAudioDescription">WebM - freies Format</string>
 | 
			
		||||
    <string name="m4aAudioDescription">m4a - bessere Qualität</string>
 | 
			
		||||
    <string name="downloadDialogTitle">Herunterladen</string>
 | 
			
		||||
    <string-array name="downloadOptions">
 | 
			
		||||
        <item>Video</item>
 | 
			
		||||
        <item>Audio</item>
 | 
			
		||||
    </string-array>
 | 
			
		||||
</resources>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,4 +13,14 @@
 | 
			
		||||
    <string name="defaultResolutionListItem">360p</string>
 | 
			
		||||
    <string name="showPlayWidthKodiPreference">show_play_with_kodi_preference</string>
 | 
			
		||||
    <string name="leftHandLayout">left_hand_layout</string>
 | 
			
		||||
    <string name="defaultAudioFormatPreference">default_audio_format</string>
 | 
			
		||||
    <string-array name="audioFormatDescriptionList">
 | 
			
		||||
        <item>@string/webMAudioDescription</item>
 | 
			
		||||
        <item>@string/m4aAudioDescription</item>
 | 
			
		||||
    </string-array>
 | 
			
		||||
    <string-array name="audioFormatList">
 | 
			
		||||
        <item>webm</item>
 | 
			
		||||
        <item>m4a</item>
 | 
			
		||||
    </string-array>
 | 
			
		||||
    <string name="defaultAudioFormat">m4a</string>
 | 
			
		||||
</resources>
 | 
			
		||||
@@ -36,4 +36,13 @@
 | 
			
		||||
    <string name="showPlayWithKodiTitle">Show \"Play with Kodi\" option</string>
 | 
			
		||||
    <string name="showPlayWithKodiSummary">Displays an option to play a video via Kodi media center.</string>
 | 
			
		||||
    <string name="leftHandLayoutTitle">Left hand friendly layout.</string>
 | 
			
		||||
    <string name="playAudio">Audio</string>
 | 
			
		||||
    <string name="defaultAudioFormatTitle">Default audio format</string>
 | 
			
		||||
    <string name="webMAudioDescription">WebM - free format</string>
 | 
			
		||||
    <string name="m4aAudioDescription">m4a - better quality</string>
 | 
			
		||||
    <string name="downloadDialogTitle">Download</string>
 | 
			
		||||
    <string-array name="downloadOptions">
 | 
			
		||||
        <item>Video</item>
 | 
			
		||||
        <item>Audio</item>
 | 
			
		||||
    </string-array>
 | 
			
		||||
</resources>
 | 
			
		||||
@@ -39,4 +39,11 @@
 | 
			
		||||
        android:title="@string/leftHandLayoutTitle"
 | 
			
		||||
        android:defaultValue="false" />
 | 
			
		||||
 | 
			
		||||
    <ListPreference
 | 
			
		||||
        android:key="@string/defaultAudioFormatPreference"
 | 
			
		||||
        android:title="@string/defaultAudioFormatTitle"
 | 
			
		||||
        android:entries="@array/audioFormatDescriptionList"
 | 
			
		||||
        android:entryValues="@array/audioFormatList"
 | 
			
		||||
        android:defaultValue="@string/defaultAudioFormat"/>
 | 
			
		||||
 | 
			
		||||
</PreferenceScreen>
 | 
			
		||||
		Reference in New Issue
	
	Block a user