feat(train): signing in to Jellyfin and marking playlists (ADR 0030, D47)
Music's decisions as D47, and its first part: the music screen from the account sheet, on Android, signs in to the person's Jellyfin with Quick Connect, else a password, and lists their playlists of music to mark for running. The token is in the keyring, the server and the marks in the person's music.json, nothing on Train's server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
5ff9b2e053
commit
3336fe4eca
5 changed files with 2364 additions and 3 deletions
|
|
@ -468,5 +468,31 @@
|
|||
"recordingMapHint": "Wischen für die Karte",
|
||||
"recordingFiguresHint": "Zurückwischen für die Werte",
|
||||
"recordingNorthUp": "Norden oben",
|
||||
"recordingHeadingUp": "Bewegungsrichtung oben"
|
||||
"recordingHeadingUp": "Bewegungsrichtung oben",
|
||||
"musicTitle": "Musik",
|
||||
"musicHint": "Jellyfin-Playlists zum Laufen",
|
||||
"musicIntro": "Train spielt Musik von deinem Jellyfin-Server und wählt Titel, deren Takt zu deinen Schritten passt. Dein Konto und deine Musik bleiben auf diesem Telefon.",
|
||||
"musicServer": "Jellyfin-Server",
|
||||
"musicConnect": "Verbinden",
|
||||
"musicBadAddress": "Gib die Adresse des Servers ein, etwa jellyfin.example.org.",
|
||||
"musicUnreachable": "Der Server ist nicht erreichbar. Prüfe die Adresse und die Verbindung.",
|
||||
"musicNotJellyfin": "Unter dieser Adresse ist kein Jellyfin-Server.",
|
||||
"musicRefused": "Jellyfin hat abgelehnt. Prüfe Benutzername und Passwort.",
|
||||
"musicCodeExpired": "Der Code ist abgelaufen.",
|
||||
"musicFailed": "Jellyfin hat mit einem Fehler geantwortet. Versuch es später noch einmal.",
|
||||
"musicQuickConnect": "Um dich bei {server} anzumelden, gib diesen Code in Jellyfin auf einem anderen Gerät ein, unter Einstellungen, Quick Connect.",
|
||||
"musicNewCode": "Neuer Code",
|
||||
"musicBack": "Zurück",
|
||||
"musicUsePassword": "Mit Passwort",
|
||||
"musicPasswordIntro": "Melde dich mit deinem Jellyfin-Benutzernamen und Passwort bei {server} an.",
|
||||
"musicUserName": "Benutzername",
|
||||
"musicPassword": "Passwort",
|
||||
"musicSignIn": "Anmelden",
|
||||
"musicSignedInAs": "Angemeldet als {name}",
|
||||
"musicSignOut": "Abmelden",
|
||||
"musicPlaylists": "Playlists zum Laufen",
|
||||
"musicPlaylistsHint": "Train wählt aus den Titeln der Playlists, die du markierst, und behält sie auf diesem Telefon.",
|
||||
"musicNoPlaylists": "Auf diesem Server gibt es noch keine Musik-Playlists.",
|
||||
"musicRetry": "Erneut versuchen",
|
||||
"musicTracks": "{count, plural, =1{1 Titel} other{{count} Titel}}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -588,5 +588,38 @@
|
|||
"recordingMapHint": "Swipe for the map",
|
||||
"recordingFiguresHint": "Swipe back for the figures",
|
||||
"recordingNorthUp": "North up",
|
||||
"recordingHeadingUp": "Heading up"
|
||||
"recordingHeadingUp": "Heading up",
|
||||
"musicTitle": "Music",
|
||||
"@musicTitle": {"description": "The music screen's title, and its tile in the account sheet."},
|
||||
"musicHint": "Jellyfin playlists to run to",
|
||||
"@musicHint": {"description": "Under Music in the account sheet."},
|
||||
"musicIntro": "Train plays music from your Jellyfin server, choosing tracks whose beat fits your steps. Your account and music stay on this phone.",
|
||||
"musicServer": "Jellyfin server",
|
||||
"@musicServer": {"description": "The label of the server's address."},
|
||||
"musicConnect": "Connect",
|
||||
"musicBadAddress": "Enter the server's address, such as jellyfin.example.org.",
|
||||
"musicUnreachable": "The server can't be reached. Check the address and the connection.",
|
||||
"musicNotJellyfin": "There is no Jellyfin server at this address.",
|
||||
"musicRefused": "Jellyfin refused. Check the user name and password.",
|
||||
"musicCodeExpired": "The code has expired.",
|
||||
"musicFailed": "Jellyfin answered with an error. Try again later.",
|
||||
"musicQuickConnect": "To sign in to {server}, enter this code in Jellyfin on another device, under Settings, Quick Connect.",
|
||||
"@musicQuickConnect": {"placeholders": {"server": {"type": "String"}}},
|
||||
"musicNewCode": "New code",
|
||||
"musicBack": "Back",
|
||||
"musicUsePassword": "Use a password",
|
||||
"musicPasswordIntro": "Sign in to {server} with your Jellyfin user name and password.",
|
||||
"@musicPasswordIntro": {"placeholders": {"server": {"type": "String"}}},
|
||||
"musicUserName": "User name",
|
||||
"musicPassword": "Password",
|
||||
"musicSignIn": "Sign in",
|
||||
"musicSignedInAs": "Signed in as {name}",
|
||||
"@musicSignedInAs": {"placeholders": {"name": {"type": "String"}}},
|
||||
"musicSignOut": "Sign out",
|
||||
"musicPlaylists": "Playlists for running",
|
||||
"musicPlaylistsHint": "Train chooses from the tracks of the playlists you mark, and keeps them on this phone.",
|
||||
"musicNoPlaylists": "There are no music playlists on this server yet.",
|
||||
"musicRetry": "Try again",
|
||||
"musicTracks": "{count, plural, =1{1 track} other{{count} tracks}}",
|
||||
"@musicTracks": {"placeholders": {"count": {"type": "int"}}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2835,6 +2835,162 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Heading up'**
|
||||
String get recordingHeadingUp;
|
||||
|
||||
/// The music screen's title, and its tile in the account sheet.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Music'**
|
||||
String get musicTitle;
|
||||
|
||||
/// Under Music in the account sheet.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Jellyfin playlists to run to'**
|
||||
String get musicHint;
|
||||
|
||||
/// No description provided for @musicIntro.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Train plays music from your Jellyfin server, choosing tracks whose beat fits your steps. Your account and music stay on this phone.'**
|
||||
String get musicIntro;
|
||||
|
||||
/// The label of the server's address.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Jellyfin server'**
|
||||
String get musicServer;
|
||||
|
||||
/// No description provided for @musicConnect.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Connect'**
|
||||
String get musicConnect;
|
||||
|
||||
/// No description provided for @musicBadAddress.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Enter the server\'s address, such as jellyfin.example.org.'**
|
||||
String get musicBadAddress;
|
||||
|
||||
/// No description provided for @musicUnreachable.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The server can\'t be reached. Check the address and the connection.'**
|
||||
String get musicUnreachable;
|
||||
|
||||
/// No description provided for @musicNotJellyfin.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'There is no Jellyfin server at this address.'**
|
||||
String get musicNotJellyfin;
|
||||
|
||||
/// No description provided for @musicRefused.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Jellyfin refused. Check the user name and password.'**
|
||||
String get musicRefused;
|
||||
|
||||
/// No description provided for @musicCodeExpired.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The code has expired.'**
|
||||
String get musicCodeExpired;
|
||||
|
||||
/// No description provided for @musicFailed.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Jellyfin answered with an error. Try again later.'**
|
||||
String get musicFailed;
|
||||
|
||||
/// No description provided for @musicQuickConnect.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'To sign in to {server}, enter this code in Jellyfin on another device, under Settings, Quick Connect.'**
|
||||
String musicQuickConnect(String server);
|
||||
|
||||
/// No description provided for @musicNewCode.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'New code'**
|
||||
String get musicNewCode;
|
||||
|
||||
/// No description provided for @musicBack.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Back'**
|
||||
String get musicBack;
|
||||
|
||||
/// No description provided for @musicUsePassword.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Use a password'**
|
||||
String get musicUsePassword;
|
||||
|
||||
/// No description provided for @musicPasswordIntro.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sign in to {server} with your Jellyfin user name and password.'**
|
||||
String musicPasswordIntro(String server);
|
||||
|
||||
/// No description provided for @musicUserName.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'User name'**
|
||||
String get musicUserName;
|
||||
|
||||
/// No description provided for @musicPassword.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Password'**
|
||||
String get musicPassword;
|
||||
|
||||
/// No description provided for @musicSignIn.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sign in'**
|
||||
String get musicSignIn;
|
||||
|
||||
/// No description provided for @musicSignedInAs.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Signed in as {name}'**
|
||||
String musicSignedInAs(String name);
|
||||
|
||||
/// No description provided for @musicSignOut.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Sign out'**
|
||||
String get musicSignOut;
|
||||
|
||||
/// No description provided for @musicPlaylists.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Playlists for running'**
|
||||
String get musicPlaylists;
|
||||
|
||||
/// No description provided for @musicPlaylistsHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Train chooses from the tracks of the playlists you mark, and keeps them on this phone.'**
|
||||
String get musicPlaylistsHint;
|
||||
|
||||
/// No description provided for @musicNoPlaylists.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'There are no music playlists on this server yet.'**
|
||||
String get musicNoPlaylists;
|
||||
|
||||
/// No description provided for @musicRetry.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Try again'**
|
||||
String get musicRetry;
|
||||
|
||||
/// No description provided for @musicTracks.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =1{1 track} other{{count} tracks}}'**
|
||||
String musicTracks(int count);
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -1681,4 +1681,104 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get recordingHeadingUp => 'Bewegungsrichtung oben';
|
||||
|
||||
@override
|
||||
String get musicTitle => 'Musik';
|
||||
|
||||
@override
|
||||
String get musicHint => 'Jellyfin-Playlists zum Laufen';
|
||||
|
||||
@override
|
||||
String get musicIntro =>
|
||||
'Train spielt Musik von deinem Jellyfin-Server und wählt Titel, deren Takt zu deinen Schritten passt. Dein Konto und deine Musik bleiben auf diesem Telefon.';
|
||||
|
||||
@override
|
||||
String get musicServer => 'Jellyfin-Server';
|
||||
|
||||
@override
|
||||
String get musicConnect => 'Verbinden';
|
||||
|
||||
@override
|
||||
String get musicBadAddress =>
|
||||
'Gib die Adresse des Servers ein, etwa jellyfin.example.org.';
|
||||
|
||||
@override
|
||||
String get musicUnreachable =>
|
||||
'Der Server ist nicht erreichbar. Prüfe die Adresse und die Verbindung.';
|
||||
|
||||
@override
|
||||
String get musicNotJellyfin =>
|
||||
'Unter dieser Adresse ist kein Jellyfin-Server.';
|
||||
|
||||
@override
|
||||
String get musicRefused =>
|
||||
'Jellyfin hat abgelehnt. Prüfe Benutzername und Passwort.';
|
||||
|
||||
@override
|
||||
String get musicCodeExpired => 'Der Code ist abgelaufen.';
|
||||
|
||||
@override
|
||||
String get musicFailed =>
|
||||
'Jellyfin hat mit einem Fehler geantwortet. Versuch es später noch einmal.';
|
||||
|
||||
@override
|
||||
String musicQuickConnect(String server) {
|
||||
return 'Um dich bei $server anzumelden, gib diesen Code in Jellyfin auf einem anderen Gerät ein, unter Einstellungen, Quick Connect.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get musicNewCode => 'Neuer Code';
|
||||
|
||||
@override
|
||||
String get musicBack => 'Zurück';
|
||||
|
||||
@override
|
||||
String get musicUsePassword => 'Mit Passwort';
|
||||
|
||||
@override
|
||||
String musicPasswordIntro(String server) {
|
||||
return 'Melde dich mit deinem Jellyfin-Benutzernamen und Passwort bei $server an.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get musicUserName => 'Benutzername';
|
||||
|
||||
@override
|
||||
String get musicPassword => 'Passwort';
|
||||
|
||||
@override
|
||||
String get musicSignIn => 'Anmelden';
|
||||
|
||||
@override
|
||||
String musicSignedInAs(String name) {
|
||||
return 'Angemeldet als $name';
|
||||
}
|
||||
|
||||
@override
|
||||
String get musicSignOut => 'Abmelden';
|
||||
|
||||
@override
|
||||
String get musicPlaylists => 'Playlists zum Laufen';
|
||||
|
||||
@override
|
||||
String get musicPlaylistsHint =>
|
||||
'Train wählt aus den Titeln der Playlists, die du markierst, und behält sie auf diesem Telefon.';
|
||||
|
||||
@override
|
||||
String get musicNoPlaylists =>
|
||||
'Auf diesem Server gibt es noch keine Musik-Playlists.';
|
||||
|
||||
@override
|
||||
String get musicRetry => 'Erneut versuchen';
|
||||
|
||||
@override
|
||||
String musicTracks(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count Titel',
|
||||
one: '1 Titel',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1671,6 +1671,104 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get recordingHeadingUp => 'Heading up';
|
||||
|
||||
@override
|
||||
String get musicTitle => 'Music';
|
||||
|
||||
@override
|
||||
String get musicHint => 'Jellyfin playlists to run to';
|
||||
|
||||
@override
|
||||
String get musicIntro =>
|
||||
'Train plays music from your Jellyfin server, choosing tracks whose beat fits your steps. Your account and music stay on this phone.';
|
||||
|
||||
@override
|
||||
String get musicServer => 'Jellyfin server';
|
||||
|
||||
@override
|
||||
String get musicConnect => 'Connect';
|
||||
|
||||
@override
|
||||
String get musicBadAddress =>
|
||||
'Enter the server\'s address, such as jellyfin.example.org.';
|
||||
|
||||
@override
|
||||
String get musicUnreachable =>
|
||||
'The server can\'t be reached. Check the address and the connection.';
|
||||
|
||||
@override
|
||||
String get musicNotJellyfin => 'There is no Jellyfin server at this address.';
|
||||
|
||||
@override
|
||||
String get musicRefused =>
|
||||
'Jellyfin refused. Check the user name and password.';
|
||||
|
||||
@override
|
||||
String get musicCodeExpired => 'The code has expired.';
|
||||
|
||||
@override
|
||||
String get musicFailed => 'Jellyfin answered with an error. Try again later.';
|
||||
|
||||
@override
|
||||
String musicQuickConnect(String server) {
|
||||
return 'To sign in to $server, enter this code in Jellyfin on another device, under Settings, Quick Connect.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get musicNewCode => 'New code';
|
||||
|
||||
@override
|
||||
String get musicBack => 'Back';
|
||||
|
||||
@override
|
||||
String get musicUsePassword => 'Use a password';
|
||||
|
||||
@override
|
||||
String musicPasswordIntro(String server) {
|
||||
return 'Sign in to $server with your Jellyfin user name and password.';
|
||||
}
|
||||
|
||||
@override
|
||||
String get musicUserName => 'User name';
|
||||
|
||||
@override
|
||||
String get musicPassword => 'Password';
|
||||
|
||||
@override
|
||||
String get musicSignIn => 'Sign in';
|
||||
|
||||
@override
|
||||
String musicSignedInAs(String name) {
|
||||
return 'Signed in as $name';
|
||||
}
|
||||
|
||||
@override
|
||||
String get musicSignOut => 'Sign out';
|
||||
|
||||
@override
|
||||
String get musicPlaylists => 'Playlists for running';
|
||||
|
||||
@override
|
||||
String get musicPlaylistsHint =>
|
||||
'Train chooses from the tracks of the playlists you mark, and keeps them on this phone.';
|
||||
|
||||
@override
|
||||
String get musicNoPlaylists =>
|
||||
'There are no music playlists on this server yet.';
|
||||
|
||||
@override
|
||||
String get musicRetry => 'Try again';
|
||||
|
||||
@override
|
||||
String musicTracks(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count tracks',
|
||||
one: '1 track',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
}
|
||||
|
||||
/// The translations for English, as used in the United Kingdom (`en_GB`).
|
||||
|
|
|
|||
Loading…
Reference in a new issue