mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 23:03:00 +00:00 
			
		
		
		
	| @@ -84,6 +84,7 @@ NewPipe は複数のサービスに対応しています。[ドキュメント]( | ||||
| * SoundCloud \[ベータ\] | ||||
| * media.ccc.de \[ベータ\] | ||||
| * PeerTube インスタンス \[ベータ\] | ||||
| * Bandcamp \[ベータ\] | ||||
|  | ||||
| <!-- Hidden span to keep old links compatible. --> | ||||
| <span id="updates"></span> | ||||
|   | ||||
| @@ -79,6 +79,7 @@ NewPipe는 여러가지 서비스를 지원합니다. 우리의 [문서](https:/ | ||||
| * SoundCloud \[beta\] | ||||
| * media.ccc.de \[beta\] | ||||
| * PeerTube instances \[beta\] | ||||
| * Bandcamp \[beta\] | ||||
|  | ||||
| ## Updates | ||||
| NewPipe 코드의 변경이 있을 때(기능 추가 또는 버그 수정으로 인해), 결국 릴리즈가 발생할 것입니다. 이것들의 형식은 x.xx.x 입니다.  | ||||
|   | ||||
| @@ -81,6 +81,7 @@ NewPipe supports multiple services. Our [docs](https://teamnewpipe.github.io/doc | ||||
| * SoundCloud \[beta\] | ||||
| * media.ccc.de \[beta\] | ||||
| * PeerTube instances \[beta\] | ||||
| * Bandcamp \[beta\] | ||||
|  | ||||
| <!-- Hidden span to keep old links compatible. --> | ||||
| <span id="updates"></span> | ||||
|   | ||||
| @@ -79,6 +79,7 @@ O NewPipe suporta vários serviços. Nosso [documentação](https://teamnewpipe. | ||||
| * 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: | ||||
|   | ||||
| @@ -81,6 +81,7 @@ NewPipe suportă servicii multiple. [Documentele](https://teamnewpipe.github.io/ | ||||
| * SoundCloud \[beta\] | ||||
| * media.ccc.de \[beta\] | ||||
| * Instanţe PeerTube \[beta\] | ||||
| * Bandcamp \[beta\] | ||||
|  | ||||
| <!-- Hidden span to keep old links compatible. --> | ||||
| <span id="updates"></span> | ||||
|   | ||||
| @@ -79,6 +79,7 @@ NewPipe wuxuu taageeraa adeegyo badan. [warqadan](https://teamnewpipe.github.io/ | ||||
| * 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: | ||||
|   | ||||
| @@ -180,7 +180,7 @@ dependencies { | ||||
|  | ||||
|     // NewPipe dependencies | ||||
|     // You can use a local version by uncommenting a few lines in settings.gradle | ||||
|     implementation "com.github.TeamNewPipe:NewPipeExtractor:7e6f464407fc1a2c8fb0886d294093526a6ef0f1" | ||||
|     implementation 'com.github.TeamNewPipe:NewPipeExtractor:def745b801b2ef35c1a0fee1be950331ca6a0cd2' | ||||
|     implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751" | ||||
|  | ||||
|     implementation "org.jsoup:jsoup:1.13.1" | ||||
|   | ||||
| @@ -317,6 +317,22 @@ | ||||
|                 <data android:pathPrefix="/accounts/" /> | ||||
|                 <data android:pathPrefix="/video-channels/" /> | ||||
|             </intent-filter> | ||||
|  | ||||
|             <!-- Bandcamp filter --> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.VIEW"/> | ||||
|                 <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/> | ||||
|                 <action android:name="android.nfc.action.NDEF_DISCOVERED"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|                 <category android:name="android.intent.category.BROWSABLE"/> | ||||
|  | ||||
|                 <data android:scheme="http"/> | ||||
|                 <data android:scheme="https"/> | ||||
|                 <data android:host="bandcamp.com"/> | ||||
|                 <data android:host="*.bandcamp.com"/> | ||||
|                 <data android:pathPrefix="/"/> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <service | ||||
|             android:name=".RouterActivity$FetcherService" | ||||
|   | ||||
| @@ -62,6 +62,7 @@ import org.schabi.newpipe.error.ReCaptchaActivity; | ||||
| import org.schabi.newpipe.error.UserAction; | ||||
| import org.schabi.newpipe.extractor.InfoItem; | ||||
| import org.schabi.newpipe.extractor.NewPipe; | ||||
| import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException; | ||||
| import org.schabi.newpipe.extractor.exceptions.ExtractionException; | ||||
| import org.schabi.newpipe.extractor.stream.AudioStream; | ||||
| import org.schabi.newpipe.extractor.stream.Stream; | ||||
| @@ -1546,10 +1547,21 @@ public final class VideoDetailFragment | ||||
|             updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl()); | ||||
|         } | ||||
|  | ||||
|         if (!info.getErrors().isEmpty()) { | ||||
|             // Bandcamp fan pages are not yet supported and thus a ContentNotAvailableException is | ||||
|             // thrown. This is not an error and thus should not be shown to the user. | ||||
|             for (final Throwable throwable : info.getErrors()) { | ||||
|                 if (throwable instanceof ContentNotSupportedException | ||||
|                         && "Fan pages are not supported".equals(throwable.getMessage())) { | ||||
|                     info.getErrors().remove(throwable); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (!info.getErrors().isEmpty()) { | ||||
|                 showSnackBarError(new ErrorInfo(info.getErrors(), | ||||
|                         UserAction.REQUESTED_STREAM, info.getUrl(), info)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         binding.detailControlsDownload.setVisibility(info.getStreamType() == StreamType.LIVE_STREAM | ||||
|                 || info.getStreamType() == StreamType.AUDIO_LIVE_STREAM ? View.GONE : View.VISIBLE); | ||||
|   | ||||
| @@ -1129,6 +1129,12 @@ public final class Player implements | ||||
|                 // Close it because when changing orientation from portrait | ||||
|                 // (in fullscreen mode) the size of queue layout can be larger than the screen size | ||||
|                 closeItemsList(); | ||||
|                 // When the orientation changed, the screen height might be smaller. | ||||
|                 // If the end screen thumbnail is not re-scaled, | ||||
|                 // it can be larger than the current screen height | ||||
|                 // and thus enlarging the whole player. | ||||
|                 // This causes the seekbar to be ouf the visible area. | ||||
|                 updateEndScreenThumbnail(); | ||||
|                 break; | ||||
|             case Intent.ACTION_SCREEN_ON: | ||||
|                 // Interrupt playback only when screen turns on | ||||
| @@ -1187,6 +1193,78 @@ public final class Player implements | ||||
|                 .loadImage(url, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, this); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Scale the player audio / end screen thumbnail down if necessary. | ||||
|      * <p> | ||||
|      * This is necessary when the thumbnail's height is larger than the device's height | ||||
|      * and thus is enlarging the player's height | ||||
|      * causing the bottom playback controls to be out of the visible screen. | ||||
|      * </p> | ||||
|      */ | ||||
|     public void updateEndScreenThumbnail() { | ||||
|         if (currentThumbnail == null) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         final float endScreenHeight = calculateMaxEndScreenThumbnailHeight(); | ||||
|  | ||||
|         final Bitmap endScreenBitmap = Bitmap.createScaledBitmap( | ||||
|                 currentThumbnail, | ||||
|                 (int) (currentThumbnail.getWidth() | ||||
|                         / (currentThumbnail.getHeight() / endScreenHeight)), | ||||
|                 (int) endScreenHeight, | ||||
|                 true); | ||||
|  | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "Thumbnail - updateEndScreenThumbnail() called with: " | ||||
|                     + "currentThumbnail = [" + currentThumbnail + "], " | ||||
|                     + currentThumbnail.getWidth() + "x" + currentThumbnail.getHeight() | ||||
|                     + ", scaled end screen height = " + endScreenHeight | ||||
|                     + ", scaled end screen width = " + endScreenBitmap.getWidth()); | ||||
|         } | ||||
|  | ||||
|         binding.endScreen.setImageBitmap(endScreenBitmap); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Calculate the maximum allowed height for the {@link R.id.endScreen} | ||||
|      * to prevent it from enlarging the player. | ||||
|      * <p> | ||||
|      * The calculating follows these rules: | ||||
|      * <ul> | ||||
|      * <li> | ||||
|      *     Show at least stream title and content creator on TVs and tablets | ||||
|      *     when in landscape (always the case for TVs) and not in fullscreen mode. | ||||
|      *     This requires to have at least <code>85dp</code> free space for {@link R.id.detail_root} | ||||
|      *     and additional space for the stream title text size | ||||
|      *     ({@link R.id.detail_title_root_layout}). | ||||
|      *     The text size is <code>15sp</code> on tablets and <code>16sp</code> on TVs, | ||||
|      *     see {@link R.id.titleTextView}. | ||||
|      * </li> | ||||
|      * <li> | ||||
|      *     Otherwise, the max thumbnail height is the screen height. | ||||
|      * </li> | ||||
|      * </ul> | ||||
|      * | ||||
|      * @return the maximum height for the end screen thumbnail | ||||
|      */ | ||||
|     private float calculateMaxEndScreenThumbnailHeight() { | ||||
|         // ensure that screenHeight is initialized and thus not 0 | ||||
|         updateScreenSize(); | ||||
|  | ||||
|         if (DeviceUtils.isTv(context) && !isFullscreen) { | ||||
|             final int videoInfoHeight = | ||||
|                     DeviceUtils.dpToPx(85, context) + DeviceUtils.spToPx(16, context); | ||||
|             return Math.min(currentThumbnail.getHeight(), screenHeight - videoInfoHeight); | ||||
|         } else if (DeviceUtils.isTablet(context) && service.isLandscape() && !isFullscreen) { | ||||
|             final int videoInfoHeight = | ||||
|                     DeviceUtils.dpToPx(85, context) + DeviceUtils.spToPx(15, context); | ||||
|             return Math.min(currentThumbnail.getHeight(), screenHeight - videoInfoHeight); | ||||
|         } else { // fullscreen player: max height is the device height | ||||
|             return Math.min(currentThumbnail.getHeight(), screenHeight); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onLoadingStarted(final String imageUri, final View view) { | ||||
|         if (DEBUG) { | ||||
| @@ -1207,23 +1285,29 @@ public final class Player implements | ||||
|     @Override | ||||
|     public void onLoadingComplete(final String imageUri, final View view, | ||||
|                                   final Bitmap loadedImage) { | ||||
|         final float width = Math.min( | ||||
|         // scale down the notification thumbnail for performance | ||||
|         final float notificationThumbnailWidth = Math.min( | ||||
|                 context.getResources().getDimension(R.dimen.player_notification_thumbnail_width), | ||||
|                 loadedImage.getWidth()); | ||||
|         currentThumbnail = Bitmap.createScaledBitmap( | ||||
|                 loadedImage, | ||||
|                 (int) notificationThumbnailWidth, | ||||
|                 (int) (loadedImage.getHeight() | ||||
|                         / (loadedImage.getWidth() / notificationThumbnailWidth)), | ||||
|                 true); | ||||
|  | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "Thumbnail - onLoadingComplete() called with: " | ||||
|                     + "imageUri = [" + imageUri + "], view = [" + view + "], " | ||||
|                     + "loadedImage = [" + loadedImage + "], " | ||||
|                     + loadedImage.getWidth() + "x" + loadedImage.getHeight() | ||||
|                     + ", scaled width = " + width); | ||||
|                     + ", scaled notification width = " + notificationThumbnailWidth); | ||||
|         } | ||||
|  | ||||
|         currentThumbnail = Bitmap.createScaledBitmap(loadedImage, | ||||
|                 (int) width, | ||||
|                 (int) (loadedImage.getHeight() / (loadedImage.getWidth() / width)), true); | ||||
|         binding.endScreen.setImageBitmap(loadedImage); | ||||
|         NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false); | ||||
|  | ||||
|         // there is a new thumbnail, thus the end screen thumbnail needs to be changed, too. | ||||
|         updateEndScreenThumbnail(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -6,8 +6,10 @@ import android.content.pm.PackageManager; | ||||
| import android.content.res.Configuration; | ||||
| import android.os.BatteryManager; | ||||
| import android.os.Build; | ||||
| import android.util.TypedValue; | ||||
| import android.view.KeyEvent; | ||||
|  | ||||
| import androidx.annotation.Dimension; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.core.content.ContextCompat; | ||||
|  | ||||
| @@ -70,4 +72,20 @@ public final class DeviceUtils { | ||||
|                 return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static int dpToPx(@Dimension(unit = Dimension.DP) final int dp, | ||||
|                              @NonNull final Context context) { | ||||
|         return (int) TypedValue.applyDimension( | ||||
|                 TypedValue.COMPLEX_UNIT_DIP, | ||||
|                 dp, | ||||
|                 context.getResources().getDisplayMetrics()); | ||||
|     } | ||||
|  | ||||
|     public static int spToPx(@Dimension(unit = Dimension.SP) final int sp, | ||||
|                              @NonNull final Context context) { | ||||
|         return (int) TypedValue.applyDimension( | ||||
|                 TypedValue.COMPLEX_UNIT_SP, | ||||
|                 sp, | ||||
|                 context.getResources().getDisplayMetrics()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -48,6 +48,10 @@ public final class KioskTranslator { | ||||
|                 return c.getString(R.string.recent); | ||||
|             case "live": | ||||
|                 return c.getString(R.string.duration_live); | ||||
|             case "Featured": | ||||
|                 return c.getString(R.string.featured); | ||||
|             case "Radio": | ||||
|                 return c.getString(R.string.radio); | ||||
|             default: | ||||
|                 return kioskId; | ||||
|         } | ||||
| @@ -69,6 +73,10 @@ public final class KioskTranslator { | ||||
|                 return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_thumb_up); | ||||
|             case "live": | ||||
|                 return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_live_tv); | ||||
|             case "Featured": | ||||
|                 return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_stars); | ||||
|             case "Radio": | ||||
|                 return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_radio); | ||||
|             default: | ||||
|                 return 0; | ||||
|         } | ||||
|   | ||||
| @@ -38,6 +38,8 @@ public final class ServiceHelper { | ||||
|                 return R.drawable.place_holder_gadse; | ||||
|             case 3: | ||||
|                 return R.drawable.place_holder_peertube; | ||||
|             case 4: | ||||
|                 return R.drawable.place_holder_bandcamp; | ||||
|             default: | ||||
|                 return R.drawable.place_holder_circle; | ||||
|         } | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-nodpi/place_holder_bandcamp.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable-nodpi/place_holder_bandcamp.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.7 KiB | 
| @@ -44,4 +44,13 @@ | ||||
|     <color name="dark_media_ccc_accent_color">#FFFFFF</color> | ||||
|     <color name="dark_media_ccc_statusbar_color">#9e9e9e</color> | ||||
|  | ||||
|     <!-- Bandcamp --> | ||||
|     <color name="light_bandcamp_primary_color">#17a0c4</color> | ||||
|     <color name="light_bandcamp_accent_color">#000000</color> | ||||
|     <color name="light_bandcamp_statusbar_color">#17a0c4</color> | ||||
|  | ||||
|     <color name="dark_bandcamp_primary_color">#17a0c4</color> | ||||
|     <color name="dark_bandcamp_accent_color">#FFFFFF</color> | ||||
|     <color name="dark_bandcamp_statusbar_color">#17a0c4</color> | ||||
|  | ||||
| </resources> | ||||
| @@ -707,4 +707,6 @@ | ||||
|     <string name="private_content">This content is private, so it cannot be streamed or downloaded by NewPipe.</string> | ||||
|     <string name="youtube_music_premium_content">This video is available only to YouTube Music Premium members, so it cannot be streamed or downloaded by NewPipe.</string> | ||||
|     <string name="paid_content">This content is only available to users who have paid, so it cannot be streamed or downloaded by NewPipe.</string> | ||||
|     <string name="featured">Featured</string> | ||||
|     <string name="radio">Radio</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -70,4 +70,23 @@ | ||||
|         <item name="colorAccent">@color/dark_media_ccc_accent_color</item> | ||||
|     </style> | ||||
|  | ||||
|     <!-- Bandcamp --> | ||||
|     <style name="LightTheme.Bandcamp" parent="LightTheme"> | ||||
|         <item name="colorPrimary">@color/light_bandcamp_primary_color</item> | ||||
|         <item name="colorPrimaryDark">@color/light_bandcamp_statusbar_color</item> | ||||
|         <item name="colorAccent">@color/light_bandcamp_accent_color</item> | ||||
|     </style> | ||||
|  | ||||
|     <style name="DarkTheme.Bandcamp" parent="DarkTheme"> | ||||
|         <item name="colorPrimary">@color/dark_bandcamp_primary_color</item> | ||||
|         <item name="colorPrimaryDark">@color/dark_bandcamp_statusbar_color</item> | ||||
|         <item name="colorAccent">@color/dark_bandcamp_accent_color</item> | ||||
|     </style> | ||||
|  | ||||
|     <style name="BlackTheme.Bandcamp" parent="BlackTheme"> | ||||
|         <item name="colorPrimary">@color/dark_bandcamp_primary_color</item> | ||||
|         <item name="colorPrimaryDark">@color/dark_bandcamp_statusbar_color</item> | ||||
|         <item name="colorAccent">@color/dark_bandcamp_accent_color</item> | ||||
|     </style> | ||||
|  | ||||
| </resources> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Tobi
					Tobi