1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_H_ 6 #define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_H_ 7 8 #include "base/macros.h" 9 #include "base/time/time.h" 10 #include "chrome/browser/media/feeds/media_feeds_store.mojom.h" 11 #include "chrome/browser/media/history/media_history_store.mojom.h" 12 #include "chrome/browser/media/kaleidoscope/mojom/kaleidoscope.mojom.h" 13 #include "components/history/core/browser/history_service_observer.h" 14 #include "components/keyed_service/core/keyed_service.h" 15 #include "content/public/browser/media_player_watch_time.h" 16 #include "net/cookies/cookie_change_dispatcher.h" 17 #include "services/media_session/public/cpp/media_metadata.h" 18 19 class Profile; 20 21 namespace media_feeds { 22 class MediaFeedsService; 23 } // namespace media_feeds 24 25 namespace media_session { 26 struct MediaImage; 27 struct MediaMetadata; 28 struct MediaPosition; 29 } // namespace media_session 30 31 namespace history { 32 class HistoryService; 33 } // namespace history 34 35 namespace media_history { 36 37 class MediaHistoryKeyedService : public KeyedService, 38 public history::HistoryServiceObserver { 39 public: 40 explicit MediaHistoryKeyedService(Profile* profile); 41 ~MediaHistoryKeyedService() override; 42 43 static bool IsEnabled(); 44 45 // Returns the instance attached to the given |profile|. 46 static MediaHistoryKeyedService* Get(Profile* profile); 47 48 // Overridden from KeyedService: 49 void Shutdown() override; 50 51 // Overridden from history::HistoryServiceObserver: 52 void OnURLsDeleted(history::HistoryService* history_service, 53 const history::DeletionInfo& deletion_info) override; 54 55 // Saves a playback from a single player in the media history store. 56 void SavePlayback(const content::MediaPlayerWatchTime& watch_time); 57 58 void GetMediaHistoryStats( 59 base::OnceCallback<void(mojom::MediaHistoryStatsPtr)> callback); 60 61 // Returns all the rows in the origin table. This should only be used for 62 // debugging because it is very slow. 63 void GetOriginRowsForDebug( 64 base::OnceCallback<void(std::vector<mojom::MediaHistoryOriginRowPtr>)> 65 callback); 66 67 // Returns all the rows in the playback table. This is only used for 68 // debugging because it loads all rows in the table. 69 void GetMediaHistoryPlaybackRowsForDebug( 70 base::OnceCallback<void(std::vector<mojom::MediaHistoryPlaybackRowPtr>)> 71 callback); 72 73 // Gets the playback sessions from the media history store. The results will 74 // be ordered by most recent first and be limited to the first |num_sessions|. 75 // For each session it calls |filter| and if that returns |true| then that 76 // session will be included in the results. 77 using GetPlaybackSessionsFilter = 78 base::RepeatingCallback<bool(const base::TimeDelta& duration, 79 const base::TimeDelta& position)>; 80 void GetPlaybackSessions( 81 base::Optional<unsigned int> num_sessions, 82 base::Optional<GetPlaybackSessionsFilter> filter, 83 base::OnceCallback<void( 84 std::vector<mojom::MediaHistoryPlaybackSessionRowPtr>)> callback); 85 86 // Saves a playback session in the media history store. 87 void SavePlaybackSession( 88 const GURL& url, 89 const media_session::MediaMetadata& metadata, 90 const base::Optional<media_session::MediaPosition>& position, 91 const std::vector<media_session::MediaImage>& artwork); 92 93 // Get origins from the origins table that have watchtime above the given 94 // threshold value. 95 void GetHighWatchTimeOrigins( 96 const base::TimeDelta& audio_video_watchtime_min, 97 base::OnceCallback<void(const std::vector<url::Origin>&)> callback); 98 99 // Returns Media Feeds items. 100 struct GetMediaFeedItemsRequest { 101 enum class Type { 102 // Return all the feed items for a feed for debugging. 103 kDebugAll, 104 105 // Returns items across all feeds that either have an active action status 106 // or a play next candidate. Ordered by most recent first. 107 kContinueWatching, 108 109 // Returns all the items for a single feed. Ordered by clicked and shown 110 // count so items that have been clicked and shown a lot will be at the 111 // end. Items must not be continue watching items. 112 kItemsForFeed 113 }; 114 115 static GetMediaFeedItemsRequest CreateItemsForDebug(int64_t feed_id); 116 117 static GetMediaFeedItemsRequest CreateItemsForFeed( 118 int64_t feed_id, 119 unsigned limit, 120 bool fetched_items_should_be_safe, 121 base::Optional<media_feeds::mojom::MediaFeedItemType> filter_by_type); 122 123 static GetMediaFeedItemsRequest CreateItemsForContinueWatching( 124 unsigned limit, 125 bool fetched_items_should_be_safe, 126 base::Optional<media_feeds::mojom::MediaFeedItemType> filter_by_type); 127 128 GetMediaFeedItemsRequest(); 129 GetMediaFeedItemsRequest(const GetMediaFeedItemsRequest& t); 130 131 Type type = Type::kDebugAll; 132 133 // The ID of the feed to retrieve items for. Only valid for |kDebugAll| and 134 // |kItemsForFeed|. 135 base::Optional<int64_t> feed_id; 136 137 // The maximum number of feeds to return. Only valid for |kContinueWatching| 138 // and |kItemsForFeed|. 139 base::Optional<unsigned> limit; 140 141 // True if the item should have passed Safe Search checks. Only valid for 142 // |kContinueWatching| and |kItemsForFeed|. 143 bool fetched_items_should_be_safe = false; 144 145 // The item type to filter by. 146 base::Optional<media_feeds::mojom::MediaFeedItemType> filter_by_type; 147 }; 148 void GetMediaFeedItems( 149 const GetMediaFeedItemsRequest& request, 150 base::OnceCallback< 151 void(std::vector<media_feeds::mojom::MediaFeedItemPtr>)> callback); 152 153 // Information about a completed media feed fetch, such as the feed items, 154 // feed info, and fetch status code. 155 struct MediaFeedFetchResult { 156 ~MediaFeedFetchResult(); 157 MediaFeedFetchResult(); 158 MediaFeedFetchResult(MediaFeedFetchResult&& t); 159 160 MediaFeedFetchResult(const MediaFeedFetchResult&) = delete; 161 void operator=(const MediaFeedFetchResult&) = delete; 162 163 int64_t feed_id; 164 165 // The feed items that were fetched. Only contains valid items. 166 std::vector<media_feeds::mojom::MediaFeedItemPtr> items; 167 168 // The status code for the fetch. 169 media_feeds::mojom::FetchResult status; 170 171 // If the feed was fetched from the browser cache then this should be true. 172 bool was_fetched_from_cache = false; 173 174 // Logos representing the feed. 175 std::vector<media_feeds::mojom::MediaImagePtr> logos; 176 177 // The display name for the feed. 178 std::string display_name; 179 180 // The reset token for the feed. 181 base::Optional<base::UnguessableToken> reset_token; 182 183 // Information about the currently logged in user. 184 media_feeds::mojom::UserIdentifierPtr user_identifier; 185 186 // If set then changes to the cookie name provided on the feed origin or any 187 // associated origin will trigger the feed to be reset. 188 std::string cookie_name_filter; 189 190 // Logs about any errors that may have occurred while fetching or converting 191 // the feed data. New-line delimited human-readable text. 192 std::string error_logs; 193 194 // If true then the backend returned a 410 Gone error. 195 bool gone = false; 196 }; 197 // Replaces the media items in |result.feed_id|. This will delete any old feed 198 // items and store the new ones in |result.items|. This will also update the 199 // |result.status|, |result.logos| and |result.display_name| for the feed. 200 void StoreMediaFeedFetchResult(MediaFeedFetchResult result, 201 base::OnceClosure callback); 202 203 void GetURLsInTableForTest(const std::string& table, 204 base::OnceCallback<void(std::set<GURL>)> callback); 205 206 // Represents an object that needs to be checked against Safe Search. 207 // Contains the ID of the item and a set of URLs that should be checked. 208 enum class SafeSearchCheckedType { 209 kFeed, 210 kFeedItem, 211 }; 212 using SafeSearchID = std::pair<SafeSearchCheckedType, int64_t>; 213 struct PendingSafeSearchCheck { 214 PendingSafeSearchCheck(SafeSearchCheckedType type, int64_t id); 215 ~PendingSafeSearchCheck(); 216 PendingSafeSearchCheck(const PendingSafeSearchCheck&) = delete; 217 PendingSafeSearchCheck& operator=(const PendingSafeSearchCheck&) = delete; 218 219 SafeSearchID const id; 220 std::set<GURL> urls; 221 }; 222 using PendingSafeSearchCheckList = 223 std::vector<std::unique_ptr<PendingSafeSearchCheck>>; 224 void GetPendingSafeSearchCheckMediaFeedItems( 225 base::OnceCallback<void(PendingSafeSearchCheckList)> callback); 226 227 // Store the Safe Search check results for multiple object. The map key is 228 // the ID of the object. 229 void StoreMediaFeedItemSafeSearchResults( 230 std::map<SafeSearchID, media_feeds::mojom::SafeSearchResult> results); 231 232 // Posts an empty task to the database thread. The callback will be called 233 // on the calling thread when the empty task is completed. This can be used 234 // for waiting for database operations in tests. 235 void PostTaskToDBForTest(base::OnceClosure callback); 236 237 // Returns Media Feeds. 238 struct GetMediaFeedsRequest { 239 enum class Type { 240 // Return all the fields. 241 kAll, 242 243 // Returns the top feeds to be fetched. These will be sorted by the 244 // by audio+video watchtime descending and we will also populate the 245 // |origin_audio_video_watchtime_percentile| field in |MediaFeedPtr|. 246 kTopFeedsForFetch, 247 248 // Returns the top feeds to be displayed. These will be sorted by the 249 // by audio+video watchtime descending and we will also populate the 250 // |origin_audio_video_watchtime_percentile| field in |MediaFeedPtr|. 251 kTopFeedsForDisplay, 252 253 // Returns the feeeds that have been selected by the user to be fetched. 254 kSelectedFeedsForFetch, 255 }; 256 257 static GetMediaFeedsRequest CreateTopFeedsForFetch( 258 unsigned limit, 259 base::TimeDelta audio_video_watchtime_min); 260 261 static GetMediaFeedsRequest CreateTopFeedsForDisplay( 262 unsigned limit, 263 int fetched_items_min, 264 bool fetched_items_min_should_be_safe, 265 base::Optional<media_feeds::mojom::MediaFeedItemType> filter_by_type); 266 267 static GetMediaFeedsRequest CreateSelectedFeedsForFetch(); 268 269 GetMediaFeedsRequest(); 270 GetMediaFeedsRequest(const GetMediaFeedsRequest& t); 271 272 Type type = Type::kAll; 273 274 // The maximum number of feeds to return. Only valid for |kTopFeedsForFetch| 275 // and |kTopFeedsForDisplay|. 276 base::Optional<unsigned> limit; 277 278 // The minimum audio+video watchtime required on the origin to return the 279 // feed. Only valid for |kTopFeedsForFetch|. 280 base::Optional<base::TimeDelta> audio_video_watchtime_min; 281 282 // The minimum number of fetched items that are required and whether they 283 // should have passed safe search. Only valid for |kTopFeedsForDisplay|. 284 base::Optional<int> fetched_items_min; 285 bool fetched_items_min_should_be_safe = false; 286 287 // The item type to filter by. 288 base::Optional<media_feeds::mojom::MediaFeedItemType> filter_by_type; 289 }; 290 void GetMediaFeeds( 291 const GetMediaFeedsRequest& request, 292 base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)> 293 callback); 294 295 // Updates the display time for the Media Feed with |feed_id| to now. 296 void UpdateMediaFeedDisplayTime(const int64_t feed_id); 297 298 // Increment the media feed items shown counter by one. 299 void IncrementMediaFeedItemsShownCount(const std::set<int64_t> feed_item_ids); 300 301 // Marks a media feed item as clicked. This is when the user has opened the 302 // item in the UI. 303 void MarkMediaFeedItemAsClicked(const int64_t& feed_item_id); 304 305 // Resets a Media Feed by deleting any items and resetting it to defaults. If 306 // |include_subdomains| is true then this will reset any feeds on any 307 // subdomain of |origin|. 308 void ResetMediaFeedDueToCookies(const url::Origin& origin, 309 const bool include_subdomains, 310 const std::string& name, 311 const net::CookieChangeCause& cause); 312 313 // Resets any Media Feeds that were fetched between |start_time| and 314 // |end_time|. This will delete any items and reset them to defaults. The 315 // reason will be set to |kCache|. 316 using CacheClearingFilter = base::RepeatingCallback<bool(const GURL& url)>; 317 void ResetMediaFeedDueToCacheClearing(const base::Time& start_time, 318 const base::Time& end_time, 319 CacheClearingFilter filter, 320 base::OnceClosure callback); 321 322 // Deletes the Media Feed and runs the callback. 323 void DeleteMediaFeed(const int64_t feed_id, base::OnceClosure callback); 324 325 // Gets the details needed to fetch a Media Feed. 326 struct MediaFeedFetchDetails { 327 MediaFeedFetchDetails(); 328 ~MediaFeedFetchDetails(); 329 MediaFeedFetchDetails(MediaFeedFetchDetails&& t); 330 MediaFeedFetchDetails& operator=(const MediaFeedFetchDetails&); 331 332 GURL url; 333 media_feeds::mojom::FetchResult last_fetch_result; 334 base::Optional<base::UnguessableToken> reset_token; 335 }; 336 using GetMediaFeedFetchDetailsCallback = 337 base::OnceCallback<void(base::Optional<MediaFeedFetchDetails>)>; 338 void GetMediaFeedFetchDetails(const int64_t feed_id, 339 GetMediaFeedFetchDetailsCallback callback); 340 341 // Updates the FeedUserStatus for a feed. 342 void UpdateFeedUserStatus(const int64_t feed_id, 343 media_feeds::mojom::FeedUserStatus status); 344 345 // Stores the Kaleidocope data keyed against a GAIA ID. 346 void SetKaleidoscopeData(media::mojom::GetCollectionsResponsePtr data, 347 const std::string& gaia_id); 348 349 // Retrieves the Kaleidoscope data keyed against a GAIA ID. The data expires 350 // after 24 hours or if the GAIA ID changes. 351 using GetKaleidoscopeDataCallback = 352 base::OnceCallback<void(media::mojom::GetCollectionsResponsePtr)>; 353 void GetKaleidoscopeData(const std::string& gaia_id, 354 GetKaleidoscopeDataCallback callback); 355 356 // Delete any stored data. 357 void DeleteKaleidoscopeData(); 358 359 protected: 360 friend class media_feeds::MediaFeedsService; 361 362 // Resets a Media Feed by deleting any items and resetting it to defaults. If 363 // |include_subdomains| is true then this will reset any feeds on any 364 // subdomain of |origin|. 365 void ResetMediaFeed(const url::Origin& origin, 366 media_feeds::mojom::ResetReason reason); 367 368 // Saves a newly discovered media feed in the media history store. 369 void DiscoverMediaFeed(const GURL& url, 370 base::OnceClosure callback = base::DoNothing()); 371 372 private: 373 class StoreHolder; 374 375 std::unique_ptr<StoreHolder> store_; 376 377 Profile* profile_; 378 379 DISALLOW_COPY_AND_ASSIGN(MediaHistoryKeyedService); 380 }; 381 382 } // namespace media_history 383 384 #endif // CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_KEYED_SERVICE_H_ 385