Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature to filter videos based on day of week and time #311

Merged
merged 1 commit into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,58 @@
"@secondsShortForm": {
"description": "Short form for the word seconds"
},
"videoFilterApplyDateToFilter": "Filter videos on given times",
"@videoFilterApplyDateToFilter": {
"description": "Label for switch to allow user to customize video filter and set days of week and time to them"
},
"videoFilterDayOfWeek": "Select days to apply filters",
"@videoFilterDayOfWeek": {
"description": "Title for day selection for the filter"
},
"videoFilterDayOfWeekDescription": "You can selectively choose days of the week and time to which the filters apply to, for example, avoid sport events spoilers.",
"@videoFilterDayOfWeekDescription": {
"description": ""
},
"videoFilterStartTime": "Start time",
"@videoFilterStartTime": {
"description": "Title for filter start time"
},
"videoFilterEndTime": "End time",
"@videoFilterEndTime": {
"description": "Title for filter end time"
},
"videoFilterAppliedOn": "Applied on {selectedDays}",
"@videoFilterAppliedOn": {
"description": "Readable text on when the filter should apply",
"placeholders": {
"selectedDays": {
"type": "String",
"example": "Monday, Wednesday, Friday"
}
}
},
"from": "From",
"@from": {
"description": "From word (as in 'From xx To xx')"
},
"to": "To",
"@to": {
"description": "To word as in 'From xx To xx')"
},
"videoFilterTimeOfDayFromTo": "From {from} to {to}",
"@videoFilterTimeOfDayFromTo": {
"description": "Time of day range",
"placeholders": {
"from": {
"type": "String",
"example": "3:00 AM"
},
"to": {
"type": "String",
"example": "5:00 PM"
}
}
},
"history": "History",
"@history": {
"description": "User view history label"
Expand Down
17 changes: 16 additions & 1 deletion lib/objectbox-model.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
},
{
"id": "6:8304874620604193998",
"lastPropertyId": "8:6020474727686624632",
"lastPropertyId": "11:8416925878752879022",
"name": "VideoFilter",
"properties": [
{
Expand Down Expand Up @@ -196,6 +196,21 @@
"id": "8:6020474727686624632",
"name": "hideFromFeed",
"type": 1
},
{
"id": "9:385259419700560741",
"name": "daysOfWeek",
"type": 27
},
{
"id": "10:4391992064156904605",
"name": "startTime",
"type": 9
},
{
"id": "11:8416925878752879022",
"name": "endTime",
"type": 9
}
],
"relations": []
Expand Down
46 changes: 43 additions & 3 deletions lib/objectbox.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 95 additions & 9 deletions lib/settings/models/db/video_filter.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:invidious/globals.dart';
import 'package:invidious/utils.dart';
import 'package:invidious/videos/models/base_video.dart';
import 'package:logging/logging.dart';
import 'package:objectbox/objectbox.dart';
Expand All @@ -9,6 +11,10 @@ import '../../../utils/models/pair.dart';

final log = Logger('Video Filter DB');

const defaultStartTime = "00:00:00";
const defaultEndTime = "23:59:59";
const wholeWeek = [1, 2, 3, 4, 5, 6, 7];

enum FilterType {
title,
channelName,
Expand Down Expand Up @@ -69,6 +75,10 @@ class VideoFilter {
return type?.name ?? '';
}

List<int> daysOfWeek = wholeWeek;
String startTime = defaultStartTime;
String endTime = defaultEndTime;

set dbType(String? value) {
type = FilterType.values.where((element) => element.name == value).firstOrNull;
}
Expand Down Expand Up @@ -97,10 +107,14 @@ class VideoFilter {

log.fine('filtering videos, we have ${filters.length} filters');

/*
videos = await Future.wait(videos?.map((v) {
return compute((message) => _innerFilterVideo(message.first, message.last), Couple(v, filters));
}).toList() ??
[]);
*/

videos = videos?.map((v) => _innerFilterVideo(v, filters)).toList() ?? [];

return videos;
}
Expand All @@ -115,21 +129,54 @@ class VideoFilter {
// Channel hide all
if (channelId != null && filterAll == true && videoChannel == channelId) {
log.fine('Video filtered because hide all == $filterAll, video channel id: ${videoChannel}, channel id ${channelId}');
return true;
return !isTimeAllowed();
}

bool filter = false;

switch (type) {
// string base operation
case FilterType.title:
return filterVideoStringOperation(video.title);
filter = filterVideoStringOperation(video.title);
case FilterType.channelName:
return video.author != null ? filterVideoStringOperation(video.author!) : true;
filter = video.author != null ? filterVideoStringOperation(video.author!) : true;
// int base operation
case FilterType.length:
return filterVideoNumberOperation(video.lengthSeconds);
filter = filterVideoNumberOperation(video.lengthSeconds);
default:
return false;
filter = false;
}

if (!filter) {
return false;
}
//if we need to filter, we need to check the time
return filter && !isTimeAllowed();
}

bool isTimeAllowed() {
var now = DateTime.now();

var daysToTest = daysOfWeek.isEmpty ? wholeWeek : daysOfWeek;
bool isDayAllowed = !daysToTest.contains(now.weekday);

if (isDayAllowed) {
print("Filter daysOfWeek ${daysOfWeek}, now day of week: ${now.weekday}");
return true;
}

List<String> safeStartTime = (startTime.isEmpty ? defaultStartTime : startTime).split(":");
List<String> safeEndTime = (endTime.isEmpty ? defaultEndTime : endTime).split(":");

DateTime startDateTime = DateTime.now().copyWith(hour: int.parse(safeStartTime[0]), minute: int.parse(safeStartTime[1]), second: int.parse(safeStartTime[2]));
DateTime endDateTime = DateTime.now().copyWith(hour: int.parse(safeEndTime[0]), minute: int.parse(safeEndTime[1]), second: int.parse(safeEndTime[2]));

// we only allow the video if current time is outside current time range
bool isTimeAllowed = now.isBefore(startDateTime) || now.isAfter(endDateTime);

print("Filter daysOfWeek ${daysOfWeek}, now day of week: ${now.weekday}, Filter from ${startDateTime} to ${endDateTime} current time ${now} ");

return isTimeAllowed;
}

bool filterVideoNumberOperation(int numberToCompare) {
Expand Down Expand Up @@ -160,15 +207,54 @@ class VideoFilter {
}
}

String localizedLabel(AppLocalizations locals) {
String localizedLabel(AppLocalizations locals, BuildContext context) {
String str = "";
if (filterAll) {
return locals.videoFilterWholeChannel(hideFromFeed ? locals.videoFilterHideLabel : locals.videoFilterFilterLabel);
str = locals.videoFilterWholeChannel(hideFromFeed ? locals.videoFilterHideLabel : locals.videoFilterFilterLabel);
} else if (type != null && operation != null) {
log.fine("Filter type $hideFromFeed");
return locals.videoFilterDescriptionString(hideFromFeed ? locals.videoFilterHideLabel : locals.videoFilterFilterLabel, FilterType.localizedType(type!, locals).toLowerCase(),
str = locals.videoFilterDescriptionString(hideFromFeed ? locals.videoFilterHideLabel : locals.videoFilterFilterLabel, FilterType.localizedType(type!, locals).toLowerCase(),
FilterOperation.localizedLabel(operation!, locals).toLowerCase(), value ?? '');
}

String daysOfWeek = localizedDaysOfWeek(locals);
if (daysOfWeek.isNotEmpty) {
if (str.isNotEmpty) {
str += "\n$daysOfWeek";
} else {
str = daysOfWeek;
}
}

String localizedTime = localizedTimes(locals, context);
if (localizedTime.isNotEmpty) {
if (str.isNotEmpty) {
str += "\n$localizedTime";
} else {
str = localizedTime;
}
}

return str;
}

String localizedDaysOfWeek(AppLocalizations locals) {
if (daysOfWeek.isNotEmpty && daysOfWeek.length != 7) {
daysOfWeek.sort();
return locals.videoFilterAppliedOn(daysOfWeek.map((e) => getWeekdayName(e)).join(", "));
} else {
return "";
return '';
}
}

String localizedTimes(AppLocalizations locals, BuildContext context) {
String str = '';
if (startTime != defaultStartTime || endTime != defaultEndTime) {
var start = timeStringToTimeOfDay(startTime);
var end = timeStringToTimeOfDay(endTime);
str = locals.videoFilterTimeOfDayFromTo(start.format(context), end.format(context));
}

return str;
}
}
Loading