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