diff options
12 files changed, 143 insertions, 49 deletions
diff --git a/ServerProxy b/ServerProxy -Subproject 158e7e67eca5d7cf69915a59503464d47f16711 +Subproject a74d706b529ebba4ab73b64169e769affb6ae2a diff --git a/app/build.gradle b/app/build.gradle index ced2d978..075e403c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "github.daneren2005.dsub" minSdkVersion 14 targetSdkVersion 23 - versionCode 186 - versionName '5.3' + versionCode 187 + versionName '5.3.1' setProperty("archivesBaseName", "DSub $versionName") resConfigs "de", "es", "fr", "hu", "nl", "pt-rPT", "ru", "sv" } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java index 16082cbd..c39e9f61 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectInternetRadioStationFragment.java @@ -18,10 +18,18 @@ */ package github.daneren2005.dsub.fragments; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -37,6 +45,8 @@ import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.UpdateView; public class SelectInternetRadioStationFragment extends SelectRecyclerFragment<InternetRadioStation> { + private static final String TAG = SelectInternetRadioStationFragment.class.getSimpleName(); + @Override public int getOptionsMenu() { return R.menu.abstract_top_menu; @@ -67,6 +77,7 @@ public class SelectInternetRadioStationFragment extends SelectRecyclerFragment<I return null; } + getStreamFromPlaylist(item); downloadService.download(item); return null; } @@ -94,6 +105,40 @@ public class SelectInternetRadioStationFragment extends SelectRecyclerFragment<I return false; } + private void getStreamFromPlaylist(InternetRadioStation internetRadioStation) { + if(internetRadioStation.getStreamUrl() != null && (internetRadioStation.getStreamUrl().indexOf(".m3u") != -1 || internetRadioStation.getStreamUrl().indexOf(".pls") != -1)) { + try { + URL url = new URL(internetRadioStation.getStreamUrl()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + try { + BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + while((line = in.readLine()) != null) { + // Not blank line or comment + if(line.length() > 0 && line.indexOf('#') != 0) { + if(internetRadioStation.getStreamUrl().indexOf(".m3u") != -1) { + internetRadioStation.setStreamUrl(line); + break; + } else { + if(line.indexOf("File1=") == 0) { + internetRadioStation.setStreamUrl(line.replace("File1=", "")); + } else if(line.indexOf("Title1=") == 0) { + internetRadioStation.setTitle(line.replace("Title1=", "")); + } + } + } + } + } finally { + connection.disconnect(); + } + } catch (Exception e) { + Log.e(TAG, "Failed to get stream data from playlist"); + } + + } + } + private void displayInternetRadioStationInfo(final InternetRadioStation station) { List<Integer> headers = new ArrayList<>(); List<String> details = new ArrayList<>(); diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index a6bbc327..1cf482ca 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -1469,7 +1469,7 @@ public class DownloadService extends Service { Notifications.hidePlayingNotification(this, this, handler); } if(mRemoteControl != null) { - mRemoteControl.setPlaybackState(playerState.getRemoteControlClientPlayState()); + mRemoteControl.setPlaybackState(playerState.getRemoteControlClientPlayState(), getCurrentPlayingIndex(), size()); } if (playerState == STARTED) { @@ -2842,6 +2842,8 @@ public class DownloadService extends Service { final Integer duration = getPlayerDuration(); final boolean isSeekable = isSeekable(); final int position = getPlayerPosition(); + final int index = getCurrentPlayingIndex(); + final int queueSize = size(); synchronized(onSongChangedListeners) { for (final OnSongChangedListener listener : onSongChangedListeners) { @@ -2861,7 +2863,7 @@ public class DownloadService extends Service { @Override public void run() { if(mRemoteControl != null) { - mRemoteControl.setPlaybackState(playerState.getRemoteControlClientPlayState()); + mRemoteControl.setPlaybackState(playerState.getRemoteControlClientPlayState(), index, queueSize); } } }); diff --git a/app/src/main/java/github/daneren2005/dsub/util/BackgroundTask.java b/app/src/main/java/github/daneren2005/dsub/util/BackgroundTask.java index 31e83200..2b0c6279 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/BackgroundTask.java +++ b/app/src/main/java/github/daneren2005/dsub/util/BackgroundTask.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import org.xmlpull.v1.XmlPullParserException; @@ -54,6 +55,7 @@ public abstract class BackgroundTask<T> implements ProgressListener { private static final Collection<Thread> threads = Collections.synchronizedCollection(new ArrayList<Thread>()); protected static final BlockingQueue<BackgroundTask.Task> queue = new LinkedBlockingQueue<BackgroundTask.Task>(10); private static Handler handler = null; + private static AtomicInteger currentlyRunning = new AtomicInteger(0); static { try { handler = new Handler(Looper.getMainLooper()); @@ -71,6 +73,11 @@ public abstract class BackgroundTask<T> implements ProgressListener { threads.add(thread); thread.start(); } + } else if(currentlyRunning.get() >= threads.size()) { + Log.w(TAG, "Emergency add new thread: " + (threads.size() + 1)); + Thread thread = new Thread(new TaskRunnable(), String.format("BackgroundTask_%d", threads.size())); + threads.add(thread); + thread.start(); } if(handler == null) { try { @@ -304,22 +311,30 @@ public abstract class BackgroundTask<T> implements ProgressListener { @Override public void run() { Looper.prepare(); + final Thread currentThread = Thread.currentThread(); while(running) { try { Task task = queue.take(); + currentlyRunning.incrementAndGet(); task.execute(); } catch(InterruptedException stop) { Log.e(TAG, "Thread died"); running = false; - threads.remove(Thread.currentThread()); } catch(Throwable t) { Log.e(TAG, "Unexpected crash in BackgroundTask thread", t); + running = false; } + + currentlyRunning.decrementAndGet(); + } + + if(threads.contains(currentThread)) { + threads.remove(currentThread); } } } - public static interface OnCancelListener { + public interface OnCancelListener { void onCancel(); } } diff --git a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java index 0d4a0f9c..d6a92b07 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java @@ -99,7 +99,12 @@ public final class Notifications { public void run() { downloadService.stopForeground(true); showDownloadingNotification(context, downloadService, handler, downloadService.getCurrentDownloading(), downloadService.getBackgroundDownloads().size()); - downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); + + try { + downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); + } catch(Exception e) { + Log.e(TAG, "Failed to start notifications after stopping foreground download"); + } } }); } else { @@ -107,13 +112,22 @@ public final class Notifications { @Override public void run() { if (playing) { - downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); + try { + downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); + } catch(Exception e) { + Log.e(TAG, "Failed to start notifications while playing"); + } } else { playShowing = false; persistentPlayingShowing = true; NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); downloadService.stopForeground(false); - notificationManager.notify(NOTIFICATION_ID_PLAYING, notification); + + try { + notificationManager.notify(NOTIFICATION_ID_PLAYING, notification); + } catch(Exception e) { + Log.e(TAG, "Failed to start notifications while paused"); + } } } }); diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java index 1f7035dc..4f9a27f0 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java @@ -29,7 +29,7 @@ public abstract class RemoteControlClientBase { public abstract void register(final Context context, final ComponentName mediaButtonReceiverComponent); public abstract void unregister(final Context context); - public abstract void setPlaybackState(int state); + public abstract void setPlaybackState(int state, int index, int queueSize); public abstract void updateMetadata(Context context, MusicDirectory.Entry currentSong); public abstract void metadataChanged(MusicDirectory.Entry currentSong); public abstract void updateAlbumArt(MusicDirectory.Entry currentSong, Bitmap bitmap); diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java index 2a06e798..74076afb 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java @@ -54,7 +54,7 @@ public class RemoteControlClientICS extends RemoteControlClientBase { audioManager.unregisterRemoteControlClient(mRemoteControl); } - public void setPlaybackState(final int state) { + public void setPlaybackState(final int state, int index, int queueSize) { if(mRemoteControl == null) { return; } diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java index e61e9a47..d10c8594 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java @@ -1,17 +1,10 @@ package github.daneren2005.dsub.util.compat; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; import android.annotation.TargetApi; -import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.media.AudioManager; -import android.media.MediaMetadataRetriever; import android.media.RemoteControlClient; -import github.daneren2005.dsub.activity.SubsonicActivity; -import github.daneren2005.dsub.service.DownloadService; + import github.daneren2005.dsub.util.SilentBackgroundTask; @TargetApi(18) @@ -36,13 +29,13 @@ public class RemoteControlClientJB extends RemoteControlClientICS { return null; } }.execute(); - setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); + setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING, 0, 0); } }); } @Override - public void setPlaybackState(final int state) { + public void setPlaybackState(final int state, int index, int queueSize) { if(mRemoteControl == null) { return; } diff --git a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java index df468155..d666afb2 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java +++ b/app/src/main/java/github/daneren2005/dsub/util/compat/RemoteControlClientLP.java @@ -39,7 +39,6 @@ import android.support.v7.media.MediaRouter; import android.util.Log; import android.view.KeyEvent; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -50,7 +49,6 @@ import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicDirectory.Entry; import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.service.DownloadFile; @@ -123,8 +121,12 @@ public class RemoteControlClientLP extends RemoteControlClientBase { mediaSession.release(); } + private void setPlaybackState(int state) { + setPlaybackState(state, downloadService.getCurrentPlayingIndex(), downloadService.size()); + } + @Override - public void setPlaybackState(int state) { + public void setPlaybackState(int state, int index, int queueSize) { PlaybackState.Builder builder = new PlaybackState.Builder(); int newState = PlaybackState.STATE_NONE; @@ -156,7 +158,7 @@ public class RemoteControlClientLP extends RemoteControlClientBase { isSong = entry.isSong(); } - builder.setActions(getPlaybackActions(isSong)); + builder.setActions(getPlaybackActions(isSong, index, queueSize)); if(entry != null) { addCustomActions(entry, builder); @@ -240,14 +242,12 @@ public class RemoteControlClientLP extends RemoteControlClientBase { return mediaSession; } - protected long getPlaybackActions(boolean isSong) { + protected long getPlaybackActions(boolean isSong, int currentIndex, int size) { long actions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_SEEK_TO | PlaybackState.ACTION_SKIP_TO_QUEUE_ITEM; - int currentIndex = downloadService.getCurrentPlayingIndex(); - int size = downloadService.size(); if(isSong) { if (currentIndex > 0) { actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS; diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 9042839f..885035a4 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -36,6 +36,7 @@ <string name="button_bar.now_playing">A reproduzir agora</string> <string name="button_bar.podcasts">Podcasts</string> <string name="button_bar.bookmarks">Marcadores</string> + <string name="button_bar.internet_radio">Rádios online</string> <string name="button_bar.shares">Partilhas</string> <string name="button_bar.chat">Chat</string> <string name="button_bar.admin">Administração</string> @@ -43,17 +44,17 @@ <string name="button_bar.offline">Offline</string> <string name="main.welcome_title">Bem-vindo!</string> - <string name="main.welcome_text">Bem-vindo ao DSub! Atualmente a aplicação está configurada para usar o servidor de demonstração do Subsonic. Depois de configurar o seu servidor pessoal (disponível em <b>subsonic.org</b>), vá às <b>Definições</b> e altere as configurações para que possa conectar-se.</string> + <string name="main.welcome_text">Bem-vindo ao DSub! Atualmente a aplicação está configurada para usar o servidor de demonstração do Subsonic. Depois de configurar o seu servidor pessoal (disponível em <b>subsonic.org</b>), consulte as <b>Definições</b> e altere as configurações para que possa conectar-se.</string> <string name="main.about_title">Sobre o DSub</string> <string name="main.faq_title">FAQ</string> <string name="main.faq_text"> <![CDATA[ <font color="red">Cache vs Cache permanente</font>: - <br/>Quando o DSub transfere as músicas, elas poderão vir a ser eliminadas mais tarde para dar espaço para novas transferências. Por outro lado, as músicas que ficam permanentemente na cache nunca serão eliminadas. - <p/><font color="red">Falhas com o ChromeCast</font>: - <br/>Experimente a opção Definições -> Reprodução -> Usar dispositivo como proxy. É uma solução alternativa devido ao Chromecast não aceitar certificados auto-assinados. + <br/>Quando o DSub transfere as músicas, as mesmas poderão ser eliminadas mais tarde para dar espaço para novas transferências. Por outro lado, as músicas que ficam permanentemente na cache nunca serão eliminadas. + <p/><font color="red">Falhas com o Chromecast</font>: + <br/>Experimente a opção Definições -> Transmissão -> Usar dispositivo como proxy. É uma solução alternativa devido ao Chromecast não aceitar certificados auto-assinados. <p/><font color="red">Primeiro nível na biblioteca são grupos de artistas</font>: - <br/>No menu de opções, desmarque a opção "Artistas no primeiro nível". Isto irá fazer com que o primeiro nível de diretorias apresentado seja tratado como grupos de artistas em vez de artistas propriamente ditos. + <br/>No menu de opções, desmarque a opção "Artistas no primeiro nível". Isto fará com que o primeiro nível de diretorias apresentado seja tratado como grupos de artistas em vez de artistas propriamente ditos. ]]> </string> <string name="main.shuffle">Aleatório</string> @@ -192,7 +193,7 @@ <string name="download.menu_shuffle_notification">A lista de reprodução foi aleatorizada</string> <string name="download.menu_remove_played_songs">Remover músicas reproduzidas</string> <string name="download.playlist_title">Guardar lista de reprodução</string> - <string name="download.playlist_name">Introduza o nome da lista de reprodução:</string> + <string name="download.playlist_name">Introduza um nome para a lista de reprodução:</string> <string name="download.playlist_saving">A guardar a lista de reprodução \"%s\"...</string> <string name="download.playlist_done">A lista de reprodução foi guardada com sucesso.</string> <string name="download.playlist_error">Falha ao guardar a lista de reprodução, tente novamente mais tarde.</string> @@ -219,6 +220,12 @@ <string name="download.thumbs_up">Gosto</string> <string name="download.thumbs_down">Não gosto</string> <string name="download.batch_mode">Modo em série</string> + <string name="download.playback_speed_half">0.5x</string> + <string name="download.playback_speed_normal">1x</string> + <string name="download.playback_speed_one_half">1.5x</string> + <string name="download.playback_speed_double">2x</string> + <string name="download.playback_speed_tripple">3x</string> + <string name="download.playback_speed_custom">Personalizado</string> <string name="sync.new_podcasts">Novos podcasts disponíveis</string> <string name="sync.new_playlists">Novas músicas nas listas de reprodução</string> @@ -277,8 +284,8 @@ <string name="settings.server_sync_summary">Ativar ou não a sincronização para este servidor</string> <string name="settings.server_sync">Sincronização ativa</string> <string name="settings.cache_title">Cache de música</string> - <string name="settings.preload_wifi">Músicas para pre-carregar (Wi-Fi)</string> - <string name="settings.preload_mobile">Músicas para pre-carregar (dados móveis)</string> + <string name="settings.preload_wifi">Músicas para pré-carregar (Wi-Fi)</string> + <string name="settings.preload_mobile">Músicas para pré-carregar (dados móveis)</string> <string name="settings.cache_size">Tamanho da cache</string> <string name="settings.cache_location">Localização da cache</string> <string name="settings.cache_location_error">Localização da cache inválida. A utilizar predefinição.</string> @@ -299,6 +306,8 @@ <string name="settings.theme_dark">Escuro</string> <string name="settings.theme_black">Preto</string> <string name="settings.theme_holo">Holo</string> + <string name="settings.theme_day_night">Dia/Noite</string> + <string name="settings.theme_day_black_night">Dia/Noite (Preto)</string> <string name="settings.theme_fullscreen">Ecrã inteiro</string> <string name="settings.theme_fullscreen_summary">Ocultar o maior número de elementos da interface que o Android permita</string> <string name="settings.track_title">Mostrar número da faixa</string> @@ -332,7 +341,7 @@ <string name="settings.max_video_bitrate_2000">2000 Kbps</string> <string name="settings.max_video_bitrate_3000">3000 Kbps</string> <string name="settings.max_video_bitrate_5000">5000 Kbps</string> - <string name="settings.max_bitrate_unlimited">Ilimitado</string> + <string name="settings.max_bitrate_unlimited">Ilimitada</string> <string name="settings.wifi_required_title">Transmissão apenas em Wi-Fi</string> <string name="settings.wifi_required_summary">Apenas transmitir multimédia se ligado por Wi-Fi</string> <string name="settings.network_timeout_title">Intervalo de ligação</string> @@ -352,7 +361,7 @@ <string name="settings.search_history_cleared">O histório de pesquisa foi apagado</string> <string name="settings.other_title">Outras definições</string> <string name="settings.scrobble_title">Scrobble para Last.FM</string> - <string name="settings.scrobble_summary">Lembrar de configurar o nome de utilizador e palavra-passe do Last.FM no servidor Subsonic</string> + <string name="settings.scrobble_summary">Não se esqueça de configurar o seu nome de utilizador e palavra-passe do Last.FM no servidor Subsonic</string> <string name="settings.hide_media_title">Ocultar do resto</string> <string name="settings.hide_media_summary">Ocultar ficheiros de música das outras aplicações</string> <string name="settings.hide_media_toast">As mudanças terão efeito na próxima vez que o Android procure músicas no seu dispositivo.</string> @@ -367,12 +376,12 @@ <string name="settings.sleep_timer_off">Desligado</string> <string name="settings.sleep_timer_on">Ligado</string> <string name="settings.sleep_timer_always_on">Sempre ligado</string> - <string name="settings.temp_loss_title">Perda de foco temporário</string> + <string name="settings.temp_loss_title">Perda temporária de foco</string> <string name="settings.temp_loss_pause">Pausar sempre</string> <string name="settings.temp_loss_pause_lower">Pausar, baixar volume quando pedido</string> <string name="settings.temp_loss_lower">Baixar sempre o volume</string> <string name="settings.temp_loss_nothing">Não fazer nada</string> - <string name="settings.keep_played_count_title">Manter músicas reproduzidas</string> + <string name="settings.keep_played_count_title">Manter as músicas reproduzidas</string> <string name="settings.keep_played_count_none">Remover todas as músicas reproduzidas</string> <string name="settings.keep_played_count_one">Manter as últimas músicas reproduzidas</string> <string name="settings.keep_played_count_two">Manter as 2 últimas músicas reproduzidas</string> @@ -384,14 +393,14 @@ <string name="settings.persistent_summary">Mostrar a notificação mesmo depois de pausar. Pressione o botão de parar para a remover</string> <string name="settings.gapless_playback">Reprodução sem pausas</string> <string name="settings.gapless_playback_summary">Se notar falhas estranhas durante a reprodução, desmarcar esta opção pode ajudar</string> - <string name="settings.chat_refresh">Taxa de atualização do Chat (s)</string> + <string name="settings.chat_refresh">Taxa de atualização do chat (s)</string> <string name="settings.chat_enabled">Ativar chat</string> <string name="settings.chat_enabled_summary">Mostrar ou não a opção \"Chat\" no menu lateral</string> <string name="settings.video_title">Vídeo</string> <string name="settings.video_player">Reprodutor de vídeo</string> <string name="settings.video_raw">Raw (Requer Subsonic 4.8+)</string> <string name="settings.video_hls">HTTP Live Stream (HLS) (Requer Subsonic 4.8+)</string> - <string name="settings.video_transcode">Transcodificação direta (Requísitos de vídeo -> mp4 ou configuração similar no servidor</string> + <string name="settings.video_transcode">Transcodificação direta (Requer vídeo -> mp4 ou configuração similar no servidor</string> <string name="settings.video_flash">Flash (Requer plugin)</string> <string name="settings.cache_screen_title">Cache/Ligação</string> <string name="settings.playback_title">Reprodução</string> @@ -401,6 +410,8 @@ <string name="settings.podcasts_enabled_summary">Mostrar ou não a opção \"Podcasts\" no menu lateral</string> <string name="settings.bookmarks_enabled">Ativar marcadores</string> <string name="settings.bookmarks_enabled_summary">Mostrar ou não a opção \"Marcadores\" no menu lateral</string> + <string name="settings.internet_radio_enabled">Ativar rádios online</string> + <string name="settings.internet_radio_enabled_summary">Mostrar ou não a opção \"Rádios online\" no menu lateral</string> <string name="settings.shares_enabled">Ativar partilhas</string> <string name="settings.shares_enabled_summary">Mostrar ou não a opção \"Partilhas\" no menu lateral</string> <string name="settings.sync_title">Sincronização</string> @@ -437,21 +448,26 @@ <string name="settings.browse_by_tags">Procurar por tags</string> <string name="settings.browse_by_tags_summary">Procurar por tags em vez da estrutura das pastas. Requer Subsonic 4.7+</string> <string name="settings.disable_exit_prompt">Desativar diálogo de saída</string> - <string name="settings.disable_exit_prompt_summary">Fechar a aplicação imediatamente após pressionar o botão voltar no ecrã inicial</string> + <string name="settings.disable_exit_prompt_summary">Fechar a aplicação imediatamente após pressionar o botão de voltar no ecrã inicial</string> <string name="settings.override_system_language">Sobrepor linguagem do sistema</string> <string name="settings.override_system_language_summary">Mostrar a aplicação em inglês mesmo se o DSub tiver uma tradução disponível para a linguagem do sistema. Poderá ser necessário limpar a aplicação da memória para as alterações terem efeito</string> <string name="settings.drawer_items_title">Separadores laterais</string> + <string name="settings.song_press_action">Ação ao pressionar uma música</string> + <string name="settings.song_press_play_single">Reproduzir apenas essa música</string> + <string name="settings.song_press_play_all">Adicionar tudo no álbum à fila de reprodução</string> + <string name="settings.song_press_play_next">Adicionar como próxima música</string> + <string name="settings.song_press_play_last">Adicionar música ao fim da fila de reprodução</string> <string name="settings.large_album_art">Grandes capas de álbum</string> <string name="settings.large_album_art_summary">Mostrar os álbuns com uma grande capa em vez de em lista</string> <string name="settings.admin_enabled">Ativar administração</string> <string name="settings.admin_enabled_summary">Mostrar ou não a opção \"Administração\" no menu lateral</string> <string name="settings.replay_gain">Replay Gain</string> - <string name="settings.replay_gain_summary">Escalar ou não o volume da reprodução por tags de replay gain nos álbuns e faixas</string> + <string name="settings.replay_gain_summary">Escalar ou não o volume da reprodução por tags \"replay gain\" nos álbuns e faixas</string> <string name="settings.replay_gain_type">Ler pelas tags</string> <string name="settings.replay_gain_type.smart">Deteção inteligente</string> <string name="settings.replay_gain_type.album">Tags nos álbuns</string> <string name="settings.replay_gain_type.track">Tags nas faixas</string> - <string name="settings.replay_gain_bump">Pré-amp do Replay Gain</string> + <string name="settings.replay_gain_bump">Pré-amplificação do Replay Gain</string> <string name="settings.replay_gain_untagged">Músicas sem Replay Gain</string> <string name="settings.casting">Transmissão</string> <string name="settings.casting_proxy">Usar dispositivo como proxy</string> @@ -461,14 +477,14 @@ <string name="settings.start_on_headphones">Iniciar com os auscultadores</string> <string name="settings.start_on_headphones_summary">Iniciar quando os auscultadores são ligados. Isto requer o uso de um serviço que inicia com o arranque, para verificar o evento de ligação dos auscultadores mesmo quando o DSub não está a ser executado</string> <string name="settings.color_action_bar">Colorir barra de ações</string> - <string name="settings.color_action_bar.summary">Colorir ou não a barra de ações e barra de estado</string> + <string name="settings.color_action_bar.summary">Colorir ou não a barra de ações e a barra de estado</string> <string name="settings.shuffle_by_album">Aleatorizar por álbum</string> <string name="settings.shuffle_by_album.true">Aleatorizar a ordem dos álbuns</string> <string name="settings.shuffle_by_album.false">Aleatorizar todas as músicas juntas</string> <string name="settings.casting_stream_original">Transmitir original</string> <string name="settings.casting_stream_original_summary">Transmitir os ficheiros originais se suportado pelo dispositivo de transmissão</string> <string name="settings.heads_up_notification">Notificações Heads Up (5.0+)</string> - <string name="settings.heads_up_notification_summary">Mostrar notificações de reprodução como notificações Heads Up (Android Lollipop+ apenas)</string> + <string name="settings.heads_up_notification_summary">Mostrar notificações de reprodução como notificações \"Heads Up\" (Android Lollipop+ apenas)</string> <string name="settings.casting_cache">Cache durante a transmissão</string> <string name="settings.casting_cache_summary">Adicionar à cache as músicas a reproduzir no momento da transmissão</string> @@ -596,6 +612,7 @@ <string name="details.title.podcast">Detalhes do podcast</string> <string name="details.title.playlist">Detalhes da lista de reprodução</string> <string name="details.title.artist">Detalhes do artista</string> + <string name="details.title.internet_radio_station">Detalhes da rádio online</string> <string name="details.podcast">Podcast</string> <string name="details.status">Estado</string> <string name="details.artist">Artista</string> @@ -635,6 +652,10 @@ <string name="details.last_played">Última reprodução</string> <string name="details.expiration">Expiração</string> <string name="details.played_count">Nº de reproduções</string> + <string name="details.stream_url">URL da transmissão</string> + <string name="details.home_page">Página web</string> + + <string name="permission.external_storage.failed">O DSub não funciona se não puder escrever no armazenamento</string> <plurals name="select_album_n_songs"> <item quantity="zero">Sem músicas</item> @@ -646,8 +667,8 @@ <item quantity="other">%d músicas agendadas para transferência.</item> </plurals> <plurals name="select_album_n_songs_added"> - <item quantity="one">Uma música adicionada à lista de reprodução.</item> - <item quantity="other">%d músicas adicionadas à lista de reprodução.</item> + <item quantity="one">Uma música adicionada à fila de reprodução.</item> + <item quantity="other">%d músicas adicionadas à fila de reprodução.</item> </plurals> <plurals name="select_album_donate_dialog_n_trial_days_left"> <item quantity="one">Um dia de período de testes restante</item> diff --git a/app/src/main/res/xml/changelog.xml b/app/src/main/res/xml/changelog.xml index 89f076f7..169edaa0 100644 --- a/app/src/main/res/xml/changelog.xml +++ b/app/src/main/res/xml/changelog.xml @@ -1,5 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <changelog> + <release version="5.3.1" versioncode="187" releasedate="10/4/2016"> + <change>Fix Internet Radio streams which point to playlists</change> + <change>Don't show playback speed button below Android 6.0</change> + </release> <release version="5.3" versioncode="186" releasedate="9/23/2016"> <change>Listen to Radio Internet Stations</change> <change>Automatic Day/Night theme</change> |