119 lines
3.2 KiB
Dart
119 lines
3.2 KiB
Dart
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
|
|
import '../extensions/helpers_extension.dart';
|
|
|
|
part 'playlist_id.freezed.dart';
|
|
|
|
/// Encapsulates a valid YouTube playlist ID.
|
|
@freezed
|
|
class PlaylistId with _$PlaylistId {
|
|
static final _regMatchExp =
|
|
RegExp(r'youtube\..+?/playlist.*?list=(.*?)(?:&|/|$)');
|
|
static final _compositeMatchExp =
|
|
RegExp(r'youtube\..+?/watch.*?list=(.*?)(?:&|/|$)');
|
|
static final _shortCompositeMatchExp =
|
|
RegExp(r'youtu\.be/.*?/.*?list=(.*?)(?:&|/|$)');
|
|
static final _embedCompositeMatchExp =
|
|
RegExp(r'youtube\..+?/embed/.*?/.*?list=(.*?)(?:&|/|$)');
|
|
|
|
/// Initializes an instance of [PlaylistId]
|
|
factory PlaylistId(String idOrUrl) {
|
|
final id = parsePlaylistId(idOrUrl);
|
|
if (id == null) {
|
|
throw ArgumentError.value(idOrUrl, 'idOrUrl', 'Invalid url');
|
|
}
|
|
return PlaylistId._internal(id);
|
|
}
|
|
|
|
const PlaylistId._();
|
|
|
|
const factory PlaylistId._internal(
|
|
|
|
/// The playlist id as string.
|
|
String value) = _PlaylistId;
|
|
|
|
/// Converts [obj] to a [PlaylistId] by calling .toString on that object.
|
|
/// If it is already a [PlaylistId], [obj] is returned
|
|
factory PlaylistId.fromString(dynamic obj) {
|
|
if (obj is PlaylistId) {
|
|
return obj;
|
|
}
|
|
return PlaylistId(obj.toString());
|
|
}
|
|
|
|
/// Returns true if the given [playlistId] is valid.
|
|
static bool validatePlaylistId(String playlistId) {
|
|
playlistId = playlistId.toUpperCase();
|
|
|
|
if (playlistId.isNullOrWhiteSpace) {
|
|
return false;
|
|
}
|
|
|
|
// Watch later
|
|
if (playlistId == 'WL') {
|
|
return true;
|
|
}
|
|
|
|
// My mix playlist
|
|
if (playlistId == 'RDMM') {
|
|
return true;
|
|
}
|
|
|
|
if (!playlistId.startsWith('PL') &&
|
|
!playlistId.startsWith('RD') &&
|
|
!playlistId.startsWith('UL') &&
|
|
!playlistId.startsWith('UU') &&
|
|
!playlistId.startsWith('PU') &&
|
|
!playlistId.startsWith('OL') &&
|
|
!playlistId.startsWith('LL') &&
|
|
!playlistId.startsWith('FL')) {
|
|
return false;
|
|
}
|
|
|
|
if (playlistId.length < 13) {
|
|
return false;
|
|
}
|
|
|
|
return !RegExp(r'[^0-9a-zA-Z_\-]').hasMatch(playlistId);
|
|
}
|
|
|
|
/// Parses a playlist [url] returning its id.
|
|
/// If the [url] is a valid it is returned itself.
|
|
static String? parsePlaylistId(String url) {
|
|
if (url.isNullOrWhiteSpace) {
|
|
return null;
|
|
}
|
|
|
|
if (validatePlaylistId(url)) {
|
|
return url;
|
|
}
|
|
|
|
var regMatch = _regMatchExp.firstMatch(url)?.group(1);
|
|
if (!regMatch.isNullOrWhiteSpace && validatePlaylistId(regMatch!)) {
|
|
return regMatch;
|
|
}
|
|
|
|
var compositeMatch = _compositeMatchExp.firstMatch(url)?.group(1);
|
|
if (!compositeMatch.isNullOrWhiteSpace &&
|
|
validatePlaylistId(compositeMatch!)) {
|
|
return compositeMatch;
|
|
}
|
|
|
|
var shortCompositeMatch = _shortCompositeMatchExp.firstMatch(url)?.group(1);
|
|
if (!shortCompositeMatch.isNullOrWhiteSpace &&
|
|
validatePlaylistId(shortCompositeMatch!)) {
|
|
return shortCompositeMatch;
|
|
}
|
|
|
|
var embedCompositeMatch = _embedCompositeMatchExp.firstMatch(url)?.group(1);
|
|
if (!embedCompositeMatch.isNullOrWhiteSpace &&
|
|
validatePlaylistId(embedCompositeMatch!)) {
|
|
return embedCompositeMatch;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@override
|
|
String toString() => value;
|
|
}
|