mirror of
https://github.com/MaintainTeam/LastPipeBender.git
synced 2025-03-01 05:48:22 +03:00
Merge branch 'sponsorblock' into bnp
This commit is contained in:
commit
a055804051
80 changed files with 3182 additions and 1196 deletions
8
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
8
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -14,9 +14,11 @@ body:
|
|||
attributes:
|
||||
label: "Checklist"
|
||||
options:
|
||||
- label: "I am able to reproduce the bug with the [latest version](https://github.com/TeamNewPipe/NewPipe/releases/latest)."
|
||||
- label: "I am able to reproduce the bug with the [latest version](https://github.com/polymorphicshade/NewPipe/releases/latest)."
|
||||
required: true
|
||||
- label: "I made sure that there are *no existing issues* - [open](https://github.com/TeamNewPipe/NewPipe/issues) or [closed](https://github.com/TeamNewPipe/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
|
||||
- label: "I am *not* able to reproduce the bug with the *same version* of [upstream NewPipe](https://github.com/TeamNewPipe/NewPipe/releases/)."
|
||||
required: true
|
||||
- label: "I made sure that there are *no existing issues* - [open](https://github.com/polymorphicshade/NewPipe/issues) or [closed](https://github.com/polymorphicshade/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
|
||||
required: true
|
||||
- label: "I have read the [FAQ](https://newpipe.net/FAQ/) and my problem isn't listed."
|
||||
required: true
|
||||
|
@ -24,7 +26,7 @@ body:
|
|||
required: true
|
||||
- label: "This issue contains only one bug."
|
||||
required: true
|
||||
- label: "I have read and understood the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/dev/.github/CONTRIBUTING.md)."
|
||||
- label: "I have read and understood the [contribution guidelines](https://github.com/polymorphicshade/NewPipe/blob/dev/.github/CONTRIBUTING.md)."
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
|
|
15
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
15
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
@ -13,7 +13,7 @@ body:
|
|||
attributes:
|
||||
label: "Checklist"
|
||||
options:
|
||||
- label: "I made sure that there are *no existing issues* - [open](https://github.com/TeamNewPipe/NewPipe/issues) or [closed](https://github.com/TeamNewPipe/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
|
||||
- label: "I made sure that there are *no existing issues* - [open](https://github.com/polymorphicshade/NewPipe/issues) or [closed](https://github.com/polymorphicshade/NewPipe/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
|
||||
required: true
|
||||
- label: "I have read the [FAQ](https://newpipe.net/FAQ/) and my problem isn't listed."
|
||||
required: true
|
||||
|
@ -23,7 +23,7 @@ body:
|
|||
required: true
|
||||
- label: "This issue contains only one feature request."
|
||||
required: true
|
||||
- label: "I have read and understood the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/dev/.github/CONTRIBUTING.md)."
|
||||
- label: "I have read and understood the [contribution guidelines](https://github.com/polymorphicshade/NewPipe/blob/dev/.github/CONTRIBUTING.md)."
|
||||
required: true
|
||||
|
||||
|
||||
|
@ -45,6 +45,17 @@ body:
|
|||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: why-relevant-to-fork
|
||||
attributes:
|
||||
label: Why ist the feature relevant to this fork?
|
||||
description: |
|
||||
Describe why your feature is relevant to the features this fork aims to provide over regular NewPipe or demonstrate that [upstream](https://github.com/TeamNewPipe/NewPipe/issues) is *explicitly* against implementing your feature for *non-technical reasons*.
|
||||
|
||||
(This is not the place for stale upstream feature requests!)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: additional-information
|
||||
attributes:
|
||||
|
|
BIN
.github/images/preview01.gif
vendored
Normal file
BIN
.github/images/preview01.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 MiB |
BIN
.github/images/preview02.gif
vendored
Normal file
BIN
.github/images/preview02.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 MiB |
150
README.md
150
README.md
|
@ -1,145 +1,23 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">A libre lightweight streaming front-end for Android.</h4>
|
||||
# NewPipe x SponsorBlock x Return YouTube Dislike
|
||||
A fork of [NewPipe](https://github.com/TeamNewPipe/NewPipe) with [SponsorBlock](https://sponsor.ajay.app/) and [Return YouTube Dislike](https://returnyoutubedislike.com/) functionality.
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-en.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||

|
||||

|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="GitHub release"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="Build Status"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/" alt="Translation Status"><img src="https://hosted.weblate.org/widgets/newpipe/-/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="IRC channel: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
<p align="center"><a href="#screenshots">Screenshots</a> • <a href="#supported-services">Supported Services</a> • <a href="#description">Description</a> • <a href="#features">Features</a> • <a href="#installation-and-updates">Installation and updates</a> • <a href="#contribution">Contribution</a> • <a href="#donate">Donate</a> • <a href="#license">License</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">Website</a> • <a href="https://newpipe.net/blog/">Blog</a> • <a href="https://newpipe.net/FAQ/">FAQ</a> • <a href="https://newpipe.net/press/">Press</a></p>
|
||||
<hr>
|
||||
The implementation is still a bit basic but it generally works pretty well.
|
||||
|
||||
*Read this in other languages: [English](README.md), [Español](doc/README.es.md), [हिन्दी](doc/README.hi.md), [한국어](doc/README.ko.md), [Soomaali](doc/README.so.md), [Português Brasil](doc/README.pt_BR.md), [Polski](doc/README.pl.md), [日本語](doc/README.ja.md), [Română](doc/README.ro.md), [Türkçe](doc/README.tr.md), [正體中文](doc/README.zh_TW.md).*
|
||||
## How can I get this?
|
||||
[<img alt="Get it on IzzyOnDroid" height="80" src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png">](https://apt.izzysoft.de/fdroid/index/apk/org.polymorphicshade.newpipe)
|
||||
|
||||
<b>WARNING: THIS APP IS IN BETA, SO YOU MAY ENCOUNTER BUGS. IF YOU DO, OPEN AN ISSUE IN OUR GITHUB REPOSITORY BY FILLING OUT THE ISSUE TEMPLATE.</b>
|
||||
Builds will be uploaded in the [Releases](https://github.com/polymorphicshade/NewPipe/releases) section. Please download the APK from the newest release and install it on your device.
|
||||
|
||||
<b>PUTTING NEWPIPE, OR ANY FORK OF IT, INTO THE GOOGLE PLAY STORE VIOLATES THEIR TERMS AND CONDITIONS.</b>
|
||||
## Why isn't this in upstream NewPipe?
|
||||
[The developer team](https://github.com/TeamNewPipe) behind the official NewPipe decided that they do not want to include these kinds of functionality in their app. See https://newpipe.schabi.org/blog/pinned/newpipe-and-online-advertising/, https://github.com/TeamNewPipe/NewPipe/pull/3205, and https://github.com/TeamNewPipe/NewPipe/issues/7469 for more information and discussion.
|
||||
|
||||
## Screenshots
|
||||
We obviously disagree but we respect their decision and continue to offer SponsorBlock and Return YouTube Dislike in NewPipe via this fork.
|
||||
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
### Supported Services
|
||||
|
||||
NewPipe currently supports these services:
|
||||
|
||||
<!-- We link to the service websites separately to avoid people accidentally opening a website they didn't want to. -->
|
||||
* YouTube ([website](https://www.youtube.com/)) and YouTube Music ([website](https://music.youtube.com/)) ([wiki](https://en.wikipedia.org/wiki/YouTube))
|
||||
* PeerTube ([website](https://joinpeertube.org/)) and all its instances (open the website to know what that means!) ([wiki](https://en.wikipedia.org/wiki/PeerTube))
|
||||
* Bandcamp ([website](https://bandcamp.com/)) ([wiki](https://en.wikipedia.org/wiki/Bandcamp))
|
||||
* SoundCloud ([website](https://soundcloud.com/)) ([wiki](https://en.wikipedia.org/wiki/SoundCloud))
|
||||
* media.ccc.de ([website](https://media.ccc.de/)) ([wiki](https://en.wikipedia.org/wiki/Chaos_Computer_Club))
|
||||
|
||||
As you can see, NewPipe supports multiple video and audio services. Though it started off with YouTube, other people have added more services over the years, making NewPipe more and more versatile!
|
||||
|
||||
Partially due to circumstance, and partially due to its popularity, YouTube is the best supported out of these services. If you use or are familiar with any of these other services, please help us improve support for them! We're looking for maintainers for SoundCloud and PeerTube.
|
||||
|
||||
If you intend to add a new service, please get in touch with us first! Our [docs](https://teamnewpipe.github.io/documentation/) provide more information on how a new service can be added to the app and to the [NewPipe Extractor](https://github.com/TeamNewPipe/NewPipeExtractor).
|
||||
|
||||
## Description
|
||||
|
||||
NewPipe works by fetching the required data from the official API (e.g. PeerTube) of the service you're using. If the official API is restricted (e.g. YouTube) for our purposes, or is proprietary, the app parses the website or uses an internal API instead. This means that you don't need an account on any service to use NewPipe.
|
||||
|
||||
Also, since they are free and open source software, neither the app nor the Extractor use any proprietary libraries or frameworks, such as Google Play Services. This means you can use NewPipe on devices or custom ROMs that do not have Google apps installed.
|
||||
|
||||
### Features
|
||||
|
||||
* Watch videos at resolutions up to 4K
|
||||
* Listen to audio in the background, only loading the audio stream to save data
|
||||
* Popup mode (floating player, aka Picture-in-Picture)
|
||||
* Watch live streams
|
||||
* Show/hide subtitles/closed captions
|
||||
* Search videos and audios (on YouTube, you can specify the content language as well)
|
||||
* Enqueue videos (and optionally save them as local playlists)
|
||||
* Show/hide general information about videos (such as description and tags)
|
||||
* Show/hide next/related videos
|
||||
* Show/hide comments
|
||||
* Search videos, audios, channels, playlists and albums
|
||||
* Browse videos and audios within a channel
|
||||
* Subscribe to channels (yes, without logging into any account!)
|
||||
* Get notifications about new videos from channels you're subscribed to
|
||||
* Create and edit channel groups (for easier browsing and management)
|
||||
* Browse video feeds generated from your channel groups
|
||||
* View and search your watch history
|
||||
* Search and watch playlists (these are remote playlists, which means they're fetched from the service you're browsing)
|
||||
* Create and edit local playlists (these are created and saved within the app, and have nothing to do with any service)
|
||||
* Download videos/audios/subtitles (closed captions)
|
||||
* Open in Kodi
|
||||
* Watch/Block age-restricted material
|
||||
|
||||
<!-- Hidden span to keep old links compatible. You should remove this span if you're translating the README into another language.-->
|
||||
<span id="updates"></span>
|
||||
|
||||
## Installation and updates
|
||||
You can install NewPipe using one of the following methods:
|
||||
1. Add our custom repo to F-Droid and install it from there. The instructions are here: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
|
||||
2. Download the APK from [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases) and install it.
|
||||
3. Update via F-Droid. This is the slowest method of getting updates, as F-Droid must recognize changes, build the APK itself, sign it, and then push the update to users.
|
||||
4. Build a debug APK yourself. This is the fastest way to get new features on your device, but is much more complicated, so we recommend using one of the other methods.
|
||||
5. If you're interested in a specific feature or bugfix provided in a Pull Request in this repo, you can also download its APK from within the PR. Read the PR description for instructions. The great thing about PR-specific APKs is that they're installed side-by-side the official app, so you don't have to worry about losing your data or messing anything up.
|
||||
|
||||
We recommend method 1 for most users. APKs installed using method 1 or 2 are compatible with each other (meaning that if you installed NewPipe using either method 1 or 2, you can also update NewPipe using the other), but not with those installed using method 3. This is due to the same signing key (ours) being used for 1 and 2, but a different signing key (F-Droid's) being used for 3. Building a debug APK using method 4 excludes a key entirely. Signing keys help ensure that a user isn't tricked into installing a malicious update to an app. When using method 5, each APK is signed with a different random key supplied by GitHub Actions, so you cannot even update it. You will have to backup and restore the app data each time you wish to use a new APK.
|
||||
|
||||
In the meanwhile, if you want to switch sources for some reason (e.g. NewPipe's core functionality breaks and F-Droid doesn't have the latest update yet), we recommend following this procedure:
|
||||
1. Back up your data via Settings > Content > Export Database so you keep your history, subscriptions, and playlists
|
||||
2. Uninstall NewPipe
|
||||
3. Download the APK from the new source and install it
|
||||
4. Import the data from step 1 via Settings > Content > Import Database
|
||||
|
||||
<b>Note: when you're importing a database into the official app, always make sure that it is the one you exported _from_ the official app. If you import a database exported from an APK other than the official app, it may break things. Such an action is unsupported, and you should only do so when you're absolutely certain you know what you're doing.</b>
|
||||
|
||||
## Contribution
|
||||
Whether you have ideas, translations, design changes, code cleaning, or even major code changes, help is always welcome. The app gets better and better with each contribution, no matter how big or small! If you'd like to get involved, check our [contribution notes](.github/CONTRIBUTING.md).
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/-/287x66-grey.png" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
## Donate
|
||||
If you like NewPipe, you're welcome to send a donation. We prefer Liberapay, as it is both open-source and non-profit. For further info on donating to NewPipe, please visit our [website](https://newpipe.net/donate).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="assets/bitcoin_qr_code.png" alt="Bitcoin QR code" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn."></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Privacy Policy
|
||||
|
||||
The NewPipe project aims to provide a private, anonymous experience for using web-based media services. Therefore, the app does not collect any data without your consent. NewPipe's privacy policy explains in detail what data is sent and stored when you send a crash report, or leave a comment in our blog. You can find the document [here](https://newpipe.net/legal/privacy/).
|
||||
## Bugs
|
||||
Please do not report bugs encountered while using this fork to the upstream developers. Either try to reproduce the bug in vanilla NewPipe and then report it (preferred) or [create a bug report in our repo](https://github.com/polymorphicshade/NewPipe/issues/new?assignees=&labels=bug&template=bug_report.md).
|
||||
|
||||
## License
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
NewPipe is Free Software: You can use, study, share, and improve it at will. Specifically you can redistribute and/or modify it under the terms of the [GNU General Public License](https://www.gnu.org/licenses/gpl.html) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
|
|
@ -16,8 +16,8 @@ android {
|
|||
namespace 'org.schabi.newpipe'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.schabi.newpipe"
|
||||
resValue "string", "app_name", "NewPipe"
|
||||
applicationId "org.polymorphicshade.newpipe"
|
||||
resValue "string", "app_name", "NewPipe SponsorBlock"
|
||||
minSdk 21
|
||||
targetSdk 33
|
||||
versionCode 992
|
||||
|
|
|
@ -71,12 +71,10 @@
|
|||
android:exported="false"
|
||||
android:label="@string/title_activity_play_queue"
|
||||
android:launchMode="singleTask" />
|
||||
|
||||
<activity
|
||||
android:name=".settings.SettingsActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/settings" />
|
||||
|
||||
<activity
|
||||
android:name=".about.AboutActivity"
|
||||
android:exported="false"
|
||||
|
@ -98,7 +96,6 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ExitActivity"
|
||||
android:exported="false"
|
||||
|
@ -445,6 +442,14 @@
|
|||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".LocalPlayerActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:foregroundServiceType="mediaPlayback"
|
||||
android:configChanges="orientation|screenSize|layoutDirection" />
|
||||
|
||||
<service
|
||||
android:name=".RouterActivity$FetcherService"
|
||||
android:exported="false" />
|
||||
|
@ -463,4 +468,4 @@
|
|||
android:name="com.samsung.android.multidisplay.keep_process_alive"
|
||||
android:value="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
|
@ -40,6 +40,7 @@ public final class DownloaderImpl extends Downloader {
|
|||
private static DownloaderImpl instance;
|
||||
private final Map<String, String> mCookies;
|
||||
private final OkHttpClient client;
|
||||
private Integer customTimeout;
|
||||
|
||||
private DownloaderImpl(final OkHttpClient.Builder builder) {
|
||||
this.client = builder
|
||||
|
@ -66,6 +67,11 @@ public final class DownloaderImpl extends Downloader {
|
|||
return instance;
|
||||
}
|
||||
|
||||
public DownloaderImpl setCustomTimeout(final Integer value) {
|
||||
this.customTimeout = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCookies(final String url) {
|
||||
final String youtubeCookie = url.contains(YOUTUBE_DOMAIN)
|
||||
? getCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY) : null;
|
||||
|
@ -166,7 +172,16 @@ public final class DownloaderImpl extends Downloader {
|
|||
|
||||
}
|
||||
|
||||
final okhttp3.Response response = client.newCall(requestBuilder.build()).execute();
|
||||
OkHttpClient tmpClient = client;
|
||||
final okhttp3.Response response;
|
||||
|
||||
if (customTimeout != null) {
|
||||
tmpClient = new OkHttpClient.Builder()
|
||||
.readTimeout(customTimeout, TimeUnit.SECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
response = tmpClient.newCall(requestBuilder.build()).execute();
|
||||
|
||||
if (response.code() == 429) {
|
||||
response.close();
|
||||
|
|
210
app/src/main/java/org/schabi/newpipe/LocalPlayerActivity.java
Normal file
210
app/src/main/java/org/schabi/newpipe/LocalPlayerActivity.java
Normal file
|
@ -0,0 +1,210 @@
|
|||
package org.schabi.newpipe;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.grack.nanojson.JsonObject;
|
||||
import com.grack.nanojson.JsonParser;
|
||||
|
||||
import org.schabi.newpipe.player.LocalPlayer;
|
||||
import org.schabi.newpipe.player.LocalPlayerListener;
|
||||
import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LocalPlayerActivity extends AppCompatActivity implements Player.Listener,
|
||||
LocalPlayerListener, PlaybackParameterDialog.Callback {
|
||||
private LocalPlayer localPlayer;
|
||||
private PlayerView playerView;
|
||||
public static final String TAG = "LocalPlayerActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_local_player);
|
||||
ThemeHelper.setTheme(this);
|
||||
|
||||
hideSystemUi(isLandscape());
|
||||
|
||||
final Intent intent = getIntent();
|
||||
|
||||
final String uri = parseUriFromIntent(intent);
|
||||
final VideoSegment[] segments = parseSegmentsFromIntent(intent);
|
||||
|
||||
localPlayer = new LocalPlayer(this);
|
||||
localPlayer.initialize(uri, segments);
|
||||
localPlayer.setListener(this);
|
||||
|
||||
playerView = findViewById(R.id.player_view);
|
||||
playerView.setPlayer(localPlayer.getExoPlayer());
|
||||
|
||||
playerView.getVideoSurfaceView().setOnLongClickListener(v -> {
|
||||
showPlaybackParameterDialog();
|
||||
return false;
|
||||
});
|
||||
|
||||
playerView.getVideoSurfaceView().setOnClickListener(v -> playerView.performClick());
|
||||
}
|
||||
|
||||
public void showPlaybackParameterDialog() {
|
||||
final PlaybackParameters playbackParameters =
|
||||
localPlayer.getExoPlayer().getPlaybackParameters();
|
||||
|
||||
boolean skipSilence = false;
|
||||
|
||||
if (localPlayer.getExoPlayer().getAudioComponent() != null) {
|
||||
skipSilence = localPlayer.getExoPlayer().getAudioComponent().getSkipSilenceEnabled();
|
||||
}
|
||||
PlaybackParameterDialog.newInstance(playbackParameters.speed, playbackParameters.pitch,
|
||||
skipSilence, this)
|
||||
.show(getSupportFragmentManager(), TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
localPlayer.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull final Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
hideSystemUi(isLandscape());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackParameterChanged(final float playbackTempo, final float playbackPitch,
|
||||
final boolean playbackSkipSilence) {
|
||||
localPlayer.setPlaybackParameters(playbackTempo, playbackPitch, playbackSkipSilence);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlocked(final SimpleExoPlayer player) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaying(final SimpleExoPlayer player) {
|
||||
setKeepScreenOn(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBuffering(final SimpleExoPlayer player) {
|
||||
setKeepScreenOn(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPaused(final SimpleExoPlayer player) {
|
||||
setKeepScreenOn(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPausedSeek(final SimpleExoPlayer player) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted(final SimpleExoPlayer player) {
|
||||
setKeepScreenOn(false);
|
||||
}
|
||||
|
||||
private static String parseUriFromIntent(final Intent intent) {
|
||||
return intent.getDataString();
|
||||
}
|
||||
|
||||
private static VideoSegment[] parseSegmentsFromIntent(final Intent intent) {
|
||||
final List<VideoSegment> result = new ArrayList<>();
|
||||
|
||||
final String segmentsJson = intent.getStringExtra("segments");
|
||||
|
||||
if (segmentsJson != null && segmentsJson.length() > 0) {
|
||||
try {
|
||||
final JsonObject obj = JsonParser.object().from(segmentsJson);
|
||||
|
||||
for (final Object item : obj.getArray("segments")) {
|
||||
final JsonObject itemObject = (JsonObject) item;
|
||||
|
||||
final double startTime = itemObject.getDouble("start");
|
||||
final double endTime = itemObject.getDouble("end");
|
||||
final String category = itemObject.getString("category");
|
||||
|
||||
final VideoSegment segment = new VideoSegment(startTime, endTime, category);
|
||||
result.add(segment);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
Log.e(TAG, "Error initializing segments", e);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new VideoSegment[0]);
|
||||
}
|
||||
|
||||
private void setKeepScreenOn(final boolean keepScreenOn) {
|
||||
if (keepScreenOn) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
playerView.getRootView().setKeepScreenOn(keepScreenOn);
|
||||
}
|
||||
|
||||
private void hideSystemUi(final boolean isLandscape) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
getWindow().getAttributes().layoutInDisplayCutoutMode =
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
}
|
||||
|
||||
int visibility;
|
||||
|
||||
if (isLandscape) {
|
||||
visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
} else {
|
||||
visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
}
|
||||
|
||||
if (!isInMultiWindow()) {
|
||||
visibility |= View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
}
|
||||
|
||||
getWindow().getDecorView().setSystemUiVisibility(visibility);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (isInMultiWindow())) {
|
||||
getWindow().setStatusBarColor(Color.TRANSPARENT);
|
||||
getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
||||
}
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
private boolean isInMultiWindow() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInMultiWindowMode();
|
||||
}
|
||||
|
||||
boolean isLandscape() {
|
||||
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
return metrics.heightPixels < metrics.widthPixels;
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ import org.schabi.newpipe.util.SimpleOnSeekBarChangeListener;
|
|||
import org.schabi.newpipe.util.StreamItemAdapter;
|
||||
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -127,6 +128,8 @@ public class DownloadDialog extends DialogFragment
|
|||
|
||||
private SharedPreferences prefs;
|
||||
|
||||
private VideoSegment[] segments;
|
||||
|
||||
// Variables for file name and MIME type when picking new folder because it's not set yet
|
||||
private String filenameTmp;
|
||||
private String mimeTmp;
|
||||
|
@ -181,6 +184,10 @@ public class DownloadDialog extends DialogFragment
|
|||
this.selectedVideoIndex = ListHelper.getDefaultResolutionIndex(context, videoStreams);
|
||||
}
|
||||
|
||||
public void setVideoSegments(final VideoSegment[] seg) {
|
||||
this.segments = seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onDismissListener the listener to call in {@link #onDismiss(DialogInterface)}
|
||||
*/
|
||||
|
@ -1062,7 +1069,8 @@ public class DownloadDialog extends DialogFragment
|
|||
}
|
||||
|
||||
DownloadManagerService.startMission(context, urls, storage, kind, threads,
|
||||
currentInfo.getUrl(), psName, psArgs, nearLength, recoveryInfo);
|
||||
currentInfo.getUrl(), psName, psArgs, nearLength, recoveryInfo,
|
||||
segments);
|
||||
|
||||
Toast.makeText(context, getString(R.string.download_has_started),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
|
|
@ -5,11 +5,13 @@ import android.app.PendingIntent
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.util.PendingIntentCompat
|
||||
|
@ -40,6 +42,10 @@ class ErrorUtil {
|
|||
*/
|
||||
@JvmStatic
|
||||
fun openActivity(context: Context, errorInfo: ErrorInfo) {
|
||||
if (getIsErrorReportsDisabled(context)) {
|
||||
return
|
||||
}
|
||||
|
||||
context.startActivity(getErrorActivityIntent(context, errorInfo))
|
||||
}
|
||||
|
||||
|
@ -104,6 +110,15 @@ class ErrorUtil {
|
|||
*/
|
||||
@JvmStatic
|
||||
fun createNotification(context: Context, errorInfo: ErrorInfo) {
|
||||
if (getIsErrorReportsDisabled(context)) {
|
||||
return
|
||||
}
|
||||
|
||||
var pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
pendingIntentFlags = pendingIntentFlags or PendingIntent.FLAG_IMMUTABLE
|
||||
}
|
||||
|
||||
val notificationBuilder: NotificationCompat.Builder =
|
||||
NotificationCompat.Builder(
|
||||
context,
|
||||
|
@ -138,6 +153,10 @@ class ErrorUtil {
|
|||
}
|
||||
|
||||
private fun showSnackbar(context: Context, rootView: View?, errorInfo: ErrorInfo) {
|
||||
if (getIsErrorReportsDisabled(context)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (rootView == null) {
|
||||
// fallback to showing a notification if no root view is available
|
||||
createNotification(context, errorInfo)
|
||||
|
@ -149,5 +168,12 @@ class ErrorUtil {
|
|||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIsErrorReportsDisabled(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(
|
||||
context.getString(R.string.disable_error_reports_key), false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,15 +107,18 @@ import org.schabi.newpipe.player.ui.VideoPlayerUi;
|
|||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.ReturnYouTubeDislikeUtils;
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
import org.schabi.newpipe.util.external_communication.KoreUtils;
|
||||
import org.schabi.newpipe.util.ListHelper;
|
||||
import org.schabi.newpipe.util.Localization;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
import org.schabi.newpipe.util.StreamTypeUtil;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
import org.schabi.newpipe.util.external_communication.KoreUtils;
|
||||
import org.schabi.newpipe.util.SponsorBlockUtils;
|
||||
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
@ -128,6 +131,7 @@ import java.util.function.Consumer;
|
|||
|
||||
import icepick.State;
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
@ -208,6 +212,8 @@ public final class VideoDetailFragment
|
|||
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||
@Nullable
|
||||
private Disposable positionSubscriber = null;
|
||||
@Nullable
|
||||
private Disposable videoSegmentsSubscriber = null;
|
||||
|
||||
private BottomSheetBehavior<FrameLayout> bottomSheetBehavior;
|
||||
private BottomSheetBehavior.BottomSheetCallback bottomSheetCallback;
|
||||
|
@ -401,6 +407,9 @@ public final class VideoDetailFragment
|
|||
if (positionSubscriber != null) {
|
||||
positionSubscriber.dispose();
|
||||
}
|
||||
if (videoSegmentsSubscriber != null) {
|
||||
videoSegmentsSubscriber.dispose();
|
||||
}
|
||||
if (currentWorker != null) {
|
||||
currentWorker.dispose();
|
||||
}
|
||||
|
@ -1534,6 +1543,19 @@ public final class VideoDetailFragment
|
|||
|
||||
binding.detailThumbsDisabledView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if (info.getDislikeCount() == -1) {
|
||||
new Thread(() -> {
|
||||
info.setDislikeCount(ReturnYouTubeDislikeUtils.getDislikes(getContext(), info));
|
||||
if (info.getDislikeCount() >= 0) {
|
||||
activity.runOnUiThread(() -> {
|
||||
binding.detailThumbsDownCountView.setText(Localization
|
||||
.shortCount(activity, info.getDislikeCount()));
|
||||
binding.detailThumbsDownCountView.setVisibility(View.VISIBLE);
|
||||
binding.detailThumbsDownImgView.setVisibility(View.VISIBLE);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
if (info.getDislikeCount() >= 0) {
|
||||
binding.detailThumbsDownCountView.setText(Localization
|
||||
.shortCount(activity, info.getDislikeCount()));
|
||||
|
@ -1661,13 +1683,32 @@ public final class VideoDetailFragment
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final DownloadDialog downloadDialog = new DownloadDialog(activity, currentInfo);
|
||||
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
||||
} catch (final Exception e) {
|
||||
ErrorUtil.showSnackbar(activity, new ErrorInfo(e, UserAction.DOWNLOAD_OPEN_DIALOG,
|
||||
"Showing download dialog", currentInfo));
|
||||
}
|
||||
videoSegmentsSubscriber = Single.fromCallable(() -> {
|
||||
VideoSegment[] videoSegments = null;
|
||||
|
||||
try {
|
||||
videoSegments =
|
||||
SponsorBlockUtils.getYouTubeVideoSegments(getContext(), currentInfo);
|
||||
} catch (final Exception e) {
|
||||
// TODO: handle?
|
||||
}
|
||||
|
||||
return videoSegments == null
|
||||
? new VideoSegment[0]
|
||||
: videoSegments;
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(videoSegments -> {
|
||||
try {
|
||||
final DownloadDialog downloadDialog = new DownloadDialog(activity, currentInfo);
|
||||
downloadDialog.setVideoSegments(videoSegments);
|
||||
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
||||
} catch (final Exception e) {
|
||||
ErrorUtil.showSnackbar(activity, new ErrorInfo(e, UserAction.DOWNLOAD_OPEN_DIALOG,
|
||||
"Showing download dialog", currentInfo));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
|
370
app/src/main/java/org/schabi/newpipe/player/LocalPlayer.java
Normal file
370
app/src/main/java/org/schabi/newpipe/player/LocalPlayer.java
Normal file
|
@ -0,0 +1,370 @@
|
|||
package org.schabi.newpipe.player;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
|
||||
import org.schabi.newpipe.DownloaderImpl;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.disposables.SerialDisposable;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.schabi.newpipe.player.Player.STATE_BLOCKED;
|
||||
import static org.schabi.newpipe.player.Player.STATE_BUFFERING;
|
||||
import static org.schabi.newpipe.player.Player.STATE_COMPLETED;
|
||||
import static org.schabi.newpipe.player.Player.STATE_PAUSED;
|
||||
import static org.schabi.newpipe.player.Player.STATE_PAUSED_SEEK;
|
||||
import static org.schabi.newpipe.player.Player.STATE_PLAYING;
|
||||
|
||||
public class LocalPlayer implements com.google.android.exoplayer2.Player.Listener {
|
||||
private static final String TAG = "LocalPlayer";
|
||||
private static final int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
|
||||
|
||||
private final Context context;
|
||||
private final SharedPreferences mPrefs;
|
||||
private SimpleExoPlayer simpleExoPlayer;
|
||||
private SerialDisposable progressUpdateReactor;
|
||||
private VideoSegment[] videoSegments;
|
||||
private LocalPlayerListener listener;
|
||||
private int lastCurrentProgress = -1;
|
||||
private int lastSkipTarget = -1;
|
||||
|
||||
public LocalPlayer(final Context context) {
|
||||
this.context = context;
|
||||
this.mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
public void initialize(final String uri, final VideoSegment[] segments) {
|
||||
this.videoSegments = segments;
|
||||
this.progressUpdateReactor = new SerialDisposable();
|
||||
|
||||
simpleExoPlayer = new SimpleExoPlayer
|
||||
.Builder(context)
|
||||
.build();
|
||||
simpleExoPlayer.addListener(this);
|
||||
simpleExoPlayer.setSeekParameters(PlayerHelper.getSeekParameters(context));
|
||||
simpleExoPlayer.setHandleAudioBecomingNoisy(true);
|
||||
simpleExoPlayer.setWakeMode(C.WAKE_MODE_NETWORK);
|
||||
|
||||
final PlaybackParameters playbackParameters = simpleExoPlayer.getPlaybackParameters();
|
||||
final float speed = mPrefs.getFloat(context.getString(
|
||||
R.string.playback_speed_key), playbackParameters.speed);
|
||||
final float pitch = mPrefs.getFloat(context.getString(
|
||||
R.string.playback_pitch_key), playbackParameters.pitch);
|
||||
|
||||
boolean defaultSkipSilence = false;
|
||||
if (simpleExoPlayer.getAudioComponent() != null) {
|
||||
defaultSkipSilence = simpleExoPlayer.getAudioComponent().getSkipSilenceEnabled();
|
||||
}
|
||||
|
||||
final boolean skipSilence = mPrefs.getBoolean(context.getString(
|
||||
R.string.playback_skip_silence_key), defaultSkipSilence);
|
||||
|
||||
setPlaybackParameters(speed, pitch, skipSilence);
|
||||
|
||||
final String autoPlayStr =
|
||||
mPrefs.getString(context.getString(R.string.autoplay_key), "");
|
||||
final boolean autoPlay =
|
||||
!autoPlayStr.equals(context.getString(R.string.autoplay_never_key));
|
||||
|
||||
simpleExoPlayer.setPlayWhenReady(autoPlay);
|
||||
|
||||
if (uri == null || uri.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final MediaItem mediaItem = new MediaItem.Builder()
|
||||
.setUri(Uri.parse(uri))
|
||||
.build();
|
||||
|
||||
final MediaSource videoSource = new ProgressiveMediaSource
|
||||
.Factory(new DefaultDataSourceFactory(context, DownloaderImpl.USER_AGENT))
|
||||
.createMediaSource(mediaItem);
|
||||
|
||||
simpleExoPlayer.addMediaSource(videoSource);
|
||||
simpleExoPlayer.prepare();
|
||||
}
|
||||
|
||||
public SimpleExoPlayer getExoPlayer() {
|
||||
return this.simpleExoPlayer;
|
||||
}
|
||||
|
||||
public void setListener(final LocalPlayerListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
simpleExoPlayer.removeListener(this);
|
||||
simpleExoPlayer.stop();
|
||||
simpleExoPlayer.release();
|
||||
progressUpdateReactor.set(null);
|
||||
}
|
||||
|
||||
public void setPlaybackParameters(final float speed, final float pitch,
|
||||
final boolean skipSilence) {
|
||||
final float roundedSpeed = Math.round(speed * 100.0f) / 100.0f;
|
||||
final float roundedPitch = Math.round(pitch * 100.0f) / 100.0f;
|
||||
|
||||
mPrefs.edit()
|
||||
.putFloat(context.getString(R.string.playback_speed_key), speed)
|
||||
.putFloat(context.getString(R.string.playback_pitch_key), pitch)
|
||||
.putBoolean(context.getString(R.string.playback_skip_silence_key), skipSilence)
|
||||
.apply();
|
||||
|
||||
simpleExoPlayer.setPlaybackParameters(
|
||||
new PlaybackParameters(roundedSpeed, roundedPitch));
|
||||
|
||||
if (simpleExoPlayer.getAudioComponent() != null) {
|
||||
simpleExoPlayer.getAudioComponent().setSkipSilenceEnabled(skipSilence);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerStateChanged(final boolean playWhenReady, final int playbackState) {
|
||||
switch (playbackState) {
|
||||
case com.google.android.exoplayer2.Player.STATE_IDLE:
|
||||
break;
|
||||
case com.google.android.exoplayer2.Player.STATE_BUFFERING:
|
||||
break;
|
||||
case com.google.android.exoplayer2.Player.STATE_READY:
|
||||
changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED);
|
||||
break;
|
||||
case com.google.android.exoplayer2.Player.STATE_ENDED:
|
||||
changeState(STATE_COMPLETED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isProgressLoopRunning() {
|
||||
return progressUpdateReactor.get() != null;
|
||||
}
|
||||
|
||||
private void startProgressLoop() {
|
||||
progressUpdateReactor.set(getProgressReactor());
|
||||
}
|
||||
|
||||
private void stopProgressLoop() {
|
||||
progressUpdateReactor.set(null);
|
||||
}
|
||||
|
||||
private Disposable getProgressReactor() {
|
||||
return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, MILLISECONDS,
|
||||
AndroidSchedulers.mainThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(ignored -> triggerProgressUpdate(),
|
||||
error -> Log.e(TAG, "Progress update failure: ", error));
|
||||
}
|
||||
|
||||
private void changeState(final int state) {
|
||||
switch (state) {
|
||||
case STATE_BLOCKED:
|
||||
onBlocked();
|
||||
break;
|
||||
case STATE_PLAYING:
|
||||
onPlaying();
|
||||
break;
|
||||
case STATE_BUFFERING:
|
||||
onBuffering();
|
||||
break;
|
||||
case STATE_PAUSED:
|
||||
onPaused();
|
||||
break;
|
||||
case STATE_PAUSED_SEEK:
|
||||
onPausedSeek();
|
||||
break;
|
||||
case STATE_COMPLETED:
|
||||
onCompleted();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onBlocked() {
|
||||
if (!isProgressLoopRunning()) {
|
||||
startProgressLoop();
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onBlocked(simpleExoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlaying() {
|
||||
if (!isProgressLoopRunning()) {
|
||||
startProgressLoop();
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onPlaying(simpleExoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void onBuffering() {
|
||||
if (listener != null) {
|
||||
listener.onBuffering(simpleExoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void onPaused() {
|
||||
if (isProgressLoopRunning()) {
|
||||
stopProgressLoop();
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onPaused(simpleExoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void onPausedSeek() {
|
||||
if (listener != null) {
|
||||
listener.onPausedSeek(simpleExoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void onCompleted() {
|
||||
if (isProgressLoopRunning()) {
|
||||
stopProgressLoop();
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onCompleted(simpleExoPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerProgressUpdate() {
|
||||
if (simpleExoPlayer == null) {
|
||||
return;
|
||||
}
|
||||
final int currentProgress = Math.max((int) simpleExoPlayer.getCurrentPosition(), 0);
|
||||
|
||||
final boolean isRewind = currentProgress < lastCurrentProgress;
|
||||
|
||||
lastCurrentProgress = currentProgress;
|
||||
|
||||
if (!mPrefs.getBoolean(
|
||||
context.getString(R.string.sponsor_block_enable_key), false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final VideoSegment segment = getSkippableSegment(currentProgress);
|
||||
if (segment == null) {
|
||||
lastSkipTarget = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int skipTarget = isRewind
|
||||
? (int) Math.ceil((segment.startTime)) - 1
|
||||
: (int) Math.ceil((segment.endTime));
|
||||
|
||||
if (skipTarget < 0) {
|
||||
skipTarget = 0;
|
||||
}
|
||||
|
||||
if (lastSkipTarget == skipTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastSkipTarget = skipTarget;
|
||||
|
||||
// temporarily force EXACT seek parameters to prevent infinite skip looping
|
||||
final SeekParameters seekParams = simpleExoPlayer.getSeekParameters();
|
||||
simpleExoPlayer.setSeekParameters(SeekParameters.EXACT);
|
||||
|
||||
seekTo(skipTarget);
|
||||
|
||||
simpleExoPlayer.setSeekParameters(seekParams);
|
||||
|
||||
if (mPrefs.getBoolean(
|
||||
context.getString(R.string.sponsor_block_notifications_key), false)) {
|
||||
String toastText = "";
|
||||
|
||||
switch (segment.category) {
|
||||
case "sponsor":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_sponsor_toast);
|
||||
break;
|
||||
case "intro":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_intro_toast);
|
||||
break;
|
||||
case "outro":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_outro_toast);
|
||||
break;
|
||||
case "interaction":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_interaction_toast);
|
||||
break;
|
||||
case "selfpromo":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_self_promo_toast);
|
||||
break;
|
||||
case "music_offtopic":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_non_music_toast);
|
||||
break;
|
||||
case "preview":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_preview_toast);
|
||||
break;
|
||||
case "filler":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_filler_toast);
|
||||
break;
|
||||
}
|
||||
|
||||
Toast.makeText(context, toastText, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void seekTo(final long positionMillis) {
|
||||
if (simpleExoPlayer != null) {
|
||||
long normalizedPositionMillis = positionMillis;
|
||||
if (normalizedPositionMillis < 0) {
|
||||
normalizedPositionMillis = 0;
|
||||
} else if (normalizedPositionMillis > simpleExoPlayer.getDuration()) {
|
||||
normalizedPositionMillis = simpleExoPlayer.getDuration();
|
||||
}
|
||||
|
||||
simpleExoPlayer.seekTo(normalizedPositionMillis);
|
||||
}
|
||||
}
|
||||
|
||||
private VideoSegment getSkippableSegment(final int progress) {
|
||||
if (videoSegments == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (final VideoSegment segment : videoSegments) {
|
||||
if (progress < segment.startTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (progress > segment.endTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package org.schabi.newpipe.player;
|
||||
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
|
||||
public interface LocalPlayerListener {
|
||||
void onBlocked(SimpleExoPlayer player);
|
||||
void onPlaying(SimpleExoPlayer player);
|
||||
void onBuffering(SimpleExoPlayer player);
|
||||
void onPaused(SimpleExoPlayer player);
|
||||
void onPausedSeek(SimpleExoPlayer player);
|
||||
void onCompleted(SimpleExoPlayer player);
|
||||
}
|
|
@ -5,8 +5,10 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed;
|
|||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.provider.Settings;
|
||||
|
@ -19,6 +21,7 @@ import android.widget.SeekBar;
|
|||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -44,6 +47,8 @@ import org.schabi.newpipe.util.PermissionHelper;
|
|||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import static org.schabi.newpipe.util.SponsorBlockUtils.markSegments;
|
||||
|
||||
public final class PlayQueueActivity extends AppCompatActivity
|
||||
implements PlayerEventListener, SeekBar.OnSeekBarChangeListener,
|
||||
View.OnClickListener, PlaybackParameterDialog.Callback {
|
||||
|
@ -214,6 +219,12 @@ public final class PlayQueueActivity extends AppCompatActivity
|
|||
onQueueUpdate(player.getPlayQueue());
|
||||
buildComponents();
|
||||
if (player != null) {
|
||||
final PlayQueueItem item = player.getPlayQueue().getItem();
|
||||
final Context context = getApplicationContext();
|
||||
final SharedPreferences prefs =
|
||||
PreferenceManager.getDefaultSharedPreferences(context);
|
||||
markSegments(item, queueControlBinding.seekBar, context, prefs);
|
||||
|
||||
player.setActivityListener(PlayQueueActivity.this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ import android.graphics.drawable.Drawable;
|
|||
import android.media.AudioManager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
@ -71,6 +72,7 @@ import com.google.android.exoplayer2.PlaybackException;
|
|||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player.PositionInfo;
|
||||
import com.google.android.exoplayer2.RenderersFactory;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.Tracks;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
|
@ -120,7 +122,9 @@ import org.schabi.newpipe.util.ListHelper;
|
|||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
import org.schabi.newpipe.util.SerializedCache;
|
||||
import org.schabi.newpipe.util.SponsorBlockMode;
|
||||
import org.schabi.newpipe.util.StreamTypeUtil;
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -161,6 +165,7 @@ public final class Player implements PlaybackListener, Listener {
|
|||
public static final String PLAY_WHEN_READY = "play_when_ready";
|
||||
public static final String PLAYER_TYPE = "player_type";
|
||||
public static final String IS_MUTED = "is_muted";
|
||||
public static final String VIDEO_SEGMENTS = "video_segments";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Time constants
|
||||
|
@ -245,6 +250,12 @@ public final class Player implements PlaybackListener, Listener {
|
|||
@NonNull private final SharedPreferences prefs;
|
||||
@NonNull private final HistoryRecordManager recordManager;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// SponsorBlock
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
private SponsorBlockMode sponsorBlockMode = SponsorBlockMode.DISABLED;
|
||||
private int lastSkipTarget = -1;
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
|
@ -437,6 +448,8 @@ public final class Player implements PlaybackListener, Listener {
|
|||
// (to disable/enable video stream or to set quality)
|
||||
setRecovery();
|
||||
reloadPlayQueueManager();
|
||||
stopProgressLoop();
|
||||
startProgressLoop();
|
||||
}
|
||||
|
||||
UIs.call(PlayerUi::setupAfterIntent);
|
||||
|
@ -615,7 +628,7 @@ public final class Player implements PlaybackListener, Listener {
|
|||
}
|
||||
|
||||
if (playQueue != null) {
|
||||
playQueueManager = new MediaSourceManager(this, playQueue);
|
||||
playQueueManager = new MediaSourceManager(context, this, playQueue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -901,12 +914,97 @@ public final class Player implements PlaybackListener, Listener {
|
|||
}
|
||||
|
||||
public void triggerProgressUpdate() {
|
||||
triggerProgressUpdate(false);
|
||||
}
|
||||
|
||||
private void triggerProgressUpdate(final boolean isRewind) {
|
||||
if (exoPlayerIsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
onUpdateProgress(Math.max((int) simpleExoPlayer.getCurrentPosition(), 0),
|
||||
(int) simpleExoPlayer.getDuration(), simpleExoPlayer.getBufferedPercentage());
|
||||
final int currentProgress = Math.max((int) simpleExoPlayer.getCurrentPosition(), 0);
|
||||
|
||||
onUpdateProgress(
|
||||
currentProgress,
|
||||
(int) simpleExoPlayer.getDuration(),
|
||||
simpleExoPlayer.getBufferedPercentage());
|
||||
|
||||
if (sponsorBlockMode == SponsorBlockMode.ENABLED && isPrepared) {
|
||||
final VideoSegment segment = getSkippableSegment(currentProgress);
|
||||
if (segment == null) {
|
||||
lastSkipTarget = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int skipTarget = isRewind
|
||||
? (int) Math.ceil((segment.startTime)) - 1
|
||||
: (int) Math.ceil((segment.endTime));
|
||||
|
||||
if (skipTarget < 0) {
|
||||
skipTarget = 0;
|
||||
}
|
||||
|
||||
if (lastSkipTarget == skipTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastSkipTarget = skipTarget;
|
||||
|
||||
// temporarily force EXACT seek parameters to prevent infinite skip looping
|
||||
final SeekParameters seekParams = simpleExoPlayer.getSeekParameters();
|
||||
simpleExoPlayer.setSeekParameters(SeekParameters.EXACT);
|
||||
|
||||
seekTo(skipTarget);
|
||||
|
||||
simpleExoPlayer.setSeekParameters(seekParams);
|
||||
|
||||
if (prefs.getBoolean(
|
||||
context.getString(R.string.sponsor_block_notifications_key), false)) {
|
||||
String toastText = "";
|
||||
|
||||
switch (segment.category) {
|
||||
case "sponsor":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_sponsor_toast);
|
||||
break;
|
||||
case "intro":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_intro_toast);
|
||||
break;
|
||||
case "outro":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_outro_toast);
|
||||
break;
|
||||
case "interaction":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_interaction_toast);
|
||||
break;
|
||||
case "selfpromo":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_self_promo_toast);
|
||||
break;
|
||||
case "music_offtopic":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_non_music_toast);
|
||||
break;
|
||||
case "preview":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_preview_toast);
|
||||
break;
|
||||
case "filler":
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_skip_filler_toast);
|
||||
break;
|
||||
}
|
||||
|
||||
Toast.makeText(context, toastText, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d("SPONSOR_BLOCK", "Skipped segment: currentProgress = ["
|
||||
+ currentProgress + "], skipped to = [" + skipTarget + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Disposable getProgressUpdateDisposable() {
|
||||
|
@ -1678,7 +1776,7 @@ public final class Player implements PlaybackListener, Listener {
|
|||
Log.d(TAG, "fastRewind() called");
|
||||
}
|
||||
seekBy(-retrieveSeekDurationFromPreferences(this));
|
||||
triggerProgressUpdate();
|
||||
triggerProgressUpdate(true);
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
@ -2243,6 +2341,49 @@ public final class Player implements PlaybackListener, Listener {
|
|||
return Optional.ofNullable(fragmentListener);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// SponsorBlock
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
//region
|
||||
|
||||
public SponsorBlockMode getSponsorBlockMode() {
|
||||
return sponsorBlockMode;
|
||||
}
|
||||
|
||||
public void setSponsorBlockMode(final SponsorBlockMode mode) {
|
||||
sponsorBlockMode = mode;
|
||||
}
|
||||
|
||||
public VideoSegment getSkippableSegment(final int progress) {
|
||||
// currentItem may get set to something later (asynchronously)
|
||||
if (currentItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final VideoSegment[] videoSegments = currentItem.getVideoSegments();
|
||||
if (videoSegments == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (final VideoSegment segment : videoSegments) {
|
||||
if (progress < segment.startTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (progress > segment.endTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
/**
|
||||
* @return the user interfaces connected with the player
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.schabi.newpipe.player.playback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -21,7 +22,9 @@ import org.schabi.newpipe.player.playqueue.events.MoveEvent;
|
|||
import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent;
|
||||
import org.schabi.newpipe.player.playqueue.events.RemoveEvent;
|
||||
import org.schabi.newpipe.player.playqueue.events.ReorderEvent;
|
||||
import org.schabi.newpipe.util.SponsorBlockUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
@ -69,6 +72,8 @@ public class MediaSourceManager {
|
|||
*/
|
||||
private static final int MAXIMUM_LOADER_SIZE = WINDOW_SIZE * 2 + 1;
|
||||
|
||||
@NonNull
|
||||
private final Context context;
|
||||
@NonNull
|
||||
private final PlaybackListener playbackListener;
|
||||
@NonNull
|
||||
|
@ -125,14 +130,16 @@ public class MediaSourceManager {
|
|||
|
||||
private final Handler removeMediaSourceHandler = new Handler();
|
||||
|
||||
public MediaSourceManager(@NonNull final PlaybackListener listener,
|
||||
public MediaSourceManager(@NonNull final Context context,
|
||||
@NonNull final PlaybackListener listener,
|
||||
@NonNull final PlayQueue playQueue) {
|
||||
this(listener, playQueue, 400L,
|
||||
this(context, listener, playQueue, 400L,
|
||||
/*playbackNearEndGapMillis=*/TimeUnit.MILLISECONDS.convert(30, TimeUnit.SECONDS),
|
||||
/*progressUpdateIntervalMillis*/TimeUnit.MILLISECONDS.convert(2, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private MediaSourceManager(@NonNull final PlaybackListener listener,
|
||||
private MediaSourceManager(@NonNull final Context context,
|
||||
@NonNull final PlaybackListener listener,
|
||||
@NonNull final PlayQueue playQueue,
|
||||
final long loadDebounceMillis,
|
||||
final long playbackNearEndGapMillis,
|
||||
|
@ -146,6 +153,7 @@ public class MediaSourceManager {
|
|||
+ " ms] for them to be useful.");
|
||||
}
|
||||
|
||||
this.context = context;
|
||||
this.playbackListener = listener;
|
||||
this.playQueue = playQueue;
|
||||
|
||||
|
@ -429,6 +437,13 @@ public class MediaSourceManager {
|
|||
final int serviceId = streamInfo.getServiceId();
|
||||
final long expiration = System.currentTimeMillis()
|
||||
+ getCacheExpirationMillis(serviceId);
|
||||
try {
|
||||
stream.setVideoSegments(
|
||||
SponsorBlockUtils.getYouTubeVideoSegments(
|
||||
context, streamInfo));
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new LoadedMediaSource(source, tag, stream,
|
||||
expiration);
|
||||
})
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
|
|||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
@ -36,6 +37,8 @@ public class PlayQueueItem implements Serializable {
|
|||
private long recoveryPosition;
|
||||
private Throwable error;
|
||||
|
||||
private VideoSegment[] videoSegments;
|
||||
|
||||
PlayQueueItem(@NonNull final StreamInfo info) {
|
||||
this(info.getName(), info.getUrl(), info.getServiceId(), info.getDuration(),
|
||||
info.getThumbnailUrl(), info.getUploaderName(),
|
||||
|
@ -137,4 +140,12 @@ public class PlayQueueItem implements Serializable {
|
|||
public void setAutoQueued(final boolean autoQueued) {
|
||||
isAutoQueued = autoQueued;
|
||||
}
|
||||
|
||||
public VideoSegment[] getVideoSegments() {
|
||||
return videoSegments;
|
||||
}
|
||||
|
||||
public void setVideoSegments(final VideoSegment[] videoSegments) {
|
||||
this.videoSegments = videoSegments;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
|||
// fullscreen player
|
||||
private ItemTouchHelper itemTouchHelper;
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, setup, destroy
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
@ -959,7 +958,6 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
|||
}
|
||||
//endregion
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Getters
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
|
@ -175,6 +175,10 @@ public final class PopupPlayerUi extends VideoPlayerUi {
|
|||
binding.topControls.setFocusable(false);
|
||||
binding.bottomControls.bringToFront();
|
||||
super.setupElementsVisibility();
|
||||
|
||||
// hide the SponsorBlock button from the pop-up player because
|
||||
// it looks bad and the UI is going to change in Tubular anyway...
|
||||
binding.switchSponsorBlocking.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -436,7 +440,6 @@ public final class PopupPlayerUi extends VideoPlayerUi {
|
|||
}
|
||||
//endregion
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Gestures
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
|
@ -15,6 +15,7 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed;
|
|||
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.nextResizeModeAndSaveToPrefs;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences;
|
||||
import static org.schabi.newpipe.util.SponsorBlockUtils.markSegments;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
|
@ -33,9 +34,11 @@ import android.view.KeyEvent;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
@ -79,13 +82,16 @@ import org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper;
|
|||
import org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHolder;
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.SponsorBlockMode;
|
||||
import org.schabi.newpipe.util.external_communication.KoreUtils;
|
||||
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||
import org.schabi.newpipe.views.player.PlayerFastSeekOverlay;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBarChangeListener,
|
||||
|
@ -139,7 +145,6 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
|||
private final SeekbarPreviewThumbnailHolder seekbarPreviewThumbnailHolder =
|
||||
new SeekbarPreviewThumbnailHolder();
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, setup, destroy
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
@ -235,6 +240,11 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
|||
));
|
||||
binding.switchMute.setOnClickListener(makeOnClickListener(player::toggleMute));
|
||||
|
||||
binding.switchSponsorBlocking.setOnClickListener(
|
||||
makeOnClickListener(this::onBlockingSponsorsButtonClicked));
|
||||
binding.switchSponsorBlocking.setOnLongClickListener(
|
||||
makeOnLongClickListener(this::onBlockingSponsorsButtonLongClicked));
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.itemsListPanel, (view, windowInsets) -> {
|
||||
final Insets cutout = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
|
||||
if (!cutout.equals(Insets.NONE)) {
|
||||
|
@ -408,6 +418,13 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
|||
protected void setupElementsVisibility() {
|
||||
setMuteButton(player.isMuted());
|
||||
animateRotation(binding.moreOptionsButton, DEFAULT_CONTROLS_DURATION, 0);
|
||||
|
||||
final boolean isSponsorBlockEnabled = player.getPrefs().getBoolean(
|
||||
context.getString(R.string.sponsor_block_enable_key), false);
|
||||
binding.switchSponsorBlocking.setVisibility(
|
||||
isSponsorBlockEnabled ? View.VISIBLE : View.GONE);
|
||||
|
||||
setBlockSponsorsButton(binding.switchSponsorBlocking);
|
||||
}
|
||||
|
||||
protected abstract void setupElementsSize(Resources resources);
|
||||
|
@ -756,6 +773,7 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
|||
super.onPrepared();
|
||||
setVideoDurationToControls((int) player.getExoPlayer().getDuration());
|
||||
binding.playbackSpeed.setText(formatSpeed(player.getPlaybackSpeed()));
|
||||
markSegments(player.getCurrentItem(), binding.playbackSeekBar, context, player.getPrefs());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -979,6 +997,21 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
|||
binding.channelTextView.setText(info.getUploaderName());
|
||||
|
||||
this.seekbarPreviewThumbnailHolder.resetFrom(player.getContext(), info.getPreviewFrames());
|
||||
|
||||
final boolean isSponsorBlockEnabled = player.getPrefs().getBoolean(
|
||||
context.getString(R.string.sponsor_block_enable_key), false);
|
||||
final Set<String> uploaderWhitelist = player.getPrefs().getStringSet(
|
||||
context.getString(R.string.sponsor_block_whitelist_key), null);
|
||||
|
||||
if (uploaderWhitelist != null && uploaderWhitelist.contains(info.getUploaderName())) {
|
||||
player.setSponsorBlockMode(SponsorBlockMode.IGNORE);
|
||||
} else {
|
||||
player.setSponsorBlockMode(isSponsorBlockEnabled
|
||||
? SponsorBlockMode.ENABLED
|
||||
: SponsorBlockMode.DISABLED);
|
||||
}
|
||||
|
||||
setBlockSponsorsButton(binding.switchSponsorBlocking);
|
||||
}
|
||||
|
||||
private void updateStreamRelatedViews() {
|
||||
|
@ -1356,6 +1389,37 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
|||
};
|
||||
}
|
||||
|
||||
protected View.OnLongClickListener makeOnLongClickListener(@NonNull final Runnable runnable) {
|
||||
return v -> {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onLongClick() called with: v = [" + v + "]");
|
||||
}
|
||||
|
||||
runnable.run();
|
||||
|
||||
// Manages the player controls after handling the view click.
|
||||
if (player.getCurrentState() == STATE_COMPLETED) {
|
||||
return true;
|
||||
}
|
||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||
showHideShadow(true, DEFAULT_CONTROLS_DURATION);
|
||||
animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION,
|
||||
AnimationType.ALPHA, 0, () -> {
|
||||
if (player.getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible) {
|
||||
if (v == binding.playPauseButton
|
||||
// Hide controls in fullscreen immediately
|
||||
|| (v == binding.screenRotationButton && isFullscreen())) {
|
||||
hideControls(0, 0);
|
||||
} else {
|
||||
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
public boolean onKeyDown(final int keyCode) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
|
@ -1459,6 +1523,96 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
|||
}
|
||||
//endregion
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// SponsorBlock
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
//region
|
||||
|
||||
public void onBlockingSponsorsButtonClicked() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onBlockingSponsorsButtonClicked() called");
|
||||
}
|
||||
|
||||
switch (player.getSponsorBlockMode()) {
|
||||
case DISABLED:
|
||||
player.setSponsorBlockMode(SponsorBlockMode.ENABLED);
|
||||
break;
|
||||
case ENABLED:
|
||||
player.setSponsorBlockMode(SponsorBlockMode.DISABLED);
|
||||
break;
|
||||
case IGNORE:
|
||||
// ignored
|
||||
}
|
||||
|
||||
setBlockSponsorsButton(binding.switchSponsorBlocking);
|
||||
}
|
||||
|
||||
public void onBlockingSponsorsButtonLongClicked() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onBlockingSponsorsButtonLongClicked() called");
|
||||
}
|
||||
|
||||
final MediaItemTag metaData = player.getCurrentMetadata();
|
||||
|
||||
if (metaData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<String> uploaderWhitelist = new HashSet<>(player.getPrefs().getStringSet(
|
||||
context.getString(R.string.sponsor_block_whitelist_key),
|
||||
new HashSet<>()));
|
||||
|
||||
final String toastText;
|
||||
|
||||
final String uploaderName = metaData.getUploaderName();
|
||||
|
||||
if (player.getSponsorBlockMode() == SponsorBlockMode.IGNORE) {
|
||||
uploaderWhitelist.remove(uploaderName);
|
||||
player.setSponsorBlockMode(SponsorBlockMode.ENABLED);
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_uploader_removed_from_whitelist_toast);
|
||||
} else {
|
||||
uploaderWhitelist.add(uploaderName);
|
||||
player.setSponsorBlockMode(SponsorBlockMode.IGNORE);
|
||||
toastText = context
|
||||
.getString(R.string.sponsor_block_uploader_added_to_whitelist_toast);
|
||||
}
|
||||
|
||||
player.getPrefs()
|
||||
.edit()
|
||||
.putStringSet(
|
||||
context.getString(R.string.sponsor_block_whitelist_key),
|
||||
new HashSet<>(uploaderWhitelist))
|
||||
.apply();
|
||||
|
||||
setBlockSponsorsButton(binding.switchSponsorBlocking);
|
||||
Toast.makeText(context, toastText, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
protected void setBlockSponsorsButton(final ImageButton button) {
|
||||
if (button == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int resId;
|
||||
|
||||
switch (player.getSponsorBlockMode()) {
|
||||
case DISABLED:
|
||||
resId = R.drawable.ic_sponsor_block_disable;
|
||||
break;
|
||||
case ENABLED:
|
||||
resId = R.drawable.ic_sponsor_block_enable;
|
||||
break;
|
||||
case IGNORE:
|
||||
resId = R.drawable.ic_sponsor_block_exclude;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
button.setImageDrawable(AppCompatResources.getDrawable(player.getService(), resId));
|
||||
}
|
||||
//endregion
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceHolderCallback helpers
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package org.schabi.newpipe.settings;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class ExtraSettingsFragment extends BasePreferenceFragment {
|
||||
@Override
|
||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||
addPreferencesFromResourceRegistry();
|
||||
}
|
||||
}
|
|
@ -73,6 +73,7 @@ public final class NewPipeSettings {
|
|||
PreferenceManager.setDefaultValues(context, R.xml.player_notification_settings, true);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.update_settings, true);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.debug_settings, true);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.sponsor_block_category_settings, true);
|
||||
|
||||
saveDefaultVideoDownloadDirectory(context);
|
||||
saveDefaultAudioDownloadDirectory(context);
|
||||
|
|
|
@ -40,6 +40,9 @@ public final class SettingsResourceRegistry {
|
|||
add(PlayerNotificationSettingsFragment.class, R.xml.player_notification_settings);
|
||||
add(UpdateSettingsFragment.class, R.xml.update_settings);
|
||||
add(VideoAudioSettingsFragment.class, R.xml.video_audio_settings);
|
||||
add(SponsorBlockSettingsFragment.class, R.xml.sponsor_block_settings);
|
||||
add(SponsorBlockCategoriesSettingsFragment.class, R.xml.sponsor_block_category_settings);
|
||||
add(ExtraSettingsFragment.class, R.xml.extra_settings);
|
||||
}
|
||||
|
||||
private SettingRegistryEntry add(
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package org.schabi.newpipe.settings;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.settings.custom.EditColorPreference;
|
||||
|
||||
public class SponsorBlockCategoriesSettingsFragment extends BasePreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||
addPreferencesFromResourceRegistry();
|
||||
|
||||
final Preference resetPreference =
|
||||
findPreference(getString(R.string.sponsor_block_category_reset_key));
|
||||
resetPreference.setOnPreferenceClickListener(p -> {
|
||||
new AlertDialog.Builder(p.getContext())
|
||||
.setMessage(R.string.sponsor_block_confirm_reset_colors)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
final SharedPreferences.Editor editor =
|
||||
getPreferenceManager()
|
||||
.getSharedPreferences()
|
||||
.edit();
|
||||
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_sponsor_color_key,
|
||||
R.color.sponsor_segment);
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_intro_color_key,
|
||||
R.color.intro_segment);
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_outro_color_key,
|
||||
R.color.outro_segment);
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_interaction_color_key,
|
||||
R.color.interaction_segment);
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_self_promo_color_key,
|
||||
R.color.self_promo_segment);
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_non_music_color_key,
|
||||
R.color.non_music_segment);
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_preview_color_key,
|
||||
R.color.preview_segment);
|
||||
setColorPreference(editor,
|
||||
R.string.sponsor_block_category_filler_color_key,
|
||||
R.color.filler_segment);
|
||||
|
||||
editor.apply();
|
||||
|
||||
Toast.makeText(p.getContext(), R.string.sponsor_block_reset_colors_toast,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
.setNegativeButton(R.string.no, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
})
|
||||
.show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setColorPreference(final SharedPreferences.Editor editor,
|
||||
@StringRes final int resId,
|
||||
@ColorRes final int colorId) {
|
||||
final String colorStr = "#" + Integer.toHexString(getResources().getColor(colorId));
|
||||
editor.putString(getString(resId), colorStr);
|
||||
final EditColorPreference colorPreference = findPreference(getString(resId));
|
||||
colorPreference.setText(colorStr);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package org.schabi.newpipe.settings;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class SponsorBlockSettingsFragment extends BasePreferenceFragment {
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||
addPreferencesFromResourceRegistry();
|
||||
|
||||
final Preference sponsorBlockWebsitePreference =
|
||||
findPreference(getString(R.string.sponsor_block_home_page_key));
|
||||
sponsorBlockWebsitePreference.setOnPreferenceClickListener((Preference p) -> {
|
||||
final Intent i = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(getString(R.string.sponsor_block_homepage_url)));
|
||||
startActivity(i);
|
||||
return true;
|
||||
});
|
||||
|
||||
final Preference sponsorBlockPrivacyPreference =
|
||||
findPreference(getString(R.string.sponsor_block_privacy_key));
|
||||
sponsorBlockPrivacyPreference.setOnPreferenceClickListener((Preference p) -> {
|
||||
final Intent i = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(getString(R.string.sponsor_block_privacy_policy_url)));
|
||||
startActivity(i);
|
||||
return true;
|
||||
});
|
||||
|
||||
final Preference sponsorBlockApiUrlPreference =
|
||||
findPreference(getString(R.string.sponsor_block_api_url_key));
|
||||
sponsorBlockApiUrlPreference
|
||||
.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
updateDependencies(preference, newValue);
|
||||
return true;
|
||||
});
|
||||
|
||||
final Preference sponsorBlockClearWhitelistPreference =
|
||||
findPreference(getString(R.string.sponsor_block_clear_whitelist_key));
|
||||
sponsorBlockClearWhitelistPreference.setOnPreferenceClickListener((Preference p) -> {
|
||||
new AlertDialog.Builder(p.getContext())
|
||||
.setMessage(R.string.sponsor_block_confirm_clear_whitelist)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||
getPreferenceManager()
|
||||
.getSharedPreferences()
|
||||
.edit()
|
||||
.putStringSet(getString(
|
||||
R.string.sponsor_block_whitelist_key), new HashSet<>())
|
||||
.apply();
|
||||
Toast.makeText(p.getContext(),
|
||||
R.string.sponsor_block_whitelist_cleared_toast,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
.setNegativeButton(R.string.no, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
})
|
||||
.show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
final Preference sponsorBlockApiUrlPreference =
|
||||
findPreference(getString(R.string.sponsor_block_api_url_key));
|
||||
final String sponsorBlockApiUrlPreferenceValue =
|
||||
getPreferenceManager()
|
||||
.getSharedPreferences()
|
||||
.getString(getString(R.string.sponsor_block_api_url_key), null);
|
||||
updateDependencies(sponsorBlockApiUrlPreference, sponsorBlockApiUrlPreferenceValue);
|
||||
}
|
||||
|
||||
private void updateDependencies(final Preference preference, final Object newValue) {
|
||||
// This is a workaround to force dependency updates for custom preferences.
|
||||
|
||||
// sponsor_block_api_url_key
|
||||
if (preference.getKey().equals(getString(R.string.sponsor_block_api_url_key))) {
|
||||
findPreference(getString(R.string.sponsor_block_enable_key))
|
||||
.onDependencyChanged(preference,
|
||||
newValue == null || newValue.equals(""));
|
||||
findPreference(getString(R.string.sponsor_block_notifications_key))
|
||||
.onDependencyChanged(preference,
|
||||
newValue == null || newValue.equals(""));
|
||||
findPreference(getString(R.string.sponsor_block_categories_key))
|
||||
.onDependencyChanged(preference,
|
||||
newValue == null || newValue.equals(""));
|
||||
findPreference(getString(R.string.sponsor_block_clear_whitelist_key))
|
||||
.onDependencyChanged(preference,
|
||||
newValue == null || newValue.equals(""));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.schabi.newpipe.settings.custom;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
|
||||
public class EditColorPreference extends EditTextPreference
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
private PreferenceViewHolder viewHolder;
|
||||
|
||||
public EditColorPreference(final Context context, final AttributeSet attrs,
|
||||
final int defStyleAttr, final int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
public EditColorPreference(final Context context, final AttributeSet attrs,
|
||||
final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
public EditColorPreference(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public EditColorPreference(final Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setWidgetLayoutResource(R.layout.preference_edit_color);
|
||||
setOnPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
|
||||
viewHolder = holder;
|
||||
|
||||
final String colorStr =
|
||||
getPreferenceManager()
|
||||
.getSharedPreferences()
|
||||
.getString(getKey(), null);
|
||||
|
||||
if (colorStr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int color = Color.parseColor(colorStr);
|
||||
|
||||
final View view = viewHolder.findViewById(R.id.segment_color_view);
|
||||
view.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(final Preference preference, final Object newValue) {
|
||||
try {
|
||||
final int color = Color.parseColor((String) newValue);
|
||||
|
||||
final View view = viewHolder.findViewById(R.id.segment_color_view);
|
||||
view.setBackgroundColor(color);
|
||||
|
||||
return true;
|
||||
} catch (final Exception e) {
|
||||
Toast.makeText(getContext(), R.string.invalid_color_toast, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package org.schabi.newpipe.settings.custom;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
|
||||
public class SponsorBlockApiUrlPreference extends Preference {
|
||||
public SponsorBlockApiUrlPreference(final Context context, final AttributeSet attrs,
|
||||
final int defStyleAttr, final int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
public SponsorBlockApiUrlPreference(final Context context, final AttributeSet attrs,
|
||||
final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public SponsorBlockApiUrlPreference(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public SponsorBlockApiUrlPreference(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
super.onClick();
|
||||
|
||||
final View alertDialogView = LayoutInflater.from(getContext())
|
||||
.inflate(R.layout.dialog_sponsor_block_api_url, null);
|
||||
|
||||
final EditText editText = alertDialogView.findViewById(R.id.api_url_edit);
|
||||
editText.setText(getSharedPreferences().getString(getKey(), null));
|
||||
editText.setOnFocusChangeListener((v, hasFocus) -> editText.post(() -> {
|
||||
final InputMethodManager inputMethodManager = (InputMethodManager) getContext()
|
||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
inputMethodManager
|
||||
.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
|
||||
}));
|
||||
editText.requestFocus();
|
||||
|
||||
alertDialogView.findViewById(R.id.icon_api_url_help)
|
||||
.setOnClickListener(v -> {
|
||||
final Uri privacyPolicyUri = Uri.parse(getContext()
|
||||
.getString(R.string.sponsor_block_privacy_policy_url));
|
||||
final View helpDialogView = LayoutInflater.from(getContext())
|
||||
.inflate(R.layout.dialog_sponsor_block_api_url_help, null);
|
||||
final View privacyPolicyButton = helpDialogView
|
||||
.findViewById(R.id.sponsor_block_privacy_policy_button);
|
||||
privacyPolicyButton.setOnClickListener(v1 -> {
|
||||
final Intent i = new Intent(Intent.ACTION_VIEW, privacyPolicyUri);
|
||||
getContext().startActivity(i);
|
||||
});
|
||||
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setView(helpDialogView)
|
||||
.setPositiveButton("Use Official", (dialog, which) -> {
|
||||
editText.setText(getContext()
|
||||
.getString(R.string.sponsor_block_default_api_url));
|
||||
dialog.dismiss();
|
||||
})
|
||||
.setNeutralButton("Close", (dialog, which) -> dialog.dismiss())
|
||||
.create()
|
||||
.show();
|
||||
});
|
||||
|
||||
final AlertDialog alertDialog =
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setView(alertDialogView)
|
||||
.setTitle(getContext().getString(R.string.sponsor_block_api_url_title))
|
||||
.setPositiveButton("OK", (dialog, which) -> {
|
||||
final String newValue = editText.getText().toString();
|
||||
final SharedPreferences.Editor editor =
|
||||
getPreferenceManager().getSharedPreferences().edit();
|
||||
editor.putString(getKey(), newValue);
|
||||
editor.apply();
|
||||
|
||||
callChangeListener(newValue);
|
||||
|
||||
dialog.dismiss();
|
||||
})
|
||||
.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel())
|
||||
.create();
|
||||
|
||||
alertDialog.show();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.grack.nanojson.JsonObject;
|
||||
import com.grack.nanojson.JsonParser;
|
||||
|
||||
import org.schabi.newpipe.DownloaderImpl;
|
||||
import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
|
||||
public final class ReturnYouTubeDislikeUtils {
|
||||
|
||||
private static final String API_URL = "https://returnyoutubedislikeapi.com/votes?videoId=";
|
||||
private static final String TAG = ReturnYouTubeDislikeUtils.class.getSimpleName();
|
||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||
|
||||
private ReturnYouTubeDislikeUtils() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("CheckStyle")
|
||||
public static int getDislikes(final Context context,
|
||||
final StreamInfo streamInfo) {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
final boolean isReturnYouTubeDislikeEnabled = prefs.getBoolean(context
|
||||
.getString(R.string.enable_return_youtube_dislike_key), false);
|
||||
|
||||
if (!isReturnYouTubeDislikeEnabled) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!streamInfo.getUrl().startsWith("https://www.youtube.com")) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
JsonObject response = null;
|
||||
|
||||
try {
|
||||
final String responseBody =
|
||||
DownloaderImpl
|
||||
.getInstance()
|
||||
.setCustomTimeout(3)
|
||||
.get(API_URL + streamInfo.getId())
|
||||
.responseBody();
|
||||
|
||||
response = JsonParser.object().from(responseBody);
|
||||
|
||||
} catch (final Exception ex) {
|
||||
if (DEBUG) {
|
||||
Log.w(TAG, Log.getStackTraceString(ex));
|
||||
}
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (response.has("dislikes")) {
|
||||
return response.getInt("dislikes", 0);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
public enum SponsorBlockMode {
|
||||
DISABLED,
|
||||
ENABLED,
|
||||
IGNORE
|
||||
}
|
344
app/src/main/java/org/schabi/newpipe/util/SponsorBlockUtils.java
Normal file
344
app/src/main/java/org/schabi/newpipe/util/SponsorBlockUtils.java
Normal file
|
@ -0,0 +1,344 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.grack.nanojson.JsonArray;
|
||||
import com.grack.nanojson.JsonObject;
|
||||
import com.grack.nanojson.JsonParser;
|
||||
|
||||
import org.schabi.newpipe.App;
|
||||
import org.schabi.newpipe.DownloaderImpl;
|
||||
import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||
import org.schabi.newpipe.views.MarkableSeekBar;
|
||||
import org.schabi.newpipe.views.SeekBarMarker;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class SponsorBlockUtils {
|
||||
private static final Application APP = App.getApp();
|
||||
private static final String TAG = SponsorBlockUtils.class.getSimpleName();
|
||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||
|
||||
private SponsorBlockUtils() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("CheckStyle")
|
||||
public static VideoSegment[] getYouTubeVideoSegments(final Context context,
|
||||
final StreamInfo streamInfo)
|
||||
throws UnsupportedEncodingException {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
final boolean isSponsorBlockEnabled = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_enable_key), false);
|
||||
|
||||
if (!isSponsorBlockEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String apiUrl = prefs.getString(context
|
||||
.getString(R.string.sponsor_block_api_url_key), null);
|
||||
|
||||
if (!streamInfo.getUrl().startsWith("https://www.youtube.com")
|
||||
|| apiUrl == null
|
||||
|| apiUrl.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean includeSponsorCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_sponsor_key), false);
|
||||
final boolean includeIntroCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_intro_key), false);
|
||||
final boolean includeOutroCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_outro_key), false);
|
||||
final boolean includeInteractionCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_interaction_key), false);
|
||||
final boolean includeSelfPromoCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_self_promo_key), false);
|
||||
final boolean includeMusicCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_non_music_key), false);
|
||||
final boolean includePreviewCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_preview_key), false);
|
||||
final boolean includeFillerCategory = prefs.getBoolean(context
|
||||
.getString(R.string.sponsor_block_category_filler_key), false);
|
||||
|
||||
final ArrayList<String> categoryParamList = new ArrayList<>();
|
||||
|
||||
if (includeSponsorCategory) {
|
||||
categoryParamList.add("sponsor");
|
||||
}
|
||||
if (includeIntroCategory) {
|
||||
categoryParamList.add("intro");
|
||||
}
|
||||
if (includeOutroCategory) {
|
||||
categoryParamList.add("outro");
|
||||
}
|
||||
if (includeInteractionCategory) {
|
||||
categoryParamList.add("interaction");
|
||||
}
|
||||
if (includeSelfPromoCategory) {
|
||||
categoryParamList.add("selfpromo");
|
||||
}
|
||||
if (includeMusicCategory) {
|
||||
categoryParamList.add("music_offtopic");
|
||||
}
|
||||
if (includePreviewCategory) {
|
||||
categoryParamList.add("preview");
|
||||
}
|
||||
|
||||
if (includeFillerCategory) {
|
||||
categoryParamList.add("filler");
|
||||
}
|
||||
|
||||
if (categoryParamList.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String categoryParams = "[\"" + TextUtils.join("\",\"", categoryParamList) + "\"]";
|
||||
categoryParams = URLEncoder.encode(categoryParams, "utf-8");
|
||||
|
||||
final String videoIdHash = toSha256(streamInfo.getId());
|
||||
|
||||
if (videoIdHash == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String params = "skipSegments/" + videoIdHash.substring(0, 4)
|
||||
+ "?categories=" + categoryParams;
|
||||
|
||||
if (!isConnected()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonArray responseArray = null;
|
||||
|
||||
try {
|
||||
final String responseBody =
|
||||
DownloaderImpl
|
||||
.getInstance()
|
||||
.setCustomTimeout(3)
|
||||
.get(apiUrl + params)
|
||||
.responseBody();
|
||||
|
||||
responseArray = JsonParser.array().from(responseBody);
|
||||
|
||||
} catch (final Exception ex) {
|
||||
if (DEBUG) {
|
||||
Log.w(TAG, Log.getStackTraceString(ex));
|
||||
}
|
||||
}
|
||||
|
||||
if (responseArray == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ArrayList<VideoSegment> result = new ArrayList<>();
|
||||
|
||||
for (final Object obj1 : responseArray) {
|
||||
final JsonObject jObj1 = (JsonObject) obj1;
|
||||
|
||||
final String responseVideoId = jObj1.getString("videoID");
|
||||
if (!responseVideoId.equals(streamInfo.getId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final JsonArray segmentArray = (JsonArray) jObj1.get("segments");
|
||||
if (segmentArray == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final Object obj2 : segmentArray) {
|
||||
final JsonObject jObj2 = (JsonObject) obj2;
|
||||
|
||||
final JsonArray segmentInfo = (JsonArray) jObj2.get("segment");
|
||||
if (segmentInfo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final double startTime = segmentInfo.getDouble(0) * 1000;
|
||||
final double endTime = segmentInfo.getDouble(1) * 1000;
|
||||
final String category = jObj2.getString("category");
|
||||
|
||||
final VideoSegment segment = new VideoSegment(startTime, endTime, category);
|
||||
result.add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new VideoSegment[0]);
|
||||
}
|
||||
|
||||
private static boolean isConnected() {
|
||||
final ConnectivityManager cm =
|
||||
(ConnectivityManager) APP.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return cm.getActiveNetworkInfo() != null
|
||||
&& cm.getActiveNetworkInfo().isConnected();
|
||||
}
|
||||
|
||||
private static String toSha256(final String videoId) {
|
||||
try {
|
||||
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
final byte[] bytes = digest.digest(videoId.getBytes(StandardCharsets.UTF_8));
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final byte b : bytes) {
|
||||
final String hex = Integer.toHexString(0xff & b);
|
||||
|
||||
if (hex.length() == 1) {
|
||||
sb.append('0');
|
||||
}
|
||||
|
||||
sb.append(hex);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
} catch (final Exception e) {
|
||||
Log.e("SPONSOR_BLOCK", "Error getting video ID hash.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Integer parseSegmentCategory(
|
||||
final String category,
|
||||
final Context context,
|
||||
final SharedPreferences prefs
|
||||
) {
|
||||
String key;
|
||||
final String colorStr;
|
||||
switch (category) {
|
||||
case "sponsor":
|
||||
key = context.getString(R.string.sponsor_block_category_sponsor_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_sponsor_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.sponsor_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
case "intro":
|
||||
key = context.getString(R.string.sponsor_block_category_intro_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_intro_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.intro_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
case "outro":
|
||||
key = context.getString(R.string.sponsor_block_category_outro_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_outro_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.outro_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
case "interaction":
|
||||
key = context.getString(R.string.sponsor_block_category_interaction_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_interaction_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.interaction_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
case "selfpromo":
|
||||
key = context.getString(R.string.sponsor_block_category_self_promo_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_self_promo_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.self_promo_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
case "music_offtopic":
|
||||
key = context.getString(R.string.sponsor_block_category_non_music_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_non_music_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.non_music_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
case "preview":
|
||||
key = context.getString(R.string.sponsor_block_category_preview_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_preview_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.preview_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
case "filler":
|
||||
key = context.getString(R.string.sponsor_block_category_filler_key);
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
key = context.getString(R.string.sponsor_block_category_filler_color_key);
|
||||
colorStr = prefs.getString(key, null);
|
||||
return colorStr == null
|
||||
? context.getResources().getColor(R.color.filler_segment)
|
||||
: Color.parseColor(colorStr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void markSegments(
|
||||
final PlayQueueItem currentItem,
|
||||
final MarkableSeekBar seekBar,
|
||||
final Context context,
|
||||
final SharedPreferences prefs
|
||||
) {
|
||||
seekBar.clearMarkers();
|
||||
|
||||
if (currentItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final VideoSegment[] segments = currentItem.getVideoSegments();
|
||||
|
||||
if (segments == null || segments.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final VideoSegment segment : segments) {
|
||||
final Integer color = parseSegmentCategory(segment.category, context, prefs);
|
||||
|
||||
// if null, then this category should not be marked
|
||||
if (color == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Duration is in seconds, we need millis
|
||||
final int length = (int) currentItem.getDuration() * 1000;
|
||||
|
||||
final SeekBarMarker seekBarMarker =
|
||||
new SeekBarMarker(segment.startTime, segment.endTime,
|
||||
length, color);
|
||||
seekBar.seekBarMarkers.add(seekBarMarker);
|
||||
}
|
||||
|
||||
seekBar.drawMarkers();
|
||||
}
|
||||
}
|
79
app/src/main/java/org/schabi/newpipe/util/Version.java
Normal file
79
app/src/main/java/org/schabi/newpipe/util/Version.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public final class Version implements Comparable<Version> {
|
||||
private static final String TAG = Version.class.getSimpleName();
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int build;
|
||||
private final int rev;
|
||||
|
||||
public Version(final int major, final int minor, final int build, final int rev) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.build = build;
|
||||
this.rev = rev;
|
||||
}
|
||||
|
||||
public static Version fromString(final String str) {
|
||||
// examples of valid version strings:
|
||||
// - 0.1
|
||||
// - v0.1.0.4
|
||||
// - 0.20.6
|
||||
// - v0.20.6_r2
|
||||
try {
|
||||
// example: v0.20.6_r2 -> v0.20.6.r2 -> 0.20.6.2
|
||||
final String[] split = str
|
||||
.replaceAll("_", ".")
|
||||
.replaceAll("[^0-9.]", "")
|
||||
.split("[^\\d]");
|
||||
|
||||
final int major = Integer.parseInt(split[0]);
|
||||
final int minor = split.length > 1
|
||||
? Integer.parseInt(split[1])
|
||||
: 0;
|
||||
final int build = split.length > 2
|
||||
? Integer.parseInt(split[2])
|
||||
: 0;
|
||||
final int rev = split.length > 3
|
||||
? Integer.parseInt(split[3])
|
||||
: 0;
|
||||
|
||||
return new Version(major, minor, build, rev);
|
||||
} catch (final Exception e) {
|
||||
Log.e(TAG, "Could not successfully parse version string.", e);
|
||||
return new Version(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
public int getMinor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
public int getBuild() {
|
||||
return build;
|
||||
}
|
||||
|
||||
public int getRev() {
|
||||
return rev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Version that) {
|
||||
if (this.getMajor() != that.getMajor()) {
|
||||
return this.getMajor() < that.getMajor() ? -1 : 1;
|
||||
} else if (this.getMinor() != that.getMinor()) {
|
||||
return this.getMinor() < that.getMinor() ? -1 : 1;
|
||||
} else if (this.getBuild() != that.getBuild()) {
|
||||
return this.getBuild() < that.getBuild() ? -1 : 1;
|
||||
} else if (this.getRev() != that.getRev()) {
|
||||
return this.getRev() < that.getRev() ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
15
app/src/main/java/org/schabi/newpipe/util/VideoSegment.java
Normal file
15
app/src/main/java/org/schabi/newpipe/util/VideoSegment.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class VideoSegment implements Serializable {
|
||||
public double startTime;
|
||||
public double endTime;
|
||||
public String category;
|
||||
|
||||
public VideoSegment(final double startTime, final double endTime, final String category) {
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.category = category;
|
||||
}
|
||||
}
|
|
@ -24,8 +24,6 @@ import android.view.KeyEvent;
|
|||
import android.view.ViewTreeObserver;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatSeekBar;
|
||||
|
||||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +31,7 @@ import org.schabi.newpipe.util.DeviceUtils;
|
|||
* (onStartTrackingTouch/onStopTrackingTouch), so existing code does not need to be changed to
|
||||
* work with it.
|
||||
*/
|
||||
public final class FocusAwareSeekBar extends AppCompatSeekBar {
|
||||
public final class FocusAwareSeekBar extends MarkableSeekBar {
|
||||
private NestedListener listener;
|
||||
|
||||
private ViewTreeObserver treeObserver;
|
||||
|
|
109
app/src/main/java/org/schabi/newpipe/views/MarkableSeekBar.java
Normal file
109
app/src/main/java/org/schabi/newpipe/views/MarkableSeekBar.java
Normal file
|
@ -0,0 +1,109 @@
|
|||
package org.schabi.newpipe.views;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatSeekBar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MarkableSeekBar extends AppCompatSeekBar {
|
||||
public ArrayList<SeekBarMarker> seekBarMarkers = new ArrayList<>();
|
||||
private Drawable originalProgressDrawable;
|
||||
|
||||
public MarkableSeekBar(final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public MarkableSeekBar(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public MarkableSeekBar(final Context context,
|
||||
final AttributeSet attrs,
|
||||
final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressDrawable(final Drawable d) {
|
||||
super.setProgressDrawable(d);
|
||||
|
||||
// stored for when we draw (and potentially re-draw) markers
|
||||
originalProgressDrawable = d;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(final int w, final int h, final int oldW, final int oldH) {
|
||||
super.onSizeChanged(w, h, oldW, oldH);
|
||||
|
||||
// re-draw markers since the progress bar may have a different width
|
||||
drawMarkers();
|
||||
}
|
||||
|
||||
public void drawMarkers() {
|
||||
if (seekBarMarkers.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Markers are drawn like so:
|
||||
//
|
||||
// - LayerDrawable (original drawable for the SeekBar)
|
||||
// - GradientDrawable (background)
|
||||
// - ScaleDrawable (secondaryProgress)
|
||||
// - ScaleDrawable (progress)
|
||||
// - LayerDrawable (we add our markers in a sub-LayerDrawable)
|
||||
// - Drawable (marker)
|
||||
// - Drawable (marker)
|
||||
// - Drawable (marker)
|
||||
// - etc...
|
||||
|
||||
final int width = getMeasuredWidth() - (getPaddingStart() + getPaddingEnd());
|
||||
|
||||
LayerDrawable layerDrawable = (LayerDrawable) originalProgressDrawable;
|
||||
|
||||
final ArrayList<Drawable> markerDrawables = new ArrayList<>();
|
||||
markerDrawables.add(layerDrawable);
|
||||
|
||||
for (final SeekBarMarker seekBarMarker : seekBarMarkers) {
|
||||
@SuppressLint("PrivateResource")
|
||||
final Drawable markerDrawable =
|
||||
ContextCompat.getDrawable(
|
||||
getContext(),
|
||||
R.drawable.abc_scrubber_primary_mtrl_alpha);
|
||||
|
||||
final PorterDuffColorFilter colorFilter =
|
||||
new PorterDuffColorFilter(seekBarMarker.color, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
assert markerDrawable != null;
|
||||
markerDrawable.setColorFilter(colorFilter);
|
||||
|
||||
markerDrawables.add(markerDrawable);
|
||||
}
|
||||
|
||||
layerDrawable = new LayerDrawable(markerDrawables.toArray(new Drawable[0]));
|
||||
|
||||
for (int i = 1; i < layerDrawable.getNumberOfLayers(); i++) {
|
||||
final SeekBarMarker seekBarMarker = seekBarMarkers.get(i - 1);
|
||||
final int l = (int) (width * seekBarMarker.percentStart);
|
||||
final int r = (int) (width * (1.0 - seekBarMarker.percentEnd));
|
||||
|
||||
layerDrawable.setLayerInset(i, l, 0, r, 0);
|
||||
}
|
||||
|
||||
super.setProgressDrawable(layerDrawable);
|
||||
}
|
||||
|
||||
public void clearMarkers() {
|
||||
seekBarMarkers.clear();
|
||||
super.setProgressDrawable(originalProgressDrawable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.schabi.newpipe.views;
|
||||
|
||||
public class SeekBarMarker {
|
||||
public double startTime;
|
||||
public double endTime;
|
||||
public double percentStart;
|
||||
public double percentEnd;
|
||||
public int color;
|
||||
|
||||
public SeekBarMarker(final double startTime,
|
||||
final double endTime,
|
||||
final int maxTime,
|
||||
final int color) {
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.percentStart = ((startTime / maxTime) * 100.0) / 100.0;
|
||||
this.percentEnd = ((endTime / maxTime) * 100.0) / 100.0;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public SeekBarMarker(final double percentStart, final double percentEnd, final int color) {
|
||||
this.percentStart = percentStart;
|
||||
this.percentEnd = percentEnd;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ public class FinishedMission extends Mission {
|
|||
timestamp = mission.timestamp;
|
||||
kind = mission.kind;
|
||||
storage = mission.storage;
|
||||
segmentsJson = mission.segmentsJson;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package us.shandian.giga.get;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Calendar;
|
||||
|
||||
|
@ -39,6 +41,8 @@ public abstract class Mission implements Serializable {
|
|||
*/
|
||||
public StoredFileHelper storage;
|
||||
|
||||
public String segmentsJson;
|
||||
|
||||
/**
|
||||
* Delete the downloaded file
|
||||
*
|
||||
|
|
|
@ -27,7 +27,7 @@ public class FinishedMissionStore extends SQLiteOpenHelper {
|
|||
// TODO: use NewPipeSQLiteHelper ('s constants) when playlist branch is merged (?)
|
||||
private static final String DATABASE_NAME = "downloads.db";
|
||||
|
||||
private static final int DATABASE_VERSION = 4;
|
||||
private static final int DATABASE_VERSION = 5;
|
||||
|
||||
/**
|
||||
* The table name of download missions (old)
|
||||
|
@ -56,6 +56,8 @@ public class FinishedMissionStore extends SQLiteOpenHelper {
|
|||
|
||||
private static final String KEY_PATH = "path";
|
||||
|
||||
private static final String KEY_SEGMENTS = "segments";
|
||||
|
||||
/**
|
||||
* The statement to create the table
|
||||
*/
|
||||
|
@ -66,6 +68,7 @@ public class FinishedMissionStore extends SQLiteOpenHelper {
|
|||
KEY_DONE + " INTEGER NOT NULL, " +
|
||||
KEY_TIMESTAMP + " INTEGER NOT NULL, " +
|
||||
KEY_KIND + " TEXT NOT NULL, " +
|
||||
KEY_SEGMENTS + " TEXT, " +
|
||||
" UNIQUE(" + KEY_TIMESTAMP + ", " + KEY_PATH + "));";
|
||||
|
||||
|
||||
|
@ -121,6 +124,11 @@ public class FinishedMissionStore extends SQLiteOpenHelper {
|
|||
|
||||
cursor.close();
|
||||
db.execSQL("DROP TABLE " + MISSIONS_TABLE_NAME_v2);
|
||||
oldVersion++;
|
||||
}
|
||||
|
||||
if (oldVersion == 4) {
|
||||
db.execSQL("ALTER TABLE " + FINISHED_TABLE_NAME + " ADD COLUMN " + KEY_SEGMENTS + " TEXT;");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,6 +145,7 @@ public class FinishedMissionStore extends SQLiteOpenHelper {
|
|||
values.put(KEY_DONE, downloadMission.length);
|
||||
values.put(KEY_TIMESTAMP, downloadMission.timestamp);
|
||||
values.put(KEY_KIND, String.valueOf(downloadMission.kind));
|
||||
values.put(KEY_SEGMENTS, downloadMission.segmentsJson);
|
||||
return values;
|
||||
}
|
||||
|
||||
|
@ -152,6 +161,7 @@ public class FinishedMissionStore extends SQLiteOpenHelper {
|
|||
mission.length = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_DONE));
|
||||
mission.timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(KEY_TIMESTAMP));
|
||||
mission.kind = kind.charAt(0);
|
||||
mission.segmentsJson = cursor.getString(cursor.getColumnIndexOrThrow(KEY_SEGMENTS));
|
||||
|
||||
try {
|
||||
mission.storage = new StoredFileHelper(context,null, Uri.parse(path), "");
|
||||
|
|
|
@ -37,6 +37,9 @@ import androidx.core.app.ServiceCompat;
|
|||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.grack.nanojson.JsonStringWriter;
|
||||
import com.grack.nanojson.JsonWriter;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.download.DownloadActivity;
|
||||
import org.schabi.newpipe.player.helper.LockManager;
|
||||
|
@ -44,6 +47,7 @@ import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
|||
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||
import org.schabi.newpipe.util.Localization;
|
||||
import org.schabi.newpipe.util.PendingIntentCompat;
|
||||
import org.schabi.newpipe.util.VideoSegment;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -79,6 +83,7 @@ public class DownloadManagerService extends Service {
|
|||
private static final String EXTRA_PARENT_PATH = "DownloadManagerService.extra.storageParentPath";
|
||||
private static final String EXTRA_STORAGE_TAG = "DownloadManagerService.extra.storageTag";
|
||||
private static final String EXTRA_RECOVERY_INFO = "DownloadManagerService.extra.recoveryInfo";
|
||||
private static final String EXTRA_SEGMENTS = "DownloadManagerService.extra.segments";
|
||||
|
||||
private static final String ACTION_RESET_DOWNLOAD_FINISHED = APPLICATION_ID + ".reset_download_finished";
|
||||
private static final String ACTION_OPEN_DOWNLOADS_FINISHED = APPLICATION_ID + ".open_downloads_finished";
|
||||
|
@ -359,7 +364,8 @@ public class DownloadManagerService extends Service {
|
|||
*/
|
||||
public static void startMission(Context context, String[] urls, StoredFileHelper storage,
|
||||
char kind, int threads, String source, String psName,
|
||||
String[] psArgs, long nearLength, MissionRecoveryInfo[] recoveryInfo) {
|
||||
String[] psArgs, long nearLength, MissionRecoveryInfo[] recoveryInfo,
|
||||
VideoSegment[] segments) {
|
||||
Intent intent = new Intent(context, DownloadManagerService.class);
|
||||
intent.setAction(Intent.ACTION_RUN);
|
||||
intent.putExtra(EXTRA_URLS, urls);
|
||||
|
@ -374,6 +380,7 @@ public class DownloadManagerService extends Service {
|
|||
intent.putExtra(EXTRA_PARENT_PATH, storage.getParentUri());
|
||||
intent.putExtra(EXTRA_PATH, storage.getUri());
|
||||
intent.putExtra(EXTRA_STORAGE_TAG, storage.getTag());
|
||||
intent.putExtra(EXTRA_SEGMENTS, segments);
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
@ -390,6 +397,7 @@ public class DownloadManagerService extends Service {
|
|||
long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0);
|
||||
String tag = intent.getStringExtra(EXTRA_STORAGE_TAG);
|
||||
Parcelable[] parcelRecovery = intent.getParcelableArrayExtra(EXTRA_RECOVERY_INFO);
|
||||
VideoSegment[] segments = (VideoSegment[]) intent.getSerializableExtra(EXTRA_SEGMENTS);
|
||||
|
||||
StoredFileHelper storage;
|
||||
try {
|
||||
|
@ -414,6 +422,25 @@ public class DownloadManagerService extends Service {
|
|||
mission.nearLength = nearLength;
|
||||
mission.recoveryInfo = recovery;
|
||||
|
||||
if (segments != null && segments.length > 0) {
|
||||
try {
|
||||
final JsonStringWriter writer = JsonWriter.string()
|
||||
.object()
|
||||
.array("segments");
|
||||
for (final VideoSegment segment : segments) {
|
||||
writer.object()
|
||||
.value("start", segment.startTime)
|
||||
.value("end", segment.endTime)
|
||||
.value("category", segment.category)
|
||||
.end();
|
||||
}
|
||||
writer.end().end();
|
||||
mission.segmentsJson = writer.done();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (ps != null)
|
||||
ps.setTemporalDir(DownloadManager.pickAvailableTemporalDir(this));
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.annotation.SuppressLint;
|
|||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
|
@ -49,6 +50,7 @@ import androidx.core.app.NotificationCompat;
|
|||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.core.os.HandlerCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||
|
@ -56,7 +58,9 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
|||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.schabi.newpipe.App;
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.LocalPlayerActivity;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.error.ErrorInfo;
|
||||
import org.schabi.newpipe.error.ErrorUtil;
|
||||
|
@ -117,8 +121,12 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
|||
|
||||
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
private SharedPreferences mPrefs;
|
||||
|
||||
public MissionAdapter(Context context, @NonNull DownloadManager downloadManager, View emptyMessage, View root) {
|
||||
mContext = context;
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(App.getApp());
|
||||
|
||||
mDownloadManager = downloadManager;
|
||||
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
|
@ -333,7 +341,25 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
|||
}
|
||||
}
|
||||
|
||||
private void viewWithFileProvider(Mission mission) {
|
||||
private void open(Mission mission) {
|
||||
if (checkInvalidFile(mission)) return;
|
||||
|
||||
String mimeType = resolveMimeType(mission);
|
||||
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.v(TAG, "Mime: " + mimeType + " package: " + BuildConfig.APPLICATION_ID + ".provider");
|
||||
|
||||
Uri uri = resolveShareableUri(mission);
|
||||
|
||||
Intent intent = new Intent(mContext, LocalPlayerActivity.class);
|
||||
intent.setDataAndType(uri, mimeType);
|
||||
intent.putExtra("segments", mission.segmentsJson);
|
||||
intent.setFlags(FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
private void openExternally(Mission mission) {
|
||||
if (checkInvalidFile(mission)) return;
|
||||
|
||||
String mimeType = resolveMimeType(mission);
|
||||
|
@ -673,6 +699,9 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
|||
applyChanges();
|
||||
checkMasterButtonsVisibility();
|
||||
return true;
|
||||
case R.id.open_externally:
|
||||
openExternally(h.item.mission);
|
||||
return true;
|
||||
case R.id.md5:
|
||||
case R.id.sha1:
|
||||
final NotificationManager notificationManager
|
||||
|
@ -889,8 +918,14 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
|||
itemView.setHapticFeedbackEnabled(true);
|
||||
|
||||
itemView.setOnClickListener(v -> {
|
||||
if (item.mission instanceof FinishedMission)
|
||||
viewWithFileProvider(item.mission);
|
||||
if (item.mission instanceof FinishedMission) {
|
||||
if (mPrefs.getBoolean(mContext
|
||||
.getString(R.string.enable_local_player_key), false)) {
|
||||
open(item.mission);
|
||||
} else {
|
||||
openExternally(item.mission);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
itemView.setOnLongClickListener(v -> {
|
||||
|
|
19
app/src/main/res/drawable-night/ic_sponsor_block_disable.xml
Normal file
19
app/src/main/res/drawable-night/ic_sponsor_block_disable.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22.7994C11.55,22.7994 11.1,22.7094 10.74,22.4394 4.89,18.8394 1.29,12.6294 1.2,5.7894 1.2,4.8894 1.65,3.9894 2.46,3.5394 8.4,0.3894 15.6,0.3894 21.54,3.6294 22.35,3.9894 22.8,4.8894 22.8,5.7894 22.71,12.6294 19.11,18.8394 13.35,22.4394 12.9,22.7094 12.45,22.7994 12,22.7994ZM12,1.9194c-3.15,0 -6.3,0.81 -9.18,2.34 -0.54,0.27 -0.9,0.9 -0.9,1.53 0.09,6.57 3.51,12.51 9.18,16.02 0.54,0.36 1.26,0.36 1.8,0C18.57,18.3894 21.9,12.3594 22.08,5.7894 22.08,5.1594 21.72,4.5294 21.18,4.2594 18.3,2.7294 15.15,1.9194 12,1.9194Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.73,4.9794C15.24,2.0994 8.76,2.0994 3.27,4.9794 3,5.1594 2.82,5.4294 2.82,5.7894c0.09,6.48 3.51,12.06 8.73,15.3 0.27,0.18 0.63,0.18 0.9,0 5.13,-3.15 8.64,-8.82 8.73,-15.3C21.18,5.4294 21,5.1594 20.73,4.9794ZM12,15.8694c-2.79,0 -4.95,-2.25 -4.95,-4.95 0,-2.7 2.25,-4.95 4.95,-4.95 2.7,0 4.95,2.25 4.95,4.95 0,2.79 -2.16,4.95 -4.95,4.95z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m15.15,13.4394c0.54,-0.72 0.9,-1.53 0.9,-2.52 0,-2.25 -1.8,-4.05 -4.05,-4.05 -0.9,0 -1.8,0.36 -2.52,0.9z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m8.85,8.4894c-0.54,0.72 -0.9,1.53 -0.9,2.52 0,2.25 1.8,4.05 4.05,4.05 0.9,0 1.8,-0.36 2.52,-0.9z"/>
|
||||
</vector>
|
13
app/src/main/res/drawable-night/ic_sponsor_block_enable.xml
Normal file
13
app/src/main/res/drawable-night/ic_sponsor_block_enable.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22.7994C11.55,22.7994 11.1,22.7094 10.74,22.4394 4.89,18.8394 1.29,12.6294 1.2,5.7894 1.2,4.8894 1.65,3.9894 2.46,3.5394 8.4,0.3894 15.6,0.3894 21.54,3.6294 22.35,3.9894 22.8,4.8894 22.8,5.7894 22.71,12.6294 19.11,18.8394 13.35,22.4394 12.9,22.7094 12.45,22.7994 12,22.7994ZM12,1.9194c-3.15,0 -6.3,0.81 -9.18,2.34 -0.54,0.27 -0.9,0.9 -0.9,1.53 0.09,6.57 3.51,12.51 9.18,16.02 0.54,0.36 1.26,0.36 1.8,0C18.57,18.3894 21.9,12.3594 22.08,5.7894 22.08,5.1594 21.72,4.5294 21.18,4.2594 18.3,2.7294 15.15,1.9194 12,1.9194Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.73,4.9794C15.24,2.0994 8.76,2.0994 3.27,4.9794 3,5.1594 2.82,5.4294 2.82,5.7894c0.09,6.48 3.51,12.06 8.73,15.3 0.27,0.18 0.63,0.18 0.9,0 5.13,-3.15 8.64,-8.82 8.73,-15.3C21.18,5.4294 21,5.1594 20.73,4.9794ZM9.66,15.1494L9.66,6.7794l7.29,4.23z"/>
|
||||
</vector>
|
13
app/src/main/res/drawable-night/ic_sponsor_block_exclude.xml
Normal file
13
app/src/main/res/drawable-night/ic_sponsor_block_exclude.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22.7994C11.55,22.7994 11.1,22.7094 10.74,22.4394 4.89,18.8394 1.29,12.6294 1.2,5.7894 1.2,4.8894 1.65,3.9894 2.46,3.5394 8.4,0.3894 15.6,0.3894 21.54,3.6294 22.35,3.9894 22.8,4.8894 22.8,5.7894 22.71,12.6294 19.11,18.8394 13.35,22.4394 12.9,22.7094 12.45,22.7994 12,22.7994ZM12,1.9194c-3.15,0 -6.3,0.81 -9.18,2.34 -0.54,0.27 -0.9,0.9 -0.9,1.53 0.09,6.57 3.51,12.51 9.18,16.02 0.54,0.36 1.26,0.36 1.8,0C18.57,18.3894 21.9,12.3594 22.08,5.7894 22.08,5.1594 21.72,4.5294 21.18,4.2594 18.3,2.7294 15.15,1.9194 12,1.9194Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.73,4.9794C15.24,2.0994 8.76,2.0994 3.27,4.9794 3,5.1594 2.82,5.4294 2.82,5.7894c0.09,6.48 3.51,12.06 8.73,15.3 0.27,0.18 0.63,0.18 0.9,0 5.13,-3.15 8.64,-8.82 8.73,-15.3C21.18,5.4294 21,5.1594 20.73,4.9794ZM12,15.4194c0,0 -4.5,-3.6 -4.5,-5.94 0,-1.53 0.99,-2.43 2.25,-2.43 1.08,0 2.25,1.17 2.25,1.17 0,0 1.08,-1.17 2.25,-1.17 1.26,0 2.25,0.81 2.25,2.43 0,2.34 -4.5,5.94 -4.5,5.94z"/>
|
||||
</vector>
|
18
app/src/main/res/drawable/ic_sponsor_block_disable.xml
Normal file
18
app/src/main/res/drawable/ic_sponsor_block_disable.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22.7994C11.55,22.7994 11.1,22.7094 10.74,22.4394 4.89,18.8394 1.29,12.6294 1.2,5.7894 1.2,4.8894 1.65,3.9894 2.46,3.5394 8.4,0.3894 15.6,0.3894 21.54,3.6294 22.35,3.9894 22.8,4.8894 22.8,5.7894 22.71,12.6294 19.11,18.8394 13.35,22.4394 12.9,22.7094 12.45,22.7994 12,22.7994ZM12,1.9194c-3.15,0 -6.3,0.81 -9.18,2.34 -0.54,0.27 -0.9,0.9 -0.9,1.53 0.09,6.57 3.51,12.51 9.18,16.02 0.54,0.36 1.26,0.36 1.8,0C18.57,18.3894 21.9,12.3594 22.08,5.7894 22.08,5.1594 21.72,4.5294 21.18,4.2594 18.3,2.7294 15.15,1.9194 12,1.9194Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.73,4.9794C15.24,2.0994 8.76,2.0994 3.27,4.9794 3,5.1594 2.82,5.4294 2.82,5.7894c0.09,6.48 3.51,12.06 8.73,15.3 0.27,0.18 0.63,0.18 0.9,0 5.13,-3.15 8.64,-8.82 8.73,-15.3C21.18,5.4294 21,5.1594 20.73,4.9794ZM12,15.8694c-2.79,0 -4.95,-2.25 -4.95,-4.95 0,-2.7 2.25,-4.95 4.95,-4.95 2.7,0 4.95,2.25 4.95,4.95 0,2.79 -2.16,4.95 -4.95,4.95z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m15.15,13.4394c0.54,-0.72 0.9,-1.53 0.9,-2.52 0,-2.25 -1.8,-4.05 -4.05,-4.05 -0.9,0 -1.8,0.36 -2.52,0.9z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m8.85,8.4894c-0.54,0.72 -0.9,1.53 -0.9,2.52 0,2.25 1.8,4.05 4.05,4.05 0.9,0 1.8,-0.36 2.52,-0.9z"/>
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_sponsor_block_enable.xml
Normal file
12
app/src/main/res/drawable/ic_sponsor_block_enable.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22.7994C11.55,22.7994 11.1,22.7094 10.74,22.4394 4.89,18.8394 1.29,12.6294 1.2,5.7894 1.2,4.8894 1.65,3.9894 2.46,3.5394 8.4,0.3894 15.6,0.3894 21.54,3.6294 22.35,3.9894 22.8,4.8894 22.8,5.7894 22.71,12.6294 19.11,18.8394 13.35,22.4394 12.9,22.7094 12.45,22.7994 12,22.7994ZM12,1.9194c-3.15,0 -6.3,0.81 -9.18,2.34 -0.54,0.27 -0.9,0.9 -0.9,1.53 0.09,6.57 3.51,12.51 9.18,16.02 0.54,0.36 1.26,0.36 1.8,0C18.57,18.3894 21.9,12.3594 22.08,5.7894 22.08,5.1594 21.72,4.5294 21.18,4.2594 18.3,2.7294 15.15,1.9194 12,1.9194Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.73,4.9794C15.24,2.0994 8.76,2.0994 3.27,4.9794 3,5.1594 2.82,5.4294 2.82,5.7894c0.09,6.48 3.51,12.06 8.73,15.3 0.27,0.18 0.63,0.18 0.9,0 5.13,-3.15 8.64,-8.82 8.73,-15.3C21.18,5.4294 21,5.1594 20.73,4.9794ZM9.66,15.1494L9.66,6.7794l7.29,4.23z"/>
|
||||
</vector>
|
12
app/src/main/res/drawable/ic_sponsor_block_exclude.xml
Normal file
12
app/src/main/res/drawable/ic_sponsor_block_exclude.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22.7994C11.55,22.7994 11.1,22.7094 10.74,22.4394 4.89,18.8394 1.29,12.6294 1.2,5.7894 1.2,4.8894 1.65,3.9894 2.46,3.5394 8.4,0.3894 15.6,0.3894 21.54,3.6294 22.35,3.9894 22.8,4.8894 22.8,5.7894 22.71,12.6294 19.11,18.8394 13.35,22.4394 12.9,22.7094 12.45,22.7994 12,22.7994ZM12,1.9194c-3.15,0 -6.3,0.81 -9.18,2.34 -0.54,0.27 -0.9,0.9 -0.9,1.53 0.09,6.57 3.51,12.51 9.18,16.02 0.54,0.36 1.26,0.36 1.8,0C18.57,18.3894 21.9,12.3594 22.08,5.7894 22.08,5.1594 21.72,4.5294 21.18,4.2594 18.3,2.7294 15.15,1.9194 12,1.9194Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.73,4.9794C15.24,2.0994 8.76,2.0994 3.27,4.9794 3,5.1594 2.82,5.4294 2.82,5.7894c0.09,6.48 3.51,12.06 8.73,15.3 0.27,0.18 0.63,0.18 0.9,0 5.13,-3.15 8.64,-8.82 8.73,-15.3C21.18,5.4294 21,5.1594 20.73,4.9794ZM12,15.4194c0,0 -4.5,-3.6 -4.5,-5.94 0,-1.53 0.99,-2.43 2.25,-2.43 1.08,0 2.25,1.17 2.25,1.17 0,0 1.08,-1.17 2.25,-1.17 1.26,0 2.25,0.81 2.25,2.43 0,2.34 -4.5,5.94 -4.5,5.94z"/>
|
||||
</vector>
|
|
@ -280,7 +280,7 @@
|
|||
tools:ignore="HardcodedText"
|
||||
tools:text="1:06:29" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSeekBar
|
||||
<org.schabi.newpipe.views.FocusAwareSeekBar
|
||||
android:id="@+id/seek_bar"
|
||||
style="@style/Widget.AppCompat.SeekBar"
|
||||
android:layout_width="0dp"
|
||||
|
|
16
app/src/main/res/layout/activity_local_player.xml
Normal file
16
app/src/main/res/layout/activity_local_player.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black"
|
||||
tools:context=".LocalPlayerActivity">
|
||||
|
||||
<com.google.android.exoplayer2.ui.PlayerView
|
||||
android:id="@+id/player_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:show_buffering="when_playing"
|
||||
app:show_shuffle_button="true" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -116,7 +116,7 @@
|
|||
tools:text="1:06:29" />
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSeekBar
|
||||
<org.schabi.newpipe.views.FocusAwareSeekBar
|
||||
android:id="@+id/seek_bar"
|
||||
style="@style/Widget.AppCompat.SeekBar"
|
||||
android:layout_width="0dp"
|
||||
|
|
33
app/src/main/res/layout/dialog_sponsor_block_api_url.xml
Normal file
33
app/src/main/res/layout/dialog_sponsor_block_api_url.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:clickable="false"
|
||||
android:paddingLeft="@dimen/video_item_search_padding"
|
||||
android:paddingRight="@dimen/video_item_search_padding"
|
||||
android:paddingTop="@dimen/video_item_search_padding">
|
||||
<EditText
|
||||
android:id="@+id/api_url_edit"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_weight="1"
|
||||
android:saveEnabled="true"
|
||||
android:inputType="textUri"
|
||||
android:maxLines="1"
|
||||
android:importantForAutofill="no"
|
||||
android:hint="https://domain.com/api/"/>
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/icon_api_url_help"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:srcCompat="@drawable/ic_help"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:tint="?attr/colorAccent"/>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:clickable="false"
|
||||
android:paddingLeft="@dimen/video_item_search_padding"
|
||||
android:paddingRight="@dimen/video_item_search_padding"
|
||||
android:paddingTop="@dimen/video_item_search_padding">
|
||||
<TextView
|
||||
android:id="@+id/api_url_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="@string/sponsor_block_api_url_help_text"/>
|
||||
<Button
|
||||
android:id="@+id/sponsor_block_privacy_policy_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/sponsor_block_privacy_policy_text"/>
|
||||
</LinearLayout>
|
|
@ -332,6 +332,7 @@
|
|||
android:id="@+id/switchMute"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="37dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/mute"
|
||||
|
@ -342,6 +343,20 @@
|
|||
app:tint="@color/white"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/switchSponsorBlocking"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/sponsor_block_toggle_skipping"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/player_main_buttons_padding"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_sponsor_block_enable"
|
||||
app:tint="@color/white"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/fullScreenButton"
|
||||
android:layout_width="40dp"
|
||||
|
|
6
app/src/main/res/layout/preference_edit_color.xml
Normal file
6
app/src/main/res/layout/preference_edit_color.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<View xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/segment_color_view"
|
||||
android:layout_width="98dp"
|
||||
android:layout_height="6dp"
|
||||
android:background="@color/black"/>
|
|
@ -29,6 +29,10 @@
|
|||
android:id="@+id/delete"
|
||||
android:title="@string/delete" />
|
||||
|
||||
<item
|
||||
android:id="@+id/open_externally"
|
||||
android:title="@string/open_with" />
|
||||
|
||||
<item
|
||||
android:id="@+id/error_message_view"
|
||||
android:title="@string/show_error" />
|
||||
|
|
|
@ -692,7 +692,7 @@
|
|||
<string name="show_error_snackbar">Mostrar una barra de error</string>
|
||||
<string name="no_appropriate_file_manager_message">No se ha encontrado un gestor de archivos apropiado para esta acción.
|
||||
\nPor favor, instale un gestor de archivos o intente desactivar \'%s\' en los ajustes de la descarga</string>
|
||||
<string name="no_appropriate_file_manager_message_android_10">No se encontró ningún administrador de archivos apropiado para esta acción.
|
||||
<string name="no_appropriate_file_manager_message_android_10">No se encontró ningún administrador de archivos apropiado para esta acción.
|
||||
\n Instale un administrador de archivos compatible con Storage Access Framework</string>
|
||||
<string name="detail_pinned_comment_view_description">Comentario fijado</string>
|
||||
<string name="leak_canary_not_available">LeakCanary no está disponible</string>
|
||||
|
@ -702,6 +702,24 @@
|
|||
<string name="streams_notification_channel_name">Nuevos streams</string>
|
||||
<string name="settings_category_player_notification_title">Notificación del reproductor</string>
|
||||
<string name="settings_category_player_notification_summary">Configurar notificación de la reproducción en curso</string>
|
||||
<string name="settings_category_sponsor_block_title">SponsorBlock (Beta, Servicio de Terceros)</string>
|
||||
<string name="settings_category_sponsor_block_categories_title">Categorías de SponsorBlock</string>
|
||||
<string name="settings_category_sponsor_block_categories_summary">Personaliza qué segmentos de video saltar, junto con sus marcas de color en la barra de búsqueda.</string>
|
||||
<string name="settings_category_sponsor_block_categories_reset_colors_title">Restablecer Colores</string>
|
||||
<string name="settings_category_sponsor_block_category_enable_title">Activar</string>
|
||||
<string name="settings_category_sponsor_block_category_color">Color en la Barra de Búsqueda</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_title">Sponsor</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_summary">Promoción pagada, recomendaciones pagadas y anuncios directos. No para promoción propia o anuncios gratuitos a causas/creadores/sitios web/productos que les gusten.</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_title">Intermisión/Animación de Introducción</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_summary">Un intervalo sin contenido real. Podría ser una pausa, un cuadro estático, una animación repetida. Esto no debe ser usado para transiciones que contengan información ni utilizarse en videos musicales.</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_title">Tarjetas/Créditos</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_summary">Créditos o cuando aparecen las tarjetas finales de YouTube. No para conclusiones habladas. Esto no debe contener contenido útil. Esto no debe ser usado en videos musicales.</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_title">Recordatorios de Interacción (Suscribir)</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_summary">Cuando hay un breve recordatorio para dar like, suscribirse o seguirlos en medio del contenido. Si es largo o sobre algo específico, debería estar bajo autopromoción en su lugar.</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_title">Promoción Propia/No Remunerada</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_summary">Similar a "sponsor", excepto que para la promoción propia o no remunerada. Esto incluye secciones sobre mercancía, donaciones o información sobre con quiénes colaboraron.</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_title">Música: Sección sin musica</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_summary">Sólo para el uso en vídeos musicales. Esto incluye introducciones u outros en videos musicales.</string>
|
||||
<string name="you_successfully_subscribed">Ahora te has suscrito a este canal</string>
|
||||
<string name="any_network">Cualquier red</string>
|
||||
<string name="enumeration_comma">,</string>
|
||||
|
@ -748,4 +766,50 @@
|
|||
<string name="card">Tarjeta</string>
|
||||
<string name="playlist_add_stream_success_duplicate">Duplicado añadido %d vez/veces</string>
|
||||
<string name="duplicate_in_playlist">Las listas de reproducción que están en gris ya contienen este elemento.</string>
|
||||
</resources>
|
||||
<!-- SponsorBlock -->
|
||||
<string name="sponsor_block">SponsorBlock</string>
|
||||
<string name="sponsor_block_home_page_title">Ver Sitio Web</string>
|
||||
<string name="sponsor_block_home_page_summary">Ver sitio web oficial de SponsorBlock.</string>
|
||||
<string name="sponsor_block_enable_title">Saltar Sponsors</string>
|
||||
<string name="sponsor_block_enable_summary">Usar la API de SponsorBlock para automáticamente saltar los sponsors en los videos. Actualmente esto solo funciona para los videos de YouTube.</string>
|
||||
<string name="sponsor_block_api_url_title">URL de la API</string>
|
||||
<string name="sponsor_block_api_url_summary">La URL a usar al consultar la API de SponsorBlock. Esta debe estar establecida para que SponsorBlock funcione.</string>
|
||||
<string name="sponsor_block_notifications_title">Notificar cuando se saltan los sponsors</string>
|
||||
<string name="sponsor_block_notifications_summary">Mostrar un aviso cuando se salta un sponsor automáticamente.</string>
|
||||
<string name="sponsor_block_privacy_title">Ver Política de Privacidad</string>
|
||||
<string name="sponsor_block_privacy_summary">Ver la política de privacidad de SponsorBlock</string>
|
||||
<string name="sponsor_block_api_url_help_text">Esta es la URL que se consultará cuando la aplicación necesite saber qué partes de un vídeo debe omitir.\n\nPuedes establecer la URL oficial haciendo clic en la opción "Usar oficial" que aparece a continuación, aunque es muy recomendable que veas la política de privacidad de SponsorBlock antes de hacerlo.</string>
|
||||
<string name="sponsor_block_privacy_policy_text">Política de Privacidad de SponsorBlock</string>
|
||||
<string name="sponsor_block_homepage_url">https://sponsor.ajay.app/</string>
|
||||
<string name="sponsor_block_default_api_url">https://sponsor.ajay.app/api/</string>
|
||||
<string name="sponsor_block_privacy_policy_url">https://gist.github.com/ajayyy/aa9f8ded2b573d4f73a3ffa0ef74f796</string>
|
||||
<string name="sponsor_block_skip_sponsor_toast">Sponsor Omitido</string>
|
||||
<string name="sponsor_block_skip_intro_toast">Intermisión/Introducción Omitida</string>
|
||||
<string name="sponsor_block_skip_outro_toast">Tarjetas/Créditos Omitidos</string>
|
||||
<string name="sponsor_block_skip_interaction_toast">Recordatorio de Interacción Omitido</string>
|
||||
<string name="sponsor_block_skip_self_promo_toast">Promoción Propia/No Remunerada Omitida</string>
|
||||
<string name="sponsor_block_skip_non_music_toast">Sin Música Omitido</string>
|
||||
<string name="sponsor_block_toggle_skipping">Alternar omisión de sponsors</string>
|
||||
<string name="sponsor_block_clear_whitelist_title">Borrar la Lista Blanca</string>
|
||||
<string name="sponsor_block_clear_whitelist_summary">Borrar la lista de canales que SponsorBlock ignorará.</string>
|
||||
<string name="sponsor_block_enabled_toast">SponsorBlock activado</string>
|
||||
<string name="sponsor_block_disabled_toast">SponsorBlock desactivado</string>
|
||||
<string name="sponsor_block_whitelist_cleared_toast">Lista blanca borrada</string>
|
||||
<string name="sponsor_block_uploader_added_to_whitelist_toast">Canal añadido a la lista blanca</string>
|
||||
<string name="sponsor_block_uploader_removed_from_whitelist_toast">Canal retirado de la lista blanca</string>
|
||||
<string name="sponsor_block_confirm_clear_whitelist">¿Estás seguro/a de que quieres borrar la lista blanca?</string>
|
||||
<string name="sponsor_block_confirm_reset_colors">¿Estás seguro/a de que quieres restablecer los colores de las categorías?</string>
|
||||
<string name="sponsor_block_reset_colors_toast">Colores restablecidos.</string>
|
||||
<!-- Extras -->
|
||||
<string name="extras">Extras</string>
|
||||
<string name="extras_todo_summary">Los retoques, arreglos y otros ajustes misceláneos pertenecen aquí.</string>
|
||||
<string name="experimental_settings">Ajustes Experimentales</string>
|
||||
<string name="enable_local_player_title">Activar Reproductor Local (alfa)</string>
|
||||
<string name="enable_local_player_summary">Utilizar un reproductor integrado para la reproducción local. Esto todavía está en desarrollo temprano, así que probablemente habrá muchos problemas, incluyendo conflictos con el reproductor existente.</string>
|
||||
<string name="force_auto_fullscreen_title">Forzar Pantalla Completa Automática</string>
|
||||
<string name="force_auto_fullscreen_summary">Si se activa, cuando el dispositivo está en modo horizontal, fuerza el modo de pantalla completa, incluso si el dispositivo es una tableta o un televisor.</string>
|
||||
<string name="disable_error_reports_title">Desactivar el Informe de Errores</string>
|
||||
<string name="disable_error_reports_summary">Evitar que aparezcan todas las pantallas de informe de errores. Esto puede hacer que la aplicación se comporte de forma inesperada. <b>¡UTILÍCELO BAJO SU PROPIO RIESGO!</b></string>
|
||||
<string name="enable_return_youtube_dislike_title">Mostrar Conteo de No Me Gusta</string>
|
||||
<string name="enable_return_youtube_dislike_summary">Utilizar el API de ReturnYouTubeDislike API para mostrar la cantidad de no me gusta de un video. Esto solo funciona con videos de YouTube.\n<b>ADVERTENCIA: Su dirección IP será visible para la API. Utilícelo bajo su propio riesgo.</b></string>
|
||||
</resources>
|
||||
|
|
|
@ -669,6 +669,54 @@
|
|||
\nSilakan pasang pengelola berkas yang kompatibel dengan Storage Access Framework</string>
|
||||
<string name="detail_pinned_comment_view_description">Komentar dipin</string>
|
||||
<string name="leak_canary_not_available">LeakCanary tidak tersedia</string>
|
||||
<!-- SponsorBlock -->
|
||||
<string name="sponsor_block">SponsorBlock</string>
|
||||
<string name="sponsor_block_home_page_title">Lihat Situs web</string>
|
||||
<string name="sponsor_block_home_page_summary">Lihat situs web Sponsorblock resmi.</string>
|
||||
<string name="sponsor_block_enable_title">Lewati Sponsor</string>
|
||||
<string name="sponsor_block_enable_summary">Gunakan API SponsorBlock untuk melewati sponsor dalam video secara otomatis. Saat ini hanya berfungsi untuk video YouTube.</string>
|
||||
<string name="sponsor_block_api_url_title">Url API</string>
|
||||
<string name="sponsor_block_api_url_summary">URL untuk digunakan saat mengkueri API SponsorBlock. Ini harus ditetapkan untuk SponsorBlock untuk bekerja.</string>
|
||||
<string name="sponsor_block_notifications_title">Beritahu saat sponsor dilewati</string>
|
||||
<string name="sponsor_block_notifications_summary">Tampilkan pemberitahuan toast ketika sponsor dilewati secara otomatis.</string>
|
||||
<string name="sponsor_block_privacy_title">Lihat Kebijakan Privasi</string>
|
||||
<string name="sponsor_block_privacy_summary">Lihat Kebijakan Privasi Sponsorblock.</string>
|
||||
<string name="sponsor_block_api_url_help_text">Ini adalah URL yang akan ditanya ketika aplikasi perlu mengetahui bagian video mana yang akan dilewati.\n\nAnda dapat mengatur URL resmi dengan mengklik opsi \'Gunakan Resmi\' di bawah ini, meskipun sangat disarankan Anda melihat kebijakan privasi SponsorBlock sebelum Anda melakukannya.</string>
|
||||
<string name="sponsor_block_privacy_policy_text">Kebijakan Privasi SponsorBlock</string>
|
||||
<string name="sponsor_block_homepage_url">https://sponsor.ajay.app/</string>
|
||||
<string name="sponsor_block_default_api_url">https://sponsor.ajay.app/api/</string>
|
||||
<string name="sponsor_block_privacy_policy_url">https://gist.github.com/ajayyy/aa9f8ded2b573d4f73a3ffa0ef74f796</string>
|
||||
<string name="sponsor_block_skip_sponsor_toast">Sponsor dilewati</string>
|
||||
<string name="sponsor_block_skip_intro_toast">Istirahat/intro Dilewati</string>
|
||||
<string name="sponsor_block_skip_outro_toast">Kartu akhir/kredit Dilewati</string>
|
||||
<string name="sponsor_block_skip_interaction_toast">Pengingat interaksi Dilewati</string>
|
||||
<string name="sponsor_block_skip_self_promo_toast">Promosi tidak dibayar/diri sendiri Dilewati</string>
|
||||
<string name="sponsor_block_skip_non_music_toast">Non-musik Dilewati</string>
|
||||
<string name="sponsor_block_skip_filler_toast">Filler Dilewati</string>
|
||||
<string name="sponsor_block_toggle_skipping">Toggle lewati sponsor</string>
|
||||
<string name="sponsor_block_clear_whitelist_title">Bersihkan daftar putih</string>
|
||||
<string name="sponsor_block_clear_whitelist_summary">Bersihkan daftar pengunggah SponsorBlock akan abaikan.</string>
|
||||
<string name="sponsor_block_enabled_toast">SponsorBlock diaktifkan</string>
|
||||
<string name="sponsor_block_disabled_toast">SponsorBlock dimatikan</string>
|
||||
<string name="sponsor_block_whitelist_cleared_toast">Daftar putih dibersihkan</string>
|
||||
<string name="sponsor_block_uploader_added_to_whitelist_toast">pengunggah ditambahkan ke daftar putih</string>
|
||||
<string name="sponsor_block_uploader_removed_from_whitelist_toast">pengunggah dihapus dari daftar putih</string>
|
||||
<string name="sponsor_block_confirm_clear_whitelist">Apakah Anda yakin ingin membersihkan daftar putih?</string>
|
||||
<string name="sponsor_block_confirm_reset_colors">Apakah Anda yakin ingin mengatur ulang kategori warna?</string>
|
||||
<string name="sponsor_block_reset_colors_toast">Warna diatur ulang.</string>
|
||||
<!-- Extras -->
|
||||
<string name="extras">Extras</string>
|
||||
<string name="extras_todo_summary">Tweak, solusi, dan pengaturan lain-lain lainnya berada di sini.</string>
|
||||
<string name="experimental_settings">Pengaturan Experimental</string>
|
||||
<string name="enable_local_player_title">Aktifkan Pemutar Lokal (alpha)</string>
|
||||
<string name="enable_local_player_summary">Gunakan pemutar bawaan untuk pemutaran lokal. Ini masih dalam perkembangan awal sehingga mungkin akan ada banyak masalah, termasuk konflik dengan pemutar yang ada.</string>
|
||||
<string name="force_auto_fullscreen_title">Paksa Fullscreen Otomatis</string>
|
||||
<string name="force_auto_fullscreen_summary">Jika diaktifkan, ketika perangkat diatur ke lanskap, paksa mode layar penuh bahkan jika perangkat adalah tablet atau TV.</string>
|
||||
<string name="disable_error_reports_title">Matikan Pelaporan Error</string>
|
||||
<string name="disable_error_reports_summary">Cegah semua layar pelaporan kesalahan dari muncul. Ini dapat mengakibatkan aplikasi berperilaku tak terduga.<b>GUNAKAN DENGAN RISIKO ANDA SENDIRI!</b></string>
|
||||
<string name="enable_return_youtube_dislike_title">Tampilkan Jumlah Dislike</string>
|
||||
<string name="enable_return_youtube_dislike_summary">Gunakan API ReturnYouTubeDislike untuk menampilkan jumlah dislike untuk video. Ini hanya bekerja untuk video YouTube.\n<b>PERHATIAN: Alamat IP Anda akan terlihat oleh API. Gunakan dengan risiko Anda sendiri!</b></string>
|
||||
<string name="playback_tempo_step">Langkah tempo</string>
|
||||
<string name="progressive_load_interval_exoplayer_default">Default ExoPlayer</string>
|
||||
<string name="progressive_load_interval_summary">Ubah ukuran interval pemuatan (saat ini %s). Nilai yang rendah mungkin dapat membuat pemuatan video awal lebih cepat. Perubahan membutuhkan pemutar dimulai ulang</string>
|
||||
<string name="loading_stream_details">Memuat detail stream…</string>
|
||||
|
|
|
@ -693,6 +693,66 @@
|
|||
\nInstallane uno compatibile con Storage Access Framework</string>
|
||||
<string name="detail_pinned_comment_view_description">Commento in primo piano</string>
|
||||
<string name="leak_canary_not_available">LeakCanary non è disponibile</string>
|
||||
<string name="settings_category_sponsor_block_title">SponsorBlock (in beta, servizio offerto da terzi)</string>
|
||||
<string name="settings_category_sponsor_block_categories_title">Categorie SponsorBlock</string>
|
||||
<string name="settings_category_sponsor_block_categories_summary">Scegli qualii segmenti video saltare, ed il loro colore sulla barra di avanzamento.</string>
|
||||
<string name="settings_category_sponsor_block_categories_reset_colors_title">Ripristina colori predefiniti</string>
|
||||
<string name="sponsor_block_home_page_title">Visita il sito web</string>
|
||||
<string name="sponsor_block_home_page_summary">Visita il sito ufficiale di SponsorBlock.</string>
|
||||
<string name="sponsor_block_enable_title">Salta gli sponsor</string>
|
||||
<string name="sponsor_block_enable_summary">Usa l\'API di SponsorBlock per saltare automaticamente gli sponsor nei video. Funziona solo nei video su YouTube.</string>
|
||||
<string name="sponsor_block_api_url_title">Url API</string>
|
||||
<string name="sponsor_block_api_url_summary">L\'url da usare quando viene interrogata l\'API di SponsorBlock. Deve essere impostata affinché SponsorBlock funzioni.</string>
|
||||
<string name="sponsor_block_notifications_title">Avvisa quando gli sponsor vengono saltati</string>
|
||||
<string name="sponsor_block_notifications_summary">Mostra una notifica toast quando uno sponsor viene saltato automaticamente.</string>
|
||||
<string name="sponsor_block_privacy_title">Visualizza la privacy policy</string>
|
||||
<string name="sponsor_block_privacy_summary">Visualizza la privacy policy di SponsorBlock.</string>
|
||||
<string name="sponsor_block_api_url_help_text">Questa è l\'URL che verrà interrogata quando l\'applicazione avrà bisogno di sapere quali pezzi di video saltare. Puoi scegliere l\'URL ufficiale cliccando \'Use Official\' qui sotto, anche se dovresti leggere la privacy policy di SponsorBlock prima di farlo.</string>
|
||||
<string name="sponsor_block_privacy_policy_text">Privacy policy di SponsorBlock</string>
|
||||
<string name="sponsor_block_skip_sponsor_toast">Saltato sponsor</string>
|
||||
<string name="sponsor_block_skip_intro_toast">Saltato interruzione/introduzione</string>
|
||||
<string name="sponsor_block_skip_outro_toast">Saltato conclusioni/titoli di coda</string>
|
||||
<string name="sponsor_block_skip_interaction_toast">Saltato promemoria d\'interazione</string>
|
||||
<string name="sponsor_block_skip_self_promo_toast">Saltato promozione non pagata/autopromozione</string>
|
||||
<string name="sponsor_block_skip_non_music_toast">Saltato sezione non musicale</string>
|
||||
<string name="sponsor_block_toggle_skipping">Abilita/disabilita salto sponsor</string>
|
||||
<string name="sponsor_block_clear_whitelist_title">Svuota lista bianca</string>
|
||||
<string name="sponsor_block_clear_whitelist_summary">Svuota la lista dei canali ignorati da SponsorBlock.</string>
|
||||
<string name="sponsor_block_enabled_toast">SponsorBlock abilitato</string>
|
||||
<string name="sponsor_block_disabled_toast">SponsorBlock disabilitato</string>
|
||||
<string name="sponsor_block_whitelist_cleared_toast">Lista bianca cancellata</string>
|
||||
<string name="sponsor_block_uploader_added_to_whitelist_toast">Canale aggiunto alla lista bianca</string>
|
||||
<string name="sponsor_block_uploader_removed_from_whitelist_toast">Canale rimosso dalla lista bianca</string>
|
||||
<string name="sponsor_block_confirm_clear_whitelist">Sicuro di voler cancellare la lista bianca?</string>
|
||||
<string name="sponsor_block_confirm_reset_colors">Sicuro di voler ripristinare i colori predefiniti delle categorie?</string>
|
||||
<string name="sponsor_block_reset_colors_toast">Colori ripristinati.</string>
|
||||
<string name="extras">Extra</string>
|
||||
<string name="extras_todo_summary">Ritocchi, soluzioni alternative e impostazioni varie vanno qui.</string>
|
||||
<string name="experimental_settings">Impostazioni sperimentali</string>
|
||||
<string name="enable_local_player_title">Abilita lettore locale (alfa)</string>
|
||||
<string name="enable_local_player_summary">Usa un lettore incluso nell\'app per la riproduzione di contenuti sul tuo dispositivo. Questa funzione è ancora in sviluppo, quindi potrebbero esserci diversi problemi, inclusi conflitti con il lettore esistente.</string>
|
||||
<string name="force_auto_fullscreen_title">Forza schermo intero automatico</string>
|
||||
<string name="force_auto_fullscreen_summary">Se abilitato, quando il dispositivo è in orizzontale forza la modalità a schermo intero anche se il dispositivo è un tablet o una TV.</string>
|
||||
<string name="disable_error_reports_title">Disabilita segnalazione errori</string>
|
||||
<string name="disable_error_reports_summary">Previene la comparsa delle schermate di errore. Potrebbe provocare malfunzionamenti dell\'app, <b>USA A TUO RISCHIO E PERICOLO!</b></string>
|
||||
<string name="enable_return_youtube_dislike_title">Mostra numero dislike</string>
|
||||
<string name="enable_return_youtube_dislike_summary">Usa l\'API di ReturnYouTubeDislike per mostrare il numero di dislike dei video. Funziona solo nei video di YouTube. <b>ATTENZIONE: Il tuo indirizzo IP sarà visibile all\'API. Usa a tuo rischio e pericolo!</b></string>
|
||||
<string name="settings_category_sponsor_block_category_enable_title">Abilita</string>
|
||||
<string name="settings_category_sponsor_block_category_color">Colore barra di avanzamento</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_title">Sponsor</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_title">Animazione interruzione/introduzione</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_title">Conclusioni/titoli di coda</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_title">Promemoria d\'interazione (iscrizione)</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_title">Promozione non pagata/autopromozione</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_title">Musica: sezione non-musicale</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_summary">Promozione a pagamento, referral a pagamento e pubblicità diretta. Non per auto-promozione o ringraziamenti gratuiti a cause/creatori/siti web/ prodotti di loro gradimento.</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_summary">Un intervallo senza contenuto effettivo. Potrebbe essere una pausa, una schermata statica, un\'animazione ripetuta. Non dovrebbe essere usato per transizioni contenenti informazioni o nei video musicali.</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_summary">I titoli di coda o quando vengono mostrate annotazioni a fine video su YouTube. Non per conclusioni provviste di informazioni. Non dovrebbe essere usato nei video musicali.</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_summary">Quando nel punto centrale del contenuto è presente un breve promemoria per aggiunta di mi piace, iscrizione o seguito. Se dovesse risultare esteso o riguardare qualcosa di specifico, potrebbe essere un\'autopromozione.</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_summary">Simile alle sponsorizzazioni tranne che per promozioni non pagate o autopromozioni. Ciò include sezioni riguardanti vendita di merce, donazioni o informazioni in merito a collaboratori.</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_summary">Solo per video musicali. Include introduzioni e outro nei video musicali.</string>
|
||||
<string name="later">Più tardi</string>
|
||||
<string name="invalid_color_toast">Colore non valido</string>
|
||||
<string name="progressive_load_interval_exoplayer_default">Predefinito ExoPlayer</string>
|
||||
<string name="progressive_load_interval_summary">Cambia la dimensione dell\'intervallo da caricare (attualmente %s). Un valore basso può velocizzare il caricamento iniziale del video. La modifica richiede il riavvio del lettore</string>
|
||||
<string name="streams_notification_channel_description">Notifiche di nuovi contenuti dalle iscrizioni</string>
|
||||
|
@ -745,4 +805,10 @@
|
|||
<string name="unset_playlist_thumbnail">Disattiva copertina permanente</string>
|
||||
<string name="duplicate_in_playlist">Le playlist in grigio contengono già questo elemento.</string>
|
||||
<string name="playlist_add_stream_success_duplicate">Doppione aggiunto %d volta/e</string>
|
||||
<string name="settings_category_sponsor_block_category_filler_title">Riempitivi irrilevanti/battute</string>
|
||||
<string name="settings_category_sponsor_block_category_filler_summary">Le scene riempitive sono aggiunte solo per riempire o per umorismo e non sono richieste per comprendere il contenuto principale del video.</string>
|
||||
<string name="settings_category_sponsor_block_category_preview_title">Anteprima/riepilogo</string>
|
||||
<string name="settings_category_sponsor_block_category_preview_summary">Riepilogo rapido degli episodi precedenti, o un\'anteprima di ciò che sta arrivando più tardi nel video attuale. Inteso per segmenti video, non per riassunti a voce.</string>
|
||||
<string name="sponsor_block_skip_preview_toast">Saltato anteprima/riepilogo</string>
|
||||
<string name="sponsor_block_skip_filler_toast">Saltato riempitivo</string>
|
||||
</resources>
|
|
@ -718,6 +718,75 @@
|
|||
<string name="streams_notifications_network_title">Conexão de rede necessária</string>
|
||||
<string name="notifications_disabled">As notificações estão desativadas</string>
|
||||
<string name="get_notified">Seja notificado</string>
|
||||
<string name="settings_category_sponsor_block_title">SponsorBlock (Em beta, serviço de terceiro)</string>
|
||||
<string name="settings_category_sponsor_block_categories_title">Categorias do SponsorBlock</string>
|
||||
<string name="settings_category_sponsor_block_categories_summary">Personalize quais segmentos de vídeo pular, junto com suas marcações de cores na barra.</string>
|
||||
<string name="settings_category_sponsor_block_categories_reset_colors_title">Redefinir cores</string>
|
||||
<string name="settings_category_sponsor_block_category_enable_title">Ativar</string>
|
||||
<string name="settings_category_sponsor_block_category_disabled_title">Desativar</string>
|
||||
<string name="settings_category_sponsor_block_category_color">Cor da barra</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_title">Patrocinador</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_summary">Promoção paga, referências pagas e anúncios diretos. Não é usado em auto promoção ou mensagens grátis para causas/criadores/sites/produtos que eles gostam.</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_title">Intervalo/Animação de introdução</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_summary">Um intervalo sem conteúdo real. Pode ser uma pausa, um quadro estático, uma animação repetitiva. Isso não é usado em transições que contém informação.</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_title">Finalização/Créditos</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_summary">Créditos ou quando os cards finais do YouTube aparecem. Não é usado em conclusões informativas.</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_title">Lembrete de interação (inscrever-se)</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_summary">Quando houver um pequeno lembrete para curtir, inscrever-se ou segui-los no meio do conteúdo. Se for longo ou sobre algo específico, deve estar em autopromoção.</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_title">Não-pago/Auto promoção</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_summary">Similar a "patrocinador", mas para auto promoções e segmentos não-pagos. Isso inclui seções sobre vendas, doações ou informações sobre com quem colaboraram.</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_title">Música: Seção sem música</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_summary">Somente para uso em vídeos de música. Isso inclui introduções ou encerramentos em videoclipes.</string>
|
||||
<string name="settings_category_sponsor_block_category_filler_title">Enrolação/Piadas</string>
|
||||
<string name="settings_category_sponsor_block_category_filler_summary">Cenas tangenciais inseridas apenas por enrolação ou humor que não são necessárias para compreender o tópico principal do vídeo.</string>
|
||||
<string name="settings_category_sponsor_block_category_preview_title">Pré-visualização/Recapitulação</string>
|
||||
<string name="settings_category_sponsor_block_category_preview_summary">Recapitulação rápida de episódios anteriores, ou uma prévia do que está chegando mais tarde no vídeo atual. Destinado a clipes editados juntos, não é para resumos falados.</string>
|
||||
<string name="sponsor_block">SponsorBlock</string>
|
||||
<string name="sponsor_block_home_page_title">Visitar site</string>
|
||||
<string name="sponsor_block_home_page_summary">Visite o site oficial do SponsorBlock.</string>
|
||||
<string name="sponsor_block_enable_title">Pular patrocinadores</string>
|
||||
<string name="sponsor_block_enable_summary">Use a API SponsorBlock para pular automaticamente os patrocinadores nos vídeos. Atualmente, isso só funciona para vídeos do YouTube.</string>
|
||||
<string name="sponsor_block_api_url_title">URL da API</string>
|
||||
<string name="sponsor_block_api_url_summary">A URL a ser usado ao consultar a API do SponsorBlock. Isso deve ser definido para que SponsorBlock funcione.</string>
|
||||
<string name="sponsor_block_notifications_title">Notificar quando os patrocinadores forem ignorados</string>
|
||||
<string name="sponsor_block_notifications_summary">Mostre uma notificação de brinde quando um patrocinador for ignorado automaticamente.</string>
|
||||
<string name="sponsor_block_privacy_title">Ver política de privacidade</string>
|
||||
<string name="sponsor_block_privacy_summary">Veja a política de privacidade do SponsorBlock.</string>
|
||||
<string name="sponsor_block_api_url_help_text">Este é o URL que será consultado quando o aplicativo precisar saber quais partes de um vídeo devem ser ignoradas.\n\nVocê pode definir o URL oficial clicando na opção \'Usar oficial\' abaixo, embora seja altamente recomendável que você veja a política de privacidade do SponsorBlock antes de usá-lo.</string>
|
||||
<string name="sponsor_block_privacy_policy_text">Política de privacidade do SponsorBlock</string>
|
||||
<string name="sponsor_block_homepage_url">https://sponsor.ajay.app/</string>
|
||||
<string name="sponsor_block_default_api_url">https://sponsor.ajay.app/api/</string>
|
||||
<string name="sponsor_block_privacy_policy_url">https://gist.github.com/ajayyy/aa9f8ded2b573d4f73a3ffa0ef74f796</string>
|
||||
<string name="sponsor_block_skip_sponsor_toast">Patrocinador ignorado</string>
|
||||
<string name="sponsor_block_skip_intro_toast">Intervalo/Introdução ignorado</string>
|
||||
<string name="sponsor_block_skip_outro_toast">Finalização/Créditos ignorado</string>
|
||||
<string name="sponsor_block_skip_interaction_toast">Lembrete de inscrição ignorado</string>
|
||||
<string name="sponsor_block_skip_self_promo_toast">Não-pago/Auto promoção ignorado</string>
|
||||
<string name="sponsor_block_skip_non_music_toast">Sem música ignorado</string>
|
||||
<string name="sponsor_block_skip_filler_toast">Enrolação/Piadas ignorado</string>
|
||||
<string name="sponsor_block_skip_preview_toast">Pré-visualização/Recapitulação ignorado</string>
|
||||
<string name="sponsor_block_toggle_skipping">Alternar patrocinadores</string>
|
||||
<string name="sponsor_block_clear_whitelist_title">Limpar lista de canais permitidos</string>
|
||||
<string name="sponsor_block_clear_whitelist_summary">Limpe a lista de canais que o SponsorBlock irá ignorar.</string>
|
||||
<string name="sponsor_block_enabled_toast">SponsorBlock habilitando</string>
|
||||
<string name="sponsor_block_disabled_toast">SponsorBlock desabilitado</string>
|
||||
<string name="sponsor_block_whitelist_cleared_toast">A lista de canais permitidos foi limpa.</string>
|
||||
<string name="sponsor_block_uploader_added_to_whitelist_toast">Canal adicionado à lista de canais permitidos</string>
|
||||
<string name="sponsor_block_uploader_removed_from_whitelist_toast">Canal removido da lista de canais permitidos</string>
|
||||
<string name="sponsor_block_confirm_clear_whitelist">Tem certeza de que deseja excluir a lista de canais permitidos?</string>
|
||||
<string name="sponsor_block_confirm_reset_colors">Tem certeza de que deseja redefinir as cores das categorias?</string>
|
||||
<string name="sponsor_block_reset_colors_toast">Cores redefinidas.</string>
|
||||
<string name="extras">Extras</string>
|
||||
<string name="extras_todo_summary">Ajustes, correções e outros ajustes diversos pertencem aqui.</string>
|
||||
<string name="experimental_settings">Configurações experimentais</string>
|
||||
<string name="enable_local_player_title">Ativar player local (alfa)</string>
|
||||
<string name="enable_local_player_summary">Use um player embutido para reprodução local. Isso ainda está em desenvolvimento inicial, então provavelmente haverá muitos problemas, incluindo conflitos com o player existente</string>
|
||||
<string name="force_auto_fullscreen_title">Forçar tela cheia automaticamente</string>
|
||||
<string name="force_auto_fullscreen_summary">Se ativado, quando o dispositivo estiver no modo paisagem, força o modo de tela cheia mesmo se o dispositivo for um tablet ou TV.</string>
|
||||
<string name="disable_error_reports_title">Desativar relatório de erros</string>
|
||||
<string name="disable_error_reports_summary">Impede que todas as telas de relatório de erros apareçam. Isso pode fazer com que o aplicativo se comporte inesperadamente. <b>USE POR SUA CONTA E RISCO!</b></string>
|
||||
<string name="enable_return_youtube_dislike_title">Mostrar contagem de não gostei</string>
|
||||
<string name="enable_return_youtube_dislike_summary">Utiliza a API ReturnYouTubeDislike para exibir o número de não gostei de um vídeo. Isso só funciona com vídeos do YouTube.\n<b>AVISO: seu endereço IP ficará visível para a API. Use por sua conta e risco.</b></string>
|
||||
<string name="percent">Por cento</string>
|
||||
<string name="semitone">Semitom</string>
|
||||
<string name="selected_stream_external_player_not_supported">A transmissão selecionada não é compatível com players externos</string>
|
||||
|
|
|
@ -649,4 +649,42 @@
|
|||
<string name="local_search_suggestions">Soojeedinada raadinta gudaha</string>
|
||||
<string name="progressive_load_interval_title">Cabirka soodaarida udhexeeya</string>
|
||||
<string name="crash_the_player">Jabi Daareha</string>
|
||||
<!-- SponsorBlock -->
|
||||
<string name="sponsor_block">SponsorBlock</string>
|
||||
<string name="sponsor_block_home_page_title">Fur website-ka</string>
|
||||
<string name="sponsor_block_home_page_summary">Booqo website-ka rasmiga ah ee SponsorBlock.</string>
|
||||
<string name="sponsor_block_enable_title">Ka bood Xaysisiistayaasha</string>
|
||||
<string name="sponsor_block_enable_summary">Isticmaal nidaamka wadashaqaynta [API] SponsorBlock Si uu app-ku si iskii ah oga boodo xayisiisyada ku dhex jira muuqaalada. Nidaamkan hadda wuxuu ku shaqeeyaa muuqaalada YouTube kaliya.</string>
|
||||
<string name="sponsor_block_api_url_title">Tixraaca wadashaqaynta [API]</string>
|
||||
<string name="sponsor_block_api_url_summary">Tixraaca la isticmaali doono marka la hirgalinayo nidaamka wadashaqaynta SponsorBlock. Waa in la fadhiisiyaa tixraacan si uu SponsorBlock u shaqeeyo.</string>
|
||||
<string name="sponsor_block_notifications_title">I ogaysii ka boodida</string>
|
||||
<string name="sponsor_block_notifications_summary">Tus ogaysiis yar marka xayisiis laga boodo.</string>
|
||||
<string name="sponsor_block_privacy_title">Siyaasada Sirdhawrka</string>
|
||||
<string name="sponsor_block_privacy_summary">Fur Siyaasada Sirdhawrka SponsorBlock.</string>
|
||||
<string name="sponsor_block_api_url_help_text">Kani waa tixraaca la isticmaali doono markuu app-ku u baahanyahay inuu ogaado qaybaha muuqaalka ee uu ka boodayo.\n\nWaxaad ku fadhiisin kartaa tixraaca rasmiga ah ee SponsorBlock adoo ku dhufanaya istikhyaarka hoose ee \'Isticmaal ka rasmiga ah\', inkastoo lagugula talinayo inaad akhrido Siyaasada Sir-dhawrka SponsorBlock.</string>
|
||||
<string name="sponsor_block_privacy_policy_text">Siyaasada Sirdhawrka SponsorBlock</string>
|
||||
<string name="sponsor_block_homepage_url">https://sponsor.ajay.app/</string>
|
||||
<string name="sponsor_block_default_api_url">https://sponsor.ajay.app/api/</string>
|
||||
<string name="sponsor_block_privacy_policy_url">https://gist.github.com/ajayyy/aa9f8ded2b573d4f73a3ffa0ef74f796</string>
|
||||
<string name="sponsor_block_skip_sponsor_toast">Waxaa laga booday xayisiiste</string>
|
||||
<string name="sponsor_block_skip_intro_toast">Waxaa laga booday kala-badhe/hordhac</string>
|
||||
<string name="sponsor_block_skip_outro_toast">Waxaa laga booday qaybaha dhamaadka/xusid</string>
|
||||
<string name="sponsor_block_skip_interaction_toast">Waxaa laga booday xusuusin falcelin</string>
|
||||
<string name="sponsor_block_skip_self_promo_toast">Waxaa laga booday xayisiis aan cidu maalgashanin/isxayisiin</string>
|
||||
<string name="sponsor_block_skip_non_music_toast">Waxaa laga booday qayb aan hees ahayn</string>
|
||||
<string name="sponsor_block_toggle_skipping">Furo ka boodida xayisiistayaasha</string>
|
||||
<string name="sponsor_block_clear_whitelist_title">Nadiifi Kuwa La Ogolyahay</string>
|
||||
<string name="sponsor_block_clear_whitelist_summary">Nadiifi soosaarayaasha uusa SponsorBlock qabanaynin.</string>
|
||||
<string name="sponsor_block_enabled_toast">SponsorBlock wuu furanyahay</string>
|
||||
<string name="sponsor_block_disabled_toast">SponsorBlock wuu xidhanyahay</string>
|
||||
<string name="sponsor_block_whitelist_cleared_toast">Waa la nafiifiyay Kuwa La Ogolyahay</string>
|
||||
<string name="sponsor_block_uploader_added_to_whitelist_toast">Soosaaraha waxaa lagu daray Kuwa La Ogolyahay</string>
|
||||
<string name="sponsor_block_uploader_removed_from_whitelist_toast">Soosaaraha waxaa laga saaray Kuwa La Ogolyahay</string>
|
||||
<string name="sponsor_block_confirm_clear_whitelist">Ma hubtaa tirtirista Kuwa La Ogolyahay?</string>
|
||||
<string name="sponsor_block_confirm_reset_colors">Ma hubtaa inaad dib ugu celinayso midabada qaybaha siday ahaayeen?</string>
|
||||
<string name="sponsor_block_reset_colors_toast">Dib uceli midabbada .</string>
|
||||
<!-- Extras -->
|
||||
<string name="extras">Dheeraad ah</string>
|
||||
<string name="extras_todo_summary">Waxkabaddalada yaryar, macmilida, iyo fadhiyo dheeraad ah.</string>
|
||||
<string name="experimental_settings">Fadhiga tijaabada ah</string>
|
||||
</resources>
|
|
@ -719,4 +719,68 @@
|
|||
<string name="msg_failed_to_copy">無法複製到剪貼簿</string>
|
||||
<string name="playlist_add_stream_success_duplicate">重複新增 %d 次</string>
|
||||
<string name="duplicate_in_playlist">變灰的播放清單已經包含此項目。</string>
|
||||
</resources>
|
||||
<!-- SponsorBlock -->
|
||||
<string name="settings_category_sponsor_block_title">SponsorBlock (測試功能、第三方服務)</string>
|
||||
<string name="settings_category_sponsor_block_categories_title">SponsorBlock 分類</string>
|
||||
<string name="settings_category_sponsor_block_categories_summary">自訂要跳過的影片片段,以及它们在進度條上的顏色標記。</string>
|
||||
<string name="settings_category_sponsor_block_categories_reset_colors_title">重設顏色</string>
|
||||
<string name="settings_category_sponsor_block_category_enable_title">啟用</string>
|
||||
<string name="settings_category_sponsor_block_category_color">進度條顏色</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_title">贊助商廣告</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_summary">付費宣傳內容、付費推薦內容和植入廣告</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_title">中間停頓/開頭動畫</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_summary">沒有實際內容的間隔。可以是暫停、靜態畫面、重複動畫</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_title">結束畫面/鳴謝</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_summary">鳴謝或當YouTube 結束畫面出現。沒有語音的結尾</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_title">互動提醒 (訂閱)</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_summary">當內容中途有一個簡短的提示來喜歡、訂閱或關注他們</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_title">非付費/自我推廣</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_summary">類似「贊助商廣告」,但是非付費或自我推廣。這包括有關商品、捐贈或與他人合作的資訊。</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_title">音樂:非音樂部分</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_summary">僅用於音樂影片。這包括音樂影片中的開頭或結尾</string>
|
||||
<string name="no">否</string>
|
||||
<string name="later">稍後</string>
|
||||
<string name="invalid_color_toast">不正確的 HEX 顏色</string>
|
||||
<string name="sponsor_block">SponsorBlock</string>
|
||||
<string name="sponsor_block_home_page_title">查看網站</string>
|
||||
<string name="sponsor_block_home_page_summary">查看 SponsorBlock 的官方網站。</string>
|
||||
<string name="sponsor_block_enable_title">跳過贊助</string>
|
||||
<string name="sponsor_block_enable_summary">使用 SponsorBlock API 來自動跳過影片的廣告。目前只作用在 YouTube 的影片。</string>
|
||||
<string name="sponsor_block_api_url_title">API 網址</string>
|
||||
<string name="sponsor_block_api_url_summary">查詢 SponsorBlock API 時要使用的網址。必須設定該網址,才能使 SponsorBlock 發揮作用。</string>
|
||||
<string name="sponsor_block_notifications_title">跳過片段時提示</string>
|
||||
<string name="sponsor_block_notifications_summary">自動跳過片段時,顯示彈出提示</string>
|
||||
<string name="sponsor_block_privacy_title">查看隱私權政策</string>
|
||||
<string name="sponsor_block_privacy_summary">查看 SponsorBlock 的隱私權政策。</string>
|
||||
<string name="sponsor_block_api_url_help_text">為了讓應用程式知道要跳過影片的哪些部分時,會查詢這個URL。\n\n你可以透過點下面的「使用官方」選項來設定官方URL,不過強烈建議你在設定之前查看 SponsorBlock 的隱私權政策。</string>
|
||||
<string name="sponsor_block_privacy_policy_text">SponsorBlock 隱私權政策</string>
|
||||
<string name="sponsor_block_skip_sponsor_toast">已跳過贊助商廣告</string>
|
||||
<string name="sponsor_block_skip_intro_toast">已跳過中間停頓/開頭動畫</string>
|
||||
<string name="sponsor_block_skip_outro_toast">已跳過結束畫面/鳴謝</string>
|
||||
<string name="sponsor_block_skip_interaction_toast">已跳過互動提醒</string>
|
||||
<string name="sponsor_block_skip_self_promo_toast">已跳過非付費/自我推廣</string>
|
||||
<string name="sponsor_block_skip_non_music_toast">已跳過非音樂部分</string>
|
||||
<string name="sponsor_block_toggle_skipping">Toggle skipping sponsors</string>
|
||||
<string name="sponsor_block_clear_whitelist_title">清空白名單</string>
|
||||
<string name="sponsor_block_clear_whitelist_summary">清理 SponsorBlock 會忽略的上傳者名單。</string>
|
||||
<string name="sponsor_block_enabled_toast">SponsorBlock 已啟用</string>
|
||||
<string name="sponsor_block_disabled_toast">SponsorBlock 已停用</string>
|
||||
<string name="sponsor_block_whitelist_cleared_toast">白名單已清空</string>
|
||||
<string name="sponsor_block_uploader_added_to_whitelist_toast">上傳者新增到白名單中</string>
|
||||
<string name="sponsor_block_uploader_removed_from_whitelist_toast">上傳者移出白名單</string>
|
||||
<string name="sponsor_block_confirm_clear_whitelist">你確定要清空白名單?</string>
|
||||
<string name="sponsor_block_confirm_reset_colors">你確定要重設這個分類顏色?</string>
|
||||
<string name="sponsor_block_reset_colors_toast">顏色已重設</string>
|
||||
<!-- Extras -->
|
||||
<string name="extras">更多</string>
|
||||
<string name="extras_todo_summary">調整、暫時解決方法和其他雜項設定屬於這裡。</string>
|
||||
<string name="experimental_settings">實驗性設定</string>
|
||||
<string name="enable_local_player_title">啟用本機播放器 (alpha)</string>
|
||||
<string name="enable_local_player_summary">使用一個內建的播放器進行本機播放。這仍然處於早期開發階段,所以可能會有很多問題,包括與現有播放器的衝突。</string>
|
||||
<string name="force_auto_fullscreen_title">強制自動全螢幕</string>
|
||||
<string name="force_auto_fullscreen_summary">啟用後,當裝置為橫向時會強制全螢幕</string>
|
||||
<string name="disable_error_reports_title">禁用錯誤回報</string>
|
||||
<string name="disable_error_reports_summary">防止出現所有錯誤報告畫面。這可能導致應用程式出現意料之外的行為。<b>風險自負!</b></string>
|
||||
<string name="enable_return_youtube_dislike_title">顯示倒讚按鈕</string>
|
||||
<string name="enable_return_youtube_dislike_summary">使用 ReturnYouTubeDislike API 來顯示影片約略不喜歡的數量。只作用在 YouTube 的影片。\n<b>警告:你的 IP 會被第三方 API 知曉。風險自負!</b></string>
|
||||
</resources>
|
||||
|
|
|
@ -84,4 +84,13 @@
|
|||
|
||||
<color name="black">#000</color>
|
||||
|
||||
<!-- default SponsorBlock segment colors -->
|
||||
<color name="sponsor_segment">#00d400</color>
|
||||
<color name="intro_segment">#00ffff</color>
|
||||
<color name="outro_segment">#0202ed</color>
|
||||
<color name="interaction_segment">#cc00ff</color>
|
||||
<color name="self_promo_segment">#ffff00</color>
|
||||
<color name="non_music_segment">#ff9900</color>
|
||||
<color name="preview_segment">#008fd6</color>
|
||||
<color name="filler_segment">#7300ff</color>
|
||||
</resources>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<string name="md5">MD5</string>
|
||||
<string name="sha1">SHA-1</string>
|
||||
<string name="recaptcha">reCAPTCHA</string>
|
||||
<string name="github_url">https://github.com/TeamNewPipe/NewPipe</string>
|
||||
<string name="github_url">https://github.com/polymorphicshade/NewPipe</string>
|
||||
<string name="donation_url">https://newpipe.net/donate/</string>
|
||||
<string name="website_url">https://newpipe.net/</string>
|
||||
<string name="privacy_policy_url">https://newpipe.net/legal/privacy/</string>
|
||||
|
|
|
@ -409,6 +409,39 @@
|
|||
<string name="update_pref_screen_key">update_pref_screen_key</string>
|
||||
<string name="update_expiry_key">update_expiry_key</string>
|
||||
|
||||
<!-- SponsorBlock -->
|
||||
<string name="sponsor_block_home_page_key" translatable="false">sponsor_block_home_page</string>
|
||||
<string name="sponsor_block_enable_key" translatable="false">sponsor_block_enable</string>
|
||||
<string name="sponsor_block_api_url_key" translatable="false">sponsor_block_api_url</string>
|
||||
<string name="sponsor_block_notifications_key" translatable="false">sponsor_block_notifications</string>
|
||||
<string name="sponsor_block_privacy_key" translatable="false">sponsor_block_privacy</string>
|
||||
<string name="sponsor_block_categories_key" translatable="false">sponsor_block_categories</string>
|
||||
<string name="sponsor_block_category_reset_key" translatable="false">sponsor_block_category_reset</string>
|
||||
<string name="sponsor_block_category_sponsor_key" translatable="false">sponsor_block_category_sponsor</string>
|
||||
<string name="sponsor_block_category_sponsor_color_key" translatable="false">sponsor_block_category_sponsor_color</string>
|
||||
<string name="sponsor_block_category_intro_key" translatable="false">sponsor_block_category_intro</string>
|
||||
<string name="sponsor_block_category_intro_color_key" translatable="false">sponsor_block_category_intro_color</string>
|
||||
<string name="sponsor_block_category_outro_key" translatable="false">sponsor_block_category_outro</string>
|
||||
<string name="sponsor_block_category_outro_color_key" translatable="false">sponsor_block_category_outro_color</string>
|
||||
<string name="sponsor_block_category_interaction_key" translatable="false">sponsor_block_category_interaction</string>
|
||||
<string name="sponsor_block_category_interaction_color_key" translatable="false">sponsor_block_category_interaction_color</string>
|
||||
<string name="sponsor_block_category_self_promo_key" translatable="false">sponsor_block_category_self_promo</string>
|
||||
<string name="sponsor_block_category_self_promo_color_key" translatable="false">sponsor_block_category_self_promo_color</string>
|
||||
<string name="sponsor_block_category_non_music_key" translatable="false">sponsor_block_category_music</string>
|
||||
<string name="sponsor_block_category_non_music_color_key" translatable="false">sponsor_block_category_music_color</string>
|
||||
<string name="sponsor_block_category_preview_key" translatable="false">sponsor_block_category_preview</string>
|
||||
<string name="sponsor_block_category_preview_color_key" translatable="false">sponsor_block_category_preview_color</string>
|
||||
<string name="sponsor_block_category_filler_key" translatable="false">sponsor_block_category_filler</string>
|
||||
<string name="sponsor_block_category_filler_color_key" translatable="false">sponsor_block_category_filler_color</string>
|
||||
<string name="sponsor_block_whitelist_key" translatable="false">sponsor_block_whitelist</string>
|
||||
<string name="sponsor_block_clear_whitelist_key" translatable="false">sponsor_block_clear_whitelist</string>
|
||||
|
||||
<!-- Extras -->
|
||||
<string name="enable_return_youtube_dislike_key" translatable="false">enable_return_youtube_dislike</string>
|
||||
<string name="enable_local_player_key" translatable="false">enable_local_player</string>
|
||||
<string name="force_auto_fullscreen_key" translatable="false">force_auto_fullscreen</string>
|
||||
<string name="disable_error_reports_key" translatable="false">disable_error_reports</string>
|
||||
|
||||
<!-- Localizations -->
|
||||
<string name="default_localization_key">system</string>
|
||||
<!-- alternatively, load these from some local android data store -->
|
||||
|
|
|
@ -146,6 +146,28 @@
|
|||
<string name="settings_category_updates_title">Updates</string>
|
||||
<string name="settings_category_player_notification_title">Player notification</string>
|
||||
<string name="settings_category_player_notification_summary">Configure current playing stream notification</string>
|
||||
<string name="settings_category_sponsor_block_title">SponsorBlock (Beta, Third-Party Service)</string>
|
||||
<string name="settings_category_sponsor_block_categories_title">SponsorBlock Categories</string>
|
||||
<string name="settings_category_sponsor_block_categories_summary">Customize which video segments to skip, along with their color markings on the seek bar.</string>
|
||||
<string name="settings_category_sponsor_block_categories_reset_colors_title">Reset Colors</string>
|
||||
<string name="settings_category_sponsor_block_category_enable_title">Enable</string>
|
||||
<string name="settings_category_sponsor_block_category_color">Seek Bar Color</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_title">Sponsor</string>
|
||||
<string name="settings_category_sponsor_block_category_sponsor_summary">Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free shoutouts to causes/creators/websites/products they like.</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_title">Intermission/Intro Animation</string>
|
||||
<string name="settings_category_sponsor_block_category_intro_summary">An interval without actual content. Could be a pause, static frame, repeating animation. This should not be used for transitions containing information or be used on music videos.</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_title">Endcards/Credits</string>
|
||||
<string name="settings_category_sponsor_block_category_outro_summary">Credits or when the YouTube endcards appear. Not for spoken conclusions. This should not include useful content. This should not be used on music videos.</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_title">Interaction Reminds (Subscribe)</string>
|
||||
<string name="settings_category_sponsor_block_category_interaction_summary">When there is a short reminder to like, subscribe or follow them in the middle of content. If it is long or about something specific, it should be under self promotion instead.</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_title">Unpaid/Self Promotion</string>
|
||||
<string name="settings_category_sponsor_block_category_self_promo_summary">Similar to "sponsor" except for unpaid or self promotion. This includes sections about merchandise, donations, or information about who they collaborated with.</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_title">Music: Non-Music Section</string>
|
||||
<string name="settings_category_sponsor_block_category_non_music_summary">Only for use in music videos. This includes introductions or outros in music videos.</string>
|
||||
<string name="settings_category_sponsor_block_category_preview_title">Preview/Recap</string>
|
||||
<string name="settings_category_sponsor_block_category_preview_summary">Quick recap of previous episodes, or a preview of what\'s coming up later in the current video. Meant for edited together clips, not for spoken summaries.</string>
|
||||
<string name="settings_category_sponsor_block_category_filler_title">Filler Tangent/Jokes</string>
|
||||
<string name="settings_category_sponsor_block_category_filler_summary">This is for tangential scenes added only for filler or humor that are not required to understand the main content of the video.</string>
|
||||
<string name="background_player_playing_toast">Playing in background</string>
|
||||
<string name="popup_playing_toast">Playing in popup mode</string>
|
||||
<string name="content">Content</string>
|
||||
|
@ -170,6 +192,9 @@
|
|||
<string name="songs">Songs</string>
|
||||
<string name="albums">Albums</string>
|
||||
<string name="artists">Artists</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="later">Later</string>
|
||||
<string name="disabled">Disabled</string>
|
||||
<string name="clear">Clear</string>
|
||||
<string name="best_resolution">Best resolution</string>
|
||||
|
@ -242,6 +267,7 @@
|
|||
<string name="restore_defaults">Restore defaults</string>
|
||||
<string name="restore_defaults_confirmation">Do you want to restore defaults?</string>
|
||||
<string name="permission_display_over_apps">Give permission to display over other apps</string>
|
||||
<string name="invalid_color_toast">Invalid color</string>
|
||||
<!-- error activity -->
|
||||
<string name="error_report_notification_title">NewPipe encountered an error, tap to report</string>
|
||||
<string name="error_report_notification_toast">An error occurred, see the notification</string>
|
||||
|
@ -829,4 +855,52 @@
|
|||
<string name="search_filters_this_year">This year</string>
|
||||
<string name="search_filters_yes">Yes</string>
|
||||
<string name="search_filters_youtube_music">YouTube Music</string>
|
||||
<!-- SponsorBlock -->
|
||||
<string name="sponsor_block">SponsorBlock</string>
|
||||
<string name="sponsor_block_home_page_title">View Website</string>
|
||||
<string name="sponsor_block_home_page_summary">View the official SponsorBlock website.</string>
|
||||
<string name="sponsor_block_enable_title">Skip Sponsors</string>
|
||||
<string name="sponsor_block_enable_summary">Use the SponsorBlock API to automatically skip sponsors in videos. This currently only works for YouTube videos.</string>
|
||||
<string name="sponsor_block_api_url_title">API Url</string>
|
||||
<string name="sponsor_block_api_url_summary">The url to use when querying the SponsorBlock API. This must be set for SponsorBlock to work.</string>
|
||||
<string name="sponsor_block_notifications_title">Notify when sponsors are skipped</string>
|
||||
<string name="sponsor_block_notifications_summary">Show a toast notification when a sponsor is automatically skipped.</string>
|
||||
<string name="sponsor_block_privacy_title">View Privacy Policy</string>
|
||||
<string name="sponsor_block_privacy_summary">View SponsorBlock\'s privacy policy.</string>
|
||||
<string name="sponsor_block_api_url_help_text">This is the URL that will be queried when the application needs to know which parts of a video to skip.\n\nYou can set the official URL by clicking the \'Use Official\' option below, though it is highly recommended you view SponsorBlock\'s privacy policy before you do.</string>
|
||||
<string name="sponsor_block_privacy_policy_text">SponsorBlock Privacy Policy</string>
|
||||
<string name="sponsor_block_homepage_url">https://sponsor.ajay.app/</string>
|
||||
<string name="sponsor_block_default_api_url">https://sponsor.ajay.app/api/</string>
|
||||
<string name="sponsor_block_privacy_policy_url">https://gist.github.com/ajayyy/aa9f8ded2b573d4f73a3ffa0ef74f796</string>
|
||||
<string name="sponsor_block_skip_sponsor_toast">Skipped sponsor</string>
|
||||
<string name="sponsor_block_skip_intro_toast">Skipped intermission/intro</string>
|
||||
<string name="sponsor_block_skip_outro_toast">Skipped endcards/credits</string>
|
||||
<string name="sponsor_block_skip_interaction_toast">Skipped interaction reminder</string>
|
||||
<string name="sponsor_block_skip_self_promo_toast">Skipped unpaid/self promo</string>
|
||||
<string name="sponsor_block_skip_non_music_toast">Skipped non-music</string>
|
||||
<string name="sponsor_block_skip_preview_toast">Skipped preview/recap</string>
|
||||
<string name="sponsor_block_skip_filler_toast">Skipped filler</string>
|
||||
<string name="sponsor_block_toggle_skipping">Toggle skipping sponsors</string>
|
||||
<string name="sponsor_block_clear_whitelist_title">Clear Whitelist</string>
|
||||
<string name="sponsor_block_clear_whitelist_summary">Clear the list of uploaders SponsorBlock will ignore.</string>
|
||||
<string name="sponsor_block_enabled_toast">SponsorBlock enabled</string>
|
||||
<string name="sponsor_block_disabled_toast">SponsorBlock disabled</string>
|
||||
<string name="sponsor_block_whitelist_cleared_toast">Whitelist cleared</string>
|
||||
<string name="sponsor_block_uploader_added_to_whitelist_toast">Uploader added to whitelist</string>
|
||||
<string name="sponsor_block_uploader_removed_from_whitelist_toast">Uploader removed from whitelist</string>
|
||||
<string name="sponsor_block_confirm_clear_whitelist">Are you sure you want to clear the whitelist?</string>
|
||||
<string name="sponsor_block_confirm_reset_colors">Are you sure you want to reset the category colors?</string>
|
||||
<string name="sponsor_block_reset_colors_toast">Colors reset.</string>
|
||||
<!-- Extras -->
|
||||
<string name="extras">Extras</string>
|
||||
<string name="extras_todo_summary">Tweaks, workarounds, and other miscellaneous settings belong here.</string>
|
||||
<string name="experimental_settings">Experimental Settings</string>
|
||||
<string name="enable_local_player_title">Enable Local Player (alpha)</string>
|
||||
<string name="enable_local_player_summary">Use a built-in player for local playback. This is still in early development so there will probably be a lot of issues, including conflicts with the existing player.</string>
|
||||
<string name="force_auto_fullscreen_title">Force Auto Fullscreen</string>
|
||||
<string name="force_auto_fullscreen_summary">If enabled, when the device is set to landscape, force fullscreen mode even if the device is a tablet or TV.</string>
|
||||
<string name="disable_error_reports_title">Disable Error Reporting</string>
|
||||
<string name="disable_error_reports_summary">Prevent all error reporting screens from appearing. This may result in the app behaving unexpectedly. <b>USE AT YOUR OWN RISK!</b></string>
|
||||
<string name="enable_return_youtube_dislike_title">Show Dislike Count</string>
|
||||
<string name="enable_return_youtube_dislike_summary">Use the ReturnYouTubeDislike API to show the amount of dislikes for a video. This only works for YouTube videos.\n<b>WARNING: Your IP address will be visible to the API. Use at your own risk!</b></string>
|
||||
</resources>
|
||||
|
|
44
app/src/main/res/xml/extra_settings.xml
Normal file
44
app/src/main/res/xml/extra_settings.xml
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/extras">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:selectable="false"
|
||||
android:persistent="false"
|
||||
android:summary="@string/extras_todo_summary"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/experimental_settings">
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/enable_local_player_key"
|
||||
android:summary="@string/enable_local_player_summary"
|
||||
android:title="@string/enable_local_player_title"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/force_auto_fullscreen_key"
|
||||
android:summary="@string/force_auto_fullscreen_summary"
|
||||
android:title="@string/force_auto_fullscreen_title"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/disable_error_reports_key"
|
||||
android:summary="@string/disable_error_reports_summary"
|
||||
android:title="@string/disable_error_reports_title"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/enable_return_youtube_dislike_key"
|
||||
android:summary="@string/enable_return_youtube_dislike_summary"
|
||||
android:title="@string/enable_return_youtube_dislike_title"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
|
@ -47,6 +47,18 @@
|
|||
android:title="@string/settings_category_updates_title"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.schabi.newpipe.settings.SponsorBlockSettingsFragment"
|
||||
android:icon="@drawable/ic_sponsor_block_enable"
|
||||
android:title="@string/sponsor_block"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.schabi.newpipe.settings.ExtraSettingsFragment"
|
||||
android:icon="@drawable/ic_asterisk"
|
||||
android:title="@string/extras"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.schabi.newpipe.settings.DebugSettingsFragment"
|
||||
android:icon="@drawable/ic_bug_report"
|
||||
|
|
207
app/src/main/res/xml/sponsor_block_category_settings.xml
Normal file
207
app/src/main/res/xml/sponsor_block_category_settings.xml
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/settings_category_sponsor_block_categories_title">
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_sponsor_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_sponsor_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true"
|
||||
android:key="@string/sponsor_block_category_sponsor_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_sponsor_key"
|
||||
android:defaultValue="@color/sponsor_segment"
|
||||
android:key="@string/sponsor_block_category_sponsor_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_intro_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_intro_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_category_intro_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_intro_key"
|
||||
android:defaultValue="@color/intro_segment"
|
||||
android:key="@string/sponsor_block_category_intro_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_outro_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_outro_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_category_outro_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_outro_key"
|
||||
android:defaultValue="@color/outro_segment"
|
||||
android:key="@string/sponsor_block_category_outro_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_interaction_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_interaction_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_category_interaction_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_interaction_key"
|
||||
android:defaultValue="@color/interaction_segment"
|
||||
android:key="@string/sponsor_block_category_interaction_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_self_promo_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_self_promo_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_category_self_promo_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_self_promo_key"
|
||||
android:defaultValue="@color/self_promo_segment"
|
||||
android:key="@string/sponsor_block_category_self_promo_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_non_music_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_non_music_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_category_non_music_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_non_music_key"
|
||||
android:defaultValue="@color/non_music_segment"
|
||||
android:key="@string/sponsor_block_category_non_music_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_preview_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_preview_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_category_preview_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_preview_key"
|
||||
android:defaultValue="@color/preview_segment"
|
||||
android:key="@string/sponsor_block_category_preview_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings_category_sponsor_block_category_filler_title">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/settings_category_sponsor_block_category_filler_summary"
|
||||
android:selectable="false"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_category_filler_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_enable_title"/>
|
||||
|
||||
<org.schabi.newpipe.settings.custom.EditColorPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_category_filler_key"
|
||||
android:defaultValue="@color/filler_segment"
|
||||
android:key="@string/sponsor_block_category_filler_color_key"
|
||||
android:title="@string/settings_category_sponsor_block_category_color"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="@string/sponsor_block_category_reset_key"
|
||||
android:title="@string/settings_category_sponsor_block_categories_reset_colors_title"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
58
app/src/main/res/xml/sponsor_block_settings.xml
Normal file
58
app/src/main/res/xml/sponsor_block_settings.xml
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/sponsor_block">
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="@string/sponsor_block_home_page_key"
|
||||
android:summary="@string/sponsor_block_home_page_summary"
|
||||
android:title="@string/sponsor_block_home_page_title"/>
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="@string/sponsor_block_privacy_key"
|
||||
android:summary="@string/sponsor_block_privacy_summary"
|
||||
android:title="@string/sponsor_block_privacy_title"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:layout="@layout/settings_category_header_layout"
|
||||
android:title="@string/settings">
|
||||
|
||||
<org.schabi.newpipe.settings.custom.SponsorBlockApiUrlPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="@string/sponsor_block_api_url_key"
|
||||
android:summary="@string/sponsor_block_api_url_summary"
|
||||
android:title="@string/sponsor_block_api_url_title"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_api_url_key"
|
||||
android:defaultValue="false"
|
||||
android:key="@string/sponsor_block_enable_key"
|
||||
android:summary="@string/sponsor_block_enable_summary"
|
||||
android:title="@string/sponsor_block_enable_title"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true"
|
||||
android:dependency="@string/sponsor_block_api_url_key"
|
||||
android:key="@string/sponsor_block_notifications_key"
|
||||
android:summary="@string/sponsor_block_notifications_summary"
|
||||
android:title="@string/sponsor_block_notifications_title"/>
|
||||
|
||||
<PreferenceScreen
|
||||
app:iconSpaceReserved="false"
|
||||
android:dependency="@string/sponsor_block_api_url_key"
|
||||
android:fragment="org.schabi.newpipe.settings.SponsorBlockCategoriesSettingsFragment"
|
||||
android:key="@string/sponsor_block_categories_key"
|
||||
android:title="@string/settings_category_sponsor_block_categories_title"
|
||||
android:summary="@string/settings_category_sponsor_block_categories_summary"/>
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:key="@string/sponsor_block_clear_whitelist_key"
|
||||
android:summary="@string/sponsor_block_clear_whitelist_summary"
|
||||
android:title="@string/sponsor_block_clear_whitelist_title"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
143
doc/README.es.md
143
doc/README.es.md
|
@ -1,143 +0,0 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="../assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">Una interfaz de streaming ligera y libre para Android.</h4>
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-es.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="Lanzamientos GitHub"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="Licencia: GPLv3"><img src="https://img.shields.io/badge/Licencia-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="Estado del Build"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/es/" alt="Estado de la Traducción"><img src="https://hosted.weblate.org/widgets/newpipe/es/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="Canal de IRC: #newpipe"><img src="https://img.shields.io/badge/Canal%20de%20IRC%20-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Recompensas en Bountysource"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<p align="center"><a href="#capturas-de-pantalla">Capturas de Pantalla</a> • <a href="#descripción">Descripción</a> • <a href="#características">Características</a> • <a href="#instalación-y-actualizaciones">Instalación y Actualizaciones</a> • <a href="#contribución">Contribución</a> • <a href="#donar">Donar</a> • <a href="#licencia">Licencia</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">Sitio Web</a> • <a href="https://newpipe.net/blog/">Blog</a> • <a href="https://newpipe.net/FAQ/">Preguntas Frecuentes</a> • <a href="https://newpipe.net/press/">Prensa</a></p>
|
||||
<hr>
|
||||
|
||||
*Lea esto en otros idiomas: [English](../README.md), [हिन्दी](README.hi.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md).*
|
||||
|
||||
<b>AVISO: ESTA ES UNA VERSIÓN BETA, POR LO TANTO, PUEDE ENCONTRAR BUGS. SI ENCUENTRA UNO ABRA UN ISSUE A TRAVÉS DE NUESTRO REPOSITORIO DE GITHUB.</b>
|
||||
|
||||
<b>COLOCAR NEWPIPE O CUALQUIER FORK DE NEWPIPE EN LA GOOGLE PLAY STORE VIOLARÁ SUS TÉRMINOS Y CONDICIONES.</b>
|
||||
|
||||
## Capturas de Pantalla
|
||||
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
## Descripción
|
||||
|
||||
NewPipe no usa ninguna librería del framework de Google, ni la API de YouTube. Los sitios web solamente se analizan para extraer la información requerida, por lo que esta app se puede usar sin los servicios de Google instalados. Además, no se necesita una cuenta de YouTube para usar NewPipe, que es un programa libre <i lang="en">copyleft</i>.
|
||||
|
||||
### Características
|
||||
|
||||
* Buscar videos
|
||||
* No requiere inicio de sesión
|
||||
* Mostrar información general sobre videos
|
||||
* Mirar videos de YouTube
|
||||
* Modo de solo audio en videos de YouTube
|
||||
* Modo pop-up (reproductor flotante)
|
||||
* Elegir un reproductor de video externo para mirar videos
|
||||
* Descargar videos
|
||||
* Descargar solo audio
|
||||
* Abrir videos en Kodi
|
||||
* Mostrar videos próximos/relacionados
|
||||
* Buscar a través de YouTube en un idioma específico
|
||||
* Mirar/Bloquear videos restringidos por edad
|
||||
* Mostrar información general sobre canales
|
||||
* Buscar de canales
|
||||
* Mirar videos de un canal
|
||||
* Soporte Orbot/Tor (todavía no directamente)
|
||||
* Soporte para videos en 1080p/2K/4K
|
||||
* Historial de videos vistos
|
||||
* Suscripción a canales
|
||||
* Historial de búsquedas
|
||||
* Buscar/Mirar listas de reproducción
|
||||
* Mirar listas de reproducción en cola
|
||||
* Poner videos en cola
|
||||
* Listas de reproducción locales
|
||||
* Subtítulos
|
||||
* Soporte para transmisiones en vivo
|
||||
* Mostrar comentarios
|
||||
|
||||
### Servicios Soportados
|
||||
|
||||
NewPipe soporta varios servicios. Nuestras [documentaciones](https://teamnewpipe.github.io/documentation/) ofrecen más información sobre cómo se puede agregar un servicio nuevo a la app y al extractor. Por favor ponte en contacto con nosotros si tienes pensado agregar uno nuevo. Actualmente los servicios soportados son:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[beta\]
|
||||
* media.ccc.de \[beta\]
|
||||
* PeerTube instances \[beta\]
|
||||
* Bandcamp \[beta\]
|
||||
|
||||
## Instalación y Actualizaciones
|
||||
|
||||
Se puede instalar NewPipe usando uno de los métodos siguientes:
|
||||
|
||||
1. Agregando nuestro repositorio personalizado a F-Droid e instalarlo desde allí. Las instrucciones están [aquí](https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/).
|
||||
2. Descargando el archivo APK de [aquí](https://github.com/TeamNewPipe/NewPipe/releases) y posteriormente instalarlo.
|
||||
3. Usando el repositorio oficial de F-Droid. Este es el método más lento para obtener actualizaciones, ya que F-Droid debe reconocer los cambios, construir el APK aparte, firmarlo con una clave, y finalmente publicar la actualización.
|
||||
4. Construyendo la app usted mismo. Este es el modo más rápido para obtener nuevas características en su dispositivo, pero es mucho más complicado, así que recomendamos uno de los otros métodos.
|
||||
|
||||
Recomendamos el método 1 para la mayoría de usuarios. Los APKs instalados usando método 1 y 2 son compatibles entre sí, pero no lo son con los instalados usando el método 3. Esto es debido a la clave de firmado, ya que los métodos 1 y 2 usan la misma clave (la nuestra), pero el método 3 usa una clave diferente (la de F-Droid). El método 4 excluye totalmente una clave de firmado. Las claves de firmado aseguran que el usuario no esté siendo engañado para instalar/actualizar una APK maliciosa.
|
||||
|
||||
Además, si quiere cambiar el método de instalación por alguna razón (por ejemplo: la funcionalidad del núcleo de NewPipe se rompe o F-Droid aún no publica la actualización), recomendamos el siguiente procedimiento:
|
||||
1. Respalde su información a través de Ajustes > Contenido > Exportar base de datos; esto guardará su historial (videos vistos y búsquedas), suscripciones, listas de reproducción y ajustes.
|
||||
2. Desinstale NewPipe.
|
||||
3. Descargue el APK con un método distinto e instálelo.
|
||||
4. Importe la información (la base de datos extraída del paso 1) a través de Ajustes > Contenido > Importar base de datos. Tenga en cuenta que esta opción superpondrá su historial actual (tanto de vídeos como de búsquedas), sus listas de reproducción y (opcionalmente) sus configuraciones.
|
||||
|
||||
## Contribución
|
||||
|
||||
Si tiene ideas, traducciones, cambios de diseño, limpieza de código o cambios grandes de código, su ayuda es siempre bienvenida. ¡Cuanto más hagamos, NewPipe será mucho mejor!
|
||||
|
||||
Si quiere involucrarse, fíjese en nuestras [notas de contribución](../.github/CONTRIBUTING.md).
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/es/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/es/287x66-grey.png" alt="Estado de la Traducción" />
|
||||
</a>
|
||||
|
||||
## Donar
|
||||
Si te gusta NewPipe, estaremos felices con una donación. Puede enviar bitcoin o donar a través de Bountysource o Liberapay. Visita nuestro [sitio web](https://newpipe.net/donate) para más información.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="../assets/bitcoin_qr_code.png" alt="Código QR del Bitcoin" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="../assets/liberapay_qr_code.png" alt="Visita NewPipe en liberapay.com" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="../assets/liberapay_donate_button.svg" alt="Dona vía Liberapay" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="../assets/bountysource_qr_code.png" alt="Visita NewPipe en bountysource.com" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Revisa cuántas recompensas puedes obtener."></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Política de Privacidad
|
||||
|
||||
El proyecto NewPipe tiene como objetivo ofrecer una experience privada y anónima al usar servicios web multimedia. Por lo tanto, la app no recoleta ningún tipo de información sin su consentimiento. La politica de privacidad de NewPipe explica en detalle qué información es enviada y almacenada cuando envía un informe de error o comenta en [nuestro blog](https://newpipe.net/blog/). Puede encontrar el documento [aquí](https://newpipe.net/legal/privacy/).
|
||||
|
||||
## Licencia
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
NewPipe es Software Libre: Puede usarlo, estudiarlo, compartirlo y mejorarlo a su voluntad. Más específicamente, puede redistribuirlo y/o modificarlo bajo los términos de la [GNU General Public License](https://www.gnu.org/licenses/gpl.html) publicada por la Free Software Foundation tanto si usa la versión 3 o posterior de la licencia.
|
149
doc/README.ja.md
149
doc/README.ja.md
|
@ -1,149 +0,0 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="../assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">自由で軽量な Android 向けストリーミングフロントエンド</h4>
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-ja.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="GitHub リリース"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg"></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="ライセンス: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="ビルド状態"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/" alt="翻訳状態"><img src="https://hosted.weblate.org/widgets/newpipe/-/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="IRC チャンネル: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource 寄付"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
<p align="center"><a href="#screenshots">スクリーンショット</a> • <a href="#description">説明</a> • <a href="#features">機能</a> • <a href="#installation-and-updates">インストールと更新</a> • <a href="#contribution">貢献</a> • <a href="#donate">寄付</a> • <a href="#license">ライセンス</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">ウェブサイト</a> • <a href="https://newpipe.net/blog/">ブログ</a> • <a href="https://newpipe.net/FAQ/">FAQ</a> • <a href="https://newpipe.net/press/">ニュース</a></p>
|
||||
<hr>
|
||||
|
||||
*他の言語で読む: [English](../README.md), [Español](README.es.md), [हिन्दी](README.hi.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md)。*
|
||||
|
||||
<b>注意: これはベータ版のため、バグが発生する可能性があります。もしバグが発生した場合、GitHub のリポジトリで Issue を開いてください。</b>
|
||||
|
||||
<b>NewPipe 及びいずれのフォークを Google Play ストアに公開すると、Google の取引条件の違反になります。</b>
|
||||
|
||||
<span id="screenshots"></span>
|
||||
## スクリーンショット
|
||||
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
<span id="description"></span>
|
||||
## 説明
|
||||
|
||||
自由なコピーレフトソフトウェアの NewPipe は一切の Google フレームワークライブラリ及び、YouTube API を使用しません。ウェブサイトは必要な情報のためだけに読み込まれるため、このアプリは Google のサービスがインストールされていない端末で使用ができます。また、NewPipe の使用に YouTube アカウントは必要となりません。
|
||||
|
||||
<span id="features"></span>
|
||||
### 機能
|
||||
|
||||
* 動画の検索
|
||||
* 動画の基本情報の表示
|
||||
* YouTube の動画の視聴
|
||||
* YouTube の動画のバックグラウンド再生
|
||||
* ポップアップモード (フローティングプレイヤー)
|
||||
* 動画を視聴するストリーミングプレイヤーの選択
|
||||
* 動画のダウンロード
|
||||
* 音声のみのダウンロード
|
||||
* Kodi での動画再生
|
||||
* 次の動画/関連動画の表示
|
||||
* 特定の言語の YouTube の検索
|
||||
* 年齢制限のあるコンテンツの視聴/ブロック
|
||||
* チャンネルの基本情報の表示
|
||||
* チャンネルの検索
|
||||
* チャンネルからの動画の視聴
|
||||
* Orbot/Tor 対応 (直接的なものは未実装)
|
||||
* 1080p/2K/4K 対応
|
||||
* 履歴の表示
|
||||
* チャンネルの登録
|
||||
* 履歴の検索
|
||||
* 再生リストの検索/視聴
|
||||
* 再生リストをキューに追加して再生
|
||||
* 動画のキューへの追加
|
||||
* 端末内の再生リスト
|
||||
* 字幕
|
||||
* ライブ配信の対応
|
||||
* コメントの表示
|
||||
|
||||
### 対応しているサービス
|
||||
|
||||
NewPipe は複数のサービスに対応しています。[ドキュメント](https://teamnewpipe.github.io/documentation/)は、どのようにしてアプリと NewPipe Extractor にサービスを追加できるかについて詳細な情報を提供しています。もし、新しいサービスを追加するならば、是非私たちに連絡をお願いします。現在対応しているサービスは:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[ベータ\]
|
||||
* media.ccc.de \[ベータ\]
|
||||
* PeerTube インスタンス \[ベータ\]
|
||||
* Bandcamp \[ベータ\]
|
||||
|
||||
<!-- Hidden span to keep old links compatible. -->
|
||||
<span id="updates"></span>
|
||||
|
||||
<span id="installation-and-updates"></span>
|
||||
## インストールと更新
|
||||
以下の方法のいずれかに従うことによって NewPipe をインストールできます。
|
||||
1. カスタムリポジトリを F-Droid に追加してリリースが公開され次第インストールする。この方法の説明はこちら: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
|
||||
2. リリースが公開され次第[GitHub のリリース](https://github.com/TeamNewPipe/NewPipe/releases)から APK をダウンロードしてインストールする。
|
||||
3. F-Droid から更新する。これは更新を手にする上で最も遅い方法です。F-Droid が変更を検知して、APK をビルドし、署名、そしてユーザーに更新を届ける必要があるためです。
|
||||
4. 自分でデバッグ APK をビルドする。これは新しい機能を使用する上で最も早い方法ですが、他と比べてとても複雑なので、他の方法の使用を推奨します。
|
||||
|
||||
私たちはほとんどのユーザーに方法1を推奨します。方法1と2でインストールされた APK は互換性がありますが、方法3でインストールされたものにはありません。これは方法1と2では、同じ署名鍵 (私たちが使用するもの)が使用されますが、方法3では異なった署名鍵 (F-Droidが使用するもの)が使用されるためです。方法4を使ったデバッグ APK のビルドは根本的に署名鍵の問題を除きます。署名鍵はユーザーが騙されて悪意のある更新がアプリにインストールされないことを助けるためにあります。
|
||||
|
||||
もし、何かしらの理由によりソースを切り替えたい場合 (例: NewPipe のコア機能が壊れてしまったが F-Droid はまだ更新をしていない) は、この手順を推奨します。
|
||||
1. 履歴や登録チャンネル、再生リストを保つために 設定 > コンテンツ > データベースをエクスポート からデータをバックアップ
|
||||
2. NewPipe をアンインストール
|
||||
3. 新しいソースから APK をダウンロードしてインストール
|
||||
4. 設定 > コンテンツ > データベースをインポート からステップ1で作ったデータベースをインポート
|
||||
|
||||
<span id="contribution"></span>
|
||||
## 貢献
|
||||
翻訳、デザインの変更、コードの整理、大規模なコードの変更などの助けはいつでも歓迎します。
|
||||
より良いものを一緒に作り上げましょう!
|
||||
|
||||
もし貢献をしたい場合、[貢献ノート](../.github/CONTRIBUTING.md)をご確認ください。
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/-/287x66-grey.png" alt="翻訳状態" />
|
||||
</a>
|
||||
|
||||
<span id="donate"></span>
|
||||
## 寄付
|
||||
もし、NewPipe を気に入っていただけたら、寄付をしていただけると嬉しいです。Bitcoin または Bountysource, Liberapay から寄付をすることができます。NewPipe への寄付については、[ウェブサイト](https://newpipe.net/donate)からお願いします。
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="../assets/bitcoin_qr_code.png" alt="Bitcoin QR コード" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="../assets/liberapay_qr_code.png" alt="liberapay.com で NewPipe を訪れる" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="../assets/liberapay_donate_button.svg" alt="Liberapay で寄付" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="../assets/bountysource_qr_code.png" alt="bountysource.com で NewPipe を訪れる" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="あなたがどれほどの寄付を得られるのか確認しましょう。"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## プライバシーポリシー
|
||||
NewPipe プロジェクトはメディアウェブサービスを使用する上でのプライベートで匿名の体験を提供することを目的としています。
|
||||
そのため、アプリはあなたの同意なしで一切のデータを収集しません。NewPipe のプライバシーポリシーはあなたがクラッシュレポートまたは、私たちのブログでコメントを送信した場合にどのようなデータが送信され、保存されるのかを詳細に説明しています。そのドキュメントは[こちら](https://newpipe.net/legal/privacy/)から見つけることができます。
|
||||
|
||||
<span id="license"></span>
|
||||
## ライセンス
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
NewPipe はフリーソフトウェアなので、あなたはあなたの望むように使用、習得、共有、改善を行えます。
|
||||
具体的には、フリーソフトウェア財団により公開された [GNU General Public License](https://www.gnu.org/licenses/gpl.html) のバージョン3のライセンスもしくは、(あなたの選択で) いずれかの後継バージョンの規約の元で配布または改変を行うことができます。
|
146
doc/README.ko.md
146
doc/README.ko.md
|
@ -1,146 +0,0 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="../assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">A libre lightweight streaming frontend for Android.</h4>
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-ko.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="GitHub release"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="Build Status"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/" alt="Translation Status"><img src="https://hosted.weblate.org/widgets/newpipe/-/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="IRC channel: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
<p align="center"><a href="#screenshots">Screenshots</a> • <a href="#description">Description</a> • <a href="#features">Features</a> • <a href="#updates">Updates</a> • <a href="#contribution">Contribution</a> • <a href="#donate">Donate</a> • <a href="#license">License</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">Website</a> • <a href="https://newpipe.net/blog/">Blog</a> • <a href="https://newpipe.net/FAQ/">FAQ</a> • <a href="https://newpipe.net/press/">Press</a></p>
|
||||
<hr>
|
||||
|
||||
*Read this in other languages: [English](../README.md), [Español](README.es.md), [हिन्दी](README.hi.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md).*
|
||||
|
||||
<b>경고: 이 버전은 베타 버전이므로, 버그가 발생할 수도 있습니다. 만약 버그가 발생하였다면, 우리의 GITHUB 저장소에서 ISSUE를 열람하여 주십시오.</b>
|
||||
|
||||
<b>NEWPIPE 또는 이것의 FORK을 구글 플레이스토어에 올리는 것은 그들의 이용약관을 위반합니다.</b>
|
||||
|
||||
## Screenshots
|
||||
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
## Description
|
||||
|
||||
NewPipe는 어떤 구글 프레임워크 라이브러리나, 유튜브 API를 사용하지 않습니다. 웹사이트는 단지 필요한 정보를 가져오기 위해 구문 분석 됩니다. 따라서 이 앱은 구글 서비스의 설치 없이 기기에서 사용될 수 있습니다. 또한, 카피레프트 자유 소프트웨어인 NewPipe를 사용하기 위해 유튜브 계정이 필요하지 않습니다.
|
||||
|
||||
### Features
|
||||
|
||||
* 영상 검색
|
||||
* 영상의 일반적인 정보 표시
|
||||
* 유튜브 영상 보기
|
||||
* 유튜브 영상 듣기
|
||||
* 팝업 모드 (floating player)
|
||||
* 영상 공유
|
||||
* 영상 다운로드
|
||||
* 음성만 다운로드
|
||||
* Kodi에서 영상 열람
|
||||
* 다음/관련된 영상 표시
|
||||
* 특정 언어로 유튜브 검색
|
||||
* 연령 제한 컨텐츠 시청/차단
|
||||
* 채널에 대한 일반적인 정보 표시
|
||||
* 채널 검색
|
||||
* 채널에서 영상 시청
|
||||
* Orbot/Tor 지원 (아직 직접적이지 않음)
|
||||
* 1080p/2K/4K 지원
|
||||
* 기록 보기
|
||||
* 채널 구독
|
||||
* 기록 검색
|
||||
* 재생목록 검색/시청
|
||||
* 추가된 재생목록 시청
|
||||
* 영상 추가
|
||||
* 지역 재생목록
|
||||
* 자막
|
||||
* 실시간 방송 지원
|
||||
* 댓글 표시
|
||||
|
||||
### Supported Services
|
||||
|
||||
NewPipe는 여러가지 서비스를 지원합니다. 우리의 [문서](https://teamnewpipe.github.io/documentation/)는 새로운 서비스가 앱과 추출기에 어떻게 추가될 수 있는지에 대한 더 많은 정보를 제공합니다. 만약 새로운 서비스를 추가하고자 한다면, 우리에게 연락해 주시기 바랍니다. 현재 지원되는 서비스:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[beta\]
|
||||
* media.ccc.de \[beta\]
|
||||
* PeerTube instances \[beta\]
|
||||
* Bandcamp \[beta\]
|
||||
|
||||
## Updates
|
||||
NewPipe 코드의 변경이 있을 때(기능 추가 또는 버그 수정으로 인해), 결국 릴리즈가 발생할 것입니다. 이것들의 형식은 x.xx.x 입니다.
|
||||
이 새로운 버전을 얻기 위해서, 당신은:
|
||||
1. 직접 디버그 APK를 생성할 수 있습니다. 이 방법은 당신의 기기에서 새로운 기능을 얻을 수 있는 가장 빠른 방법이지만, 꽤 많이 복잡합니다.
|
||||
따라서 우리는 다른 방법들 중 하나를 사용하는 것을 추천합니다.
|
||||
2. 우리의 커스텀 저장소를 F-Droid에 추가하고 우리가 릴리즈를 게시하는 대로 저곳에서 릴리즈를 설치할 수 있습니다.
|
||||
이에 대한 설명서는 이곳에서 확인할 수 있습니다: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
|
||||
3. 우리가 릴리즈를 게시하는 대로 [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases)에서 APK를 다운받고 이것을 설치할 수 있습니다.
|
||||
4. F-Droid를 통해 업데이트 할 수 있습니다. F-Droid는 변화를 인식하고, 스스로 APK를 생성하고, 이것에 서명하고, 사용자들에서 업데이트를 전달해야만 하기 때문에,
|
||||
이것은 업데이트를 받는 가장 느린 방법입니다.
|
||||
|
||||
우리는 대부분의 사용자에게 2번쨰 방법을 추천합니다. 방법 2 또는 3을 사용하여 설치된 APK는 서로 호환되지만, 방법 4를 사용하여 설치된 것들과는 호환되지 않습니다. 이것은 방법 2 또는 3에서는 같은 (우리의)서명 키가 사용되지만, 방법 4에서는 다른 (F-Droid의)서명 키가 사용되기 때문입니다. 방법 1을 사용하여 디버그 APK를 생성하는 것에서는 키가 완전히 제외됩니다. 서명 키는 사용자가 앱에 악의적인 업데이트를 설치하는 것에 대해 속지 않도록 보장하는 것을 도와줍니다.
|
||||
|
||||
한편, 만약 어떠한 이유(예. NewPipe의 핵심 기능이 손상되었고 F-Droid가 아직 업데이트를 가지지 않는 경우) 때문에 소스를 바꾸길 원한다면,
|
||||
우리는 다음과 같은 절차를 따르는 것을 권장합니다:
|
||||
1. 당신의 기록, 구독, 그리고 재생목록을 유지할 수 있도록 Settings > Content > Export Database 를 통해 데이터를 백업하십시오.
|
||||
2. NewPipe를 삭제하십시오.
|
||||
3. 새로운 소스에서 APK를 다운로드하고 이것을 설치하십시오.
|
||||
4. Step 1의 Settings > Content > Import Database 을 통해 데이터를 불러오십시오.
|
||||
|
||||
## Contribution
|
||||
당신이 아이디어, 번역, 디자인 변경, 코드 정리, 또는 정말 큰 코드 수정에 대한 의견이 있다면, 도움은 항상 환영합니다.
|
||||
더 많이 수행될수록 더 많이 발전할 수 있습니다!
|
||||
|
||||
만약 참여하고 싶다면, 우리의 [컨트리뷰션 공지](../.github/CONTRIBUTING.md)를 참고하십시오.
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/-/287x66-grey.png" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
## Donate
|
||||
만약 NewPipe가 마음에 들었다면, 우리는 기부에 대해 기꺼이 환영합니다. bitcoin을 보내거나, Bountysource 또는 Liberapay를 통해 기부할 수 있습니다. NewPipe에 기부하는 것에 대한 자세한 정보를 원한다면, 우리의 [웹사이트](https://newpipe.net/donate)를 방문하여 주십시오.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="../assets/bitcoin_qr_code.png" alt="Bitcoin QR code" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="../assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="../assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="../assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn."></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Privacy Policy
|
||||
|
||||
NewPipe 프로젝트는 미디어 웹 서비스를 사용하는 것에 대한 사적의, 익명의 경험을 제공하는 것을 목표로 하고 있습니다.
|
||||
그러므로, 앱은 당신의 동의 없이 어떤 데이터도 수집하지 않습니다. NewPipe의 개인정보보호정책은 당신이 충돌 리포트를 보내거나, 또는 우리의 블로그에 글을 남길 때 어떤 데이터가 보내지고 저장되는지에 대해 상세히 설명합니다. 이 문서는 [여기](https://newpipe.net/legal/privacy/)에서 확인할 수 있습니다.
|
||||
|
||||
## License
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
NewPipe는 자유 소프트웨어입니다: 당신의 마음대로 이것을 사용하고, 연구하고, 공유하고, 개선할 수 있습니다.
|
||||
구체적으로 당신은 자유 소프트웨어 재단에서 발행되는, 버전 3 또는 (당신의 선택에 따라)이후 버전의,
|
||||
[GNU General Public License](https://www.gnu.org/licenses/gpl.html) 하에서 이것을 재배포 및/또는 수정할 수 있습니다.
|
|
@ -1,143 +0,0 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="../assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">Uma interface de streaming leve e gratuita para Android.</h4>
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-pt-br.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="GitHub release"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="Build Status"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/" alt="Translation Status"><img src="https://hosted.weblate.org/widgets/newpipe/-/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="IRC channel: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
<p align="center"><a href="#screenshots">Screenshots</a> • <a href="#description">Descrição</a> • <a href="#features">Características</a> • <a href="#updates">Atualizações</a> • <a href="#contribution">Contribuição</a> • <a href="#donate">Doar</a> • <a href="#license">Licença</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">Site</a> • <a href="https://newpipe.net/blog/">Blog</a> • <a href="https://newpipe.net/FAQ/">FAQ</a> • <a href="https://newpipe.net/press/">Press</a></p>
|
||||
<hr>
|
||||
|
||||
*Read this in other languages: [English](../README.md), [Español](README.es.md), [हिन्दी](README.hi.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md).*
|
||||
|
||||
<b>AVISO: ESTA É UMA VERSÃO BETA, PORTANTO, VOCÊ PODE ENCONTRAR BUGS. ENCONTROU ALGUM, ABRA UM ISSUE ATRAVÉS DO NOSSO REPOSITÓRIO GITHUB.</b>
|
||||
|
||||
<b>COLOCAR NEWPIPE OU QUALQUER FORK DELE NA GOOGLE PLAY STORE VIOLA SEUS TERMOS E CONDIÇÕES.</b>
|
||||
|
||||
## Screenshots
|
||||
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
## Descrição
|
||||
|
||||
O NewPipe não usa nenhuma biblioteca de framework do Google, nem a API do YouTube. Os sites são apenas analisados para obter informações necessárias, para que este aplicativo possa ser usado em dispositivos sem os serviços do Google instalados. Além disso, você não precisa de uma conta no YouTube para usar o NewPipe, que é um software livre com copyleft.
|
||||
|
||||
### Características
|
||||
|
||||
* Procurar vídeos
|
||||
* Exibir informações gerais sobre vídeos
|
||||
* Assista aos vídeos do YouTube
|
||||
* Ouça vídeos do YouTube
|
||||
* Modo popup (player flutuante)
|
||||
* Selecione o player para assistir streaming
|
||||
* Baixar vídeos
|
||||
* Baixar somente áudio
|
||||
* Abrir vídeo no Kodi
|
||||
* Mostrar vídeos próximos/relacionados
|
||||
* Pesquise no YouTube em um idioma específico
|
||||
* Assistir/Bloquear material restrito
|
||||
* Exibir informações gerais sobre canais
|
||||
* Pesquisar canais
|
||||
* Assista a vídeos de um canal
|
||||
* Suporte Orbot/Tor (ainda não diretamente)
|
||||
* Suporte 1080p/2K/4K
|
||||
* Ver histórico
|
||||
* Inscreva-se nos canais
|
||||
* Procurar histórico
|
||||
* Porcurar/Assistir playlists
|
||||
* Assistir playlists em fila
|
||||
* Vídeos em fila
|
||||
* Playlists Local
|
||||
* Legenda
|
||||
* Suporte a live
|
||||
* Mostrar comentários
|
||||
|
||||
### Serviços Suportados
|
||||
|
||||
O NewPipe suporta vários serviços. Nosso [documentação](https://teamnewpipe.github.io/documentation/) fornecer mais informações sobre como um novo serviço pode ser adicionado ao aplicativo e ao extrator. Por favor, entre em contato conosco se você pretende adicionar um novo. Atualmente, os serviços suportados são:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[beta\]
|
||||
* media.ccc.de \[beta\]
|
||||
* PeerTube instances \[beta\]
|
||||
* Bandcamp \[beta\]
|
||||
|
||||
## Atualizações
|
||||
Quando uma alteração no código NewPipe (devido à adição de recursos ou fixação de bugs), eventualmente ocorrerá uma versão. Estes estão no formato x.xx.x . A fim de obter esta nova versão, você pode:
|
||||
1. Construa um APK de depuração você mesmo. Esta é a maneira mais rápida de obter novos recursos em seu dispositivo, mas é muito mais complicado, por isso recomendamos usar um dos outros métodos.
|
||||
2. Adicione nosso repo personalizado ao F-Droid e instale-o a partir daí assim que publicarmos um lançamento. As instruções estão aqui.: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
|
||||
3. Baixe o APK do [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases) e instalá-lo assim que publicarmos um lançamento.
|
||||
4. Atualização via F-droid. Este é o método mais lento para obter atualizações, pois o F-Droid deve reconhecer alterações, construir o próprio APK, assiná-lo e, em seguida, enviar a atualização para os usuários.
|
||||
|
||||
Recomendamos o método 2 para a maioria dos usuários. Os APKs instalados usando o método 2 ou 3 são compatíveis entre si, mas não com aqueles instalados usando o método 4. Isso se deve à mesma chave de assinatura (nossa) sendo usada para 2 e 3, mas uma chave de assinatura diferente (F-Droid's) está sendo usada para 4. Construir um APK depuração usando o método 1 exclui totalmente uma chave. Assinar chaves ajudam a garantir que um usuário não seja enganado para instalar uma atualização maliciosa em um aplicativo.
|
||||
|
||||
Enquanto isso, se você quiser trocar de fontes por algum motivo (por exemplo, a funcionalidade principal do NewPipe foi quebrada e o F-Droid ainda não tem a atualização), recomendamos seguir este procedimento:
|
||||
1. Faça backup de seus dados através de Configurações > Conteúdo > Exportar Base de Dados para que você mantenha seu histórico, inscrições e playlists
|
||||
2. Desinstale o NewPipe
|
||||
3. Baixe o APK da nova fonte e instale-o
|
||||
4. Importe os dados da etapa 1 via Configurações > Conteúdo > Inportar Banco de Dados
|
||||
|
||||
## Contribuição
|
||||
Se você tem ideias, traduções, alterações de design, limpeza de códigos ou mudanças reais de código, a ajuda é sempre bem-vinda.
|
||||
Quanto mais for feito, melhor fica!
|
||||
|
||||
Se você quiser se envolver, verifique nossa [notas de contribuição](../.github/CONTRIBUTING.md).
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/-/287x66-grey.png" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
## Doar
|
||||
Se você gosta de NewPipe, ficaríamos felizes com uma doação. Você pode enviar bitcoin ou doar via Bountysource ou Liberapay. Para obter mais informações sobre como doar para a NewPipe, visite nosso [site](https://newpipe.net/donate).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="../assets/bitcoin_qr_code.png" alt="Bitcoin QR code" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="../assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="../assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="../assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn."></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Política de Privacidade
|
||||
|
||||
O projeto NewPipe tem como objetivo proporcionar uma experiência privada e anônima para o uso de serviços web de mídia.
|
||||
Portanto, o aplicativo não coleta nenhum dado sem o seu consentimento. A política de privacidade da NewPipe explica em detalhes quais dados são enviados e armazenados quando você envia um relatório de erro ou comenta em nosso blog. Você pode encontrar o documento [aqui](https://newpipe.net/legal/privacy/).
|
||||
|
||||
## Licença
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
NewPipe é Software Livre: Você pode usar, estudar compartilhamento e melhorá-lo à sua vontade.
|
||||
Especificamente, você pode redistribuir e/ou modificá-lo sob os termos do
|
||||
[GNU General Public License](https://www.gnu.org/licenses/gpl.html) publicado pela Free Software Foundation, seja a versão 3 da Licença, ou
|
||||
(a sua opção) qualquer versão posterior.
|
145
doc/README.ro.md
145
doc/README.ro.md
|
@ -1,145 +0,0 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="../assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">Un front-end de streaming „uşor” liber, pentru Android.</h4>
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-ro.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="GitHub release"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="License: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="Build Status"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/" alt="Translation Status"><img src="https://hosted.weblate.org/widgets/newpipe/-/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="IRC channel: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource bounties"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
<p align="center"><a href="#screenshots">Capturi de ecran</a> • <a href="#description">Descriere</a> • <a href="#features">Funcţii</a> • <a href="#installation-and-updates">Instalare şi actualizări</a> • <a href="#contribution">Contribuţie</a> • <a href="#donate">Donaţi</a> • <a href="#license">Licenţă</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">Website</a> • <a href="https://newpipe.net/blog/">Blog</a> • <a href="https://newpipe.net/FAQ/">FAQ</a> • <a href="https://newpipe.net/press/">Presă</a></p>
|
||||
<hr>
|
||||
|
||||
*Citiţi în alte limbi: [English](../README.md), [Español](README.es.md), [हिन्दी](README.hi.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md).*
|
||||
|
||||
<b>Atenţionare: ACEASTA ESTE O VERSIUNE BETA, AŞA CĂ S-AR PUTE SĂ ÎNTÂLNIŢI ERORI. DACĂ SE ÎNTÂMPLĂ ACEST LUCRU, DESCHIDEŢI UN ISSUE PRIN REPSITORY-UL NOSTRU GITHUB.</b>
|
||||
|
||||
<b>PUNERA NEWPIPE SAU ORICĂRUI FORK AL ACESTUIA ÎN MAGAZINUL GOOGLE PLAY LE ÎNCALCĂ TERMENII ŞI CONDIŢIILE.</b>
|
||||
|
||||
## Capturi de ecran
|
||||
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
## Descriere
|
||||
|
||||
NewPipe nu foloseşte nici-o bibliotecă Google framework sau API-ul Youtube. Website-urile sunt doar analizate pentru a prelua informaţia necesară, aşa că această aplicaţie poate fi folosită pe telefoane fără Serviciile Google instalate. De asemenea, nu aveţi nevoie de un cont Youtube pentru a folosi Newpipe, care este sofware liber şi copylefted.
|
||||
|
||||
### Funcţii
|
||||
|
||||
* Căutarea videoclipurilor
|
||||
* Nu este necesară logarea
|
||||
* Afişarea informaţiilor generale despre videoclipuri
|
||||
* Urmărirea videoclipurilor Youtube
|
||||
* Ascultarea videoclipurilor Youtube
|
||||
* Modul popup (player plutitor)
|
||||
* Selectarea playerului de streaming pentru vizionarea videoclipului
|
||||
* Descărcarea videoclipurilor
|
||||
* Doar descărcarea sunetului
|
||||
* Deschiderea videoclipurilor cu Kodi
|
||||
* Expunerea videoclipurilor următoare/asociate
|
||||
* Căutarea YouTube într-o limbă specifică
|
||||
* Vizionarea/Blocarea materialului restricţionat în funcţie de vârstă
|
||||
* Afişarea informaţiilor generale despre canale
|
||||
* Căutarea canalelor
|
||||
* Vizionarea videoclipurilor dintr-un canal
|
||||
* Suport Orbot/Tor (încă nu direct)
|
||||
* Suport 1080p/2K/4K
|
||||
* Vizionarea istoricului
|
||||
* Abonarea la canale
|
||||
* Căutarea în istoric
|
||||
* Căutarea/vizionarea playlisturilor
|
||||
* Vizionarea ca playlisturi puse în coadă
|
||||
* Punerea în coadă a videoclipurilor
|
||||
* Playlisturi locale
|
||||
* Subtitrări
|
||||
* Suport al transmiterilor live
|
||||
* Afişarea comentariilor
|
||||
|
||||
### Servicii întreţinute
|
||||
|
||||
NewPipe suportă servicii multiple. [Documentele](https://teamnewpipe.github.io/documentation/) noastre furnizează mai multe informaţii în legătură cu modalităţile prin care un nou serviciu poate fi adăugat aplicaţiei şi extractorului. Vă rugăm să ne contactaţi dacă doriţi să adăugaţi unul nou. Serviciile întreţinute acum sunt:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[beta\]
|
||||
* media.ccc.de \[beta\]
|
||||
* Instanţe PeerTube \[beta\]
|
||||
* Bandcamp \[beta\]
|
||||
|
||||
<!-- Hidden span to keep old links compatible. -->
|
||||
<span id="updates"></span>
|
||||
|
||||
## Instalare şi actualizări
|
||||
Puteţi instala NewPipe folosind una dintre următoarele metode:
|
||||
1. Adăugaţi depozitul nostru F-droid personalizat. Instrucţiunile sunt aici: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
|
||||
2. Descărcaţi APK-ul din [GitHub Releases](https://github.com/TeamNewPipe/NewPipe/releases) şi instalaţi-l.
|
||||
3. Actualizaţi via F-Droid. Aceasta este cea mai lentă metodă de a obţine actualizări, deoarece F-Droid trebuie să recunoască schimbările, să constriască APK-ul, să îl semneze, iar apoi să îl trimită utilizatorilor.
|
||||
4. Construiţi un APK de depanare. Aceasta este cea mai rapidă metodă de a primi funcţii noi, dar este mult mai complicată, aşa că vă recomandăm să folosiţi una dintre celelalte metode.
|
||||
|
||||
Recomandăm metoda 1 pentru majoritatea utilizatorilor. APK-urile din metodele 1 şi 2 suntcompatibile una cu cealaltă, dar nu cu cele din metoda 3. Acest lucru se datorează faptului că aceeași cheie de semnare (a noastră) este utilizată pentru 1 și 2, dar o altă cheie de semnare (F-Droid) este utilizată pentru 3. Construirea unui APK de depanare folosind metoda 4 exclude o cheie în întregime. Cheile de semnare vă asigură că un utilizator nu este păcălit să instaleze o actualizare rău intenționată a unei aplicații.
|
||||
|
||||
Între timp, dacă doriți să schimbați sursa dintr-un anumit motiv (de exemplu, funcționalitatea de bază a NewPipe a fost întreruptă și F-Droid nu are încă actualizarea), vă recomandăm să folosiţi următoarea procedură:
|
||||
1. Faceți o copie de rezervă a datelor prin Setări> Conținut> Exportați baza de date, astfel încât să vă păstrați istoricul, abonamentele și playlisturile
|
||||
2. Dezinstalaţi NewPipe
|
||||
3. Descărcaţi APK-ul din noua sursă şi instalaţi-l
|
||||
4. Importați datele de la pasul 1 prin Setări> Conținut> Importare bază de date
|
||||
|
||||
## Contribuţie
|
||||
Dacă aveţi idei, traduceri, schimbări de design, curaţarea codului, sau schimbări majore ale codului, ajutorul este întotdeauna binevenit.
|
||||
Cu cât se face mai mult cu atât mai bună devine aplicaţia!
|
||||
|
||||
Dacă doriţi să vă implicaţi, accesaţi [notele noastre de contribuţie](../.github/CONTRIBUTING.md).
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/-/287x66-grey.png" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
## Donaţii
|
||||
Dacă vă place NewPipe, am fi bucuroşi să primim o donaţie. Puteţi să ne trimiteţi bitcoin sau să ne donaţi cu Bountysource sau Liberapay. Pentru mai multe informaţii în legătură cu donaţiile către NewPipe, vă rugăm vizitaţi [website-ul nostru](https://newpipe.net/donate).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="../assets/bitcoin_qr_code.png" alt="Bitcoin QR code" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="../assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="../assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="../assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn."></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Politica de Confidenţialitate
|
||||
|
||||
Proiectul NewPipe îşi propune să furnizeze o experienţă privată şi anonimă pentru utilizarea serviciilor web media.
|
||||
Prin urmare, aplicaţia nu colectează niciun fel de informaţii fără acordul dumneavoastră. Politica de confidențialitate a NewPipe explică în detaliu ce date sunt trimise și stocate atunci când trimiteți un raport de blocare sau comentați pe blogul nostru. Puteți găsi documentul [aici](https://newpipe.net/legal/privacy/).
|
||||
|
||||
## Licenţă
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
NewPipe este Software Gratuit: Îl puteţi folosi şi împărtăşi cum doriţi. Mai exact, îl puteți redistribui și / sau modifica în conformitate cu termenii
|
||||
[GNU General Public License](https://www.gnu.org/licenses/gpl.html) aşa cum a fost publicat de Free Software Foundation, fie versiunea 3 a Licenței, fie
|
||||
(la alegerea dvs.) orice versiune ulterioară.
|
138
doc/README.so.md
138
doc/README.so.md
|
@ -1,138 +0,0 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="../assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">App bilaash ah oo fudud looguna talagalay in Android-ka wax loogu daawado.</h4>
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-so.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="Siidaynta GitHub "><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="Laysinka: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="Darajada Dhismaha"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/" alt="Heerka Turjimaada"><img src="https://hosted.weblate.org/widgets/newpipe/-/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="Kanaalka IRC: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Kuwa Bountysource "><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
<p align="center"><a href="#sawir-shaashadeed">Sawir-shaashadeed</a> • <a href="#faahfaahin">Faahfaahin</a> • <a href="#waxqabadka">Waxqabadka</a> • <a href="#kushubida-iyo-cusboonaysiinta">Kushubida iyo cusboonaysiinta</a> • <a href="#kusoo-kordhin">Kusoo Kordhin</a> • <a href="#ugu-deeq">Ugu Deeq</a> • <a href="#laysinka">Laysinka</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">Website-ka</a> • <a href="https://newpipe.net/blog/">Maqaalada</a> • <a href="https://newpipe.net/FAQ/">Su'aalaha Aalaa La-iswaydiiyo</a> • <a href="https://newpipe.net/press/">Warbaahinta</a></p>
|
||||
<hr>
|
||||
|
||||
*Ku akhri luuqad kale: [English](../README.md), [Español](README.es.md), [हिन्दी](README.hi.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md).*
|
||||
|
||||
<b>DIGNIIN: MIDKAN, NOOCA APP-KA EE HADDA WALI TIJAABO AYUU KU JIRAA, SIDAA DARTEED CILLADO AYAAD LA KULMI KARTAA. HADAAD LA KULANTO, KA FUR ARIN SHARAXAYA QAYBTANADA ARRIMAHA EE GITHUB-KA.</b>
|
||||
|
||||
<b>NEWPIPE AMA KUWA KU SALAYSAN IN PLAYSTORE-KA LA GALIYO WAXAY KA HOR IMANAYSAA SHARCIGA IYO SHURUUDAHA AY LEEYIHIIN.</b>
|
||||
|
||||
## Sawir-shaashadeed
|
||||
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
## Faahfaahin
|
||||
|
||||
NewPipe ma isticmalo nidaamka wada shaqaynta Google, ama API-ga YouTube. Kaliya website-yada ayaa la furaa si xogta loo baahanyahay loogala soo dhex baxo, App-kan waxaa lagu isticmaali karaa aaladaha aysa ku jirin Adeegyada Google. Sidoo kale, uma baahnid akoon YouTube ah si aad u isticmaasho NewPipe, kaasoo ah barnaamij bilaash ah.
|
||||
|
||||
### Waxqabadka
|
||||
|
||||
* Raadi muuqaalo
|
||||
* Soo bandhiga faahfaahin guud oo muuqaalada ku saabsan
|
||||
* Ku daawo muuqaalada YouTube
|
||||
* Dhagayso muuqaalada YouTube
|
||||
* Qaab daaqad ah (muuqaal daare yar oo application-nada dul fuula)
|
||||
* Dooro muuqaal daareha aad rabto inaad wax ku daawato
|
||||
* Daji muuqaalada
|
||||
* Daji dhagaysiga kaliya (cod)
|
||||
* Ku fur muuqaal Kodi
|
||||
* Tus muuqaalada ka xiga/kuwa lamidka ah
|
||||
* Inaad luuqada aad rabto wax kaga dhex raadiso YouTube
|
||||
* Daawo/xanib muuqaalada da'da ku xidhan
|
||||
* Soo bandhig xog guud oo ku saabsan kanaalada
|
||||
* Raadi kanaalo
|
||||
* Daawo muuqaalada kanaal
|
||||
* Taageerida Orbot/Tor (wali toos ma aha)
|
||||
* Taageerida muuqaalada 1080p/2K/4K
|
||||
* Kaydka wixii hore [aad u daawatay]
|
||||
* Inaad rukumato kanaalada
|
||||
* Kaydinta waxaad raadisay
|
||||
* Raadi/daawo xulalka
|
||||
* U daawo sidii xulal la horay
|
||||
* Hormo gali muuqaalada
|
||||
* Xulal gudaha [aalada] ah
|
||||
* Qoraal-hooseed
|
||||
* Taageerida waxyaabaha tooska ah
|
||||
* Soo bandhiga faalooyinka
|
||||
|
||||
### Adeegyada la Taageero
|
||||
|
||||
NewPipe wuxuu taageeraa adeegyo badan. [warqadan](https://teamnewpipe.github.io/documentation/) ayaa si faahfaahsan u sharaxaysa sida adeeg cusub loogu soo dari lahaa iyo kala fur-furaha. Fadlan nala soo xidhiidh hadaad rabto inaad mid cusub kusoo darto. Adeegyada aan hadda taageero waxaa kamid ah:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[tijaabo\]
|
||||
* media.ccc.de \[tijaabo\]
|
||||
* PeerTube instances \[tijaabo\]
|
||||
* Bandcamp \[tijaabo\]
|
||||
|
||||
## Kushubida iyo cusboonaysiinta
|
||||
Marka koodhka NewPipe isbadal ku dhaco (wax cusub oo lagusoo kordhiyay ama cilad bixin), ugu dambayn waxaa lasii daayaa mid cusub (Siidayn). Siidaynta qaabkeedu waa x.xx.x . Si aad midka cusub u hesho, waxaad samayn kartaa:
|
||||
1. Inaad mid cusub (APK) adigu dhisato. Tani waa mida ugu dagdag badan eed waxyaabaha cusub ku heli karto, laakiin way adagtahay, sidaa darteed waxaan soojeedinaynaa inaad isticmaasho qababka kale.
|
||||
2. Ku dar qayb gaar ah xaganaga F-Droid oo xagaas kaga shub isla markay siidayn soobaxdo. Hagitaanka xagan ka eeg: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
|
||||
3. Kasoo dajiso APK-ga xaga [Siidaynta GitHub](https://github.com/TeamNewPipe/NewPipe/releases) oo ku shubo isla markay siidayn soobaxdo.
|
||||
4. Ka cusboonaysii xaga F-Droid. Tani waa mida ugu daahitaanka badan, sababtoo ah F-Droid waxay fiirin isbadalka waxayna iyadu dhisi mid (app), sixiixi, kadibna ay cusboonaysiinta usiidayn isticmaalayaasha.
|
||||
|
||||
Waxaan usoojeedinaynaa isticmaaalka qaabka 2 dadka badankood. APK-yada loogu shubo qaabka 2 ama 3 way isqaadan karaan, laakiin isma qaadan karaan kuwa loogu shubay qaabka 4. Sababtuna waxaa weeye furaha sixiixa oo iskumid ah (kaanaga weeye) oo loo isticmaalay 2 iyo 3, laakiin furo sixiixeed ka duwan (midka F-Droid) oo loo isticmaalay 4. Dhisida APK ayadoo la isticmaalayo qaabka 1 waxay gabi ahaanba ka reebtaa wax fure ah. Furayaasha sixiixa waxay xaqiijiyaan in isticmaalaha aan lagu khaldin inuu ku shubto cusboonaysiin khalad ah (wax lasoo dhexraaciyay) app-ka.
|
||||
|
||||
Waxaa kale, hadaad rabto inaad tixraacayada kala badasho sabab jirta awgeed (tusaale shaqaynta aasaasiga ah ee NewPipe ayaa khalkhashay F-Droid-na wali cusboonysiin ma hayo), waxaan soojeedinaynaa isticmaalka qaabkan:
|
||||
1. Xogtaada koobi ka samee adoo raacaya Fadhiga > Luuqada & Fadhiga Kale > Gudbi Xog Diyaaran si aysa kaaga bixin kaydka wixii hore, rukunka, iyo xulalka
|
||||
2. Saar NewPipe
|
||||
3. Kasoo daji APK-ga tixraaca cusub oo ku shub
|
||||
4. Kasoo gali xogta talaabada 1 xaga Fadhiga > Luuqada & Fadhiga Kale > Soo Gali Xog Kaydsan
|
||||
|
||||
## Kusoo Kordhin
|
||||
Hadaad hayso fikrado; rogid, qaab badal, nadiifin koodh, ama koodhka ood si wayn wax oga badashaa—caawinta marwalba waa lasoo dhawaynayaa. Waxbadan hadii la qabto waxbadan ayaa fiicnaan!
|
||||
|
||||
Hadaad jeceshahay inaad qayb ka noqoto, fiiri [ogaysiisyada kusoo kordhinta](../.github/CONTRIBUTING.md).
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/-/287x66-grey.png" alt="Heerka turjimaada" />
|
||||
</a>
|
||||
|
||||
## Ugu Deeq
|
||||
Hadaad jeceshahay NewPipe waan ku faraxsanaan lahayn deeq. Waxaad soo diri kartaa bitcoin ama sidoo kale waxaad deeqda kusoo diri kartaa xaga Bountysource ama Liberapay. Faahfaahin dheeraad ah oo kusaabsan ugu deeqida NewPipe, fadlan booqo [website-kanaga](https://newpipe.net/donate).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="../assets/bitcoin_qr_code.png" alt="Bitcoin QR code" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="../assets/liberapay_qr_code.png" alt="Visit NewPipe at liberapay.com" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="../assets/liberapay_donate_button.svg" alt="Donate via Liberapay" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="../assets/bountysource_qr_code.png" alt="Visit NewPipe at bountysource.com" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Check out how many bounties you can earn."></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Siyaasada Sirdhawrka
|
||||
|
||||
Mashruuca NewPipe waxay ujeedadiisu tahay inuu bixiyo wax kuu gaar ah, oo adoon shaqsi ahaan laguu aqoonsan aad isticmaasho website-yada wax laga daawado/dhagaysto.
|
||||
Sidaa darteed, app-ku wax xog ah ma uruuriyo fasaxaaga la'aantii. Siyaasada Sirdhawrka NewPipe ayaa si faahfaahsan u sharaxda waxii xog ah ee la diro markaad cillad wariso, ama aad bogganaga faallo ka dhiibato. Warqada waxaad ka heli kartaa [halkan](https://newpipe.net/legal/privacy/).
|
||||
|
||||
## Laysinka
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
NewPipe waa barnaamij bilaash ah oon lahayn xuquuqda daabacaada: Waad isticmaali kartaa, waad wadaagi kartaa waadna hormarin kartaa hadaad rabto. Gaar ahaan waad sii daabici kartaa ama wax baad ka badali kartaa ayadoo la raacayo shuruudaha sharciga guud ee [GNU](https://www.gnu.org/licenses/gpl.html) sida ay soosaareen Ururka Barnaamijyada Bilaashka ah, soosaarista 3aad ee laysinka, ama (hadaad doonto) nooc walba oo kasii dambeeyay laysinkii 3aad.
|
145
doc/README.tr.md
145
doc/README.tr.md
|
@ -1,145 +0,0 @@
|
|||
<p align="center"><a href="https://newpipe.net"><img src="../assets/new_pipe_icon_5.png" width="150"></a></p>
|
||||
<h2 align="center"><b>NewPipe</b></h2>
|
||||
<h4 align="center">Android için hafif ve özgür bir akış arayüzü.</h4>
|
||||
|
||||
<p align="center"><a href="https://f-droid.org/packages/org.schabi.newpipe/"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-tr.svg" alt="Get it on F-Droid" height=80/></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/releases" alt="GitHub sürümleri"><img src="https://img.shields.io/github/release/TeamNewPipe/NewPipe.svg" ></a>
|
||||
<a href="https://www.gnu.org/licenses/gpl-3.0" alt="Lisans: GPLv3"><img src="https://img.shields.io/badge/License-GPL%20v3-blue.svg"></a>
|
||||
<a href="https://github.com/TeamNewPipe/NewPipe/actions" alt="Derleme Durumu"><img src="https://github.com/TeamNewPipe/NewPipe/workflows/CI/badge.svg?branch=dev&event=push"></a>
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/" alt="Çeviri Durumu"><img src="https://hosted.weblate.org/widgets/newpipe/-/svg-badge.svg"></a>
|
||||
<a href="https://web.libera.chat/#newpipe" alt="IRC kanalı: #newpipe"><img src="https://img.shields.io/badge/IRC%20chat-%23newpipe-brightgreen.svg"></a>
|
||||
<a href="https://www.bountysource.com/teams/newpipe" alt="Bountysource ödülleri"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f"></a>
|
||||
</p>
|
||||
<hr>
|
||||
<p align="center"><a href="#ekran-fotoğrafları">Ekran fotoğrafları</a> • <a href="#açıklama">Açıklama</a> • <a href="#özellikler">Özellikler</a> • <a href="#kurulum-ve-güncellemeler">Kurulum ve güncellemeler</a> • <a href="#katkıda-bulunma">Katkıda bulunma</a> • <a href="#bağış">Bağış</a> • <a href="#lisans">Lisans</a></p>
|
||||
<p align="center"><a href="https://newpipe.net">Web sitesi</a> • <a href="https://newpipe.net/blog/">Blog</a> • <a href="https://newpipe.net/FAQ/">SSS</a> • <a href="https://newpipe.net/press/">Basın</a></p>
|
||||
<hr>
|
||||
|
||||
*Bu sayfayı diğer dillerde okuyun: [English](../README.md), [Español](README.es.md), [हिन्दी](README.hi.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [Polski](README.pl.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md), [正體中文](README.zh_TW.md).*
|
||||
|
||||
<b>UYARI: BU SÜRÜM BETA SÜRÜMÜDÜR, BU NEDENLE HATALARLA KARŞILAŞABİLİRSİNİZ. HATA BULURSANIZ BU GITHUB DEPOSUNDA BUNU BİLDİRİN.</b>
|
||||
|
||||
<b>GOOGLE PLAY STORE'A NEWPIPE VEYA BAŞKA BİR KOPYASINI KOYMAK, PLAY STORE ŞARTLARINI VE KOŞULLARINI İHLAL EDER.</b>
|
||||
|
||||
## Ekran görüntüleri
|
||||
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_01.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_02.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_03.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_04.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_05.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_06.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_07.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_08.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_09.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](../fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
|
||||
[<img src="../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png" width=405>](../fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
|
||||
|
||||
## Açıklama
|
||||
|
||||
NewPipe herhangi bir Google çerçeve kütüphanesini, ya da YouTube API hizmetlerini kullanmaz. Gerekli web hizmetleri yalnızca gerekli bilgileri almak için kaynak olarak kullanılır, bu nedenle bu uygulama Google hizmetleri yüklü olmayan cihazlarda da kullanılabilir. Ayrıca, copyleft özgür yazılımı olan NewPipe'ı kullanmak için bir YouTube hesabına ihtiyacınız yoktur.
|
||||
|
||||
### Özellikler
|
||||
|
||||
* Video arama
|
||||
* Videolar hakkında genel bilgileri görüntüleme
|
||||
* YouTube videoları izleme
|
||||
* YouTube videolarını dinleme
|
||||
* Pop-up modu (hareketli oynatıcı)
|
||||
* Video izlemek için akış oynatıcısını seçme
|
||||
* Video indirme
|
||||
* Sadece ses indirme
|
||||
* Videoyu Kodi'de açma
|
||||
* Sonraki video/ilgili videolar
|
||||
* YouTube'u belirli bir dilde arayın
|
||||
* Yaş sınırlı içeriği izleme/engelleme
|
||||
* Kanallar hakkındaki genel bilgileri görüntüleme
|
||||
* Kanal arama
|
||||
* Bir kanaldaki videoları izleme
|
||||
* Orbot/Tor desteği (henüz direkt olarak değil)
|
||||
* 1080p/2K/4K desteği
|
||||
* Geçmişi görme
|
||||
* Kanallara abone olma
|
||||
* Geçmişte arama
|
||||
* Oynatma listesi arama/oynatma
|
||||
* Çalma listelerini sıralayıp oynatın
|
||||
* Videoları sırayla oynatın
|
||||
* Yerel oynatma listeleri
|
||||
* Altyazılar
|
||||
* Canlı yayın desteği
|
||||
* Yorumları görme
|
||||
|
||||
### Desteklenen servisler
|
||||
|
||||
NewPipe birden fazla hizmeti destekler. Uygulamaya ve ayıklayıcıya yeni bir hizmet ekleme konusunda daha fazla bilgiye [kılavuzlarımızdan](https://teamnewpipe.github.io/documentation/) ulaşabilirsiniz. Yeni bir hizmet eklemek istiyorsanız lütfen bizimle iletişime geçin. Şu anda desteklenen hizmetler şunlardır:
|
||||
|
||||
* YouTube
|
||||
* SoundCloud \[beta\]
|
||||
* media.ccc.de \[beta\]
|
||||
* PeerTube \[beta\]
|
||||
* Bandcamp \[beta\]
|
||||
|
||||
<!-- Eski bağlantıları uyumlu tutmak için gizli span. -->
|
||||
<span id="updates"></span>
|
||||
|
||||
## Kurulum ve güncellemeler
|
||||
Aşağıdaki yöntemlerden birini kullanarak NewPipe'ı kurabilirsiniz:
|
||||
1. Özel depomuzu F-Droid'e ekleyin ve oradan yükleyin. Kılavuzu şurada bulabilirsiniz: https://newpipe.net/FAQ/tutorials/install-add-fdroid-repo/
|
||||
2. APK'yı [GitHub sürümlerinden](https://github.com/TeamNewPipe/NewPipe/releases) indirin ve kurun.
|
||||
3. F-Droid ile güncelleyin. Bu, güncellemeleri almanın en yavaş yöntemidir, çünkü F-Droid değişiklikleri tanımalı, APK'yı kendisi oluşturmalı, imzalamalı ve ardından güncellemeyi kullanıcılara dağıtmalıdır.
|
||||
4. Kendiniz bir APK derleyin. Bu yöntem, cihazınızda yeni özellikler edinmenin en hızlı yoludur, ancak çok daha karmaşıktır, bu nedenle diğer yöntemlerden birini kullanmanızı öneririz.
|
||||
|
||||
Çoğu kullanıcı için yöntem 1'i öneririz. Yöntem 1 veya 2 kullanılarak yüklenen APK'lar birbiriyle uyumludur, ancak yöntem 3 kullanılarak yüklenenlerle uyumlu değildir. Bu durum, 1 ve 2 için kullanılan aynı imzalama anahtarıın (bizim anahtarımız) 3 için kullanılan imzalama anahtarından (F-Droid'in anahtarı) farklı olmasından kaynaklanmaktadır. Yöntem 4 kullanılarak oluşturulan deneysel APK'larda anahtar yoktur. İmzalama anahtarları, bir kullanıcının bir uygulamaya kötü amaçlı bir güncelleme yüklemek için kandırılmadığından emin olmanıza yardımcı olur.
|
||||
|
||||
Bu arada, herhangi bir nedenle kaynakları değiştirmek istiyorsanız (örneğin, NewPipe'ın temel bir işlevi bozuldu ve F-Droid tarafında henüz bir güncelleme yayınlanmadı), bu prosedürü izlemenizi öneririz:
|
||||
1. Verilerinizi yedekleyin. `NewPipe Ayarları > İçerik > Veritabanını dışa aktar` seçeneklerini izleyerek aboneliklerinizi, oynatma listelerinizi ve geçmişinizi yedekleyin.
|
||||
2. NewPipe'ı kaldırın
|
||||
3. APK dosyasını yeni bir kaynaktan indirin ve yükleyin
|
||||
4. `Ayarlar > İçerik > Veritabanını içe aktar` seçeneklerini izleyerek 1. adımdaki verileri içe aktarın
|
||||
|
||||
## Katkıda bulunma
|
||||
Fikirleriniz, çevirileriniz, tasarım değişiklikleriniz, kod temizlemeniz veya ağır kod değişiklikleriniz olsun, yardımınıza her zaman açığız.
|
||||
Yapılan her değişiklikle NewPipe daha da iyi bir konuma geliyor!
|
||||
|
||||
Eğer yer almak istiyorsanız, [katkı sağlayanlar için hazırladığımız notları](../.github/CONTRIBUTING.md) kontrol edin.
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/newpipe/">
|
||||
<img src="https://hosted.weblate.org/widgets/newpipe/-/287x66-grey.png" alt="Çeviri istatistikleri" />
|
||||
</a>
|
||||
|
||||
## Bağış
|
||||
NewPipe'ı beğendiyseniz, yapacağınız bağışlar bizi motive eder. Bitcoin gönderebilir veya Bountysource veya Liberapay aracılığıyla bağış yapabilirsiniz. NewPipe'a bağış yapma hakkında daha fazla bilgi için lütfen [web sitemizi](https://newpipe.net/donate) ziyaret edin.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://bitcoin.org/img/icons/logotop.svg" alt="Bitcoin"></td>
|
||||
<td><img src="../assets/bitcoin_qr_code.png" alt="Bitcoin QR kodu" width="100px"></td>
|
||||
<td><samp>16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh</samp></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="https://upload.wikimedia.org/wikipedia/commons/2/27/Liberapay_logo_v2_white-on-yellow.svg" alt="Liberapay" width="80px" ></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/"><img src="../assets/liberapay_qr_code.png" alt="liberapay.com üzerinde NewPipe'ı ziyaret edin" width="100px"></a></td>
|
||||
<td><a href="https://liberapay.com/TeamNewPipe/donate"><img src="../assets/liberapay_donate_button.svg" alt="Liberapay aracılığıyla bağış yapın" height="35px"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/22/Bountysource.png/320px-Bountysource.png" alt="Bountysource" width="190px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe"><img src="../assets/bountysource_qr_code.png" alt="bountysource.com üzerinde NewPipe'ı ziyaret edin" width="100px"></a></td>
|
||||
<td><a href="https://www.bountysource.com/teams/newpipe/issues"><img src="https://img.shields.io/bountysource/team/newpipe/activity.svg?colorB=cd201f" height="30px" alt="Ne kadar ödül kazanabileceğinizi kontrol edin."></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Gizlilik politikası
|
||||
|
||||
NewPipe projesi, çevrimiçi akış hizmetlerini kullanmak için özel, özgür ve anonim bir deneyim sunmayı amaçlamaktadır.
|
||||
Bu doğrultuda, uygulama sizin izniniz olmadan herhangi bir veri toplamaz. NewPipe'ın Gizlilik Politikası, bir çökme raporu gönderdiğinizde veya blogumuzda yorum yaptığınızda hangi verilerin gönderildiğini ve saklandığını ayrıntılı olarak açıklar. İlgili belgeyi [burada](https://newpipe.net/legal/privacy/) bulabilirsiniz.
|
||||
|
||||
## Lisans
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
NewPipe özgür bir yazılımdır. Kendi başınıza kullanabilir, öğrenebilir, paylaşabilir
|
||||
ve geliştirebilirsiniz. Free Software Foundation tarafından yayınlanan GNU Genel Kamu Lisansı,
|
||||
Lisansın 3. sürümü veya (isteğe bağlı olarak) daha sonraki bir sürümü şartları ve
|
||||
koşulları altında yeniden dağıtabilir ve/veya değiştirebilirsiniz.
|
|
@ -1 +1,3 @@
|
|||
NewPipe verwendet keine Bibliotheken des Google-Frameworks oder der YouTube-API. Es analysiert die Website, um die benötigten Informationen zu erlangen. Aus diesem Grund kann die App ohne die Google Services verwendet werden. Ebenso wird kein YouTube-Konto für NewPipe benötigt und es ist FLOSS (Freie Software / Open-Source-Software).
|
||||
<i>NewPipe x SponsorBlock</i> ist ein Fork von <a href='https://github.com/TeamNewPipe/NewPipe' target='_blank' rel='nofollow'>NewPipe</a>, der um <a href='https://sponsor.ajay.app/' target='_blank' rel='nofollow'>SponsorBlock</a>-Funktionalität erweitert wurde – d. h. die App hat die Fähigkeit, Sponsor-Segmente in YouTube Videos zu überspringen. Dies basiert auf Crowd-Sourcing.
|
||||
|
||||
<i>NewPipe</i> verwendet keine Bibliotheken des Google-Frameworks oder der YouTube-API. Es analysiert die Webseite, um die benötigten Informationen zu erlangen. Aus diesem Grund kann die App ohne die Google Services verwendet werden. Ebenso wird kein YouTube-Konto für NewPipe benötigt und es ist FLOSS (Freie Software / Open-Source-Software).
|
||||
|
|
|
@ -1 +1 @@
|
|||
Eine freie, leichtgewichtige YouTube-App für Android.
|
||||
Eine freie, leichtgewichtige YouTube-App mit SponsorBlock-Fähigkeiten
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
NewPipe does not use any Google framework libraries, or the YouTube API. It only parses the website in order to gain the information it needs. Therefore this app can be used on devices without Google Services installed. Also, you don't need a YouTube account to use NewPipe, and it's FLOSS.
|
||||
<i>NewPipe x SponsorBlock</i> is a fork of <a href='https://github.com/TeamNewPipe/NewPipe' target='_blank' rel='nofollow'>NewPipe</a> with <a href='https://sponsor.ajay.app/' target='_blank' rel='nofollow'>SponsorBlock</a> functionality – i.e. it has the ability to skip sponsor segments in YouTube videos, which is a crowd-sourced effort.
|
||||
|
||||
<i>NewPipe</i> does not use any Google framework libraries, or the YouTube API. It only parses the website in order to gain the information it needs. Therefore this app can be used on devices without Google Services installed. Also, you don't need a YouTube account to use NewPipe, and it's FLOSS.
|
||||
|
|
|
@ -1 +1 @@
|
|||
A free lightweight YouTube frontend for Android.
|
||||
A free lightweight YouTube frontend for Android with SponsorBlock capabilities
|
||||
|
|
Loading…
Add table
Reference in a new issue