newpipe-documentation/03_Implement_a_service/index.html

328 lines
20 KiB
HTML

<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="../img/favicon.ico" />
<title>Implementing a Service - NewPipe Development Documentation</title>
<!-- local fonts -->
<link rel="stylesheet" href="../css/local_fonts.css" type="text/css" />
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
<link rel="stylesheet" href="../css/theme_child.css" type="text/css" />
<!-- local code syntax highlighting -->
<link rel="stylesheet" href="../css/github.min.css" type="text/css" />
<link rel="stylesheet" href="../css/highlight.css" type="text/css" />
<script>
// Current page data
var mkdocs_page_name = "Implementing a Service";
var mkdocs_page_input_path = "03_Implement_a_service.md";
var mkdocs_page_url = null;
</script>
<script src="../js/jquery-2.1.1.min.js" defer></script>
<script src="../js/modernizr-2.8.3.min.js" defer></script>
<script src="../js/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href=".." class="icon icon-home"> NewPipe Development Documentation
</a><div role="search">
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" title="Type search term here" />
</form>
</div>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul>
<li class="toctree-l1"><a class="reference internal" href="..">Welcome to the NewPipe Development Docs</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../00_Prepare_everything/">Before You Start</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../01_Concept_of_the_extractor/">Concept of the Extractor</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../02_Concept_of_LinkHandler/">Concept of the LinkHandler</a>
</li>
</ul>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal current" href="./">Implementing a Service</a>
<ul class="current">
<li class="toctree-l2"><a class="reference internal" href="#required-and-optional-parts">Required and Optional Parts</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="#allowed-libraries">Allowed Libraries</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="#head-of-service">Head of Service</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="#stream">Stream</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="#search">Search</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="#playlist">Playlist</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="#channel">Channel</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="#kiosk">Kiosk</a>
<ul>
<li class="toctree-l3"><a class="reference internal" href="#multiple-kiosks">Multiple Kiosks</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../04_Run_changes_in_App/">Testing Your Changes in the App</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../05_Mock_tests/">Mock Tests</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../06_releasing/">Releasing a New NewPipe Version</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../07_release_instructions/">Release instructions for normal releases</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../08_documentation/">About This Documentation</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../09_maintainers_view/">Maintainers' Section</a>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="..">NewPipe Development Documentation</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href=".." class="icon icon-home" alt="Docs"></a> &raquo;</li>
<li>Implementing a Service</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="section" itemprop="articleBody">
<h1 id="implementing-a-service">Implementing a Service</h1>
<p>Services, or better service connectors, are the parts of NewPipe which communicate with an actual service like YouTube.
This page will describe how you can implement and add your own services to the extractor. Please make sure you read and understand the
<a href="https://teamnewpipe.github.io/documentation/01_Concept_of_the_extractor/">Concept of Extractors</a>
and the <a href="https://teamnewpipe.github.io/documentation/02_Concept_of_LinkHandler/">Concept of LinkHandler</a>
before continuing.</p>
<h3 id="required-and-optional-parts">Required and Optional Parts</h3>
<p>Your service does not have to implement everything; some parts are optional.
This is because not all services support every feature other services support. For example, it might be that a certain
service does not support channels. If so, you can leave out the implementation of channels, and make the corresponding
factory method of the your <strong>StreamingService</strong> implementation return <strong>null</strong>. The frontend will handle the lack of
having channels.</p>
<p>However, if you start to implement one of the optional parts of the list below, you will have to implement all of its parts/classes. NewPipe will crash if you only implement the extractor for the list item of a channel, but not the channel extractor itself.</p>
<p><strong>The Parts of a Service:</strong></p>
<ul>
<li><a href="#head-of-service">Head of Service</a></li>
<li><a href="#stream">Stream</a></li>
<li><a href="#search">Search</a></li>
<li><a href="#playlist">Playlist</a> <em>(optional)</em></li>
<li><a href="#channel">Channel</a> <em>(optional)</em></li>
<li><a href="#kiosk">Kiosk</a> <em>(optional)</em></li>
</ul>
<h3 id="allowed-libraries">Allowed Libraries</h3>
<p>The NewPipe Extractor already includes a lot of usable tools and external libraries that should make extracting easy.
For some specific (tiny) tasks, Regex is allowed. Here you can take a look at the
<a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/utils/Parser.html">Parser</a>,
which will give you a little help with that. <strong>Use Regex with care!!!</strong> Avoid it as often as possible. It's better to
ask us to introduce a new library than start using Regex too often.</p>
<ul>
<li>Html/XML Parsing: <a href="https://jsoup.org/apidocs/overview-summary.html">jsoup</a></li>
<li>JSON Parsing: <a href="https://github.com/mmastrac/nanojson#parser-example">nanojson</a></li>
<li>JavaScript Parsing/Execution: <a href="https://github.com/mozilla/rhino">Mozilla Rhino</a></li>
<li>Link detection in strings: <a href="https://github.com/robinst/autolink-java">AutoLink</a></li>
</ul>
<p>If you need to introduce new libraries, please tell us before you do so.</p>
<h3 id="head-of-service">Head of Service</h3>
<p>First of all, if you want to create a new service, you should create a new package below <code>org.schabi.newpipe.services</code>
, with the name of your service as package name.</p>
<p><strong>Parts Required to be Implemented:</strong></p>
<ul>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/StreamingService.html">StreamingService</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/StreamingService.ServiceInfo.html">ServiceInfo</a></li>
</ul>
<p><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/StreamingService.html">StreamingService</a>
is a factory class that will return objects of all important parts of your service.
Every extractor, handler, and info type you add and should be part of your implementation, must be instantiated using an
instance of this class. You can see it as a factory for all objects of your implementation.</p>
<p><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/StreamingService.ServiceInfo.html">ServiceInfo</a>
will return some metadata about your service such as the name, capabilities, the author's name, and their
email address for further notice and maintenance issues. Remember, after extending this class, you need to return an
instance of it by through your implementation of
<a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/StreamingService.html#getServiceInfo--"><code>StreamingService.getServiceInfo()</code></a>.</p>
<p>When these two classes are extended by you, you need to add your <code>StreamingService</code> to the
<a href="https://github.com/TeamNewPipe/NewPipeExtractor/blob/49c2eb51859a58e4bb5ead2d9d0771408f7d59d6/extractor/src/main/java/org/schabi/newpipe/extractor/ServiceList.java#L23">ServiceList</a>
of NewPipe. This way, your service will become an official part of the NewPipe Extractor.
Every service has an ID, which will be set when this list gets created. You need to set this ID by entering it in the constructor.
So when adding your service just give it the ID of the previously last service in the list incremented by one.</p>
<h3 id="stream">Stream</h3>
<p>Streams are considered single entities of video or audio. They have metadata like a title, a description,
next/related videos, a thumbnail and comments. To obtain the URL to the actual stream data, as well as its metadata,
StreamExtractor is used. The LinkHandlerFactory will represent a link to such a stream. StreamInfoItemExtractor will
extract one item in a list of items representing such streams, like a search result or a playlist.
Since every streaming service (obviously) provides streams, this is required to implement. Otherwise, your service was
pretty useless :)</p>
<p><strong>Parts Required to be Implemented:</strong></p>
<ul>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/stream/StreamExtractor.html">StreamExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/stream/StreamInfoItemExtractor.html">StreamInfoItemExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/linkhandler/LinkHandlerFactory.html">LinkHandlerFactory</a></li>
</ul>
<h3 id="search">Search</h3>
<p>The SearchExtractor is also required to be implemented. It will take a search query represented as
<a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/linkhandler/SearchQueryHandler.html">SearchQueryHandler</a>
and return a list of search results. Since many services support suggestions as you type, you will also want to implement
a <strong>SuggestionExtractor</strong>. This will make it possible for the frontend to also display a suggestion while typing.</p>
<p><strong>Parts Required to be Implemented:</strong></p>
<ul>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/search/SearchExtractor.html">SearchExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/linkhandler/SearchQueryHandlerFactory.html">SearchQueryHandlerFactory</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/suggestion/SuggestionExtractor.html">SuggestionExtractor</a> <em>(optional)</em></li>
</ul>
<h3 id="playlist">Playlist</h3>
<p>Playlists are lists of streams provided by the service (you might not have to be concerned over locally saved playlists, those will be handled by the frontend).
A playlist may only contain <strong>StreamInfoItems</strong>, but no other <strong>InfoItem</strong> types.</p>
<p><strong>Parts Required to be Implemented:</strong></p>
<ul>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/playlist/PlaylistExtractor.html">PlaylistExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/playlist/PlaylistExtractor.html">PlayListInfoItemExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/linkhandler/ListLinkHandlerFactory.html">ListLinkHandlerFactory</a></li>
</ul>
<h3 id="channel">Channel</h3>
<p>A Channel is mostly a <a href="#playlist">Playlist</a>, the only difference is that it does not only represent a simple list of streams, but also a
user, a channel, or any entity that could be represented as a user. This is why the metadata supported by the ChannelExtractor
differs from the one of a playlist.</p>
<p><strong>Parts Required to be Implemented:</strong></p>
<ul>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/channel/ChannelExtractor.html">ChannelExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/channel/ChannelExtractor.html">ChannelInfoItemExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/linkhandler/ListLinkHandlerFactory.html">ListLinkHandlerFactory</a></li>
</ul>
<h3 id="kiosk">Kiosk</h3>
<p>A kiosk is a list of <strong>InfoItems</strong> which will be displayed on the main page of NewPipe. A kiosk is mostly similar to the content
displayed on the main page of a video platform. A kiosk could be something like "Top 20", "Charts", "News", "Creators Selection" etc.
Kiosks are controversial; many people may not like them. If you also don't like them, please consider your users and refrain from denying support for them.
Your service would look pretty empty if you select it and no video is being displayed. Also, you should not override the preference of the user,
since users of NewPipe can decide by the settings whether they want to see the kiosk page or not.</p>
<h4 id="multiple-kiosks">Multiple Kiosks</h4>
<p>Most services will implement more than one kiosk, so a service might have a "Top 20" for different categories like "Country Music", "Techno", etc.
This is why the extractor will let you implement multiple <strong>KioskExtractors</strong>. Since different kiosk pages might also differ
with their HTML structure, every page you want to support has to be implemented as its own <strong>KioskExtractor</strong>.
However, if the pages are similar, you can use the same implementation, but set the page type when you instantiate your <strong>KioskExtractor</strong>
through the <strong>KioskList.KioskExtractorFactory</strong>.</p>
<p>Every kiosk you implement needs to be added to your <strong>KioskList</strong> which you return with your
<strong>StreamingService</strong> implementation.</p>
<p>It is also important to set the default kiosk. This will be the kiosk that will be shown by the first start of your service.</p>
<p>An example implementation of the
<a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/StreamingService.html">getKioskList()</a>
could look like this:</p>
<pre><code class="language-java">@Override
public KioskList getKioskList() throws ExtractionException {
KioskList list = new KioskList(getServiceId());
list.addKioskEntry(new KioskList.KioskExtractorFactory() {
@Override
public KioskExtractor createNewKiosk(StreamingService streamingService,
String url,
String id,
Localization local)
throws ExtractionException {
return new YoutubeTrendingExtractor(YoutubeService.this,
new YoutubeTrendingLinkHandlerFactory().fromUrl(url), id, local);
}
}, new YoutubeTrendingLinkHandlerFactory(), &quot;Trending&quot;);
list.setDefaultKiosk(&quot;Trending&quot;);
return list;
}
</code></pre>
<p><strong>Parts Required to be Implemented:</strong></p>
<ul>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/kiosk/KioskList.KioskExtractorFactory.html">KioskList.KioskExtractorFactory</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/kiosk/KioskExtractor.html">KioskExtractor</a></li>
<li><a href="https://teamnewpipe.github.io/NewPipeExtractor/javadoc/org/schabi/newpipe/extractor/linkhandler/ListLinkHandlerFactory.html">ListLinkHandlerFactory</a></li>
</ul>
</div>
</div><footer>
<div class="rst-footer-buttons" role="navigation" aria-label="Footer Navigation">
<a href="../02_Concept_of_LinkHandler/" class="btn btn-neutral float-left" title="Concept of the LinkHandler"><span class="icon icon-circle-arrow-left"></span> Previous</a>
<a href="../04_Run_changes_in_App/" class="btn btn-neutral float-right" title="Testing Your Changes in the App">Next <span class="icon icon-circle-arrow-right"></span></a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" aria-label="Versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../02_Concept_of_LinkHandler/" style="color: #fcfcfc">&laquo; Previous</a></span>
<span><a href="../04_Run_changes_in_App/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
<script>var base_url = '..';</script>
<script src="../js/theme_extra.js" defer></script>
<script src="../js/theme.js" defer></script>
<script src="../search/main.js" defer></script>
<script defer>
window.onload = function () {
SphinxRtdTheme.Navigation.enable(true);
};
</script>
</body>
</html>