In my Android application, I have an embedded YouTube video.
I'm getting the Youtube video ID from the original url as follows:
private String extractYoutubeId(String url) {
String video_id = "";
if (url != null && url.trim().length() > 0 && url.startsWith("http")) {
String expression = "^.*((youtu.be" + "\\/)"
+ "|(v\\/)|(\\/u\\/w\\/)|(embed\\/)|(watch\\?))\\??v?=?([^#\\&\\?]*).*";
CharSequence input = url;
Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {
String groupIndex1 = matcher.group(7);
if (groupIndex1 != null && groupIndex1.length() == 11)
video_id = groupIndex1;
}
}
return video_id;
}
This works just fine for an original url like this: http://www.youtube.com/watch?v=A7ry4cx6HfY
When I do that the video is loaded and played perfectly fine, but the quality is very bad. (240p or even worse, I think)
So from googling, I know that you just need to add a parameter like &vq=large or &vq=hd1080 to get 480p/1080p.
But when I use a url like this http://www.youtube.com/watch?v=A7ry4cx6HfY&vq=hd1080 the parameter is ignored and the quality is still bad.
How can I get the video in better quality? Of course, assuming that the video is available in that quality. Why is my parameter being ignored?
Try this code here.
// (?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})
final static String reg = "(?:youtube(?:-nocookie)?\\.com\\/(?:[^\\/\\n\\s]+\\/\\S+\\/|(?:v|e(?:mbed)?)\\/|\\S*?[?&]v=)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})";
public static String getVideoId(String videoUrl) {
if (videoUrl == null || videoUrl.trim().length() <= 0)
return null;
Pattern pattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(videoUrl);
if (matcher.find())
return matcher.group(1);
return null;
}
You can find my whole parser code from here
https://github.com/TheFinestArtist/YouTubePlayerActivity/blob/master/library/src/main/java/com/thefinestartist/ytpa/utils/YoutubeUrlParser.java
This is useful open source I made to play Youtube Video.
https://github.com/TheFinestArtist/YouTubePlayerActivity
I solved this problem by using the official Google Youtube API for Android.
It's probably not the best idea to try implementing the getting of the videos by oneself. Using the API does that for you and it works just fine.
EDIT
Here the link to the API: https://developers.google.com/youtube/android/player/
Related
All my images are encrypted in Android file system. When I need to show them, I need to decrypt, generate the bitmap and then delete the file. I'm trying to use Picasso to load my images. I created an RequestHandler to decrypt and load image.
RequestHandler accepts two types of result:
1. the bitmap or 2. a stream.
I'm trying to return the stream. That way Picasso can load images using the best practices, prevent out of memory. I created an custom Stream class and override the Dispose() method to delete the decrypted file after use.
The problem is: The stream is not disposing, neither closing, after the image is loaded, and I can't for automatic dispose by GAC (I'm using Xamarin/C#). Any ideas? What can I do?
UPDATE (19/01/17): I found out a small bug in my code and after fixing it, my problem was solved. But here is my custom RequestHandler for future reference... EncryptedFileStream is my custom stream that wraps the original stream and delete the decrypted file on Dispose().
public class EncryptedFilenameRequestHandler : RequestHandler
{
private readonly Context _context;
private readonly ICriptoService _criptoService;
public EncryptedFilenameRequestHandler(Context context, ICriptoService criptoService)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (criptoService == null) throw new ArgumentNullException(nameof(criptoService));
_context = context;
_criptoService = criptoService;
}
public override bool CanHandleRequest(Request request)
{
var uri = request.Uri;
return string.Compare(uri.Scheme, Constantes.AppSchema, true) == 0 &&
string.Compare(uri.Authority, Constantes.Host, true) == 0 &&
string.Compare(uri.Path, "/loadimagem/filename/encrypted", true) == 0;
}
public override Result Load(Request request, int networkPolicy)
{
string password = request.Uri.GetQueryParameter("p");
string encryptedFilename = request.Uri.GetQueryParameter("f");
string decryptedFilename = System.IO.Path.Combine(AppEnviroment.GetTempDirectory(), Guid.NewGuid().ToString("N"));
if (string.IsNullOrWhiteSpace(encryptedFilename) || !File.Exists(encryptedFilename))
return null;
_criptoService.Decrypt(encryptedFilename, decryptedFilename, password);
//retorna um stream para leitura do arquivo descriptografado
var uri = Android.Net.Uri.FromFile(new Java.IO.File(decryptedFilename));
var stream = new EncryptedFileStream(decryptedFilename, _context.ContentResolver.OpenInputStream(uri));
return new Result(stream, Picasso.LoadedFrom.Disk);
}
}
I found out a small bug in my code and, after fixing it, my problem was solved. The code for EncryptedFilenameRequestHandler posted in the question is working without any problem.
I am validating a URL before to open using Patterns.WEB_URL. It works perfect until lollipop that return true to "http://www.google" url for example.
final String registrationUrl = "http://www.google";
final Pattern urlPattern = Patterns.WEB_URL;
Boolean bool = urlPattern.matcher(registrationUrl).matches();
Any idea how to validate a URL? URLUtil.isValidUrl() dont work for me.
My application is about downloading an image from a specific website e.g. www.example.com/img-...
The user will input the url for the img to the EditText field. e.g. www.example.com/img-123
My problem is that when the user inputs a wrong URL, i.e. one with no no image, it is empty e.g. www.example.com/img-222
I want to detect this and tell the user their input does not link to an image and try again.
I'm using the isValidUrl() function to detect if the input is a WEB_URL only but what I want is that when the entered url has no image, the program should tell them it is an incorrect format for url.
I'm using Jsoup.connect(url).get(); to connect to the url and get the image and save it
private boolean isValidUrl(String url) {
Pattern p = Patterns.WEB_URL;
Matcher m = p.matcher(url);
if(m.matches())
return true;
else
return false;
}
We can use android native android.webkit.URLUtil class to validate any kind of url.
URLUtil.isValidUrl(downloadImaheEditText.getText().toString());
it will return true if valid else false.
String[] schemes = {"http","https"}; //DEFAULT schemes = "http", "https", "ftp"
UrlValidator urlValidator = new UrlValidator(schemes);
if (urlValidator.isValid("http://www.google.com")) {
//url is valid
}else{
//url is invalid
}
Use Apache commons-validator URLValidator class
I tried this and it worked for me. Please find the code snippet below:
public static boolean isURL(String url) {
Pattern p = Patterns.WEB_URL;
Matcher m = p.matcher(url.toLowerCase());
return m.matches();
}
In my application Youtube videos were playing perfectly in InApp. But certainly 2 days before I got the following alert message "Sorry, this video cannot be played" while playing the video and videos are not playing. I have tried different youtube video links, but no hope. If I use this code :
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.youtube.com/embed/Ai47z6qh8S0"));
startActivity(browserIntent);
Videos are playing then in browser. But I need this video to be played inside the application.
Previously I used the following code to create the youtube url
public static String calculateYouTubeUrl(String pYouTubeFmtQuality, boolean pFallback,
String pYouTubeVideoId) throws IOException,
ClientProtocolException, UnsupportedEncodingException {
String lUriStr = null;
HttpClient lClient = new DefaultHttpClient();
HttpGet lGetMethod = new HttpGet(OpenYouTubePlayerActivity.YOUTUBE_VIDEO_INFORMATION_URL +
pYouTubeVideoId);
HttpResponse lResp = null;
lResp = lClient.execute(lGetMethod);
ByteArrayOutputStream lBOS = new ByteArrayOutputStream();
String lInfoStr = null;
lResp.getEntity().writeTo(lBOS);
lInfoStr = new String(lBOS.toString("UTF-8"));
String[] lArgs=lInfoStr.split("&");
Map<String,String> lArgMap = new HashMap<String, String>();
for(int i=0; i<lArgs.length; i++){
String[] lArgValStrArr = lArgs[i].split("=");
if(lArgValStrArr != null){
if(lArgValStrArr.length >= 2){
lArgMap.put(lArgValStrArr[0], URLDecoder.decode(lArgValStrArr[1]));
}
}
}
//Find out the URI string from the parameters
//Populate the list of formats for the video
String lFmtList = URLDecoder.decode(lArgMap.get("fmt_list"));
ArrayList<Format> lFormats = new ArrayList<Format>();
if(null != lFmtList){
String lFormatStrs[] = lFmtList.split(",");
for(String lFormatStr : lFormatStrs){
Format lFormat = new Format(lFormatStr);
lFormats.add(lFormat);
}
}
//Populate the list of streams for the video
String lStreamList = lArgMap.get("url_encoded_fmt_stream_map");
if(null != lStreamList){
String lStreamStrs[] = lStreamList.split(",");
ArrayList<VideoStream> lStreams = new ArrayList<VideoStream>();
for(String lStreamStr : lStreamStrs){
VideoStream lStream = new VideoStream(lStreamStr);
lStreams.add(lStream);
}
//Search for the given format in the list of video formats
// if it is there, select the corresponding stream
// otherwise if fallback is requested, check for next lower format
int lFormatId = Integer.parseInt(pYouTubeFmtQuality);
Format lSearchFormat = new Format(lFormatId);
while(!lFormats.contains(lSearchFormat) && pFallback ){
int lOldId = lSearchFormat.getId();
int lNewId = getSupportedFallbackId(lOldId);
if(lOldId == lNewId){
break;
}
lSearchFormat = new Format(lNewId);
}
int lIndex = lFormats.indexOf(lSearchFormat);
if(lIndex >= 0){
VideoStream lSearchStream = lStreams.get(lIndex);
lUriStr = lSearchStream.getUrl();
}
}
//Return the URI string. It may be null if the format (or a fallback format if enabled)
// is not found in the list of formats for the video
return lUriStr;
}
Please help me to figure out this issue.
Thanks Santanu
This kind of youtube link wont work on android application, although it works fine on browsers. To make it work on an application you need to get the RTSP link of the video first.
Refer to this thread and see if you can find a solution there.
Example of youtube link working on android(I have tested this one):
rtsp://v2.cache6.c.youtube.com/CjgLENy73wIaLwn_aij76iwMRRMYESARFEIJbXYtZ29vZ2xlSARSB3JlbGF0ZWRgnfqw4Jajx8xPDA==/0/0/0/video.3gp
<iframe width="637" height="358" src="http://www.youtube.com/embed/Ai47z6qh8S0?fs=1&feature=oembed" frameborder="0" allowfullscreen=""></iframe>
try this or
you need to have hardware acceleration turned on
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("Video url"));
VideoActivity.this.startActivity(i);
//And add below code in Manifest.xml file.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
I'm writing a basic file browser that changes the icon used for files displayed depending on the MIME type of the file, but I'm having trouble finding the MIME type of some files, and I'm not sure why, the code I'm using to find the MIME Type is thus:
private String getFileMimeType(File file)
{
Uri fileUri = Uri.fromFile(file);
String ext = MimeTypeMap.getFileExtensionFromUrl(fileUri.toString());
return mtm.getMimeTypeFromExtension(ext);
}
It works for some file, but not for some with more complicated characters in them, which I don't really understand, example below:
The files with tildas are all functional mp3s but all return null for their MIME types, which isn't good for functioning mp3s, so I'm curious if there's any simple workaround for files with special chars in their name.
Its because of the "~" character in your filenames.
Look at the implementation of getFileExtensionFromUrl
/**
* Returns the file extension or an empty string iff there is no
* extension.
*/
public static String getFileExtensionFromUrl(String url) {
if (url != null && url.length() > 0) {
int query = url.lastIndexOf('?');
if (query > 0) {
url = url.substring(0, query);
}
int filenamePos = url.lastIndexOf('/');
String filename =
0 <= filenamePos ? url.substring(filenamePos + 1) : url;
// if the filename contains special characters, we don't
// consider it valid for our matching purposes:
if (filename.length() > 0 &&
Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)]+", filename)) { // <--
int dotPos = filename.lastIndexOf('.');
if (0 <= dotPos) {
return filename.substring(dotPos + 1);
}
}
}
return "";
}
a possible solution would be to write your own implemenation of this method with wider matching rule.
Hope this helps
As it's the extension that you really need to work with getMimeTypeFromExtension(..), you could try getting it yourself by simply using lastIndexOf(".") to get the extension as a 'substring' from File.getAbsolutePath().