-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
228 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import 'dart:io'; | ||
|
||
// import 'package:csv/csv.dart'; | ||
// import 'package:csv/csv.dart'; | ||
// import 'package:fast_csv/csv_parser.dart'; | ||
import 'package:xdg_directories/xdg_directories.dart' as xdg; | ||
|
||
import '../util/csv_parser.dart'; | ||
|
||
enum ItemType { | ||
video, | ||
playlist, | ||
channel, | ||
} | ||
|
||
class HistoryDatabase { | ||
const HistoryDatabase({required this.history}); | ||
|
||
final List<HistoryModel> history; | ||
|
||
static Future<HistoryDatabase> load({final int? limit}) async { | ||
final file = File('${xdg.dataHome.path}/yatta/history.csv'); | ||
return HistoryDatabase( | ||
history: const CsvParser() | ||
.parse(await file.readAsLines()) | ||
.map((final e) => switch (e) { | ||
{ | ||
'id': final String id, | ||
'type': final String type, | ||
'provider': final String provider, | ||
'title': final String title, | ||
'description': final String description, | ||
'url': final String url, | ||
'viewCount': final String viewCount, | ||
'channelId': final String channelId, | ||
'channelTitle': final String channelTitle, | ||
'iconUrl': final String iconUrl, | ||
'thumbnailUrl': final String thumbnailUrl, | ||
'previewUrl': final String previewUrl, | ||
'publishDate': final String publishDate, | ||
'duration': _, | ||
'romanizedMetadata': final String romanizedMetadata, | ||
'history': final String history, | ||
} => | ||
HistoryModel( | ||
id: id, | ||
title: title, | ||
description: description, | ||
duration: Duration.zero, | ||
romanizedMetadata: romanizedMetadata, | ||
publishDate: publishDate, | ||
type: switch (type) { | ||
'video' => ItemType.video, | ||
'playlist' => ItemType.playlist, | ||
'channel' => ItemType.channel, | ||
_ => ItemType.video, | ||
}, | ||
history: history.split(','), | ||
channelId: channelId, | ||
iconUrl: iconUrl, | ||
thumbnailUrl: thumbnailUrl, | ||
previewUrl: previewUrl, | ||
provider: provider, | ||
channelTitle: channelTitle, | ||
url: url, | ||
viewCount: int.tryParse(viewCount), | ||
), | ||
_ => throw UnimplementedError(), | ||
}) | ||
.toList()); | ||
} | ||
} | ||
|
||
class HistoryModel { | ||
const HistoryModel({ | ||
required this.id, | ||
required this.title, | ||
required this.duration, | ||
required this.description, | ||
required this.romanizedMetadata, | ||
required this.publishDate, | ||
required this.type, | ||
required this.history, | ||
required this.channelId, | ||
required this.iconUrl, | ||
required this.thumbnailUrl, | ||
required this.previewUrl, | ||
required this.provider, | ||
required this.channelTitle, | ||
required this.url, | ||
required this.viewCount, | ||
}); | ||
|
||
/// Can be video id or playlist id | ||
final String id; | ||
|
||
final ItemType type; | ||
|
||
/// Video site (e.g. "youtube") | ||
final String provider; | ||
|
||
final String title; | ||
final String description; | ||
final String url; | ||
final int? viewCount; | ||
|
||
/// Channel name | ||
final String channelTitle; | ||
final String channelId; | ||
|
||
/// Cover image < 120px width | ||
final String iconUrl; | ||
|
||
/// Cover image < 32px width | ||
final String thumbnailUrl; | ||
|
||
/// Cover image < 48px width | ||
final String previewUrl; | ||
|
||
/// ISO 8601 format time | ||
final String publishDate; | ||
final Duration duration; | ||
|
||
/// ISO 8601 format time | ||
final List<String> history; | ||
|
||
/// Search friendly string | ||
final String romanizedMetadata; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/// Not exactly RFC 4810 | ||
class CsvParser { | ||
const CsvParser({this.separator = ';'}); | ||
final String separator; | ||
|
||
static List<String> _splitLine(final String line) { | ||
var buff = <String>['']; | ||
var inQuotationMark = false; | ||
|
||
for (var i = 0; i < line.length; i++) { | ||
if (!inQuotationMark) { | ||
if (line[i] == ',') { | ||
buff = [...buff, '']; | ||
continue; | ||
} | ||
} | ||
if (line[i] == '"') { | ||
inQuotationMark = !inQuotationMark; | ||
continue; | ||
} | ||
buff.last += line[i]; | ||
} | ||
return buff; | ||
} | ||
|
||
List<Map<String, dynamic>> parse(final List<String> csv) { | ||
var lineNumber = 0; | ||
late final List<String> header; | ||
final content = <List<String>>[]; | ||
|
||
csv.forEach((final line) { | ||
if (lineNumber == 0) { | ||
header = _splitLine(line); | ||
} else { | ||
content.add(_splitLine(line)); | ||
} | ||
lineNumber++; | ||
}); | ||
|
||
return content.map((final e) => Map.fromIterables(header, e)).toList(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import 'package:test/test.dart'; | ||
import 'package:yatta/util/csv_parser.dart'; | ||
|
||
const String csv = ''' | ||
id,type,provider,title,description,url,viewCount,channelId,channelTitle,iconUrl,thumbnailUrl,previewUrl,publishDate,duration,history,romanized | ||
W2muWA-40Uk,video,youtube,三月のパンタシア 『夜光』,三月のパンタシア-夜光 小説「さよならの空はあの青い花の輝きとよく似ていた」(みあ著)主題歌 ...,https://youtu.be/W2muWA-40Uk,,UC4lk0Ob-F3ptOQUUq8s0pzQ,三月のパンタシア Official YouTube Channel,https://i.ytimg.com/vi/W2muWA-40Uk/default.jpg,https://i.ytimg.com/vi/W2muWA-40Uk/mqdefault.jpg,https://i.ytimg.com/vi/W2muWA-40Uk/hqdefault.jpg,2021-07-21T13:00:10Z,03:40,"2021-07-21T13:00:10Z,2022-07-21T13:00:10Z",sangatsu no phantasia yakou sangatsu no phantasia yakou sousetsu sayonara no sora wa ano aoi hana no kagayaki to yoku nite ita mia cho shudaika'''; | ||
|
||
void main() { | ||
group('Parse history', () { | ||
const parsedCsv = [ | ||
{ | ||
'id': 'W2muWA-40Uk', | ||
'type': 'video', | ||
'provider': 'youtube', | ||
'title': '三月のパンタシア 『夜光』', | ||
'description': '三月のパンタシア-夜光 小説「さよならの空はあの青い花の輝きとよく似ていた」(みあ著)主題歌 ...', | ||
'url': 'https://youtu.be/W2muWA-40Uk', | ||
'viewCount': '', | ||
'channelId': 'UC4lk0Ob-F3ptOQUUq8s0pzQ', | ||
'channelTitle': '三月のパンタシア Official YouTube Channel', | ||
'iconUrl': 'https://i.ytimg.com/vi/W2muWA-40Uk/default.jpg', | ||
'thumbnailUrl': 'https://i.ytimg.com/vi/W2muWA-40Uk/mqdefault.jpg', | ||
'previewUrl': 'https://i.ytimg.com/vi/W2muWA-40Uk/hqdefault.jpg', | ||
'publishDate': '2021-07-21T13:00:10Z', | ||
'duration': '03:40', | ||
'history': '2021-07-21T13:00:10Z,2022-07-21T13:00:10Z', | ||
'romanized': ''' | ||
sangatsu no phantasia yakou sangatsu no phantasia yakou sousetsu sayonara no sora wa ano aoi hana no kagayaki to yoku nite ita mia cho shudaika''' | ||
} | ||
]; | ||
|
||
test( | ||
'history', | ||
() => expect(const CsvParser().parse(csv.split('\n')), parsedCsv), | ||
); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters