Skip to content

Commit

Permalink
fix: internet archive errors after their ddos attack recovery (#979)
Browse files Browse the repository at this point in the history
  • Loading branch information
Feichtmeier authored Oct 25, 2024
1 parent 59851fe commit 13fefb6
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 127 deletions.
7 changes: 7 additions & 0 deletions lib/common/logging.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:flutter/foundation.dart';

void printMessageInDebugMode(String message) {
if (kDebugMode) {
print(message);
}
}
4 changes: 4 additions & 0 deletions lib/common/view/safe_network_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:path/path.dart' as p;
import 'package:xdg_directories/xdg_directories.dart';

import '../../extensions/build_context_x.dart';
import '../logging.dart';
import 'icons.dart';

class SafeNetworkImage extends StatelessWidget {
Expand All @@ -21,6 +22,7 @@ class SafeNetworkImage extends StatelessWidget {
this.errorIcon,
this.height,
this.width,
this.httpHeaders,
});

final String? url;
Expand All @@ -30,6 +32,7 @@ class SafeNetworkImage extends StatelessWidget {
final Widget? errorIcon;
final double? height;
final double? width;
final Map<String, String>? httpHeaders;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -64,6 +67,7 @@ class SafeNetworkImage extends StatelessWidget {
width: width,
),
errorWidget: (context, url, _) => errorWidget,
errorListener: (e) => printMessageInDebugMode(e.toString()),
);
} on Exception {
return fallBack;
Expand Down
6 changes: 5 additions & 1 deletion lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,15 @@ const shops = <String, String>{

const kSponsorLink = 'https://github.com/sponsors/Feichtmeier';

const kAlbumArtHeaders = {
const kMusicBrainzHeaders = {
'Accept': 'application/json',
'User-Agent': '$kAppTitle ($kRepoUrl)',
};

const kInternetArchiveHeaders = {
'User-Agent': '$kAppTitle ($kRepoUrl)',
};

const kAudioHeaderDescriptionWidth = 400.0;

const kShowLeadingThreshold = 3000;
34 changes: 22 additions & 12 deletions lib/expose/expose_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,23 @@ class ExposeService {
_discordRPC?.isConnectedStream ?? Stream.value(false);

Future<void> exposeTitleOnline({
required String line1,
required String line2,
required String line3,
required String title,
required String artist,
required String additionalInfo,
String? imageUrl,
}) async {
await _exposeTitleToDiscord(
title: title,
artist: artist,
additionalInfo: additionalInfo,
imageUrl: imageUrl,
);
}

Future<void> _exposeTitleToDiscord({
required String title,
required String artist,
required String additionalInfo,
String? imageUrl,
}) async {
try {
Expand All @@ -26,11 +40,11 @@ class ExposeService {
await _discordRPC?.setActivity(
activity: RPCActivity(
assets: RPCAssets(
largeText: line3,
largeText: additionalInfo,
largeImage: imageUrl,
),
details: line1,
state: line2,
details: title,
state: artist,
activityType: ActivityType.listening,
),
);
Expand All @@ -41,11 +55,7 @@ class ExposeService {
}

Future<void> connect() async {
try {
await _discordRPC?.connect();
} on Exception catch (e) {
_errorController.add(e.toString());
}
await connectToDiscord();
}

Future<void> connectToDiscord() async {
Expand All @@ -65,7 +75,7 @@ class ExposeService {
}

Future<void> dispose() async {
await _discordRPC?.disconnect();
await disconnectFromDiscord();
await _errorController.close();
}
}
2 changes: 0 additions & 2 deletions lib/player/player_model.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:async';

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:safe_change_notifier/safe_change_notifier.dart';

Expand Down Expand Up @@ -106,7 +105,6 @@ class PlayerModel extends SafeChangeNotifier {
index: index,
);

Color? get color => _playerService.color;
String? get remoteImageUrl => _playerService.remoteImageUrl;

bool _isUpNextExpanded = false;
Expand Down
98 changes: 35 additions & 63 deletions lib/player/player_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import 'dart:math';
import 'dart:typed_data';

import 'package:audio_service/audio_service.dart';
import 'package:flutter/material.dart';
import 'package:html/parser.dart';
import 'package:media_kit/media_kit.dart' hide PlayerState;
import 'package:media_kit_video/media_kit_video.dart';
import 'package:palette_generator/palette_generator.dart';
import 'package:path/path.dart' as p;
import 'package:smtc_windows/smtc_windows.dart';

Expand Down Expand Up @@ -67,7 +65,7 @@ class PlayerService {

MpvMetaData? _mpvMetaData;
MpvMetaData? get mpvMetaData => _mpvMetaData;
void _setMpvMetaData(MpvMetaData? value) {
Future<void> _setMpvMetaData(MpvMetaData? value) async {
_mpvMetaData = value;

var validHistoryElement = _mpvMetaData?.icyTitle.isNotEmpty == true;
Expand All @@ -88,6 +86,8 @@ class PlayerService {
icyName: audio?.title?.trim() ?? _mpvMetaData?.icyName ?? '',
),
);

await _processParsedIcyTitle(mpvMetaData!.icyTitle.everyWordCapitalized);
}
_propertiesChangedController.add(true);
}
Expand Down Expand Up @@ -224,12 +224,13 @@ class PlayerService {
),
);
}
_setMediaControlsMetaData(audio: audio!);
_loadColorAndSetRemoteUrl();
_exposeService.exposeTitleOnline(
line1: audio?.title ?? '',
line2: audio?.artist ?? '',
line3: audio?.album ?? '',
_setRemoteImageUrl(_audio?.imageUrl ?? _audio?.albumArtUrl);

await _setMediaControlsMetaData(audio: audio!);
await _exposeService.exposeTitleOnline(
title: audio?.title ?? '',
artist: audio?.artist ?? '',
additionalInfo: audio?.album ?? '',
imageUrl: audio?.imageUrl ?? audio?.albumArtUrl,
);
_firstPlay = false;
Expand Down Expand Up @@ -291,32 +292,12 @@ class PlayerService {
final newData = MpvMetaData.fromJson(data);
final parsedIcyTitle =
HtmlParser(newData.icyTitle).parseFragment().text;
if (parsedIcyTitle == _mpvMetaData?.icyTitle) return;
if (parsedIcyTitle == null ||
parsedIcyTitle == _mpvMetaData?.icyTitle) {
return;
}

_setMpvMetaData(newData.copyWith(icyTitle: parsedIcyTitle));

if (parsedIcyTitle == null) return;

final songInfo = parsedIcyTitle.splitByDash;
_onlineArtService.fetchAlbumArt(parsedIcyTitle).then(
(albumArt) async {
final mergedAudio =
(_audio ?? const Audio(audioType: AudioType.radio)).copyWith(
imageUrl: albumArt,
title: songInfo.songName,
artist: songInfo.artist,
);
await _setMediaControlsMetaData(audio: mergedAudio);
await _loadColorAndSetRemoteUrl(artUrl: albumArt);

await _exposeService.exposeTitleOnline(
line1: songInfo.songName ?? '',
line2: songInfo.artist ?? '',
line3: _audio?.title ?? 'Internet Radio',
imageUrl: albumArt,
);
},
);
},
);

Expand All @@ -343,6 +324,27 @@ class PlayerService {
await _setPlayerState();
}

Future<void> _processParsedIcyTitle(String parsedIcyTitle) async {
final songInfo = parsedIcyTitle.splitByDash;
final albumArt = await _onlineArtService.fetchAlbumArt(parsedIcyTitle);

final mergedAudio =
(_audio ?? const Audio(audioType: AudioType.radio)).copyWith(
imageUrl: albumArt,
title: songInfo.songName,
artist: songInfo.artist,
);
await _setMediaControlsMetaData(audio: mergedAudio);
_setRemoteImageUrl(albumArt ?? _audio?.imageUrl ?? _audio?.albumArtUrl);

await _exposeService.exposeTitleOnline(
title: songInfo.songName ?? '',
artist: songInfo.artist ?? '',
additionalInfo: _audio?.title ?? 'Internet Radio',
imageUrl: albumArt,
);
}

Future<void> playNext() async {
await safeLastPosition();
if (!repeatSingle && nextAudio != null) {
Expand Down Expand Up @@ -457,43 +459,13 @@ class PlayerService {
await _play(newPosition: _position);
}

Color? _color;
Color? get color => _color;

String? _remoteImageUrl;
String? get remoteImageUrl => _remoteImageUrl;
void _setRemoteImageUrl(String? url) {
_remoteImageUrl = url;
_propertiesChangedController.add(true);
}

Future<void> _loadColorAndSetRemoteUrl({String? artUrl}) async {
final pic = CoverStore().get(_audio?.albumId);
if (pic == null &&
audio?.imageUrl == null &&
audio?.albumArtUrl == null &&
artUrl == null) {
_color = null;
_setRemoteImageUrl(null);

return;
}

ImageProvider? image;
if (pic != null) {
_setRemoteImageUrl(null);
image = MemoryImage(pic);
} else {
final url = artUrl ?? _audio!.imageUrl ?? _audio!.albumArtUrl!;
_setRemoteImageUrl(url);
image = NetworkImage(
url,
);
}
final generator = await PaletteGenerator.fromImageProvider(image);
_color = generator.dominantColor?.color;
}

Future<void> _setPlayerState() async {
final playerState = await _readPlayerState();

Expand Down
14 changes: 13 additions & 1 deletion lib/player/view/bottom_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import '../../common/view/theme.dart';
import '../../extensions/build_context_x.dart';
import '../../l10n/l10n.dart';
import '../../player/player_model.dart';
import 'blurred_full_height_player_image.dart';
import 'bottom_player_image.dart';
import 'play_button.dart';
import 'playback_rate_button.dart';
Expand Down Expand Up @@ -145,6 +146,17 @@ class BottomPlayer extends StatelessWidget with WatchItMixin {
);
}

return player;
if (isVideo == true) {
return player;
}

return Stack(
children: [
BlurredFullHeightPlayerImage(
size: Size(context.mediaQuerySize.width, bottomPlayerHeight),
),
player,
],
);
}
}
6 changes: 1 addition & 5 deletions lib/player/view/player_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import 'package:flutter/material.dart';
import 'package:watch_it/watch_it.dart';

import '../../app/app_model.dart';
import '../../common/view/theme.dart';
import '../../extensions/build_context_x.dart';
import '../player_model.dart';
import 'bottom_player.dart';
import 'full_height_player.dart';

Expand Down Expand Up @@ -45,8 +43,6 @@ class _PlayerViewState extends State<PlayerView> {
@override
Widget build(BuildContext context) {
final theme = context.theme;
final c = watchPropertyValue((PlayerModel m) => m.color);
final color = getPlayerBg(c, theme.cardColor);

Widget player;
if (widget.position != PlayerPosition.bottom) {
Expand All @@ -66,7 +62,7 @@ class _PlayerViewState extends State<PlayerView> {
// VERY important to reduce CPU usage
return RepaintBoundary(
child: Material(
color: color,
color: theme.cardColor,
child: player,
),
);
Expand Down
Loading

0 comments on commit 13fefb6

Please sign in to comment.