Merge pull request #887 from jaedb/develop

Develop
This commit is contained in:
James Barnsley
2023-02-12 07:56:52 +13:00
committed by GitHub
16 changed files with 1738 additions and 1174 deletions

View File

@ -10,7 +10,6 @@ services:
- /tmp/snapserver:/tmp
- ./docker/snapserver/snapserver.conf:/etc/snapserver.conf
- ./docker/snapserver/snapserver.json:/root/.config/snapserver/server.json
- ./docker/snapserver/meta_mopidy.py:/usr/share/snapserver/plug-ins/meta_mopidy.py
mopidy:
image: jaedb/iris
environment:

577
src/js/locale/br.yaml Normal file
View File

@ -0,0 +1,577 @@
name: Português
##
# Common and reusable phrases
##
errors:
uri_not_found: 'Não posso encotrar naeda com a URI %{uri}'
could_not_load: 'Não posso carregar %{name}'
could_not_load_library: 'Não posso carregar %{name} de %{provider}'
no_results: Sem resultados
authorization_required: 'devo autorizar %{provider} antes'
enable_first: 'Habilite %{provider} antes'
no_service_worker: Serviço não suportado
required: Requerido
unknown_error: Erro desconhecido
need_to_be_online: Você precisa estar online para carregar este recurso
nothing_selected: Nada seleccionado
cannot_reorder:
title: Não consigo reordenar Não consigo reordenar itens
description: Limpe a ordem/filtros e tente novamente
actions:
play: Reproduzir
play_all: Reproduzir tudo
play_next: Reproduzir próximo
shuffle_play: Reprodução aleatoria
pause: Pausa
stop: Parar
add_to_playlist: Adicionar à Playlist
add_to_library: Adicionar à Biblioteca
added_tracks_to: 'Adicionar %{count} faixas a '
remove_from_library: Removido da Biblioteca
add_to_queue: Adicionar à fila
reset: Reiniciar
back: Voltar
refresh: Atualizar
enable: Habilitar
disable: Desabilitar
send: Enviar
save: Guardar
start: Iniciar
edit: Editar
add: Adicionar
confirm: Deseja confirmar?
delete: Apagar
remove: Remover
cancel: Cancelar
created: '%{name} Criado'
saved: '%{name} guardado'
deleted: '%{name} apagado'
common:
popularity: Popularidade
name: Nome
artist: Artista
duration: Duração
source: Fonte
sources: Fontes
sort: Ordenar
filter: Filtrar
by: ' por '
loading_library: 'Carregando %{provider} %{type}'
fields:
start_typing: 'Começar a escrever...'
search: 'Buscar...'
sort: Ordenar
view: Ver
source: Fonte
uri: URI(s)
items_to_add:
label: Etiquetas a adicionar
placeholder: Sem Etiquetas
filter: Filtrar
filters:
all: Todo
thumbnails: Miniaturas
list: Lista
as_loaded: Como carregar
name: Nome
artist: Artista
album: Album
updated: Atualizando
tracks: Faixas
source: Fonte
editable: Editável
owner: Proprietário
followers: Seguidores
popularity: Popularidade
time:
seconds:
short: seg
singular: segundo
plural: segundos
minutes:
short: min
singular: minuto
plural: minutos
hours:
short: hor
singular: hora
plural: horas
days:
short: día
singular: día
plural: días
weeks:
short: sem
singular: semana
plural: semanas
years:
short: ano
singular: ano
plural: anos
specs:
tracks: '%{count} faixas'
albums: '%{count} álbuns'
followers: '%{count} seguidores'
listeners: '%{count} ouvintes'
playlists: '%{count} playlists'
plays: '%{count} reproduções'
popularity: '%{percent}% popularidade'
added: 'Adicionado '
added_ago: 'Adicionado á %{time}'
edited: 'Editado '
edited_ago: 'Editado á %{time}'
played_ago: 'Reproduzido á %{time}'
services:
mopidy:
title: Mopidy
local: Local
adding_uris: 'Adicionando %{count} URI(s)'
adding_uris_broadcast: '%{username} está adicionando %{count} URI(s)'
searching: 'Buscando %{provider} %{type}'
searching_providers: 'Buscando %{count} provedores Mopidy'
loading_albums: 'Carregando %{count} álbuns locais'
spotify:
title: Spotify
pusher:
title: Pusher
snapcast:
title: Snapcast
genius:
title: Genius
switch_lyrics_result: Alterar para outro resultado de pesquisa de letras
want_lyrics: 'Quer ver as letras das músicas? Autorizar o Genius em '
google:
title: Google
lastfm:
title: LastFM
love: Love
unlove: Unlove
##
# Components
##
sidebar:
now_playing: Tocando
search: Buscar
discover: Encontrar
genre: Género
featured_playlists: Playlist destacadas
new_releases: Novos lançamentos
my_music: Minha música
playlists: Playlists
artists: Artistas
albums: Álbuns
tracks: Faixas
browse: Navegar
settings: Ajustes
not_connected: '%{name} não conectado'
browser_offline: Navegador offline
update_available: Atualização disponível
context_menu:
add_to_playlist:
title: Adicionar à Playlist
no_playlists: Sem Playlists editáveis
play_next: Reproduzir a seguir
play_top_tracks: Reproduzir as faixas superiores
play_all_tracks: Reproduzir todas as faixas
love_track: Faixa favorita
unlove_track: Faixa descartada
pin: Fixar
unpin: Desfixar
go_to_artist: Ir a artista
go_to_user: Ir a usuario
track_info: Informações da faixa
discover_similar: Encontrar similares
start_radio: Começar rádio
copy_uri: Copiar URI(s)
refresh: Atualizar
playback_controls:
consume: Usar
shuffle: Aleatória
repeat: Repetir
no_outputs: Sem saídas
mute: Mute
unmute: Desmute
snapcast:
enabled: Habilitado
streaming_enabled: Streaming habilitado
show_disconnected_clients: Mostrar clientes desconectados
no_connected_clients: Nenhum cliente conectado
host: Host
port: Porta
name: Nome
name_disconnected: Nome (desconectado)
group: Grupo
new_group: '+ Novo grupo'
latency: Latência
stream: Stream
volume: Volúme
authentication:
popup_blocked: Pop-up bloqueado. Permita janelas pop-up e tente novamente.
failed: Falha na autorização. %{origin} não é o URL de autorização configurado.
log_out: Sair
log_in: Entrar
##
# Views
##
now_playing:
title: Reproduzir
context_actions:
radio: Radio
history: Historico
add_uri: Adicionar URI
current_track:
playing_from: Reproduzindo de
shuffle: Aleatória
clear: Limpar
radio: Rádio
album:
title: Álbum
title_window: '%{name} por %{artist} (album)'
wiki:
title: Acerca de
published: 'Publicado: %{date}'
tracks:
title: Faixas
sort:
disc_track: Número da faixa
name: Nome
artist:
title: Artista
title_window: '%{name} (artista)'
overview:
title: Visão geral
top_tracks: Faixas superiores
albums: Sem álbum
related_artists:
title: Artistas relacionados
more: Todos os artistas relacionados
tracks:
title: Faixas
sort:
disc_track: Número de Faixas
name: Nome
album: Álbum
related_artists:
title: Artistas relacionados
about:
title: Acerca de
source: '%{source} artista'
wiki:
published: 'Publicado: %{date}'
origin: 'Origem: '
albums:
sort:
default: Por padrão
name: Nome
release_date: Lançado
track_count: Faixa
filter:
all: Todo
albums: Álbuns
singles: Singles
compilations: Copilação
debug:
title: Depurar
ui:
title: Interface de usuário
debug:
title: Depurar
overlay: Mostrar capa de depuração
logging:
title: Iniciando sessão
mopidy: Log Mopidy
pusher: Log Notificações
actions: Log Ações
snapcast: Log Snapcast
create_notification: Criado notificação
create_process: Criado notificação de proceso
run_test: Executar teste
call: Chamar
data: Data
examples: Exemplo
playlist:
title: Playlist
title_window: '%{name} (playlist)'
title_plural: Playlists
tracks:
title: Faixas
sort:
default: Por Padrão
sort_id: Como cargado
added_at: Data adição
name: Nome
artist: Artista
album: Álbum
queue_history:
title: Histórico de reprodução
search:
title: Buscar
title_window: 'Buscar: %{term}'
context_actions:
sort: Ordenar
source: 'Fontes (%{count})'
placeholder: Buscar
all:
title: Todo
artists:
title: Artistas
more: 'Todos os artistas (%{count})'
albums:
title: Álbumes
more: 'Todos os álbuns (%{count})'
playlists:
title: Playlists
more: 'Todas as playlists (%{count})'
tracks:
title: Faixas
track:
title: Faixa
title_window: '%{name} por %{artists} (track)'
lyrics_origin: 'Origem: '
explicit: Explícito
disc_number: 'Disco %{number}'
track_number: 'Faixa %{number}'
unknown_album: Álbum desconhecido
want_lyrics: 'Quer ver a letra da faixa? Autorize Genius baixo '
settings:
title: Ajustes
help: Ajuda
server:
title: Servidor
username:
label: Nome de usuário
description: Uma string não exclusiva usada para identificar este cliente (sem caracteres especiais)
interface:
title: Interface
language:
label: Idioma
theme:
label: Tema
auto: Auto
auto_tooltip: Detectar a sua preferência do navegador do sistema operacional
dark: Escuro
light: Claro
behavior:
label: Comportamento
clear_tracklist: Limpar lista de faixas da reprodução URI(s)
clear_tracklist_tooltip: Reproduzir uma ou mias URIs irá limpar a fila de reprodução atual
hotkeys: Habilitar teclas de atalho
smooth_scrolling: Ativar rolagem suave
touch_events: Ativar eventos de toque nos controles de reprodução
touch_events_tooltip: Permitir deslizar para a esquerda e para a direita para mudar de faixa
wide_scrollbars: Use barras de rolagem largas
grid_glow: Efeito brilhante nas miniaturas
grid_glow_tooltip: Desative o efeito para dispositivos lentos ou navegadores antigos
reporting:
label: Etiquetas
sublabel: Permitir etiquetas de estatisticas de uso anônimo
description: 'Esses dados de uso anônimos são importantes para identificar bugs e possíveis recursos que tornam o Iris melhor. você quer saber mais? Ler '
privacy_policy: Política de privacidade
are_you_sure: Tem certeza de que não deseja esse recurso?
commands:
label: Comandos
advanced:
title: Avançado
start_local_scan: Iniciar pesquisa local
artist_uri:
label: URI da biblioteca de artistas
description: URI usado para armazenar a biblioteca do artista
album_uri:
label: URI da biblioteca de álbuns
description: URI usado para armazenar a biblioteca de álbuns
track_uri:
label: URI da biblioteca de faixas
description: URI usado para armazenar a biblioteca de faixas
connections:
label: Conexões
version:
label: Versão
upgrade_available: 'Atualização disponível (%{version})'
upgrade: 'Aztualizar a %{version}'
up_to_date: Atualizada
share_configuration: Compartilhar configurações
restart: Reiniciar servidor
reset: Reiniciar ajustes
about:
title: Acerca de
blurb_1: ' é um projeto open-source de '
blurb_2: '. É grátis e não tem garantia. Se você pagou a alguém por este software, informe-nos.'
donate: Doar
github: GitHub
pusher_connection_list:
not_connected: Não conectado
no_connections: Sem conexão
you: ' (Você)'
servers:
inactive: Inativo
connecting: Conectando
disconnected: Desconectado
connected: Conectado
new_server: Novo servidor
name: Nome
host: Host
port: Porta
encryption:
label: criptografia
sublabel: Usar SSL
description: Requer um proxy SSL
switch: Trocar este servidor
reconnect: Reconectar
services:
title: Serviços
limited_access: Acceso limitado
unknown: Desconhecido
current_user: Usuario atual
authorization: Autorização
refresh_token: Atualizar o token
authorized: Autorizado
read_only: Somente leitura
unauthorized: Sem autorização
enabled: Habilitado
disabled: Deshabilitado
connected: Conectado
disconnected: Desconectado
spotify:
mopidy_spotify_not_running: A extensão Mopidy-Spotify não está funcionando. Não será possível reproduzir faixas do Spotify
country:
label: País
description: Código do país ISO 3166-1 alpha-2 (eg 'PT')
locale:
title: Local
description: Código de idioma em minúsculas ISO 639 e código do país em maiúsculas ISO 3166-1 alpha-2, acompanhado por um sublinhado (eg 'pt_BR')
user:
title: Usuário
title_window: '%{name} (usuario)'
you: Vocês
discover:
title: Encontrar
categories:
title: 'Género / Estilo'
category:
title: 'Género / Estilo'
category: Categoría
featured:
title: Playlists destacadas
new_releases:
title: Novos lançamentos
recommendations:
title: Encontrar
tracks: Faixas
artists: Artistas
albums: Álbuns
body_title: Explorar nova música
body_subtitle: Adicione propriedades musicais para construir seu som
too_many_seeds: Muitas faixas! Você pode usar até 5 faixas entre músicas, artistas e gêneros.
find_recommendations: Encontrar recomendações
library:
albums:
title: Meus álbuns
artists:
title: Meus artistas
browse:
title: Navegar
browse_directory:
title: Diretório
playlists:
title: Meinhas playlists
tracks:
title: Meinhas faixas
modal:
add_to_playlist:
title: adicionar à Playlist
subtitle: 'Selecione a lista de reprodução para adicionar %{count} faixa%{plural}'
no_playlists: Nenhuma lista de reprodução disponível
no_editable_playlists: Sem listas de reprodução editáveis
add_to_queue:
title: Adicionar à fila
subtitle: Adicione uma lista separada por vírgulas de URIs à fila de reprodução
uris: URI(s)
add_random: Encontrar faixas aleatorias
position:
label: Posição
end: Fim
next: Depois da faixa atual
edit_playlist:
title: Editar playlist
title_create: Crear playlist
name_required: Requier um nome
name: Nome
description: Descrição
provider: Provedor
image:
label: Arte da capa
description: Só JPEG, 256kB máx. Deixe-o vazio para manter a imagem inalterada.
options:
label: Opções
public: Público
collaborative: Colaborativa
create_playlist: Crio a playlist
edit_command:
title: Editar comando
title_create: Criar comando
name: Nome
colour: Cor
icon: Icone
url: URL
method:
label: Método
get: GET
post: POST
data: Dados
headers: Cabeçalhos adicionais
edit_radio:
title: Rádio
subtitle: Adicione e remova faixas para moldar o som do seu rádio. O rádio usa as recomendações do Spotify para sugerir músicas semelhantes às suas faixas.
invalid_seed_uri: URI(s) inválida
too_many_seeds: Mais de 5 faixas, ignorando o resto
only_spotify_uris: Só URIs do Spotify são suportados
already_added: URI já adicionado
no_seeds: Sem faixas
initial_setup:
title: Bem-vindo a Iris
username: Usuário
kiosk:
title: Reproduzindo
title_window: '%{name} por %{artist} (reproduzindo agora)'
lyrics: Letras
share_configuration:
title: Compartilhar configurações
subtitle: Transfira suas autorizações e configurações de interface para outro usuário conectado
no_peers: Sem conexões de mesmo nível
recipients: Recipientes
configurations: ConfiguraçÕes
authorization: '%{service} autorização'
logged_in_as: 'Registrado como %{name}'
snapcast_description: Detalhes da conexão do servidor
interface: Ajustes de Interface
interface_description: Tema, ordem, filtros, etc
import:
title: Configuração compartilhad
subtitle: 'Outro usuário compartilhou suas configurações com você. Isso inclui:'
do_you_want_to_import: Você quer importar?
import_now: Importar agora
successful: Importada com sucesso
reset:
title: Reiniciar Iris
subtitle: Limpe suas configurações locais, informações de armazenamento ou cache
items: Reiniciar de fábrica
preferences:
label: Preferencias
description: Costumização de Interface
database:
label: Base de dados
description: Base de dados local de bibliotecas e ajustes
service_worker:
label: Service worker
description: Reinstalar service worker
cache:
label: Extrair cacher
description: Uma API externa requer cache (requer Service Worker)
test_mode:
label: Modo Teste
description: Log detalhado para fins de diagnóstico

