[YouTube] Support handles and all custom channel names

More non-channel paths have been also added to the excluded custom name paths,
documentation and exception messages have been improved and fixed in some
places, and the licence header of YoutubeChannelLinkHandlerFactory has been
moved to its beginning and updated.
This commit is contained in:
AudricV 2022-11-02 16:57:18 +01:00
parent ffffb04439
commit 61ce041bda
No known key found for this signature in database
GPG key ID: DA92EC7905614198

View file

@ -1,3 +1,23 @@
/*
* Created by Christian Schabesberger on 25.07.16.
*
* Copyright (C) Christian Schabesberger 2018 <chrźis.schabesberger@mailbox.org>
* YoutubeChannelLinkHandlerFactory.java is part of NewPipe Extractor.
*
* NewPipe Extractor 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 Extractor 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 Extractor. If not, see <https://www.gnu.org/licenses/>.
*/
package org.schabi.newpipe.extractor.services.youtube.linkHandler; package org.schabi.newpipe.extractor.services.youtube.linkHandler;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -6,36 +26,21 @@ import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper; import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
import org.schabi.newpipe.extractor.utils.Utils; import org.schabi.newpipe.extractor.utils.Utils;
import javax.annotation.Nonnull;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
/* import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
* Created by Christian Schabesberger on 25.07.16.
*
* Copyright (C) Christian Schabesberger 2018 <chrźis.schabesberger@mailbox.org>
* YoutubeChannelLinkHandlerFactory.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 final class YoutubeChannelLinkHandlerFactory extends ListLinkHandlerFactory { public final class YoutubeChannelLinkHandlerFactory extends ListLinkHandlerFactory {
private static final YoutubeChannelLinkHandlerFactory INSTANCE private static final YoutubeChannelLinkHandlerFactory INSTANCE
= new YoutubeChannelLinkHandlerFactory(); = new YoutubeChannelLinkHandlerFactory();
private static final Pattern EXCLUDED_SEGMENTS = private static final Pattern EXCLUDED_SEGMENTS = Pattern.compile(
Pattern.compile("playlist|watch|attribution_link|watch_popup|embed|feed|select_site"); // CHECKSTYLE:OFF
"playlist|watch|attribution_link|watch_popup|embed|feed|select_site|account|reporthistory|redirect");
// CHECKSTYLE:ON
private YoutubeChannelLinkHandlerFactory() { private YoutubeChannelLinkHandlerFactory() {
} }
@ -45,10 +50,10 @@ public final class YoutubeChannelLinkHandlerFactory extends ListLinkHandlerFacto
} }
/** /**
* Returns URL to channel from an ID * Returns the URL to a channel from an ID.
* *
* @param id Channel ID including e.g. 'channel/' * @param id the channel ID including e.g. 'channel/'
* @return URL to channel * @return the URL to the channel
*/ */
@Override @Override
public String getUrl(final String id, public String getUrl(final String id,
@ -58,16 +63,26 @@ public final class YoutubeChannelLinkHandlerFactory extends ListLinkHandlerFacto
} }
/** /**
* Returns true if path conform to * Checks whether the given path conforms to custom short channel URLs like
* custom short channel URLs like youtube.com/yourcustomname * {@code youtube.com/yourcustomname}.
* *
* @param splitPath path segments array * @param splitPath the path segments array
* @return true - if value conform to short channel URL, false - not * @return whether the value conform to short channel URLs
*/ */
private boolean isCustomShortChannelUrl(final String[] splitPath) { private boolean isCustomShortChannelUrl(@Nonnull final String[] splitPath) {
return splitPath.length == 1 && !EXCLUDED_SEGMENTS.matcher(splitPath[0]).matches(); return splitPath.length == 1 && !EXCLUDED_SEGMENTS.matcher(splitPath[0]).matches();
} }
/**
* Checks whether the given path conforms to handle URLs like {@code youtube.com/@yourhandle}.
*
* @param splitPath the path segments array
* @return whether the value conform to handle URLs
*/
private boolean isHandle(@Nonnull final String[] splitPath) {
return splitPath.length > 0 && splitPath[0].startsWith("@");
}
@Override @Override
public String getId(final String url) throws ParsingException { public String getId(final String url) throws ParsingException {
try { try {
@ -77,35 +92,38 @@ public final class YoutubeChannelLinkHandlerFactory extends ListLinkHandlerFacto
if (!Utils.isHTTP(urlObj) || !(YoutubeParsingHelper.isYoutubeURL(urlObj) if (!Utils.isHTTP(urlObj) || !(YoutubeParsingHelper.isYoutubeURL(urlObj)
|| YoutubeParsingHelper.isInvidioURL(urlObj) || YoutubeParsingHelper.isInvidioURL(urlObj)
|| YoutubeParsingHelper.isHooktubeURL(urlObj))) { || YoutubeParsingHelper.isHooktubeURL(urlObj))) {
throw new ParsingException("the URL given is not a Youtube-URL"); throw new ParsingException("The URL given is not a YouTube URL");
} }
// remove leading "/" // Remove leading "/"
path = path.substring(1); path = path.substring(1);
String[] splitPath = path.split("/"); String[] splitPath = path.split("/");
// Handle custom short channel URLs like youtube.com/yourcustomname if (isHandle(splitPath)) {
if (isCustomShortChannelUrl(splitPath)) { // Handle YouTube handle URLs like youtube.com/@yourhandle
return splitPath[0];
} else if (isCustomShortChannelUrl(splitPath)) {
// Handle custom short channel URLs like youtube.com/yourcustomname
path = "c/" + path; path = "c/" + path;
splitPath = path.split("/"); splitPath = path.split("/");
} }
if (!path.startsWith("user/") if (!path.startsWith("user/") && !path.startsWith("channel/")
&& !path.startsWith("channel/")
&& !path.startsWith("c/")) { && !path.startsWith("c/")) {
throw new ParsingException("the URL given is neither a channel nor an user"); throw new ParsingException(
"The given URL is not a channel, a user or a handle URL");
} }
final String id = splitPath[1]; final String id = splitPath[1];
if (id == null || !id.matches("[A-Za-z0-9_-]+")) { if (isBlank(id)) {
throw new ParsingException("The given id is not a Youtube-Video-ID"); throw new ParsingException("The given ID is not a YouTube channel or user ID");
} }
return splitPath[0] + "/" + id; return splitPath[0] + "/" + id;
} catch (final Exception exception) { } catch (final Exception e) {
throw new ParsingException("Error could not parse url :" + exception.getMessage(), throw new ParsingException("Could not parse URL :" + e.getMessage(), e);
exception);
} }
} }