about summary refs log tree commit diff
path: root/youtube_dl
diff options
context:
space:
mode:
authorSergey M․ <dstftw@gmail.com>2016-03-01 01:01:33 +0600
committerSergey M․ <dstftw@gmail.com>2016-03-01 01:01:33 +0600
commitd77ab8e255e593d8534bdd47e84c0cc03c4e6efd (patch)
treeff6952244d0777d40a03b84a217ee14866f62964 /youtube_dl
parent4b3cd7316cbb95100f7fc4dd03d86e0fd7674996 (diff)
downloadyoutube-dl-d77ab8e255e593d8534bdd47e84c0cc03c4e6efd.tar.gz
youtube-dl-d77ab8e255e593d8534bdd47e84c0cc03c4e6efd.tar.xz
youtube-dl-d77ab8e255e593d8534bdd47e84c0cc03c4e6efd.zip
Add --mark-watched feature (Closes #5054)
Diffstat (limited to 'youtube_dl')
-rw-r--r--youtube_dl/__init__.py1
-rw-r--r--youtube_dl/extractor/common.py9
-rw-r--r--youtube_dl/extractor/youtube.py26
-rw-r--r--youtube_dl/options.py4
4 files changed, 40 insertions, 0 deletions
diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py
index f5f064241..79b389840 100644
--- a/youtube_dl/__init__.py
+++ b/youtube_dl/__init__.py
@@ -355,6 +355,7 @@ def _real_main(argv=None):
         'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
         'encoding': opts.encoding,
         'extract_flat': opts.extract_flat,
+        'mark_watched': opts.mark_watched,
         'merge_output_format': opts.merge_output_format,
         'postprocessors': postprocessors,
         'fixup': opts.fixup,
diff --git a/youtube_dl/extractor/common.py b/youtube_dl/extractor/common.py
index 3f16b1b9e..a7c700099 100644
--- a/youtube_dl/extractor/common.py
+++ b/youtube_dl/extractor/common.py
@@ -1620,6 +1620,15 @@ class InfoExtractor(object):
     def _get_automatic_captions(self, *args, **kwargs):
         raise NotImplementedError('This method must be implemented by subclasses')
 
+    def mark_watched(self, *args, **kwargs):
+        if (self._downloader.params.get('mark_watched', False) and
+                (self._get_login_info()[0] is not None or
+                    self._downloader.params.get('cookiefile') is not None)):
+            self._mark_watched(*args, **kwargs)
+
+    def _mark_watched(self, *args, **kwargs):
+        raise NotImplementedError('This method must be implemented by subclasses')
+
 
 class SearchInfoExtractor(InfoExtractor):
     """
diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
index ec90c2111..ba339b67d 100644
--- a/youtube_dl/extractor/youtube.py
+++ b/youtube_dl/extractor/youtube.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
 import itertools
 import json
 import os.path
+import random
 import re
 import time
 import traceback
@@ -1046,6 +1047,29 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
             self._downloader.report_warning(err_msg)
             return {}
 
+    def _mark_watched(self, video_id, video_info):
+        playback_url = video_info.get('videostats_playback_base_url', [None])[0]
+        if not playback_url:
+            return
+        parsed_playback_url = compat_urlparse.urlparse(playback_url)
+        qs = compat_urlparse.parse_qs(parsed_playback_url.query)
+
+        # cpn generation algorithm is reverse engineered from base.js.
+        # In fact it works even with dummy cpn.
+        CPN_ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_'
+        cpn = ''.join((CPN_ALPHABET[random.randint(0, 256) & 63] for _ in range(0, 16)))
+
+        qs.update({
+            'ver': ['2'],
+            'cpn': [cpn],
+        })
+        playback_url = compat_urlparse.urlunparse(
+            parsed_playback_url._replace(query=compat_urllib_parse.urlencode(qs, True)))
+
+        self._download_webpage(
+            playback_url, video_id, 'Marking watched',
+            'Unable to mark watched', fatal=False)
+
     @classmethod
     def extract_id(cls, url):
         mobj = re.match(cls._VALID_URL, url, re.VERBOSE)
@@ -1555,6 +1579,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
 
         self._sort_formats(formats)
 
+        self.mark_watched(video_id, video_info)
+
         return {
             'id': video_id,
             'uploader': video_uploader,
diff --git a/youtube_dl/options.py b/youtube_dl/options.py
index 3afa8bb6f..048dee881 100644
--- a/youtube_dl/options.py
+++ b/youtube_dl/options.py
@@ -171,6 +171,10 @@ def parseOpts(overrideArguments=None):
         default=False,
         help='Do not extract the videos of a playlist, only list them.')
     general.add_option(
+        '--mark-watched',
+        action='store_true', dest='mark_watched', default=False,
+        help='Mark videos watched (YouTube only)')
+    general.add_option(
         '--no-color', '--no-colors',
         action='store_true', dest='no_color',
         default=False,