View File

@ -9,6 +9,7 @@ import _pl from './pl.yaml';
import _it from './it.yaml';
import _es from './es.yaml';
import _ru from './ru.yaml';
import _br from './br.yaml';
// Merge languages with English. This provides English fallbacks to untranslated
// fields without breaking the UI (with blanks)
@ -30,6 +31,8 @@ const es = {};
merge(es, en, _es);
const ru = {};
merge(ru, en, _ru);
const br = {};
merge(br, en, _br);
const available = [
{ key: 'en', name: en.name },
@ -39,6 +42,7 @@ const available = [
{ key: 'it', name: it.name },
{ key: 'ja', name: ja.name },
{ key: 'nl', name: nl.name },
{ key: 'br', name: br.name },
{ key: 'pl', name: pl.name },
{ key: 'ru', name: ru.name },
{ key: 'sv', name: sv.name },
@ -46,6 +50,7 @@ const available = [
export default {
en,
br,
es,
de,
fr,

View File

@ -19,10 +19,10 @@ errors:
title: Невозможно изменить порядок элементов
description: Удалить сортировку/фильтры и повторить попытку
actions:
play: Играть
play: Воспроизвести
play_all: Воспроизвести все
play_next: Играть дальше
shuffle_play: Играть в случайном порядке
play_next: Воспроизвести следующим
shuffle_play: Воспроизвести в случайном порядке
pause: Пауза
stop: Стоп
add_to_playlist: Добавить в плейлист
@ -31,7 +31,7 @@ actions:
remove_from_library: Удалить из библиотеки
add_to_queue: Добавить в очередь
reset: Сброс
back: Отменить
back: Назад
refresh: Oбновить
enable: Включить
disable: Выключить
@ -59,7 +59,7 @@ common:
by: 'после'
loading_library: 'Загружается %{provider} %{type}'
play_state:
playing: Играет
playing: Воспроизведение
paused: Приостановлено
stopped: Остановлено
idle: Бездействие
@ -78,7 +78,7 @@ fields:
all: Все
thumbnails: Миниатюры
list: Список
as_loaded: Как загружено
as_loaded: Время добавления
name: Имя
artist: Исполнитель
album: Альбом
@ -132,7 +132,7 @@ services:
restore_defaults: Восстановить значения по умолчанию
mopidy:
title: Mopidy
local: Local
local: Локальные
adding_uris: 'Добавление %{count} URI(s)'
adding_uris_broadcast: '%{username} добавил %{count} URI(s)'
searching: 'Поиск %{provider} %{type}'
@ -165,8 +165,8 @@ services:
sidebar:
now_playing: Сейчас играет
search: Поиск
discover: Обнаружить
genre: Жанр / Настроение
discover: Найти новое
moods: Жанр / Настроение
featured_playlists: Избранные плейлисты.
new_releases: Новые релизы
my_music: Моя музыка
@ -174,7 +174,7 @@ sidebar:
artists: Исполнитель
albums: Альбомы
tracks: Треки
browse: Смотреть
browse: Сервисы
settings: Настройки
servers: Серверы
not_connected: '%{name} не подключен'
@ -185,7 +185,7 @@ context_menu:
title: Добавить в плейлист
new_playlist: Создать плейлист
no_playlists: Нет доступных для записи плейлистов
play_next: Играть дальше
play_next: Воспроизвести следующим
play_top_tracks: Воспроизвести лучшие треки
play_all_tracks: Воспроизвести все треки
love_track: Любимые треки
@ -213,7 +213,7 @@ snapcast:
show_disconnected_clients: Показать отключенные клиенты
no_connected_clients: Нет подключенных клиентов
host: Host
port: Port
port: Порт
name: Имя
name_disconnected: Имя (Отключен)
group: Группа
@ -229,9 +229,9 @@ snapcast:
incompatible: ' (требуется при подключении из сеанса браузера HTTPS)'
authentication:
popup_blocked: Всплывающее окно заблокировано. Разрешите всплывающие окна и повторите попытку.
failed: Авторизация не удалась. %{origin} is not the configured authorization_url.
log_out: Log out
log_in: Log in
failed: Авторизация не удалась. %{origin}, не настроен authorization_url.
log_out: Выйти
log_in: Войти
##
@ -255,7 +255,7 @@ album:
title: О
published: 'Опубликовано: %{date}'
tracks:
title: Треке
title: Треки
sort:
disc_track: Номер трека
name: Имя
@ -418,14 +418,17 @@ settings:
upgrade_available: 'Доступно обновление (%{version})'
upgrade: 'Обновить до %{version}'
up_to_date: Актуально
share_configuration: Поделиться конфигурацией
shared_configuration:
label: Конфигурация
share: Поделиться
import: Импортировать
restart: Перезапустить сервер
reset: Сброс настроек
about:
title: О
blurb_1: ' это проект с открытым исходным кодом от '
blurb_2: '. It is provided free and with absolutely no warranty. If you paid someone for this software, please let me know.'
donate: Donate
donate: Поддержать
github: GitHub
pusher_connection_list:
not_connected: Не подключен
@ -454,7 +457,7 @@ settings:
unknown: Неизвестно
current_user: Текущий пользователь
authorization: Авторизация
refresh_token: RОбновить токен
refresh_token: Обновить токен
authorized: Авторизованный
read_only: Только для чтения
unauthorized: Неавторизованный
@ -563,9 +566,45 @@ modal:
title: Добро пожаловать в Ирис
username: Пользователь
kiosk:
title: Сейчас играет
title: Воспроизведение
title_window: '%{name} by %{artist} (сейчас воспроизводится)'
lyrics: Текст песни
shared_config:
no_peers: Нет соединений
recipients: Получатели
configurations: Настройки
import_now: Импортировать
imported: Импортирование завершено
share: Поделиться
shared: Настройки предоставлены
push:
title: Поделиться настройками
subtitle: Поделиться авторизациями и настройками интерфейса с другими подключенными пользователями
pushed:
title: Настройки получены
subtitle: Другой пользователь поделилился настройками с вами
server:
title: Импортировать настройки
subtitle: Импортировать авторизации сторонних серверов и настройки интерфейса
label: Сервер
description: Сохранить на сервер чтобы другие пользователи могли импортировать
config:
label: Настройки
ui:
label: Пользовательский интерфейс
description: Тема, сортировка, фильтры и т.д.
spotify:
label: Авторизация Spotify
description: 'Вы вошли в систему как %{name}'
lastfm:
label: Авторизация LastFM
description: 'Вы вошли в систему как %{name}'
genius:
label: Авторизация Genius
description: 'Вы вошли в систему как %{name}'
snapcast:
label: Сервер Snapcast
description: Настройки подключения
share_configuration:
title: Поделиться конфигурацией
subtitle: Передайте свои авторизации и настройки интерфейса другому подключенному пользователю

View File

@ -258,8 +258,10 @@ export function findTrackLyrics(uri) {
// Immediately go and get the first result's lyrics
const lyrics_result = lyrics_results[0];
if (lyrics_result) {
dispatch(getTrackLyrics(track.uri, lyrics_result.path));
}
}
dispatch(uiActions.stopLoading(loader_key));
},
(error) => {

View File

@ -1899,11 +1899,15 @@ const MopidyMiddleware = (function () {
playlistsToLoad.map((uri) => {
request(store, 'playlists.lookup', { uri })
.then((playlist) => {
playlists[uri] = formatPlaylist({
playlists[uri] = {
uri,
loading: false,
...playlist ? formatPlaylist({
name: playlist.name,
uri: playlist.uri,
tracks: formatTracks(playlist.tracks),
});
}) : {},
};
loaded += 1;
if (loaded === toLoad) {
resolve(playlists);

View File

@ -15,10 +15,15 @@ import { SourceIcon } from '../components/Icon';
import DropdownField from '../components/Fields/DropdownField';
import FilterField from '../components/Fields/FilterField';
import { i18n, I18n } from '../locale';
import * as coreActions from '../services/core/actions';
import * as uiActions from '../services/ui/actions';
import * as mopidyActions from '../services/mopidy/actions';
import * as lastfmActions from '../services/lastfm/actions';
import { loadAlbum } from '../services/core/actions';
import { playURIs } from '../services/mopidy/actions';
import { getAlbum } from '../services/lastfm/actions';
import {
setSort,
setWindowTitle,
showContextMenu,
hideContextMenu,
} from '../services/ui/actions';
import { uriSource } from '../util/helpers';
import Button from '../components/Button';
import { makeItemSelector, makeSortSelector } from '../util/selectors';
@ -28,15 +33,6 @@ import { decodeUri, formatContext } from '../util/format';
const SORT_KEY = 'album_tracks';
const Album = () => {
const { loadAlbum } = coreActions;
const { getAlbum } = lastfmActions;
const { playURIs } = mopidyActions;
const {
setSort,
setWindowTitle,
showContextMenu,
hideContextMenu,
} = uiActions;
const dispatch = useDispatch();
const { uri: encodedUri } = useParams();
const uri = decodeUri(encodedUri);

View File

@ -1,6 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import Loader from '../../components/Loader';
import Header from '../../components/Header';
import TrackList from '../../components/TrackList';
@ -10,8 +10,15 @@ import DropdownField from '../../components/Fields/DropdownField';
import FilterField from '../../components/Fields/FilterField';
import Icon from '../../components/Icon';
import ErrorBoundary from '../../components/ErrorBoundary';
import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import {
set,
setWindowTitle,
hideContextMenu,
} from '../../services/ui/actions';
import {
getDirectory,
playURIs,
} from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
import { arrayOf, sortItems, applyFilter } from '../../util/arrays';
import { i18n, I18n } from '../../locale';
@ -19,7 +26,8 @@ import Button from '../../components/Button';
import { encodeUri, decodeUri } from '../../util/format';
import { makeLoadingSelector } from '../../util/selectors';
import ErrorMessage from '../../components/ErrorMessage';
import { withRouter } from '../../util';
const loadingSelector = makeLoadingSelector(['mopidy_library.(browse|lookup)']);
const Breadcrumbs = ({ uri }) => {
let parent_uri = uri || null;
@ -64,61 +72,39 @@ const Subdirectories = ({ items, view }) => {
);
};
class BrowseDirectory extends React.Component {
constructor(props) {
super(props);
const BrowseDirectory = () => {
const dispatch = useDispatch();
const [filter, setFilter] = useState('');
const directoryInState = useSelector(({ mopidy }) => mopidy?.directory || {});
const view = useSelector(({ ui }) => ui?.library_directory_view);
const loading = useSelector(loadingSelector);
this.state = {
filter: '',
};
let { uri, name } = useParams();
uri = decodeUri(uri);
name = decodeURIComponent(name);
const uriMatcher = [uri, decodeURIComponent(uri)]; // Lenient matching due to encoding diffs
const directory = directoryInState && uriMatcher.includes(directoryInState.uri)
? directoryInState
: undefined;
useEffect(() => {
dispatch(setWindowTitle(i18n('library.browse_directory.title')));
dispatch(getDirectory(uri));
}, []);
useEffect(() => {
dispatch(getDirectory(uri));
}, [uri]);
const onViewChange = (value) => {
dispatch(set({ library_directory_view: value }));
dispatch(hideContextMenu());
}
componentDidMount() {
const {
uiActions: {
setWindowTitle,
},
} = this.props;
setWindowTitle(i18n('library.browse_directory.title'));
this.loadDirectory();
}
componentDidUpdate = ({ uri: prevUri }) => {
const { uri } = this.props;
if (uri && uri !== prevUri) {
this.loadDirectory();
}
}
loadDirectory = () => {
const {
uri,
mopidyActions: {
getDirectory,
},
} = this.props;
getDirectory(uri);
}
playAll = () => {
const {
uri,
mopidyActions: {
playURIs,
},
uiActions: {
hideContextMenu,
},
directory: {
tracks,
} = {},
} = this.props;
const playAll = () => {
if (!tracks || !tracks.length) return;
dispatch(
playURIs({
uris: arrayOf('uri', sortItems(tracks, 'name')),
from: {
@ -126,28 +112,16 @@ class BrowseDirectory extends React.Component {
type: 'browse',
uri,
},
});
hideContextMenu();
})
);
dispatch(hideContextMenu());
}
goBack = () => {
const { uiActions: { hideContextMenu } } = this.props;
const goBack = () => {
dispatch(hideContextMenu());
window.history.back();
hideContextMenu();
}
render = () => {
const {
uri,
directory,
uiActions,
loading,
view,
name,
} = this.props;
const { filter } = this.state;
if (!directory || (!directory.subdirectories && !directory.tracks)) {
if (loading) {
return <Loader body loading />;
@ -185,8 +159,8 @@ class BrowseDirectory extends React.Component {
<>
<FilterField
initialValue={filter}
handleChange={(value) => this.setState({ filter: value })}
onSubmit={() => uiActions.hideContextMenu()}
handleChange={setFilter}
onSubmit={() => dispatch(hideContextMenu())}
/>
<DropdownField
icon="visibility"
@ -194,11 +168,11 @@ class BrowseDirectory extends React.Component {
value={view}
valueAsLabel
options={view_options}
handleChange={(value) => { uiActions.set({ library_directory_view: value }); uiActions.hideContextMenu(); }}
handleChange={onViewChange}
/>
{tracks && (
<Button
onClick={this.playAll}
onClick={playAll}
noHover
discrete
tracking={{ category: 'Directory', action: 'Play' }}
@ -208,9 +182,9 @@ class BrowseDirectory extends React.Component {
</Button>
)}
<Button
onClick={(e) => { uiActions.hideContextMenu(); this.goBack(e); }}
noHover
onClick={goBack}
tracking={{ category: 'Directory', action: 'Back' }}
noHover
>
<Icon name="keyboard_backspace" />
<I18n path="actions.back" />
@ -220,7 +194,7 @@ class BrowseDirectory extends React.Component {
return (
<div className="view library-local-view">
<Header options={options} uiActions={uiActions}>
<Header options={options}>
<Icon name="folder" type="material" />
<div className="header__text">
{name || i18n('library.browse_directory.title')}
@ -246,39 +220,6 @@ class BrowseDirectory extends React.Component {
</section>
</div>
);
}
}
const loadingSelector = makeLoadingSelector(['mopidy_library.(browse|lookup)']);
const mapStateToProps = (state, ownProps) => {
console.debug('browser directory', ownProps)
const {
mopidy: {
directory: _directory = {},
},
ui: {
library_directory_view: view,
},
} = state;
const uri = decodeUri(ownProps.params.uri);
const uriMatcher = [uri, decodeURIComponent(uri)]; // Lenient matching due to encoding diffs
const directory = _directory && uriMatcher.includes(_directory.uri)
? _directory
: undefined;
return {
uri,
name: decodeURIComponent(ownProps.params.name),
loading: loadingSelector(state),
directory,
view,
};
};
const mapDispatchToProps = (dispatch) => ({
uiActions: bindActionCreators(uiActions, dispatch),
mopidyActions: bindActionCreators(mopidyActions, dispatch),
spotifyActions: bindActionCreators(spotifyActions, dispatch),
});
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(BrowseDirectory));
export default BrowseDirectory;

View File

@ -106,7 +106,7 @@ const KioskMode = () => {
if (current_track.lyrics) return;
// We got results, but failed to load the lyrics, so re-try
if (current_track.lyrics_results && current_track.lyrics === null) {
if (current_track?.lyrics_results && current_track.lyrics === null) {
dispatch(geniusActions.getTrackLyrics(current_track.uri, current_track.path));
return;
}

View File

@ -12,7 +12,7 @@
z-index: 99;
font-size: 13px;
font-weight: 500;
font-family: "Overpass";
font-family: $font-family-alt;
&__section {
@include animate();

View File

@ -3,7 +3,7 @@
@include noselect();
font-size: 13px;
font-weight: 500;
font-family: "Overpass";
font-family: $font-family-alt;
position: relative;
display: inline-block;

View File

@ -44,7 +44,7 @@ main {
button {
font-size: 13px;
font-weight: 800;
font-family: "Overpass";
font-family: $font-family-alt;
background: transparent;
text-transform: none;
padding: 13px 10px;

View File

@ -29,7 +29,7 @@
line-height: 1em;
&__item {
font-family: "Overpass";
font-family: $font-family-alt;
font-weight: 600;
font-size: 1.05rem;
color: colour('white');

View File

@ -32,7 +32,7 @@
body,
html {
font-family: "Overpass", Helvetica, Arial, sans-serif;
font-family: $font-family-alt;
font-size: 14px;
letter-spacing: -0.02rem;
touch-action: manipulation;

View File

@ -17,7 +17,7 @@ select {
padding: 10px 14px;
background: rgba(128, 128, 128, 0.05);
color: colour('white');
font-family: "Overpass", Helvetica, Arial, sans-serif;
font-family: $font-family-alt;
font-size: 14px;
border-radius: 3px;
letter-spacing: -0.01rem;

View File

@ -4,6 +4,7 @@ $bp_medium: 800px;
$bp_small: 500px;
$bp_narrow: 360px;
$bp_shallow: 650px;
$font-family-alt: "Overpass", Helvetica, Arial, sans-serif;
@mixin one_line_text {
white-space: nowrap;
@ -343,7 +344,7 @@ $bp_shallow: 650px;
}
@mixin feature_font() {
font-family: "Overpass";
font-family: $font-family-alt;
font-weight: 600;
}